1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #include <io/xdf_shell.h>
27
28 /*
29 * We're emulating (and possibly layering on top of) cmdk devices, so xdf
30 * disk unit mappings must match up with cmdk disk unit mappings'.
31 */
32 #if !defined(XDF_PSHIFT)
33 #error "can't find definition for xdf unit mappings - XDF_PSHIFT"
34 #endif /* XDF_PSHIFT */
35
36 #if !defined(CMDK_UNITSHF)
37 #error "can't find definition for cmdk unit mappings - CMDK_UNITSHF"
38 #endif /* CMDK_UNITSHF */
39
40 #if ((XDF_PSHIFT - CMDK_UNITSHF) != 0)
41 #error "cmdk and xdf unit mappings don't match."
42 #endif /* ((XDF_PSHIFT - CMDK_UNITSHF) != 0) */
43
44 extern const struct dev_ops cmdk_ops;
45 extern void *cmdk_state;
46
47 /*
48 * Globals required by xdf_shell.c
49 */
50 const char *xdfs_c_name = "cmdk";
51 const char *xdfs_c_linkinfo = "PV Common Direct Access Disk";
52 void **xdfs_c_hvm_ss = &cmdk_state;
53 const size_t xdfs_c_hvm_ss_size = sizeof (struct cmdk);
54 const struct dev_ops *xdfs_c_hvm_dev_ops = &cmdk_ops;
55
56 const xdfs_h2p_map_t xdfs_c_h2p_map[] = {
57 /*
58 * The paths mapping here are very specific to xen and qemu. When a
59 * domU is booted under xen in HVM mode, qemu is normally used to
60 * emulate up to four ide disks. These disks always have the four
61 * path listed below. To configure an emulated ide device, the
62 * xen domain configuration file normally has an entry that looks
63 * like this:
64 * disk = [ 'file:/foo.img,hda,w' ]
65 *
66 * The part we're interested in is the 'hda', which we'll call the
67 * xen disk device name here. The xen management tools (which parse
68 * the xen domain configuration file and launch qemu) makes the
69 * following assumptions about this value:
70 * hda == emulated ide disk 0 (ide bus 0, master)
71 * hdb == emulated ide disk 1 (ide bus 0, slave)
72 * hdc == emulated ide disk 2 (ide bus 1, master)
73 * hdd == emulated ide disk 3 (ide bus 1, slave)
74 *
75 * (Uncoincidentally, these xen disk device names actually map to
76 * the /dev filesystem names of ide disk devices in Linux. So in
77 * Linux /dev/hda is the first ide disk.) So for the first part of
78 * our mapping we've just hardcoded the cmdk paths that we know
79 * qemu will use.
80 *
81 * To understand the second half of the mapping (ie, the xdf device
82 * that each emulated cmdk device should be mapped two) we need to
83 * know the solaris device node address that will be assigned to
84 * each xdf device. (The device node address is the decimal
85 * number that comes after the "xdf@" in the device path.)
86 *
87 * So the question becomes, how do we know what the xenstore device
88 * id for emulated disk will be? Well, it turns out that since the
89 * xen management tools expect the disk device names to be Linux
90 * device names, those same management tools assign each disk a
91 * device id that matches the dev_t of the corresponding device
92 * under Linux. (Big shocker.) This xen device name-to-id mapping
93 * is currently all hard coded here:
94 * xen.hg/tools/python/xen/util/blkif.py`blkdev_name_to_number()
95 *
96 * So looking at the code above we can see the following xen disk
97 * device name to xenstore device id mappings:
98 * 'hda' == 0t768 == ((3 * 256) + (0 * 64))
99 * 'hdb' == 0t832 == ((3 * 256) + (1 * 64))
100 * 'hdc' == 0t5632 == ((22 * 256) + (0 * 64))
101 * 'hdd' == 0t5696 == ((22 * 256) + (1 * 64))
102 */
103 { "/pci@0,0/pci-ide@1,1/ide@0/cmdk@0,0", "/xpvd/xdf@768" },
104 { "/pci@0,0/pci-ide@1,1/ide@0/cmdk@1,0", "/xpvd/xdf@832" },
105 { "/pci@0,0/pci-ide@1,1/ide@1/cmdk@0,0", "/xpvd/xdf@5632" },
106 { "/pci@0,0/pci-ide@1,1/ide@1/cmdk@1,0", "/xpvd/xdf@5696" },
107 { NULL, 0 }
108 };
109
110 /*
111 * Private functions
112 */
113 /*
114 * xdfs_get_modser() is basically a local copy of
115 * cmdk_get_modser() modified to work without the dadk layer.
116 * (which the non-pv version of the cmdk driver uses.)
117 */
118 static int
xdfs_get_modser(xdfs_state_t * xsp,int ioccmd,char * buf,int len)119 xdfs_get_modser(xdfs_state_t *xsp, int ioccmd, char *buf, int len)
120 {
121 struct scsi_device *scsi_device;
122 opaque_t ctlobjp;
123 dadk_ioc_string_t strarg;
124 char *s;
125 char ch;
126 boolean_t ret;
127 int i;
128 int tb;
129
130 strarg.is_buf = buf;
131 strarg.is_size = len;
132 scsi_device = ddi_get_driver_private(xsp->xdfss_dip);
133 ctlobjp = scsi_device->sd_address.a_hba_tran;
134 if (CTL_IOCTL(ctlobjp,
135 ioccmd, (uintptr_t)&strarg, FNATIVE | FKIOCTL) != 0)
136 return (0);
137
138 /*
139 * valid model/serial string must contain a non-zero non-space
140 * trim trailing spaces/NULL
141 */
142 ret = B_FALSE;
143 s = buf;
144 for (i = 0; i < strarg.is_size; i++) {
145 ch = *s++;
146 if (ch != ' ' && ch != '\0')
147 tb = i + 1;
148 if (ch != ' ' && ch != '\0' && ch != '0')
149 ret = B_TRUE;
150 }
151
152 if (ret == B_FALSE)
153 return (0);
154
155 return (tb);
156 }
157
158 /*
159 * xdfs_devid_modser() is basically a copy of cmdk_devid_modser()
160 * that has been modified to use local pv cmdk driver functions.
161 *
162 * Build a devid from the model and serial number
163 * Return DDI_SUCCESS or DDI_FAILURE.
164 */
165 static int
xdfs_devid_modser(xdfs_state_t * xsp)166 xdfs_devid_modser(xdfs_state_t *xsp)
167 {
168 int rc = DDI_FAILURE;
169 char *hwid;
170 int modlen;
171 int serlen;
172
173 /*
174 * device ID is a concatenation of model number, '=', serial number.
175 */
176 hwid = kmem_alloc(CMDK_HWIDLEN, KM_SLEEP);
177 modlen = xdfs_get_modser(xsp, DIOCTL_GETMODEL, hwid, CMDK_HWIDLEN);
178 if (modlen == 0)
179 goto err;
180
181 hwid[modlen++] = '=';
182 serlen = xdfs_get_modser(xsp, DIOCTL_GETSERIAL,
183 hwid + modlen, CMDK_HWIDLEN - modlen);
184 if (serlen == 0)
185 goto err;
186
187 hwid[modlen + serlen] = 0;
188
189 /* Initialize the device ID, trailing NULL not included */
190 rc = ddi_devid_init(xsp->xdfss_dip, DEVID_ATA_SERIAL, modlen + serlen,
191 hwid, (ddi_devid_t *)&xsp->xdfss_tgt_devid);
192 if (rc != DDI_SUCCESS)
193 goto err;
194
195 kmem_free(hwid, CMDK_HWIDLEN);
196 return (DDI_SUCCESS);
197
198 err:
199 kmem_free(hwid, CMDK_HWIDLEN);
200 return (DDI_FAILURE);
201 }
202
203 /*
204 * xdfs_devid_read() is basically a local copy of
205 * cmdk_devid_read() modified to work without the dadk layer.
206 * (which the non-pv version of the cmdk driver uses.)
207 *
208 * Read a devid from on the first block of the last track of
209 * the last cylinder. Make sure what we read is a valid devid.
210 * Return DDI_SUCCESS or DDI_FAILURE.
211 */
212 static int
xdfs_devid_read(xdfs_state_t * xsp)213 xdfs_devid_read(xdfs_state_t *xsp)
214 {
215 diskaddr_t blk;
216 struct dk_devid *dkdevidp;
217 uint_t *ip, chksum;
218 int i;
219
220 if (cmlb_get_devid_block(xsp->xdfss_cmlbhandle, &blk, 0) != 0)
221 return (DDI_FAILURE);
222
223 dkdevidp = kmem_zalloc(NBPSCTR, KM_SLEEP);
224 if (xdfs_lb_rdwr(xsp->xdfss_dip,
225 TG_READ, dkdevidp, blk, NBPSCTR, NULL) != 0)
226 goto err;
227
228 /* Validate the revision */
229 if ((dkdevidp->dkd_rev_hi != DK_DEVID_REV_MSB) ||
230 (dkdevidp->dkd_rev_lo != DK_DEVID_REV_LSB))
231 goto err;
232
233 /* Calculate the checksum */
234 chksum = 0;
235 ip = (uint_t *)dkdevidp;
236 for (i = 0; i < ((NBPSCTR - sizeof (int))/sizeof (int)); i++)
237 chksum ^= ip[i];
238 if (DKD_GETCHKSUM(dkdevidp) != chksum)
239 goto err;
240
241 /* Validate the device id */
242 if (ddi_devid_valid((ddi_devid_t)dkdevidp->dkd_devid) != DDI_SUCCESS)
243 goto err;
244
245 /* keep a copy of the device id */
246 i = ddi_devid_sizeof((ddi_devid_t)dkdevidp->dkd_devid);
247 xsp->xdfss_tgt_devid = kmem_alloc(i, KM_SLEEP);
248 bcopy(dkdevidp->dkd_devid, xsp->xdfss_tgt_devid, i);
249 kmem_free(dkdevidp, NBPSCTR);
250 return (DDI_SUCCESS);
251
252 err:
253 kmem_free(dkdevidp, NBPSCTR);
254 return (DDI_FAILURE);
255 }
256
257 /*
258 * xdfs_devid_fabricate() is basically a local copy of
259 * cmdk_devid_fabricate() modified to work without the dadk layer.
260 * (which the non-pv version of the cmdk driver uses.)
261 *
262 * Create a devid and write it on the first block of the last track of
263 * the last cylinder.
264 * Return DDI_SUCCESS or DDI_FAILURE.
265 */
266 static int
xdfs_devid_fabricate(xdfs_state_t * xsp)267 xdfs_devid_fabricate(xdfs_state_t *xsp)
268 {
269 ddi_devid_t devid = NULL; /* devid made by ddi_devid_init */
270 struct dk_devid *dkdevidp = NULL; /* devid struct stored on disk */
271 diskaddr_t blk;
272 uint_t *ip, chksum;
273 int i;
274
275 if (cmlb_get_devid_block(xsp->xdfss_cmlbhandle, &blk, 0) != 0)
276 return (DDI_FAILURE);
277
278 if (ddi_devid_init(xsp->xdfss_dip, DEVID_FAB, 0, NULL, &devid) !=
279 DDI_SUCCESS)
280 return (DDI_FAILURE);
281
282 /* allocate a buffer */
283 dkdevidp = (struct dk_devid *)kmem_zalloc(NBPSCTR, KM_SLEEP);
284
285 /* Fill in the revision */
286 dkdevidp->dkd_rev_hi = DK_DEVID_REV_MSB;
287 dkdevidp->dkd_rev_lo = DK_DEVID_REV_LSB;
288
289 /* Copy in the device id */
290 i = ddi_devid_sizeof(devid);
291 if (i > DK_DEVID_SIZE)
292 goto err;
293 bcopy(devid, dkdevidp->dkd_devid, i);
294
295 /* Calculate the chksum */
296 chksum = 0;
297 ip = (uint_t *)dkdevidp;
298 for (i = 0; i < ((NBPSCTR - sizeof (int))/sizeof (int)); i++)
299 chksum ^= ip[i];
300
301 /* Fill in the checksum */
302 DKD_FORMCHKSUM(chksum, dkdevidp);
303
304 if (xdfs_lb_rdwr(xsp->xdfss_dip,
305 TG_WRITE, dkdevidp, blk, NBPSCTR, NULL) != 0)
306 goto err;
307
308 kmem_free(dkdevidp, NBPSCTR);
309
310 xsp->xdfss_tgt_devid = devid;
311 return (DDI_SUCCESS);
312
313 err:
314 if (dkdevidp != NULL)
315 kmem_free(dkdevidp, NBPSCTR);
316 if (devid != NULL)
317 ddi_devid_free(devid);
318 return (DDI_FAILURE);
319 }
320
321 /*
322 * xdfs_rwcmd_copyin() is a duplicate of rwcmd_copyin().
323 */
324 static int
xdfs_rwcmd_copyin(struct dadkio_rwcmd * rwcmdp,caddr_t inaddr,int flag)325 xdfs_rwcmd_copyin(struct dadkio_rwcmd *rwcmdp, caddr_t inaddr, int flag)
326 {
327 switch (ddi_model_convert_from(flag)) {
328 case DDI_MODEL_ILP32: {
329 struct dadkio_rwcmd32 cmd32;
330
331 if (ddi_copyin(inaddr, &cmd32,
332 sizeof (struct dadkio_rwcmd32), flag)) {
333 return (EFAULT);
334 }
335
336 rwcmdp->cmd = cmd32.cmd;
337 rwcmdp->flags = cmd32.flags;
338 rwcmdp->blkaddr = (blkaddr_t)cmd32.blkaddr;
339 rwcmdp->buflen = cmd32.buflen;
340 rwcmdp->bufaddr = (caddr_t)(intptr_t)cmd32.bufaddr;
341 /*
342 * Note: we do not convert the 'status' field,
343 * as it should not contain valid data at this
344 * point.
345 */
346 bzero(&rwcmdp->status, sizeof (rwcmdp->status));
347 break;
348 }
349 case DDI_MODEL_NONE: {
350 if (ddi_copyin(inaddr, rwcmdp,
351 sizeof (struct dadkio_rwcmd), flag)) {
352 return (EFAULT);
353 }
354 }
355 }
356 return (0);
357 }
358
359 /*
360 * xdfs_rwcmd_copyout() is a duplicate of rwcmd_copyout().
361 */
362 static int
xdfs_rwcmd_copyout(struct dadkio_rwcmd * rwcmdp,caddr_t outaddr,int flag)363 xdfs_rwcmd_copyout(struct dadkio_rwcmd *rwcmdp, caddr_t outaddr, int flag)
364 {
365 switch (ddi_model_convert_from(flag)) {
366 case DDI_MODEL_ILP32: {
367 struct dadkio_rwcmd32 cmd32;
368
369 cmd32.cmd = rwcmdp->cmd;
370 cmd32.flags = rwcmdp->flags;
371 cmd32.blkaddr = rwcmdp->blkaddr;
372 cmd32.buflen = rwcmdp->buflen;
373 ASSERT64(((uintptr_t)rwcmdp->bufaddr >> 32) == 0);
374 cmd32.bufaddr = (caddr32_t)(uintptr_t)rwcmdp->bufaddr;
375
376 cmd32.status.status = rwcmdp->status.status;
377 cmd32.status.resid = rwcmdp->status.resid;
378 cmd32.status.failed_blk_is_valid =
379 rwcmdp->status.failed_blk_is_valid;
380 cmd32.status.failed_blk = rwcmdp->status.failed_blk;
381 cmd32.status.fru_code_is_valid =
382 rwcmdp->status.fru_code_is_valid;
383 cmd32.status.fru_code = rwcmdp->status.fru_code;
384
385 bcopy(rwcmdp->status.add_error_info,
386 cmd32.status.add_error_info, DADKIO_ERROR_INFO_LEN);
387
388 if (ddi_copyout(&cmd32, outaddr,
389 sizeof (struct dadkio_rwcmd32), flag))
390 return (EFAULT);
391 break;
392 }
393 case DDI_MODEL_NONE: {
394 if (ddi_copyout(rwcmdp, outaddr,
395 sizeof (struct dadkio_rwcmd), flag))
396 return (EFAULT);
397 }
398 }
399 return (0);
400 }
401
402 static int
xdfs_dioctl_rwcmd(dev_t dev,intptr_t arg,int flag)403 xdfs_dioctl_rwcmd(dev_t dev, intptr_t arg, int flag)
404 {
405 struct dadkio_rwcmd *rwcmdp;
406 struct iovec aiov;
407 struct uio auio;
408 struct buf *bp;
409 int rw, status;
410
411 rwcmdp = kmem_alloc(sizeof (struct dadkio_rwcmd), KM_SLEEP);
412 status = xdfs_rwcmd_copyin(rwcmdp, (caddr_t)arg, flag);
413
414 if (status != 0)
415 goto out;
416
417 switch (rwcmdp->cmd) {
418 case DADKIO_RWCMD_READ:
419 case DADKIO_RWCMD_WRITE:
420 break;
421 default:
422 status = EINVAL;
423 goto out;
424 }
425
426 bzero((caddr_t)&aiov, sizeof (struct iovec));
427 aiov.iov_base = rwcmdp->bufaddr;
428 aiov.iov_len = rwcmdp->buflen;
429
430 bzero((caddr_t)&auio, sizeof (struct uio));
431 auio.uio_iov = &aiov;
432 auio.uio_iovcnt = 1;
433 auio.uio_loffset = (offset_t)rwcmdp->blkaddr * (offset_t)XB_BSIZE;
434 auio.uio_resid = rwcmdp->buflen;
435 auio.uio_segflg = (flag & FKIOCTL) ? UIO_SYSSPACE : UIO_USERSPACE;
436
437 /*
438 * Tell the xdf driver that this I/O request is using an absolute
439 * offset.
440 */
441 bp = getrbuf(KM_SLEEP);
442 bp->b_private = (void *)XB_SLICE_NONE;
443
444 rw = ((rwcmdp->cmd == DADKIO_RWCMD_WRITE) ? B_WRITE : B_READ);
445 status = physio(xdfs_strategy, bp, dev, rw, xdfs_minphys, &auio);
446
447 biofini(bp);
448 kmem_free(bp, sizeof (buf_t));
449
450 if (status == 0)
451 status = xdfs_rwcmd_copyout(rwcmdp, (caddr_t)arg, flag);
452
453 out:
454 kmem_free(rwcmdp, sizeof (struct dadkio_rwcmd));
455 return (status);
456 }
457
458
459 /*
460 * xdf_shell callback functions
461 */
462 /*ARGSUSED*/
463 int
xdfs_c_ioctl(xdfs_state_t * xsp,dev_t dev,int part,int cmd,intptr_t arg,int flag,cred_t * credp,int * rvalp,boolean_t * done)464 xdfs_c_ioctl(xdfs_state_t *xsp, dev_t dev, int part,
465 int cmd, intptr_t arg, int flag, cred_t *credp, int *rvalp, boolean_t *done)
466 {
467 *done = B_TRUE;
468 switch (cmd) {
469 default:
470 *done = B_FALSE;
471 return (0);
472 case DKIOCLOCK:
473 case DKIOCUNLOCK:
474 case FDEJECT:
475 case DKIOCEJECT:
476 case CDROMEJECT: {
477 /* we don't support ejectable devices */
478 return (ENOTTY);
479 }
480 case DKIOCGETWCE:
481 case DKIOCSETWCE: {
482 /* we don't support write cache get/set */
483 return (EIO);
484 }
485 case DKIOCADDBAD: {
486 /*
487 * This is for ata/ide bad block handling. It is supposed
488 * to cause the driver to re-read the bad block list and
489 * alternate map after it has been updated. Our driver
490 * will refuse to attach to any disk which has a bad blocks
491 * list defined, so there really isn't much to do here.
492 */
493 return (0);
494 }
495 case DKIOCGETDEF: {
496 /*
497 * I can't actually find any code that utilizes this ioctl,
498 * hence we're leaving it explicitly unimplemented.
499 */
500 ASSERT("ioctl cmd unsupported by xdf shell: DKIOCGETDEF");
501 return (EIO);
502 }
503 case DIOCTL_RWCMD: {
504 /*
505 * This just seems to just be an alternate interface for
506 * reading and writing the disk. Great, another way to
507 * do the same thing...
508 */
509 return (xdfs_dioctl_rwcmd(dev, arg, flag));
510 }
511 case DKIOCINFO: {
512 int instance = ddi_get_instance(xsp->xdfss_dip);
513 dev_info_t *dip = xsp->xdfss_dip;
514 struct dk_cinfo info;
515 int rv;
516
517 /* Pass on the ioctl request, save the response */
518 if ((rv = ldi_ioctl(xsp->xdfss_tgt_lh[part],
519 cmd, (intptr_t)&info, FKIOCTL, credp, rvalp)) != 0)
520 return (rv);
521
522 /* Update controller info */
523 info.dki_cnum = ddi_get_instance(ddi_get_parent(dip));
524 (void) strlcpy(info.dki_cname,
525 ddi_get_name(ddi_get_parent(dip)), sizeof (info.dki_cname));
526
527 /* Update unit info. */
528 if (info.dki_ctype == DKC_VBD)
529 info.dki_ctype = DKC_DIRECT;
530 info.dki_unit = instance;
531 (void) strlcpy(info.dki_dname,
532 ddi_driver_name(dip), sizeof (info.dki_dname));
533 info.dki_addr = 1;
534
535 if (ddi_copyout(&info, (void *)arg, sizeof (info), flag))
536 return (EFAULT);
537 return (0);
538 }
539 } /* switch (cmd) */
540 /*NOTREACHED*/
541 }
542
543 /*
544 * xdfs_c_devid_setup() is a slightly modified copy of cmdk_devid_setup().
545 *
546 * Create and register the devid.
547 * There are 4 different ways we can get a device id:
548 * 1. Already have one - nothing to do
549 * 2. Build one from the drive's model and serial numbers
550 * 3. Read one from the disk (first sector of last track)
551 * 4. Fabricate one and write it on the disk.
552 * If any of these succeeds, register the deviceid
553 */
554 void
xdfs_c_devid_setup(xdfs_state_t * xsp)555 xdfs_c_devid_setup(xdfs_state_t *xsp)
556 {
557 int rc;
558
559 /* Try options until one succeeds, or all have failed */
560
561 /* 1. All done if already registered */
562
563 if (xsp->xdfss_tgt_devid != NULL)
564 return;
565
566 /* 2. Build a devid from the model and serial number */
567 rc = xdfs_devid_modser(xsp);
568 if (rc != DDI_SUCCESS) {
569 /* 3. Read devid from the disk, if present */
570 rc = xdfs_devid_read(xsp);
571
572 /* 4. otherwise make one up and write it on the disk */
573 if (rc != DDI_SUCCESS)
574 rc = xdfs_devid_fabricate(xsp);
575 }
576
577 /* If we managed to get a devid any of the above ways, register it */
578 if (rc == DDI_SUCCESS)
579 (void) ddi_devid_register(xsp->xdfss_dip, xsp->xdfss_tgt_devid);
580 }
581
582 int
xdfs_c_getpgeom(dev_info_t * dip,cmlb_geom_t * pgeom)583 xdfs_c_getpgeom(dev_info_t *dip, cmlb_geom_t *pgeom)
584 {
585 struct scsi_device *scsi_device;
586 struct tgdk_geom tgdk_geom;
587 opaque_t ctlobjp;
588 int err;
589
590 scsi_device = ddi_get_driver_private(dip);
591 ctlobjp = scsi_device->sd_address.a_hba_tran;
592 if ((err = CTL_IOCTL(ctlobjp,
593 DIOCTL_GETPHYGEOM, (uintptr_t)&tgdk_geom, FKIOCTL)) != 0)
594 return (err);
595
596 /* This driver won't work if this isn't true */
597 ASSERT(tgdk_geom.g_secsiz == XB_BSIZE);
598
599 pgeom->g_ncyl = tgdk_geom.g_cyl;
600 pgeom->g_acyl = tgdk_geom.g_acyl;
601 pgeom->g_nhead = tgdk_geom.g_head;
602 pgeom->g_nsect = tgdk_geom.g_sec;
603 pgeom->g_secsize = tgdk_geom.g_secsiz;
604 pgeom->g_capacity = tgdk_geom.g_cap;
605 pgeom->g_intrlv = 1;
606 pgeom->g_rpm = 3600;
607 return (0);
608 }
609
610 boolean_t
xdfs_c_bb_check(xdfs_state_t * xsp)611 xdfs_c_bb_check(xdfs_state_t *xsp)
612 {
613 struct alts_parttbl *ap;
614 diskaddr_t nblocks, blk;
615 uint32_t altused, altbase, altlast;
616 uint16_t vtoctag;
617 int alts;
618
619 /* find slice with V_ALTSCTR tag */
620 for (alts = 0; alts < NDKMAP; alts++) {
621
622 if (cmlb_partinfo(xsp->xdfss_cmlbhandle, alts,
623 &nblocks, &blk, NULL, &vtoctag, 0) != 0) {
624 /* no partition table exists */
625 return (B_FALSE);
626 }
627
628 if ((vtoctag == V_ALTSCTR) && (nblocks > 1))
629 break;
630 }
631 if (alts >= NDKMAP)
632 return (B_FALSE); /* no V_ALTSCTR slice defined */
633
634 /* read in ALTS label block */
635 ap = (struct alts_parttbl *)kmem_zalloc(NBPSCTR, KM_SLEEP);
636 if (xdfs_lb_rdwr(xsp->xdfss_dip, TG_READ, ap, blk, NBPSCTR, NULL) != 0)
637 goto err;
638
639 altused = ap->alts_ent_used; /* number of BB entries */
640 altbase = ap->alts_ent_base; /* blk offset from begin slice */
641 altlast = ap->alts_ent_end; /* blk offset to last block */
642
643 if ((altused == 0) || (altbase < 1) ||
644 (altbase > altlast) || (altlast >= nblocks))
645 goto err;
646
647 /* we found bad block mappins */
648 kmem_free(ap, NBPSCTR);
649 return (B_TRUE);
650
651 err:
652 kmem_free(ap, NBPSCTR);
653 return (B_FALSE);
654 }
655
656 char *
xdfs_c_cmlb_node_type(xdfs_state_t * xsp)657 xdfs_c_cmlb_node_type(xdfs_state_t *xsp)
658 {
659 return (xsp->xdfss_tgt_is_cd ? DDI_NT_CD : DDI_NT_BLOCK);
660 }
661
662 /*ARGSUSED*/
663 int
xdfs_c_cmlb_alter_behavior(xdfs_state_t * xsp)664 xdfs_c_cmlb_alter_behavior(xdfs_state_t *xsp)
665 {
666 return (xsp->xdfss_tgt_is_cd ?
667 0 : CMLB_CREATE_ALTSLICE_VTOC_16_DTYPE_DIRECT);
668 }
669
670 /*ARGSUSED*/
671 void
xdfs_c_attach(xdfs_state_t * xsp)672 xdfs_c_attach(xdfs_state_t *xsp)
673 {
674 }
675