xref: /titanic_51/usr/src/uts/i86pc/i86hvm/io/pv_cmdk.c (revision 7f0b8309074a5d8e9f9d8ffe7aad7bb0b1ee6b1f)
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