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 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 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 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 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 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 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 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 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 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 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 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 * 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 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 672 xdfs_c_attach(xdfs_state_t *xsp) 673 { 674 } 675