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