xref: /titanic_51/usr/src/uts/intel/io/dktp/dcdev/dadk.c (revision b89e420ae1290e425c29db875ec0c0546006eec7)
1507c3241Smlf /*
2507c3241Smlf  * CDDL HEADER START
3507c3241Smlf  *
4507c3241Smlf  * The contents of this file are subject to the terms of the
5507c3241Smlf  * Common Development and Distribution License (the "License").
6507c3241Smlf  * 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  */
21507c3241Smlf 
22507c3241Smlf /*
23744947dcSTom Erickson  * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
24507c3241Smlf  */
25507c3241Smlf 
26507c3241Smlf /*
27507c3241Smlf  * Direct Attached Disk
28507c3241Smlf  */
29507c3241Smlf 
30507c3241Smlf #include <sys/file.h>
31507c3241Smlf #include <sys/scsi/scsi.h>
32507c3241Smlf #include <sys/var.h>
33507c3241Smlf #include <sys/proc.h>
34507c3241Smlf #include <sys/dktp/cm.h>
35507c3241Smlf #include <sys/vtoc.h>
36507c3241Smlf #include <sys/dkio.h>
370f2c99a4Syt160523 #include <sys/policy.h>
380f2c99a4Syt160523 #include <sys/priv.h>
39507c3241Smlf 
40507c3241Smlf #include <sys/dktp/dadev.h>
41507c3241Smlf #include <sys/dktp/fctypes.h>
42507c3241Smlf #include <sys/dktp/flowctrl.h>
43507c3241Smlf #include <sys/dktp/tgcom.h>
44507c3241Smlf #include <sys/dktp/tgdk.h>
45507c3241Smlf #include <sys/dktp/bbh.h>
46507c3241Smlf #include <sys/dktp/dadkio.h>
47507c3241Smlf #include <sys/dktp/dadk.h>
48507c3241Smlf #include <sys/cdio.h>
49507c3241Smlf 
50507c3241Smlf /*
51507c3241Smlf  * Local Function Prototypes
52507c3241Smlf  */
53507c3241Smlf static void dadk_restart(void *pktp);
54507c3241Smlf static void dadk_pktcb(struct cmpkt *pktp);
55507c3241Smlf static void dadk_iodone(struct buf *bp);
56507c3241Smlf static void dadk_polldone(struct buf *bp);
57507c3241Smlf static void dadk_setcap(struct dadk *dadkp);
584d27faddSmarx static void dadk_create_errstats(struct dadk *dadkp, int instance);
594d27faddSmarx static void dadk_destroy_errstats(struct dadk *dadkp);
60507c3241Smlf 
61507c3241Smlf static int dadk_chkerr(struct cmpkt *pktp);
62507c3241Smlf static int dadk_ioprep(struct dadk *dadkp, struct cmpkt *pktp);
63507c3241Smlf static int dadk_iosetup(struct dadk *dadkp, struct cmpkt *pktp);
64507c3241Smlf static int dadk_ioretry(struct cmpkt *pktp, int action);
65507c3241Smlf 
66507c3241Smlf static struct cmpkt *dadk_pktprep(struct dadk *dadkp, struct cmpkt *in_pktp,
67507c3241Smlf     struct buf *bp, void (*cb_func)(struct buf *), int (*func)(caddr_t),
68507c3241Smlf     caddr_t arg);
69507c3241Smlf 
70507c3241Smlf static int  dadk_pkt(opaque_t com_data, struct buf *bp, int (*func)(caddr_t),
71507c3241Smlf     caddr_t arg);
72507c3241Smlf static void dadk_transport(opaque_t com_data, struct buf *bp);
732df1fe9cSrandyf static int dadk_ctl_ioctl(struct dadk *, uint32_t, uintptr_t, int);
74507c3241Smlf 
75507c3241Smlf struct tgcom_objops dadk_com_ops = {
76507c3241Smlf 	nodev,
77507c3241Smlf 	nodev,
78507c3241Smlf 	dadk_pkt,
79507c3241Smlf 	dadk_transport,
80507c3241Smlf 	0, 0
81507c3241Smlf };
82507c3241Smlf 
83507c3241Smlf /*
84507c3241Smlf  * architecture dependent allocation restrictions for dadk_iob_alloc(). For
85507c3241Smlf  * x86, we'll set dma_attr_addr_hi to dadk_max_phys_addr and dma_attr_sgllen
86507c3241Smlf  * to dadk_sgl_size during _init().
87507c3241Smlf  */
88507c3241Smlf #if defined(__sparc)
89507c3241Smlf static ddi_dma_attr_t dadk_alloc_attr = {
90507c3241Smlf 	DMA_ATTR_V0,	/* version number */
91507c3241Smlf 	0x0,		/* lowest usable address */
92507c3241Smlf 	0xFFFFFFFFull,	/* high DMA address range */
93507c3241Smlf 	0xFFFFFFFFull,	/* DMA counter register */
94507c3241Smlf 	1,		/* DMA address alignment */
95507c3241Smlf 	1,		/* DMA burstsizes */
96507c3241Smlf 	1,		/* min effective DMA size */
97507c3241Smlf 	0xFFFFFFFFull,	/* max DMA xfer size */
98507c3241Smlf 	0xFFFFFFFFull,	/* segment boundary */
99507c3241Smlf 	1,		/* s/g list length */
100507c3241Smlf 	512,		/* granularity of device */
101507c3241Smlf 	0,		/* DMA transfer flags */
102507c3241Smlf };
103507c3241Smlf #elif defined(__x86)
104507c3241Smlf static ddi_dma_attr_t dadk_alloc_attr = {
105507c3241Smlf 	DMA_ATTR_V0,	/* version number */
106507c3241Smlf 	0x0,		/* lowest usable address */
107507c3241Smlf 	0x0,		/* high DMA address range [set in _init()] */
108507c3241Smlf 	0xFFFFull,	/* DMA counter register */
109507c3241Smlf 	512,		/* DMA address alignment */
110507c3241Smlf 	1,		/* DMA burstsizes */
111507c3241Smlf 	1,		/* min effective DMA size */
112507c3241Smlf 	0xFFFFFFFFull,	/* max DMA xfer size */
113507c3241Smlf 	0xFFFFFFFFull,	/* segment boundary */
114507c3241Smlf 	0,		/* s/g list length [set in _init()] */
115507c3241Smlf 	512,		/* granularity of device */
116507c3241Smlf 	0,		/* DMA transfer flags */
117507c3241Smlf };
118507c3241Smlf 
119507c3241Smlf uint64_t dadk_max_phys_addr = 0xFFFFFFFFull;
120507c3241Smlf int dadk_sgl_size = 0xFF;
121507c3241Smlf #endif
122507c3241Smlf 
123507c3241Smlf static int dadk_rmb_ioctl(struct dadk *dadkp, int cmd, intptr_t arg, int flags,
124507c3241Smlf     int silent);
125507c3241Smlf static void dadk_rmb_iodone(struct buf *bp);
126507c3241Smlf 
127507c3241Smlf static int dadk_dk_buf_setup(struct dadk *dadkp, opaque_t *cmdp,
128507c3241Smlf     dev_t dev, enum uio_seg dataspace, int rw);
129507c3241Smlf static void dadk_dk(struct dadk *dadkp, struct dadkio_rwcmd *scmdp,
130507c3241Smlf     struct buf *bp);
131507c3241Smlf static void dadkmin(struct buf *bp);
132507c3241Smlf static int dadk_dk_strategy(struct buf *bp);
133507c3241Smlf static void dadk_recorderr(struct cmpkt *pktp, struct dadkio_rwcmd *rwcmdp);
134507c3241Smlf 
135507c3241Smlf struct tgdk_objops dadk_ops = {
136507c3241Smlf 	dadk_init,
137507c3241Smlf 	dadk_free,
138507c3241Smlf 	dadk_probe,
139507c3241Smlf 	dadk_attach,
140507c3241Smlf 	dadk_open,
141507c3241Smlf 	dadk_close,
142507c3241Smlf 	dadk_ioctl,
143507c3241Smlf 	dadk_strategy,
144507c3241Smlf 	dadk_setgeom,
145507c3241Smlf 	dadk_getgeom,
146507c3241Smlf 	dadk_iob_alloc,
147507c3241Smlf 	dadk_iob_free,
148507c3241Smlf 	dadk_iob_htoc,
149507c3241Smlf 	dadk_iob_xfer,
150507c3241Smlf 	dadk_dump,
151507c3241Smlf 	dadk_getphygeom,
152507c3241Smlf 	dadk_set_bbhobj,
153507c3241Smlf 	dadk_check_media,
154507c3241Smlf 	dadk_inquiry,
155507c3241Smlf 	dadk_cleanup,
156507c3241Smlf 	0
157507c3241Smlf };
158507c3241Smlf 
159507c3241Smlf /*
160507c3241Smlf  * Local static data
161507c3241Smlf  */
162507c3241Smlf 
163507c3241Smlf #ifdef	DADK_DEBUG
164507c3241Smlf #define	DENT	0x0001
165507c3241Smlf #define	DERR	0x0002
166507c3241Smlf #define	DIO	0x0004
167507c3241Smlf #define	DGEOM	0x0010
168507c3241Smlf #define	DSTATE  0x0020
169507c3241Smlf static	int	dadk_debug = DGEOM;
170507c3241Smlf 
171507c3241Smlf #endif	/* DADK_DEBUG */
172507c3241Smlf 
173507c3241Smlf static int dadk_check_media_time = 3000000;	/* 3 Second State Check */
174507c3241Smlf static int dadk_dk_maxphys = 0x80000;
175507c3241Smlf 
176507c3241Smlf static char	*dadk_cmds[] = {
177507c3241Smlf 	"\000Unknown",			/* unknown 		*/
178507c3241Smlf 	"\001read sector",		/* DCMD_READ 1		*/
179507c3241Smlf 	"\002write sector",		/* DCMD_WRITE 2		*/
180507c3241Smlf 	"\003format track",		/* DCMD_FMTTRK 3	*/
181507c3241Smlf 	"\004format whole drive",	/* DCMD_FMTDRV 4	*/
182507c3241Smlf 	"\005recalibrate",		/* DCMD_RECAL  5	*/
183507c3241Smlf 	"\006seek sector",		/* DCMD_SEEK   6	*/
184507c3241Smlf 	"\007read verify",		/* DCMD_RDVER  7	*/
185507c3241Smlf 	"\010read defect list",		/* DCMD_GETDEF 8	*/
186507c3241Smlf 	"\011lock door",		/* DCMD_LOCK   9	*/
187507c3241Smlf 	"\012unlock door",		/* DCMD_UNLOCK 10	*/
188507c3241Smlf 	"\013start motor",		/* DCMD_START_MOTOR 11	*/
189507c3241Smlf 	"\014stop motor",		/* DCMD_STOP_MOTOR 12	*/
190507c3241Smlf 	"\015eject",			/* DCMD_EJECT  13	*/
191507c3241Smlf 	"\016update geometry",		/* DCMD_UPDATE_GEOM  14	*/
192507c3241Smlf 	"\017get state",		/* DCMD_GET_STATE  15	*/
193507c3241Smlf 	"\020cdrom pause",		/* DCMD_PAUSE  16	*/
194507c3241Smlf 	"\021cdrom resume",		/* DCMD_RESUME  17	*/
195507c3241Smlf 	"\022cdrom play track index",	/* DCMD_PLAYTRKIND  18	*/
196507c3241Smlf 	"\023cdrom play msf",		/* DCMD_PLAYMSF  19	*/
197507c3241Smlf 	"\024cdrom sub channel",	/* DCMD_SUBCHNL  20	*/
198507c3241Smlf 	"\025cdrom read mode 1",	/* DCMD_READMODE1  21	*/
199507c3241Smlf 	"\026cdrom read toc header",	/* DCMD_READTOCHDR  22	*/
200507c3241Smlf 	"\027cdrom read toc entry",	/* DCMD_READTOCENT  23	*/
201507c3241Smlf 	"\030cdrom read offset",	/* DCMD_READOFFSET  24	*/
202507c3241Smlf 	"\031cdrom read mode 2",	/* DCMD_READMODE2  25	*/
203507c3241Smlf 	"\032cdrom volume control",	/* DCMD_VOLCTRL  26	*/
204507c3241Smlf 	"\033flush cache",		/* DCMD_FLUSH_CACHE  27	*/
205507c3241Smlf 	NULL
206507c3241Smlf };
207507c3241Smlf 
208507c3241Smlf static char *dadk_sense[] = {
209507c3241Smlf 	"\000Success",			/* DERR_SUCCESS		*/
210507c3241Smlf 	"\001address mark not found",	/* DERR_AMNF		*/
211507c3241Smlf 	"\002track 0 not found",	/* DERR_TKONF		*/
212507c3241Smlf 	"\003aborted command",		/* DERR_ABORT		*/
213507c3241Smlf 	"\004write fault",		/* DERR_DWF		*/
214507c3241Smlf 	"\005ID not found",		/* DERR_IDNF		*/
215507c3241Smlf 	"\006drive busy",		/* DERR_BUSY		*/
216507c3241Smlf 	"\007uncorrectable data error",	/* DERR_UNC		*/
217507c3241Smlf 	"\010bad block detected",	/* DERR_BBK		*/
218507c3241Smlf 	"\011invalid command",		/* DERR_INVCDB		*/
219507c3241Smlf 	"\012device hard error",	/* DERR_HARD		*/
220507c3241Smlf 	"\013illegal length indicated", /* DERR_ILI		*/
221507c3241Smlf 	"\014end of media",		/* DERR_EOM		*/
222507c3241Smlf 	"\015media change requested",	/* DERR_MCR		*/
223507c3241Smlf 	"\016recovered from error",	/* DERR_RECOVER		*/
224507c3241Smlf 	"\017device not ready",		/* DERR_NOTREADY	*/
225507c3241Smlf 	"\020medium error",		/* DERR_MEDIUM		*/
226507c3241Smlf 	"\021hardware error",		/* DERR_HW		*/
227507c3241Smlf 	"\022illegal request",		/* DERR_ILL		*/
228507c3241Smlf 	"\023unit attention",		/* DERR_UNIT_ATTN	*/
229507c3241Smlf 	"\024data protection",		/* DERR_DATA_PROT	*/
230507c3241Smlf 	"\025miscompare",		/* DERR_MISCOMPARE	*/
231507c3241Smlf 	"\026ICRC error during UDMA",	/* DERR_ICRC		*/
232507c3241Smlf 	"\027reserved",			/* DERR_RESV		*/
233507c3241Smlf 	NULL
234507c3241Smlf };
235507c3241Smlf 
236507c3241Smlf static char *dadk_name = "Disk";
237507c3241Smlf 
238507c3241Smlf /*
239507c3241Smlf  *	This is the loadable module wrapper
240507c3241Smlf  */
241507c3241Smlf #include <sys/modctl.h>
242507c3241Smlf 
243507c3241Smlf extern struct mod_ops mod_miscops;
244507c3241Smlf 
245507c3241Smlf static struct modlmisc modlmisc = {
246507c3241Smlf 	&mod_miscops,	/* Type of module */
2471dc8bc23Szk194757 	"Direct Attached Disk"
248507c3241Smlf };
249507c3241Smlf 
250507c3241Smlf static struct modlinkage modlinkage = {
251507c3241Smlf 	MODREV_1, (void *)&modlmisc, NULL
252507c3241Smlf };
253507c3241Smlf 
254507c3241Smlf int
255507c3241Smlf _init(void)
256507c3241Smlf {
257507c3241Smlf #ifdef DADK_DEBUG
258507c3241Smlf 	if (dadk_debug & DENT)
259507c3241Smlf 		PRF("dadk_init: call\n");
260507c3241Smlf #endif
261507c3241Smlf 
262507c3241Smlf #if defined(__x86)
263507c3241Smlf 	/* set the max physical address for iob allocs on x86 */
264507c3241Smlf 	dadk_alloc_attr.dma_attr_addr_hi = dadk_max_phys_addr;
265507c3241Smlf 
266507c3241Smlf 	/*
267507c3241Smlf 	 * set the sgllen for iob allocs on x86. If this is set less than
268507c3241Smlf 	 * the number of pages the buffer will take (taking into account
269507c3241Smlf 	 * alignment), it would force the allocator to try and allocate
270507c3241Smlf 	 * contiguous pages.
271507c3241Smlf 	 */
272507c3241Smlf 	dadk_alloc_attr.dma_attr_sgllen = dadk_sgl_size;
273507c3241Smlf #endif
274507c3241Smlf 
275507c3241Smlf 	return (mod_install(&modlinkage));
276507c3241Smlf }
277507c3241Smlf 
278507c3241Smlf int
279507c3241Smlf _fini(void)
280507c3241Smlf {
281507c3241Smlf #ifdef DADK_DEBUG
282507c3241Smlf 	if (dadk_debug & DENT)
283507c3241Smlf 		PRF("dadk_fini: call\n");
284507c3241Smlf #endif
285507c3241Smlf 
286507c3241Smlf 	return (mod_remove(&modlinkage));
287507c3241Smlf }
288507c3241Smlf 
289507c3241Smlf int
290507c3241Smlf _info(struct modinfo *modinfop)
291507c3241Smlf {
292507c3241Smlf 	return (mod_info(&modlinkage, modinfop));
293507c3241Smlf }
294507c3241Smlf 
295507c3241Smlf struct tgdk_obj *
296507c3241Smlf dadk_create()
297507c3241Smlf {
298507c3241Smlf 	struct tgdk_obj *dkobjp;
299507c3241Smlf 	struct dadk *dadkp;
300507c3241Smlf 
301507c3241Smlf 	dkobjp = kmem_zalloc((sizeof (*dkobjp) + sizeof (*dadkp)), KM_NOSLEEP);
302507c3241Smlf 	if (!dkobjp)
303507c3241Smlf 		return (NULL);
304507c3241Smlf 	dadkp = (struct dadk *)(dkobjp+1);
305507c3241Smlf 
306507c3241Smlf 	dkobjp->tg_ops  = (struct  tgdk_objops *)&dadk_ops;
307507c3241Smlf 	dkobjp->tg_data = (opaque_t)dadkp;
308507c3241Smlf 	dkobjp->tg_ext = &(dkobjp->tg_extblk);
309507c3241Smlf 	dadkp->dad_extp = &(dkobjp->tg_extblk);
310507c3241Smlf 
311507c3241Smlf #ifdef DADK_DEBUG
312507c3241Smlf 	if (dadk_debug & DENT)
313507c3241Smlf 		PRF("dadk_create: tgdkobjp= 0x%x dadkp= 0x%x\n", dkobjp, dadkp);
314507c3241Smlf #endif
315507c3241Smlf 	return (dkobjp);
316507c3241Smlf }
317507c3241Smlf 
318507c3241Smlf int
319507c3241Smlf dadk_init(opaque_t objp, opaque_t devp, opaque_t flcobjp, opaque_t queobjp,
320507c3241Smlf 	opaque_t bbhobjp, void *lkarg)
321507c3241Smlf {
322507c3241Smlf 	struct dadk *dadkp = (struct dadk *)objp;
323507c3241Smlf 	struct scsi_device *sdevp = (struct scsi_device *)devp;
324507c3241Smlf 
325507c3241Smlf 	dadkp->dad_sd = devp;
326507c3241Smlf 	dadkp->dad_ctlobjp = (opaque_t)sdevp->sd_address.a_hba_tran;
327507c3241Smlf 	sdevp->sd_private = (caddr_t)dadkp;
328507c3241Smlf 
329507c3241Smlf 	/* initialize the communication object */
330507c3241Smlf 	dadkp->dad_com.com_data = (opaque_t)dadkp;
331507c3241Smlf 	dadkp->dad_com.com_ops  = &dadk_com_ops;
332507c3241Smlf 
333507c3241Smlf 	dadkp->dad_bbhobjp = bbhobjp;
334507c3241Smlf 	BBH_INIT(bbhobjp);
335507c3241Smlf 
336507c3241Smlf 	dadkp->dad_flcobjp = flcobjp;
3372df1fe9cSrandyf 	mutex_init(&dadkp->dad_cmd_mutex, NULL, MUTEX_DRIVER, NULL);
3382df1fe9cSrandyf 	dadkp->dad_cmd_count = 0;
339507c3241Smlf 	return (FLC_INIT(flcobjp, &(dadkp->dad_com), queobjp, lkarg));
340507c3241Smlf }
341507c3241Smlf 
342507c3241Smlf int
343507c3241Smlf dadk_free(struct tgdk_obj *dkobjp)
344507c3241Smlf {
345507c3241Smlf 	TGDK_CLEANUP(dkobjp);
346507c3241Smlf 	kmem_free(dkobjp, (sizeof (*dkobjp) + sizeof (struct dadk)));
347507c3241Smlf 
348507c3241Smlf 	return (DDI_SUCCESS);
349507c3241Smlf }
350507c3241Smlf 
351507c3241Smlf void
352507c3241Smlf dadk_cleanup(struct tgdk_obj *dkobjp)
353507c3241Smlf {
354507c3241Smlf 	struct dadk *dadkp;
355507c3241Smlf 
356507c3241Smlf 	dadkp = (struct dadk *)(dkobjp->tg_data);
357507c3241Smlf 	if (dadkp->dad_sd)
358507c3241Smlf 		dadkp->dad_sd->sd_private = NULL;
359507c3241Smlf 	if (dadkp->dad_bbhobjp) {
360507c3241Smlf 		BBH_FREE(dadkp->dad_bbhobjp);
361507c3241Smlf 		dadkp->dad_bbhobjp = NULL;
362507c3241Smlf 	}
363507c3241Smlf 	if (dadkp->dad_flcobjp) {
364507c3241Smlf 		FLC_FREE(dadkp->dad_flcobjp);
365507c3241Smlf 		dadkp->dad_flcobjp = NULL;
366507c3241Smlf 	}
3672df1fe9cSrandyf 	mutex_destroy(&dadkp->dad_cmd_mutex);
368507c3241Smlf }
369507c3241Smlf 
370507c3241Smlf /* ARGSUSED */
371507c3241Smlf int
372507c3241Smlf dadk_probe(opaque_t objp, int kmsflg)
373507c3241Smlf {
374507c3241Smlf 	struct dadk *dadkp = (struct dadk *)objp;
375507c3241Smlf 	struct scsi_device *devp;
376507c3241Smlf 	char   name[80];
377507c3241Smlf 
378507c3241Smlf 	devp = dadkp->dad_sd;
379507c3241Smlf 	if (!devp->sd_inq || (devp->sd_inq->inq_dtype == DTYPE_NOTPRESENT) ||
380507c3241Smlf 	    (devp->sd_inq->inq_dtype == DTYPE_UNKNOWN)) {
381507c3241Smlf 		return (DDI_PROBE_FAILURE);
382507c3241Smlf 	}
383507c3241Smlf 
384507c3241Smlf 	switch (devp->sd_inq->inq_dtype) {
385507c3241Smlf 		case DTYPE_DIRECT:
386507c3241Smlf 			dadkp->dad_ctype = DKC_DIRECT;
387507c3241Smlf 			dadkp->dad_extp->tg_nodetype = DDI_NT_BLOCK;
388507c3241Smlf 			dadkp->dad_extp->tg_ctype = DKC_DIRECT;
389507c3241Smlf 			break;
390507c3241Smlf 		case DTYPE_RODIRECT: /* eg cdrom */
391507c3241Smlf 			dadkp->dad_ctype = DKC_CDROM;
392507c3241Smlf 			dadkp->dad_extp->tg_rdonly = 1;
393507c3241Smlf 			dadkp->dad_rdonly = 1;
394507c3241Smlf 			dadkp->dad_cdrom = 1;
395507c3241Smlf 			dadkp->dad_extp->tg_nodetype = DDI_NT_CD;
396507c3241Smlf 			dadkp->dad_extp->tg_ctype = DKC_CDROM;
397507c3241Smlf 			break;
398507c3241Smlf 		case DTYPE_WORM:
399507c3241Smlf 		case DTYPE_OPTICAL:
400507c3241Smlf 		default:
401507c3241Smlf 			return (DDI_PROBE_FAILURE);
402507c3241Smlf 	}
403507c3241Smlf 
404507c3241Smlf 	dadkp->dad_extp->tg_rmb = dadkp->dad_rmb = devp->sd_inq->inq_rmb;
405507c3241Smlf 
406507c3241Smlf 	dadkp->dad_secshf = SCTRSHFT;
407507c3241Smlf 	dadkp->dad_blkshf = 0;
408507c3241Smlf 
409507c3241Smlf 	/* display the device name */
410507c3241Smlf 	(void) strcpy(name, "Vendor '");
411507c3241Smlf 	gda_inqfill((caddr_t)devp->sd_inq->inq_vid, 8, &name[strlen(name)]);
412507c3241Smlf 	(void) strcat(name, "' Product '");
413507c3241Smlf 	gda_inqfill((caddr_t)devp->sd_inq->inq_pid, 16, &name[strlen(name)]);
414507c3241Smlf 	(void) strcat(name, "'");
415507c3241Smlf 	gda_log(devp->sd_dev, dadk_name, CE_NOTE, "!<%s>\n", name);
416507c3241Smlf 
417507c3241Smlf 	return (DDI_PROBE_SUCCESS);
418507c3241Smlf }
419507c3241Smlf 
420507c3241Smlf 
421507c3241Smlf /* ARGSUSED */
422507c3241Smlf int
423507c3241Smlf dadk_attach(opaque_t objp)
424507c3241Smlf {
425507c3241Smlf 	return (DDI_SUCCESS);
426507c3241Smlf }
427507c3241Smlf 
428507c3241Smlf int
429507c3241Smlf dadk_set_bbhobj(opaque_t objp, opaque_t bbhobjp)
430507c3241Smlf {
431507c3241Smlf 	struct dadk *dadkp = (struct dadk *)objp;
432507c3241Smlf 	/* free the old bbh object */
433507c3241Smlf 	if (dadkp->dad_bbhobjp)
434507c3241Smlf 		BBH_FREE(dadkp->dad_bbhobjp);
435507c3241Smlf 
436507c3241Smlf 	/* initialize the new bbh object */
437507c3241Smlf 	dadkp->dad_bbhobjp = bbhobjp;
438507c3241Smlf 	BBH_INIT(bbhobjp);
439507c3241Smlf 
440507c3241Smlf 	return (DDI_SUCCESS);
441507c3241Smlf }
442507c3241Smlf 
443507c3241Smlf /* ARGSUSED */
444507c3241Smlf int
445507c3241Smlf dadk_open(opaque_t objp, int flag)
446507c3241Smlf {
447507c3241Smlf 	struct dadk *dadkp = (struct dadk *)objp;
448507c3241Smlf 	int error;
449507c3241Smlf 	int wce;
450507c3241Smlf 
451507c3241Smlf 	if (!dadkp->dad_rmb) {
452507c3241Smlf 		if (dadkp->dad_phyg.g_cap) {
453507c3241Smlf 			FLC_START_KSTAT(dadkp->dad_flcobjp, "disk",
454507c3241Smlf 			    ddi_get_instance(CTL_DIP_DEV(dadkp->dad_ctlobjp)));
455507c3241Smlf 			return (DDI_SUCCESS);
456507c3241Smlf 		}
457507c3241Smlf 	} else {
458507c3241Smlf 		mutex_enter(&dadkp->dad_mutex);
459507c3241Smlf 		dadkp->dad_iostate = DKIO_NONE;
460507c3241Smlf 		cv_broadcast(&dadkp->dad_state_cv);
461507c3241Smlf 		mutex_exit(&dadkp->dad_mutex);
462507c3241Smlf 
4632df1fe9cSrandyf 		if (dadk_rmb_ioctl(dadkp, DCMD_START_MOTOR, 0, 0,
4642df1fe9cSrandyf 		    DADK_SILENT) ||
465507c3241Smlf 		    dadk_rmb_ioctl(dadkp, DCMD_LOCK, 0, 0, DADK_SILENT) ||
4662df1fe9cSrandyf 		    dadk_rmb_ioctl(dadkp, DCMD_UPDATE_GEOM, 0, 0,
4672df1fe9cSrandyf 		    DADK_SILENT)) {
468507c3241Smlf 			return (DDI_FAILURE);
469507c3241Smlf 		}
470507c3241Smlf 
471507c3241Smlf 		mutex_enter(&dadkp->dad_mutex);
472507c3241Smlf 		dadkp->dad_iostate = DKIO_INSERTED;
473507c3241Smlf 		cv_broadcast(&dadkp->dad_state_cv);
474507c3241Smlf 		mutex_exit(&dadkp->dad_mutex);
475507c3241Smlf 	}
476507c3241Smlf 
477507c3241Smlf 	/*
478507c3241Smlf 	 * get write cache enable state
479507c3241Smlf 	 * If there is an error, must assume that write cache
480507c3241Smlf 	 * is enabled.
481507c3241Smlf 	 * NOTE: Since there is currently no Solaris mechanism to
482507c3241Smlf 	 * change the state of the Write Cache Enable feature,
483507c3241Smlf 	 * this code just checks the value of the WCE bit
484507c3241Smlf 	 * obtained at device init time.  If a mechanism
485507c3241Smlf 	 * is added to the driver to change WCE, dad_wce
486507c3241Smlf 	 * must be updated appropriately.
487507c3241Smlf 	 */
4882df1fe9cSrandyf 	error = dadk_ctl_ioctl(dadkp, DIOCTL_GETWCE,
4894d27faddSmarx 	    (uintptr_t)&wce, FKIOCTL | FNATIVE);
490507c3241Smlf 	mutex_enter(&dadkp->dad_mutex);
491507c3241Smlf 	dadkp->dad_wce = (error != 0) || (wce != 0);
492507c3241Smlf 	mutex_exit(&dadkp->dad_mutex);
493507c3241Smlf 
494507c3241Smlf 	/* logical disk geometry */
4952df1fe9cSrandyf 	(void) dadk_ctl_ioctl(dadkp, DIOCTL_GETGEOM,
4964d27faddSmarx 	    (uintptr_t)&dadkp->dad_logg, FKIOCTL | FNATIVE);
497507c3241Smlf 	if (dadkp->dad_logg.g_cap == 0)
498507c3241Smlf 		return (DDI_FAILURE);
499507c3241Smlf 
500507c3241Smlf 	/* get physical disk geometry */
5012df1fe9cSrandyf 	(void) dadk_ctl_ioctl(dadkp, DIOCTL_GETPHYGEOM,
5024d27faddSmarx 	    (uintptr_t)&dadkp->dad_phyg, FKIOCTL | FNATIVE);
503507c3241Smlf 	if (dadkp->dad_phyg.g_cap == 0)
504507c3241Smlf 		return (DDI_FAILURE);
505507c3241Smlf 
506507c3241Smlf 	dadk_setcap(dadkp);
507507c3241Smlf 
5084d27faddSmarx 	dadk_create_errstats(dadkp,
5094d27faddSmarx 	    ddi_get_instance(CTL_DIP_DEV(dadkp->dad_ctlobjp)));
5104d27faddSmarx 
511507c3241Smlf 	/* start profiling */
512507c3241Smlf 	FLC_START_KSTAT(dadkp->dad_flcobjp, "disk",
513507c3241Smlf 	    ddi_get_instance(CTL_DIP_DEV(dadkp->dad_ctlobjp)));
514507c3241Smlf 
515507c3241Smlf 	return (DDI_SUCCESS);
516507c3241Smlf }
517507c3241Smlf 
518507c3241Smlf static void
519507c3241Smlf dadk_setcap(struct dadk *dadkp)
520507c3241Smlf {
521507c3241Smlf 	int	 totsize;
522507c3241Smlf 	int	 i;
523507c3241Smlf 
524507c3241Smlf 	totsize = dadkp->dad_phyg.g_secsiz;
525507c3241Smlf 
526507c3241Smlf 	if (totsize == 0) {
527507c3241Smlf 		if (dadkp->dad_cdrom) {
528507c3241Smlf 			totsize = 2048;
529507c3241Smlf 		} else {
530507c3241Smlf 			totsize = NBPSCTR;
531507c3241Smlf 		}
532507c3241Smlf 	} else {
533507c3241Smlf 		/* Round down sector size to multiple of 512B */
534507c3241Smlf 		totsize &= ~(NBPSCTR-1);
535507c3241Smlf 	}
536507c3241Smlf 	dadkp->dad_phyg.g_secsiz = totsize;
537507c3241Smlf 
538507c3241Smlf 	/* set sec,block shift factor - (512->0, 1024->1, 2048->2, etc.) */
539507c3241Smlf 	totsize >>= SCTRSHFT;
5402df1fe9cSrandyf 	for (i = 0; totsize != 1; i++, totsize >>= 1)
5412df1fe9cSrandyf 		;
542507c3241Smlf 	dadkp->dad_blkshf = i;
543507c3241Smlf 	dadkp->dad_secshf = i + SCTRSHFT;
544507c3241Smlf }
545507c3241Smlf 
546507c3241Smlf 
5474d27faddSmarx static void
5484d27faddSmarx dadk_create_errstats(struct dadk *dadkp, int instance)
5494d27faddSmarx {
5504d27faddSmarx 	dadk_errstats_t *dep;
5514d27faddSmarx 	char kstatname[KSTAT_STRLEN];
5524d27faddSmarx 	dadk_ioc_string_t dadk_ioc_string;
5534d27faddSmarx 
5544d27faddSmarx 	if (dadkp->dad_errstats)
5554d27faddSmarx 		return;
5564d27faddSmarx 
5574d27faddSmarx 	(void) sprintf(kstatname, "cmdk%d,error", instance);
5584d27faddSmarx 	dadkp->dad_errstats = kstat_create("cmdkerror", instance,
5594d27faddSmarx 	    kstatname, "device_error", KSTAT_TYPE_NAMED,
5604d27faddSmarx 	    sizeof (dadk_errstats_t) / sizeof (kstat_named_t),
5614d27faddSmarx 	    KSTAT_FLAG_PERSISTENT);
5624d27faddSmarx 
5634d27faddSmarx 	if (!dadkp->dad_errstats)
5644d27faddSmarx 		return;
5654d27faddSmarx 
5664d27faddSmarx 	dep = (dadk_errstats_t *)dadkp->dad_errstats->ks_data;
5674d27faddSmarx 
5684d27faddSmarx 	kstat_named_init(&dep->dadk_softerrs,
5694d27faddSmarx 	    "Soft Errors", KSTAT_DATA_UINT32);
5704d27faddSmarx 	kstat_named_init(&dep->dadk_harderrs,
5714d27faddSmarx 	    "Hard Errors", KSTAT_DATA_UINT32);
5724d27faddSmarx 	kstat_named_init(&dep->dadk_transerrs,
5734d27faddSmarx 	    "Transport Errors", KSTAT_DATA_UINT32);
5744d27faddSmarx 	kstat_named_init(&dep->dadk_model,
5754d27faddSmarx 	    "Model", KSTAT_DATA_CHAR);
5764d27faddSmarx 	kstat_named_init(&dep->dadk_revision,
5774d27faddSmarx 	    "Revision", KSTAT_DATA_CHAR);
5784d27faddSmarx 	kstat_named_init(&dep->dadk_serial,
5794d27faddSmarx 	    "Serial No", KSTAT_DATA_CHAR);
5804d27faddSmarx 	kstat_named_init(&dep->dadk_capacity,
5814d27faddSmarx 	    "Size", KSTAT_DATA_ULONGLONG);
5824d27faddSmarx 	kstat_named_init(&dep->dadk_rq_media_err,
5834d27faddSmarx 	    "Media Error", KSTAT_DATA_UINT32);
5844d27faddSmarx 	kstat_named_init(&dep->dadk_rq_ntrdy_err,
5854d27faddSmarx 	    "Device Not Ready", KSTAT_DATA_UINT32);
5864d27faddSmarx 	kstat_named_init(&dep->dadk_rq_nodev_err,
5874d27faddSmarx 	    "No Device", KSTAT_DATA_UINT32);
5884d27faddSmarx 	kstat_named_init(&dep->dadk_rq_recov_err,
5894d27faddSmarx 	    "Recoverable", KSTAT_DATA_UINT32);
5904d27faddSmarx 	kstat_named_init(&dep->dadk_rq_illrq_err,
5914d27faddSmarx 	    "Illegal Request", KSTAT_DATA_UINT32);
5924d27faddSmarx 
5934d27faddSmarx 	dadkp->dad_errstats->ks_private = dep;
5944d27faddSmarx 	dadkp->dad_errstats->ks_update = nulldev;
5954d27faddSmarx 	kstat_install(dadkp->dad_errstats);
5964d27faddSmarx 
5974d27faddSmarx 	/* get model */
5984d27faddSmarx 	dep->dadk_model.value.c[0] = 0;
5994d27faddSmarx 	dadk_ioc_string.is_buf = &dep->dadk_model.value.c[0];
6001a5cb58cSmarx 	dadk_ioc_string.is_size = sizeof (dep->dadk_model.value.c);
6012df1fe9cSrandyf 	(void) dadk_ctl_ioctl(dadkp, DIOCTL_GETMODEL,
6024d27faddSmarx 	    (uintptr_t)&dadk_ioc_string, FKIOCTL | FNATIVE);
6034d27faddSmarx 
6044d27faddSmarx 	/* get serial */
6054d27faddSmarx 	dep->dadk_serial.value.c[0] = 0;
6064d27faddSmarx 	dadk_ioc_string.is_buf = &dep->dadk_serial.value.c[0];
6071a5cb58cSmarx 	dadk_ioc_string.is_size = sizeof (dep->dadk_serial.value.c);
6082df1fe9cSrandyf 	(void) dadk_ctl_ioctl(dadkp, DIOCTL_GETSERIAL,
6094d27faddSmarx 	    (uintptr_t)&dadk_ioc_string, FKIOCTL | FNATIVE);
6104d27faddSmarx 
6114d27faddSmarx 	/* Get revision */
6124d27faddSmarx 	dep->dadk_revision.value.c[0] = 0;
6134d27faddSmarx 
6144d27faddSmarx 	/* Get capacity */
6154d27faddSmarx 
6164d27faddSmarx 	dep->dadk_capacity.value.ui64 =
6174d27faddSmarx 	    (uint64_t)dadkp->dad_logg.g_cap *
6184d27faddSmarx 	    (uint64_t)dadkp->dad_logg.g_secsiz;
6194d27faddSmarx }
6204d27faddSmarx 
6214d27faddSmarx 
622507c3241Smlf int
623507c3241Smlf dadk_close(opaque_t objp)
624507c3241Smlf {
625507c3241Smlf 	struct dadk *dadkp = (struct dadk *)objp;
626507c3241Smlf 
627507c3241Smlf 	if (dadkp->dad_rmb) {
628507c3241Smlf 		(void) dadk_rmb_ioctl(dadkp, DCMD_STOP_MOTOR, 0, 0,
629507c3241Smlf 		    DADK_SILENT);
630507c3241Smlf 		(void) dadk_rmb_ioctl(dadkp, DCMD_UNLOCK, 0, 0, DADK_SILENT);
631507c3241Smlf 	}
632507c3241Smlf 	FLC_STOP_KSTAT(dadkp->dad_flcobjp);
6334d27faddSmarx 
6344d27faddSmarx 	dadk_destroy_errstats(dadkp);
6354d27faddSmarx 
636507c3241Smlf 	return (DDI_SUCCESS);
637507c3241Smlf }
638507c3241Smlf 
6394d27faddSmarx static void
6404d27faddSmarx dadk_destroy_errstats(struct dadk *dadkp)
6414d27faddSmarx {
6424d27faddSmarx 	if (!dadkp->dad_errstats)
6434d27faddSmarx 		return;
6444d27faddSmarx 
6454d27faddSmarx 	kstat_delete(dadkp->dad_errstats);
6464d27faddSmarx 	dadkp->dad_errstats = NULL;
6474d27faddSmarx }
6484d27faddSmarx 
6494d27faddSmarx 
650507c3241Smlf int
651507c3241Smlf dadk_strategy(opaque_t objp, struct buf *bp)
652507c3241Smlf {
653507c3241Smlf 	struct dadk *dadkp = (struct dadk *)objp;
654507c3241Smlf 
655507c3241Smlf 	if (dadkp->dad_rdonly && !(bp->b_flags & B_READ)) {
656507c3241Smlf 		bioerror(bp, EROFS);
657507c3241Smlf 		return (DDI_FAILURE);
658507c3241Smlf 	}
659507c3241Smlf 
660507c3241Smlf 	if (bp->b_bcount & (dadkp->DAD_SECSIZ-1)) {
661507c3241Smlf 		bioerror(bp, ENXIO);
662507c3241Smlf 		return (DDI_FAILURE);
663507c3241Smlf 	}
664507c3241Smlf 
665507c3241Smlf 	SET_BP_SEC(bp, (LBLK2SEC(GET_BP_SEC(bp), dadkp->dad_blkshf)));
6662df1fe9cSrandyf 	mutex_enter(&dadkp->dad_cmd_mutex);
6672df1fe9cSrandyf 	dadkp->dad_cmd_count++;
6682df1fe9cSrandyf 	mutex_exit(&dadkp->dad_cmd_mutex);
669507c3241Smlf 	FLC_ENQUE(dadkp->dad_flcobjp, bp);
670507c3241Smlf 
671507c3241Smlf 	return (DDI_SUCCESS);
672507c3241Smlf }
673507c3241Smlf 
674507c3241Smlf int
675507c3241Smlf dadk_dump(opaque_t objp, struct buf *bp)
676507c3241Smlf {
677507c3241Smlf 	struct dadk *dadkp = (struct dadk *)objp;
678507c3241Smlf 	struct cmpkt *pktp;
679507c3241Smlf 
680507c3241Smlf 	if (dadkp->dad_rdonly) {
681507c3241Smlf 		bioerror(bp, EROFS);
682507c3241Smlf 		return (DDI_FAILURE);
683507c3241Smlf 	}
684507c3241Smlf 
685507c3241Smlf 	if (bp->b_bcount & (dadkp->DAD_SECSIZ-1)) {
686507c3241Smlf 		bioerror(bp, ENXIO);
687507c3241Smlf 		return (DDI_FAILURE);
688507c3241Smlf 	}
689507c3241Smlf 
690507c3241Smlf 	SET_BP_SEC(bp, (LBLK2SEC(GET_BP_SEC(bp), dadkp->dad_blkshf)));
691507c3241Smlf 
692507c3241Smlf 	pktp = dadk_pktprep(dadkp, NULL, bp, dadk_polldone, NULL, NULL);
693507c3241Smlf 	if (!pktp) {
694507c3241Smlf 		cmn_err(CE_WARN, "no resources for dumping");
695507c3241Smlf 		bioerror(bp, EIO);
696507c3241Smlf 		return (DDI_FAILURE);
697507c3241Smlf 	}
698507c3241Smlf 	pktp->cp_flags |= CPF_NOINTR;
699507c3241Smlf 
700507c3241Smlf 	(void) dadk_ioprep(dadkp, pktp);
701507c3241Smlf 	dadk_transport(dadkp, bp);
702507c3241Smlf 	pktp->cp_byteleft -= pktp->cp_bytexfer;
703507c3241Smlf 
704507c3241Smlf 	while (geterror(bp) == 0 && pktp->cp_byteleft != 0) {
705507c3241Smlf 		(void) dadk_iosetup(dadkp, pktp);
706507c3241Smlf 		dadk_transport(dadkp, bp);
707507c3241Smlf 		pktp->cp_byteleft -= pktp->cp_bytexfer;
708507c3241Smlf 	}
709507c3241Smlf 
710507c3241Smlf 	if (pktp->cp_private)
711507c3241Smlf 		BBH_FREEHANDLE(dadkp->dad_bbhobjp, pktp->cp_private);
712507c3241Smlf 	gda_free(dadkp->dad_ctlobjp, pktp, NULL);
713507c3241Smlf 	return (DDI_SUCCESS);
714507c3241Smlf }
715507c3241Smlf 
716507c3241Smlf /* ARGSUSED  */
717507c3241Smlf int
718507c3241Smlf dadk_ioctl(opaque_t objp, dev_t dev, int cmd, intptr_t arg, int flag,
719507c3241Smlf 	cred_t *cred_p, int *rval_p)
720507c3241Smlf {
721507c3241Smlf 	struct dadk *dadkp = (struct dadk *)objp;
722507c3241Smlf 
723507c3241Smlf 	switch (cmd) {
724507c3241Smlf 	case DKIOCGETDEF:
725507c3241Smlf 		{
726507c3241Smlf 		struct buf	*bp;
727507c3241Smlf 		int		err, head;
728507c3241Smlf 		unsigned char	*secbuf;
729507c3241Smlf 		STRUCT_DECL(defect_header, adh);
730507c3241Smlf 
731507c3241Smlf 		STRUCT_INIT(adh, flag & FMODELS);
732507c3241Smlf 
733507c3241Smlf 		/*
734507c3241Smlf 		 * copyin header ....
735507c3241Smlf 		 * yields head number and buffer address
736507c3241Smlf 		 */
737507c3241Smlf 		if (ddi_copyin((caddr_t)arg, STRUCT_BUF(adh), STRUCT_SIZE(adh),
738507c3241Smlf 		    flag))
739507c3241Smlf 			return (EFAULT);
740507c3241Smlf 		head = STRUCT_FGET(adh, head);
741507c3241Smlf 		if (head < 0 || head >= dadkp->dad_phyg.g_head)
742507c3241Smlf 			return (ENXIO);
743507c3241Smlf 		secbuf = kmem_zalloc(NBPSCTR, KM_SLEEP);
744507c3241Smlf 		if (!secbuf)
745507c3241Smlf 			return (ENOMEM);
746507c3241Smlf 		bp = getrbuf(KM_SLEEP);
747507c3241Smlf 		if (!bp) {
748507c3241Smlf 			kmem_free(secbuf, NBPSCTR);
749507c3241Smlf 			return (ENOMEM);
750507c3241Smlf 		}
751507c3241Smlf 
752507c3241Smlf 		bp->b_edev = dev;
753507c3241Smlf 		bp->b_dev  = cmpdev(dev);
754507c3241Smlf 		bp->b_flags = B_BUSY;
755507c3241Smlf 		bp->b_resid = 0;
756507c3241Smlf 		bp->b_bcount = NBPSCTR;
757507c3241Smlf 		bp->b_un.b_addr = (caddr_t)secbuf;
758507c3241Smlf 		bp->b_blkno = head; /* I had to put it somwhere! */
759507c3241Smlf 		bp->b_forw = (struct buf *)dadkp;
760507c3241Smlf 		bp->b_back = (struct buf *)DCMD_GETDEF;
761507c3241Smlf 
7622df1fe9cSrandyf 		mutex_enter(&dadkp->dad_cmd_mutex);
7632df1fe9cSrandyf 		dadkp->dad_cmd_count++;
7642df1fe9cSrandyf 		mutex_exit(&dadkp->dad_cmd_mutex);
765507c3241Smlf 		FLC_ENQUE(dadkp->dad_flcobjp, bp);
766507c3241Smlf 		err = biowait(bp);
767507c3241Smlf 		if (!err) {
768507c3241Smlf 			if (ddi_copyout((caddr_t)secbuf,
769507c3241Smlf 			    STRUCT_FGETP(adh, buffer), NBPSCTR, flag))
770507c3241Smlf 				err = ENXIO;
771507c3241Smlf 		}
772507c3241Smlf 		kmem_free(secbuf, NBPSCTR);
773507c3241Smlf 		freerbuf(bp);
774507c3241Smlf 		return (err);
775507c3241Smlf 		}
776507c3241Smlf 	case DIOCTL_RWCMD:
777507c3241Smlf 		{
778507c3241Smlf 		struct dadkio_rwcmd *rwcmdp;
779507c3241Smlf 		int status, rw;
780507c3241Smlf 
781507c3241Smlf 		/*
782507c3241Smlf 		 * copied in by cmdk and, if necessary, converted to the
783507c3241Smlf 		 * correct datamodel
784507c3241Smlf 		 */
785507c3241Smlf 		rwcmdp = (struct dadkio_rwcmd *)(intptr_t)arg;
786507c3241Smlf 
787507c3241Smlf 		/*
788507c3241Smlf 		 * handle the complex cases here; we pass these
789507c3241Smlf 		 * through to the driver, which will queue them and
790507c3241Smlf 		 * handle the requests asynchronously.  The simpler
791507c3241Smlf 		 * cases ,which can return immediately, fail here, and
792507c3241Smlf 		 * the request reverts to the dadk_ioctl routine, while
793507c3241Smlf 		 *  will reroute them directly to the ata driver.
794507c3241Smlf 		 */
795507c3241Smlf 		switch (rwcmdp->cmd) {
796507c3241Smlf 			case DADKIO_RWCMD_READ :
797507c3241Smlf 				/*FALLTHROUGH*/
798507c3241Smlf 			case DADKIO_RWCMD_WRITE:
799507c3241Smlf 				rw = ((rwcmdp->cmd == DADKIO_RWCMD_WRITE) ?
800507c3241Smlf 				    B_WRITE : B_READ);
801507c3241Smlf 				status = dadk_dk_buf_setup(dadkp,
802507c3241Smlf 				    (opaque_t)rwcmdp, dev, ((flag &FKIOCTL) ?
803507c3241Smlf 				    UIO_SYSSPACE : UIO_USERSPACE), rw);
804507c3241Smlf 				return (status);
805507c3241Smlf 			default:
806507c3241Smlf 				return (EINVAL);
807507c3241Smlf 			}
808507c3241Smlf 		}
8090f2c99a4Syt160523 	case DKIOC_UPDATEFW:
8100f2c99a4Syt160523 
8110f2c99a4Syt160523 		/*
8120f2c99a4Syt160523 		 * Require PRIV_ALL privilege to invoke DKIOC_UPDATEFW
8130f2c99a4Syt160523 		 * to protect the firmware update from malicious use
8140f2c99a4Syt160523 		 */
8150f2c99a4Syt160523 		if (PRIV_POLICY(cred_p, PRIV_ALL, B_FALSE, EPERM, NULL) != 0)
8160f2c99a4Syt160523 			return (EPERM);
8170f2c99a4Syt160523 		else
8182df1fe9cSrandyf 			return (dadk_ctl_ioctl(dadkp, cmd, arg, flag));
8190f2c99a4Syt160523 
820507c3241Smlf 	case DKIOCFLUSHWRITECACHE:
821507c3241Smlf 		{
822507c3241Smlf 			struct buf *bp;
823507c3241Smlf 			int err = 0;
824507c3241Smlf 			struct dk_callback *dkc = (struct dk_callback *)arg;
825507c3241Smlf 			struct cmpkt *pktp;
826507c3241Smlf 			int is_sync = 1;
827507c3241Smlf 
828507c3241Smlf 			mutex_enter(&dadkp->dad_mutex);
829507c3241Smlf 			if (dadkp->dad_noflush || !  dadkp->dad_wce) {
830507c3241Smlf 				err = dadkp->dad_noflush ? ENOTSUP : 0;
831507c3241Smlf 				mutex_exit(&dadkp->dad_mutex);
832507c3241Smlf 				/*
833507c3241Smlf 				 * If a callback was requested: a
834507c3241Smlf 				 * callback will always be done if the
835507c3241Smlf 				 * caller saw the DKIOCFLUSHWRITECACHE
836507c3241Smlf 				 * ioctl return 0, and never done if the
837507c3241Smlf 				 * caller saw the ioctl return an error.
838507c3241Smlf 				 */
839507c3241Smlf 				if ((flag & FKIOCTL) && dkc != NULL &&
840507c3241Smlf 				    dkc->dkc_callback != NULL) {
841507c3241Smlf 					(*dkc->dkc_callback)(dkc->dkc_cookie,
842507c3241Smlf 					    err);
843507c3241Smlf 					/*
844507c3241Smlf 					 * Did callback and reported error.
845507c3241Smlf 					 * Since we did a callback, ioctl
846507c3241Smlf 					 * should return 0.
847507c3241Smlf 					 */
848507c3241Smlf 					err = 0;
849507c3241Smlf 				}
850507c3241Smlf 				return (err);
851507c3241Smlf 			}
852507c3241Smlf 			mutex_exit(&dadkp->dad_mutex);
853507c3241Smlf 
854507c3241Smlf 			bp = getrbuf(KM_SLEEP);
855507c3241Smlf 
856507c3241Smlf 			bp->b_edev = dev;
857507c3241Smlf 			bp->b_dev  = cmpdev(dev);
858507c3241Smlf 			bp->b_flags = B_BUSY;
859507c3241Smlf 			bp->b_resid = 0;
860507c3241Smlf 			bp->b_bcount = 0;
861507c3241Smlf 			SET_BP_SEC(bp, 0);
862507c3241Smlf 
863507c3241Smlf 			if ((flag & FKIOCTL) && dkc != NULL &&
864507c3241Smlf 			    dkc->dkc_callback != NULL) {
865507c3241Smlf 				struct dk_callback *dkc2 =
866507c3241Smlf 				    (struct dk_callback *)kmem_zalloc(
867507c3241Smlf 				    sizeof (struct dk_callback), KM_SLEEP);
868507c3241Smlf 
869507c3241Smlf 				bcopy(dkc, dkc2, sizeof (*dkc2));
870744947dcSTom Erickson 				bp->b_private = dkc2;
871507c3241Smlf 				bp->b_iodone = dadk_flushdone;
872507c3241Smlf 				is_sync = 0;
873507c3241Smlf 			}
874507c3241Smlf 
875507c3241Smlf 			/*
876507c3241Smlf 			 * Setup command pkt
877507c3241Smlf 			 * dadk_pktprep() can't fail since DDI_DMA_SLEEP set
878507c3241Smlf 			 */
879507c3241Smlf 			pktp = dadk_pktprep(dadkp, NULL, bp,
880507c3241Smlf 			    dadk_iodone, DDI_DMA_SLEEP, NULL);
881507c3241Smlf 
882507c3241Smlf 			pktp->cp_time = DADK_FLUSH_CACHE_TIME;
883507c3241Smlf 
884507c3241Smlf 			*((char *)(pktp->cp_cdbp)) = DCMD_FLUSH_CACHE;
885507c3241Smlf 			pktp->cp_byteleft = 0;
886507c3241Smlf 			pktp->cp_private = NULL;
887507c3241Smlf 			pktp->cp_secleft = 0;
888507c3241Smlf 			pktp->cp_srtsec = -1;
889507c3241Smlf 			pktp->cp_bytexfer = 0;
890507c3241Smlf 
891507c3241Smlf 			CTL_IOSETUP(dadkp->dad_ctlobjp, pktp);
892507c3241Smlf 
8932df1fe9cSrandyf 			mutex_enter(&dadkp->dad_cmd_mutex);
8942df1fe9cSrandyf 			dadkp->dad_cmd_count++;
8952df1fe9cSrandyf 			mutex_exit(&dadkp->dad_cmd_mutex);
896507c3241Smlf 			FLC_ENQUE(dadkp->dad_flcobjp, bp);
897507c3241Smlf 
898507c3241Smlf 			if (is_sync) {
899507c3241Smlf 				err = biowait(bp);
900507c3241Smlf 				freerbuf(bp);
901507c3241Smlf 			}
902507c3241Smlf 			return (err);
903507c3241Smlf 		}
904507c3241Smlf 	default:
905507c3241Smlf 		if (!dadkp->dad_rmb)
9062df1fe9cSrandyf 			return (dadk_ctl_ioctl(dadkp, cmd, arg, flag));
907507c3241Smlf 	}
908507c3241Smlf 
909507c3241Smlf 	switch (cmd) {
910507c3241Smlf 	case CDROMSTOP:
911507c3241Smlf 		return (dadk_rmb_ioctl(dadkp, DCMD_STOP_MOTOR, 0,
912507c3241Smlf 		    0, DADK_SILENT));
913507c3241Smlf 	case CDROMSTART:
914507c3241Smlf 		return (dadk_rmb_ioctl(dadkp, DCMD_START_MOTOR, 0,
915507c3241Smlf 		    0, DADK_SILENT));
916507c3241Smlf 	case DKIOCLOCK:
917507c3241Smlf 		return (dadk_rmb_ioctl(dadkp, DCMD_LOCK, 0, 0, DADK_SILENT));
918507c3241Smlf 	case DKIOCUNLOCK:
919507c3241Smlf 		return (dadk_rmb_ioctl(dadkp, DCMD_UNLOCK, 0, 0, DADK_SILENT));
920507c3241Smlf 	case DKIOCEJECT:
921507c3241Smlf 	case CDROMEJECT:
922507c3241Smlf 		{
923507c3241Smlf 			int ret;
924507c3241Smlf 
925507c3241Smlf 			if (ret = dadk_rmb_ioctl(dadkp, DCMD_UNLOCK, 0, 0,
926507c3241Smlf 			    DADK_SILENT)) {
927507c3241Smlf 				return (ret);
928507c3241Smlf 			}
929507c3241Smlf 			if (ret = dadk_rmb_ioctl(dadkp, DCMD_EJECT, 0, 0,
930507c3241Smlf 			    DADK_SILENT)) {
931507c3241Smlf 				return (ret);
932507c3241Smlf 			}
933507c3241Smlf 			mutex_enter(&dadkp->dad_mutex);
934507c3241Smlf 			dadkp->dad_iostate = DKIO_EJECTED;
935507c3241Smlf 			cv_broadcast(&dadkp->dad_state_cv);
936507c3241Smlf 			mutex_exit(&dadkp->dad_mutex);
937507c3241Smlf 
938507c3241Smlf 			return (0);
939507c3241Smlf 
940507c3241Smlf 		}
941507c3241Smlf 	default:
942507c3241Smlf 		return (ENOTTY);
943507c3241Smlf 	/*
944507c3241Smlf 	 * cdrom audio commands
945507c3241Smlf 	 */
946507c3241Smlf 	case CDROMPAUSE:
947507c3241Smlf 		cmd = DCMD_PAUSE;
948507c3241Smlf 		break;
949507c3241Smlf 	case CDROMRESUME:
950507c3241Smlf 		cmd = DCMD_RESUME;
951507c3241Smlf 		break;
952507c3241Smlf 	case CDROMPLAYMSF:
953507c3241Smlf 		cmd = DCMD_PLAYMSF;
954507c3241Smlf 		break;
955507c3241Smlf 	case CDROMPLAYTRKIND:
956507c3241Smlf 		cmd = DCMD_PLAYTRKIND;
957507c3241Smlf 		break;
958507c3241Smlf 	case CDROMREADTOCHDR:
959507c3241Smlf 		cmd = DCMD_READTOCHDR;
960507c3241Smlf 		break;
961507c3241Smlf 	case CDROMREADTOCENTRY:
962507c3241Smlf 		cmd = DCMD_READTOCENT;
963507c3241Smlf 		break;
964507c3241Smlf 	case CDROMVOLCTRL:
965507c3241Smlf 		cmd = DCMD_VOLCTRL;
966507c3241Smlf 		break;
967507c3241Smlf 	case CDROMSUBCHNL:
968507c3241Smlf 		cmd = DCMD_SUBCHNL;
969507c3241Smlf 		break;
970507c3241Smlf 	case CDROMREADMODE2:
971507c3241Smlf 		cmd = DCMD_READMODE2;
972507c3241Smlf 		break;
973507c3241Smlf 	case CDROMREADMODE1:
974507c3241Smlf 		cmd = DCMD_READMODE1;
975507c3241Smlf 		break;
976507c3241Smlf 	case CDROMREADOFFSET:
977507c3241Smlf 		cmd = DCMD_READOFFSET;
978507c3241Smlf 		break;
979507c3241Smlf 	}
980507c3241Smlf 	return (dadk_rmb_ioctl(dadkp, cmd, arg, flag, 0));
981507c3241Smlf }
982507c3241Smlf 
983507c3241Smlf int
984507c3241Smlf dadk_flushdone(struct buf *bp)
985507c3241Smlf {
986744947dcSTom Erickson 	struct dk_callback *dkc = bp->b_private;
987507c3241Smlf 
988507c3241Smlf 	ASSERT(dkc != NULL && dkc->dkc_callback != NULL);
989507c3241Smlf 
990507c3241Smlf 	(*dkc->dkc_callback)(dkc->dkc_cookie, geterror(bp));
991507c3241Smlf 
992507c3241Smlf 	kmem_free(dkc, sizeof (*dkc));
993507c3241Smlf 	freerbuf(bp);
994507c3241Smlf 	return (0);
995507c3241Smlf }
996507c3241Smlf 
997507c3241Smlf int
998507c3241Smlf dadk_getphygeom(opaque_t objp, struct tgdk_geom *dkgeom_p)
999507c3241Smlf {
1000507c3241Smlf 	struct dadk *dadkp = (struct dadk *)objp;
1001507c3241Smlf 
1002507c3241Smlf 	bcopy((caddr_t)&dadkp->dad_phyg, (caddr_t)dkgeom_p,
1003507c3241Smlf 	    sizeof (struct tgdk_geom));
1004507c3241Smlf 	return (DDI_SUCCESS);
1005507c3241Smlf }
1006507c3241Smlf 
1007507c3241Smlf int
1008507c3241Smlf dadk_getgeom(opaque_t objp, struct tgdk_geom *dkgeom_p)
1009507c3241Smlf {
1010507c3241Smlf 	struct dadk *dadkp = (struct dadk *)objp;
1011507c3241Smlf 	bcopy((caddr_t)&dadkp->dad_logg, (caddr_t)dkgeom_p,
1012507c3241Smlf 	    sizeof (struct tgdk_geom));
1013507c3241Smlf 	return (DDI_SUCCESS);
1014507c3241Smlf }
1015507c3241Smlf 
1016507c3241Smlf int
1017507c3241Smlf dadk_setgeom(opaque_t objp, struct tgdk_geom *dkgeom_p)
1018507c3241Smlf {
1019507c3241Smlf 	struct dadk *dadkp = (struct dadk *)objp;
1020507c3241Smlf 
1021507c3241Smlf 	dadkp->dad_logg.g_cyl = dkgeom_p->g_cyl;
1022507c3241Smlf 	dadkp->dad_logg.g_head = dkgeom_p->g_head;
1023507c3241Smlf 	dadkp->dad_logg.g_sec = dkgeom_p->g_sec;
1024507c3241Smlf 	dadkp->dad_logg.g_cap = dkgeom_p->g_cap;
1025507c3241Smlf 	return (DDI_SUCCESS);
1026507c3241Smlf }
1027507c3241Smlf 
1028507c3241Smlf 
1029507c3241Smlf tgdk_iob_handle
1030507c3241Smlf dadk_iob_alloc(opaque_t objp, daddr_t blkno, ssize_t xfer, int kmsflg)
1031507c3241Smlf {
1032507c3241Smlf 	struct dadk *dadkp = (struct dadk *)objp;
1033507c3241Smlf 	struct buf *bp;
1034507c3241Smlf 	struct tgdk_iob *iobp;
1035507c3241Smlf 	size_t rlen;
1036507c3241Smlf 
1037507c3241Smlf 	iobp = kmem_zalloc(sizeof (*iobp), kmsflg);
1038507c3241Smlf 	if (iobp == NULL)
1039507c3241Smlf 		return (NULL);
1040507c3241Smlf 	if ((bp = getrbuf(kmsflg)) == NULL) {
1041507c3241Smlf 		kmem_free(iobp, sizeof (*iobp));
1042507c3241Smlf 		return (NULL);
1043507c3241Smlf 	}
1044507c3241Smlf 
1045507c3241Smlf 	iobp->b_psec  = LBLK2SEC(blkno, dadkp->dad_blkshf);
1046507c3241Smlf 	iobp->b_pbyteoff = (blkno & ((1<<dadkp->dad_blkshf) - 1)) << SCTRSHFT;
1047507c3241Smlf 	iobp->b_pbytecnt = ((iobp->b_pbyteoff + xfer + dadkp->DAD_SECSIZ - 1)
1048507c3241Smlf 	    >> dadkp->dad_secshf) << dadkp->dad_secshf;
1049507c3241Smlf 
1050507c3241Smlf 	bp->b_un.b_addr = 0;
1051507c3241Smlf 	/*
1052507c3241Smlf 	 * use i_ddi_mem_alloc() for now until we have an interface to allocate
1053*b89e420aSGarrett D'Amore 	 * memory for DMA which doesn't require a DMA handle.
1054507c3241Smlf 	 */
1055507c3241Smlf 	if (i_ddi_mem_alloc((dadkp->dad_sd)->sd_dev, &dadk_alloc_attr,
1056507c3241Smlf 	    (size_t)iobp->b_pbytecnt, ((kmsflg == KM_SLEEP) ? 1 : 0), 0, NULL,
1057507c3241Smlf 	    &bp->b_un.b_addr, &rlen, NULL) != DDI_SUCCESS) {
1058507c3241Smlf 		freerbuf(bp);
1059507c3241Smlf 		kmem_free(iobp, sizeof (*iobp));
1060507c3241Smlf 		return (NULL);
1061507c3241Smlf 	}
1062507c3241Smlf 	iobp->b_flag |= IOB_BPALLOC | IOB_BPBUFALLOC;
1063507c3241Smlf 	iobp->b_bp = bp;
1064507c3241Smlf 	iobp->b_lblk = blkno;
1065507c3241Smlf 	iobp->b_xfer = xfer;
1066507c3241Smlf 	iobp->b_lblk = blkno;
1067507c3241Smlf 	iobp->b_xfer = xfer;
1068507c3241Smlf 	return (iobp);
1069507c3241Smlf }
1070507c3241Smlf 
1071507c3241Smlf /* ARGSUSED */
1072507c3241Smlf int
1073507c3241Smlf dadk_iob_free(opaque_t objp, struct tgdk_iob *iobp)
1074507c3241Smlf {
1075507c3241Smlf 	struct buf *bp;
1076507c3241Smlf 
1077507c3241Smlf 	if (iobp) {
1078507c3241Smlf 		if (iobp->b_bp && (iobp->b_flag & IOB_BPALLOC)) {
1079507c3241Smlf 			bp = iobp->b_bp;
1080507c3241Smlf 			if (bp->b_un.b_addr && (iobp->b_flag & IOB_BPBUFALLOC))
10817b93957cSeota 				i_ddi_mem_free((caddr_t)bp->b_un.b_addr, NULL);
1082507c3241Smlf 			freerbuf(bp);
1083507c3241Smlf 		}
1084507c3241Smlf 		kmem_free(iobp, sizeof (*iobp));
1085507c3241Smlf 	}
1086507c3241Smlf 	return (DDI_SUCCESS);
1087507c3241Smlf }
1088507c3241Smlf 
1089507c3241Smlf /* ARGSUSED */
1090507c3241Smlf caddr_t
1091507c3241Smlf dadk_iob_htoc(opaque_t objp, struct tgdk_iob *iobp)
1092507c3241Smlf {
1093507c3241Smlf 	return (iobp->b_bp->b_un.b_addr+iobp->b_pbyteoff);
1094507c3241Smlf }
1095507c3241Smlf 
1096507c3241Smlf 
1097507c3241Smlf caddr_t
1098507c3241Smlf dadk_iob_xfer(opaque_t objp, struct tgdk_iob *iobp, int rw)
1099507c3241Smlf {
1100507c3241Smlf 	struct dadk	*dadkp = (struct dadk *)objp;
1101507c3241Smlf 	struct buf	*bp;
1102507c3241Smlf 	int		err;
1103507c3241Smlf 
1104507c3241Smlf 	bp = iobp->b_bp;
1105507c3241Smlf 	if (dadkp->dad_rdonly && !(rw & B_READ)) {
1106507c3241Smlf 		bioerror(bp, EROFS);
1107507c3241Smlf 		return (NULL);
1108507c3241Smlf 	}
1109507c3241Smlf 
1110507c3241Smlf 	bp->b_flags |= (B_BUSY | rw);
1111507c3241Smlf 	bp->b_bcount = iobp->b_pbytecnt;
1112507c3241Smlf 	SET_BP_SEC(bp, iobp->b_psec);
1113507c3241Smlf 	bp->av_back = (struct buf *)0;
1114507c3241Smlf 	bp->b_resid = 0;
1115507c3241Smlf 
1116507c3241Smlf 	/* call flow control */
11172df1fe9cSrandyf 	mutex_enter(&dadkp->dad_cmd_mutex);
11182df1fe9cSrandyf 	dadkp->dad_cmd_count++;
11192df1fe9cSrandyf 	mutex_exit(&dadkp->dad_cmd_mutex);
1120507c3241Smlf 	FLC_ENQUE(dadkp->dad_flcobjp, bp);
1121507c3241Smlf 	err = biowait(bp);
1122507c3241Smlf 
1123507c3241Smlf 	bp->b_bcount = iobp->b_xfer;
1124507c3241Smlf 	bp->b_flags &= ~(B_DONE|B_BUSY);
1125507c3241Smlf 
1126507c3241Smlf 	if (err)
1127507c3241Smlf 		return (NULL);
1128507c3241Smlf 
1129507c3241Smlf 	return (bp->b_un.b_addr+iobp->b_pbyteoff);
1130507c3241Smlf }
1131507c3241Smlf 
1132507c3241Smlf static void
1133507c3241Smlf dadk_transport(opaque_t com_data, struct buf *bp)
1134507c3241Smlf {
1135507c3241Smlf 	struct dadk *dadkp = (struct dadk *)com_data;
1136507c3241Smlf 
1137507c3241Smlf 	if (CTL_TRANSPORT(dadkp->dad_ctlobjp, GDA_BP_PKT(bp)) ==
1138507c3241Smlf 	    CTL_SEND_SUCCESS)
1139507c3241Smlf 		return;
1140507c3241Smlf 	dadk_restart((void*)GDA_BP_PKT(bp));
1141507c3241Smlf }
1142507c3241Smlf 
1143507c3241Smlf static int
1144507c3241Smlf dadk_pkt(opaque_t com_data, struct buf *bp, int (*func)(caddr_t), caddr_t arg)
1145507c3241Smlf {
1146507c3241Smlf 	struct cmpkt *pktp;
1147507c3241Smlf 	struct dadk *dadkp = (struct dadk *)com_data;
1148507c3241Smlf 
1149507c3241Smlf 	if (GDA_BP_PKT(bp))
1150507c3241Smlf 		return (DDI_SUCCESS);
1151507c3241Smlf 
1152507c3241Smlf 	pktp = dadk_pktprep(dadkp, NULL, bp, dadk_iodone, func, arg);
1153507c3241Smlf 	if (!pktp)
1154507c3241Smlf 		return (DDI_FAILURE);
1155507c3241Smlf 
1156507c3241Smlf 	return (dadk_ioprep(dadkp, pktp));
1157507c3241Smlf }
1158507c3241Smlf 
1159507c3241Smlf /*
1160507c3241Smlf  * Read, Write preparation
1161507c3241Smlf  */
1162507c3241Smlf static int
1163507c3241Smlf dadk_ioprep(struct dadk *dadkp, struct cmpkt *pktp)
1164507c3241Smlf {
1165507c3241Smlf 	struct buf *bp;
1166507c3241Smlf 
1167507c3241Smlf 	bp = pktp->cp_bp;
1168507c3241Smlf 	if (bp->b_forw == (struct buf *)dadkp)
1169507c3241Smlf 		*((char *)(pktp->cp_cdbp)) = (char)(intptr_t)bp->b_back;
1170507c3241Smlf 
1171507c3241Smlf 	else if (bp->b_flags & B_READ)
1172507c3241Smlf 		*((char *)(pktp->cp_cdbp)) = DCMD_READ;
1173507c3241Smlf 	else
1174507c3241Smlf 		*((char *)(pktp->cp_cdbp)) = DCMD_WRITE;
1175507c3241Smlf 	pktp->cp_byteleft = bp->b_bcount;
1176507c3241Smlf 
1177507c3241Smlf 	/* setup the bad block list handle */
1178507c3241Smlf 	pktp->cp_private = BBH_GETHANDLE(dadkp->dad_bbhobjp, bp);
1179507c3241Smlf 	return (dadk_iosetup(dadkp, pktp));
1180507c3241Smlf }
1181507c3241Smlf 
1182507c3241Smlf static int
1183507c3241Smlf dadk_iosetup(struct dadk *dadkp, struct cmpkt *pktp)
1184507c3241Smlf {
1185507c3241Smlf 	struct buf	*bp;
1186507c3241Smlf 	bbh_cookie_t	bbhckp;
1187507c3241Smlf 	int		seccnt;
1188507c3241Smlf 
1189507c3241Smlf 	seccnt = pktp->cp_bytexfer >> dadkp->dad_secshf;
1190507c3241Smlf 	pktp->cp_secleft -= seccnt;
1191507c3241Smlf 
1192507c3241Smlf 	if (pktp->cp_secleft) {
1193507c3241Smlf 		pktp->cp_srtsec += seccnt;
1194507c3241Smlf 	} else {
1195507c3241Smlf 		/* get the first cookie from the bad block list */
1196507c3241Smlf 		if (!pktp->cp_private) {
1197507c3241Smlf 			bp = pktp->cp_bp;
1198507c3241Smlf 			pktp->cp_srtsec  = GET_BP_SEC(bp);
1199507c3241Smlf 			pktp->cp_secleft = (bp->b_bcount >> dadkp->dad_secshf);
1200507c3241Smlf 		} else {
1201507c3241Smlf 			bbhckp = BBH_HTOC(dadkp->dad_bbhobjp,
1202507c3241Smlf 			    pktp->cp_private);
1203507c3241Smlf 			pktp->cp_srtsec = BBH_GETCK_SECTOR(dadkp->dad_bbhobjp,
1204507c3241Smlf 			    bbhckp);
1205507c3241Smlf 			pktp->cp_secleft = BBH_GETCK_SECLEN(dadkp->dad_bbhobjp,
1206507c3241Smlf 			    bbhckp);
1207507c3241Smlf 		}
1208507c3241Smlf 	}
1209507c3241Smlf 
1210507c3241Smlf 	pktp->cp_bytexfer = pktp->cp_secleft << dadkp->dad_secshf;
1211507c3241Smlf 
1212507c3241Smlf 	if (CTL_IOSETUP(dadkp->dad_ctlobjp, pktp)) {
1213507c3241Smlf 		return (DDI_SUCCESS);
1214507c3241Smlf 	} else {
1215507c3241Smlf 		return (DDI_FAILURE);
1216507c3241Smlf 	}
1217507c3241Smlf 
1218507c3241Smlf 
1219507c3241Smlf 
1220507c3241Smlf 
1221507c3241Smlf }
1222507c3241Smlf 
1223507c3241Smlf static struct cmpkt *
1224507c3241Smlf dadk_pktprep(struct dadk *dadkp, struct cmpkt *in_pktp, struct buf *bp,
1225507c3241Smlf     void (*cb_func)(struct buf *), int (*func)(caddr_t), caddr_t arg)
1226507c3241Smlf {
1227507c3241Smlf 	struct cmpkt *pktp;
1228507c3241Smlf 
1229507c3241Smlf 	pktp = gda_pktprep(dadkp->dad_ctlobjp, in_pktp, (opaque_t)bp, func,
1230507c3241Smlf 	    arg);
1231507c3241Smlf 
1232507c3241Smlf 	if (pktp) {
1233507c3241Smlf 		pktp->cp_callback = dadk_pktcb;
1234507c3241Smlf 		pktp->cp_time = DADK_IO_TIME;
1235507c3241Smlf 		pktp->cp_flags = 0;
1236507c3241Smlf 		pktp->cp_iodone = cb_func;
1237507c3241Smlf 		pktp->cp_dev_private = (opaque_t)dadkp;
1238507c3241Smlf 
1239507c3241Smlf 	}
1240507c3241Smlf 
1241507c3241Smlf 	return (pktp);
1242507c3241Smlf }
1243507c3241Smlf 
1244507c3241Smlf 
1245507c3241Smlf static void
1246507c3241Smlf dadk_restart(void *vpktp)
1247507c3241Smlf {
1248507c3241Smlf 	struct cmpkt *pktp = (struct cmpkt *)vpktp;
1249507c3241Smlf 
1250507c3241Smlf 	if (dadk_ioretry(pktp, QUE_COMMAND) == JUST_RETURN)
1251507c3241Smlf 		return;
1252507c3241Smlf 	pktp->cp_iodone(pktp->cp_bp);
1253507c3241Smlf }
1254507c3241Smlf 
1255507c3241Smlf static int
1256507c3241Smlf dadk_ioretry(struct cmpkt *pktp, int action)
1257507c3241Smlf {
1258507c3241Smlf 	struct buf *bp;
1259507c3241Smlf 	struct dadk *dadkp = PKT2DADK(pktp);
1260507c3241Smlf 
1261507c3241Smlf 	switch (action) {
1262507c3241Smlf 	case QUE_COMMAND:
1263507c3241Smlf 		if (pktp->cp_retry++ < DADK_RETRY_COUNT) {
1264507c3241Smlf 			CTL_IOSETUP(dadkp->dad_ctlobjp, pktp);
1265507c3241Smlf 			if (CTL_TRANSPORT(dadkp->dad_ctlobjp, pktp) ==
1266507c3241Smlf 			    CTL_SEND_SUCCESS) {
1267507c3241Smlf 				return (JUST_RETURN);
1268507c3241Smlf 			}
1269507c3241Smlf 			gda_log(dadkp->dad_sd->sd_dev, dadk_name,
12702df1fe9cSrandyf 			    CE_WARN, "transport of command fails\n");
1271507c3241Smlf 		} else
1272507c3241Smlf 			gda_log(dadkp->dad_sd->sd_dev,
1273507c3241Smlf 			    dadk_name, CE_WARN,
1274507c3241Smlf 			    "exceeds maximum number of retries\n");
1275507c3241Smlf 		bioerror(pktp->cp_bp, ENXIO);
1276507c3241Smlf 		/*FALLTHROUGH*/
1277507c3241Smlf 	case COMMAND_DONE_ERROR:
1278507c3241Smlf 		bp = pktp->cp_bp;
1279507c3241Smlf 		bp->b_resid += pktp->cp_byteleft - pktp->cp_bytexfer +
1280507c3241Smlf 		    pktp->cp_resid;
1281507c3241Smlf 		if (geterror(bp) == 0) {
1282507c3241Smlf 			if ((*((char *)(pktp->cp_cdbp)) == DCMD_FLUSH_CACHE) &&
1283507c3241Smlf 			    (pktp->cp_dev_private == (opaque_t)dadkp) &&
1284507c3241Smlf 			    ((int)(*(char *)pktp->cp_scbp) == DERR_ABORT)) {
1285507c3241Smlf 				/*
1286507c3241Smlf 				 * Flag "unimplemented" responses for
1287507c3241Smlf 				 * DCMD_FLUSH_CACHE as ENOTSUP
1288507c3241Smlf 				 */
1289507c3241Smlf 				bioerror(bp, ENOTSUP);
1290507c3241Smlf 				mutex_enter(&dadkp->dad_mutex);
1291507c3241Smlf 				dadkp->dad_noflush = 1;
1292507c3241Smlf 				mutex_exit(&dadkp->dad_mutex);
1293507c3241Smlf 			} else {
1294507c3241Smlf 				bioerror(bp, EIO);
1295507c3241Smlf 			}
1296507c3241Smlf 		}
1297507c3241Smlf 		/*FALLTHROUGH*/
1298507c3241Smlf 	case COMMAND_DONE:
1299507c3241Smlf 	default:
1300507c3241Smlf 		return (COMMAND_DONE);
1301507c3241Smlf 	}
1302507c3241Smlf }
1303507c3241Smlf 
1304507c3241Smlf 
1305507c3241Smlf static void
1306507c3241Smlf dadk_pktcb(struct cmpkt *pktp)
1307507c3241Smlf {
1308507c3241Smlf 	int action;
1309507c3241Smlf 	struct dadkio_rwcmd *rwcmdp;
1310507c3241Smlf 
1311507c3241Smlf 	rwcmdp = (struct dadkio_rwcmd *)pktp->cp_passthru;  /* ioctl packet */
1312507c3241Smlf 
1313507c3241Smlf 	if (pktp->cp_reason == CPS_SUCCESS) {
1314507c3241Smlf 		if (rwcmdp && (rwcmdp != (opaque_t)DADK_SILENT))
1315507c3241Smlf 			rwcmdp->status.status = DADKIO_STAT_NO_ERROR;
1316507c3241Smlf 		pktp->cp_iodone(pktp->cp_bp);
1317507c3241Smlf 		return;
1318507c3241Smlf 	}
1319507c3241Smlf 
1320507c3241Smlf 	if (rwcmdp && (rwcmdp != (opaque_t)DADK_SILENT)) {
1321507c3241Smlf 		if (pktp->cp_reason == CPS_CHKERR)
1322507c3241Smlf 			dadk_recorderr(pktp, rwcmdp);
1323507c3241Smlf 		dadk_iodone(pktp->cp_bp);
1324507c3241Smlf 		return;
1325507c3241Smlf 	}
1326507c3241Smlf 
1327507c3241Smlf 	if (pktp->cp_reason == CPS_CHKERR)
1328507c3241Smlf 		action = dadk_chkerr(pktp);
1329507c3241Smlf 	else
1330507c3241Smlf 		action = COMMAND_DONE_ERROR;
1331507c3241Smlf 
1332507c3241Smlf 	if (action == JUST_RETURN)
1333507c3241Smlf 		return;
1334507c3241Smlf 
13351dc8bc23Szk194757 	/*
13361dc8bc23Szk194757 	 * If we are panicking don't retry the command
13371dc8bc23Szk194757 	 * just fail it so we can go down completing all
13381dc8bc23Szk194757 	 * of the buffers.
13391dc8bc23Szk194757 	 */
13401dc8bc23Szk194757 	if (ddi_in_panic() && action == QUE_COMMAND)
13411dc8bc23Szk194757 		action = COMMAND_DONE_ERROR;
13421dc8bc23Szk194757 
1343507c3241Smlf 	if (action != COMMAND_DONE) {
1344507c3241Smlf 		if ((dadk_ioretry(pktp, action)) == JUST_RETURN)
1345507c3241Smlf 			return;
1346507c3241Smlf 	}
1347507c3241Smlf 	pktp->cp_iodone(pktp->cp_bp);
1348507c3241Smlf }
1349507c3241Smlf 
1350507c3241Smlf 
1351507c3241Smlf 
1352507c3241Smlf static struct dadkio_derr dadk_errtab[] = {
1353507c3241Smlf 	{COMMAND_DONE, GDA_INFORMATIONAL},	/*  0 DERR_SUCCESS	*/
1354507c3241Smlf 	{QUE_COMMAND, GDA_FATAL},		/*  1 DERR_AMNF		*/
1355507c3241Smlf 	{QUE_COMMAND, GDA_FATAL},		/*  2 DERR_TKONF	*/
1356507c3241Smlf 	{COMMAND_DONE_ERROR, GDA_INFORMATIONAL}, /* 3 DERR_ABORT	*/
1357507c3241Smlf 	{QUE_COMMAND, GDA_RETRYABLE},		/*  4 DERR_DWF		*/
1358507c3241Smlf 	{QUE_COMMAND, GDA_FATAL},		/*  5 DERR_IDNF		*/
1359507c3241Smlf 	{JUST_RETURN, GDA_INFORMATIONAL},	/*  6 DERR_BUSY		*/
1360507c3241Smlf 	{QUE_COMMAND, GDA_FATAL},		/*  7 DERR_UNC		*/
1361507c3241Smlf 	{QUE_COMMAND, GDA_RETRYABLE},		/*  8 DERR_BBK		*/
1362507c3241Smlf 	{COMMAND_DONE_ERROR, GDA_FATAL},	/*  9 DERR_INVCDB	*/
1363507c3241Smlf 	{COMMAND_DONE_ERROR, GDA_FATAL},	/* 10 DERR_HARD		*/
1364507c3241Smlf 	{COMMAND_DONE_ERROR, GDA_FATAL},	/* 11 DERR_ILI		*/
1365507c3241Smlf 	{COMMAND_DONE_ERROR, GDA_FATAL},	/* 12 DERR_EOM		*/
1366507c3241Smlf 	{COMMAND_DONE, GDA_INFORMATIONAL},	/* 13 DERR_MCR		*/
1367507c3241Smlf 	{COMMAND_DONE, GDA_INFORMATIONAL},	/* 14 DERR_RECOVER	*/
1368507c3241Smlf 	{COMMAND_DONE_ERROR, GDA_FATAL},	/* 15 DERR_NOTREADY	*/
1369507c3241Smlf 	{QUE_COMMAND, GDA_RETRYABLE},		/* 16 DERR_MEDIUM	*/
1370507c3241Smlf 	{COMMAND_DONE_ERROR, GDA_FATAL},	/* 17 DERR_HW		*/
1371507c3241Smlf 	{COMMAND_DONE, GDA_FATAL},		/* 18 DERR_ILL		*/
1372507c3241Smlf 	{COMMAND_DONE, GDA_FATAL},		/* 19 DERR_UNIT_ATTN	*/
1373507c3241Smlf 	{COMMAND_DONE_ERROR, GDA_FATAL},	/* 20 DERR_DATA_PROT	*/
1374507c3241Smlf 	{COMMAND_DONE_ERROR, GDA_FATAL},	/* 21 DERR_MISCOMPARE	*/
1375507c3241Smlf 	{QUE_COMMAND, GDA_RETRYABLE},		/* 22 DERR_ICRC		*/
1376507c3241Smlf 	{COMMAND_DONE_ERROR, GDA_FATAL},	/* 23 DERR_RESV		*/
1377507c3241Smlf };
1378507c3241Smlf 
1379507c3241Smlf static int
1380507c3241Smlf dadk_chkerr(struct cmpkt *pktp)
1381507c3241Smlf {
1382342440ecSPrasad Singamsetty 	daddr_t err_blkno;
13834d27faddSmarx 	struct dadk *dadkp = PKT2DADK(pktp);
13844d27faddSmarx 	dadk_errstats_t *dep;
13854d27faddSmarx 	int scb = *(char *)pktp->cp_scbp;
1386507c3241Smlf 
13874d27faddSmarx 	if (scb == DERR_SUCCESS) {
13884d27faddSmarx 		if (pktp->cp_retry != 0 && dadkp->dad_errstats != NULL) {
13894d27faddSmarx 			dep = (dadk_errstats_t *)
13904d27faddSmarx 			    dadkp->dad_errstats->ks_data;
13914d27faddSmarx 			dep->dadk_rq_recov_err.value.ui32++;
13924d27faddSmarx 		}
1393507c3241Smlf 		return (COMMAND_DONE);
13944d27faddSmarx 	}
1395507c3241Smlf 
1396507c3241Smlf 	if (pktp->cp_retry) {
1397507c3241Smlf 		err_blkno = pktp->cp_srtsec + ((pktp->cp_bytexfer -
1398507c3241Smlf 		    pktp->cp_resid) >> dadkp->dad_secshf);
1399507c3241Smlf 	} else
1400507c3241Smlf 		err_blkno = -1;
1401507c3241Smlf 
14024d27faddSmarx 	if (dadkp->dad_errstats != NULL) {
14034d27faddSmarx 		dep = (dadk_errstats_t *)dadkp->dad_errstats->ks_data;
14044d27faddSmarx 
14051a5cb58cSmarx 		switch (dadk_errtab[scb].d_severity) {
14061a5cb58cSmarx 			case GDA_RETRYABLE:
14074d27faddSmarx 				dep->dadk_softerrs.value.ui32++;
14081a5cb58cSmarx 				break;
14091a5cb58cSmarx 
14101a5cb58cSmarx 			case GDA_FATAL:
14114d27faddSmarx 				dep->dadk_harderrs.value.ui32++;
14121a5cb58cSmarx 				break;
14131a5cb58cSmarx 
14141a5cb58cSmarx 			default:
14151a5cb58cSmarx 				break;
14161a5cb58cSmarx 		}
14174d27faddSmarx 
14184d27faddSmarx 		switch (scb) {
14194d27faddSmarx 			case DERR_INVCDB:
14204d27faddSmarx 			case DERR_ILI:
14214d27faddSmarx 			case DERR_EOM:
14224d27faddSmarx 			case DERR_HW:
14234d27faddSmarx 			case DERR_ICRC:
14244d27faddSmarx 				dep->dadk_transerrs.value.ui32++;
14254d27faddSmarx 				break;
14264d27faddSmarx 
14274d27faddSmarx 			case DERR_AMNF:
14284d27faddSmarx 			case DERR_TKONF:
14294d27faddSmarx 			case DERR_DWF:
14304d27faddSmarx 			case DERR_BBK:
14314d27faddSmarx 			case DERR_UNC:
14324d27faddSmarx 			case DERR_HARD:
14334d27faddSmarx 			case DERR_MEDIUM:
14344d27faddSmarx 			case DERR_DATA_PROT:
14354d27faddSmarx 			case DERR_MISCOMP:
14364d27faddSmarx 				dep->dadk_rq_media_err.value.ui32++;
14374d27faddSmarx 				break;
14384d27faddSmarx 
14394d27faddSmarx 			case DERR_NOTREADY:
14404d27faddSmarx 				dep->dadk_rq_ntrdy_err.value.ui32++;
14414d27faddSmarx 				break;
14424d27faddSmarx 
14434d27faddSmarx 			case DERR_IDNF:
14444d27faddSmarx 			case DERR_UNIT_ATTN:
14454d27faddSmarx 				dep->dadk_rq_nodev_err.value.ui32++;
14464d27faddSmarx 				break;
14474d27faddSmarx 
14484d27faddSmarx 			case DERR_ILL:
14494d27faddSmarx 			case DERR_RESV:
14504d27faddSmarx 				dep->dadk_rq_illrq_err.value.ui32++;
14514d27faddSmarx 				break;
14524d27faddSmarx 
14534d27faddSmarx 			default:
14544d27faddSmarx 				break;
14554d27faddSmarx 		}
14564d27faddSmarx 	}
14574d27faddSmarx 
1458507c3241Smlf 	/* if attempting to read a sector from a cdrom audio disk */
1459507c3241Smlf 	if ((dadkp->dad_cdrom) &&
1460507c3241Smlf 	    (*((char *)(pktp->cp_cdbp)) == DCMD_READ) &&
1461507c3241Smlf 	    (scb == DERR_ILL)) {
1462507c3241Smlf 		return (COMMAND_DONE);
1463507c3241Smlf 	}
1464507c3241Smlf 	if (pktp->cp_passthru == NULL) {
1465507c3241Smlf 		gda_errmsg(dadkp->dad_sd, pktp, dadk_name,
1466507c3241Smlf 		    dadk_errtab[scb].d_severity, pktp->cp_srtsec,
1467507c3241Smlf 		    err_blkno, dadk_cmds, dadk_sense);
1468507c3241Smlf 	}
1469507c3241Smlf 
1470507c3241Smlf 	if (scb == DERR_BUSY) {
1471507c3241Smlf 		(void) timeout(dadk_restart, (void *)pktp, DADK_BSY_TIMEOUT);
1472507c3241Smlf 	}
1473507c3241Smlf 
14741a5cb58cSmarx 	return (dadk_errtab[scb].d_action);
1475507c3241Smlf }
1476507c3241Smlf 
1477507c3241Smlf static void
1478507c3241Smlf dadk_recorderr(struct cmpkt *pktp, struct dadkio_rwcmd *rwcmdp)
1479507c3241Smlf {
1480507c3241Smlf 	struct dadk *dadkp;
1481507c3241Smlf 	int scb;
1482507c3241Smlf 
1483507c3241Smlf 	dadkp = PKT2DADK(pktp);
1484507c3241Smlf 	scb = (int)(*(char *)pktp->cp_scbp);
1485507c3241Smlf 
1486507c3241Smlf 
1487507c3241Smlf 	rwcmdp->status.failed_blk = rwcmdp->blkaddr +
14882df1fe9cSrandyf 	    ((pktp->cp_bytexfer - pktp->cp_resid) >> dadkp->dad_secshf);
1489507c3241Smlf 
1490507c3241Smlf 	rwcmdp->status.resid = pktp->cp_bp->b_resid +
1491507c3241Smlf 	    pktp->cp_byteleft - pktp->cp_bytexfer + pktp->cp_resid;
1492507c3241Smlf 	switch ((int)(* (char *)pktp->cp_scbp)) {
1493507c3241Smlf 	case DERR_AMNF:
1494507c3241Smlf 	case DERR_ABORT:
1495507c3241Smlf 		rwcmdp->status.status = DADKIO_STAT_ILLEGAL_REQUEST;
1496507c3241Smlf 		break;
1497507c3241Smlf 	case DERR_DWF:
1498507c3241Smlf 	case DERR_IDNF:
1499507c3241Smlf 		rwcmdp->status.status = DADKIO_STAT_ILLEGAL_ADDRESS;
1500507c3241Smlf 		break;
1501507c3241Smlf 	case DERR_TKONF:
1502507c3241Smlf 	case DERR_UNC:
1503507c3241Smlf 	case DERR_BBK:
1504507c3241Smlf 		rwcmdp->status.status = DADKIO_STAT_MEDIUM_ERROR;
1505507c3241Smlf 		rwcmdp->status.failed_blk_is_valid = 1;
1506507c3241Smlf 		rwcmdp->status.resid = 0;
1507507c3241Smlf 		break;
1508507c3241Smlf 	case DERR_BUSY:
1509507c3241Smlf 		rwcmdp->status.status = DADKIO_STAT_NOT_READY;
1510507c3241Smlf 		break;
1511507c3241Smlf 	case DERR_INVCDB:
1512507c3241Smlf 	case DERR_HARD:
1513507c3241Smlf 		rwcmdp->status.status = DADKIO_STAT_HARDWARE_ERROR;
1514507c3241Smlf 		break;
1515507c3241Smlf 	case DERR_ICRC:
1516507c3241Smlf 	default:
1517507c3241Smlf 		rwcmdp->status.status = DADKIO_STAT_NOT_SUPPORTED;
1518507c3241Smlf 	}
1519507c3241Smlf 
1520507c3241Smlf 	if (rwcmdp->flags & DADKIO_FLAG_SILENT)
1521507c3241Smlf 		return;
1522507c3241Smlf 	gda_errmsg(dadkp->dad_sd, pktp, dadk_name, dadk_errtab[scb].d_severity,
1523507c3241Smlf 	    rwcmdp->blkaddr, rwcmdp->status.failed_blk,
1524507c3241Smlf 	    dadk_cmds, dadk_sense);
1525507c3241Smlf }
1526507c3241Smlf 
1527507c3241Smlf /*ARGSUSED*/
1528507c3241Smlf static void
1529507c3241Smlf dadk_polldone(struct buf *bp)
1530507c3241Smlf {
15312df1fe9cSrandyf 	struct cmpkt *pktp;
15322df1fe9cSrandyf 	struct dadk *dadkp;
15332df1fe9cSrandyf 
15342df1fe9cSrandyf 	pktp  = GDA_BP_PKT(bp);
15352df1fe9cSrandyf 	dadkp = PKT2DADK(pktp);
15362df1fe9cSrandyf 	mutex_enter(&dadkp->dad_cmd_mutex);
15372df1fe9cSrandyf 	dadkp->dad_cmd_count--;
15382df1fe9cSrandyf 	mutex_exit(&dadkp->dad_cmd_mutex);
1539507c3241Smlf }
1540507c3241Smlf 
1541507c3241Smlf static void
1542507c3241Smlf dadk_iodone(struct buf *bp)
1543507c3241Smlf {
1544507c3241Smlf 	struct cmpkt *pktp;
1545507c3241Smlf 	struct dadk *dadkp;
1546507c3241Smlf 
1547507c3241Smlf 	pktp  = GDA_BP_PKT(bp);
1548507c3241Smlf 	dadkp = PKT2DADK(pktp);
1549507c3241Smlf 
1550507c3241Smlf 	/* check for all iodone */
1551507c3241Smlf 	pktp->cp_byteleft -= pktp->cp_bytexfer;
1552507c3241Smlf 	if (geterror(bp) == 0 && pktp->cp_byteleft != 0) {
1553507c3241Smlf 		pktp->cp_retry = 0;
1554507c3241Smlf 		(void) dadk_iosetup(dadkp, pktp);
1555507c3241Smlf 
1556507c3241Smlf 
1557507c3241Smlf 	/* 	transport the next one */
1558507c3241Smlf 		if (CTL_TRANSPORT(dadkp->dad_ctlobjp, pktp) == CTL_SEND_SUCCESS)
1559507c3241Smlf 			return;
1560507c3241Smlf 		if ((dadk_ioretry(pktp, QUE_COMMAND)) == JUST_RETURN)
1561507c3241Smlf 			return;
1562507c3241Smlf 	}
1563507c3241Smlf 
1564507c3241Smlf 	/* start next one */
1565507c3241Smlf 	FLC_DEQUE(dadkp->dad_flcobjp, bp);
1566507c3241Smlf 
1567507c3241Smlf 	/* free pkt */
1568507c3241Smlf 	if (pktp->cp_private)
1569507c3241Smlf 		BBH_FREEHANDLE(dadkp->dad_bbhobjp, pktp->cp_private);
1570507c3241Smlf 	gda_free(dadkp->dad_ctlobjp, pktp, NULL);
15712df1fe9cSrandyf 	mutex_enter(&dadkp->dad_cmd_mutex);
15722df1fe9cSrandyf 	dadkp->dad_cmd_count--;
15732df1fe9cSrandyf 	mutex_exit(&dadkp->dad_cmd_mutex);
1574507c3241Smlf 	biodone(bp);
1575507c3241Smlf }
1576507c3241Smlf 
1577507c3241Smlf int
1578507c3241Smlf dadk_check_media(opaque_t objp, int *state)
1579507c3241Smlf {
1580507c3241Smlf 	struct dadk *dadkp = (struct dadk *)objp;
1581507c3241Smlf 
1582507c3241Smlf 	if (!dadkp->dad_rmb) {
1583507c3241Smlf 		return (ENXIO);
1584507c3241Smlf 	}
1585507c3241Smlf #ifdef DADK_DEBUG
1586507c3241Smlf 	if (dadk_debug & DSTATE)
1587507c3241Smlf 		PRF("dadk_check_media: user state %x disk state %x\n",
1588507c3241Smlf 		    *state, dadkp->dad_iostate);
1589507c3241Smlf #endif
1590507c3241Smlf 	/*
1591507c3241Smlf 	 * If state already changed just return
1592507c3241Smlf 	 */
1593507c3241Smlf 	if (*state != dadkp->dad_iostate) {
1594507c3241Smlf 		*state = dadkp->dad_iostate;
1595507c3241Smlf 		return (0);
1596507c3241Smlf 	}
1597507c3241Smlf 
1598507c3241Smlf 	/*
1599507c3241Smlf 	 * Startup polling on thread state
1600507c3241Smlf 	 */
1601507c3241Smlf 	mutex_enter(&dadkp->dad_mutex);
1602507c3241Smlf 	if (dadkp->dad_thread_cnt == 0) {
1603507c3241Smlf 		/*
1604507c3241Smlf 		 * One thread per removable dadk device
1605507c3241Smlf 		 */
1606507c3241Smlf 		(void) thread_create(NULL, 0, dadk_watch_thread, dadkp, 0, &p0,
1607507c3241Smlf 		    TS_RUN, v.v_maxsyspri - 2);
1608507c3241Smlf 	}
1609507c3241Smlf 	dadkp->dad_thread_cnt++;
1610507c3241Smlf 
1611507c3241Smlf 	/*
1612507c3241Smlf 	 * Wait for state to change
1613507c3241Smlf 	 */
1614507c3241Smlf 	do {
1615507c3241Smlf 		if (cv_wait_sig(&dadkp->dad_state_cv, &dadkp->dad_mutex) == 0) {
1616507c3241Smlf 			dadkp->dad_thread_cnt--;
1617507c3241Smlf 			mutex_exit(&dadkp->dad_mutex);
1618507c3241Smlf 			return (EINTR);
1619507c3241Smlf 		}
1620507c3241Smlf 	} while (*state == dadkp->dad_iostate);
1621507c3241Smlf 	*state = dadkp->dad_iostate;
1622507c3241Smlf 	dadkp->dad_thread_cnt--;
1623507c3241Smlf 	mutex_exit(&dadkp->dad_mutex);
1624507c3241Smlf 	return (0);
1625507c3241Smlf }
1626507c3241Smlf 
1627507c3241Smlf 
1628507c3241Smlf #define	MEDIA_ACCESS_DELAY 2000000
1629507c3241Smlf 
1630507c3241Smlf static void
1631507c3241Smlf dadk_watch_thread(struct dadk *dadkp)
1632507c3241Smlf {
1633507c3241Smlf 	enum dkio_state state;
1634507c3241Smlf 	int interval;
1635507c3241Smlf 
1636507c3241Smlf 	interval = drv_usectohz(dadk_check_media_time);
1637507c3241Smlf 
1638507c3241Smlf 	do {
1639507c3241Smlf 		if (dadk_rmb_ioctl(dadkp, DCMD_GET_STATE, (intptr_t)&state, 0,
1640507c3241Smlf 		    DADK_SILENT)) {
1641507c3241Smlf 			/*
1642507c3241Smlf 			 * Assume state remained the same
1643507c3241Smlf 			 */
1644507c3241Smlf 			state = dadkp->dad_iostate;
1645507c3241Smlf 		}
1646507c3241Smlf 
1647507c3241Smlf 		/*
1648507c3241Smlf 		 * now signal the waiting thread if this is *not* the
1649507c3241Smlf 		 * specified state;
1650507c3241Smlf 		 * delay the signal if the state is DKIO_INSERTED
1651507c3241Smlf 		 * to allow the target to recover
1652507c3241Smlf 		 */
1653507c3241Smlf 		if (state != dadkp->dad_iostate) {
1654507c3241Smlf 
1655507c3241Smlf 			dadkp->dad_iostate = state;
1656507c3241Smlf 			if (state == DKIO_INSERTED) {
1657507c3241Smlf 				/*
1658507c3241Smlf 				 * delay the signal to give the drive a chance
1659507c3241Smlf 				 * to do what it apparently needs to do
1660507c3241Smlf 				 */
1661507c3241Smlf 				(void) timeout((void(*)(void *))cv_broadcast,
1662507c3241Smlf 				    (void *)&dadkp->dad_state_cv,
1663507c3241Smlf 				    drv_usectohz((clock_t)MEDIA_ACCESS_DELAY));
1664507c3241Smlf 			} else {
1665507c3241Smlf 				cv_broadcast(&dadkp->dad_state_cv);
1666507c3241Smlf 			}
1667507c3241Smlf 		}
1668507c3241Smlf 		delay(interval);
1669507c3241Smlf 	} while (dadkp->dad_thread_cnt);
1670507c3241Smlf }
1671507c3241Smlf 
1672507c3241Smlf int
1673507c3241Smlf dadk_inquiry(opaque_t objp, opaque_t *inqpp)
1674507c3241Smlf {
1675507c3241Smlf 	struct dadk *dadkp = (struct dadk *)objp;
1676507c3241Smlf 	struct scsi_inquiry **sinqpp = (struct scsi_inquiry **)inqpp;
1677507c3241Smlf 
1678507c3241Smlf 	if (dadkp && dadkp->dad_sd && dadkp->dad_sd->sd_inq) {
1679507c3241Smlf 		*sinqpp = dadkp->dad_sd->sd_inq;
1680507c3241Smlf 		return (DDI_SUCCESS);
1681507c3241Smlf 	}
1682507c3241Smlf 
1683507c3241Smlf 	return (DDI_FAILURE);
1684507c3241Smlf }
1685507c3241Smlf 
1686507c3241Smlf static int
1687507c3241Smlf dadk_rmb_ioctl(struct dadk *dadkp, int cmd, intptr_t arg, int flags, int silent)
1688507c3241Smlf 
1689507c3241Smlf {
1690507c3241Smlf 	struct buf *bp;
1691507c3241Smlf 	int err;
1692507c3241Smlf 	struct cmpkt *pktp;
1693507c3241Smlf 
1694507c3241Smlf 	if ((bp = getrbuf(KM_SLEEP)) == NULL) {
1695507c3241Smlf 		return (ENOMEM);
1696507c3241Smlf 	}
1697507c3241Smlf 	pktp = dadk_pktprep(dadkp, NULL, bp, dadk_rmb_iodone, NULL, NULL);
1698507c3241Smlf 	if (!pktp) {
1699507c3241Smlf 		freerbuf(bp);
1700507c3241Smlf 		return (ENOMEM);
1701507c3241Smlf 	}
1702507c3241Smlf 	bp->b_back  = (struct buf *)arg;
1703507c3241Smlf 	bp->b_forw  = (struct buf *)dadkp->dad_flcobjp;
1704507c3241Smlf 	pktp->cp_passthru = (opaque_t)(intptr_t)silent;
1705507c3241Smlf 
17062df1fe9cSrandyf 	err = dadk_ctl_ioctl(dadkp, cmd, (uintptr_t)pktp, flags);
1707507c3241Smlf 	freerbuf(bp);
1708507c3241Smlf 	gda_free(dadkp->dad_ctlobjp, pktp, NULL);
1709507c3241Smlf 	return (err);
1710507c3241Smlf 
1711507c3241Smlf 
1712507c3241Smlf }
1713507c3241Smlf 
1714507c3241Smlf static void
1715507c3241Smlf dadk_rmb_iodone(struct buf *bp)
1716507c3241Smlf {
1717507c3241Smlf 	struct cmpkt *pktp;
1718507c3241Smlf 	struct dadk *dadkp;
1719507c3241Smlf 
1720507c3241Smlf 	pktp  = GDA_BP_PKT(bp);
1721507c3241Smlf 	dadkp = PKT2DADK(pktp);
1722507c3241Smlf 
1723507c3241Smlf 	bp->b_flags &= ~(B_DONE|B_BUSY);
1724507c3241Smlf 
1725507c3241Smlf 	/* Start next one */
1726507c3241Smlf 	FLC_DEQUE(dadkp->dad_flcobjp, bp);
1727507c3241Smlf 
17282df1fe9cSrandyf 	mutex_enter(&dadkp->dad_cmd_mutex);
17292df1fe9cSrandyf 	dadkp->dad_cmd_count--;
17302df1fe9cSrandyf 	mutex_exit(&dadkp->dad_cmd_mutex);
1731507c3241Smlf 	biodone(bp);
1732507c3241Smlf }
1733507c3241Smlf 
1734507c3241Smlf static int
1735507c3241Smlf dadk_dk_buf_setup(struct dadk *dadkp, opaque_t *cmdp, dev_t dev,
1736507c3241Smlf 	enum uio_seg dataspace, int rw)
1737507c3241Smlf {
1738507c3241Smlf 	struct dadkio_rwcmd *rwcmdp = (struct dadkio_rwcmd *)cmdp;
1739507c3241Smlf 	struct buf	*bp;
1740507c3241Smlf 	struct iovec	aiov;
1741507c3241Smlf 	struct uio	auio;
1742507c3241Smlf 	struct uio	*uio = &auio;
1743507c3241Smlf 	int		status;
1744507c3241Smlf 
1745507c3241Smlf 	bp = getrbuf(KM_SLEEP);
1746507c3241Smlf 
1747507c3241Smlf 	bp->av_forw = bp->b_forw = (struct buf *)dadkp;
1748507c3241Smlf 	bp->b_back  = (struct buf *)rwcmdp;	/* ioctl packet */
1749507c3241Smlf 
1750507c3241Smlf 	bzero((caddr_t)&auio, sizeof (struct uio));
1751507c3241Smlf 	bzero((caddr_t)&aiov, sizeof (struct iovec));
1752507c3241Smlf 	aiov.iov_base = rwcmdp->bufaddr;
1753507c3241Smlf 	aiov.iov_len = rwcmdp->buflen;
1754507c3241Smlf 	uio->uio_iov = &aiov;
1755507c3241Smlf 
1756507c3241Smlf 	uio->uio_iovcnt = 1;
1757507c3241Smlf 	uio->uio_resid = rwcmdp->buflen;
1758507c3241Smlf 	uio->uio_segflg = dataspace;
1759507c3241Smlf 
1760507c3241Smlf 	/* Let physio do the rest... */
1761507c3241Smlf 	status = physio(dadk_dk_strategy, bp, dev, rw, dadkmin, uio);
1762507c3241Smlf 
1763507c3241Smlf 	freerbuf(bp);
1764507c3241Smlf 	return (status);
1765507c3241Smlf 
1766507c3241Smlf }
1767507c3241Smlf 
1768507c3241Smlf /* Do not let a user gendisk request get too big or */
1769507c3241Smlf /* else we could use to many resources.		    */
1770507c3241Smlf 
1771507c3241Smlf static void
1772507c3241Smlf dadkmin(struct buf *bp)
1773507c3241Smlf {
1774507c3241Smlf 	if (bp->b_bcount > dadk_dk_maxphys)
1775507c3241Smlf 		bp->b_bcount = dadk_dk_maxphys;
1776507c3241Smlf }
1777507c3241Smlf 
1778507c3241Smlf static int
1779507c3241Smlf dadk_dk_strategy(struct buf *bp)
1780507c3241Smlf {
1781507c3241Smlf 	dadk_dk((struct dadk *)bp->av_forw, (struct dadkio_rwcmd *)bp->b_back,
1782507c3241Smlf 	    bp);
1783507c3241Smlf 	return (0);
1784507c3241Smlf }
1785507c3241Smlf 
1786507c3241Smlf static void
1787507c3241Smlf dadk_dk(struct dadk *dadkp, struct dadkio_rwcmd *rwcmdp, struct buf *bp)
1788507c3241Smlf {
1789507c3241Smlf 	struct  cmpkt *pktp;
1790507c3241Smlf 
1791507c3241Smlf 	pktp = dadk_pktprep(dadkp, NULL, bp, dadk_iodone, NULL, NULL);
1792507c3241Smlf 	if (!pktp) {
1793507c3241Smlf 		bioerror(bp, ENOMEM);
1794507c3241Smlf 		biodone(bp);
1795507c3241Smlf 		return;
1796507c3241Smlf 	}
1797507c3241Smlf 
1798507c3241Smlf 	pktp->cp_passthru = rwcmdp;
1799507c3241Smlf 
1800507c3241Smlf 	(void) dadk_ioprep(dadkp, pktp);
1801507c3241Smlf 
18022df1fe9cSrandyf 	mutex_enter(&dadkp->dad_cmd_mutex);
18032df1fe9cSrandyf 	dadkp->dad_cmd_count++;
18042df1fe9cSrandyf 	mutex_exit(&dadkp->dad_cmd_mutex);
1805507c3241Smlf 	FLC_ENQUE(dadkp->dad_flcobjp, bp);
1806507c3241Smlf }
18072df1fe9cSrandyf 
18082df1fe9cSrandyf /*
18092df1fe9cSrandyf  * There is no existing way to notify cmdk module
18102df1fe9cSrandyf  * when the command completed, so add this function
18112df1fe9cSrandyf  * to calculate how many on-going commands.
18122df1fe9cSrandyf  */
18132df1fe9cSrandyf int
18142df1fe9cSrandyf dadk_getcmds(opaque_t objp)
18152df1fe9cSrandyf {
18162df1fe9cSrandyf 	struct dadk *dadkp = (struct dadk *)objp;
18172df1fe9cSrandyf 	int count;
18182df1fe9cSrandyf 
18192df1fe9cSrandyf 	mutex_enter(&dadkp->dad_cmd_mutex);
18202df1fe9cSrandyf 	count = dadkp->dad_cmd_count;
18212df1fe9cSrandyf 	mutex_exit(&dadkp->dad_cmd_mutex);
18222df1fe9cSrandyf 	return (count);
18232df1fe9cSrandyf }
18242df1fe9cSrandyf 
18252df1fe9cSrandyf /*
18262df1fe9cSrandyf  * this function was used to calc the cmd for CTL_IOCTL
18272df1fe9cSrandyf  */
18282df1fe9cSrandyf static int
18292df1fe9cSrandyf dadk_ctl_ioctl(struct dadk *dadkp, uint32_t cmd, uintptr_t arg, int flag)
18302df1fe9cSrandyf {
18312df1fe9cSrandyf 	int error;
18322df1fe9cSrandyf 	mutex_enter(&dadkp->dad_cmd_mutex);
18332df1fe9cSrandyf 	dadkp->dad_cmd_count++;
18342df1fe9cSrandyf 	mutex_exit(&dadkp->dad_cmd_mutex);
18352df1fe9cSrandyf 	error = CTL_IOCTL(dadkp->dad_ctlobjp, cmd, arg, flag);
18362df1fe9cSrandyf 	mutex_enter(&dadkp->dad_cmd_mutex);
18372df1fe9cSrandyf 	dadkp->dad_cmd_count--;
18382df1fe9cSrandyf 	mutex_exit(&dadkp->dad_cmd_mutex);
18392df1fe9cSrandyf 	return (error);
18402df1fe9cSrandyf }
1841