1507c3241Smlf /* 2507c3241Smlf * CDDL HEADER START 3507c3241Smlf * 4507c3241Smlf * The contents of this file are subject to the terms of the 5e8fb11a1Sshidokht * Common Development and Distribution License (the "License"). 6e8fb11a1Sshidokht * You may not use this file except in compliance with the License. 7507c3241Smlf * 8507c3241Smlf * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9507c3241Smlf * or http://www.opensolaris.org/os/licensing. 10507c3241Smlf * See the License for the specific language governing permissions 11507c3241Smlf * and limitations under the License. 12507c3241Smlf * 13507c3241Smlf * When distributing Covered Code, include this CDDL HEADER in each 14507c3241Smlf * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15507c3241Smlf * If applicable, add the following below this CDDL HEADER, with the 16507c3241Smlf * fields enclosed by brackets "[]" replaced with your own identifying 17507c3241Smlf * information: Portions Copyright [yyyy] [name of copyright owner] 18507c3241Smlf * 19507c3241Smlf * CDDL HEADER END 20507c3241Smlf */ 21342440ecSPrasad Singamsetty 22507c3241Smlf /* 238b6b46faSzhongyan gu - Sun Microsystems - Beijing China * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved. 24507c3241Smlf */ 25507c3241Smlf 26507c3241Smlf #include <sys/scsi/scsi.h> 27507c3241Smlf #include <sys/dktp/cm.h> 28507c3241Smlf #include <sys/dktp/quetypes.h> 29507c3241Smlf #include <sys/dktp/queue.h> 30507c3241Smlf #include <sys/dktp/fctypes.h> 31507c3241Smlf #include <sys/dktp/flowctrl.h> 32507c3241Smlf #include <sys/dktp/cmdev.h> 33507c3241Smlf #include <sys/dkio.h> 34507c3241Smlf #include <sys/dktp/tgdk.h> 35507c3241Smlf #include <sys/dktp/dadk.h> 36507c3241Smlf #include <sys/dktp/bbh.h> 37507c3241Smlf #include <sys/dktp/altsctr.h> 38507c3241Smlf #include <sys/dktp/cmdk.h> 39507c3241Smlf 40507c3241Smlf #include <sys/stat.h> 41507c3241Smlf #include <sys/vtoc.h> 42507c3241Smlf #include <sys/file.h> 43507c3241Smlf #include <sys/dktp/dadkio.h> 44507c3241Smlf #include <sys/aio_req.h> 45507c3241Smlf 46507c3241Smlf #include <sys/cmlb.h> 47507c3241Smlf 48507c3241Smlf /* 49507c3241Smlf * Local Static Data 50507c3241Smlf */ 51507c3241Smlf #ifdef CMDK_DEBUG 52507c3241Smlf #define DENT 0x0001 53507c3241Smlf #define DIO 0x0002 54507c3241Smlf 55507c3241Smlf static int cmdk_debug = DIO; 56507c3241Smlf #endif 57507c3241Smlf 58507c3241Smlf #ifndef TRUE 59507c3241Smlf #define TRUE 1 60507c3241Smlf #endif 61507c3241Smlf 62507c3241Smlf #ifndef FALSE 63507c3241Smlf #define FALSE 0 64507c3241Smlf #endif 65507c3241Smlf 66507c3241Smlf /* 67507c3241Smlf * NDKMAP is the base number for accessing the fdisk partitions. 68507c3241Smlf * c?d?p0 --> cmdk@?,?:q 69507c3241Smlf */ 70507c3241Smlf #define PARTITION0_INDEX (NDKMAP + 0) 71507c3241Smlf 72507c3241Smlf #define DKTP_DATA (dkp->dk_tgobjp)->tg_data 73507c3241Smlf #define DKTP_EXT (dkp->dk_tgobjp)->tg_ext 74507c3241Smlf 757f0b8309SEdward Pilatowicz void *cmdk_state; 76507c3241Smlf 77507c3241Smlf /* 78507c3241Smlf * the cmdk_attach_mutex protects cmdk_max_instance in multi-threaded 79507c3241Smlf * attach situations 80507c3241Smlf */ 81507c3241Smlf static kmutex_t cmdk_attach_mutex; 82507c3241Smlf static int cmdk_max_instance = 0; 83507c3241Smlf 84507c3241Smlf /* 85507c3241Smlf * Panic dumpsys state 86507c3241Smlf * There is only a single flag that is not mutex locked since 87507c3241Smlf * the system is prevented from thread switching and cmdk_dump 88507c3241Smlf * will only be called in a single threaded operation. 89507c3241Smlf */ 90507c3241Smlf static int cmdk_indump; 91507c3241Smlf 92507c3241Smlf /* 93507c3241Smlf * Local Function Prototypes 94507c3241Smlf */ 95507c3241Smlf static int cmdk_create_obj(dev_info_t *dip, struct cmdk *dkp); 96507c3241Smlf static void cmdk_destroy_obj(dev_info_t *dip, struct cmdk *dkp); 97507c3241Smlf static void cmdkmin(struct buf *bp); 98507c3241Smlf static int cmdkrw(dev_t dev, struct uio *uio, int flag); 99507c3241Smlf static int cmdkarw(dev_t dev, struct aio_req *aio, int flag); 100507c3241Smlf 101507c3241Smlf /* 102507c3241Smlf * Bad Block Handling Functions Prototypes 103507c3241Smlf */ 104507c3241Smlf static void cmdk_bbh_reopen(struct cmdk *dkp); 105507c3241Smlf static opaque_t cmdk_bbh_gethandle(opaque_t bbh_data, struct buf *bp); 106507c3241Smlf static bbh_cookie_t cmdk_bbh_htoc(opaque_t bbh_data, opaque_t handle); 107507c3241Smlf static void cmdk_bbh_freehandle(opaque_t bbh_data, opaque_t handle); 108507c3241Smlf static void cmdk_bbh_close(struct cmdk *dkp); 109507c3241Smlf static void cmdk_bbh_setalts_idx(struct cmdk *dkp); 110507c3241Smlf static int cmdk_bbh_bsearch(struct alts_ent *buf, int cnt, daddr32_t key); 111507c3241Smlf 112507c3241Smlf static struct bbh_objops cmdk_bbh_ops = { 113507c3241Smlf nulldev, 114507c3241Smlf nulldev, 115507c3241Smlf cmdk_bbh_gethandle, 116507c3241Smlf cmdk_bbh_htoc, 117507c3241Smlf cmdk_bbh_freehandle, 118507c3241Smlf 0, 0 119507c3241Smlf }; 120507c3241Smlf 121507c3241Smlf static int cmdkopen(dev_t *dev_p, int flag, int otyp, cred_t *credp); 122507c3241Smlf static int cmdkclose(dev_t dev, int flag, int otyp, cred_t *credp); 123507c3241Smlf static int cmdkstrategy(struct buf *bp); 124507c3241Smlf static int cmdkdump(dev_t dev, caddr_t addr, daddr_t blkno, int nblk); 125507c3241Smlf static int cmdkioctl(dev_t, int, intptr_t, int, cred_t *, int *); 126507c3241Smlf static int cmdkread(dev_t dev, struct uio *uio, cred_t *credp); 127507c3241Smlf static int cmdkwrite(dev_t dev, struct uio *uio, cred_t *credp); 128507c3241Smlf static int cmdk_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, 129507c3241Smlf int mod_flags, char *name, caddr_t valuep, int *lengthp); 130507c3241Smlf static int cmdkaread(dev_t dev, struct aio_req *aio, cred_t *credp); 131507c3241Smlf static int cmdkawrite(dev_t dev, struct aio_req *aio, cred_t *credp); 132507c3241Smlf 133507c3241Smlf /* 134507c3241Smlf * Device driver ops vector 135507c3241Smlf */ 136507c3241Smlf 137507c3241Smlf static struct cb_ops cmdk_cb_ops = { 138507c3241Smlf cmdkopen, /* open */ 139507c3241Smlf cmdkclose, /* close */ 140507c3241Smlf cmdkstrategy, /* strategy */ 141507c3241Smlf nodev, /* print */ 142507c3241Smlf cmdkdump, /* dump */ 143507c3241Smlf cmdkread, /* read */ 144507c3241Smlf cmdkwrite, /* write */ 145507c3241Smlf cmdkioctl, /* ioctl */ 146507c3241Smlf nodev, /* devmap */ 147507c3241Smlf nodev, /* mmap */ 148507c3241Smlf nodev, /* segmap */ 149507c3241Smlf nochpoll, /* poll */ 150507c3241Smlf cmdk_prop_op, /* cb_prop_op */ 151507c3241Smlf 0, /* streamtab */ 152507c3241Smlf D_64BIT | D_MP | D_NEW, /* Driver comaptibility flag */ 153507c3241Smlf CB_REV, /* cb_rev */ 154507c3241Smlf cmdkaread, /* async read */ 155507c3241Smlf cmdkawrite /* async write */ 156507c3241Smlf }; 157507c3241Smlf 158507c3241Smlf static int cmdkinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 159507c3241Smlf void **result); 160507c3241Smlf static int cmdkprobe(dev_info_t *dip); 161507c3241Smlf static int cmdkattach(dev_info_t *dip, ddi_attach_cmd_t cmd); 162507c3241Smlf static int cmdkdetach(dev_info_t *dip, ddi_detach_cmd_t cmd); 163507c3241Smlf 1642df1fe9cSrandyf static void cmdk_setup_pm(dev_info_t *dip, struct cmdk *dkp); 1652df1fe9cSrandyf static int cmdkresume(dev_info_t *dip); 1662df1fe9cSrandyf static int cmdksuspend(dev_info_t *dip); 1672df1fe9cSrandyf static int cmdkpower(dev_info_t *dip, int component, int level); 1682df1fe9cSrandyf 169507c3241Smlf struct dev_ops cmdk_ops = { 170507c3241Smlf DEVO_REV, /* devo_rev, */ 171507c3241Smlf 0, /* refcnt */ 172507c3241Smlf cmdkinfo, /* info */ 173507c3241Smlf nulldev, /* identify */ 174507c3241Smlf cmdkprobe, /* probe */ 175507c3241Smlf cmdkattach, /* attach */ 176507c3241Smlf cmdkdetach, /* detach */ 177507c3241Smlf nodev, /* reset */ 178507c3241Smlf &cmdk_cb_ops, /* driver operations */ 1792df1fe9cSrandyf (struct bus_ops *)0, /* bus operations */ 18019397407SSherry Moore cmdkpower, /* power */ 18119397407SSherry Moore ddi_quiesce_not_needed, /* quiesce */ 182507c3241Smlf }; 183507c3241Smlf 184507c3241Smlf /* 185507c3241Smlf * This is the loadable module wrapper. 186507c3241Smlf */ 187507c3241Smlf #include <sys/modctl.h> 188507c3241Smlf 1897f0b8309SEdward Pilatowicz #ifndef XPV_HVM_DRIVER 190507c3241Smlf static struct modldrv modldrv = { 191507c3241Smlf &mod_driverops, /* Type of module. This one is a driver */ 192613b2871SRichard Bean "Common Direct Access Disk", 193507c3241Smlf &cmdk_ops, /* driver ops */ 194507c3241Smlf }; 195507c3241Smlf 196507c3241Smlf static struct modlinkage modlinkage = { 197507c3241Smlf MODREV_1, (void *)&modldrv, NULL 198507c3241Smlf }; 199507c3241Smlf 2007f0b8309SEdward Pilatowicz 2017f0b8309SEdward Pilatowicz #else /* XPV_HVM_DRIVER */ 2027f0b8309SEdward Pilatowicz static struct modlmisc modlmisc = { 2037f0b8309SEdward Pilatowicz &mod_miscops, /* Type of module. This one is a misc */ 2047f0b8309SEdward Pilatowicz "HVM Common Direct Access Disk", 2057f0b8309SEdward Pilatowicz }; 2067f0b8309SEdward Pilatowicz 2077f0b8309SEdward Pilatowicz static struct modlinkage modlinkage = { 2087f0b8309SEdward Pilatowicz MODREV_1, (void *)&modlmisc, NULL 2097f0b8309SEdward Pilatowicz }; 2107f0b8309SEdward Pilatowicz 2117f0b8309SEdward Pilatowicz #endif /* XPV_HVM_DRIVER */ 2127f0b8309SEdward Pilatowicz 213507c3241Smlf /* Function prototypes for cmlb callbacks */ 214507c3241Smlf 215507c3241Smlf static int cmdk_lb_rdwr(dev_info_t *dip, uchar_t cmd, void *bufaddr, 216e8fb11a1Sshidokht diskaddr_t start, size_t length, void *tg_cookie); 217e8fb11a1Sshidokht 218e8fb11a1Sshidokht static int cmdk_lb_getinfo(dev_info_t *dip, int cmd, void *arg, 219e8fb11a1Sshidokht void *tg_cookie); 220507c3241Smlf 221507c3241Smlf static void cmdk_devid_setup(struct cmdk *dkp); 222507c3241Smlf static int cmdk_devid_modser(struct cmdk *dkp); 223507c3241Smlf static int cmdk_get_modser(struct cmdk *dkp, int ioccmd, char *buf, int len); 224507c3241Smlf static int cmdk_devid_fabricate(struct cmdk *dkp); 225507c3241Smlf static int cmdk_devid_read(struct cmdk *dkp); 226507c3241Smlf 227507c3241Smlf static cmlb_tg_ops_t cmdk_lb_ops = { 228e8fb11a1Sshidokht TG_DK_OPS_VERSION_1, 229507c3241Smlf cmdk_lb_rdwr, 230e8fb11a1Sshidokht cmdk_lb_getinfo 231507c3241Smlf }; 232507c3241Smlf 23306bbe1e0Sedp static boolean_t 23406bbe1e0Sedp cmdk_isopen(struct cmdk *dkp, dev_t dev) 23506bbe1e0Sedp { 23606bbe1e0Sedp int part, otyp; 23706bbe1e0Sedp ulong_t partbit; 23806bbe1e0Sedp 23906bbe1e0Sedp ASSERT(MUTEX_HELD((&dkp->dk_mutex))); 24006bbe1e0Sedp 24106bbe1e0Sedp part = CMDKPART(dev); 24206bbe1e0Sedp partbit = 1 << part; 24306bbe1e0Sedp 24406bbe1e0Sedp /* account for close */ 24506bbe1e0Sedp if (dkp->dk_open_lyr[part] != 0) 24606bbe1e0Sedp return (B_TRUE); 24706bbe1e0Sedp for (otyp = 0; otyp < OTYPCNT; otyp++) 24806bbe1e0Sedp if (dkp->dk_open_reg[otyp] & partbit) 24906bbe1e0Sedp return (B_TRUE); 25006bbe1e0Sedp return (B_FALSE); 25106bbe1e0Sedp } 25206bbe1e0Sedp 253507c3241Smlf int 254507c3241Smlf _init(void) 255507c3241Smlf { 256507c3241Smlf int rval; 257507c3241Smlf 2587f0b8309SEdward Pilatowicz #ifndef XPV_HVM_DRIVER 259507c3241Smlf if (rval = ddi_soft_state_init(&cmdk_state, sizeof (struct cmdk), 7)) 260507c3241Smlf return (rval); 2617f0b8309SEdward Pilatowicz #endif /* !XPV_HVM_DRIVER */ 262507c3241Smlf 263507c3241Smlf mutex_init(&cmdk_attach_mutex, NULL, MUTEX_DRIVER, NULL); 264507c3241Smlf if ((rval = mod_install(&modlinkage)) != 0) { 265507c3241Smlf mutex_destroy(&cmdk_attach_mutex); 2667f0b8309SEdward Pilatowicz #ifndef XPV_HVM_DRIVER 267507c3241Smlf ddi_soft_state_fini(&cmdk_state); 2687f0b8309SEdward Pilatowicz #endif /* !XPV_HVM_DRIVER */ 269507c3241Smlf } 270507c3241Smlf return (rval); 271507c3241Smlf } 272507c3241Smlf 273507c3241Smlf int 274507c3241Smlf _fini(void) 275507c3241Smlf { 276507c3241Smlf return (EBUSY); 277507c3241Smlf } 278507c3241Smlf 279507c3241Smlf int 280507c3241Smlf _info(struct modinfo *modinfop) 281507c3241Smlf { 282507c3241Smlf return (mod_info(&modlinkage, modinfop)); 283507c3241Smlf } 284507c3241Smlf 285507c3241Smlf /* 286507c3241Smlf * Autoconfiguration Routines 287507c3241Smlf */ 288507c3241Smlf static int 289507c3241Smlf cmdkprobe(dev_info_t *dip) 290507c3241Smlf { 291507c3241Smlf int instance; 292507c3241Smlf int status; 293507c3241Smlf struct cmdk *dkp; 294507c3241Smlf 295507c3241Smlf instance = ddi_get_instance(dip); 296507c3241Smlf 2977f0b8309SEdward Pilatowicz #ifndef XPV_HVM_DRIVER 298507c3241Smlf if (ddi_get_soft_state(cmdk_state, instance)) 299507c3241Smlf return (DDI_PROBE_PARTIAL); 300507c3241Smlf 3017f0b8309SEdward Pilatowicz if (ddi_soft_state_zalloc(cmdk_state, instance) != DDI_SUCCESS) 3027f0b8309SEdward Pilatowicz return (DDI_PROBE_PARTIAL); 3037f0b8309SEdward Pilatowicz #endif /* !XPV_HVM_DRIVER */ 3047f0b8309SEdward Pilatowicz 3057f0b8309SEdward Pilatowicz if ((dkp = ddi_get_soft_state(cmdk_state, instance)) == NULL) 306507c3241Smlf return (DDI_PROBE_PARTIAL); 307507c3241Smlf 308507c3241Smlf mutex_init(&dkp->dk_mutex, NULL, MUTEX_DRIVER, NULL); 309507c3241Smlf rw_init(&dkp->dk_bbh_mutex, NULL, RW_DRIVER, NULL); 310507c3241Smlf dkp->dk_dip = dip; 311507c3241Smlf mutex_enter(&dkp->dk_mutex); 312507c3241Smlf 313507c3241Smlf dkp->dk_dev = makedevice(ddi_driver_major(dip), 314507c3241Smlf ddi_get_instance(dip) << CMDK_UNITSHF); 315507c3241Smlf 316507c3241Smlf /* linkage to dadk and strategy */ 317507c3241Smlf if (cmdk_create_obj(dip, dkp) != DDI_SUCCESS) { 318507c3241Smlf mutex_exit(&dkp->dk_mutex); 319507c3241Smlf mutex_destroy(&dkp->dk_mutex); 320507c3241Smlf rw_destroy(&dkp->dk_bbh_mutex); 3217f0b8309SEdward Pilatowicz #ifndef XPV_HVM_DRIVER 322507c3241Smlf ddi_soft_state_free(cmdk_state, instance); 3237f0b8309SEdward Pilatowicz #endif /* !XPV_HVM_DRIVER */ 324507c3241Smlf return (DDI_PROBE_PARTIAL); 325507c3241Smlf } 326507c3241Smlf 327507c3241Smlf status = dadk_probe(DKTP_DATA, KM_NOSLEEP); 328507c3241Smlf if (status != DDI_PROBE_SUCCESS) { 329507c3241Smlf cmdk_destroy_obj(dip, dkp); /* dadk/strategy linkage */ 330507c3241Smlf mutex_exit(&dkp->dk_mutex); 331507c3241Smlf mutex_destroy(&dkp->dk_mutex); 332507c3241Smlf rw_destroy(&dkp->dk_bbh_mutex); 3337f0b8309SEdward Pilatowicz #ifndef XPV_HVM_DRIVER 334507c3241Smlf ddi_soft_state_free(cmdk_state, instance); 3357f0b8309SEdward Pilatowicz #endif /* !XPV_HVM_DRIVER */ 336507c3241Smlf return (status); 337507c3241Smlf } 338507c3241Smlf 339507c3241Smlf mutex_exit(&dkp->dk_mutex); 340507c3241Smlf #ifdef CMDK_DEBUG 341507c3241Smlf if (cmdk_debug & DENT) 342507c3241Smlf PRF("cmdkprobe: instance= %d name= `%s`\n", 343507c3241Smlf instance, ddi_get_name_addr(dip)); 344507c3241Smlf #endif 345507c3241Smlf return (status); 346507c3241Smlf } 347507c3241Smlf 348507c3241Smlf static int 349507c3241Smlf cmdkattach(dev_info_t *dip, ddi_attach_cmd_t cmd) 350507c3241Smlf { 351507c3241Smlf int instance; 352507c3241Smlf struct cmdk *dkp; 353507c3241Smlf char *node_type; 354507c3241Smlf 3552df1fe9cSrandyf switch (cmd) { 3562df1fe9cSrandyf case DDI_ATTACH: 3572df1fe9cSrandyf break; 3582df1fe9cSrandyf case DDI_RESUME: 3592df1fe9cSrandyf return (cmdkresume(dip)); 3602df1fe9cSrandyf default: 361507c3241Smlf return (DDI_FAILURE); 3622df1fe9cSrandyf } 363507c3241Smlf 364507c3241Smlf instance = ddi_get_instance(dip); 365507c3241Smlf if (!(dkp = ddi_get_soft_state(cmdk_state, instance))) 366507c3241Smlf return (DDI_FAILURE); 367507c3241Smlf 3682df1fe9cSrandyf dkp->dk_pm_level = CMDK_SPINDLE_UNINIT; 3692df1fe9cSrandyf mutex_init(&dkp->dk_mutex, NULL, MUTEX_DRIVER, NULL); 3702df1fe9cSrandyf 371507c3241Smlf mutex_enter(&dkp->dk_mutex); 372507c3241Smlf 373507c3241Smlf /* dadk_attach is an empty function that only returns SUCCESS */ 374507c3241Smlf (void) dadk_attach(DKTP_DATA); 375507c3241Smlf 376507c3241Smlf node_type = (DKTP_EXT->tg_nodetype); 377507c3241Smlf 378507c3241Smlf /* 379507c3241Smlf * this open allows cmlb to read the device 380507c3241Smlf * and determine the label types 381507c3241Smlf * so that cmlb can create minor nodes for device 382507c3241Smlf */ 383507c3241Smlf 384507c3241Smlf /* open the target disk */ 385507c3241Smlf if (dadk_open(DKTP_DATA, 0) != DDI_SUCCESS) 386507c3241Smlf goto fail2; 387507c3241Smlf 388342440ecSPrasad Singamsetty #ifdef _ILP32 389342440ecSPrasad Singamsetty { 390342440ecSPrasad Singamsetty struct tgdk_geom phyg; 391342440ecSPrasad Singamsetty (void) dadk_getphygeom(DKTP_DATA, &phyg); 392342440ecSPrasad Singamsetty if ((phyg.g_cap - 1) > DK_MAX_BLOCKS) { 393342440ecSPrasad Singamsetty (void) dadk_close(DKTP_DATA); 394342440ecSPrasad Singamsetty goto fail2; 395342440ecSPrasad Singamsetty } 396342440ecSPrasad Singamsetty } 397342440ecSPrasad Singamsetty #endif 398342440ecSPrasad Singamsetty 399342440ecSPrasad Singamsetty 400507c3241Smlf /* mark as having opened target */ 401507c3241Smlf dkp->dk_flag |= CMDK_TGDK_OPEN; 402507c3241Smlf 403507c3241Smlf cmlb_alloc_handle((cmlb_handle_t *)&dkp->dk_cmlbhandle); 404507c3241Smlf 405507c3241Smlf if (cmlb_attach(dip, 406507c3241Smlf &cmdk_lb_ops, 407507c3241Smlf DTYPE_DIRECT, /* device_type */ 4087f0b8309SEdward Pilatowicz B_FALSE, /* removable */ 4097f0b8309SEdward Pilatowicz B_FALSE, /* hot pluggable XXX */ 410507c3241Smlf node_type, 411507c3241Smlf CMLB_CREATE_ALTSLICE_VTOC_16_DTYPE_DIRECT, /* alter_behaviour */ 412e8fb11a1Sshidokht dkp->dk_cmlbhandle, 413e8fb11a1Sshidokht 0) != 0) 414507c3241Smlf goto fail1; 415507c3241Smlf 416507c3241Smlf /* Calling validate will create minor nodes according to disk label */ 417e8fb11a1Sshidokht (void) cmlb_validate(dkp->dk_cmlbhandle, 0, 0); 418507c3241Smlf 419507c3241Smlf /* set bbh (Bad Block Handling) */ 420507c3241Smlf cmdk_bbh_reopen(dkp); 421507c3241Smlf 422507c3241Smlf /* setup devid string */ 423507c3241Smlf cmdk_devid_setup(dkp); 424507c3241Smlf 425507c3241Smlf mutex_enter(&cmdk_attach_mutex); 426507c3241Smlf if (instance > cmdk_max_instance) 427507c3241Smlf cmdk_max_instance = instance; 428507c3241Smlf mutex_exit(&cmdk_attach_mutex); 429507c3241Smlf 430507c3241Smlf mutex_exit(&dkp->dk_mutex); 431507c3241Smlf 432507c3241Smlf /* 433507c3241Smlf * Add a zero-length attribute to tell the world we support 434507c3241Smlf * kernel ioctls (for layered drivers) 435507c3241Smlf */ 436507c3241Smlf (void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP, 437507c3241Smlf DDI_KERNEL_IOCTL, NULL, 0); 438507c3241Smlf ddi_report_dev(dip); 439507c3241Smlf 4402df1fe9cSrandyf /* 4412df1fe9cSrandyf * Initialize power management 4422df1fe9cSrandyf */ 4432df1fe9cSrandyf mutex_init(&dkp->dk_pm_mutex, NULL, MUTEX_DRIVER, NULL); 4442df1fe9cSrandyf cv_init(&dkp->dk_suspend_cv, NULL, CV_DRIVER, NULL); 4452df1fe9cSrandyf cmdk_setup_pm(dip, dkp); 4462df1fe9cSrandyf 447507c3241Smlf return (DDI_SUCCESS); 448507c3241Smlf 449507c3241Smlf fail1: 450507c3241Smlf cmlb_free_handle(&dkp->dk_cmlbhandle); 451507c3241Smlf (void) dadk_close(DKTP_DATA); 452507c3241Smlf fail2: 453507c3241Smlf cmdk_destroy_obj(dip, dkp); 454507c3241Smlf rw_destroy(&dkp->dk_bbh_mutex); 455507c3241Smlf mutex_exit(&dkp->dk_mutex); 456507c3241Smlf mutex_destroy(&dkp->dk_mutex); 4577f0b8309SEdward Pilatowicz #ifndef XPV_HVM_DRIVER 458507c3241Smlf ddi_soft_state_free(cmdk_state, instance); 4597f0b8309SEdward Pilatowicz #endif /* !XPV_HVM_DRIVER */ 460507c3241Smlf return (DDI_FAILURE); 461507c3241Smlf } 462507c3241Smlf 463507c3241Smlf 464507c3241Smlf static int 465507c3241Smlf cmdkdetach(dev_info_t *dip, ddi_detach_cmd_t cmd) 466507c3241Smlf { 467507c3241Smlf struct cmdk *dkp; 468507c3241Smlf int instance; 469507c3241Smlf int max_instance; 470507c3241Smlf 4712df1fe9cSrandyf switch (cmd) { 4722df1fe9cSrandyf case DDI_DETACH: 4732df1fe9cSrandyf /* return (DDI_FAILURE); */ 4742df1fe9cSrandyf break; 4752df1fe9cSrandyf case DDI_SUSPEND: 4762df1fe9cSrandyf return (cmdksuspend(dip)); 4772df1fe9cSrandyf default: 478507c3241Smlf #ifdef CMDK_DEBUG 479507c3241Smlf if (cmdk_debug & DIO) { 480507c3241Smlf PRF("cmdkdetach: cmd = %d unknown\n", cmd); 481507c3241Smlf } 482507c3241Smlf #endif 483507c3241Smlf return (DDI_FAILURE); 484507c3241Smlf } 485507c3241Smlf 486507c3241Smlf mutex_enter(&cmdk_attach_mutex); 487507c3241Smlf max_instance = cmdk_max_instance; 488507c3241Smlf mutex_exit(&cmdk_attach_mutex); 489507c3241Smlf 490507c3241Smlf /* check if any instance of driver is open */ 491507c3241Smlf for (instance = 0; instance < max_instance; instance++) { 492507c3241Smlf dkp = ddi_get_soft_state(cmdk_state, instance); 493507c3241Smlf if (!dkp) 494507c3241Smlf continue; 495507c3241Smlf if (dkp->dk_flag & CMDK_OPEN) 496507c3241Smlf return (DDI_FAILURE); 497507c3241Smlf } 498507c3241Smlf 499507c3241Smlf instance = ddi_get_instance(dip); 500507c3241Smlf if (!(dkp = ddi_get_soft_state(cmdk_state, instance))) 501507c3241Smlf return (DDI_SUCCESS); 502507c3241Smlf 503507c3241Smlf mutex_enter(&dkp->dk_mutex); 504507c3241Smlf 505507c3241Smlf /* 506507c3241Smlf * The cmdk_part_info call at the end of cmdkattach may have 507507c3241Smlf * caused cmdk_reopen to do a TGDK_OPEN, make sure we close on 508507c3241Smlf * detach for case when cmdkopen/cmdkclose never occurs. 509507c3241Smlf */ 510507c3241Smlf if (dkp->dk_flag & CMDK_TGDK_OPEN) { 511507c3241Smlf dkp->dk_flag &= ~CMDK_TGDK_OPEN; 512507c3241Smlf (void) dadk_close(DKTP_DATA); 513507c3241Smlf } 514507c3241Smlf 515e8fb11a1Sshidokht cmlb_detach(dkp->dk_cmlbhandle, 0); 516507c3241Smlf cmlb_free_handle(&dkp->dk_cmlbhandle); 517507c3241Smlf ddi_prop_remove_all(dip); 518507c3241Smlf 519507c3241Smlf cmdk_destroy_obj(dip, dkp); /* dadk/strategy linkage */ 5208b6b46faSzhongyan gu - Sun Microsystems - Beijing China 5218b6b46faSzhongyan gu - Sun Microsystems - Beijing China /* 5228b6b46faSzhongyan gu - Sun Microsystems - Beijing China * free the devid structure if allocated before 5238b6b46faSzhongyan gu - Sun Microsystems - Beijing China */ 5248b6b46faSzhongyan gu - Sun Microsystems - Beijing China if (dkp->dk_devid) { 5258b6b46faSzhongyan gu - Sun Microsystems - Beijing China ddi_devid_free(dkp->dk_devid); 5268b6b46faSzhongyan gu - Sun Microsystems - Beijing China dkp->dk_devid = NULL; 5278b6b46faSzhongyan gu - Sun Microsystems - Beijing China } 5288b6b46faSzhongyan gu - Sun Microsystems - Beijing China 529507c3241Smlf mutex_exit(&dkp->dk_mutex); 530507c3241Smlf mutex_destroy(&dkp->dk_mutex); 531507c3241Smlf rw_destroy(&dkp->dk_bbh_mutex); 5322df1fe9cSrandyf mutex_destroy(&dkp->dk_pm_mutex); 5332df1fe9cSrandyf cv_destroy(&dkp->dk_suspend_cv); 5347f0b8309SEdward Pilatowicz #ifndef XPV_HVM_DRIVER 535507c3241Smlf ddi_soft_state_free(cmdk_state, instance); 5367f0b8309SEdward Pilatowicz #endif /* !XPV_HVM_DRIVER */ 537507c3241Smlf 538507c3241Smlf return (DDI_SUCCESS); 539507c3241Smlf } 540507c3241Smlf 541507c3241Smlf static int 542507c3241Smlf cmdkinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 543507c3241Smlf { 544507c3241Smlf dev_t dev = (dev_t)arg; 545507c3241Smlf int instance; 546507c3241Smlf struct cmdk *dkp; 547507c3241Smlf 548507c3241Smlf #ifdef lint 549507c3241Smlf dip = dip; /* no one ever uses this */ 550507c3241Smlf #endif 551507c3241Smlf #ifdef CMDK_DEBUG 552507c3241Smlf if (cmdk_debug & DENT) 553507c3241Smlf PRF("cmdkinfo: call\n"); 554507c3241Smlf #endif 555507c3241Smlf instance = CMDKUNIT(dev); 556507c3241Smlf 557507c3241Smlf switch (infocmd) { 558507c3241Smlf case DDI_INFO_DEVT2DEVINFO: 559507c3241Smlf if (!(dkp = ddi_get_soft_state(cmdk_state, instance))) 560507c3241Smlf return (DDI_FAILURE); 561507c3241Smlf *result = (void *) dkp->dk_dip; 562507c3241Smlf break; 563507c3241Smlf case DDI_INFO_DEVT2INSTANCE: 564507c3241Smlf *result = (void *)(intptr_t)instance; 565507c3241Smlf break; 566507c3241Smlf default: 567507c3241Smlf return (DDI_FAILURE); 568507c3241Smlf } 569507c3241Smlf return (DDI_SUCCESS); 570507c3241Smlf } 571507c3241Smlf 5722df1fe9cSrandyf /* 5732df1fe9cSrandyf * Initialize the power management components 5742df1fe9cSrandyf */ 5752df1fe9cSrandyf static void 5762df1fe9cSrandyf cmdk_setup_pm(dev_info_t *dip, struct cmdk *dkp) 5772df1fe9cSrandyf { 5782df1fe9cSrandyf char *pm_comp[] = { "NAME=cmdk", "0=off", "1=on", NULL }; 5792df1fe9cSrandyf 5802df1fe9cSrandyf /* 5812df1fe9cSrandyf * Since the cmdk device does not the 'reg' property, 5822df1fe9cSrandyf * cpr will not call its DDI_SUSPEND/DDI_RESUME entries. 5832df1fe9cSrandyf * The following code is to tell cpr that this device 5842df1fe9cSrandyf * DOES need to be suspended and resumed. 5852df1fe9cSrandyf */ 5862df1fe9cSrandyf (void) ddi_prop_update_string(DDI_DEV_T_NONE, dip, 5872df1fe9cSrandyf "pm-hardware-state", "needs-suspend-resume"); 5882df1fe9cSrandyf 5892df1fe9cSrandyf if (ddi_prop_update_string_array(DDI_DEV_T_NONE, dip, 5902df1fe9cSrandyf "pm-components", pm_comp, 3) == DDI_PROP_SUCCESS) { 5912df1fe9cSrandyf if (pm_raise_power(dip, 0, CMDK_SPINDLE_ON) == DDI_SUCCESS) { 5922df1fe9cSrandyf mutex_enter(&dkp->dk_pm_mutex); 5932df1fe9cSrandyf dkp->dk_pm_level = CMDK_SPINDLE_ON; 5942df1fe9cSrandyf dkp->dk_pm_is_enabled = 1; 5952df1fe9cSrandyf mutex_exit(&dkp->dk_pm_mutex); 5962df1fe9cSrandyf } else { 5972df1fe9cSrandyf mutex_enter(&dkp->dk_pm_mutex); 5982df1fe9cSrandyf dkp->dk_pm_level = CMDK_SPINDLE_OFF; 5992df1fe9cSrandyf dkp->dk_pm_is_enabled = 0; 6002df1fe9cSrandyf mutex_exit(&dkp->dk_pm_mutex); 6012df1fe9cSrandyf } 6022df1fe9cSrandyf } else { 6032df1fe9cSrandyf mutex_enter(&dkp->dk_pm_mutex); 6042df1fe9cSrandyf dkp->dk_pm_level = CMDK_SPINDLE_UNINIT; 6052df1fe9cSrandyf dkp->dk_pm_is_enabled = 0; 6062df1fe9cSrandyf mutex_exit(&dkp->dk_pm_mutex); 6072df1fe9cSrandyf } 6082df1fe9cSrandyf } 6092df1fe9cSrandyf 6102df1fe9cSrandyf /* 6112df1fe9cSrandyf * suspend routine, it will be run when get the command 6122df1fe9cSrandyf * DDI_SUSPEND at detach(9E) from system power management 6132df1fe9cSrandyf */ 6142df1fe9cSrandyf static int 6152df1fe9cSrandyf cmdksuspend(dev_info_t *dip) 6162df1fe9cSrandyf { 6172df1fe9cSrandyf struct cmdk *dkp; 6182df1fe9cSrandyf int instance; 6192df1fe9cSrandyf clock_t count = 0; 6202df1fe9cSrandyf 6212df1fe9cSrandyf instance = ddi_get_instance(dip); 6222df1fe9cSrandyf if (!(dkp = ddi_get_soft_state(cmdk_state, instance))) 6232df1fe9cSrandyf return (DDI_FAILURE); 6242df1fe9cSrandyf mutex_enter(&dkp->dk_mutex); 6252df1fe9cSrandyf if (dkp->dk_flag & CMDK_SUSPEND) { 6262df1fe9cSrandyf mutex_exit(&dkp->dk_mutex); 6272df1fe9cSrandyf return (DDI_SUCCESS); 6282df1fe9cSrandyf } 6292df1fe9cSrandyf dkp->dk_flag |= CMDK_SUSPEND; 6302df1fe9cSrandyf 6312df1fe9cSrandyf /* need to wait a while */ 6322df1fe9cSrandyf while (dadk_getcmds(DKTP_DATA) != 0) { 6332df1fe9cSrandyf delay(drv_usectohz(1000000)); 6342df1fe9cSrandyf if (count > 60) { 6352df1fe9cSrandyf dkp->dk_flag &= ~CMDK_SUSPEND; 6362df1fe9cSrandyf cv_broadcast(&dkp->dk_suspend_cv); 6372df1fe9cSrandyf mutex_exit(&dkp->dk_mutex); 6382df1fe9cSrandyf return (DDI_FAILURE); 6392df1fe9cSrandyf } 6402df1fe9cSrandyf count++; 6412df1fe9cSrandyf } 6422df1fe9cSrandyf mutex_exit(&dkp->dk_mutex); 6432df1fe9cSrandyf return (DDI_SUCCESS); 6442df1fe9cSrandyf } 6452df1fe9cSrandyf 6462df1fe9cSrandyf /* 6472df1fe9cSrandyf * resume routine, it will be run when get the command 6482df1fe9cSrandyf * DDI_RESUME at attach(9E) from system power management 6492df1fe9cSrandyf */ 6502df1fe9cSrandyf static int 6512df1fe9cSrandyf cmdkresume(dev_info_t *dip) 6522df1fe9cSrandyf { 6532df1fe9cSrandyf struct cmdk *dkp; 6542df1fe9cSrandyf int instance; 6552df1fe9cSrandyf 6562df1fe9cSrandyf instance = ddi_get_instance(dip); 6572df1fe9cSrandyf if (!(dkp = ddi_get_soft_state(cmdk_state, instance))) 6582df1fe9cSrandyf return (DDI_FAILURE); 6592df1fe9cSrandyf mutex_enter(&dkp->dk_mutex); 6602df1fe9cSrandyf if (!(dkp->dk_flag & CMDK_SUSPEND)) { 6612df1fe9cSrandyf mutex_exit(&dkp->dk_mutex); 6622df1fe9cSrandyf return (DDI_FAILURE); 6632df1fe9cSrandyf } 6642df1fe9cSrandyf dkp->dk_pm_level = CMDK_SPINDLE_ON; 6652df1fe9cSrandyf dkp->dk_flag &= ~CMDK_SUSPEND; 6662df1fe9cSrandyf cv_broadcast(&dkp->dk_suspend_cv); 6672df1fe9cSrandyf mutex_exit(&dkp->dk_mutex); 6682df1fe9cSrandyf return (DDI_SUCCESS); 6692df1fe9cSrandyf 6702df1fe9cSrandyf } 6712df1fe9cSrandyf 6722df1fe9cSrandyf /* 6732df1fe9cSrandyf * power management entry point, it was used to 6742df1fe9cSrandyf * change power management component. 6752df1fe9cSrandyf * Actually, the real hard drive suspend/resume 6762df1fe9cSrandyf * was handled in ata, so this function is not 6772df1fe9cSrandyf * doing any real work other than verifying that 6782df1fe9cSrandyf * the disk is idle. 6792df1fe9cSrandyf */ 6802df1fe9cSrandyf static int 6812df1fe9cSrandyf cmdkpower(dev_info_t *dip, int component, int level) 6822df1fe9cSrandyf { 6832df1fe9cSrandyf struct cmdk *dkp; 6842df1fe9cSrandyf int instance; 6852df1fe9cSrandyf 6862df1fe9cSrandyf instance = ddi_get_instance(dip); 6872df1fe9cSrandyf if (!(dkp = ddi_get_soft_state(cmdk_state, instance)) || 6882df1fe9cSrandyf component != 0 || level > CMDK_SPINDLE_ON || 6892df1fe9cSrandyf level < CMDK_SPINDLE_OFF) { 6902df1fe9cSrandyf return (DDI_FAILURE); 6912df1fe9cSrandyf } 6922df1fe9cSrandyf 6932df1fe9cSrandyf mutex_enter(&dkp->dk_pm_mutex); 6942df1fe9cSrandyf if (dkp->dk_pm_is_enabled && dkp->dk_pm_level == level) { 6952df1fe9cSrandyf mutex_exit(&dkp->dk_pm_mutex); 6962df1fe9cSrandyf return (DDI_SUCCESS); 6972df1fe9cSrandyf } 6982df1fe9cSrandyf mutex_exit(&dkp->dk_pm_mutex); 6992df1fe9cSrandyf 7002df1fe9cSrandyf if ((level == CMDK_SPINDLE_OFF) && 7012df1fe9cSrandyf (dadk_getcmds(DKTP_DATA) != 0)) { 7022df1fe9cSrandyf return (DDI_FAILURE); 7032df1fe9cSrandyf } 7042df1fe9cSrandyf 7052df1fe9cSrandyf mutex_enter(&dkp->dk_pm_mutex); 7062df1fe9cSrandyf dkp->dk_pm_level = level; 7072df1fe9cSrandyf mutex_exit(&dkp->dk_pm_mutex); 7082df1fe9cSrandyf return (DDI_SUCCESS); 7092df1fe9cSrandyf } 7102df1fe9cSrandyf 711507c3241Smlf static int 712507c3241Smlf cmdk_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int mod_flags, 713507c3241Smlf char *name, caddr_t valuep, int *lengthp) 714507c3241Smlf { 715507c3241Smlf struct cmdk *dkp; 716507c3241Smlf 717507c3241Smlf #ifdef CMDK_DEBUG 718507c3241Smlf if (cmdk_debug & DENT) 719507c3241Smlf PRF("cmdk_prop_op: call\n"); 720507c3241Smlf #endif 721507c3241Smlf 722507c3241Smlf dkp = ddi_get_soft_state(cmdk_state, ddi_get_instance(dip)); 723b9ccdc5aScth if (dkp == NULL) 724b9ccdc5aScth return (ddi_prop_op(dev, dip, prop_op, mod_flags, 725507c3241Smlf name, valuep, lengthp)); 726b9ccdc5aScth 727b9ccdc5aScth return (cmlb_prop_op(dkp->dk_cmlbhandle, 728b9ccdc5aScth dev, dip, prop_op, mod_flags, name, valuep, lengthp, 729b9ccdc5aScth CMDKPART(dev), NULL)); 730507c3241Smlf } 731507c3241Smlf 732507c3241Smlf /* 733507c3241Smlf * dump routine 734507c3241Smlf */ 735507c3241Smlf static int 736507c3241Smlf cmdkdump(dev_t dev, caddr_t addr, daddr_t blkno, int nblk) 737507c3241Smlf { 738507c3241Smlf int instance; 739507c3241Smlf struct cmdk *dkp; 740507c3241Smlf diskaddr_t p_lblksrt; 741507c3241Smlf diskaddr_t p_lblkcnt; 742507c3241Smlf struct buf local; 743507c3241Smlf struct buf *bp; 744507c3241Smlf 745507c3241Smlf #ifdef CMDK_DEBUG 746507c3241Smlf if (cmdk_debug & DENT) 747507c3241Smlf PRF("cmdkdump: call\n"); 748507c3241Smlf #endif 749507c3241Smlf instance = CMDKUNIT(dev); 750507c3241Smlf if (!(dkp = ddi_get_soft_state(cmdk_state, instance)) || (blkno < 0)) 751507c3241Smlf return (ENXIO); 752507c3241Smlf 753507c3241Smlf if (cmlb_partinfo( 754507c3241Smlf dkp->dk_cmlbhandle, 755507c3241Smlf CMDKPART(dev), 756507c3241Smlf &p_lblkcnt, 757507c3241Smlf &p_lblksrt, 758507c3241Smlf NULL, 759e8fb11a1Sshidokht NULL, 760e8fb11a1Sshidokht 0)) { 761507c3241Smlf return (ENXIO); 762507c3241Smlf } 763507c3241Smlf 764507c3241Smlf if ((blkno+nblk) > p_lblkcnt) 765507c3241Smlf return (EINVAL); 766507c3241Smlf 767507c3241Smlf cmdk_indump = 1; /* Tell disk targets we are panic dumpping */ 768507c3241Smlf 769507c3241Smlf bp = &local; 770507c3241Smlf bzero(bp, sizeof (*bp)); 771507c3241Smlf bp->b_flags = B_BUSY; 772507c3241Smlf bp->b_un.b_addr = addr; 773507c3241Smlf bp->b_bcount = nblk << SCTRSHFT; 774507c3241Smlf SET_BP_SEC(bp, ((ulong_t)(p_lblksrt + blkno))); 775507c3241Smlf 776507c3241Smlf (void) dadk_dump(DKTP_DATA, bp); 777507c3241Smlf return (bp->b_error); 778507c3241Smlf } 779507c3241Smlf 780507c3241Smlf /* 781507c3241Smlf * Copy in the dadkio_rwcmd according to the user's data model. If needed, 782507c3241Smlf * convert it for our internal use. 783507c3241Smlf */ 784507c3241Smlf static int 785507c3241Smlf rwcmd_copyin(struct dadkio_rwcmd *rwcmdp, caddr_t inaddr, int flag) 786507c3241Smlf { 787507c3241Smlf switch (ddi_model_convert_from(flag)) { 788507c3241Smlf case DDI_MODEL_ILP32: { 789507c3241Smlf struct dadkio_rwcmd32 cmd32; 790507c3241Smlf 791507c3241Smlf if (ddi_copyin(inaddr, &cmd32, 792507c3241Smlf sizeof (struct dadkio_rwcmd32), flag)) { 793507c3241Smlf return (EFAULT); 794507c3241Smlf } 795507c3241Smlf 796507c3241Smlf rwcmdp->cmd = cmd32.cmd; 797507c3241Smlf rwcmdp->flags = cmd32.flags; 798342440ecSPrasad Singamsetty rwcmdp->blkaddr = (blkaddr_t)cmd32.blkaddr; 799507c3241Smlf rwcmdp->buflen = cmd32.buflen; 800507c3241Smlf rwcmdp->bufaddr = (caddr_t)(intptr_t)cmd32.bufaddr; 801507c3241Smlf /* 802507c3241Smlf * Note: we do not convert the 'status' field, 803507c3241Smlf * as it should not contain valid data at this 804507c3241Smlf * point. 805507c3241Smlf */ 806507c3241Smlf bzero(&rwcmdp->status, sizeof (rwcmdp->status)); 807507c3241Smlf break; 808507c3241Smlf } 809507c3241Smlf case DDI_MODEL_NONE: { 810507c3241Smlf if (ddi_copyin(inaddr, rwcmdp, 811507c3241Smlf sizeof (struct dadkio_rwcmd), flag)) { 812507c3241Smlf return (EFAULT); 813507c3241Smlf } 814507c3241Smlf } 815507c3241Smlf } 816507c3241Smlf return (0); 817507c3241Smlf } 818507c3241Smlf 819507c3241Smlf /* 820507c3241Smlf * If necessary, convert the internal rwcmdp and status to the appropriate 821507c3241Smlf * data model and copy it out to the user. 822507c3241Smlf */ 823507c3241Smlf static int 824507c3241Smlf rwcmd_copyout(struct dadkio_rwcmd *rwcmdp, caddr_t outaddr, int flag) 825507c3241Smlf { 826507c3241Smlf switch (ddi_model_convert_from(flag)) { 827507c3241Smlf case DDI_MODEL_ILP32: { 828507c3241Smlf struct dadkio_rwcmd32 cmd32; 829507c3241Smlf 830507c3241Smlf cmd32.cmd = rwcmdp->cmd; 831507c3241Smlf cmd32.flags = rwcmdp->flags; 832507c3241Smlf cmd32.blkaddr = rwcmdp->blkaddr; 833507c3241Smlf cmd32.buflen = rwcmdp->buflen; 834507c3241Smlf ASSERT64(((uintptr_t)rwcmdp->bufaddr >> 32) == 0); 835507c3241Smlf cmd32.bufaddr = (caddr32_t)(uintptr_t)rwcmdp->bufaddr; 836507c3241Smlf 837507c3241Smlf cmd32.status.status = rwcmdp->status.status; 838507c3241Smlf cmd32.status.resid = rwcmdp->status.resid; 839507c3241Smlf cmd32.status.failed_blk_is_valid = 840507c3241Smlf rwcmdp->status.failed_blk_is_valid; 841507c3241Smlf cmd32.status.failed_blk = rwcmdp->status.failed_blk; 842507c3241Smlf cmd32.status.fru_code_is_valid = 843507c3241Smlf rwcmdp->status.fru_code_is_valid; 844507c3241Smlf cmd32.status.fru_code = rwcmdp->status.fru_code; 845507c3241Smlf 846507c3241Smlf bcopy(rwcmdp->status.add_error_info, 847507c3241Smlf cmd32.status.add_error_info, DADKIO_ERROR_INFO_LEN); 848507c3241Smlf 849507c3241Smlf if (ddi_copyout(&cmd32, outaddr, 850507c3241Smlf sizeof (struct dadkio_rwcmd32), flag)) 851507c3241Smlf return (EFAULT); 852507c3241Smlf break; 853507c3241Smlf } 854507c3241Smlf case DDI_MODEL_NONE: { 855507c3241Smlf if (ddi_copyout(rwcmdp, outaddr, 856507c3241Smlf sizeof (struct dadkio_rwcmd), flag)) 857507c3241Smlf return (EFAULT); 858507c3241Smlf } 859507c3241Smlf } 860507c3241Smlf return (0); 861507c3241Smlf } 862507c3241Smlf 863507c3241Smlf /* 864507c3241Smlf * ioctl routine 865507c3241Smlf */ 866507c3241Smlf static int 867507c3241Smlf cmdkioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *credp, int *rvalp) 868507c3241Smlf { 869507c3241Smlf int instance; 870507c3241Smlf struct scsi_device *devp; 871507c3241Smlf struct cmdk *dkp; 872507c3241Smlf char data[NBPSCTR]; 873507c3241Smlf 874507c3241Smlf instance = CMDKUNIT(dev); 875507c3241Smlf if (!(dkp = ddi_get_soft_state(cmdk_state, instance))) 876507c3241Smlf return (ENXIO); 877507c3241Smlf 8782df1fe9cSrandyf mutex_enter(&dkp->dk_mutex); 8792df1fe9cSrandyf while (dkp->dk_flag & CMDK_SUSPEND) { 8802df1fe9cSrandyf cv_wait(&dkp->dk_suspend_cv, &dkp->dk_mutex); 8812df1fe9cSrandyf } 8822df1fe9cSrandyf mutex_exit(&dkp->dk_mutex); 8832df1fe9cSrandyf 884507c3241Smlf bzero(data, sizeof (data)); 885507c3241Smlf 886507c3241Smlf switch (cmd) { 887507c3241Smlf 888507c3241Smlf case DKIOCGMEDIAINFO: { 889507c3241Smlf struct dk_minfo media_info; 890507c3241Smlf struct tgdk_geom phyg; 891507c3241Smlf 892507c3241Smlf /* dadk_getphygeom always returns success */ 893507c3241Smlf (void) dadk_getphygeom(DKTP_DATA, &phyg); 894507c3241Smlf 895507c3241Smlf media_info.dki_lbsize = phyg.g_secsiz; 896507c3241Smlf media_info.dki_capacity = phyg.g_cap; 897507c3241Smlf media_info.dki_media_type = DK_FIXED_DISK; 898507c3241Smlf 899507c3241Smlf if (ddi_copyout(&media_info, (void *)arg, 900507c3241Smlf sizeof (struct dk_minfo), flag)) { 901507c3241Smlf return (EFAULT); 902507c3241Smlf } else { 903507c3241Smlf return (0); 904507c3241Smlf } 905507c3241Smlf } 906507c3241Smlf 907507c3241Smlf case DKIOCINFO: { 908507c3241Smlf struct dk_cinfo *info = (struct dk_cinfo *)data; 909507c3241Smlf 910507c3241Smlf /* controller information */ 911507c3241Smlf info->dki_ctype = (DKTP_EXT->tg_ctype); 912507c3241Smlf info->dki_cnum = ddi_get_instance(ddi_get_parent(dkp->dk_dip)); 913507c3241Smlf (void) strcpy(info->dki_cname, 914507c3241Smlf ddi_get_name(ddi_get_parent(dkp->dk_dip))); 915507c3241Smlf 916507c3241Smlf /* Unit Information */ 917507c3241Smlf info->dki_unit = ddi_get_instance(dkp->dk_dip); 918507c3241Smlf devp = ddi_get_driver_private(dkp->dk_dip); 919507c3241Smlf info->dki_slave = (CMDEV_TARG(devp)<<3) | CMDEV_LUN(devp); 920507c3241Smlf (void) strcpy(info->dki_dname, ddi_driver_name(dkp->dk_dip)); 921507c3241Smlf info->dki_flags = DKI_FMTVOL; 922507c3241Smlf info->dki_partition = CMDKPART(dev); 923507c3241Smlf 924507c3241Smlf info->dki_maxtransfer = maxphys / DEV_BSIZE; 925507c3241Smlf info->dki_addr = 1; 926507c3241Smlf info->dki_space = 0; 927507c3241Smlf info->dki_prio = 0; 928507c3241Smlf info->dki_vec = 0; 929507c3241Smlf 930507c3241Smlf if (ddi_copyout(data, (void *)arg, sizeof (*info), flag)) 931507c3241Smlf return (EFAULT); 932507c3241Smlf else 933507c3241Smlf return (0); 934507c3241Smlf } 935507c3241Smlf 936507c3241Smlf case DKIOCSTATE: { 937507c3241Smlf int state; 938507c3241Smlf int rval; 939507c3241Smlf diskaddr_t p_lblksrt; 940507c3241Smlf diskaddr_t p_lblkcnt; 941507c3241Smlf 942507c3241Smlf if (ddi_copyin((void *)arg, &state, sizeof (int), flag)) 943507c3241Smlf return (EFAULT); 944507c3241Smlf 945507c3241Smlf /* dadk_check_media blocks until state changes */ 946507c3241Smlf if (rval = dadk_check_media(DKTP_DATA, &state)) 947507c3241Smlf return (rval); 948507c3241Smlf 949507c3241Smlf if (state == DKIO_INSERTED) { 950507c3241Smlf 951e8fb11a1Sshidokht if (cmlb_validate(dkp->dk_cmlbhandle, 0, 0) != 0) 952507c3241Smlf return (ENXIO); 953507c3241Smlf 954507c3241Smlf if (cmlb_partinfo(dkp->dk_cmlbhandle, CMDKPART(dev), 955e8fb11a1Sshidokht &p_lblkcnt, &p_lblksrt, NULL, NULL, 0)) 956507c3241Smlf return (ENXIO); 957507c3241Smlf 958507c3241Smlf if (p_lblkcnt <= 0) 959507c3241Smlf return (ENXIO); 960507c3241Smlf } 961507c3241Smlf 962507c3241Smlf if (ddi_copyout(&state, (caddr_t)arg, sizeof (int), flag)) 963507c3241Smlf return (EFAULT); 964507c3241Smlf 965507c3241Smlf return (0); 966507c3241Smlf } 967507c3241Smlf 968507c3241Smlf /* 969507c3241Smlf * is media removable? 970507c3241Smlf */ 971507c3241Smlf case DKIOCREMOVABLE: { 972507c3241Smlf int i; 973507c3241Smlf 974507c3241Smlf i = (DKTP_EXT->tg_rmb) ? 1 : 0; 975507c3241Smlf 976507c3241Smlf if (ddi_copyout(&i, (caddr_t)arg, sizeof (int), flag)) 977507c3241Smlf return (EFAULT); 978507c3241Smlf 979507c3241Smlf return (0); 980507c3241Smlf } 981507c3241Smlf 982507c3241Smlf case DKIOCADDBAD: 983507c3241Smlf /* 984507c3241Smlf * This is not an update mechanism to add bad blocks 985507c3241Smlf * to the bad block structures stored on disk. 986507c3241Smlf * 987507c3241Smlf * addbadsec(1M) will update the bad block data on disk 988507c3241Smlf * and use this ioctl to force the driver to re-initialize 989507c3241Smlf * the list of bad blocks in the driver. 990507c3241Smlf */ 991507c3241Smlf 992507c3241Smlf /* start BBH */ 993507c3241Smlf cmdk_bbh_reopen(dkp); 994507c3241Smlf return (0); 995507c3241Smlf 996507c3241Smlf case DKIOCG_PHYGEOM: 997507c3241Smlf case DKIOCG_VIRTGEOM: 998507c3241Smlf case DKIOCGGEOM: 999507c3241Smlf case DKIOCSGEOM: 1000507c3241Smlf case DKIOCGAPART: 1001507c3241Smlf case DKIOCSAPART: 1002507c3241Smlf case DKIOCGVTOC: 1003507c3241Smlf case DKIOCSVTOC: 1004507c3241Smlf case DKIOCPARTINFO: 1005342440ecSPrasad Singamsetty case DKIOCGEXTVTOC: 1006342440ecSPrasad Singamsetty case DKIOCSEXTVTOC: 1007342440ecSPrasad Singamsetty case DKIOCEXTPARTINFO: 1008507c3241Smlf case DKIOCGMBOOT: 1009507c3241Smlf case DKIOCSMBOOT: 1010507c3241Smlf case DKIOCGETEFI: 1011507c3241Smlf case DKIOCSETEFI: 1012507c3241Smlf case DKIOCPARTITION: 1013aa1b14e7SSheshadri Vasudevan case DKIOCSETEXTPART: 1014507c3241Smlf { 1015507c3241Smlf int rc; 1016507c3241Smlf 1017e8fb11a1Sshidokht rc = cmlb_ioctl(dkp->dk_cmlbhandle, dev, cmd, arg, flag, 1018e8fb11a1Sshidokht credp, rvalp, 0); 10193b22643dSJan Setje-Eilers if (cmd == DKIOCSVTOC || cmd == DKIOCSEXTVTOC) 1020507c3241Smlf cmdk_devid_setup(dkp); 1021507c3241Smlf return (rc); 1022507c3241Smlf } 1023507c3241Smlf 1024507c3241Smlf case DIOCTL_RWCMD: { 1025507c3241Smlf struct dadkio_rwcmd *rwcmdp; 1026507c3241Smlf int status; 1027507c3241Smlf 1028507c3241Smlf rwcmdp = kmem_alloc(sizeof (struct dadkio_rwcmd), KM_SLEEP); 1029507c3241Smlf 1030507c3241Smlf status = rwcmd_copyin(rwcmdp, (caddr_t)arg, flag); 1031507c3241Smlf 1032507c3241Smlf if (status == 0) { 1033507c3241Smlf bzero(&(rwcmdp->status), sizeof (struct dadkio_status)); 1034507c3241Smlf status = dadk_ioctl(DKTP_DATA, 1035507c3241Smlf dev, 1036507c3241Smlf cmd, 1037507c3241Smlf (uintptr_t)rwcmdp, 1038507c3241Smlf flag, 1039507c3241Smlf credp, 1040507c3241Smlf rvalp); 1041507c3241Smlf } 1042507c3241Smlf if (status == 0) 1043507c3241Smlf status = rwcmd_copyout(rwcmdp, (caddr_t)arg, flag); 1044507c3241Smlf 1045507c3241Smlf kmem_free(rwcmdp, sizeof (struct dadkio_rwcmd)); 1046507c3241Smlf return (status); 1047507c3241Smlf } 1048507c3241Smlf 1049507c3241Smlf default: 1050507c3241Smlf return (dadk_ioctl(DKTP_DATA, 1051507c3241Smlf dev, 1052507c3241Smlf cmd, 1053507c3241Smlf arg, 1054507c3241Smlf flag, 1055507c3241Smlf credp, 1056507c3241Smlf rvalp)); 1057507c3241Smlf } 1058507c3241Smlf } 1059507c3241Smlf 1060507c3241Smlf /*ARGSUSED1*/ 1061507c3241Smlf static int 1062507c3241Smlf cmdkclose(dev_t dev, int flag, int otyp, cred_t *credp) 1063507c3241Smlf { 1064507c3241Smlf int part; 1065507c3241Smlf ulong_t partbit; 1066507c3241Smlf int instance; 1067507c3241Smlf struct cmdk *dkp; 1068507c3241Smlf int lastclose = 1; 1069507c3241Smlf int i; 1070507c3241Smlf 1071507c3241Smlf instance = CMDKUNIT(dev); 1072507c3241Smlf if (!(dkp = ddi_get_soft_state(cmdk_state, instance)) || 1073507c3241Smlf (otyp >= OTYPCNT)) 1074507c3241Smlf return (ENXIO); 1075507c3241Smlf 1076507c3241Smlf mutex_enter(&dkp->dk_mutex); 1077507c3241Smlf 1078507c3241Smlf /* check if device has been opened */ 107906bbe1e0Sedp ASSERT(cmdk_isopen(dkp, dev)); 1080507c3241Smlf if (!(dkp->dk_flag & CMDK_OPEN)) { 1081507c3241Smlf mutex_exit(&dkp->dk_mutex); 1082507c3241Smlf return (ENXIO); 1083507c3241Smlf } 1084507c3241Smlf 10852df1fe9cSrandyf while (dkp->dk_flag & CMDK_SUSPEND) { 10862df1fe9cSrandyf cv_wait(&dkp->dk_suspend_cv, &dkp->dk_mutex); 10872df1fe9cSrandyf } 10882df1fe9cSrandyf 1089507c3241Smlf part = CMDKPART(dev); 1090507c3241Smlf partbit = 1 << part; 1091507c3241Smlf 1092507c3241Smlf /* account for close */ 1093507c3241Smlf if (otyp == OTYP_LYR) { 109406bbe1e0Sedp ASSERT(dkp->dk_open_lyr[part] > 0); 1095507c3241Smlf if (dkp->dk_open_lyr[part]) 1096507c3241Smlf dkp->dk_open_lyr[part]--; 109706bbe1e0Sedp } else { 109806bbe1e0Sedp ASSERT((dkp->dk_open_reg[otyp] & partbit) != 0); 1099507c3241Smlf dkp->dk_open_reg[otyp] &= ~partbit; 110006bbe1e0Sedp } 1101507c3241Smlf dkp->dk_open_exl &= ~partbit; 1102507c3241Smlf 1103507c3241Smlf for (i = 0; i < CMDK_MAXPART; i++) 1104507c3241Smlf if (dkp->dk_open_lyr[i] != 0) { 1105507c3241Smlf lastclose = 0; 1106507c3241Smlf break; 1107507c3241Smlf } 1108507c3241Smlf 1109507c3241Smlf if (lastclose) 1110507c3241Smlf for (i = 0; i < OTYPCNT; i++) 1111507c3241Smlf if (dkp->dk_open_reg[i] != 0) { 1112507c3241Smlf lastclose = 0; 1113507c3241Smlf break; 1114507c3241Smlf } 1115507c3241Smlf 1116507c3241Smlf mutex_exit(&dkp->dk_mutex); 1117507c3241Smlf 1118507c3241Smlf if (lastclose) 1119e8fb11a1Sshidokht cmlb_invalidate(dkp->dk_cmlbhandle, 0); 1120507c3241Smlf 1121507c3241Smlf return (DDI_SUCCESS); 1122507c3241Smlf } 1123507c3241Smlf 1124507c3241Smlf /*ARGSUSED3*/ 1125507c3241Smlf static int 1126507c3241Smlf cmdkopen(dev_t *dev_p, int flag, int otyp, cred_t *credp) 1127507c3241Smlf { 1128507c3241Smlf dev_t dev = *dev_p; 1129507c3241Smlf int part; 1130507c3241Smlf ulong_t partbit; 1131507c3241Smlf int instance; 1132507c3241Smlf struct cmdk *dkp; 1133507c3241Smlf diskaddr_t p_lblksrt; 1134507c3241Smlf diskaddr_t p_lblkcnt; 1135507c3241Smlf int i; 1136507c3241Smlf int nodelay; 1137507c3241Smlf 1138507c3241Smlf instance = CMDKUNIT(dev); 1139507c3241Smlf if (!(dkp = ddi_get_soft_state(cmdk_state, instance))) 1140507c3241Smlf return (ENXIO); 1141507c3241Smlf 1142507c3241Smlf if (otyp >= OTYPCNT) 1143507c3241Smlf return (EINVAL); 1144507c3241Smlf 11452df1fe9cSrandyf mutex_enter(&dkp->dk_mutex); 11462df1fe9cSrandyf while (dkp->dk_flag & CMDK_SUSPEND) { 11472df1fe9cSrandyf cv_wait(&dkp->dk_suspend_cv, &dkp->dk_mutex); 11482df1fe9cSrandyf } 11492df1fe9cSrandyf mutex_exit(&dkp->dk_mutex); 11502df1fe9cSrandyf 1151507c3241Smlf part = CMDKPART(dev); 1152507c3241Smlf partbit = 1 << part; 1153507c3241Smlf nodelay = (flag & (FNDELAY | FNONBLOCK)); 1154507c3241Smlf 1155507c3241Smlf mutex_enter(&dkp->dk_mutex); 1156507c3241Smlf 1157e8fb11a1Sshidokht if (cmlb_validate(dkp->dk_cmlbhandle, 0, 0) != 0) { 1158507c3241Smlf 1159507c3241Smlf /* fail if not doing non block open */ 1160507c3241Smlf if (!nodelay) { 1161507c3241Smlf mutex_exit(&dkp->dk_mutex); 1162507c3241Smlf return (ENXIO); 1163507c3241Smlf } 1164507c3241Smlf } else if (cmlb_partinfo(dkp->dk_cmlbhandle, part, &p_lblkcnt, 1165e8fb11a1Sshidokht &p_lblksrt, NULL, NULL, 0) == 0) { 1166507c3241Smlf 1167507c3241Smlf if (p_lblkcnt <= 0 && (!nodelay || otyp != OTYP_CHR)) { 1168507c3241Smlf mutex_exit(&dkp->dk_mutex); 1169507c3241Smlf return (ENXIO); 1170507c3241Smlf } 1171507c3241Smlf } else { 1172507c3241Smlf /* fail if not doing non block open */ 1173507c3241Smlf if (!nodelay) { 1174507c3241Smlf mutex_exit(&dkp->dk_mutex); 1175507c3241Smlf return (ENXIO); 1176507c3241Smlf } 1177507c3241Smlf } 1178507c3241Smlf 1179507c3241Smlf if ((DKTP_EXT->tg_rdonly) && (flag & FWRITE)) { 1180507c3241Smlf mutex_exit(&dkp->dk_mutex); 1181507c3241Smlf return (EROFS); 1182507c3241Smlf } 1183507c3241Smlf 1184507c3241Smlf /* check for part already opend exclusively */ 1185507c3241Smlf if (dkp->dk_open_exl & partbit) 1186507c3241Smlf goto excl_open_fail; 1187507c3241Smlf 1188507c3241Smlf /* check if we can establish exclusive open */ 1189507c3241Smlf if (flag & FEXCL) { 1190507c3241Smlf if (dkp->dk_open_lyr[part]) 1191507c3241Smlf goto excl_open_fail; 1192507c3241Smlf for (i = 0; i < OTYPCNT; i++) { 1193507c3241Smlf if (dkp->dk_open_reg[i] & partbit) 1194507c3241Smlf goto excl_open_fail; 1195507c3241Smlf } 1196507c3241Smlf } 1197507c3241Smlf 1198507c3241Smlf /* open will succeed, account for open */ 1199507c3241Smlf dkp->dk_flag |= CMDK_OPEN; 1200507c3241Smlf if (otyp == OTYP_LYR) 1201507c3241Smlf dkp->dk_open_lyr[part]++; 1202507c3241Smlf else 1203507c3241Smlf dkp->dk_open_reg[otyp] |= partbit; 1204507c3241Smlf if (flag & FEXCL) 1205507c3241Smlf dkp->dk_open_exl |= partbit; 1206507c3241Smlf 1207507c3241Smlf mutex_exit(&dkp->dk_mutex); 1208507c3241Smlf return (DDI_SUCCESS); 1209507c3241Smlf 1210507c3241Smlf excl_open_fail: 1211507c3241Smlf mutex_exit(&dkp->dk_mutex); 1212507c3241Smlf return (EBUSY); 1213507c3241Smlf } 1214507c3241Smlf 1215507c3241Smlf /* 1216507c3241Smlf * read routine 1217507c3241Smlf */ 1218507c3241Smlf /*ARGSUSED2*/ 1219507c3241Smlf static int 1220507c3241Smlf cmdkread(dev_t dev, struct uio *uio, cred_t *credp) 1221507c3241Smlf { 1222507c3241Smlf return (cmdkrw(dev, uio, B_READ)); 1223507c3241Smlf } 1224507c3241Smlf 1225507c3241Smlf /* 1226507c3241Smlf * async read routine 1227507c3241Smlf */ 1228507c3241Smlf /*ARGSUSED2*/ 1229507c3241Smlf static int 1230507c3241Smlf cmdkaread(dev_t dev, struct aio_req *aio, cred_t *credp) 1231507c3241Smlf { 1232507c3241Smlf return (cmdkarw(dev, aio, B_READ)); 1233507c3241Smlf } 1234507c3241Smlf 1235507c3241Smlf /* 1236507c3241Smlf * write routine 1237507c3241Smlf */ 1238507c3241Smlf /*ARGSUSED2*/ 1239507c3241Smlf static int 1240507c3241Smlf cmdkwrite(dev_t dev, struct uio *uio, cred_t *credp) 1241507c3241Smlf { 1242507c3241Smlf return (cmdkrw(dev, uio, B_WRITE)); 1243507c3241Smlf } 1244507c3241Smlf 1245507c3241Smlf /* 1246507c3241Smlf * async write routine 1247507c3241Smlf */ 1248507c3241Smlf /*ARGSUSED2*/ 1249507c3241Smlf static int 1250507c3241Smlf cmdkawrite(dev_t dev, struct aio_req *aio, cred_t *credp) 1251507c3241Smlf { 1252507c3241Smlf return (cmdkarw(dev, aio, B_WRITE)); 1253507c3241Smlf } 1254507c3241Smlf 1255507c3241Smlf static void 1256507c3241Smlf cmdkmin(struct buf *bp) 1257507c3241Smlf { 1258507c3241Smlf if (bp->b_bcount > DK_MAXRECSIZE) 1259507c3241Smlf bp->b_bcount = DK_MAXRECSIZE; 1260507c3241Smlf } 1261507c3241Smlf 1262507c3241Smlf static int 1263507c3241Smlf cmdkrw(dev_t dev, struct uio *uio, int flag) 1264507c3241Smlf { 12652df1fe9cSrandyf int instance; 12662df1fe9cSrandyf struct cmdk *dkp; 12672df1fe9cSrandyf 12682df1fe9cSrandyf instance = CMDKUNIT(dev); 12692df1fe9cSrandyf if (!(dkp = ddi_get_soft_state(cmdk_state, instance))) 12702df1fe9cSrandyf return (ENXIO); 12712df1fe9cSrandyf 12722df1fe9cSrandyf mutex_enter(&dkp->dk_mutex); 12732df1fe9cSrandyf while (dkp->dk_flag & CMDK_SUSPEND) { 12742df1fe9cSrandyf cv_wait(&dkp->dk_suspend_cv, &dkp->dk_mutex); 12752df1fe9cSrandyf } 12762df1fe9cSrandyf mutex_exit(&dkp->dk_mutex); 12772df1fe9cSrandyf 1278507c3241Smlf return (physio(cmdkstrategy, (struct buf *)0, dev, flag, cmdkmin, uio)); 1279507c3241Smlf } 1280507c3241Smlf 1281507c3241Smlf static int 1282507c3241Smlf cmdkarw(dev_t dev, struct aio_req *aio, int flag) 1283507c3241Smlf { 12842df1fe9cSrandyf int instance; 12852df1fe9cSrandyf struct cmdk *dkp; 12862df1fe9cSrandyf 12872df1fe9cSrandyf instance = CMDKUNIT(dev); 12882df1fe9cSrandyf if (!(dkp = ddi_get_soft_state(cmdk_state, instance))) 12892df1fe9cSrandyf return (ENXIO); 12902df1fe9cSrandyf 12912df1fe9cSrandyf mutex_enter(&dkp->dk_mutex); 12922df1fe9cSrandyf while (dkp->dk_flag & CMDK_SUSPEND) { 12932df1fe9cSrandyf cv_wait(&dkp->dk_suspend_cv, &dkp->dk_mutex); 12942df1fe9cSrandyf } 12952df1fe9cSrandyf mutex_exit(&dkp->dk_mutex); 12962df1fe9cSrandyf 1297507c3241Smlf return (aphysio(cmdkstrategy, anocancel, dev, flag, cmdkmin, aio)); 1298507c3241Smlf } 1299507c3241Smlf 1300507c3241Smlf /* 1301507c3241Smlf * strategy routine 1302507c3241Smlf */ 1303507c3241Smlf static int 1304507c3241Smlf cmdkstrategy(struct buf *bp) 1305507c3241Smlf { 1306507c3241Smlf int instance; 1307507c3241Smlf struct cmdk *dkp; 1308507c3241Smlf long d_cnt; 1309507c3241Smlf diskaddr_t p_lblksrt; 1310507c3241Smlf diskaddr_t p_lblkcnt; 1311507c3241Smlf 1312507c3241Smlf instance = CMDKUNIT(bp->b_edev); 1313507c3241Smlf if (cmdk_indump || !(dkp = ddi_get_soft_state(cmdk_state, instance)) || 1314507c3241Smlf (dkblock(bp) < 0)) { 1315507c3241Smlf bp->b_resid = bp->b_bcount; 1316507c3241Smlf SETBPERR(bp, ENXIO); 1317507c3241Smlf biodone(bp); 1318507c3241Smlf return (0); 1319507c3241Smlf } 1320507c3241Smlf 13212df1fe9cSrandyf mutex_enter(&dkp->dk_mutex); 132206bbe1e0Sedp ASSERT(cmdk_isopen(dkp, bp->b_edev)); 13232df1fe9cSrandyf while (dkp->dk_flag & CMDK_SUSPEND) { 13242df1fe9cSrandyf cv_wait(&dkp->dk_suspend_cv, &dkp->dk_mutex); 13252df1fe9cSrandyf } 13262df1fe9cSrandyf mutex_exit(&dkp->dk_mutex); 13272df1fe9cSrandyf 1328507c3241Smlf bp->b_flags &= ~(B_DONE|B_ERROR); 1329507c3241Smlf bp->b_resid = 0; 1330507c3241Smlf bp->av_back = NULL; 1331507c3241Smlf 1332507c3241Smlf /* 1333507c3241Smlf * only re-read the vtoc if necessary (force == FALSE) 1334507c3241Smlf */ 1335e8fb11a1Sshidokht if (cmlb_partinfo(dkp->dk_cmlbhandle, CMDKPART(bp->b_edev), 1336e8fb11a1Sshidokht &p_lblkcnt, &p_lblksrt, NULL, NULL, 0)) { 1337507c3241Smlf SETBPERR(bp, ENXIO); 1338507c3241Smlf } 1339507c3241Smlf 1340507c3241Smlf if ((bp->b_bcount & (NBPSCTR-1)) || (dkblock(bp) > p_lblkcnt)) 1341507c3241Smlf SETBPERR(bp, ENXIO); 1342507c3241Smlf 1343507c3241Smlf if ((bp->b_flags & B_ERROR) || (dkblock(bp) == p_lblkcnt)) { 1344507c3241Smlf bp->b_resid = bp->b_bcount; 1345507c3241Smlf biodone(bp); 1346507c3241Smlf return (0); 1347507c3241Smlf } 1348507c3241Smlf 1349507c3241Smlf d_cnt = bp->b_bcount >> SCTRSHFT; 1350507c3241Smlf if ((dkblock(bp) + d_cnt) > p_lblkcnt) { 1351507c3241Smlf bp->b_resid = ((dkblock(bp) + d_cnt) - p_lblkcnt) << SCTRSHFT; 1352507c3241Smlf bp->b_bcount -= bp->b_resid; 1353507c3241Smlf } 1354507c3241Smlf 1355507c3241Smlf SET_BP_SEC(bp, ((ulong_t)(p_lblksrt + dkblock(bp)))); 1356507c3241Smlf if (dadk_strategy(DKTP_DATA, bp) != DDI_SUCCESS) { 1357507c3241Smlf bp->b_resid += bp->b_bcount; 1358507c3241Smlf biodone(bp); 1359507c3241Smlf } 1360507c3241Smlf return (0); 1361507c3241Smlf } 1362507c3241Smlf 1363507c3241Smlf static int 1364507c3241Smlf cmdk_create_obj(dev_info_t *dip, struct cmdk *dkp) 1365507c3241Smlf { 1366507c3241Smlf struct scsi_device *devp; 1367507c3241Smlf opaque_t queobjp = NULL; 1368507c3241Smlf opaque_t flcobjp = NULL; 1369507c3241Smlf char que_keyvalp[64]; 1370507c3241Smlf int que_keylen; 1371507c3241Smlf char flc_keyvalp[64]; 1372507c3241Smlf int flc_keylen; 1373507c3241Smlf 1374507c3241Smlf ASSERT(mutex_owned(&dkp->dk_mutex)); 1375507c3241Smlf 1376507c3241Smlf /* Create linkage to queueing routines based on property */ 1377507c3241Smlf que_keylen = sizeof (que_keyvalp); 1378507c3241Smlf if (ddi_prop_op(DDI_DEV_T_NONE, dip, PROP_LEN_AND_VAL_BUF, 1379507c3241Smlf DDI_PROP_CANSLEEP, "queue", que_keyvalp, &que_keylen) != 1380507c3241Smlf DDI_PROP_SUCCESS) { 1381507c3241Smlf cmn_err(CE_WARN, "cmdk_create_obj: queue property undefined"); 1382507c3241Smlf return (DDI_FAILURE); 1383507c3241Smlf } 1384507c3241Smlf que_keyvalp[que_keylen] = (char)0; 1385507c3241Smlf 1386507c3241Smlf if (strcmp(que_keyvalp, "qfifo") == 0) { 1387507c3241Smlf queobjp = (opaque_t)qfifo_create(); 1388507c3241Smlf } else if (strcmp(que_keyvalp, "qsort") == 0) { 1389507c3241Smlf queobjp = (opaque_t)qsort_create(); 1390507c3241Smlf } else { 1391507c3241Smlf return (DDI_FAILURE); 1392507c3241Smlf } 1393507c3241Smlf 1394507c3241Smlf /* Create linkage to dequeueing routines based on property */ 1395507c3241Smlf flc_keylen = sizeof (flc_keyvalp); 1396507c3241Smlf if (ddi_prop_op(DDI_DEV_T_NONE, dip, PROP_LEN_AND_VAL_BUF, 1397507c3241Smlf DDI_PROP_CANSLEEP, "flow_control", flc_keyvalp, &flc_keylen) != 1398507c3241Smlf DDI_PROP_SUCCESS) { 1399507c3241Smlf cmn_err(CE_WARN, 1400507c3241Smlf "cmdk_create_obj: flow-control property undefined"); 1401507c3241Smlf return (DDI_FAILURE); 1402507c3241Smlf } 1403507c3241Smlf 1404507c3241Smlf flc_keyvalp[flc_keylen] = (char)0; 1405507c3241Smlf 1406507c3241Smlf if (strcmp(flc_keyvalp, "dsngl") == 0) { 1407507c3241Smlf flcobjp = (opaque_t)dsngl_create(); 1408507c3241Smlf } else if (strcmp(flc_keyvalp, "dmult") == 0) { 1409507c3241Smlf flcobjp = (opaque_t)dmult_create(); 1410507c3241Smlf } else { 1411507c3241Smlf return (DDI_FAILURE); 1412507c3241Smlf } 1413507c3241Smlf 1414507c3241Smlf /* populate bbh_obj object stored in dkp */ 1415507c3241Smlf dkp->dk_bbh_obj.bbh_data = dkp; 1416507c3241Smlf dkp->dk_bbh_obj.bbh_ops = &cmdk_bbh_ops; 1417507c3241Smlf 1418507c3241Smlf /* create linkage to dadk */ 1419507c3241Smlf dkp->dk_tgobjp = (opaque_t)dadk_create(); 1420507c3241Smlf 1421507c3241Smlf devp = ddi_get_driver_private(dip); 1422507c3241Smlf (void) dadk_init(DKTP_DATA, devp, flcobjp, queobjp, &dkp->dk_bbh_obj, 1423507c3241Smlf NULL); 1424507c3241Smlf 1425507c3241Smlf return (DDI_SUCCESS); 1426507c3241Smlf } 1427507c3241Smlf 1428507c3241Smlf static void 1429507c3241Smlf cmdk_destroy_obj(dev_info_t *dip, struct cmdk *dkp) 1430507c3241Smlf { 1431507c3241Smlf char que_keyvalp[64]; 1432507c3241Smlf int que_keylen; 1433507c3241Smlf char flc_keyvalp[64]; 1434507c3241Smlf int flc_keylen; 1435507c3241Smlf 1436507c3241Smlf ASSERT(mutex_owned(&dkp->dk_mutex)); 1437507c3241Smlf 1438507c3241Smlf (void) dadk_free((dkp->dk_tgobjp)); 1439507c3241Smlf dkp->dk_tgobjp = NULL; 1440507c3241Smlf 1441507c3241Smlf que_keylen = sizeof (que_keyvalp); 1442507c3241Smlf if (ddi_prop_op(DDI_DEV_T_NONE, dip, PROP_LEN_AND_VAL_BUF, 1443507c3241Smlf DDI_PROP_CANSLEEP, "queue", que_keyvalp, &que_keylen) != 1444507c3241Smlf DDI_PROP_SUCCESS) { 1445507c3241Smlf cmn_err(CE_WARN, "cmdk_destroy_obj: queue property undefined"); 1446507c3241Smlf return; 1447507c3241Smlf } 1448507c3241Smlf que_keyvalp[que_keylen] = (char)0; 1449507c3241Smlf 1450507c3241Smlf flc_keylen = sizeof (flc_keyvalp); 1451507c3241Smlf if (ddi_prop_op(DDI_DEV_T_NONE, dip, PROP_LEN_AND_VAL_BUF, 1452507c3241Smlf DDI_PROP_CANSLEEP, "flow_control", flc_keyvalp, &flc_keylen) != 1453507c3241Smlf DDI_PROP_SUCCESS) { 1454507c3241Smlf cmn_err(CE_WARN, 1455507c3241Smlf "cmdk_destroy_obj: flow-control property undefined"); 1456507c3241Smlf return; 1457507c3241Smlf } 1458507c3241Smlf flc_keyvalp[flc_keylen] = (char)0; 1459507c3241Smlf } 1460e8fb11a1Sshidokht /*ARGSUSED5*/ 1461507c3241Smlf static int 1462e8fb11a1Sshidokht cmdk_lb_rdwr(dev_info_t *dip, uchar_t cmd, void *bufaddr, 1463e8fb11a1Sshidokht diskaddr_t start, size_t count, void *tg_cookie) 1464507c3241Smlf { 1465507c3241Smlf struct cmdk *dkp; 1466507c3241Smlf opaque_t handle; 1467507c3241Smlf int rc = 0; 1468507c3241Smlf char *bufa; 1469de6d0fcdSShidokht Yadegari size_t buflen; 1470507c3241Smlf 1471507c3241Smlf dkp = ddi_get_soft_state(cmdk_state, ddi_get_instance(dip)); 1472507c3241Smlf if (dkp == NULL) 1473507c3241Smlf return (ENXIO); 1474507c3241Smlf 1475507c3241Smlf if (cmd != TG_READ && cmd != TG_WRITE) 1476507c3241Smlf return (EINVAL); 1477507c3241Smlf 1478de6d0fcdSShidokht Yadegari /* buflen must be multiple of 512 */ 1479de6d0fcdSShidokht Yadegari buflen = (count + NBPSCTR - 1) & -NBPSCTR; 1480de6d0fcdSShidokht Yadegari handle = dadk_iob_alloc(DKTP_DATA, start, buflen, KM_SLEEP); 1481507c3241Smlf if (!handle) 1482507c3241Smlf return (ENOMEM); 1483507c3241Smlf 1484507c3241Smlf if (cmd == TG_READ) { 1485507c3241Smlf bufa = dadk_iob_xfer(DKTP_DATA, handle, B_READ); 1486507c3241Smlf if (!bufa) 1487507c3241Smlf rc = EIO; 1488507c3241Smlf else 1489507c3241Smlf bcopy(bufa, bufaddr, count); 1490507c3241Smlf } else { 1491507c3241Smlf bufa = dadk_iob_htoc(DKTP_DATA, handle); 1492507c3241Smlf bcopy(bufaddr, bufa, count); 1493507c3241Smlf bufa = dadk_iob_xfer(DKTP_DATA, handle, B_WRITE); 1494507c3241Smlf if (!bufa) 1495507c3241Smlf rc = EIO; 1496507c3241Smlf } 1497507c3241Smlf (void) dadk_iob_free(DKTP_DATA, handle); 1498507c3241Smlf 1499507c3241Smlf return (rc); 1500507c3241Smlf } 1501507c3241Smlf 1502e8fb11a1Sshidokht /*ARGSUSED3*/ 1503507c3241Smlf static int 1504e8fb11a1Sshidokht cmdk_lb_getinfo(dev_info_t *dip, int cmd, void *arg, void *tg_cookie) 1505507c3241Smlf { 1506e8fb11a1Sshidokht 1507507c3241Smlf struct cmdk *dkp; 1508507c3241Smlf struct tgdk_geom phyg; 1509507c3241Smlf 1510e8fb11a1Sshidokht 1511507c3241Smlf dkp = ddi_get_soft_state(cmdk_state, ddi_get_instance(dip)); 1512507c3241Smlf if (dkp == NULL) 1513507c3241Smlf return (ENXIO); 1514507c3241Smlf 1515e8fb11a1Sshidokht switch (cmd) { 1516e8fb11a1Sshidokht case TG_GETPHYGEOM: { 1517e8fb11a1Sshidokht cmlb_geom_t *phygeomp = (cmlb_geom_t *)arg; 1518e8fb11a1Sshidokht 1519507c3241Smlf /* dadk_getphygeom always returns success */ 1520507c3241Smlf (void) dadk_getphygeom(DKTP_DATA, &phyg); 1521507c3241Smlf 1522e8fb11a1Sshidokht phygeomp->g_capacity = phyg.g_cap; 1523e8fb11a1Sshidokht phygeomp->g_nsect = phyg.g_sec; 1524e8fb11a1Sshidokht phygeomp->g_nhead = phyg.g_head; 1525e8fb11a1Sshidokht phygeomp->g_acyl = phyg.g_acyl; 1526e8fb11a1Sshidokht phygeomp->g_ncyl = phyg.g_cyl; 1527e8fb11a1Sshidokht phygeomp->g_secsize = phyg.g_secsiz; 1528e8fb11a1Sshidokht phygeomp->g_intrlv = 1; 1529e8fb11a1Sshidokht phygeomp->g_rpm = 3600; 1530507c3241Smlf 1531507c3241Smlf return (0); 1532507c3241Smlf } 1533507c3241Smlf 1534e8fb11a1Sshidokht case TG_GETVIRTGEOM: { 1535e8fb11a1Sshidokht cmlb_geom_t *virtgeomp = (cmlb_geom_t *)arg; 1536507c3241Smlf diskaddr_t capacity; 1537507c3241Smlf 1538507c3241Smlf (void) dadk_getgeom(DKTP_DATA, &phyg); 1539507c3241Smlf capacity = phyg.g_cap; 1540507c3241Smlf 1541507c3241Smlf /* 1542507c3241Smlf * If the controller returned us something that doesn't 1543507c3241Smlf * really fit into an Int 13/function 8 geometry 1544507c3241Smlf * result, just fail the ioctl. See PSARC 1998/313. 1545507c3241Smlf */ 1546507c3241Smlf if (capacity < 0 || capacity >= 63 * 254 * 1024) 1547507c3241Smlf return (EINVAL); 1548507c3241Smlf 1549507c3241Smlf virtgeomp->g_capacity = capacity; 1550507c3241Smlf virtgeomp->g_nsect = 63; 1551507c3241Smlf virtgeomp->g_nhead = 254; 1552507c3241Smlf virtgeomp->g_ncyl = capacity / (63 * 254); 1553507c3241Smlf virtgeomp->g_acyl = 0; 1554507c3241Smlf virtgeomp->g_secsize = 512; 1555507c3241Smlf virtgeomp->g_intrlv = 1; 1556507c3241Smlf virtgeomp->g_rpm = 3600; 1557507c3241Smlf 1558507c3241Smlf return (0); 1559507c3241Smlf } 1560507c3241Smlf 1561e8fb11a1Sshidokht case TG_GETCAPACITY: 1562e8fb11a1Sshidokht case TG_GETBLOCKSIZE: 1563507c3241Smlf { 1564507c3241Smlf 1565507c3241Smlf /* dadk_getphygeom always returns success */ 1566507c3241Smlf (void) dadk_getphygeom(DKTP_DATA, &phyg); 1567e8fb11a1Sshidokht if (cmd == TG_GETCAPACITY) 1568e8fb11a1Sshidokht *(diskaddr_t *)arg = phyg.g_cap; 1569e8fb11a1Sshidokht else 1570e8fb11a1Sshidokht *(uint32_t *)arg = (uint32_t)phyg.g_secsiz; 1571507c3241Smlf 1572507c3241Smlf return (0); 1573507c3241Smlf } 1574507c3241Smlf 1575e8fb11a1Sshidokht case TG_GETATTR: { 1576e8fb11a1Sshidokht tg_attribute_t *tgattribute = (tg_attribute_t *)arg; 1577507c3241Smlf if ((DKTP_EXT->tg_rdonly)) 1578507c3241Smlf tgattribute->media_is_writable = FALSE; 1579507c3241Smlf else 1580507c3241Smlf tgattribute->media_is_writable = TRUE; 1581*b2b61b8fSYuri Pankov tgattribute->media_is_rotational = TRUE; 1582507c3241Smlf 1583507c3241Smlf return (0); 1584507c3241Smlf } 1585507c3241Smlf 1586e8fb11a1Sshidokht default: 1587e8fb11a1Sshidokht return (ENOTTY); 1588e8fb11a1Sshidokht } 1589e8fb11a1Sshidokht } 1590e8fb11a1Sshidokht 1591e8fb11a1Sshidokht 1592e8fb11a1Sshidokht 1593e8fb11a1Sshidokht 1594e8fb11a1Sshidokht 1595507c3241Smlf /* 1596507c3241Smlf * Create and register the devid. 1597507c3241Smlf * There are 4 different ways we can get a device id: 1598507c3241Smlf * 1. Already have one - nothing to do 1599507c3241Smlf * 2. Build one from the drive's model and serial numbers 1600507c3241Smlf * 3. Read one from the disk (first sector of last track) 1601507c3241Smlf * 4. Fabricate one and write it on the disk. 1602507c3241Smlf * If any of these succeeds, register the deviceid 1603507c3241Smlf */ 1604507c3241Smlf static void 1605507c3241Smlf cmdk_devid_setup(struct cmdk *dkp) 1606507c3241Smlf { 1607507c3241Smlf int rc; 1608507c3241Smlf 1609507c3241Smlf /* Try options until one succeeds, or all have failed */ 1610507c3241Smlf 1611507c3241Smlf /* 1. All done if already registered */ 1612507c3241Smlf if (dkp->dk_devid != NULL) 1613507c3241Smlf return; 1614507c3241Smlf 1615507c3241Smlf /* 2. Build a devid from the model and serial number */ 1616507c3241Smlf rc = cmdk_devid_modser(dkp); 1617507c3241Smlf if (rc != DDI_SUCCESS) { 1618507c3241Smlf /* 3. Read devid from the disk, if present */ 1619507c3241Smlf rc = cmdk_devid_read(dkp); 1620507c3241Smlf 1621507c3241Smlf /* 4. otherwise make one up and write it on the disk */ 1622507c3241Smlf if (rc != DDI_SUCCESS) 1623507c3241Smlf rc = cmdk_devid_fabricate(dkp); 1624507c3241Smlf } 1625507c3241Smlf 1626507c3241Smlf /* If we managed to get a devid any of the above ways, register it */ 1627507c3241Smlf if (rc == DDI_SUCCESS) 1628507c3241Smlf (void) ddi_devid_register(dkp->dk_dip, dkp->dk_devid); 1629507c3241Smlf 1630507c3241Smlf } 1631507c3241Smlf 1632507c3241Smlf /* 1633507c3241Smlf * Build a devid from the model and serial number 1634507c3241Smlf * Return DDI_SUCCESS or DDI_FAILURE. 1635507c3241Smlf */ 1636507c3241Smlf static int 1637507c3241Smlf cmdk_devid_modser(struct cmdk *dkp) 1638507c3241Smlf { 1639507c3241Smlf int rc = DDI_FAILURE; 1640507c3241Smlf char *hwid; 1641507c3241Smlf int modlen; 1642507c3241Smlf int serlen; 1643507c3241Smlf 1644507c3241Smlf /* 1645507c3241Smlf * device ID is a concatenation of model number, '=', serial number. 1646507c3241Smlf */ 1647507c3241Smlf hwid = kmem_alloc(CMDK_HWIDLEN, KM_SLEEP); 1648507c3241Smlf modlen = cmdk_get_modser(dkp, DIOCTL_GETMODEL, hwid, CMDK_HWIDLEN); 1649507c3241Smlf if (modlen == 0) { 1650507c3241Smlf rc = DDI_FAILURE; 1651507c3241Smlf goto err; 1652507c3241Smlf } 1653507c3241Smlf hwid[modlen++] = '='; 1654507c3241Smlf serlen = cmdk_get_modser(dkp, DIOCTL_GETSERIAL, 1655507c3241Smlf hwid + modlen, CMDK_HWIDLEN - modlen); 1656507c3241Smlf if (serlen == 0) { 1657507c3241Smlf rc = DDI_FAILURE; 1658507c3241Smlf goto err; 1659507c3241Smlf } 1660507c3241Smlf hwid[modlen + serlen] = 0; 1661507c3241Smlf 1662507c3241Smlf /* Initialize the device ID, trailing NULL not included */ 1663507c3241Smlf rc = ddi_devid_init(dkp->dk_dip, DEVID_ATA_SERIAL, modlen + serlen, 16643d510deaSMark Logan hwid, &dkp->dk_devid); 1665507c3241Smlf if (rc != DDI_SUCCESS) { 1666507c3241Smlf rc = DDI_FAILURE; 1667507c3241Smlf goto err; 1668507c3241Smlf } 1669507c3241Smlf 1670507c3241Smlf rc = DDI_SUCCESS; 1671507c3241Smlf 1672507c3241Smlf err: 1673507c3241Smlf kmem_free(hwid, CMDK_HWIDLEN); 1674507c3241Smlf return (rc); 1675507c3241Smlf } 1676507c3241Smlf 1677507c3241Smlf static int 1678507c3241Smlf cmdk_get_modser(struct cmdk *dkp, int ioccmd, char *buf, int len) 1679507c3241Smlf { 1680507c3241Smlf dadk_ioc_string_t strarg; 1681507c3241Smlf int rval; 1682507c3241Smlf char *s; 1683507c3241Smlf char ch; 1684507c3241Smlf boolean_t ret; 1685507c3241Smlf int i; 1686507c3241Smlf int tb; 1687507c3241Smlf 1688507c3241Smlf strarg.is_buf = buf; 1689507c3241Smlf strarg.is_size = len; 1690507c3241Smlf if (dadk_ioctl(DKTP_DATA, 1691507c3241Smlf dkp->dk_dev, 1692507c3241Smlf ioccmd, 1693507c3241Smlf (uintptr_t)&strarg, 1694507c3241Smlf FNATIVE | FKIOCTL, 1695507c3241Smlf NULL, 1696507c3241Smlf &rval) != 0) 1697507c3241Smlf return (0); 1698507c3241Smlf 1699507c3241Smlf /* 1700507c3241Smlf * valid model/serial string must contain a non-zero non-space 1701507c3241Smlf * trim trailing spaces/NULL 1702507c3241Smlf */ 1703507c3241Smlf ret = B_FALSE; 1704507c3241Smlf s = buf; 1705507c3241Smlf for (i = 0; i < strarg.is_size; i++) { 1706507c3241Smlf ch = *s++; 1707507c3241Smlf if (ch != ' ' && ch != '\0') 1708507c3241Smlf tb = i + 1; 1709507c3241Smlf if (ch != ' ' && ch != '\0' && ch != '0') 1710507c3241Smlf ret = B_TRUE; 1711507c3241Smlf } 1712507c3241Smlf 1713507c3241Smlf if (ret == B_FALSE) 1714507c3241Smlf return (0); 1715507c3241Smlf 1716507c3241Smlf return (tb); 1717507c3241Smlf } 1718507c3241Smlf 1719507c3241Smlf /* 1720507c3241Smlf * Read a devid from on the first block of the last track of 1721507c3241Smlf * the last cylinder. Make sure what we read is a valid devid. 1722507c3241Smlf * Return DDI_SUCCESS or DDI_FAILURE. 1723507c3241Smlf */ 1724507c3241Smlf static int 1725507c3241Smlf cmdk_devid_read(struct cmdk *dkp) 1726507c3241Smlf { 1727507c3241Smlf diskaddr_t blk; 1728507c3241Smlf struct dk_devid *dkdevidp; 1729507c3241Smlf uint_t *ip; 1730507c3241Smlf int chksum; 1731507c3241Smlf int i, sz; 1732e4da943dSMark Logan tgdk_iob_handle handle = NULL; 1733507c3241Smlf int rc = DDI_FAILURE; 1734507c3241Smlf 1735e8fb11a1Sshidokht if (cmlb_get_devid_block(dkp->dk_cmlbhandle, &blk, 0)) 1736507c3241Smlf goto err; 1737507c3241Smlf 1738507c3241Smlf /* read the devid */ 1739507c3241Smlf handle = dadk_iob_alloc(DKTP_DATA, blk, NBPSCTR, KM_SLEEP); 1740507c3241Smlf if (handle == NULL) 1741507c3241Smlf goto err; 1742507c3241Smlf 1743507c3241Smlf dkdevidp = (struct dk_devid *)dadk_iob_xfer(DKTP_DATA, handle, B_READ); 1744507c3241Smlf if (dkdevidp == NULL) 1745507c3241Smlf goto err; 1746507c3241Smlf 1747507c3241Smlf /* Validate the revision */ 1748507c3241Smlf if ((dkdevidp->dkd_rev_hi != DK_DEVID_REV_MSB) || 1749507c3241Smlf (dkdevidp->dkd_rev_lo != DK_DEVID_REV_LSB)) 1750507c3241Smlf goto err; 1751507c3241Smlf 1752507c3241Smlf /* Calculate the checksum */ 1753507c3241Smlf chksum = 0; 1754507c3241Smlf ip = (uint_t *)dkdevidp; 1755507c3241Smlf for (i = 0; i < ((NBPSCTR - sizeof (int))/sizeof (int)); i++) 1756507c3241Smlf chksum ^= ip[i]; 1757507c3241Smlf if (DKD_GETCHKSUM(dkdevidp) != chksum) 1758507c3241Smlf goto err; 1759507c3241Smlf 1760507c3241Smlf /* Validate the device id */ 1761507c3241Smlf if (ddi_devid_valid((ddi_devid_t)dkdevidp->dkd_devid) != DDI_SUCCESS) 1762507c3241Smlf goto err; 1763507c3241Smlf 1764507c3241Smlf /* keep a copy of the device id */ 1765507c3241Smlf sz = ddi_devid_sizeof((ddi_devid_t)dkdevidp->dkd_devid); 1766507c3241Smlf dkp->dk_devid = kmem_alloc(sz, KM_SLEEP); 1767507c3241Smlf bcopy(dkdevidp->dkd_devid, dkp->dk_devid, sz); 1768507c3241Smlf 1769507c3241Smlf rc = DDI_SUCCESS; 1770507c3241Smlf 1771507c3241Smlf err: 1772507c3241Smlf if (handle != NULL) 1773507c3241Smlf (void) dadk_iob_free(DKTP_DATA, handle); 1774507c3241Smlf return (rc); 1775507c3241Smlf } 1776507c3241Smlf 1777507c3241Smlf /* 1778507c3241Smlf * Create a devid and write it on the first block of the last track of 1779507c3241Smlf * the last cylinder. 1780507c3241Smlf * Return DDI_SUCCESS or DDI_FAILURE. 1781507c3241Smlf */ 1782507c3241Smlf static int 1783507c3241Smlf cmdk_devid_fabricate(struct cmdk *dkp) 1784507c3241Smlf { 1785507c3241Smlf ddi_devid_t devid = NULL; /* devid made by ddi_devid_init */ 1786507c3241Smlf struct dk_devid *dkdevidp; /* devid struct stored on disk */ 1787507c3241Smlf diskaddr_t blk; 1788507c3241Smlf tgdk_iob_handle handle = NULL; 1789507c3241Smlf uint_t *ip, chksum; 1790507c3241Smlf int i; 17913d510deaSMark Logan int rc = DDI_FAILURE; 1792507c3241Smlf 17933d510deaSMark Logan if (ddi_devid_init(dkp->dk_dip, DEVID_FAB, 0, NULL, &devid) != 17943d510deaSMark Logan DDI_SUCCESS) 1795507c3241Smlf goto err; 1796507c3241Smlf 1797e8fb11a1Sshidokht if (cmlb_get_devid_block(dkp->dk_cmlbhandle, &blk, 0)) { 1798507c3241Smlf /* no device id block address */ 17993d510deaSMark Logan goto err; 1800507c3241Smlf } 1801507c3241Smlf 1802507c3241Smlf handle = dadk_iob_alloc(DKTP_DATA, blk, NBPSCTR, KM_SLEEP); 1803507c3241Smlf if (!handle) 1804507c3241Smlf goto err; 1805507c3241Smlf 1806507c3241Smlf /* Locate the buffer */ 1807507c3241Smlf dkdevidp = (struct dk_devid *)dadk_iob_htoc(DKTP_DATA, handle); 1808507c3241Smlf 1809507c3241Smlf /* Fill in the revision */ 1810507c3241Smlf bzero(dkdevidp, NBPSCTR); 1811507c3241Smlf dkdevidp->dkd_rev_hi = DK_DEVID_REV_MSB; 1812507c3241Smlf dkdevidp->dkd_rev_lo = DK_DEVID_REV_LSB; 1813507c3241Smlf 1814507c3241Smlf /* Copy in the device id */ 1815507c3241Smlf i = ddi_devid_sizeof(devid); 1816507c3241Smlf if (i > DK_DEVID_SIZE) 1817507c3241Smlf goto err; 1818507c3241Smlf bcopy(devid, dkdevidp->dkd_devid, i); 1819507c3241Smlf 1820507c3241Smlf /* Calculate the chksum */ 1821507c3241Smlf chksum = 0; 1822507c3241Smlf ip = (uint_t *)dkdevidp; 1823507c3241Smlf for (i = 0; i < ((NBPSCTR - sizeof (int))/sizeof (int)); i++) 1824507c3241Smlf chksum ^= ip[i]; 1825507c3241Smlf 1826507c3241Smlf /* Fill in the checksum */ 1827507c3241Smlf DKD_FORMCHKSUM(chksum, dkdevidp); 1828507c3241Smlf 1829507c3241Smlf /* write the devid */ 1830507c3241Smlf (void) dadk_iob_xfer(DKTP_DATA, handle, B_WRITE); 1831507c3241Smlf 1832507c3241Smlf dkp->dk_devid = devid; 1833507c3241Smlf 1834507c3241Smlf rc = DDI_SUCCESS; 1835507c3241Smlf 1836507c3241Smlf err: 1837507c3241Smlf if (handle != NULL) 1838507c3241Smlf (void) dadk_iob_free(DKTP_DATA, handle); 1839507c3241Smlf 1840507c3241Smlf if (rc != DDI_SUCCESS && devid != NULL) 1841507c3241Smlf ddi_devid_free(devid); 1842507c3241Smlf 1843507c3241Smlf return (rc); 1844507c3241Smlf } 1845507c3241Smlf 1846507c3241Smlf static void 1847507c3241Smlf cmdk_bbh_free_alts(struct cmdk *dkp) 1848507c3241Smlf { 1849507c3241Smlf if (dkp->dk_alts_hdl) { 1850507c3241Smlf (void) dadk_iob_free(DKTP_DATA, dkp->dk_alts_hdl); 1851507c3241Smlf kmem_free(dkp->dk_slc_cnt, 1852507c3241Smlf NDKMAP * (sizeof (uint32_t) + sizeof (struct alts_ent *))); 1853507c3241Smlf dkp->dk_alts_hdl = NULL; 1854507c3241Smlf } 1855507c3241Smlf } 1856507c3241Smlf 1857507c3241Smlf static void 1858507c3241Smlf cmdk_bbh_reopen(struct cmdk *dkp) 1859507c3241Smlf { 1860507c3241Smlf tgdk_iob_handle handle = NULL; 1861507c3241Smlf diskaddr_t slcb, slcn, slce; 1862507c3241Smlf struct alts_parttbl *ap; 1863507c3241Smlf struct alts_ent *enttblp; 1864507c3241Smlf uint32_t altused; 1865507c3241Smlf uint32_t altbase; 1866507c3241Smlf uint32_t altlast; 1867507c3241Smlf int alts; 1868507c3241Smlf uint16_t vtoctag; 1869507c3241Smlf int i, j; 1870507c3241Smlf 1871507c3241Smlf /* find slice with V_ALTSCTR tag */ 1872507c3241Smlf for (alts = 0; alts < NDKMAP; alts++) { 1873507c3241Smlf if (cmlb_partinfo( 1874507c3241Smlf dkp->dk_cmlbhandle, 1875507c3241Smlf alts, 1876507c3241Smlf &slcn, 1877507c3241Smlf &slcb, 1878507c3241Smlf NULL, 1879e8fb11a1Sshidokht &vtoctag, 1880e8fb11a1Sshidokht 0)) { 1881507c3241Smlf goto empty; /* no partition table exists */ 1882507c3241Smlf } 1883507c3241Smlf 1884507c3241Smlf if (vtoctag == V_ALTSCTR && slcn > 1) 1885507c3241Smlf break; 1886507c3241Smlf } 1887507c3241Smlf if (alts >= NDKMAP) { 1888507c3241Smlf goto empty; /* no V_ALTSCTR slice defined */ 1889507c3241Smlf } 1890507c3241Smlf 1891507c3241Smlf /* read in ALTS label block */ 1892507c3241Smlf handle = dadk_iob_alloc(DKTP_DATA, slcb, NBPSCTR, KM_SLEEP); 1893507c3241Smlf if (!handle) { 1894507c3241Smlf goto empty; 1895507c3241Smlf } 1896507c3241Smlf 1897507c3241Smlf ap = (struct alts_parttbl *)dadk_iob_xfer(DKTP_DATA, handle, B_READ); 1898507c3241Smlf if (!ap || (ap->alts_sanity != ALTS_SANITY)) { 1899507c3241Smlf goto empty; 1900507c3241Smlf } 1901507c3241Smlf 1902507c3241Smlf altused = ap->alts_ent_used; /* number of BB entries */ 1903507c3241Smlf altbase = ap->alts_ent_base; /* blk offset from begin slice */ 1904507c3241Smlf altlast = ap->alts_ent_end; /* blk offset to last block */ 1905507c3241Smlf /* ((altused * sizeof (struct alts_ent) + NBPSCTR - 1) & ~NBPSCTR) */ 1906507c3241Smlf 1907507c3241Smlf if (altused == 0 || 1908507c3241Smlf altbase < 1 || 1909507c3241Smlf altbase > altlast || 1910507c3241Smlf altlast >= slcn) { 1911507c3241Smlf goto empty; 1912507c3241Smlf } 1913507c3241Smlf (void) dadk_iob_free(DKTP_DATA, handle); 1914507c3241Smlf 1915507c3241Smlf /* read in ALTS remapping table */ 1916507c3241Smlf handle = dadk_iob_alloc(DKTP_DATA, 1917507c3241Smlf slcb + altbase, 1918507c3241Smlf (altlast - altbase + 1) << SCTRSHFT, KM_SLEEP); 1919507c3241Smlf if (!handle) { 1920507c3241Smlf goto empty; 1921507c3241Smlf } 1922507c3241Smlf 1923507c3241Smlf enttblp = (struct alts_ent *)dadk_iob_xfer(DKTP_DATA, handle, B_READ); 1924507c3241Smlf if (!enttblp) { 1925507c3241Smlf goto empty; 1926507c3241Smlf } 1927507c3241Smlf 1928507c3241Smlf rw_enter(&dkp->dk_bbh_mutex, RW_WRITER); 1929507c3241Smlf 1930507c3241Smlf /* allocate space for dk_slc_cnt and dk_slc_ent tables */ 1931507c3241Smlf if (dkp->dk_slc_cnt == NULL) { 1932507c3241Smlf dkp->dk_slc_cnt = kmem_alloc(NDKMAP * 1933507c3241Smlf (sizeof (long) + sizeof (struct alts_ent *)), KM_SLEEP); 1934507c3241Smlf } 1935507c3241Smlf dkp->dk_slc_ent = (struct alts_ent **)(dkp->dk_slc_cnt + NDKMAP); 1936507c3241Smlf 1937507c3241Smlf /* free previous BB table (if any) */ 1938507c3241Smlf if (dkp->dk_alts_hdl) { 1939507c3241Smlf (void) dadk_iob_free(DKTP_DATA, dkp->dk_alts_hdl); 1940507c3241Smlf dkp->dk_alts_hdl = NULL; 1941507c3241Smlf dkp->dk_altused = 0; 1942507c3241Smlf } 1943507c3241Smlf 1944507c3241Smlf /* save linkage to new BB table */ 1945507c3241Smlf dkp->dk_alts_hdl = handle; 1946507c3241Smlf dkp->dk_altused = altused; 1947507c3241Smlf 1948507c3241Smlf /* 1949507c3241Smlf * build indexes to BB table by slice 1950507c3241Smlf * effectively we have 1951507c3241Smlf * struct alts_ent *enttblp[altused]; 1952507c3241Smlf * 1953507c3241Smlf * uint32_t dk_slc_cnt[NDKMAP]; 1954507c3241Smlf * struct alts_ent *dk_slc_ent[NDKMAP]; 1955507c3241Smlf */ 1956507c3241Smlf for (i = 0; i < NDKMAP; i++) { 1957507c3241Smlf if (cmlb_partinfo( 1958507c3241Smlf dkp->dk_cmlbhandle, 1959507c3241Smlf i, 1960507c3241Smlf &slcn, 1961507c3241Smlf &slcb, 1962507c3241Smlf NULL, 1963e8fb11a1Sshidokht NULL, 1964e8fb11a1Sshidokht 0)) { 1965507c3241Smlf goto empty1; 1966507c3241Smlf } 1967507c3241Smlf 1968507c3241Smlf dkp->dk_slc_cnt[i] = 0; 1969507c3241Smlf if (slcn == 0) 1970507c3241Smlf continue; /* slice is not allocated */ 1971507c3241Smlf 1972507c3241Smlf /* last block in slice */ 1973507c3241Smlf slce = slcb + slcn - 1; 1974507c3241Smlf 1975507c3241Smlf /* find first remap entry in after beginnning of slice */ 1976507c3241Smlf for (j = 0; j < altused; j++) { 1977507c3241Smlf if (enttblp[j].bad_start + enttblp[j].bad_end >= slcb) 1978507c3241Smlf break; 1979507c3241Smlf } 1980507c3241Smlf dkp->dk_slc_ent[i] = enttblp + j; 1981507c3241Smlf 1982507c3241Smlf /* count remap entrys until end of slice */ 1983507c3241Smlf for (; j < altused && enttblp[j].bad_start <= slce; j++) { 1984507c3241Smlf dkp->dk_slc_cnt[i] += 1; 1985507c3241Smlf } 1986507c3241Smlf } 1987507c3241Smlf 1988507c3241Smlf rw_exit(&dkp->dk_bbh_mutex); 1989507c3241Smlf return; 1990507c3241Smlf 1991507c3241Smlf empty: 1992507c3241Smlf rw_enter(&dkp->dk_bbh_mutex, RW_WRITER); 1993507c3241Smlf empty1: 1994507c3241Smlf if (handle && handle != dkp->dk_alts_hdl) 1995507c3241Smlf (void) dadk_iob_free(DKTP_DATA, handle); 1996507c3241Smlf 1997507c3241Smlf if (dkp->dk_alts_hdl) { 1998507c3241Smlf (void) dadk_iob_free(DKTP_DATA, dkp->dk_alts_hdl); 1999507c3241Smlf dkp->dk_alts_hdl = NULL; 2000507c3241Smlf } 2001507c3241Smlf 2002507c3241Smlf rw_exit(&dkp->dk_bbh_mutex); 2003507c3241Smlf } 2004507c3241Smlf 2005507c3241Smlf /*ARGSUSED*/ 2006507c3241Smlf static bbh_cookie_t 2007507c3241Smlf cmdk_bbh_htoc(opaque_t bbh_data, opaque_t handle) 2008507c3241Smlf { 2009507c3241Smlf struct bbh_handle *hp; 2010507c3241Smlf bbh_cookie_t ckp; 2011507c3241Smlf 2012507c3241Smlf hp = (struct bbh_handle *)handle; 2013507c3241Smlf ckp = hp->h_cktab + hp->h_idx; 2014507c3241Smlf hp->h_idx++; 2015507c3241Smlf return (ckp); 2016507c3241Smlf } 2017507c3241Smlf 2018507c3241Smlf /*ARGSUSED*/ 2019507c3241Smlf static void 2020507c3241Smlf cmdk_bbh_freehandle(opaque_t bbh_data, opaque_t handle) 2021507c3241Smlf { 2022507c3241Smlf struct bbh_handle *hp; 2023507c3241Smlf 2024507c3241Smlf hp = (struct bbh_handle *)handle; 2025507c3241Smlf kmem_free(handle, (sizeof (struct bbh_handle) + 2026507c3241Smlf (hp->h_totck * (sizeof (struct bbh_cookie))))); 2027507c3241Smlf } 2028507c3241Smlf 2029507c3241Smlf 2030507c3241Smlf /* 2031507c3241Smlf * cmdk_bbh_gethandle remaps the bad sectors to alternates. 2032507c3241Smlf * There are 7 different cases when the comparison is made 2033507c3241Smlf * between the bad sector cluster and the disk section. 2034507c3241Smlf * 2035507c3241Smlf * bad sector cluster gggggggggggbbbbbbbggggggggggg 2036507c3241Smlf * case 1: ddddd 2037507c3241Smlf * case 2: -d----- 2038507c3241Smlf * case 3: ddddd 2039507c3241Smlf * case 4: dddddddddddd 2040507c3241Smlf * case 5: ddddddd----- 2041507c3241Smlf * case 6: ---ddddddd 2042507c3241Smlf * case 7: ddddddd 2043507c3241Smlf * 2044507c3241Smlf * where: g = good sector, b = bad sector 2045507c3241Smlf * d = sector in disk section 2046507c3241Smlf * - = disk section may be extended to cover those disk area 2047507c3241Smlf */ 2048507c3241Smlf 2049507c3241Smlf static opaque_t 2050507c3241Smlf cmdk_bbh_gethandle(opaque_t bbh_data, struct buf *bp) 2051507c3241Smlf { 2052507c3241Smlf struct cmdk *dkp = (struct cmdk *)bbh_data; 2053507c3241Smlf struct bbh_handle *hp; 2054507c3241Smlf struct bbh_cookie *ckp; 2055507c3241Smlf struct alts_ent *altp; 2056507c3241Smlf uint32_t alts_used; 2057507c3241Smlf uint32_t part = CMDKPART(bp->b_edev); 2058507c3241Smlf daddr32_t lastsec; 2059507c3241Smlf long d_count; 2060507c3241Smlf int i; 2061507c3241Smlf int idx; 2062507c3241Smlf int cnt; 2063507c3241Smlf 2064507c3241Smlf if (part >= V_NUMPAR) 2065507c3241Smlf return (NULL); 2066507c3241Smlf 2067507c3241Smlf /* 2068507c3241Smlf * This if statement is atomic and it will succeed 2069507c3241Smlf * if there are no bad blocks (almost always) 2070507c3241Smlf * 2071507c3241Smlf * so this if is performed outside of the rw_enter for speed 2072507c3241Smlf * and then repeated inside the rw_enter for safety 2073507c3241Smlf */ 2074507c3241Smlf if (!dkp->dk_alts_hdl) { 2075507c3241Smlf return (NULL); 2076507c3241Smlf } 2077507c3241Smlf 2078507c3241Smlf rw_enter(&dkp->dk_bbh_mutex, RW_READER); 2079507c3241Smlf 2080507c3241Smlf if (dkp->dk_alts_hdl == NULL) { 2081507c3241Smlf rw_exit(&dkp->dk_bbh_mutex); 2082507c3241Smlf return (NULL); 2083507c3241Smlf } 2084507c3241Smlf 2085507c3241Smlf alts_used = dkp->dk_slc_cnt[part]; 2086507c3241Smlf if (alts_used == 0) { 2087507c3241Smlf rw_exit(&dkp->dk_bbh_mutex); 2088507c3241Smlf return (NULL); 2089507c3241Smlf } 2090507c3241Smlf altp = dkp->dk_slc_ent[part]; 2091507c3241Smlf 2092507c3241Smlf /* 2093507c3241Smlf * binary search for the largest bad sector index in the alternate 2094507c3241Smlf * entry table which overlaps or larger than the starting d_sec 2095507c3241Smlf */ 2096507c3241Smlf i = cmdk_bbh_bsearch(altp, alts_used, GET_BP_SEC(bp)); 2097507c3241Smlf /* if starting sector is > the largest bad sector, return */ 2098507c3241Smlf if (i == -1) { 2099507c3241Smlf rw_exit(&dkp->dk_bbh_mutex); 2100507c3241Smlf return (NULL); 2101507c3241Smlf } 2102507c3241Smlf /* i is the starting index. Set altp to the starting entry addr */ 2103507c3241Smlf altp += i; 2104507c3241Smlf 2105507c3241Smlf d_count = bp->b_bcount >> SCTRSHFT; 2106507c3241Smlf lastsec = GET_BP_SEC(bp) + d_count - 1; 2107507c3241Smlf 2108507c3241Smlf /* calculate the number of bad sectors */ 2109507c3241Smlf for (idx = i, cnt = 0; idx < alts_used; idx++, altp++, cnt++) { 2110507c3241Smlf if (lastsec < altp->bad_start) 2111507c3241Smlf break; 2112507c3241Smlf } 2113507c3241Smlf 2114507c3241Smlf if (!cnt) { 2115507c3241Smlf rw_exit(&dkp->dk_bbh_mutex); 2116507c3241Smlf return (NULL); 2117507c3241Smlf } 2118507c3241Smlf 2119507c3241Smlf /* calculate the maximum number of reserved cookies */ 2120507c3241Smlf cnt <<= 1; 2121507c3241Smlf cnt++; 2122507c3241Smlf 2123507c3241Smlf /* allocate the handle */ 2124507c3241Smlf hp = (struct bbh_handle *)kmem_zalloc((sizeof (*hp) + 2125507c3241Smlf (cnt * sizeof (*ckp))), KM_SLEEP); 2126507c3241Smlf 2127507c3241Smlf hp->h_idx = 0; 2128507c3241Smlf hp->h_totck = cnt; 2129507c3241Smlf ckp = hp->h_cktab = (struct bbh_cookie *)(hp + 1); 2130507c3241Smlf ckp[0].ck_sector = GET_BP_SEC(bp); 2131507c3241Smlf ckp[0].ck_seclen = d_count; 2132507c3241Smlf 2133507c3241Smlf altp = dkp->dk_slc_ent[part]; 2134507c3241Smlf altp += i; 2135507c3241Smlf for (idx = 0; i < alts_used; i++, altp++) { 2136507c3241Smlf /* CASE 1: */ 2137507c3241Smlf if (lastsec < altp->bad_start) 2138507c3241Smlf break; 2139507c3241Smlf 2140507c3241Smlf /* CASE 3: */ 2141507c3241Smlf if (ckp[idx].ck_sector > altp->bad_end) 2142507c3241Smlf continue; 2143507c3241Smlf 2144507c3241Smlf /* CASE 2 and 7: */ 2145507c3241Smlf if ((ckp[idx].ck_sector >= altp->bad_start) && 2146507c3241Smlf (lastsec <= altp->bad_end)) { 2147507c3241Smlf ckp[idx].ck_sector = altp->good_start + 2148507c3241Smlf ckp[idx].ck_sector - altp->bad_start; 2149507c3241Smlf break; 2150507c3241Smlf } 2151507c3241Smlf 2152507c3241Smlf /* at least one bad sector in our section. break it. */ 2153507c3241Smlf /* CASE 5: */ 2154507c3241Smlf if ((lastsec >= altp->bad_start) && 2155507c3241Smlf (lastsec <= altp->bad_end)) { 2156507c3241Smlf ckp[idx+1].ck_seclen = lastsec - altp->bad_start + 1; 2157507c3241Smlf ckp[idx].ck_seclen -= ckp[idx+1].ck_seclen; 2158507c3241Smlf ckp[idx+1].ck_sector = altp->good_start; 2159507c3241Smlf break; 2160507c3241Smlf } 2161507c3241Smlf /* CASE 6: */ 2162507c3241Smlf if ((ckp[idx].ck_sector <= altp->bad_end) && 2163507c3241Smlf (ckp[idx].ck_sector >= altp->bad_start)) { 2164507c3241Smlf ckp[idx+1].ck_seclen = ckp[idx].ck_seclen; 2165507c3241Smlf ckp[idx].ck_seclen = altp->bad_end - 2166507c3241Smlf ckp[idx].ck_sector + 1; 2167507c3241Smlf ckp[idx+1].ck_seclen -= ckp[idx].ck_seclen; 2168507c3241Smlf ckp[idx].ck_sector = altp->good_start + 2169507c3241Smlf ckp[idx].ck_sector - altp->bad_start; 2170507c3241Smlf idx++; 2171507c3241Smlf ckp[idx].ck_sector = altp->bad_end + 1; 2172507c3241Smlf continue; /* check rest of section */ 2173507c3241Smlf } 2174507c3241Smlf 2175507c3241Smlf /* CASE 4: */ 2176507c3241Smlf ckp[idx].ck_seclen = altp->bad_start - ckp[idx].ck_sector; 2177507c3241Smlf ckp[idx+1].ck_sector = altp->good_start; 2178507c3241Smlf ckp[idx+1].ck_seclen = altp->bad_end - altp->bad_start + 1; 2179507c3241Smlf idx += 2; 2180507c3241Smlf ckp[idx].ck_sector = altp->bad_end + 1; 2181507c3241Smlf ckp[idx].ck_seclen = lastsec - altp->bad_end; 2182507c3241Smlf } 2183507c3241Smlf 2184507c3241Smlf rw_exit(&dkp->dk_bbh_mutex); 2185507c3241Smlf return ((opaque_t)hp); 2186507c3241Smlf } 2187507c3241Smlf 2188507c3241Smlf static int 2189507c3241Smlf cmdk_bbh_bsearch(struct alts_ent *buf, int cnt, daddr32_t key) 2190507c3241Smlf { 2191507c3241Smlf int i; 2192507c3241Smlf int ind; 2193507c3241Smlf int interval; 2194507c3241Smlf int mystatus = -1; 2195507c3241Smlf 2196507c3241Smlf if (!cnt) 2197507c3241Smlf return (mystatus); 2198507c3241Smlf 2199507c3241Smlf ind = 1; /* compiler complains about possible uninitialized var */ 2200507c3241Smlf for (i = 1; i <= cnt; i <<= 1) 2201507c3241Smlf ind = i; 2202507c3241Smlf 2203507c3241Smlf for (interval = ind; interval; ) { 2204507c3241Smlf if ((key >= buf[ind-1].bad_start) && 2205507c3241Smlf (key <= buf[ind-1].bad_end)) { 2206507c3241Smlf return (ind-1); 2207507c3241Smlf } else { 2208507c3241Smlf interval >>= 1; 2209507c3241Smlf if (key < buf[ind-1].bad_start) { 2210507c3241Smlf /* record the largest bad sector index */ 2211507c3241Smlf mystatus = ind-1; 2212507c3241Smlf if (!interval) 2213507c3241Smlf break; 2214507c3241Smlf ind = ind - interval; 2215507c3241Smlf } else { 2216507c3241Smlf /* 2217507c3241Smlf * if key is larger than the last element 2218507c3241Smlf * then break 2219507c3241Smlf */ 2220507c3241Smlf if ((ind == cnt) || !interval) 2221507c3241Smlf break; 2222507c3241Smlf if ((ind+interval) <= cnt) 2223507c3241Smlf ind += interval; 2224507c3241Smlf } 2225507c3241Smlf } 2226507c3241Smlf } 2227507c3241Smlf return (mystatus); 2228507c3241Smlf } 2229