xref: /onnv-gate/usr/src/uts/i86pc/i86hvm/io/pv_cmdk.c (revision 8863:94039d51dda4)
16451Sedp /*
26451Sedp  * CDDL HEADER START
36451Sedp  *
46451Sedp  * The contents of this file are subject to the terms of the
56451Sedp  * Common Development and Distribution License (the "License").
66451Sedp  * You may not use this file except in compliance with the License.
76451Sedp  *
86451Sedp  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96451Sedp  * or http://www.opensolaris.org/os/licensing.
106451Sedp  * See the License for the specific language governing permissions
116451Sedp  * and limitations under the License.
126451Sedp  *
136451Sedp  * When distributing Covered Code, include this CDDL HEADER in each
146451Sedp  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156451Sedp  * If applicable, add the following below this CDDL HEADER, with the
166451Sedp  * fields enclosed by brackets "[]" replaced with your own identifying
176451Sedp  * information: Portions Copyright [yyyy] [name of copyright owner]
186451Sedp  *
196451Sedp  * CDDL HEADER END
206451Sedp  */
216451Sedp /*
22*8863SEdward.Pilatowicz@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
236451Sedp  * Use is subject to license terms.
246451Sedp  */
256451Sedp 
26*8863SEdward.Pilatowicz@Sun.COM #include <io/xdf_shell.h>
276451Sedp 
286451Sedp /*
29*8863SEdward.Pilatowicz@Sun.COM  * We're emulating (and possibly layering on top of) cmdk devices, so xdf
30*8863SEdward.Pilatowicz@Sun.COM  * disk unit mappings must match up with cmdk disk unit mappings'.
316451Sedp  */
32*8863SEdward.Pilatowicz@Sun.COM #if !defined(XDF_PSHIFT)
33*8863SEdward.Pilatowicz@Sun.COM #error "can't find definition for xdf unit mappings - XDF_PSHIFT"
34*8863SEdward.Pilatowicz@Sun.COM #endif /* XDF_PSHIFT */
35*8863SEdward.Pilatowicz@Sun.COM 
36*8863SEdward.Pilatowicz@Sun.COM #if !defined(CMDK_UNITSHF)
37*8863SEdward.Pilatowicz@Sun.COM #error "can't find definition for cmdk unit mappings - CMDK_UNITSHF"
38*8863SEdward.Pilatowicz@Sun.COM #endif /* CMDK_UNITSHF */
39*8863SEdward.Pilatowicz@Sun.COM 
40*8863SEdward.Pilatowicz@Sun.COM #if ((XDF_PSHIFT - CMDK_UNITSHF) != 0)
41*8863SEdward.Pilatowicz@Sun.COM #error "cmdk and xdf unit mappings don't match."
42*8863SEdward.Pilatowicz@Sun.COM #endif /* ((XDF_PSHIFT - CMDK_UNITSHF) != 0) */
43*8863SEdward.Pilatowicz@Sun.COM 
44*8863SEdward.Pilatowicz@Sun.COM extern const struct dev_ops	cmdk_ops;
45*8863SEdward.Pilatowicz@Sun.COM extern void			*cmdk_state;
466451Sedp 
476451Sedp /*
48*8863SEdward.Pilatowicz@Sun.COM  * Globals required by xdf_shell.c
496451Sedp  */
50*8863SEdward.Pilatowicz@Sun.COM const char		*xdfs_c_name = "cmdk";
51*8863SEdward.Pilatowicz@Sun.COM const char		*xdfs_c_linkinfo = "PV Common Direct Access Disk";
52*8863SEdward.Pilatowicz@Sun.COM void			**xdfs_c_hvm_ss = &cmdk_state;
53*8863SEdward.Pilatowicz@Sun.COM const size_t		xdfs_c_hvm_ss_size = sizeof (struct cmdk);
54*8863SEdward.Pilatowicz@Sun.COM const struct dev_ops	*xdfs_c_hvm_dev_ops = &cmdk_ops;
556451Sedp 
56*8863SEdward.Pilatowicz@Sun.COM const xdfs_h2p_map_t xdfs_c_h2p_map[] = {
576451Sedp 	/*
586451Sedp 	 * The paths mapping here are very specific to xen and qemu.  When a
596451Sedp 	 * domU is booted under xen in HVM mode, qemu is normally used to
606451Sedp 	 * emulate up to four ide disks.  These disks always have the four
616451Sedp 	 * path listed below.  To configure an emulated ide device, the
626451Sedp 	 * xen domain configuration file normally has an entry that looks
636451Sedp 	 * like this:
646451Sedp 	 *	disk = [ 'file:/foo.img,hda,w' ]
656451Sedp 	 *
666451Sedp 	 * The part we're interested in is the 'hda', which we'll call the
676451Sedp 	 * xen disk device name here.  The xen management tools (which parse
686451Sedp 	 * the xen domain configuration file and launch qemu) makes the
696451Sedp 	 * following assumptions about this value:
706451Sedp 	 *	hda == emulated ide disk 0 (ide bus 0, master)
716451Sedp 	 *	hdb == emulated ide disk 1 (ide bus 0, slave)
726451Sedp 	 *	hdc == emulated ide disk 2 (ide bus 1, master)
736451Sedp 	 *	hdd == emulated ide disk 3 (ide bus 1, slave)
746451Sedp 	 *
756451Sedp 	 * (Uncoincidentally, these xen disk device names actually map to
766451Sedp 	 * the /dev filesystem names of ide disk devices in Linux.  So in
776451Sedp 	 * Linux /dev/hda is the first ide disk.)  So for the first part of
786451Sedp 	 * our mapping we've just hardcoded the cmdk paths that we know
796451Sedp 	 * qemu will use.
806451Sedp 	 *
816451Sedp 	 * To understand the second half of the mapping (ie, the xdf device
826451Sedp 	 * that each emulated cmdk device should be mapped two) we need to
836451Sedp 	 * know the solaris device node address that will be assigned to
846500Sjhd 	 * each xdf device.  (The device node address is the decimal
856500Sjhd 	 * number that comes after the "xdf@" in the device path.)
866451Sedp 	 *
876451Sedp 	 * So the question becomes, how do we know what the xenstore device
886451Sedp 	 * id for emulated disk will be?  Well, it turns out that since the
896451Sedp 	 * xen management tools expect the disk device names to be Linux
906451Sedp 	 * device names, those same management tools assign each disk a
916451Sedp 	 * device id that matches the dev_t of the corresponding device
926451Sedp 	 * under Linux.  (Big shocker.)  This xen device name-to-id mapping
936451Sedp 	 * is currently all hard coded here:
946451Sedp 	 *	xen.hg/tools/python/xen/util/blkif.py`blkdev_name_to_number()
956451Sedp 	 *
966451Sedp 	 * So looking at the code above we can see the following xen disk
976451Sedp 	 * device name to xenstore device id mappings:
986500Sjhd 	 *	'hda' == 0t768  == ((3  * 256) + (0 * 64))
996500Sjhd 	 *	'hdb' == 0t832  == ((3  * 256) + (1 * 64))
1006500Sjhd 	 *	'hdc' == 0t5632 == ((22 * 256) + (0 * 64))
1016500Sjhd 	 *	'hdd' == 0t5696 == ((22 * 256) + (1 * 64))
1026451Sedp 	 */
1036500Sjhd 	{ "/pci@0,0/pci-ide@1,1/ide@0/cmdk@0,0", "/xpvd/xdf@768" },
1046500Sjhd 	{ "/pci@0,0/pci-ide@1,1/ide@0/cmdk@1,0", "/xpvd/xdf@832" },
1056500Sjhd 	{ "/pci@0,0/pci-ide@1,1/ide@1/cmdk@0,0", "/xpvd/xdf@5632" },
1066500Sjhd 	{ "/pci@0,0/pci-ide@1,1/ide@1/cmdk@1,0", "/xpvd/xdf@5696" },
1076451Sedp 	{ NULL, 0 }
1086451Sedp };
1096451Sedp 
1106451Sedp /*
111*8863SEdward.Pilatowicz@Sun.COM  * Private functions
1126451Sedp  */
1136451Sedp /*
114*8863SEdward.Pilatowicz@Sun.COM  * xdfs_get_modser() is basically a local copy of
1156451Sedp  * cmdk_get_modser() modified to work without the dadk layer.
1166451Sedp  * (which the non-pv version of the cmdk driver uses.)
1176451Sedp  */
1186451Sedp static int
xdfs_get_modser(xdfs_state_t * xsp,int ioccmd,char * buf,int len)119*8863SEdward.Pilatowicz@Sun.COM xdfs_get_modser(xdfs_state_t *xsp, int ioccmd, char *buf, int len)
1206451Sedp {
1216451Sedp 	struct scsi_device	*scsi_device;
1226451Sedp 	opaque_t		ctlobjp;
1236451Sedp 	dadk_ioc_string_t	strarg;
1246451Sedp 	char			*s;
1256451Sedp 	char			ch;
1266451Sedp 	boolean_t		ret;
1276451Sedp 	int			i;
1286451Sedp 	int			tb;
1296451Sedp 
1306451Sedp 	strarg.is_buf = buf;
1316451Sedp 	strarg.is_size = len;
132*8863SEdward.Pilatowicz@Sun.COM 	scsi_device = ddi_get_driver_private(xsp->xdfss_dip);
1336451Sedp 	ctlobjp = scsi_device->sd_address.a_hba_tran;
1346451Sedp 	if (CTL_IOCTL(ctlobjp,
1356451Sedp 	    ioccmd, (uintptr_t)&strarg, FNATIVE | FKIOCTL) != 0)
1366451Sedp 		return (0);
1376451Sedp 
1386451Sedp 	/*
1396451Sedp 	 * valid model/serial string must contain a non-zero non-space
1406451Sedp 	 * trim trailing spaces/NULL
1416451Sedp 	 */
1426451Sedp 	ret = B_FALSE;
1436451Sedp 	s = buf;
1446451Sedp 	for (i = 0; i < strarg.is_size; i++) {
1456451Sedp 		ch = *s++;
1466451Sedp 		if (ch != ' ' && ch != '\0')
1476451Sedp 			tb = i + 1;
1486451Sedp 		if (ch != ' ' && ch != '\0' && ch != '0')
1496451Sedp 			ret = B_TRUE;
1506451Sedp 	}
1516451Sedp 
1526451Sedp 	if (ret == B_FALSE)
1536451Sedp 		return (0);
1546451Sedp 
1556451Sedp 	return (tb);
1566451Sedp }
1576451Sedp 
1586451Sedp /*
159*8863SEdward.Pilatowicz@Sun.COM  * xdfs_devid_modser() is basically a copy of cmdk_devid_modser()
1606451Sedp  * that has been modified to use local pv cmdk driver functions.
1616451Sedp  *
1626451Sedp  * Build a devid from the model and serial number
1636451Sedp  * Return DDI_SUCCESS or DDI_FAILURE.
1646451Sedp  */
1656451Sedp static int
xdfs_devid_modser(xdfs_state_t * xsp)166*8863SEdward.Pilatowicz@Sun.COM xdfs_devid_modser(xdfs_state_t *xsp)
1676451Sedp {
1686451Sedp 	int	rc = DDI_FAILURE;
1696451Sedp 	char	*hwid;
1706451Sedp 	int	modlen;
1716451Sedp 	int	serlen;
1726451Sedp 
1736451Sedp 	/*
1746451Sedp 	 * device ID is a concatenation of model number, '=', serial number.
1756451Sedp 	 */
1766451Sedp 	hwid = kmem_alloc(CMDK_HWIDLEN, KM_SLEEP);
177*8863SEdward.Pilatowicz@Sun.COM 	modlen = xdfs_get_modser(xsp, DIOCTL_GETMODEL, hwid, CMDK_HWIDLEN);
1786451Sedp 	if (modlen == 0)
1796451Sedp 		goto err;
1806451Sedp 
1816451Sedp 	hwid[modlen++] = '=';
182*8863SEdward.Pilatowicz@Sun.COM 	serlen = xdfs_get_modser(xsp, DIOCTL_GETSERIAL,
1836451Sedp 	    hwid + modlen, CMDK_HWIDLEN - modlen);
1846451Sedp 	if (serlen == 0)
1856451Sedp 		goto err;
1866451Sedp 
1876451Sedp 	hwid[modlen + serlen] = 0;
1886451Sedp 
1896451Sedp 	/* Initialize the device ID, trailing NULL not included */
190*8863SEdward.Pilatowicz@Sun.COM 	rc = ddi_devid_init(xsp->xdfss_dip, DEVID_ATA_SERIAL, modlen + serlen,
191*8863SEdward.Pilatowicz@Sun.COM 	    hwid, (ddi_devid_t *)&xsp->xdfss_tgt_devid);
1926451Sedp 	if (rc != DDI_SUCCESS)
1936451Sedp 		goto err;
1946451Sedp 
1956451Sedp 	kmem_free(hwid, CMDK_HWIDLEN);
1966451Sedp 	return (DDI_SUCCESS);
1976451Sedp 
1986451Sedp err:
1996451Sedp 	kmem_free(hwid, CMDK_HWIDLEN);
2006451Sedp 	return (DDI_FAILURE);
2016451Sedp }
2026451Sedp 
2036451Sedp /*
204*8863SEdward.Pilatowicz@Sun.COM  * xdfs_devid_read() is basically a local copy of
2056451Sedp  * cmdk_devid_read() modified to work without the dadk layer.
2066451Sedp  * (which the non-pv version of the cmdk driver uses.)
2076451Sedp  *
2086451Sedp  * Read a devid from on the first block of the last track of
2096451Sedp  * the last cylinder.  Make sure what we read is a valid devid.
2106451Sedp  * Return DDI_SUCCESS or DDI_FAILURE.
2116451Sedp  */
2126451Sedp static int
xdfs_devid_read(xdfs_state_t * xsp)213*8863SEdward.Pilatowicz@Sun.COM xdfs_devid_read(xdfs_state_t *xsp)
2146451Sedp {
2156451Sedp 	diskaddr_t	blk;
2166451Sedp 	struct dk_devid *dkdevidp;
2176451Sedp 	uint_t		*ip, chksum;
2186451Sedp 	int		i;
2196451Sedp 
220*8863SEdward.Pilatowicz@Sun.COM 	if (cmlb_get_devid_block(xsp->xdfss_cmlbhandle, &blk, 0) != 0)
2216451Sedp 		return (DDI_FAILURE);
2226451Sedp 
2236451Sedp 	dkdevidp = kmem_zalloc(NBPSCTR, KM_SLEEP);
224*8863SEdward.Pilatowicz@Sun.COM 	if (xdfs_lb_rdwr(xsp->xdfss_dip,
2256451Sedp 	    TG_READ, dkdevidp, blk, NBPSCTR, NULL) != 0)
2266451Sedp 		goto err;
2276451Sedp 
2286451Sedp 	/* Validate the revision */
2296451Sedp 	if ((dkdevidp->dkd_rev_hi != DK_DEVID_REV_MSB) ||
2306451Sedp 	    (dkdevidp->dkd_rev_lo != DK_DEVID_REV_LSB))
2316451Sedp 		goto err;
2326451Sedp 
2336451Sedp 	/* Calculate the checksum */
2346451Sedp 	chksum = 0;
2356451Sedp 	ip = (uint_t *)dkdevidp;
2366451Sedp 	for (i = 0; i < ((NBPSCTR - sizeof (int))/sizeof (int)); i++)
2376451Sedp 		chksum ^= ip[i];
2386451Sedp 	if (DKD_GETCHKSUM(dkdevidp) != chksum)
2396451Sedp 		goto err;
2406451Sedp 
2416451Sedp 	/* Validate the device id */
2426451Sedp 	if (ddi_devid_valid((ddi_devid_t)dkdevidp->dkd_devid) != DDI_SUCCESS)
2436451Sedp 		goto err;
2446451Sedp 
2456451Sedp 	/* keep a copy of the device id */
2466451Sedp 	i = ddi_devid_sizeof((ddi_devid_t)dkdevidp->dkd_devid);
247*8863SEdward.Pilatowicz@Sun.COM 	xsp->xdfss_tgt_devid = kmem_alloc(i, KM_SLEEP);
248*8863SEdward.Pilatowicz@Sun.COM 	bcopy(dkdevidp->dkd_devid, xsp->xdfss_tgt_devid, i);
2496451Sedp 	kmem_free(dkdevidp, NBPSCTR);
2506451Sedp 	return (DDI_SUCCESS);
2516451Sedp 
2526451Sedp err:
2536451Sedp 	kmem_free(dkdevidp, NBPSCTR);
2546451Sedp 	return (DDI_FAILURE);
2556451Sedp }
2566451Sedp 
2576451Sedp /*
258*8863SEdward.Pilatowicz@Sun.COM  * xdfs_devid_fabricate() is basically a local copy of
2596451Sedp  * cmdk_devid_fabricate() modified to work without the dadk layer.
2606451Sedp  * (which the non-pv version of the cmdk driver uses.)
2616451Sedp  *
2626451Sedp  * Create a devid and write it on the first block of the last track of
2636451Sedp  * the last cylinder.
2646451Sedp  * Return DDI_SUCCESS or DDI_FAILURE.
2656451Sedp  */
2666451Sedp static int
xdfs_devid_fabricate(xdfs_state_t * xsp)267*8863SEdward.Pilatowicz@Sun.COM xdfs_devid_fabricate(xdfs_state_t *xsp)
2686451Sedp {
2696451Sedp 	ddi_devid_t	devid = NULL; /* devid made by ddi_devid_init  */
2706451Sedp 	struct dk_devid	*dkdevidp = NULL; /* devid struct stored on disk */
2716451Sedp 	diskaddr_t	blk;
2726451Sedp 	uint_t		*ip, chksum;
2736451Sedp 	int		i;
2746451Sedp 
275*8863SEdward.Pilatowicz@Sun.COM 	if (cmlb_get_devid_block(xsp->xdfss_cmlbhandle, &blk, 0) != 0)
2766451Sedp 		return (DDI_FAILURE);
2776451Sedp 
278*8863SEdward.Pilatowicz@Sun.COM 	if (ddi_devid_init(xsp->xdfss_dip, DEVID_FAB, 0, NULL, &devid) !=
2796451Sedp 	    DDI_SUCCESS)
2806451Sedp 		return (DDI_FAILURE);
2816451Sedp 
2826451Sedp 	/* allocate a buffer */
2836451Sedp 	dkdevidp = (struct dk_devid *)kmem_zalloc(NBPSCTR, KM_SLEEP);
2846451Sedp 
2856451Sedp 	/* Fill in the revision */
2866451Sedp 	dkdevidp->dkd_rev_hi = DK_DEVID_REV_MSB;
2876451Sedp 	dkdevidp->dkd_rev_lo = DK_DEVID_REV_LSB;
2886451Sedp 
2896451Sedp 	/* Copy in the device id */
2906451Sedp 	i = ddi_devid_sizeof(devid);
2916451Sedp 	if (i > DK_DEVID_SIZE)
2926451Sedp 		goto err;
2936451Sedp 	bcopy(devid, dkdevidp->dkd_devid, i);
2946451Sedp 
2956451Sedp 	/* Calculate the chksum */
2966451Sedp 	chksum = 0;
2976451Sedp 	ip = (uint_t *)dkdevidp;
2986451Sedp 	for (i = 0; i < ((NBPSCTR - sizeof (int))/sizeof (int)); i++)
2996451Sedp 		chksum ^= ip[i];
3006451Sedp 
3016451Sedp 	/* Fill in the checksum */
3026451Sedp 	DKD_FORMCHKSUM(chksum, dkdevidp);
3036451Sedp 
304*8863SEdward.Pilatowicz@Sun.COM 	if (xdfs_lb_rdwr(xsp->xdfss_dip,
3056451Sedp 	    TG_WRITE, dkdevidp, blk, NBPSCTR, NULL) != 0)
3066451Sedp 		goto err;
3076451Sedp 
3086451Sedp 	kmem_free(dkdevidp, NBPSCTR);
3096451Sedp 
310*8863SEdward.Pilatowicz@Sun.COM 	xsp->xdfss_tgt_devid = devid;
3116451Sedp 	return (DDI_SUCCESS);
3126451Sedp 
3136451Sedp err:
3146451Sedp 	if (dkdevidp != NULL)
3156451Sedp 		kmem_free(dkdevidp, NBPSCTR);
3166451Sedp 	if (devid != NULL)
3176451Sedp 		ddi_devid_free(devid);
3186451Sedp 	return (DDI_FAILURE);
3196451Sedp }
3206451Sedp 
3216451Sedp /*
322*8863SEdward.Pilatowicz@Sun.COM  * xdfs_rwcmd_copyin() is a duplicate of rwcmd_copyin().
3236451Sedp  */
3246451Sedp static int
xdfs_rwcmd_copyin(struct dadkio_rwcmd * rwcmdp,caddr_t inaddr,int flag)325*8863SEdward.Pilatowicz@Sun.COM xdfs_rwcmd_copyin(struct dadkio_rwcmd *rwcmdp, caddr_t inaddr, int flag)
3266451Sedp {
3276451Sedp 	switch (ddi_model_convert_from(flag)) {
3286451Sedp 		case DDI_MODEL_ILP32: {
3296451Sedp 			struct dadkio_rwcmd32 cmd32;
3306451Sedp 
3316451Sedp 			if (ddi_copyin(inaddr, &cmd32,
3326451Sedp 			    sizeof (struct dadkio_rwcmd32), flag)) {
3336451Sedp 				return (EFAULT);
3346451Sedp 			}
3356451Sedp 
3366451Sedp 			rwcmdp->cmd = cmd32.cmd;
3376451Sedp 			rwcmdp->flags = cmd32.flags;
3387563SPrasad.Singamsetty@Sun.COM 			rwcmdp->blkaddr = (blkaddr_t)cmd32.blkaddr;
3396451Sedp 			rwcmdp->buflen = cmd32.buflen;
3406451Sedp 			rwcmdp->bufaddr = (caddr_t)(intptr_t)cmd32.bufaddr;
3416451Sedp 			/*
3426451Sedp 			 * Note: we do not convert the 'status' field,
3436451Sedp 			 * as it should not contain valid data at this
3446451Sedp 			 * point.
3456451Sedp 			 */
3466451Sedp 			bzero(&rwcmdp->status, sizeof (rwcmdp->status));
3476451Sedp 			break;
3486451Sedp 		}
3496451Sedp 		case DDI_MODEL_NONE: {
3506451Sedp 			if (ddi_copyin(inaddr, rwcmdp,
3516451Sedp 			    sizeof (struct dadkio_rwcmd), flag)) {
3526451Sedp 				return (EFAULT);
3536451Sedp 			}
3546451Sedp 		}
3556451Sedp 	}
3566451Sedp 	return (0);
3576451Sedp }
3586451Sedp 
3596451Sedp /*
360*8863SEdward.Pilatowicz@Sun.COM  * xdfs_rwcmd_copyout() is a duplicate of rwcmd_copyout().
3616451Sedp  */
3626451Sedp static int
xdfs_rwcmd_copyout(struct dadkio_rwcmd * rwcmdp,caddr_t outaddr,int flag)363*8863SEdward.Pilatowicz@Sun.COM xdfs_rwcmd_copyout(struct dadkio_rwcmd *rwcmdp, caddr_t outaddr, int flag)
3646451Sedp {
3656451Sedp 	switch (ddi_model_convert_from(flag)) {
3666451Sedp 		case DDI_MODEL_ILP32: {
3676451Sedp 			struct dadkio_rwcmd32 cmd32;
3686451Sedp 
3696451Sedp 			cmd32.cmd = rwcmdp->cmd;
3706451Sedp 			cmd32.flags = rwcmdp->flags;
3716451Sedp 			cmd32.blkaddr = rwcmdp->blkaddr;
3726451Sedp 			cmd32.buflen = rwcmdp->buflen;
3736451Sedp 			ASSERT64(((uintptr_t)rwcmdp->bufaddr >> 32) == 0);
3746451Sedp 			cmd32.bufaddr = (caddr32_t)(uintptr_t)rwcmdp->bufaddr;
3756451Sedp 
3766451Sedp 			cmd32.status.status = rwcmdp->status.status;
3776451Sedp 			cmd32.status.resid = rwcmdp->status.resid;
3786451Sedp 			cmd32.status.failed_blk_is_valid =
3796451Sedp 			    rwcmdp->status.failed_blk_is_valid;
3806451Sedp 			cmd32.status.failed_blk = rwcmdp->status.failed_blk;
3816451Sedp 			cmd32.status.fru_code_is_valid =
3826451Sedp 			    rwcmdp->status.fru_code_is_valid;
3836451Sedp 			cmd32.status.fru_code = rwcmdp->status.fru_code;
3846451Sedp 
3856451Sedp 			bcopy(rwcmdp->status.add_error_info,
3866451Sedp 			    cmd32.status.add_error_info, DADKIO_ERROR_INFO_LEN);
3876451Sedp 
3886451Sedp 			if (ddi_copyout(&cmd32, outaddr,
3896451Sedp 			    sizeof (struct dadkio_rwcmd32), flag))
3906451Sedp 				return (EFAULT);
3916451Sedp 			break;
3926451Sedp 		}
3936451Sedp 		case DDI_MODEL_NONE: {
3946451Sedp 			if (ddi_copyout(rwcmdp, outaddr,
3956451Sedp 			    sizeof (struct dadkio_rwcmd), flag))
3966451Sedp 			return (EFAULT);
3976451Sedp 		}
3986451Sedp 	}
3996451Sedp 	return (0);
4006451Sedp }
4016451Sedp 
4026451Sedp static int
xdfs_dioctl_rwcmd(dev_t dev,intptr_t arg,int flag)403*8863SEdward.Pilatowicz@Sun.COM xdfs_dioctl_rwcmd(dev_t dev, intptr_t arg, int flag)
4046451Sedp {
4056451Sedp 	struct dadkio_rwcmd	*rwcmdp;
4066451Sedp 	struct iovec		aiov;
4076451Sedp 	struct uio		auio;
4086451Sedp 	struct buf		*bp;
4096451Sedp 	int			rw, status;
4106451Sedp 
4116451Sedp 	rwcmdp = kmem_alloc(sizeof (struct dadkio_rwcmd), KM_SLEEP);
412*8863SEdward.Pilatowicz@Sun.COM 	status = xdfs_rwcmd_copyin(rwcmdp, (caddr_t)arg, flag);
4136451Sedp 
4146451Sedp 	if (status != 0)
4156451Sedp 		goto out;
4166451Sedp 
4176451Sedp 	switch (rwcmdp->cmd) {
4186451Sedp 		case DADKIO_RWCMD_READ:
4196451Sedp 		case DADKIO_RWCMD_WRITE:
4206451Sedp 			break;
4216451Sedp 		default:
4226451Sedp 			status = EINVAL;
4236451Sedp 			goto out;
4246451Sedp 	}
4256451Sedp 
4266451Sedp 	bzero((caddr_t)&aiov, sizeof (struct iovec));
4276451Sedp 	aiov.iov_base = rwcmdp->bufaddr;
4286451Sedp 	aiov.iov_len = rwcmdp->buflen;
4296451Sedp 
4306451Sedp 	bzero((caddr_t)&auio, sizeof (struct uio));
4316451Sedp 	auio.uio_iov = &aiov;
4326451Sedp 	auio.uio_iovcnt = 1;
4336451Sedp 	auio.uio_loffset = (offset_t)rwcmdp->blkaddr * (offset_t)XB_BSIZE;
4346451Sedp 	auio.uio_resid = rwcmdp->buflen;
4356451Sedp 	auio.uio_segflg = (flag & FKIOCTL) ? UIO_SYSSPACE : UIO_USERSPACE;
4366451Sedp 
4376451Sedp 	/*
4386451Sedp 	 * Tell the xdf driver that this I/O request is using an absolute
4396451Sedp 	 * offset.
4406451Sedp 	 */
4416451Sedp 	bp = getrbuf(KM_SLEEP);
4426451Sedp 	bp->b_private = (void *)XB_SLICE_NONE;
4436451Sedp 
4446451Sedp 	rw = ((rwcmdp->cmd == DADKIO_RWCMD_WRITE) ? B_WRITE : B_READ);
445*8863SEdward.Pilatowicz@Sun.COM 	status = physio(xdfs_strategy, bp, dev, rw, xdfs_minphys, &auio);
4466451Sedp 
4476451Sedp 	biofini(bp);
4486451Sedp 	kmem_free(bp, sizeof (buf_t));
4496451Sedp 
4506451Sedp 	if (status == 0)
451*8863SEdward.Pilatowicz@Sun.COM 		status = xdfs_rwcmd_copyout(rwcmdp, (caddr_t)arg, flag);
4526451Sedp 
4536451Sedp out:
4546451Sedp 	kmem_free(rwcmdp, sizeof (struct dadkio_rwcmd));
4556451Sedp 	return (status);
4566451Sedp }
4576451Sedp 
458*8863SEdward.Pilatowicz@Sun.COM 
459*8863SEdward.Pilatowicz@Sun.COM /*
460*8863SEdward.Pilatowicz@Sun.COM  * xdf_shell callback functions
461*8863SEdward.Pilatowicz@Sun.COM  */
462*8863SEdward.Pilatowicz@Sun.COM /*ARGSUSED*/
463*8863SEdward.Pilatowicz@Sun.COM int
xdfs_c_ioctl(xdfs_state_t * xsp,dev_t dev,int part,int cmd,intptr_t arg,int flag,cred_t * credp,int * rvalp,boolean_t * done)464*8863SEdward.Pilatowicz@Sun.COM xdfs_c_ioctl(xdfs_state_t *xsp, dev_t dev, int part,
465*8863SEdward.Pilatowicz@Sun.COM     int cmd, intptr_t arg, int flag, cred_t *credp, int *rvalp, boolean_t *done)
4666451Sedp {
467*8863SEdward.Pilatowicz@Sun.COM 	*done = B_TRUE;
4686451Sedp 	switch (cmd) {
4696451Sedp 	default:
470*8863SEdward.Pilatowicz@Sun.COM 		*done = B_FALSE;
471*8863SEdward.Pilatowicz@Sun.COM 		return (0);
472*8863SEdward.Pilatowicz@Sun.COM 	case DKIOCLOCK:
473*8863SEdward.Pilatowicz@Sun.COM 	case DKIOCUNLOCK:
474*8863SEdward.Pilatowicz@Sun.COM 	case FDEJECT:
475*8863SEdward.Pilatowicz@Sun.COM 	case DKIOCEJECT:
476*8863SEdward.Pilatowicz@Sun.COM 	case CDROMEJECT: {
477*8863SEdward.Pilatowicz@Sun.COM 		/* we don't support ejectable devices */
478*8863SEdward.Pilatowicz@Sun.COM 		return (ENOTTY);
479*8863SEdward.Pilatowicz@Sun.COM 	}
4806451Sedp 	case DKIOCGETWCE:
481*8863SEdward.Pilatowicz@Sun.COM 	case DKIOCSETWCE: {
482*8863SEdward.Pilatowicz@Sun.COM 		/* we don't support write cache get/set */
4836451Sedp 		return (EIO);
484*8863SEdward.Pilatowicz@Sun.COM 	}
4856451Sedp 	case DKIOCADDBAD: {
4866451Sedp 		/*
4876451Sedp 		 * This is for ata/ide bad block handling.  It is supposed
4886451Sedp 		 * to cause the driver to re-read the bad block list and
4896451Sedp 		 * alternate map after it has been updated.  Our driver
4906451Sedp 		 * will refuse to attach to any disk which has a bad blocks
4916451Sedp 		 * list defined, so there really isn't much to do here.
4926451Sedp 		 */
4936451Sedp 		return (0);
4946451Sedp 	}
4956451Sedp 	case DKIOCGETDEF: {
4966451Sedp 		/*
4976451Sedp 		 * I can't actually find any code that utilizes this ioctl,
4986451Sedp 		 * hence we're leaving it explicitly unimplemented.
4996451Sedp 		 */
500*8863SEdward.Pilatowicz@Sun.COM 		ASSERT("ioctl cmd unsupported by xdf shell: DKIOCGETDEF");
5016451Sedp 		return (EIO);
5026451Sedp 	}
5036451Sedp 	case DIOCTL_RWCMD: {
5046451Sedp 		/*
5056451Sedp 		 * This just seems to just be an alternate interface for
5066451Sedp 		 * reading and writing the disk.  Great, another way to
5076451Sedp 		 * do the same thing...
5086451Sedp 		 */
509*8863SEdward.Pilatowicz@Sun.COM 		return (xdfs_dioctl_rwcmd(dev, arg, flag));
5106451Sedp 	}
5116451Sedp 	case DKIOCINFO: {
512*8863SEdward.Pilatowicz@Sun.COM 		int		instance = ddi_get_instance(xsp->xdfss_dip);
513*8863SEdward.Pilatowicz@Sun.COM 		dev_info_t	*dip = xsp->xdfss_dip;
5146451Sedp 		struct dk_cinfo	info;
515*8863SEdward.Pilatowicz@Sun.COM 		int		rv;
5166451Sedp 
5176451Sedp 		/* Pass on the ioctl request, save the response */
518*8863SEdward.Pilatowicz@Sun.COM 		if ((rv = ldi_ioctl(xsp->xdfss_tgt_lh[part],
5196451Sedp 		    cmd, (intptr_t)&info, FKIOCTL, credp, rvalp)) != 0)
520*8863SEdward.Pilatowicz@Sun.COM 			return (rv);
5216451Sedp 
5226451Sedp 		/* Update controller info */
5236451Sedp 		info.dki_cnum = ddi_get_instance(ddi_get_parent(dip));
5246451Sedp 		(void) strlcpy(info.dki_cname,
5256451Sedp 		    ddi_get_name(ddi_get_parent(dip)), sizeof (info.dki_cname));
5266451Sedp 
5276451Sedp 		/* Update unit info. */
5286451Sedp 		if (info.dki_ctype == DKC_VBD)
5296451Sedp 			info.dki_ctype = DKC_DIRECT;
5306451Sedp 		info.dki_unit = instance;
5316451Sedp 		(void) strlcpy(info.dki_dname,
5326451Sedp 		    ddi_driver_name(dip), sizeof (info.dki_dname));
5336451Sedp 		info.dki_addr = 1;
5346451Sedp 
5356451Sedp 		if (ddi_copyout(&info, (void *)arg, sizeof (info), flag))
5366451Sedp 			return (EFAULT);
5376451Sedp 		return (0);
5386451Sedp 	}
5396451Sedp 	} /* switch (cmd) */
5406451Sedp 	/*NOTREACHED*/
5416451Sedp }
5426451Sedp 
543*8863SEdward.Pilatowicz@Sun.COM /*
544*8863SEdward.Pilatowicz@Sun.COM  * xdfs_c_devid_setup() is a slightly modified copy of cmdk_devid_setup().
545*8863SEdward.Pilatowicz@Sun.COM  *
546*8863SEdward.Pilatowicz@Sun.COM  * Create and register the devid.
547*8863SEdward.Pilatowicz@Sun.COM  * There are 4 different ways we can get a device id:
548*8863SEdward.Pilatowicz@Sun.COM  *    1. Already have one - nothing to do
549*8863SEdward.Pilatowicz@Sun.COM  *    2. Build one from the drive's model and serial numbers
550*8863SEdward.Pilatowicz@Sun.COM  *    3. Read one from the disk (first sector of last track)
551*8863SEdward.Pilatowicz@Sun.COM  *    4. Fabricate one and write it on the disk.
552*8863SEdward.Pilatowicz@Sun.COM  * If any of these succeeds, register the deviceid
553*8863SEdward.Pilatowicz@Sun.COM  */
554*8863SEdward.Pilatowicz@Sun.COM void
xdfs_c_devid_setup(xdfs_state_t * xsp)555*8863SEdward.Pilatowicz@Sun.COM xdfs_c_devid_setup(xdfs_state_t *xsp)
5566451Sedp {
557*8863SEdward.Pilatowicz@Sun.COM 	int	rc;
5586451Sedp 
559*8863SEdward.Pilatowicz@Sun.COM 	/* Try options until one succeeds, or all have failed */
5606451Sedp 
561*8863SEdward.Pilatowicz@Sun.COM 	/* 1. All done if already registered */
5626451Sedp 
563*8863SEdward.Pilatowicz@Sun.COM 	if (xsp->xdfss_tgt_devid != NULL)
564*8863SEdward.Pilatowicz@Sun.COM 		return;
5656451Sedp 
566*8863SEdward.Pilatowicz@Sun.COM 	/* 2. Build a devid from the model and serial number */
567*8863SEdward.Pilatowicz@Sun.COM 	rc = xdfs_devid_modser(xsp);
568*8863SEdward.Pilatowicz@Sun.COM 	if (rc != DDI_SUCCESS) {
569*8863SEdward.Pilatowicz@Sun.COM 		/* 3. Read devid from the disk, if present */
570*8863SEdward.Pilatowicz@Sun.COM 		rc = xdfs_devid_read(xsp);
5716451Sedp 
572*8863SEdward.Pilatowicz@Sun.COM 		/* 4. otherwise make one up and write it on the disk */
573*8863SEdward.Pilatowicz@Sun.COM 		if (rc != DDI_SUCCESS)
574*8863SEdward.Pilatowicz@Sun.COM 			rc = xdfs_devid_fabricate(xsp);
575*8863SEdward.Pilatowicz@Sun.COM 	}
5766451Sedp 
577*8863SEdward.Pilatowicz@Sun.COM 	/* If we managed to get a devid any of the above ways, register it */
578*8863SEdward.Pilatowicz@Sun.COM 	if (rc == DDI_SUCCESS)
579*8863SEdward.Pilatowicz@Sun.COM 		(void) ddi_devid_register(xsp->xdfss_dip, xsp->xdfss_tgt_devid);
5806451Sedp }
5816451Sedp 
582*8863SEdward.Pilatowicz@Sun.COM int
xdfs_c_getpgeom(dev_info_t * dip,cmlb_geom_t * pgeom)583*8863SEdward.Pilatowicz@Sun.COM xdfs_c_getpgeom(dev_info_t *dip, cmlb_geom_t *pgeom)
5846451Sedp {
5856451Sedp 	struct scsi_device	*scsi_device;
5866451Sedp 	struct tgdk_geom	tgdk_geom;
5876451Sedp 	opaque_t		ctlobjp;
5886451Sedp 	int			err;
5896451Sedp 
5906451Sedp 	scsi_device = ddi_get_driver_private(dip);
5916451Sedp 	ctlobjp = scsi_device->sd_address.a_hba_tran;
5926451Sedp 	if ((err = CTL_IOCTL(ctlobjp,
5936451Sedp 	    DIOCTL_GETPHYGEOM, (uintptr_t)&tgdk_geom, FKIOCTL)) != 0)
5946451Sedp 		return (err);
5956451Sedp 
5966451Sedp 	/* This driver won't work if this isn't true */
5976451Sedp 	ASSERT(tgdk_geom.g_secsiz == XB_BSIZE);
5986451Sedp 
5996451Sedp 	pgeom->g_ncyl = tgdk_geom.g_cyl;
6006451Sedp 	pgeom->g_acyl = tgdk_geom.g_acyl;
6016451Sedp 	pgeom->g_nhead = tgdk_geom.g_head;
6026451Sedp 	pgeom->g_nsect = tgdk_geom.g_sec;
6036451Sedp 	pgeom->g_secsize = tgdk_geom.g_secsiz;
6046451Sedp 	pgeom->g_capacity = tgdk_geom.g_cap;
6056451Sedp 	pgeom->g_intrlv = 1;
6066451Sedp 	pgeom->g_rpm = 3600;
6076451Sedp 	return (0);
6086451Sedp }
6096451Sedp 
610*8863SEdward.Pilatowicz@Sun.COM boolean_t
xdfs_c_bb_check(xdfs_state_t * xsp)611*8863SEdward.Pilatowicz@Sun.COM xdfs_c_bb_check(xdfs_state_t *xsp)
6126451Sedp {
6136451Sedp 	struct alts_parttbl	*ap;
6146451Sedp 	diskaddr_t		nblocks, blk;
6156451Sedp 	uint32_t		altused, altbase, altlast;
6166451Sedp 	uint16_t		vtoctag;
6176451Sedp 	int			alts;
6186451Sedp 
6196451Sedp 	/* find slice with V_ALTSCTR tag */
6206451Sedp 	for (alts = 0; alts < NDKMAP; alts++) {
6216451Sedp 
622*8863SEdward.Pilatowicz@Sun.COM 		if (cmlb_partinfo(xsp->xdfss_cmlbhandle, alts,
6236451Sedp 		    &nblocks, &blk, NULL, &vtoctag, 0) != 0) {
6246451Sedp 			/* no partition table exists */
6256451Sedp 			return (B_FALSE);
6266451Sedp 		}
6276451Sedp 
6286451Sedp 		if ((vtoctag == V_ALTSCTR) && (nblocks > 1))
6296451Sedp 			break;
6306451Sedp 	}
6316451Sedp 	if (alts >= NDKMAP)
6326451Sedp 		return (B_FALSE); /* no V_ALTSCTR slice defined */
6336451Sedp 
6346451Sedp 	/* read in ALTS label block */
6356451Sedp 	ap = (struct alts_parttbl *)kmem_zalloc(NBPSCTR, KM_SLEEP);
636*8863SEdward.Pilatowicz@Sun.COM 	if (xdfs_lb_rdwr(xsp->xdfss_dip, TG_READ, ap, blk, NBPSCTR, NULL) != 0)
6376451Sedp 		goto err;
6386451Sedp 
6396451Sedp 	altused = ap->alts_ent_used;	/* number of BB entries */
6406451Sedp 	altbase = ap->alts_ent_base;	/* blk offset from begin slice */
6416451Sedp 	altlast = ap->alts_ent_end;	/* blk offset to last block */
6426451Sedp 
6436451Sedp 	if ((altused == 0) || (altbase < 1) ||
6446451Sedp 	    (altbase > altlast) || (altlast >= nblocks))
6456451Sedp 		goto err;
6466451Sedp 
6476451Sedp 	/* we found bad block mappins */
6486451Sedp 	kmem_free(ap, NBPSCTR);
6496451Sedp 	return (B_TRUE);
6506451Sedp 
6516451Sedp err:
6526451Sedp 	kmem_free(ap, NBPSCTR);
6536451Sedp 	return (B_FALSE);
6546451Sedp }
6556451Sedp 
656*8863SEdward.Pilatowicz@Sun.COM char *
xdfs_c_cmlb_node_type(xdfs_state_t * xsp)657*8863SEdward.Pilatowicz@Sun.COM xdfs_c_cmlb_node_type(xdfs_state_t *xsp)
6586451Sedp {
659*8863SEdward.Pilatowicz@Sun.COM 	return (xsp->xdfss_tgt_is_cd ? DDI_NT_CD : DDI_NT_BLOCK);
6606451Sedp }
6616451Sedp 
6626451Sedp /*ARGSUSED*/
663*8863SEdward.Pilatowicz@Sun.COM int
xdfs_c_cmlb_alter_behavior(xdfs_state_t * xsp)664*8863SEdward.Pilatowicz@Sun.COM xdfs_c_cmlb_alter_behavior(xdfs_state_t *xsp)
6656451Sedp {
666*8863SEdward.Pilatowicz@Sun.COM 	return (xsp->xdfss_tgt_is_cd ?
667*8863SEdward.Pilatowicz@Sun.COM 	    0 : CMLB_CREATE_ALTSLICE_VTOC_16_DTYPE_DIRECT);
6686451Sedp }
6696451Sedp 
670*8863SEdward.Pilatowicz@Sun.COM /*ARGSUSED*/
671*8863SEdward.Pilatowicz@Sun.COM void
xdfs_c_attach(xdfs_state_t * xsp)672*8863SEdward.Pilatowicz@Sun.COM xdfs_c_attach(xdfs_state_t *xsp)
6736451Sedp {
6746451Sedp }
675