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 /*
  23  * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
  24  */
  25 
  26 #include <sys/scsi/scsi.h>
  27 #include <sys/dktp/cm.h>
  28 #include <sys/dktp/quetypes.h>
  29 #include <sys/dktp/queue.h>
  30 #include <sys/dktp/fctypes.h>
  31 #include <sys/dktp/flowctrl.h>
  32 #include <sys/dktp/cmdev.h>
  33 #include <sys/dkio.h>
  34 #include <sys/dktp/tgdk.h>
  35 #include <sys/dktp/dadk.h>
  36 #include <sys/dktp/bbh.h>
  37 #include <sys/dktp/altsctr.h>
  38 #include <sys/dktp/cmdk.h>
  39 
  40 #include <sys/stat.h>
  41 #include <sys/vtoc.h>
  42 #include <sys/file.h>
  43 #include <sys/dktp/dadkio.h>
  44 #include <sys/aio_req.h>
  45 
  46 #include <sys/cmlb.h>
  47 
  48 /*
  49  * Local Static Data
  50  */
  51 #ifdef CMDK_DEBUG
  52 #define DENT    0x0001
  53 #define DIO     0x0002
  54 
  55 static  int     cmdk_debug = DIO;
  56 #endif
  57 
  58 #ifndef TRUE
  59 #define TRUE    1
  60 #endif
  61 
  62 #ifndef FALSE
  63 #define FALSE   0
  64 #endif
  65 
  66 /*
  67  * NDKMAP is the base number for accessing the fdisk partitions.
  68  * c?d?p0 --> cmdk@?,?:q
  69  */
  70 #define PARTITION0_INDEX        (NDKMAP + 0)
  71 
  72 #define DKTP_DATA               (dkp->dk_tgobjp)->tg_data
  73 #define DKTP_EXT                (dkp->dk_tgobjp)->tg_ext
  74 
  75 void *cmdk_state;
  76 
  77 /*
  78  * the cmdk_attach_mutex protects cmdk_max_instance in multi-threaded
  79  * attach situations
  80  */
  81 static kmutex_t cmdk_attach_mutex;
  82 static int cmdk_max_instance = 0;
  83 
  84 /*
  85  * Panic dumpsys state
  86  * There is only a single flag that is not mutex locked since
  87  * the system is prevented from thread switching and cmdk_dump
  88  * will only be called in a single threaded operation.
  89  */
  90 static int      cmdk_indump;
  91 
  92 /*
  93  * Local Function Prototypes
  94  */
  95 static int cmdk_create_obj(dev_info_t *dip, struct cmdk *dkp);
  96 static void cmdk_destroy_obj(dev_info_t *dip, struct cmdk *dkp);
  97 static void cmdkmin(struct buf *bp);
  98 static int cmdkrw(dev_t dev, struct uio *uio, int flag);
  99 static int cmdkarw(dev_t dev, struct aio_req *aio, int flag);
 100 
 101 /*
 102  * Bad Block Handling Functions Prototypes
 103  */
 104 static void cmdk_bbh_reopen(struct cmdk *dkp);
 105 static opaque_t cmdk_bbh_gethandle(opaque_t bbh_data, struct buf *bp);
 106 static bbh_cookie_t cmdk_bbh_htoc(opaque_t bbh_data, opaque_t handle);
 107 static void cmdk_bbh_freehandle(opaque_t bbh_data, opaque_t handle);
 108 static void cmdk_bbh_close(struct cmdk *dkp);
 109 static void cmdk_bbh_setalts_idx(struct cmdk *dkp);
 110 static int cmdk_bbh_bsearch(struct alts_ent *buf, int cnt, daddr32_t key);
 111 
 112 static struct bbh_objops cmdk_bbh_ops = {
 113         nulldev,
 114         nulldev,
 115         cmdk_bbh_gethandle,
 116         cmdk_bbh_htoc,
 117         cmdk_bbh_freehandle,
 118         0, 0
 119 };
 120 
 121 static int cmdkopen(dev_t *dev_p, int flag, int otyp, cred_t *credp);
 122 static int cmdkclose(dev_t dev, int flag, int otyp, cred_t *credp);
 123 static int cmdkstrategy(struct buf *bp);
 124 static int cmdkdump(dev_t dev, caddr_t addr, daddr_t blkno, int nblk);
 125 static int cmdkioctl(dev_t, int, intptr_t, int, cred_t *, int *);
 126 static int cmdkread(dev_t dev, struct uio *uio, cred_t *credp);
 127 static int cmdkwrite(dev_t dev, struct uio *uio, cred_t *credp);
 128 static int cmdk_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
 129     int mod_flags, char *name, caddr_t valuep, int *lengthp);
 130 static int cmdkaread(dev_t dev, struct aio_req *aio, cred_t *credp);
 131 static int cmdkawrite(dev_t dev, struct aio_req *aio, cred_t *credp);
 132 
 133 /*
 134  * Device driver ops vector
 135  */
 136 
 137 static struct cb_ops cmdk_cb_ops = {
 138         cmdkopen,               /* open */
 139         cmdkclose,              /* close */
 140         cmdkstrategy,           /* strategy */
 141         nodev,                  /* print */
 142         cmdkdump,               /* dump */
 143         cmdkread,               /* read */
 144         cmdkwrite,              /* write */
 145         cmdkioctl,              /* ioctl */
 146         nodev,                  /* devmap */
 147         nodev,                  /* mmap */
 148         nodev,                  /* segmap */
 149         nochpoll,               /* poll */
 150         cmdk_prop_op,           /* cb_prop_op */
 151         0,                      /* streamtab  */
 152         D_64BIT | D_MP | D_NEW, /* Driver comaptibility flag */
 153         CB_REV,                 /* cb_rev */
 154         cmdkaread,              /* async read */
 155         cmdkawrite              /* async write */
 156 };
 157 
 158 static int cmdkinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
 159     void **result);
 160 static int cmdkprobe(dev_info_t *dip);
 161 static int cmdkattach(dev_info_t *dip, ddi_attach_cmd_t cmd);
 162 static int cmdkdetach(dev_info_t *dip, ddi_detach_cmd_t cmd);
 163 
 164 static void cmdk_setup_pm(dev_info_t *dip, struct cmdk *dkp);
 165 static int cmdkresume(dev_info_t *dip);
 166 static int cmdksuspend(dev_info_t *dip);
 167 static int cmdkpower(dev_info_t *dip, int component, int level);
 168 
 169 struct dev_ops cmdk_ops = {
 170         DEVO_REV,               /* devo_rev, */
 171         0,                      /* refcnt  */
 172         cmdkinfo,               /* info */
 173         nulldev,                /* identify */
 174         cmdkprobe,              /* probe */
 175         cmdkattach,             /* attach */
 176         cmdkdetach,             /* detach */
 177         nodev,                  /* reset */
 178         &cmdk_cb_ops,               /* driver operations */
 179         (struct bus_ops *)0,    /* bus operations */
 180         cmdkpower,              /* power */
 181         ddi_quiesce_not_needed, /* quiesce */
 182 };
 183 
 184 /*
 185  * This is the loadable module wrapper.
 186  */
 187 #include <sys/modctl.h>
 188 
 189 #ifndef XPV_HVM_DRIVER
 190 static struct modldrv modldrv = {
 191         &mod_driverops,             /* Type of module. This one is a driver */
 192         "Common Direct Access Disk",
 193         &cmdk_ops,                          /* driver ops           */
 194 };
 195 
 196 static struct modlinkage modlinkage = {
 197         MODREV_1, (void *)&modldrv, NULL
 198 };
 199 
 200 
 201 #else /* XPV_HVM_DRIVER */
 202 static struct modlmisc modlmisc = {
 203         &mod_miscops,               /* Type of module. This one is a misc */
 204         "HVM Common Direct Access Disk",
 205 };
 206 
 207 static struct modlinkage modlinkage = {
 208         MODREV_1, (void *)&modlmisc, NULL
 209 };
 210 
 211 #endif /* XPV_HVM_DRIVER */
 212 
 213 /* Function prototypes for cmlb callbacks */
 214 
 215 static int cmdk_lb_rdwr(dev_info_t *dip, uchar_t cmd, void *bufaddr,
 216     diskaddr_t start, size_t length, void *tg_cookie);
 217 
 218 static int cmdk_lb_getinfo(dev_info_t *dip, int cmd,  void *arg,
 219     void *tg_cookie);
 220 
 221 static void cmdk_devid_setup(struct cmdk *dkp);
 222 static int cmdk_devid_modser(struct cmdk *dkp);
 223 static int cmdk_get_modser(struct cmdk *dkp, int ioccmd, char *buf, int len);
 224 static int cmdk_devid_fabricate(struct cmdk *dkp);
 225 static int cmdk_devid_read(struct cmdk *dkp);
 226 
 227 static cmlb_tg_ops_t cmdk_lb_ops = {
 228         TG_DK_OPS_VERSION_1,
 229         cmdk_lb_rdwr,
 230         cmdk_lb_getinfo
 231 };
 232 
 233 static boolean_t
 234 cmdk_isopen(struct cmdk *dkp, dev_t dev)
 235 {
 236         int             part, otyp;
 237         ulong_t         partbit;
 238 
 239         ASSERT(MUTEX_HELD((&dkp->dk_mutex)));
 240 
 241         part = CMDKPART(dev);
 242         partbit = 1 << part;
 243 
 244         /* account for close */
 245         if (dkp->dk_open_lyr[part] != 0)
 246                 return (B_TRUE);
 247         for (otyp = 0; otyp < OTYPCNT; otyp++)
 248                 if (dkp->dk_open_reg[otyp] & partbit)
 249                         return (B_TRUE);
 250         return (B_FALSE);
 251 }
 252 
 253 int
 254 _init(void)
 255 {
 256         int     rval;
 257 
 258 #ifndef XPV_HVM_DRIVER
 259         if (rval = ddi_soft_state_init(&cmdk_state, sizeof (struct cmdk), 7))
 260                 return (rval);
 261 #endif /* !XPV_HVM_DRIVER */
 262 
 263         mutex_init(&cmdk_attach_mutex, NULL, MUTEX_DRIVER, NULL);
 264         if ((rval = mod_install(&modlinkage)) != 0) {
 265                 mutex_destroy(&cmdk_attach_mutex);
 266 #ifndef XPV_HVM_DRIVER
 267                 ddi_soft_state_fini(&cmdk_state);
 268 #endif /* !XPV_HVM_DRIVER */
 269         }
 270         return (rval);
 271 }
 272 
 273 int
 274 _fini(void)
 275 {
 276         return (EBUSY);
 277 }
 278 
 279 int
 280 _info(struct modinfo *modinfop)
 281 {
 282         return (mod_info(&modlinkage, modinfop));
 283 }
 284 
 285 /*
 286  * Autoconfiguration Routines
 287  */
 288 static int
 289 cmdkprobe(dev_info_t *dip)
 290 {
 291         int     instance;
 292         int     status;
 293         struct  cmdk    *dkp;
 294 
 295         instance = ddi_get_instance(dip);
 296 
 297 #ifndef XPV_HVM_DRIVER
 298         if (ddi_get_soft_state(cmdk_state, instance))
 299                 return (DDI_PROBE_PARTIAL);
 300 
 301         if (ddi_soft_state_zalloc(cmdk_state, instance) != DDI_SUCCESS)
 302                 return (DDI_PROBE_PARTIAL);
 303 #endif /* !XPV_HVM_DRIVER */
 304 
 305         if ((dkp = ddi_get_soft_state(cmdk_state, instance)) == NULL)
 306                 return (DDI_PROBE_PARTIAL);
 307 
 308         mutex_init(&dkp->dk_mutex, NULL, MUTEX_DRIVER, NULL);
 309         rw_init(&dkp->dk_bbh_mutex, NULL, RW_DRIVER, NULL);
 310         dkp->dk_dip = dip;
 311         mutex_enter(&dkp->dk_mutex);
 312 
 313         dkp->dk_dev = makedevice(ddi_driver_major(dip),
 314             ddi_get_instance(dip) << CMDK_UNITSHF);
 315 
 316         /* linkage to dadk and strategy */
 317         if (cmdk_create_obj(dip, dkp) != DDI_SUCCESS) {
 318                 mutex_exit(&dkp->dk_mutex);
 319                 mutex_destroy(&dkp->dk_mutex);
 320                 rw_destroy(&dkp->dk_bbh_mutex);
 321 #ifndef XPV_HVM_DRIVER
 322                 ddi_soft_state_free(cmdk_state, instance);
 323 #endif /* !XPV_HVM_DRIVER */
 324                 return (DDI_PROBE_PARTIAL);
 325         }
 326 
 327         status = dadk_probe(DKTP_DATA, KM_NOSLEEP);
 328         if (status != DDI_PROBE_SUCCESS) {
 329                 cmdk_destroy_obj(dip, dkp);     /* dadk/strategy linkage  */
 330                 mutex_exit(&dkp->dk_mutex);
 331                 mutex_destroy(&dkp->dk_mutex);
 332                 rw_destroy(&dkp->dk_bbh_mutex);
 333 #ifndef XPV_HVM_DRIVER
 334                 ddi_soft_state_free(cmdk_state, instance);
 335 #endif /* !XPV_HVM_DRIVER */
 336                 return (status);
 337         }
 338 
 339         mutex_exit(&dkp->dk_mutex);
 340 #ifdef CMDK_DEBUG
 341         if (cmdk_debug & DENT)
 342                 PRF("cmdkprobe: instance= %d name= `%s`\n",
 343                     instance, ddi_get_name_addr(dip));
 344 #endif
 345         return (status);
 346 }
 347 
 348 static int
 349 cmdkattach(dev_info_t *dip, ddi_attach_cmd_t cmd)
 350 {
 351         int             instance;
 352         struct          cmdk *dkp;
 353         char            *node_type;
 354 
 355         switch (cmd) {
 356         case DDI_ATTACH:
 357                 break;
 358         case DDI_RESUME:
 359                 return (cmdkresume(dip));
 360         default:
 361                 return (DDI_FAILURE);
 362         }
 363 
 364         instance = ddi_get_instance(dip);
 365         if (!(dkp = ddi_get_soft_state(cmdk_state, instance)))
 366                 return (DDI_FAILURE);
 367 
 368         dkp->dk_pm_level = CMDK_SPINDLE_UNINIT;
 369         mutex_init(&dkp->dk_mutex, NULL, MUTEX_DRIVER, NULL);
 370 
 371         mutex_enter(&dkp->dk_mutex);
 372 
 373         /* dadk_attach is an empty function that only returns SUCCESS */
 374         (void) dadk_attach(DKTP_DATA);
 375 
 376         node_type = (DKTP_EXT->tg_nodetype);
 377 
 378         /*
 379          * this open allows cmlb to read the device
 380          * and determine the label types
 381          * so that cmlb can create minor nodes for device
 382          */
 383 
 384         /* open the target disk  */
 385         if (dadk_open(DKTP_DATA, 0) != DDI_SUCCESS)
 386                 goto fail2;
 387 
 388 #ifdef _ILP32
 389         {
 390                 struct  tgdk_geom phyg;
 391                 (void) dadk_getphygeom(DKTP_DATA, &phyg);
 392                 if ((phyg.g_cap - 1) > DK_MAX_BLOCKS) {
 393                         (void) dadk_close(DKTP_DATA);
 394                         goto fail2;
 395                 }
 396         }
 397 #endif
 398 
 399 
 400         /* mark as having opened target */
 401         dkp->dk_flag |= CMDK_TGDK_OPEN;
 402 
 403         cmlb_alloc_handle((cmlb_handle_t *)&dkp->dk_cmlbhandle);
 404 
 405         if (cmlb_attach(dip,
 406             &cmdk_lb_ops,
 407             DTYPE_DIRECT,               /* device_type */
 408             B_FALSE,                    /* removable */
 409             B_FALSE,                    /* hot pluggable XXX */
 410             node_type,
 411             CMLB_CREATE_ALTSLICE_VTOC_16_DTYPE_DIRECT,  /* alter_behaviour */
 412             dkp->dk_cmlbhandle,
 413             0) != 0)
 414                 goto fail1;
 415 
 416         /* Calling validate will create minor nodes according to disk label */
 417         (void) cmlb_validate(dkp->dk_cmlbhandle, 0, 0);
 418 
 419         /* set bbh (Bad Block Handling) */
 420         cmdk_bbh_reopen(dkp);
 421 
 422         /* setup devid string */
 423         cmdk_devid_setup(dkp);
 424 
 425         mutex_enter(&cmdk_attach_mutex);
 426         if (instance > cmdk_max_instance)
 427                 cmdk_max_instance = instance;
 428         mutex_exit(&cmdk_attach_mutex);
 429 
 430         mutex_exit(&dkp->dk_mutex);
 431 
 432         /*
 433          * Add a zero-length attribute to tell the world we support
 434          * kernel ioctls (for layered drivers)
 435          */
 436         (void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
 437             DDI_KERNEL_IOCTL, NULL, 0);
 438         ddi_report_dev(dip);
 439 
 440         /*
 441          * Initialize power management
 442          */
 443         mutex_init(&dkp->dk_pm_mutex, NULL, MUTEX_DRIVER, NULL);
 444         cv_init(&dkp->dk_suspend_cv,   NULL, CV_DRIVER, NULL);
 445         cmdk_setup_pm(dip, dkp);
 446 
 447         return (DDI_SUCCESS);
 448 
 449 fail1:
 450         cmlb_free_handle(&dkp->dk_cmlbhandle);
 451         (void) dadk_close(DKTP_DATA);
 452 fail2:
 453         cmdk_destroy_obj(dip, dkp);
 454         rw_destroy(&dkp->dk_bbh_mutex);
 455         mutex_exit(&dkp->dk_mutex);
 456         mutex_destroy(&dkp->dk_mutex);
 457 #ifndef XPV_HVM_DRIVER
 458         ddi_soft_state_free(cmdk_state, instance);
 459 #endif /* !XPV_HVM_DRIVER */
 460         return (DDI_FAILURE);
 461 }
 462 
 463 
 464 static int
 465 cmdkdetach(dev_info_t *dip, ddi_detach_cmd_t cmd)
 466 {
 467         struct cmdk     *dkp;
 468         int             instance;
 469         int             max_instance;
 470 
 471         switch (cmd) {
 472         case DDI_DETACH:
 473                 /* return (DDI_FAILURE); */
 474                 break;
 475         case DDI_SUSPEND:
 476                 return (cmdksuspend(dip));
 477         default:
 478 #ifdef CMDK_DEBUG
 479                 if (cmdk_debug & DIO) {
 480                         PRF("cmdkdetach: cmd = %d unknown\n", cmd);
 481                 }
 482 #endif
 483                 return (DDI_FAILURE);
 484         }
 485 
 486         mutex_enter(&cmdk_attach_mutex);
 487         max_instance = cmdk_max_instance;
 488         mutex_exit(&cmdk_attach_mutex);
 489 
 490         /* check if any instance of driver is open */
 491         for (instance = 0; instance < max_instance; instance++) {
 492                 dkp = ddi_get_soft_state(cmdk_state, instance);
 493                 if (!dkp)
 494                         continue;
 495                 if (dkp->dk_flag & CMDK_OPEN)
 496                         return (DDI_FAILURE);
 497         }
 498 
 499         instance = ddi_get_instance(dip);
 500         if (!(dkp = ddi_get_soft_state(cmdk_state, instance)))
 501                 return (DDI_SUCCESS);
 502 
 503         mutex_enter(&dkp->dk_mutex);
 504 
 505         /*
 506          * The cmdk_part_info call at the end of cmdkattach may have
 507          * caused cmdk_reopen to do a TGDK_OPEN, make sure we close on
 508          * detach for case when cmdkopen/cmdkclose never occurs.
 509          */
 510         if (dkp->dk_flag & CMDK_TGDK_OPEN) {
 511                 dkp->dk_flag &= ~CMDK_TGDK_OPEN;
 512                 (void) dadk_close(DKTP_DATA);
 513         }
 514 
 515         cmlb_detach(dkp->dk_cmlbhandle, 0);
 516         cmlb_free_handle(&dkp->dk_cmlbhandle);
 517         ddi_prop_remove_all(dip);
 518 
 519         cmdk_destroy_obj(dip, dkp);     /* dadk/strategy linkage  */
 520 
 521         /*
 522          * free the devid structure if allocated before
 523          */
 524         if (dkp->dk_devid) {
 525                 ddi_devid_free(dkp->dk_devid);
 526                 dkp->dk_devid = NULL;
 527         }
 528 
 529         mutex_exit(&dkp->dk_mutex);
 530         mutex_destroy(&dkp->dk_mutex);
 531         rw_destroy(&dkp->dk_bbh_mutex);
 532         mutex_destroy(&dkp->dk_pm_mutex);
 533         cv_destroy(&dkp->dk_suspend_cv);
 534 #ifndef XPV_HVM_DRIVER
 535         ddi_soft_state_free(cmdk_state, instance);
 536 #endif /* !XPV_HVM_DRIVER */
 537 
 538         return (DDI_SUCCESS);
 539 }
 540 
 541 static int
 542 cmdkinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
 543 {
 544         dev_t           dev = (dev_t)arg;
 545         int             instance;
 546         struct  cmdk    *dkp;
 547 
 548 #ifdef lint
 549         dip = dip;      /* no one ever uses this */
 550 #endif
 551 #ifdef CMDK_DEBUG
 552         if (cmdk_debug & DENT)
 553                 PRF("cmdkinfo: call\n");
 554 #endif
 555         instance = CMDKUNIT(dev);
 556 
 557         switch (infocmd) {
 558                 case DDI_INFO_DEVT2DEVINFO:
 559                         if (!(dkp = ddi_get_soft_state(cmdk_state, instance)))
 560                                 return (DDI_FAILURE);
 561                         *result = (void *) dkp->dk_dip;
 562                         break;
 563                 case DDI_INFO_DEVT2INSTANCE:
 564                         *result = (void *)(intptr_t)instance;
 565                         break;
 566                 default:
 567                         return (DDI_FAILURE);
 568         }
 569         return (DDI_SUCCESS);
 570 }
 571 
 572 /*
 573  * Initialize the power management components
 574  */
 575 static void
 576 cmdk_setup_pm(dev_info_t *dip, struct cmdk *dkp)
 577 {
 578         char *pm_comp[] = { "NAME=cmdk", "0=off", "1=on", NULL };
 579 
 580         /*
 581          * Since the cmdk device does not the 'reg' property,
 582          * cpr will not call its DDI_SUSPEND/DDI_RESUME entries.
 583          * The following code is to tell cpr that this device
 584          * DOES need to be suspended and resumed.
 585          */
 586         (void) ddi_prop_update_string(DDI_DEV_T_NONE, dip,
 587             "pm-hardware-state", "needs-suspend-resume");
 588 
 589         if (ddi_prop_update_string_array(DDI_DEV_T_NONE, dip,
 590             "pm-components", pm_comp, 3) == DDI_PROP_SUCCESS) {
 591                 if (pm_raise_power(dip, 0, CMDK_SPINDLE_ON) == DDI_SUCCESS) {
 592                         mutex_enter(&dkp->dk_pm_mutex);
 593                         dkp->dk_pm_level = CMDK_SPINDLE_ON;
 594                         dkp->dk_pm_is_enabled = 1;
 595                         mutex_exit(&dkp->dk_pm_mutex);
 596                 } else {
 597                         mutex_enter(&dkp->dk_pm_mutex);
 598                         dkp->dk_pm_level = CMDK_SPINDLE_OFF;
 599                         dkp->dk_pm_is_enabled = 0;
 600                         mutex_exit(&dkp->dk_pm_mutex);
 601                 }
 602         } else {
 603                 mutex_enter(&dkp->dk_pm_mutex);
 604                 dkp->dk_pm_level = CMDK_SPINDLE_UNINIT;
 605                 dkp->dk_pm_is_enabled = 0;
 606                 mutex_exit(&dkp->dk_pm_mutex);
 607         }
 608 }
 609 
 610 /*
 611  * suspend routine, it will be run when get the command
 612  * DDI_SUSPEND at detach(9E) from system power management
 613  */
 614 static int
 615 cmdksuspend(dev_info_t *dip)
 616 {
 617         struct cmdk     *dkp;
 618         int             instance;
 619         clock_t         count = 0;
 620 
 621         instance = ddi_get_instance(dip);
 622         if (!(dkp = ddi_get_soft_state(cmdk_state, instance)))
 623                 return (DDI_FAILURE);
 624         mutex_enter(&dkp->dk_mutex);
 625         if (dkp->dk_flag & CMDK_SUSPEND) {
 626                 mutex_exit(&dkp->dk_mutex);
 627                 return (DDI_SUCCESS);
 628         }
 629         dkp->dk_flag |= CMDK_SUSPEND;
 630 
 631         /* need to wait a while */
 632         while (dadk_getcmds(DKTP_DATA) != 0) {
 633                 delay(drv_sectohz(1));
 634                 if (count > 60) {
 635                         dkp->dk_flag &= ~CMDK_SUSPEND;
 636                         cv_broadcast(&dkp->dk_suspend_cv);
 637                         mutex_exit(&dkp->dk_mutex);
 638                         return (DDI_FAILURE);
 639                 }
 640                 count++;
 641         }
 642         mutex_exit(&dkp->dk_mutex);
 643         return (DDI_SUCCESS);
 644 }
 645 
 646 /*
 647  * resume routine, it will be run when get the command
 648  * DDI_RESUME at attach(9E) from system power management
 649  */
 650 static int
 651 cmdkresume(dev_info_t *dip)
 652 {
 653         struct cmdk     *dkp;
 654         int             instance;
 655 
 656         instance = ddi_get_instance(dip);
 657         if (!(dkp = ddi_get_soft_state(cmdk_state, instance)))
 658                 return (DDI_FAILURE);
 659         mutex_enter(&dkp->dk_mutex);
 660         if (!(dkp->dk_flag & CMDK_SUSPEND)) {
 661                 mutex_exit(&dkp->dk_mutex);
 662                 return (DDI_FAILURE);
 663         }
 664         dkp->dk_pm_level = CMDK_SPINDLE_ON;
 665         dkp->dk_flag &= ~CMDK_SUSPEND;
 666         cv_broadcast(&dkp->dk_suspend_cv);
 667         mutex_exit(&dkp->dk_mutex);
 668         return (DDI_SUCCESS);
 669 
 670 }
 671 
 672 /*
 673  * power management entry point, it was used to
 674  * change power management component.
 675  * Actually, the real hard drive suspend/resume
 676  * was handled in ata, so this function is not
 677  * doing any real work other than verifying that
 678  * the disk is idle.
 679  */
 680 static int
 681 cmdkpower(dev_info_t *dip, int component, int level)
 682 {
 683         struct cmdk     *dkp;
 684         int             instance;
 685 
 686         instance = ddi_get_instance(dip);
 687         if (!(dkp = ddi_get_soft_state(cmdk_state, instance)) ||
 688             component != 0 || level > CMDK_SPINDLE_ON ||
 689             level < CMDK_SPINDLE_OFF) {
 690                 return (DDI_FAILURE);
 691         }
 692 
 693         mutex_enter(&dkp->dk_pm_mutex);
 694         if (dkp->dk_pm_is_enabled && dkp->dk_pm_level == level) {
 695                 mutex_exit(&dkp->dk_pm_mutex);
 696                 return (DDI_SUCCESS);
 697         }
 698         mutex_exit(&dkp->dk_pm_mutex);
 699 
 700         if ((level == CMDK_SPINDLE_OFF) &&
 701             (dadk_getcmds(DKTP_DATA) != 0)) {
 702                 return (DDI_FAILURE);
 703         }
 704 
 705         mutex_enter(&dkp->dk_pm_mutex);
 706         dkp->dk_pm_level = level;
 707         mutex_exit(&dkp->dk_pm_mutex);
 708         return (DDI_SUCCESS);
 709 }
 710 
 711 static int
 712 cmdk_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int mod_flags,
 713     char *name, caddr_t valuep, int *lengthp)
 714 {
 715         struct  cmdk    *dkp;
 716 
 717 #ifdef CMDK_DEBUG
 718         if (cmdk_debug & DENT)
 719                 PRF("cmdk_prop_op: call\n");
 720 #endif
 721 
 722         dkp = ddi_get_soft_state(cmdk_state, ddi_get_instance(dip));
 723         if (dkp == NULL)
 724                 return (ddi_prop_op(dev, dip, prop_op, mod_flags,
 725                     name, valuep, lengthp));
 726 
 727         return (cmlb_prop_op(dkp->dk_cmlbhandle,
 728             dev, dip, prop_op, mod_flags, name, valuep, lengthp,
 729             CMDKPART(dev), NULL));
 730 }
 731 
 732 /*
 733  * dump routine
 734  */
 735 static int
 736 cmdkdump(dev_t dev, caddr_t addr, daddr_t blkno, int nblk)
 737 {
 738         int             instance;
 739         struct  cmdk    *dkp;
 740         diskaddr_t      p_lblksrt;
 741         diskaddr_t      p_lblkcnt;
 742         struct  buf     local;
 743         struct  buf     *bp;
 744 
 745 #ifdef CMDK_DEBUG
 746         if (cmdk_debug & DENT)
 747                 PRF("cmdkdump: call\n");
 748 #endif
 749         instance = CMDKUNIT(dev);
 750         if (!(dkp = ddi_get_soft_state(cmdk_state, instance)) || (blkno < 0))
 751                 return (ENXIO);
 752 
 753         if (cmlb_partinfo(
 754             dkp->dk_cmlbhandle,
 755             CMDKPART(dev),
 756             &p_lblkcnt,
 757             &p_lblksrt,
 758             NULL,
 759             NULL,
 760             0)) {
 761                 return (ENXIO);
 762         }
 763 
 764         if ((blkno+nblk) > p_lblkcnt)
 765                 return (EINVAL);
 766 
 767         cmdk_indump = 1;        /* Tell disk targets we are panic dumpping */
 768 
 769         bp = &local;
 770         bzero(bp, sizeof (*bp));
 771         bp->b_flags = B_BUSY;
 772         bp->b_un.b_addr = addr;
 773         bp->b_bcount = nblk << SCTRSHFT;
 774         SET_BP_SEC(bp, ((ulong_t)(p_lblksrt + blkno)));
 775 
 776         (void) dadk_dump(DKTP_DATA, bp);
 777         return (bp->b_error);
 778 }
 779 
 780 /*
 781  * Copy in the dadkio_rwcmd according to the user's data model.  If needed,
 782  * convert it for our internal use.
 783  */
 784 static int
 785 rwcmd_copyin(struct dadkio_rwcmd *rwcmdp, caddr_t inaddr, int flag)
 786 {
 787         switch (ddi_model_convert_from(flag)) {
 788                 case DDI_MODEL_ILP32: {
 789                         struct dadkio_rwcmd32 cmd32;
 790 
 791                         if (ddi_copyin(inaddr, &cmd32,
 792                             sizeof (struct dadkio_rwcmd32), flag)) {
 793                                 return (EFAULT);
 794                         }
 795 
 796                         rwcmdp->cmd = cmd32.cmd;
 797                         rwcmdp->flags = cmd32.flags;
 798                         rwcmdp->blkaddr = (blkaddr_t)cmd32.blkaddr;
 799                         rwcmdp->buflen = cmd32.buflen;
 800                         rwcmdp->bufaddr = (caddr_t)(intptr_t)cmd32.bufaddr;
 801                         /*
 802                          * Note: we do not convert the 'status' field,
 803                          * as it should not contain valid data at this
 804                          * point.
 805                          */
 806                         bzero(&rwcmdp->status, sizeof (rwcmdp->status));
 807                         break;
 808                 }
 809                 case DDI_MODEL_NONE: {
 810                         if (ddi_copyin(inaddr, rwcmdp,
 811                             sizeof (struct dadkio_rwcmd), flag)) {
 812                                 return (EFAULT);
 813                         }
 814                 }
 815         }
 816         return (0);
 817 }
 818 
 819 /*
 820  * If necessary, convert the internal rwcmdp and status to the appropriate
 821  * data model and copy it out to the user.
 822  */
 823 static int
 824 rwcmd_copyout(struct dadkio_rwcmd *rwcmdp, caddr_t outaddr, int flag)
 825 {
 826         switch (ddi_model_convert_from(flag)) {
 827                 case DDI_MODEL_ILP32: {
 828                         struct dadkio_rwcmd32 cmd32;
 829 
 830                         cmd32.cmd = rwcmdp->cmd;
 831                         cmd32.flags = rwcmdp->flags;
 832                         cmd32.blkaddr = rwcmdp->blkaddr;
 833                         cmd32.buflen = rwcmdp->buflen;
 834                         ASSERT64(((uintptr_t)rwcmdp->bufaddr >> 32) == 0);
 835                         cmd32.bufaddr = (caddr32_t)(uintptr_t)rwcmdp->bufaddr;
 836 
 837                         cmd32.status.status = rwcmdp->status.status;
 838                         cmd32.status.resid = rwcmdp->status.resid;
 839                         cmd32.status.failed_blk_is_valid =
 840                             rwcmdp->status.failed_blk_is_valid;
 841                         cmd32.status.failed_blk = rwcmdp->status.failed_blk;
 842                         cmd32.status.fru_code_is_valid =
 843                             rwcmdp->status.fru_code_is_valid;
 844                         cmd32.status.fru_code = rwcmdp->status.fru_code;
 845 
 846                         bcopy(rwcmdp->status.add_error_info,
 847                             cmd32.status.add_error_info, DADKIO_ERROR_INFO_LEN);
 848 
 849                         if (ddi_copyout(&cmd32, outaddr,
 850                             sizeof (struct dadkio_rwcmd32), flag))
 851                                 return (EFAULT);
 852                         break;
 853                 }
 854                 case DDI_MODEL_NONE: {
 855                         if (ddi_copyout(rwcmdp, outaddr,
 856                             sizeof (struct dadkio_rwcmd), flag))
 857                         return (EFAULT);
 858                 }
 859         }
 860         return (0);
 861 }
 862 
 863 /*
 864  * ioctl routine
 865  */
 866 static int
 867 cmdkioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *credp, int *rvalp)
 868 {
 869         int             instance;
 870         struct scsi_device *devp;
 871         struct cmdk     *dkp;
 872         char            data[NBPSCTR];
 873 
 874         instance = CMDKUNIT(dev);
 875         if (!(dkp = ddi_get_soft_state(cmdk_state, instance)))
 876                 return (ENXIO);
 877 
 878         mutex_enter(&dkp->dk_mutex);
 879         while (dkp->dk_flag & CMDK_SUSPEND) {
 880                 cv_wait(&dkp->dk_suspend_cv, &dkp->dk_mutex);
 881         }
 882         mutex_exit(&dkp->dk_mutex);
 883 
 884         bzero(data, sizeof (data));
 885 
 886         switch (cmd) {
 887 
 888         case DKIOCGMEDIAINFO: {
 889                 struct dk_minfo media_info;
 890                 struct  tgdk_geom phyg;
 891 
 892                 /* dadk_getphygeom always returns success */
 893                 (void) dadk_getphygeom(DKTP_DATA, &phyg);
 894 
 895                 media_info.dki_lbsize = phyg.g_secsiz;
 896                 media_info.dki_capacity = phyg.g_cap;
 897                 media_info.dki_media_type = DK_FIXED_DISK;
 898 
 899                 if (ddi_copyout(&media_info, (void *)arg,
 900                     sizeof (struct dk_minfo), flag)) {
 901                         return (EFAULT);
 902                 } else {
 903                         return (0);
 904                 }
 905         }
 906 
 907         case DKIOCINFO: {
 908                 struct dk_cinfo *info = (struct dk_cinfo *)data;
 909 
 910                 /* controller information */
 911                 info->dki_ctype = (DKTP_EXT->tg_ctype);
 912                 info->dki_cnum = ddi_get_instance(ddi_get_parent(dkp->dk_dip));
 913                 (void) strcpy(info->dki_cname,
 914                     ddi_get_name(ddi_get_parent(dkp->dk_dip)));
 915 
 916                 /* Unit Information */
 917                 info->dki_unit = ddi_get_instance(dkp->dk_dip);
 918                 devp = ddi_get_driver_private(dkp->dk_dip);
 919                 info->dki_slave = (CMDEV_TARG(devp)<<3) | CMDEV_LUN(devp);
 920                 (void) strcpy(info->dki_dname, ddi_driver_name(dkp->dk_dip));
 921                 info->dki_flags = DKI_FMTVOL;
 922                 info->dki_partition = CMDKPART(dev);
 923 
 924                 info->dki_maxtransfer = maxphys / DEV_BSIZE;
 925                 info->dki_addr = 1;
 926                 info->dki_space = 0;
 927                 info->dki_prio = 0;
 928                 info->dki_vec = 0;
 929 
 930                 if (ddi_copyout(data, (void *)arg, sizeof (*info), flag))
 931                         return (EFAULT);
 932                 else
 933                         return (0);
 934         }
 935 
 936         case DKIOCSTATE: {
 937                 int     state;
 938                 int     rval;
 939                 diskaddr_t      p_lblksrt;
 940                 diskaddr_t      p_lblkcnt;
 941 
 942                 if (ddi_copyin((void *)arg, &state, sizeof (int), flag))
 943                         return (EFAULT);
 944 
 945                 /* dadk_check_media blocks until state changes */
 946                 if (rval = dadk_check_media(DKTP_DATA, &state))
 947                         return (rval);
 948 
 949                 if (state == DKIO_INSERTED) {
 950 
 951                         if (cmlb_validate(dkp->dk_cmlbhandle, 0, 0) != 0)
 952                                 return (ENXIO);
 953 
 954                         if (cmlb_partinfo(dkp->dk_cmlbhandle, CMDKPART(dev),
 955                             &p_lblkcnt, &p_lblksrt, NULL, NULL, 0))
 956                                 return (ENXIO);
 957 
 958                         if (p_lblkcnt <= 0)
 959                                 return (ENXIO);
 960                 }
 961 
 962                 if (ddi_copyout(&state, (caddr_t)arg, sizeof (int), flag))
 963                         return (EFAULT);
 964 
 965                 return (0);
 966         }
 967 
 968         /*
 969          * is media removable?
 970          */
 971         case DKIOCREMOVABLE: {
 972                 int i;
 973 
 974                 i = (DKTP_EXT->tg_rmb) ? 1 : 0;
 975 
 976                 if (ddi_copyout(&i, (caddr_t)arg, sizeof (int), flag))
 977                         return (EFAULT);
 978 
 979                 return (0);
 980         }
 981 
 982         case DKIOCADDBAD:
 983                 /*
 984                  * This is not an update mechanism to add bad blocks
 985                  * to the bad block structures stored on disk.
 986                  *
 987                  * addbadsec(1M) will update the bad block data on disk
 988                  * and use this ioctl to force the driver to re-initialize
 989                  * the list of bad blocks in the driver.
 990                  */
 991 
 992                 /* start BBH */
 993                 cmdk_bbh_reopen(dkp);
 994                 return (0);
 995 
 996         case DKIOCG_PHYGEOM:
 997         case DKIOCG_VIRTGEOM:
 998         case DKIOCGGEOM:
 999         case DKIOCSGEOM:
1000         case DKIOCGAPART:
1001         case DKIOCSAPART:
1002         case DKIOCGVTOC:
1003         case DKIOCSVTOC:
1004         case DKIOCPARTINFO:
1005         case DKIOCGEXTVTOC:
1006         case DKIOCSEXTVTOC:
1007         case DKIOCEXTPARTINFO:
1008         case DKIOCGMBOOT:
1009         case DKIOCSMBOOT:
1010         case DKIOCGETEFI:
1011         case DKIOCSETEFI:
1012         case DKIOCPARTITION:
1013         case DKIOCSETEXTPART:
1014         {
1015                 int rc;
1016 
1017                 rc = cmlb_ioctl(dkp->dk_cmlbhandle, dev, cmd, arg, flag,
1018                     credp, rvalp, 0);
1019                 if (cmd == DKIOCSVTOC || cmd == DKIOCSEXTVTOC)
1020                         cmdk_devid_setup(dkp);
1021                 return (rc);
1022         }
1023 
1024         case DIOCTL_RWCMD: {
1025                 struct  dadkio_rwcmd *rwcmdp;
1026                 int     status;
1027 
1028                 rwcmdp = kmem_alloc(sizeof (struct dadkio_rwcmd), KM_SLEEP);
1029 
1030                 status = rwcmd_copyin(rwcmdp, (caddr_t)arg, flag);
1031 
1032                 if (status == 0) {
1033                         bzero(&(rwcmdp->status), sizeof (struct dadkio_status));
1034                         status = dadk_ioctl(DKTP_DATA,
1035                             dev,
1036                             cmd,
1037                             (uintptr_t)rwcmdp,
1038                             flag,
1039                             credp,
1040                             rvalp);
1041                 }
1042                 if (status == 0)
1043                         status = rwcmd_copyout(rwcmdp, (caddr_t)arg, flag);
1044 
1045                 kmem_free(rwcmdp, sizeof (struct dadkio_rwcmd));
1046                 return (status);
1047         }
1048 
1049         default:
1050                 return (dadk_ioctl(DKTP_DATA,
1051                     dev,
1052                     cmd,
1053                     arg,
1054                     flag,
1055                     credp,
1056                     rvalp));
1057         }
1058 }
1059 
1060 /*ARGSUSED1*/
1061 static int
1062 cmdkclose(dev_t dev, int flag, int otyp, cred_t *credp)
1063 {
1064         int             part;
1065         ulong_t         partbit;
1066         int             instance;
1067         struct cmdk     *dkp;
1068         int             lastclose = 1;
1069         int             i;
1070 
1071         instance = CMDKUNIT(dev);
1072         if (!(dkp = ddi_get_soft_state(cmdk_state, instance)) ||
1073             (otyp >= OTYPCNT))
1074                 return (ENXIO);
1075 
1076         mutex_enter(&dkp->dk_mutex);
1077 
1078         /* check if device has been opened */
1079         ASSERT(cmdk_isopen(dkp, dev));
1080         if (!(dkp->dk_flag & CMDK_OPEN)) {
1081                 mutex_exit(&dkp->dk_mutex);
1082                 return (ENXIO);
1083         }
1084 
1085         while (dkp->dk_flag & CMDK_SUSPEND) {
1086                 cv_wait(&dkp->dk_suspend_cv, &dkp->dk_mutex);
1087         }
1088 
1089         part = CMDKPART(dev);
1090         partbit = 1 << part;
1091 
1092         /* account for close */
1093         if (otyp == OTYP_LYR) {
1094                 ASSERT(dkp->dk_open_lyr[part] > 0);
1095                 if (dkp->dk_open_lyr[part])
1096                         dkp->dk_open_lyr[part]--;
1097         } else {
1098                 ASSERT((dkp->dk_open_reg[otyp] & partbit) != 0);
1099                 dkp->dk_open_reg[otyp] &= ~partbit;
1100         }
1101         dkp->dk_open_exl &= ~partbit;
1102 
1103         for (i = 0; i < CMDK_MAXPART; i++)
1104                 if (dkp->dk_open_lyr[i] != 0) {
1105                         lastclose = 0;
1106                         break;
1107                 }
1108 
1109         if (lastclose)
1110                 for (i = 0; i < OTYPCNT; i++)
1111                         if (dkp->dk_open_reg[i] != 0) {
1112                                 lastclose = 0;
1113                                 break;
1114                         }
1115 
1116         mutex_exit(&dkp->dk_mutex);
1117 
1118         if (lastclose)
1119                 cmlb_invalidate(dkp->dk_cmlbhandle, 0);
1120 
1121         return (DDI_SUCCESS);
1122 }
1123 
1124 /*ARGSUSED3*/
1125 static int
1126 cmdkopen(dev_t *dev_p, int flag, int otyp, cred_t *credp)
1127 {
1128         dev_t           dev = *dev_p;
1129         int             part;
1130         ulong_t         partbit;
1131         int             instance;
1132         struct  cmdk    *dkp;
1133         diskaddr_t      p_lblksrt;
1134         diskaddr_t      p_lblkcnt;
1135         int             i;
1136         int             nodelay;
1137 
1138         instance = CMDKUNIT(dev);
1139         if (!(dkp = ddi_get_soft_state(cmdk_state, instance)))
1140                 return (ENXIO);
1141 
1142         if (otyp >= OTYPCNT)
1143                 return (EINVAL);
1144 
1145         mutex_enter(&dkp->dk_mutex);
1146         while (dkp->dk_flag & CMDK_SUSPEND) {
1147                 cv_wait(&dkp->dk_suspend_cv, &dkp->dk_mutex);
1148         }
1149         mutex_exit(&dkp->dk_mutex);
1150 
1151         part = CMDKPART(dev);
1152         partbit = 1 << part;
1153         nodelay = (flag & (FNDELAY | FNONBLOCK));
1154 
1155         mutex_enter(&dkp->dk_mutex);
1156 
1157         if (cmlb_validate(dkp->dk_cmlbhandle, 0, 0) != 0) {
1158 
1159                 /* fail if not doing non block open */
1160                 if (!nodelay) {
1161                         mutex_exit(&dkp->dk_mutex);
1162                         return (ENXIO);
1163                 }
1164         } else if (cmlb_partinfo(dkp->dk_cmlbhandle, part, &p_lblkcnt,
1165             &p_lblksrt, NULL, NULL, 0) == 0) {
1166 
1167                 if (p_lblkcnt <= 0 && (!nodelay || otyp != OTYP_CHR)) {
1168                         mutex_exit(&dkp->dk_mutex);
1169                         return (ENXIO);
1170                 }
1171         } else {
1172                 /* fail if not doing non block open */
1173                 if (!nodelay) {
1174                         mutex_exit(&dkp->dk_mutex);
1175                         return (ENXIO);
1176                 }
1177         }
1178 
1179         if ((DKTP_EXT->tg_rdonly) && (flag & FWRITE)) {
1180                 mutex_exit(&dkp->dk_mutex);
1181                 return (EROFS);
1182         }
1183 
1184         /* check for part already opend exclusively */
1185         if (dkp->dk_open_exl & partbit)
1186                 goto excl_open_fail;
1187 
1188         /* check if we can establish exclusive open */
1189         if (flag & FEXCL) {
1190                 if (dkp->dk_open_lyr[part])
1191                         goto excl_open_fail;
1192                 for (i = 0; i < OTYPCNT; i++) {
1193                         if (dkp->dk_open_reg[i] & partbit)
1194                                 goto excl_open_fail;
1195                 }
1196         }
1197 
1198         /* open will succeed, account for open */
1199         dkp->dk_flag |= CMDK_OPEN;
1200         if (otyp == OTYP_LYR)
1201                 dkp->dk_open_lyr[part]++;
1202         else
1203                 dkp->dk_open_reg[otyp] |= partbit;
1204         if (flag & FEXCL)
1205                 dkp->dk_open_exl |= partbit;
1206 
1207         mutex_exit(&dkp->dk_mutex);
1208         return (DDI_SUCCESS);
1209 
1210 excl_open_fail:
1211         mutex_exit(&dkp->dk_mutex);
1212         return (EBUSY);
1213 }
1214 
1215 /*
1216  * read routine
1217  */
1218 /*ARGSUSED2*/
1219 static int
1220 cmdkread(dev_t dev, struct uio *uio, cred_t *credp)
1221 {
1222         return (cmdkrw(dev, uio, B_READ));
1223 }
1224 
1225 /*
1226  * async read routine
1227  */
1228 /*ARGSUSED2*/
1229 static int
1230 cmdkaread(dev_t dev, struct aio_req *aio, cred_t *credp)
1231 {
1232         return (cmdkarw(dev, aio, B_READ));
1233 }
1234 
1235 /*
1236  * write routine
1237  */
1238 /*ARGSUSED2*/
1239 static int
1240 cmdkwrite(dev_t dev, struct uio *uio, cred_t *credp)
1241 {
1242         return (cmdkrw(dev, uio, B_WRITE));
1243 }
1244 
1245 /*
1246  * async write routine
1247  */
1248 /*ARGSUSED2*/
1249 static int
1250 cmdkawrite(dev_t dev, struct aio_req *aio, cred_t *credp)
1251 {
1252         return (cmdkarw(dev, aio, B_WRITE));
1253 }
1254 
1255 static void
1256 cmdkmin(struct buf *bp)
1257 {
1258         if (bp->b_bcount > DK_MAXRECSIZE)
1259                 bp->b_bcount = DK_MAXRECSIZE;
1260 }
1261 
1262 static int
1263 cmdkrw(dev_t dev, struct uio *uio, int flag)
1264 {
1265         int             instance;
1266         struct  cmdk    *dkp;
1267 
1268         instance = CMDKUNIT(dev);
1269         if (!(dkp = ddi_get_soft_state(cmdk_state, instance)))
1270                 return (ENXIO);
1271 
1272         mutex_enter(&dkp->dk_mutex);
1273         while (dkp->dk_flag & CMDK_SUSPEND) {
1274                 cv_wait(&dkp->dk_suspend_cv, &dkp->dk_mutex);
1275         }
1276         mutex_exit(&dkp->dk_mutex);
1277 
1278         return (physio(cmdkstrategy, (struct buf *)0, dev, flag, cmdkmin, uio));
1279 }
1280 
1281 static int
1282 cmdkarw(dev_t dev, struct aio_req *aio, int flag)
1283 {
1284         int             instance;
1285         struct  cmdk    *dkp;
1286 
1287         instance = CMDKUNIT(dev);
1288         if (!(dkp = ddi_get_soft_state(cmdk_state, instance)))
1289                 return (ENXIO);
1290 
1291         mutex_enter(&dkp->dk_mutex);
1292         while (dkp->dk_flag & CMDK_SUSPEND) {
1293                 cv_wait(&dkp->dk_suspend_cv, &dkp->dk_mutex);
1294         }
1295         mutex_exit(&dkp->dk_mutex);
1296 
1297         return (aphysio(cmdkstrategy, anocancel, dev, flag, cmdkmin, aio));
1298 }
1299 
1300 /*
1301  * strategy routine
1302  */
1303 static int
1304 cmdkstrategy(struct buf *bp)
1305 {
1306         int             instance;
1307         struct  cmdk    *dkp;
1308         long            d_cnt;
1309         diskaddr_t      p_lblksrt;
1310         diskaddr_t      p_lblkcnt;
1311 
1312         instance = CMDKUNIT(bp->b_edev);
1313         if (cmdk_indump || !(dkp = ddi_get_soft_state(cmdk_state, instance)) ||
1314             (dkblock(bp) < 0)) {
1315                 bp->b_resid = bp->b_bcount;
1316                 SETBPERR(bp, ENXIO);
1317                 biodone(bp);
1318                 return (0);
1319         }
1320 
1321         mutex_enter(&dkp->dk_mutex);
1322         ASSERT(cmdk_isopen(dkp, bp->b_edev));
1323         while (dkp->dk_flag & CMDK_SUSPEND) {
1324                 cv_wait(&dkp->dk_suspend_cv, &dkp->dk_mutex);
1325         }
1326         mutex_exit(&dkp->dk_mutex);
1327 
1328         bp->b_flags &= ~(B_DONE|B_ERROR);
1329         bp->b_resid = 0;
1330         bp->av_back = NULL;
1331 
1332         /*
1333          * only re-read the vtoc if necessary (force == FALSE)
1334          */
1335         if (cmlb_partinfo(dkp->dk_cmlbhandle, CMDKPART(bp->b_edev),
1336             &p_lblkcnt, &p_lblksrt, NULL, NULL, 0)) {
1337                 SETBPERR(bp, ENXIO);
1338         }
1339 
1340         if ((bp->b_bcount & (NBPSCTR-1)) || (dkblock(bp) > p_lblkcnt))
1341                 SETBPERR(bp, ENXIO);
1342 
1343         if ((bp->b_flags & B_ERROR) || (dkblock(bp) == p_lblkcnt)) {
1344                 bp->b_resid = bp->b_bcount;
1345                 biodone(bp);
1346                 return (0);
1347         }
1348 
1349         d_cnt = bp->b_bcount >> SCTRSHFT;
1350         if ((dkblock(bp) + d_cnt) > p_lblkcnt) {
1351                 bp->b_resid = ((dkblock(bp) + d_cnt) - p_lblkcnt) << SCTRSHFT;
1352                 bp->b_bcount -= bp->b_resid;
1353         }
1354 
1355         SET_BP_SEC(bp, ((ulong_t)(p_lblksrt + dkblock(bp))));
1356         if (dadk_strategy(DKTP_DATA, bp) != DDI_SUCCESS) {
1357                 bp->b_resid += bp->b_bcount;
1358                 biodone(bp);
1359         }
1360         return (0);
1361 }
1362 
1363 static int
1364 cmdk_create_obj(dev_info_t *dip, struct cmdk *dkp)
1365 {
1366         struct scsi_device *devp;
1367         opaque_t        queobjp = NULL;
1368         opaque_t        flcobjp = NULL;
1369         char            que_keyvalp[64];
1370         int             que_keylen;
1371         char            flc_keyvalp[64];
1372         int             flc_keylen;
1373 
1374         ASSERT(mutex_owned(&dkp->dk_mutex));
1375 
1376         /* Create linkage to queueing routines based on property */
1377         que_keylen = sizeof (que_keyvalp);
1378         if (ddi_prop_op(DDI_DEV_T_NONE, dip, PROP_LEN_AND_VAL_BUF,
1379             DDI_PROP_CANSLEEP, "queue", que_keyvalp, &que_keylen) !=
1380             DDI_PROP_SUCCESS) {
1381                 cmn_err(CE_WARN, "cmdk_create_obj: queue property undefined");
1382                 return (DDI_FAILURE);
1383         }
1384         que_keyvalp[que_keylen] = (char)0;
1385 
1386         if (strcmp(que_keyvalp, "qfifo") == 0) {
1387                 queobjp = (opaque_t)qfifo_create();
1388         } else if (strcmp(que_keyvalp, "qsort") == 0) {
1389                 queobjp = (opaque_t)qsort_create();
1390         } else {
1391                 return (DDI_FAILURE);
1392         }
1393 
1394         /* Create linkage to dequeueing routines based on property */
1395         flc_keylen = sizeof (flc_keyvalp);
1396         if (ddi_prop_op(DDI_DEV_T_NONE, dip, PROP_LEN_AND_VAL_BUF,
1397             DDI_PROP_CANSLEEP, "flow_control", flc_keyvalp, &flc_keylen) !=
1398             DDI_PROP_SUCCESS) {
1399                 cmn_err(CE_WARN,
1400                     "cmdk_create_obj: flow-control property undefined");
1401                 return (DDI_FAILURE);
1402         }
1403 
1404         flc_keyvalp[flc_keylen] = (char)0;
1405 
1406         if (strcmp(flc_keyvalp, "dsngl") == 0) {
1407                 flcobjp = (opaque_t)dsngl_create();
1408         } else if (strcmp(flc_keyvalp, "dmult") == 0) {
1409                 flcobjp = (opaque_t)dmult_create();
1410         } else {
1411                 return (DDI_FAILURE);
1412         }
1413 
1414         /* populate bbh_obj object stored in dkp */
1415         dkp->dk_bbh_obj.bbh_data = dkp;
1416         dkp->dk_bbh_obj.bbh_ops = &cmdk_bbh_ops;
1417 
1418         /* create linkage to dadk */
1419         dkp->dk_tgobjp = (opaque_t)dadk_create();
1420 
1421         devp = ddi_get_driver_private(dip);
1422         (void) dadk_init(DKTP_DATA, devp, flcobjp, queobjp, &dkp->dk_bbh_obj,
1423             NULL);
1424 
1425         return (DDI_SUCCESS);
1426 }
1427 
1428 static void
1429 cmdk_destroy_obj(dev_info_t *dip, struct cmdk *dkp)
1430 {
1431         char            que_keyvalp[64];
1432         int             que_keylen;
1433         char            flc_keyvalp[64];
1434         int             flc_keylen;
1435 
1436         ASSERT(mutex_owned(&dkp->dk_mutex));
1437 
1438         (void) dadk_free((dkp->dk_tgobjp));
1439         dkp->dk_tgobjp = NULL;
1440 
1441         que_keylen = sizeof (que_keyvalp);
1442         if (ddi_prop_op(DDI_DEV_T_NONE, dip, PROP_LEN_AND_VAL_BUF,
1443             DDI_PROP_CANSLEEP, "queue", que_keyvalp, &que_keylen) !=
1444             DDI_PROP_SUCCESS) {
1445                 cmn_err(CE_WARN, "cmdk_destroy_obj: queue property undefined");
1446                 return;
1447         }
1448         que_keyvalp[que_keylen] = (char)0;
1449 
1450         flc_keylen = sizeof (flc_keyvalp);
1451         if (ddi_prop_op(DDI_DEV_T_NONE, dip, PROP_LEN_AND_VAL_BUF,
1452             DDI_PROP_CANSLEEP, "flow_control", flc_keyvalp, &flc_keylen) !=
1453             DDI_PROP_SUCCESS) {
1454                 cmn_err(CE_WARN,
1455                     "cmdk_destroy_obj: flow-control property undefined");
1456                 return;
1457         }
1458         flc_keyvalp[flc_keylen] = (char)0;
1459 }
1460 /*ARGSUSED5*/
1461 static int
1462 cmdk_lb_rdwr(dev_info_t *dip, uchar_t cmd, void *bufaddr,
1463     diskaddr_t start, size_t count, void *tg_cookie)
1464 {
1465         struct cmdk     *dkp;
1466         opaque_t        handle;
1467         int             rc = 0;
1468         char            *bufa;
1469         size_t          buflen;
1470 
1471         dkp = ddi_get_soft_state(cmdk_state, ddi_get_instance(dip));
1472         if (dkp == NULL)
1473                 return (ENXIO);
1474 
1475         if (cmd != TG_READ && cmd != TG_WRITE)
1476                 return (EINVAL);
1477 
1478         /* buflen must be multiple of 512 */
1479         buflen = (count + NBPSCTR - 1) & -NBPSCTR;
1480         handle = dadk_iob_alloc(DKTP_DATA, start, buflen, KM_SLEEP);
1481         if (!handle)
1482                 return (ENOMEM);
1483 
1484         if (cmd == TG_READ) {
1485                 bufa = dadk_iob_xfer(DKTP_DATA, handle, B_READ);
1486                 if (!bufa)
1487                         rc = EIO;
1488                 else
1489                         bcopy(bufa, bufaddr, count);
1490         } else {
1491                 bufa = dadk_iob_htoc(DKTP_DATA, handle);
1492                 bcopy(bufaddr, bufa, count);
1493                 bufa = dadk_iob_xfer(DKTP_DATA, handle, B_WRITE);
1494                 if (!bufa)
1495                         rc = EIO;
1496         }
1497         (void) dadk_iob_free(DKTP_DATA, handle);
1498 
1499         return (rc);
1500 }
1501 
1502 /*ARGSUSED3*/
1503 static int
1504 cmdk_lb_getinfo(dev_info_t *dip, int cmd, void *arg, void *tg_cookie)
1505 {
1506 
1507         struct cmdk             *dkp;
1508         struct tgdk_geom        phyg;
1509 
1510 
1511         dkp = ddi_get_soft_state(cmdk_state, ddi_get_instance(dip));
1512         if (dkp == NULL)
1513                 return (ENXIO);
1514 
1515         switch (cmd) {
1516         case TG_GETPHYGEOM: {
1517                 cmlb_geom_t *phygeomp = (cmlb_geom_t *)arg;
1518 
1519                 /* dadk_getphygeom always returns success */
1520                 (void) dadk_getphygeom(DKTP_DATA, &phyg);
1521 
1522                 phygeomp->g_capacity = phyg.g_cap;
1523                 phygeomp->g_nsect    = phyg.g_sec;
1524                 phygeomp->g_nhead    = phyg.g_head;
1525                 phygeomp->g_acyl     = phyg.g_acyl;
1526                 phygeomp->g_ncyl     = phyg.g_cyl;
1527                 phygeomp->g_secsize  = phyg.g_secsiz;
1528                 phygeomp->g_intrlv   = 1;
1529                 phygeomp->g_rpm              = 3600;
1530 
1531                 return (0);
1532         }
1533 
1534         case TG_GETVIRTGEOM: {
1535                 cmlb_geom_t *virtgeomp = (cmlb_geom_t *)arg;
1536                 diskaddr_t              capacity;
1537 
1538                 (void) dadk_getgeom(DKTP_DATA, &phyg);
1539                 capacity = phyg.g_cap;
1540 
1541                 /*
1542                  * If the controller returned us something that doesn't
1543                  * really fit into an Int 13/function 8 geometry
1544                  * result, just fail the ioctl.  See PSARC 1998/313.
1545                  */
1546                 if (capacity < 0 || capacity >= 63 * 254 * 1024)
1547                         return (EINVAL);
1548 
1549                 virtgeomp->g_capacity        = capacity;
1550                 virtgeomp->g_nsect   = 63;
1551                 virtgeomp->g_nhead   = 254;
1552                 virtgeomp->g_ncyl    = capacity / (63 * 254);
1553                 virtgeomp->g_acyl    = 0;
1554                 virtgeomp->g_secsize = 512;
1555                 virtgeomp->g_intrlv  = 1;
1556                 virtgeomp->g_rpm     = 3600;
1557 
1558                 return (0);
1559         }
1560 
1561         case TG_GETCAPACITY:
1562         case TG_GETBLOCKSIZE:
1563         {
1564 
1565                 /* dadk_getphygeom always returns success */
1566                 (void) dadk_getphygeom(DKTP_DATA, &phyg);
1567                 if (cmd == TG_GETCAPACITY)
1568                         *(diskaddr_t *)arg = phyg.g_cap;
1569                 else
1570                         *(uint32_t *)arg = (uint32_t)phyg.g_secsiz;
1571 
1572                 return (0);
1573         }
1574 
1575         case TG_GETATTR: {
1576                 tg_attribute_t *tgattribute = (tg_attribute_t *)arg;
1577                 if ((DKTP_EXT->tg_rdonly))
1578                         tgattribute->media_is_writable = FALSE;
1579                 else
1580                         tgattribute->media_is_writable = TRUE;
1581 
1582                 return (0);
1583         }
1584 
1585         default:
1586                 return (ENOTTY);
1587         }
1588 }
1589 
1590 
1591 
1592 
1593 
1594 /*
1595  * Create and register the devid.
1596  * There are 4 different ways we can get a device id:
1597  *    1. Already have one - nothing to do
1598  *    2. Build one from the drive's model and serial numbers
1599  *    3. Read one from the disk (first sector of last track)
1600  *    4. Fabricate one and write it on the disk.
1601  * If any of these succeeds, register the deviceid
1602  */
1603 static void
1604 cmdk_devid_setup(struct cmdk *dkp)
1605 {
1606         int     rc;
1607 
1608         /* Try options until one succeeds, or all have failed */
1609 
1610         /* 1. All done if already registered */
1611         if (dkp->dk_devid != NULL)
1612                 return;
1613 
1614         /* 2. Build a devid from the model and serial number */
1615         rc = cmdk_devid_modser(dkp);
1616         if (rc != DDI_SUCCESS) {
1617                 /* 3. Read devid from the disk, if present */
1618                 rc = cmdk_devid_read(dkp);
1619 
1620                 /* 4. otherwise make one up and write it on the disk */
1621                 if (rc != DDI_SUCCESS)
1622                         rc = cmdk_devid_fabricate(dkp);
1623         }
1624 
1625         /* If we managed to get a devid any of the above ways, register it */
1626         if (rc == DDI_SUCCESS)
1627                 (void) ddi_devid_register(dkp->dk_dip, dkp->dk_devid);
1628 
1629 }
1630 
1631 /*
1632  * Build a devid from the model and serial number
1633  * Return DDI_SUCCESS or DDI_FAILURE.
1634  */
1635 static int
1636 cmdk_devid_modser(struct cmdk *dkp)
1637 {
1638         int     rc = DDI_FAILURE;
1639         char    *hwid;
1640         int     modlen;
1641         int     serlen;
1642 
1643         /*
1644          * device ID is a concatenation of model number, '=', serial number.
1645          */
1646         hwid = kmem_alloc(CMDK_HWIDLEN, KM_SLEEP);
1647         modlen = cmdk_get_modser(dkp, DIOCTL_GETMODEL, hwid, CMDK_HWIDLEN);
1648         if (modlen == 0) {
1649                 rc = DDI_FAILURE;
1650                 goto err;
1651         }
1652         hwid[modlen++] = '=';
1653         serlen = cmdk_get_modser(dkp, DIOCTL_GETSERIAL,
1654             hwid + modlen, CMDK_HWIDLEN - modlen);
1655         if (serlen == 0) {
1656                 rc = DDI_FAILURE;
1657                 goto err;
1658         }
1659         hwid[modlen + serlen] = 0;
1660 
1661         /* Initialize the device ID, trailing NULL not included */
1662         rc = ddi_devid_init(dkp->dk_dip, DEVID_ATA_SERIAL, modlen + serlen,
1663             hwid, &dkp->dk_devid);
1664         if (rc != DDI_SUCCESS) {
1665                 rc = DDI_FAILURE;
1666                 goto err;
1667         }
1668 
1669         rc = DDI_SUCCESS;
1670 
1671 err:
1672         kmem_free(hwid, CMDK_HWIDLEN);
1673         return (rc);
1674 }
1675 
1676 static int
1677 cmdk_get_modser(struct cmdk *dkp, int ioccmd, char *buf, int len)
1678 {
1679         dadk_ioc_string_t strarg;
1680         int             rval;
1681         char            *s;
1682         char            ch;
1683         boolean_t       ret;
1684         int             i;
1685         int             tb;
1686 
1687         strarg.is_buf = buf;
1688         strarg.is_size = len;
1689         if (dadk_ioctl(DKTP_DATA,
1690             dkp->dk_dev,
1691             ioccmd,
1692             (uintptr_t)&strarg,
1693             FNATIVE | FKIOCTL,
1694             NULL,
1695             &rval) != 0)
1696                 return (0);
1697 
1698         /*
1699          * valid model/serial string must contain a non-zero non-space
1700          * trim trailing spaces/NULL
1701          */
1702         ret = B_FALSE;
1703         s = buf;
1704         for (i = 0; i < strarg.is_size; i++) {
1705                 ch = *s++;
1706                 if (ch != ' ' && ch != '\0')
1707                         tb = i + 1;
1708                 if (ch != ' ' && ch != '\0' && ch != '0')
1709                         ret = B_TRUE;
1710         }
1711 
1712         if (ret == B_FALSE)
1713                 return (0);
1714 
1715         return (tb);
1716 }
1717 
1718 /*
1719  * Read a devid from on the first block of the last track of
1720  * the last cylinder.  Make sure what we read is a valid devid.
1721  * Return DDI_SUCCESS or DDI_FAILURE.
1722  */
1723 static int
1724 cmdk_devid_read(struct cmdk *dkp)
1725 {
1726         diskaddr_t      blk;
1727         struct dk_devid *dkdevidp;
1728         uint_t          *ip;
1729         int             chksum;
1730         int             i, sz;
1731         tgdk_iob_handle handle = NULL;
1732         int             rc = DDI_FAILURE;
1733 
1734         if (cmlb_get_devid_block(dkp->dk_cmlbhandle, &blk, 0))
1735                 goto err;
1736 
1737         /* read the devid */
1738         handle = dadk_iob_alloc(DKTP_DATA, blk, NBPSCTR, KM_SLEEP);
1739         if (handle == NULL)
1740                 goto err;
1741 
1742         dkdevidp = (struct dk_devid *)dadk_iob_xfer(DKTP_DATA, handle, B_READ);
1743         if (dkdevidp == NULL)
1744                 goto err;
1745 
1746         /* Validate the revision */
1747         if ((dkdevidp->dkd_rev_hi != DK_DEVID_REV_MSB) ||
1748             (dkdevidp->dkd_rev_lo != DK_DEVID_REV_LSB))
1749                 goto err;
1750 
1751         /* Calculate the checksum */
1752         chksum = 0;
1753         ip = (uint_t *)dkdevidp;
1754         for (i = 0; i < ((NBPSCTR - sizeof (int))/sizeof (int)); i++)
1755                 chksum ^= ip[i];
1756         if (DKD_GETCHKSUM(dkdevidp) != chksum)
1757                 goto err;
1758 
1759         /* Validate the device id */
1760         if (ddi_devid_valid((ddi_devid_t)dkdevidp->dkd_devid) != DDI_SUCCESS)
1761                 goto err;
1762 
1763         /* keep a copy of the device id */
1764         sz = ddi_devid_sizeof((ddi_devid_t)dkdevidp->dkd_devid);
1765         dkp->dk_devid = kmem_alloc(sz, KM_SLEEP);
1766         bcopy(dkdevidp->dkd_devid, dkp->dk_devid, sz);
1767 
1768         rc = DDI_SUCCESS;
1769 
1770 err:
1771         if (handle != NULL)
1772                 (void) dadk_iob_free(DKTP_DATA, handle);
1773         return (rc);
1774 }
1775 
1776 /*
1777  * Create a devid and write it on the first block of the last track of
1778  * the last cylinder.
1779  * Return DDI_SUCCESS or DDI_FAILURE.
1780  */
1781 static int
1782 cmdk_devid_fabricate(struct cmdk *dkp)
1783 {
1784         ddi_devid_t     devid = NULL;   /* devid made by ddi_devid_init  */
1785         struct dk_devid *dkdevidp;      /* devid struct stored on disk */
1786         diskaddr_t      blk;
1787         tgdk_iob_handle handle = NULL;
1788         uint_t          *ip, chksum;
1789         int             i;
1790         int             rc = DDI_FAILURE;
1791 
1792         if (ddi_devid_init(dkp->dk_dip, DEVID_FAB, 0, NULL, &devid) !=
1793             DDI_SUCCESS)
1794                 goto err;
1795 
1796         if (cmlb_get_devid_block(dkp->dk_cmlbhandle, &blk, 0)) {
1797                 /* no device id block address */
1798                 goto err;
1799         }
1800 
1801         handle = dadk_iob_alloc(DKTP_DATA, blk, NBPSCTR, KM_SLEEP);
1802         if (!handle)
1803                 goto err;
1804 
1805         /* Locate the buffer */
1806         dkdevidp = (struct dk_devid *)dadk_iob_htoc(DKTP_DATA, handle);
1807 
1808         /* Fill in the revision */
1809         bzero(dkdevidp, NBPSCTR);
1810         dkdevidp->dkd_rev_hi = DK_DEVID_REV_MSB;
1811         dkdevidp->dkd_rev_lo = DK_DEVID_REV_LSB;
1812 
1813         /* Copy in the device id */
1814         i = ddi_devid_sizeof(devid);
1815         if (i > DK_DEVID_SIZE)
1816                 goto err;
1817         bcopy(devid, dkdevidp->dkd_devid, i);
1818 
1819         /* Calculate the chksum */
1820         chksum = 0;
1821         ip = (uint_t *)dkdevidp;
1822         for (i = 0; i < ((NBPSCTR - sizeof (int))/sizeof (int)); i++)
1823                 chksum ^= ip[i];
1824 
1825         /* Fill in the checksum */
1826         DKD_FORMCHKSUM(chksum, dkdevidp);
1827 
1828         /* write the devid */
1829         (void) dadk_iob_xfer(DKTP_DATA, handle, B_WRITE);
1830 
1831         dkp->dk_devid = devid;
1832 
1833         rc = DDI_SUCCESS;
1834 
1835 err:
1836         if (handle != NULL)
1837                 (void) dadk_iob_free(DKTP_DATA, handle);
1838 
1839         if (rc != DDI_SUCCESS && devid != NULL)
1840                 ddi_devid_free(devid);
1841 
1842         return (rc);
1843 }
1844 
1845 static void
1846 cmdk_bbh_free_alts(struct cmdk *dkp)
1847 {
1848         if (dkp->dk_alts_hdl) {
1849                 (void) dadk_iob_free(DKTP_DATA, dkp->dk_alts_hdl);
1850                 kmem_free(dkp->dk_slc_cnt,
1851                     NDKMAP * (sizeof (uint32_t) + sizeof (struct alts_ent *)));
1852                 dkp->dk_alts_hdl = NULL;
1853         }
1854 }
1855 
1856 static void
1857 cmdk_bbh_reopen(struct cmdk *dkp)
1858 {
1859         tgdk_iob_handle         handle = NULL;
1860         diskaddr_t              slcb, slcn, slce;
1861         struct  alts_parttbl    *ap;
1862         struct  alts_ent        *enttblp;
1863         uint32_t                altused;
1864         uint32_t                altbase;
1865         uint32_t                altlast;
1866         int                     alts;
1867         uint16_t                vtoctag;
1868         int                     i, j;
1869 
1870         /* find slice with V_ALTSCTR tag */
1871         for (alts = 0; alts < NDKMAP; alts++) {
1872                 if (cmlb_partinfo(
1873                     dkp->dk_cmlbhandle,
1874                     alts,
1875                     &slcn,
1876                     &slcb,
1877                     NULL,
1878                     &vtoctag,
1879                     0)) {
1880                         goto empty;     /* no partition table exists */
1881                 }
1882 
1883                 if (vtoctag == V_ALTSCTR && slcn > 1)
1884                         break;
1885         }
1886         if (alts >= NDKMAP) {
1887                 goto empty;     /* no V_ALTSCTR slice defined */
1888         }
1889 
1890         /* read in ALTS label block */
1891         handle = dadk_iob_alloc(DKTP_DATA, slcb, NBPSCTR, KM_SLEEP);
1892         if (!handle) {
1893                 goto empty;
1894         }
1895 
1896         ap = (struct alts_parttbl *)dadk_iob_xfer(DKTP_DATA, handle, B_READ);
1897         if (!ap || (ap->alts_sanity != ALTS_SANITY)) {
1898                 goto empty;
1899         }
1900 
1901         altused = ap->alts_ent_used; /* number of BB entries */
1902         altbase = ap->alts_ent_base; /* blk offset from begin slice */
1903         altlast = ap->alts_ent_end;  /* blk offset to last block */
1904         /* ((altused * sizeof (struct alts_ent) + NBPSCTR - 1) & ~NBPSCTR) */
1905 
1906         if (altused == 0 ||
1907             altbase < 1 ||
1908             altbase > altlast ||
1909             altlast >= slcn) {
1910                 goto empty;
1911         }
1912         (void) dadk_iob_free(DKTP_DATA, handle);
1913 
1914         /* read in ALTS remapping table */
1915         handle = dadk_iob_alloc(DKTP_DATA,
1916             slcb + altbase,
1917             (altlast - altbase + 1) << SCTRSHFT, KM_SLEEP);
1918         if (!handle) {
1919                 goto empty;
1920         }
1921 
1922         enttblp = (struct alts_ent *)dadk_iob_xfer(DKTP_DATA, handle, B_READ);
1923         if (!enttblp) {
1924                 goto empty;
1925         }
1926 
1927         rw_enter(&dkp->dk_bbh_mutex, RW_WRITER);
1928 
1929         /* allocate space for dk_slc_cnt and dk_slc_ent tables */
1930         if (dkp->dk_slc_cnt == NULL) {
1931                 dkp->dk_slc_cnt = kmem_alloc(NDKMAP *
1932                     (sizeof (long) + sizeof (struct alts_ent *)), KM_SLEEP);
1933         }
1934         dkp->dk_slc_ent = (struct alts_ent **)(dkp->dk_slc_cnt + NDKMAP);
1935 
1936         /* free previous BB table (if any) */
1937         if (dkp->dk_alts_hdl) {
1938                 (void) dadk_iob_free(DKTP_DATA, dkp->dk_alts_hdl);
1939                 dkp->dk_alts_hdl = NULL;
1940                 dkp->dk_altused = 0;
1941         }
1942 
1943         /* save linkage to new BB table */
1944         dkp->dk_alts_hdl = handle;
1945         dkp->dk_altused = altused;
1946 
1947         /*
1948          * build indexes to BB table by slice
1949          * effectively we have
1950          *      struct alts_ent *enttblp[altused];
1951          *
1952          *      uint32_t        dk_slc_cnt[NDKMAP];
1953          *      struct alts_ent *dk_slc_ent[NDKMAP];
1954          */
1955         for (i = 0; i < NDKMAP; i++) {
1956                 if (cmlb_partinfo(
1957                     dkp->dk_cmlbhandle,
1958                     i,
1959                     &slcn,
1960                     &slcb,
1961                     NULL,
1962                     NULL,
1963                     0)) {
1964                         goto empty1;
1965                 }
1966 
1967                 dkp->dk_slc_cnt[i] = 0;
1968                 if (slcn == 0)
1969                         continue;       /* slice is not allocated */
1970 
1971                 /* last block in slice */
1972                 slce = slcb + slcn - 1;
1973 
1974                 /* find first remap entry in after beginnning of slice */
1975                 for (j = 0; j < altused; j++) {
1976                         if (enttblp[j].bad_start + enttblp[j].bad_end >= slcb)
1977                                 break;
1978                 }
1979                 dkp->dk_slc_ent[i] = enttblp + j;
1980 
1981                 /* count remap entrys until end of slice */
1982                 for (; j < altused && enttblp[j].bad_start <= slce; j++) {
1983                         dkp->dk_slc_cnt[i] += 1;
1984                 }
1985         }
1986 
1987         rw_exit(&dkp->dk_bbh_mutex);
1988         return;
1989 
1990 empty:
1991         rw_enter(&dkp->dk_bbh_mutex, RW_WRITER);
1992 empty1:
1993         if (handle && handle != dkp->dk_alts_hdl)
1994                 (void) dadk_iob_free(DKTP_DATA, handle);
1995 
1996         if (dkp->dk_alts_hdl) {
1997                 (void) dadk_iob_free(DKTP_DATA, dkp->dk_alts_hdl);
1998                 dkp->dk_alts_hdl = NULL;
1999         }
2000 
2001         rw_exit(&dkp->dk_bbh_mutex);
2002 }
2003 
2004 /*ARGSUSED*/
2005 static bbh_cookie_t
2006 cmdk_bbh_htoc(opaque_t bbh_data, opaque_t handle)
2007 {
2008         struct  bbh_handle *hp;
2009         bbh_cookie_t ckp;
2010 
2011         hp = (struct  bbh_handle *)handle;
2012         ckp = hp->h_cktab + hp->h_idx;
2013         hp->h_idx++;
2014         return (ckp);
2015 }
2016 
2017 /*ARGSUSED*/
2018 static void
2019 cmdk_bbh_freehandle(opaque_t bbh_data, opaque_t handle)
2020 {
2021         struct  bbh_handle *hp;
2022 
2023         hp = (struct  bbh_handle *)handle;
2024         kmem_free(handle, (sizeof (struct bbh_handle) +
2025             (hp->h_totck * (sizeof (struct bbh_cookie)))));
2026 }
2027 
2028 
2029 /*
2030  *      cmdk_bbh_gethandle remaps the bad sectors to alternates.
2031  *      There are 7 different cases when the comparison is made
2032  *      between the bad sector cluster and the disk section.
2033  *
2034  *      bad sector cluster      gggggggggggbbbbbbbggggggggggg
2035  *      case 1:                    ddddd
2036  *      case 2:                            -d-----
2037  *      case 3:                                      ddddd
2038  *      case 4:                          dddddddddddd
2039  *      case 5:                       ddddddd-----
2040  *      case 6:                            ---ddddddd
2041  *      case 7:                            ddddddd
2042  *
2043  *      where:  g = good sector,        b = bad sector
2044  *              d = sector in disk section
2045  *              - = disk section may be extended to cover those disk area
2046  */
2047 
2048 static opaque_t
2049 cmdk_bbh_gethandle(opaque_t bbh_data, struct buf *bp)
2050 {
2051         struct cmdk             *dkp = (struct cmdk *)bbh_data;
2052         struct bbh_handle       *hp;
2053         struct bbh_cookie       *ckp;
2054         struct alts_ent         *altp;
2055         uint32_t                alts_used;
2056         uint32_t                part = CMDKPART(bp->b_edev);
2057         daddr32_t               lastsec;
2058         long                    d_count;
2059         int                     i;
2060         int                     idx;
2061         int                     cnt;
2062 
2063         if (part >= V_NUMPAR)
2064                 return (NULL);
2065 
2066         /*
2067          * This if statement is atomic and it will succeed
2068          * if there are no bad blocks (almost always)
2069          *
2070          * so this if is performed outside of the rw_enter for speed
2071          * and then repeated inside the rw_enter for safety
2072          */
2073         if (!dkp->dk_alts_hdl) {
2074                 return (NULL);
2075         }
2076 
2077         rw_enter(&dkp->dk_bbh_mutex, RW_READER);
2078 
2079         if (dkp->dk_alts_hdl == NULL) {
2080                 rw_exit(&dkp->dk_bbh_mutex);
2081                 return (NULL);
2082         }
2083 
2084         alts_used = dkp->dk_slc_cnt[part];
2085         if (alts_used == 0) {
2086                 rw_exit(&dkp->dk_bbh_mutex);
2087                 return (NULL);
2088         }
2089         altp = dkp->dk_slc_ent[part];
2090 
2091         /*
2092          * binary search for the largest bad sector index in the alternate
2093          * entry table which overlaps or larger than the starting d_sec
2094          */
2095         i = cmdk_bbh_bsearch(altp, alts_used, GET_BP_SEC(bp));
2096         /* if starting sector is > the largest bad sector, return */
2097         if (i == -1) {
2098                 rw_exit(&dkp->dk_bbh_mutex);
2099                 return (NULL);
2100         }
2101         /* i is the starting index.  Set altp to the starting entry addr */
2102         altp += i;
2103 
2104         d_count = bp->b_bcount >> SCTRSHFT;
2105         lastsec = GET_BP_SEC(bp) + d_count - 1;
2106 
2107         /* calculate the number of bad sectors */
2108         for (idx = i, cnt = 0; idx < alts_used; idx++, altp++, cnt++) {
2109                 if (lastsec < altp->bad_start)
2110                         break;
2111         }
2112 
2113         if (!cnt) {
2114                 rw_exit(&dkp->dk_bbh_mutex);
2115                 return (NULL);
2116         }
2117 
2118         /* calculate the maximum number of reserved cookies */
2119         cnt <<= 1;
2120         cnt++;
2121 
2122         /* allocate the handle */
2123         hp = (struct bbh_handle *)kmem_zalloc((sizeof (*hp) +
2124             (cnt * sizeof (*ckp))), KM_SLEEP);
2125 
2126         hp->h_idx = 0;
2127         hp->h_totck = cnt;
2128         ckp = hp->h_cktab = (struct bbh_cookie *)(hp + 1);
2129         ckp[0].ck_sector = GET_BP_SEC(bp);
2130         ckp[0].ck_seclen = d_count;
2131 
2132         altp = dkp->dk_slc_ent[part];
2133         altp += i;
2134         for (idx = 0; i < alts_used; i++, altp++) {
2135                 /* CASE 1: */
2136                 if (lastsec < altp->bad_start)
2137                         break;
2138 
2139                 /* CASE 3: */
2140                 if (ckp[idx].ck_sector > altp->bad_end)
2141                         continue;
2142 
2143                 /* CASE 2 and 7: */
2144                 if ((ckp[idx].ck_sector >= altp->bad_start) &&
2145                     (lastsec <= altp->bad_end)) {
2146                         ckp[idx].ck_sector = altp->good_start +
2147                             ckp[idx].ck_sector - altp->bad_start;
2148                         break;
2149                 }
2150 
2151                 /* at least one bad sector in our section.  break it. */
2152                 /* CASE 5: */
2153                 if ((lastsec >= altp->bad_start) &&
2154                     (lastsec <= altp->bad_end)) {
2155                         ckp[idx+1].ck_seclen = lastsec - altp->bad_start + 1;
2156                         ckp[idx].ck_seclen -= ckp[idx+1].ck_seclen;
2157                         ckp[idx+1].ck_sector = altp->good_start;
2158                         break;
2159                 }
2160                 /* CASE 6: */
2161                 if ((ckp[idx].ck_sector <= altp->bad_end) &&
2162                     (ckp[idx].ck_sector >= altp->bad_start)) {
2163                         ckp[idx+1].ck_seclen = ckp[idx].ck_seclen;
2164                         ckp[idx].ck_seclen = altp->bad_end -
2165                             ckp[idx].ck_sector + 1;
2166                         ckp[idx+1].ck_seclen -= ckp[idx].ck_seclen;
2167                         ckp[idx].ck_sector = altp->good_start +
2168                             ckp[idx].ck_sector - altp->bad_start;
2169                         idx++;
2170                         ckp[idx].ck_sector = altp->bad_end + 1;
2171                         continue;       /* check rest of section */
2172                 }
2173 
2174                 /* CASE 4: */
2175                 ckp[idx].ck_seclen = altp->bad_start - ckp[idx].ck_sector;
2176                 ckp[idx+1].ck_sector = altp->good_start;
2177                 ckp[idx+1].ck_seclen = altp->bad_end - altp->bad_start + 1;
2178                 idx += 2;
2179                 ckp[idx].ck_sector = altp->bad_end + 1;
2180                 ckp[idx].ck_seclen = lastsec - altp->bad_end;
2181         }
2182 
2183         rw_exit(&dkp->dk_bbh_mutex);
2184         return ((opaque_t)hp);
2185 }
2186 
2187 static int
2188 cmdk_bbh_bsearch(struct alts_ent *buf, int cnt, daddr32_t key)
2189 {
2190         int     i;
2191         int     ind;
2192         int     interval;
2193         int     mystatus = -1;
2194 
2195         if (!cnt)
2196                 return (mystatus);
2197 
2198         ind = 1; /* compiler complains about possible uninitialized var */
2199         for (i = 1; i <= cnt; i <<= 1)
2200                 ind = i;
2201 
2202         for (interval = ind; interval; ) {
2203                 if ((key >= buf[ind-1].bad_start) &&
2204                     (key <= buf[ind-1].bad_end)) {
2205                         return (ind-1);
2206                 } else {
2207                         interval >>= 1;
2208                         if (key < buf[ind-1].bad_start) {
2209                                 /* record the largest bad sector index */
2210                                 mystatus = ind-1;
2211                                 if (!interval)
2212                                         break;
2213                                 ind = ind - interval;
2214                         } else {
2215                                 /*
2216                                  * if key is larger than the last element
2217                                  * then break
2218                                  */
2219                                 if ((ind == cnt) || !interval)
2220                                         break;
2221                                 if ((ind+interval) <= cnt)
2222                                         ind += interval;
2223                         }
2224                 }
2225         }
2226         return (mystatus);
2227 }