xref: /illumos-gate/usr/src/uts/common/io/emul64_bsd.c (revision 03831d35)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * pseudo scsi disk driver
31  */
32 
33 #include <sys/scsi/scsi.h>
34 #include <sys/ddi.h>
35 #include <sys/sunddi.h>
36 #include <sys/kmem.h>
37 #include <sys/taskq.h>
38 #include <sys/disp.h>
39 #include <sys/types.h>
40 #include <sys/buf.h>
41 
42 #include <sys/emul64.h>
43 #include <sys/emul64cmd.h>
44 #include <sys/emul64var.h>
45 
46 /*
47  * Mode sense/select page control
48  */
49 #define	MODE_SENSE_PC_CURRENT		0
50 #define	MODE_SENSE_PC_CHANGEABLE	1
51 #define	MODE_SENSE_PC_DEFAULT		2
52 #define	MODE_SENSE_PC_SAVED		3
53 
54 /*
55  * Byte conversion macros
56  */
57 #if	defined(_BIG_ENDIAN)
58 #define	ushort_to_scsi_ushort(n)	(n)
59 #define	uint32_to_scsi_uint32(n)	(n)
60 #define	uint64_to_scsi_uint64(n)	(n)
61 #elif	defined(_LITTLE_ENDIAN)
62 
63 #define	ushort_to_scsi_ushort(n)			\
64 		((((n) & 0x00ff) << 8) |		\
65 		(((n)  & 0xff00) >> 8))
66 
67 #define	uint32_to_scsi_uint32(n)			\
68 		((((n) & 0x000000ff) << 24) |		\
69 		(((n)  & 0x0000ff00) << 8) |		\
70 		(((n)  & 0x00ff0000) >> 8) |		\
71 		(((n)  & 0xff000000) >> 24))
72 #define	uint64_to_scsi_uint64(n)				\
73 		((((n) & 0x00000000000000ff) << 56) |           \
74 		(((n)  & 0x000000000000ff00) << 40) |           \
75 		(((n)  & 0x0000000000ff0000) << 24) |           \
76 		(((n)  & 0x00000000ff000000) << 8) |            \
77 		(((n)  & 0x000000ff00000000) >> 8) |            \
78 		(((n)  & 0x0000ff0000000000) >> 24) |           \
79 		(((n)  & 0x00ff000000000000) >> 40) |           \
80 		(((n)  & 0xff00000000000000) >> 56))
81 #else
82 error no _BIG_ENDIAN or _LITTLE_ENDIAN
83 #endif
84 #define	uint_to_byte0(n)		((n) & 0xff)
85 #define	uint_to_byte1(n)		(((n)>>8) & 0xff)
86 #define	uint_to_byte2(n)		(((n)>>16) & 0xff)
87 #define	uint_to_byte3(n)		(((n)>>24) & 0xff)
88 
89 /*
90  * struct prop_map
91  *
92  * This structure maps a property name to the place to store its value.
93  */
94 struct prop_map {
95 	char 		*pm_name;	/* Name of the property. */
96 	int		*pm_value;	/* Place to store the value. */
97 };
98 
99 static int emul64_debug_blklist = 0;
100 
101 /*
102  * Some interesting statistics.  These are protected by the
103  * emul64_stats_mutex.  It would be nice to have an ioctl to print them out,
104  * but we don't have the development time for that now.  You can at least
105  * look at them with adb.
106  */
107 
108 int		emul64_collect_stats = 1; /* Collect stats if non-zero */
109 kmutex_t	emul64_stats_mutex;	/* Protect these variables */
110 long		emul64_nowrite_count = 0; /* # active nowrite ranges */
111 static uint64_t	emul64_skipped_io = 0;	/* Skipped I/O operations, because of */
112 					/* EMUL64_WRITE_OFF. */
113 static uint64_t	emul64_skipped_blk = 0;	/* Skipped blocks because of */
114 					/* EMUL64_WRITE_OFF. */
115 static uint64_t	emul64_io_ops = 0;	/* Total number of I/O operations */
116 					/* including skipped and actual. */
117 static uint64_t	emul64_io_blocks = 0;	/* Total number of blocks involved */
118 					/* in I/O operations. */
119 static uint64_t	emul64_nonzero = 0;	/* Number of non-zero data blocks */
120 					/* currently held in memory */
121 static uint64_t	emul64_max_list_length = 0; /* Maximum size of a linked */
122 					    /* list of non-zero blocks. */
123 uint64_t emul64_taskq_max = 0;		/* emul64_scsi_start uses the taskq */
124 					/* mechanism to dispatch work. */
125 					/* If the number of entries in the */
126 					/* exceeds the maximum for the queue */
127 					/* the queue a 1 second delay is */
128 					/* encountered in taskq_ent_alloc. */
129 					/* This counter counts the number */
130 					/* times that this happens. */
131 
132 /*
133  * Since emul64 does no physical I/O, operations that would normally be I/O
134  * intensive become CPU bound.  An example of this is RAID 5
135  * initialization.  When the kernel becomes CPU bound, it looks as if the
136  * machine is hung.
137  *
138  * To avoid this problem, we provide a function, emul64_yield_check, that does a
139  * delay from time to time to yield up the CPU.  The following variables
140  * are tunables for this algorithm.
141  *
142  *	emul64_num_delay_called	Number of times we called delay.  This is
143  *				not really a tunable.  Rather it is a
144  *				counter that provides useful information
145  *				for adjusting the tunables.
146  *	emul64_yield_length	Number of microseconds to yield the CPU.
147  *	emul64_yield_period	Number of I/O operations between yields.
148  *	emul64_yield_enable	emul64 will yield the CPU, only if this
149  *				variable contains a non-zero value.  This
150  *				allows the yield functionality to be turned
151  *				off for experimentation purposes.
152  *
153  * The value of 1000 for emul64_yield_period has been determined by
154  * experience with running the tests.
155  */
156 static uint64_t		emul64_num_delay_called = 0;
157 static int		emul64_yield_length = 1000;
158 static int		emul64_yield_period = 1000;
159 static int		emul64_yield_enable = 1;
160 static kmutex_t		emul64_yield_mutex;
161 static kcondvar_t 	emul64_yield_cv;
162 
163 /*
164  * This array establishes a set of tunable variables that can be set by
165  * defining properties in the emul64.conf file.
166  */
167 struct prop_map emul64_properties[] = {
168 	"emul64_collect_stats",		&emul64_collect_stats,
169 	"emul64_yield_length",		&emul64_yield_length,
170 	"emul64_yield_period",		&emul64_yield_period,
171 	"emul64_yield_enable",		&emul64_yield_enable,
172 	"emul64_max_task",		&emul64_max_task,
173 	"emul64_task_nthreads",		&emul64_task_nthreads
174 };
175 
176 static unsigned char *emul64_zeros = NULL; /* Block of 0s for comparison */
177 
178 extern void emul64_check_cond(struct scsi_pkt *pkt, uchar_t key,
179 				uchar_t asc, uchar_t ascq);
180 /* ncyl=250000 acyl=2 nhead=24 nsect=357 */
181 uint_t dkg_rpm = 3600;
182 
183 static int bsd_mode_sense_dad_mode_geometry(struct scsi_pkt *);
184 static int bsd_mode_sense_dad_mode_err_recov(struct scsi_pkt *);
185 static int bsd_mode_sense_modepage_disco_reco(struct scsi_pkt *);
186 static int bsd_mode_sense_dad_mode_format(struct scsi_pkt *);
187 static int bsd_mode_sense_dad_mode_cache(struct scsi_pkt *);
188 static int bsd_readblks(struct emul64 *, ushort_t, ushort_t, diskaddr_t,
189 				int, unsigned char *);
190 static int bsd_writeblks(struct emul64 *, ushort_t, ushort_t, diskaddr_t,
191 				int, unsigned char *);
192 emul64_tgt_t *find_tgt(struct emul64 *, ushort_t, ushort_t);
193 static blklist_t *bsd_findblk(emul64_tgt_t *, diskaddr_t, avl_index_t *);
194 static void bsd_allocblk(emul64_tgt_t *, diskaddr_t, caddr_t, avl_index_t);
195 static void bsd_freeblk(emul64_tgt_t *, blklist_t *);
196 static void emul64_yield_check();
197 static emul64_rng_overlap_t bsd_tgt_overlap(emul64_tgt_t *, diskaddr_t, int);
198 
199 char *emul64_name = "emul64";
200 
201 
202 /* XXX replace with FORMG0COUNT */
203 #define	GETG0COUNT(cdb)		((cdb)->g0_count0)
204 
205 #define	GETG1COUNT(cdb)		((cdb)->g1_count1 << 8)  + \
206 				((cdb)->g1_count0)
207 
208 #define	GETG4COUNT(cdb)	\
209 			((uint64_t)(cdb)->g4_count3 << 24)  + \
210 			((uint64_t)(cdb)->g4_count2 << 16)  + \
211 			((uint64_t)(cdb)->g4_count1 << 8)  + \
212 			((uint64_t)(cdb)->g4_count0)
213 
214 
215 /*
216  * Initialize globals in this file.
217  */
218 void
219 emul64_bsd_init()
220 {
221 	emul64_zeros = (unsigned char *) kmem_zalloc(DEV_BSIZE, KM_SLEEP);
222 	mutex_init(&emul64_stats_mutex, NULL, MUTEX_DRIVER, NULL);
223 	mutex_init(&emul64_yield_mutex, NULL, MUTEX_DRIVER, NULL);
224 	cv_init(&emul64_yield_cv, NULL, CV_DRIVER, NULL);
225 }
226 
227 /*
228  * Clean up globals in this file.
229  */
230 void
231 emul64_bsd_fini()
232 {
233 	cv_destroy(&emul64_yield_cv);
234 	mutex_destroy(&emul64_yield_mutex);
235 	mutex_destroy(&emul64_stats_mutex);
236 	if (emul64_zeros != NULL) {
237 		kmem_free(emul64_zeros, DEV_BSIZE);
238 		emul64_zeros = NULL;
239 	}
240 }
241 
242 /*
243  * Attempt to get the values of the properties that are specified in the
244  * emul64_properties array.  If the property exists, copy its value to the
245  * specified location.  All the properties have been assigned default
246  * values in this driver, so if we cannot get the property that is not a
247  * problem.
248  */
249 void
250 emul64_bsd_get_props(dev_info_t *dip)
251 {
252 	uint_t		count;
253 	uint_t		i;
254 	struct prop_map	*pmp;
255 	int		*properties;
256 
257 	for (pmp = emul64_properties, i = 0;
258 		i < sizeof (emul64_properties) / sizeof (struct prop_map);
259 		i++, pmp++) {
260 		if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
261 				DDI_PROP_DONTPASS,
262 				pmp->pm_name, &properties,
263 				&count) == DDI_PROP_SUCCESS) {
264 			if (count >= 1) {
265 				*pmp->pm_value = *properties;
266 			}
267 			ddi_prop_free((void *) properties);
268 		}
269 	}
270 }
271 
272 int
273 emul64_bsd_blkcompare(const void *a1, const void *b1)
274 {
275 	blklist_t	*a = (blklist_t *)a1;
276 	blklist_t	*b = (blklist_t *)b1;
277 
278 	if (a->bl_blkno < b->bl_blkno)
279 		return (-1);
280 	if (a->bl_blkno == b->bl_blkno)
281 		return (0);
282 	return (1);
283 }
284 
285 /* ARGSUSED 0 */
286 int
287 bsd_scsi_start_stop_unit(struct scsi_pkt *pkt)
288 {
289 	return (0);
290 }
291 
292 /* ARGSUSED 0 */
293 int
294 bsd_scsi_test_unit_ready(struct scsi_pkt *pkt)
295 {
296 	return (0);
297 }
298 
299 /* ARGSUSED 0 */
300 int
301 bsd_scsi_request_sense(struct scsi_pkt *pkt)
302 {
303 	return (0);
304 }
305 
306 int
307 bsd_scsi_inq_page0(struct scsi_pkt *pkt, uchar_t pqdtype)
308 {
309 	struct emul64_cmd	*sp = PKT2CMD(pkt);
310 
311 	if (sp->cmd_count < 6) {
312 		cmn_err(CE_CONT, "%s: bsd_scsi_inq_page0: size %d required\n",
313 		    emul64_name, 6);
314 		return (EIO);
315 	}
316 
317 	sp->cmd_addr[0] = pqdtype;	/* periph qual., dtype */
318 	sp->cmd_addr[1] = 0;		/* page code */
319 	sp->cmd_addr[2] = 0;		/* reserved */
320 	sp->cmd_addr[3] = 6 - 3;	/* length */
321 	sp->cmd_addr[4] = 0;		/* 1st page */
322 	sp->cmd_addr[5] = 0x83;		/* 2nd page */
323 
324 	pkt->pkt_resid = sp->cmd_count - 6;
325 	return (0);
326 }
327 
328 int
329 bsd_scsi_inq_page83(struct scsi_pkt *pkt, uchar_t pqdtype)
330 {
331 	struct emul64		*emul64 = PKT2EMUL64(pkt);
332 	struct emul64_cmd	*sp = PKT2CMD(pkt);
333 	int			instance = ddi_get_instance(emul64->emul64_dip);
334 
335 	if (sp->cmd_count < 22) {
336 		cmn_err(CE_CONT, "%s: bsd_scsi_inq_page83: size %d required\n",
337 		    emul64_name, 22);
338 		return (EIO);
339 	}
340 
341 	sp->cmd_addr[0] = pqdtype;	/* periph qual., dtype */
342 	sp->cmd_addr[1] = 0x83;		/* page code */
343 	sp->cmd_addr[2] = 0;		/* reserved */
344 	sp->cmd_addr[3] = (22 - 8) + 4;	/* length */
345 
346 	sp->cmd_addr[4] = 1;		/* code set - binary */
347 	sp->cmd_addr[5] = 3;		/* association and device ID type 3 */
348 	sp->cmd_addr[6] = 0;		/* reserved */
349 	sp->cmd_addr[7] = 22 - 8;	/* ID length */
350 
351 	sp->cmd_addr[8] = 0xde;		/* @8: identifier, byte 0 */
352 	sp->cmd_addr[9] = 0xca;
353 	sp->cmd_addr[10] = 0xde;
354 	sp->cmd_addr[11] = 0x80;
355 
356 	sp->cmd_addr[12] = 0xba;
357 	sp->cmd_addr[13] = 0xbe;
358 	sp->cmd_addr[14] = 0xab;
359 	sp->cmd_addr[15] = 0xba;
360 					/* @22: */
361 
362 	/*
363 	 * Instances seem to be assigned sequentially, so it unlikely that we
364 	 * will have more than 65535 of them.
365 	 */
366 	sp->cmd_addr[16] = uint_to_byte1(instance);
367 	sp->cmd_addr[17] = uint_to_byte0(instance);
368 	sp->cmd_addr[18] = uint_to_byte1(TGT(sp));
369 	sp->cmd_addr[19] = uint_to_byte0(TGT(sp));
370 	sp->cmd_addr[20] = uint_to_byte1(LUN(sp));
371 	sp->cmd_addr[21] = uint_to_byte0(LUN(sp));
372 
373 	pkt->pkt_resid = sp->cmd_count - 22;
374 	return (0);
375 }
376 
377 int
378 bsd_scsi_inquiry(struct scsi_pkt *pkt)
379 {
380 	struct emul64_cmd	*sp = PKT2CMD(pkt);
381 	union scsi_cdb		*cdb = (union scsi_cdb *)pkt->pkt_cdbp;
382 	emul64_tgt_t		*tgt;
383 	uchar_t			pqdtype;
384 	struct scsi_inquiry	inq;
385 
386 	EMUL64_MUTEX_ENTER(sp->cmd_emul64);
387 	tgt = find_tgt(sp->cmd_emul64,
388 	    pkt->pkt_address.a_target, pkt->pkt_address.a_lun);
389 	EMUL64_MUTEX_EXIT(sp->cmd_emul64);
390 
391 	if (sp->cmd_count < sizeof (inq)) {
392 		cmn_err(CE_CONT, "%s: bsd_scsi_inquiry: size %d required\n",
393 		    emul64_name, (int)sizeof (inq));
394 		return (EIO);
395 	}
396 
397 	if (cdb->cdb_opaque[1] & 0xfc) {
398 		cmn_err(CE_WARN, "%s: bsd_scsi_inquiry: 0x%x",
399 		    emul64_name, cdb->cdb_opaque[1]);
400 		emul64_check_cond(pkt, 0x5, 0x24, 0x0);	/* inv. fld in cdb */
401 		return (0);
402 	}
403 
404 	pqdtype = tgt->emul64_tgt_dtype;
405 	if (cdb->cdb_opaque[1] & 0x1) {
406 		switch (cdb->cdb_opaque[2]) {
407 			case 0x00:
408 				return (bsd_scsi_inq_page0(pkt, pqdtype));
409 			case 0x83:
410 				return (bsd_scsi_inq_page83(pkt, pqdtype));
411 			default:
412 				cmn_err(CE_WARN, "%s: bsd_scsi_inquiry: "
413 				    "unsupported 0x%x",
414 				    emul64_name, cdb->cdb_opaque[2]);
415 				return (0);
416 		}
417 	}
418 
419 	/* set up the inquiry data we return */
420 	(void) bzero((void *)&inq, sizeof (inq));
421 
422 	inq.inq_dtype = pqdtype;
423 	inq.inq_ansi = 2;
424 	inq.inq_rdf = 2;
425 	inq.inq_len = sizeof (inq) - 4;
426 	inq.inq_wbus16 = 1;
427 	inq.inq_cmdque = 1;
428 
429 	(void) bcopy(tgt->emul64_tgt_inq, inq.inq_vid,
430 	    sizeof (tgt->emul64_tgt_inq));
431 	(void) bcopy("1", inq.inq_revision, 2);
432 	(void) bcopy((void *)&inq, sp->cmd_addr, sizeof (inq));
433 
434 	pkt->pkt_resid = sp->cmd_count - sizeof (inq);
435 	return (0);
436 }
437 
438 /* ARGSUSED 0 */
439 int
440 bsd_scsi_format(struct scsi_pkt *pkt)
441 {
442 	return (0);
443 }
444 
445 int
446 bsd_scsi_io(struct scsi_pkt *pkt)
447 {
448 	struct emul64_cmd	*sp = PKT2CMD(pkt);
449 	union scsi_cdb		*cdb = (union scsi_cdb *)pkt->pkt_cdbp;
450 	diskaddr_t		lblkno;
451 	int			nblks;
452 
453 	switch (cdb->scc_cmd) {
454 	case SCMD_READ:
455 			lblkno = (uint32_t)GETG0ADDR(cdb);
456 			nblks = GETG0COUNT(cdb);
457 			pkt->pkt_resid = bsd_readblks(sp->cmd_emul64,
458 					pkt->pkt_address.a_target,
459 					pkt->pkt_address.a_lun,
460 					lblkno, nblks, sp->cmd_addr);
461 			if (emul64debug) {
462 				cmn_err(CE_CONT, "%s: bsd_scsi_io: "
463 				    "read g0 blk=%lld (0x%llx) nblks=%d\n",
464 				    emul64_name, lblkno, lblkno, nblks);
465 			}
466 		break;
467 	case SCMD_WRITE:
468 			lblkno = (uint32_t)GETG0ADDR(cdb);
469 			nblks = GETG0COUNT(cdb);
470 			pkt->pkt_resid = bsd_writeblks(sp->cmd_emul64,
471 					pkt->pkt_address.a_target,
472 					pkt->pkt_address.a_lun,
473 					lblkno, nblks, sp->cmd_addr);
474 			if (emul64debug) {
475 				cmn_err(CE_CONT, "%s: bsd_scsi_io: "
476 				    "write g0 blk=%lld (0x%llx) nblks=%d\n",
477 				    emul64_name, lblkno, lblkno, nblks);
478 			}
479 		break;
480 	case SCMD_READ_G1:
481 			lblkno = (uint32_t)GETG1ADDR(cdb);
482 			nblks = GETG1COUNT(cdb);
483 			pkt->pkt_resid = bsd_readblks(sp->cmd_emul64,
484 					pkt->pkt_address.a_target,
485 					pkt->pkt_address.a_lun,
486 					lblkno, nblks, sp->cmd_addr);
487 			if (emul64debug) {
488 				cmn_err(CE_CONT, "%s: bsd_scsi_io: "
489 				    "read g1 blk=%lld (0x%llx) nblks=%d\n",
490 				    emul64_name, lblkno, lblkno, nblks);
491 			}
492 		break;
493 	case SCMD_WRITE_G1:
494 			lblkno = (uint32_t)GETG1ADDR(cdb);
495 			nblks = GETG1COUNT(cdb);
496 			pkt->pkt_resid = bsd_writeblks(sp->cmd_emul64,
497 					pkt->pkt_address.a_target,
498 					pkt->pkt_address.a_lun,
499 					lblkno, nblks, sp->cmd_addr);
500 			if (emul64debug) {
501 				cmn_err(CE_CONT, "%s: bsd_scsi_io: "
502 				    "write g1 blk=%lld (0x%llx) nblks=%d\n",
503 				    emul64_name, lblkno, lblkno, nblks);
504 			}
505 		break;
506 	case SCMD_READ_G4:
507 			lblkno = GETG4ADDR(cdb);
508 			lblkno <<= 32;
509 			lblkno |= (uint32_t)GETG4ADDRTL(cdb);
510 			nblks = GETG4COUNT(cdb);
511 			pkt->pkt_resid = bsd_readblks(sp->cmd_emul64,
512 					pkt->pkt_address.a_target,
513 					pkt->pkt_address.a_lun,
514 					lblkno, nblks, sp->cmd_addr);
515 			if (emul64debug) {
516 				cmn_err(CE_CONT, "%s: bsd_scsi_io: "
517 				    "read g4 blk=%lld (0x%llx) nblks=%d\n",
518 				    emul64_name, lblkno, lblkno, nblks);
519 			}
520 		break;
521 	case SCMD_WRITE_G4:
522 			lblkno = GETG4ADDR(cdb);
523 			lblkno <<= 32;
524 			lblkno |= (uint32_t)GETG4ADDRTL(cdb);
525 			nblks = GETG4COUNT(cdb);
526 			pkt->pkt_resid = bsd_writeblks(sp->cmd_emul64,
527 					pkt->pkt_address.a_target,
528 					pkt->pkt_address.a_lun,
529 					lblkno, nblks, sp->cmd_addr);
530 			if (emul64debug) {
531 				cmn_err(CE_CONT, "%s: bsd_scsi_io: "
532 				    "write g4 blk=%lld (0x%llx) nblks=%d\n",
533 				    emul64_name, lblkno, lblkno, nblks);
534 			}
535 		break;
536 	default:
537 		cmn_err(CE_WARN, "%s: bsd_scsi_io: unhandled I/O: 0x%x",
538 		    emul64_name, cdb->scc_cmd);
539 		break;
540 	}
541 
542 	if (pkt->pkt_resid != 0)
543 		cmn_err(CE_WARN, "%s: bsd_scsi_io: "
544 		    "pkt_resid: 0x%lx, lblkno %lld, nblks %d",
545 		    emul64_name, pkt->pkt_resid, lblkno, nblks);
546 
547 	return (0);
548 }
549 
550 int
551 bsd_scsi_log_sense(struct scsi_pkt *pkt)
552 {
553 	union scsi_cdb		*cdb = (union scsi_cdb *)pkt->pkt_cdbp;
554 	struct emul64_cmd	*sp = PKT2CMD(pkt);
555 	int			page_code;
556 
557 	if (sp->cmd_count < 9) {
558 		cmn_err(CE_CONT, "%s: bsd_scsi_log_sense size %d required\n",
559 		    emul64_name, 9);
560 		return (EIO);
561 	}
562 
563 	page_code = cdb->cdb_opaque[2] & 0x3f;
564 	if (page_code) {
565 		cmn_err(CE_CONT, "%s: bsd_scsi_log_sense: "
566 		    "page 0x%x not supported\n", emul64_name, page_code);
567 		emul64_check_cond(pkt, 0x5, 0x24, 0x0); /* inv. fld in cdb */
568 		return (0);
569 	}
570 
571 	sp->cmd_addr[0] = 0;		/* page code */
572 	sp->cmd_addr[1] = 0;		/* reserved */
573 	sp->cmd_addr[2] = 0;		/* MSB of page length */
574 	sp->cmd_addr[3] = 8 - 3;	/* LSB of page length */
575 
576 	sp->cmd_addr[4] = 0;		/* MSB of parameter code */
577 	sp->cmd_addr[5] = 0;		/* LSB of parameter code */
578 	sp->cmd_addr[6] = 0;		/* parameter control byte */
579 	sp->cmd_addr[7] = 4 - 3;	/* parameter length */
580 	sp->cmd_addr[8] = 0x0;		/* parameter value */
581 
582 	pkt->pkt_resid = sp->cmd_count - 9;
583 	return (0);
584 }
585 
586 int
587 bsd_scsi_mode_sense(struct scsi_pkt *pkt)
588 {
589 	union scsi_cdb	*cdb = (union scsi_cdb *)pkt->pkt_cdbp;
590 	int		page_control;
591 	int		page_code;
592 	int		rval = 0;
593 
594 	switch (cdb->scc_cmd) {
595 	case SCMD_MODE_SENSE:
596 			page_code = cdb->cdb_opaque[2] & 0x3f;
597 			page_control = (cdb->cdb_opaque[2] >> 6) & 0x03;
598 			if (emul64debug) {
599 				cmn_err(CE_CONT, "%s: bsd_scsi_mode_sense: "
600 				    "page=0x%x control=0x%x nbytes=%d\n",
601 				    emul64_name, page_code, page_control,
602 				    GETG0COUNT(cdb));
603 			}
604 		break;
605 	case SCMD_MODE_SENSE_G1:
606 			page_code = cdb->cdb_opaque[2] & 0x3f;
607 			page_control = (cdb->cdb_opaque[2] >> 6) & 0x03;
608 			if (emul64debug) {
609 				cmn_err(CE_CONT, "%s: bsd_scsi_mode_sense: "
610 				    "page=0x%x control=0x%x nbytes=%d\n",
611 				    emul64_name, page_code, page_control,
612 				    GETG1COUNT(cdb));
613 			}
614 		break;
615 	default:
616 		cmn_err(CE_CONT, "%s: bsd_scsi_mode_sense: "
617 		    "cmd 0x%x not supported\n", emul64_name, cdb->scc_cmd);
618 		return (EIO);
619 	}
620 
621 	switch (page_code) {
622 	case DAD_MODE_GEOMETRY:
623 		rval = bsd_mode_sense_dad_mode_geometry(pkt);
624 		break;
625 	case DAD_MODE_ERR_RECOV:
626 		rval = bsd_mode_sense_dad_mode_err_recov(pkt);
627 		break;
628 	case MODEPAGE_DISCO_RECO:
629 		rval = bsd_mode_sense_modepage_disco_reco(pkt);
630 		break;
631 	case DAD_MODE_FORMAT:
632 		rval = bsd_mode_sense_dad_mode_format(pkt);
633 		break;
634 	case DAD_MODE_CACHE:
635 		rval = bsd_mode_sense_dad_mode_cache(pkt);
636 		break;
637 	default:
638 		cmn_err(CE_CONT, "%s: bsd_scsi_mode_sense: "
639 		    "page 0x%x not supported\n", emul64_name, page_code);
640 		rval = EIO;
641 		break;
642 	}
643 
644 	return (rval);
645 }
646 
647 
648 static int
649 bsd_mode_sense_dad_mode_geometry(struct scsi_pkt *pkt)
650 {
651 	struct emul64_cmd	*sp = PKT2CMD(pkt);
652 	union scsi_cdb		*cdb = (union scsi_cdb *)pkt->pkt_cdbp;
653 	uchar_t			*addr = (uchar_t *)sp->cmd_addr;
654 	emul64_tgt_t		*tgt;
655 	int			page_control;
656 	struct mode_header	header;
657 	struct mode_geometry	page4;
658 	int			ncyl;
659 	int			rval = 0;
660 
661 	page_control = (cdb->cdb_opaque[2] >> 6) & 0x03;
662 
663 	if (emul64debug) {
664 		cmn_err(CE_CONT, "%s: bsd_mode_sense_dad_mode_geometry: "
665 		    "pc=%d n=%d\n", emul64_name, page_control, sp->cmd_count);
666 	}
667 
668 	if (sp->cmd_count < (sizeof (header) + sizeof (page4))) {
669 		cmn_err(CE_CONT, "%s: bsd_mode_sense_dad_mode_geometry: "
670 		    "size %d required\n",
671 		    emul64_name, (int)(sizeof (header) + sizeof (page4)));
672 		return (EIO);
673 	}
674 
675 	(void) bzero(&header, sizeof (header));
676 	(void) bzero(&page4, sizeof (page4));
677 
678 	header.length = sizeof (header) + sizeof (page4) - 1;
679 	header.bdesc_length = 0;
680 
681 	page4.mode_page.code = DAD_MODE_GEOMETRY;
682 	page4.mode_page.ps = 1;
683 	page4.mode_page.length = sizeof (page4) - sizeof (struct mode_page);
684 
685 	switch (page_control) {
686 	case MODE_SENSE_PC_CURRENT:
687 	case MODE_SENSE_PC_DEFAULT:
688 	case MODE_SENSE_PC_SAVED:
689 		EMUL64_MUTEX_ENTER(sp->cmd_emul64);
690 		tgt = find_tgt(sp->cmd_emul64,
691 		    pkt->pkt_address.a_target, pkt->pkt_address.a_lun);
692 		EMUL64_MUTEX_EXIT(sp->cmd_emul64);
693 		ncyl = tgt->emul64_tgt_ncyls;
694 		page4.cyl_ub = uint_to_byte2(ncyl);
695 		page4.cyl_mb = uint_to_byte1(ncyl);
696 		page4.cyl_lb = uint_to_byte0(ncyl);
697 		page4.heads = uint_to_byte0(tgt->emul64_tgt_nheads);
698 		page4.rpm = ushort_to_scsi_ushort(dkg_rpm);
699 		break;
700 	case MODE_SENSE_PC_CHANGEABLE:
701 		page4.cyl_ub = 0xff;
702 		page4.cyl_mb = 0xff;
703 		page4.cyl_lb = 0xff;
704 		page4.heads = 0xff;
705 		page4.rpm = 0xffff;
706 		break;
707 	}
708 
709 	(void) bcopy(&header, addr, sizeof (header));
710 	(void) bcopy(&page4, addr + sizeof (header), sizeof (page4));
711 
712 	pkt->pkt_resid = sp->cmd_count - sizeof (page4) - sizeof (header);
713 	rval = 0;
714 
715 	return (rval);
716 }
717 
718 static int
719 bsd_mode_sense_dad_mode_err_recov(struct scsi_pkt *pkt)
720 {
721 	struct emul64_cmd	*sp = PKT2CMD(pkt);
722 	union scsi_cdb		*cdb = (union scsi_cdb *)pkt->pkt_cdbp;
723 	uchar_t			*addr = (uchar_t *)sp->cmd_addr;
724 	int			page_control;
725 	struct mode_header	header;
726 	struct mode_err_recov	page1;
727 	int			rval = 0;
728 
729 	page_control = (cdb->cdb_opaque[2] >> 6) & 0x03;
730 
731 	if (emul64debug) {
732 		cmn_err(CE_CONT, "%s: bsd_mode_sense_dad_mode_err_recov: "
733 		    "pc=%d n=%d\n", emul64_name, page_control, sp->cmd_count);
734 	}
735 
736 	if (sp->cmd_count < (sizeof (header) + sizeof (page1))) {
737 		cmn_err(CE_CONT, "%s: bsd_mode_sense_dad_mode_err_recov: "
738 		    "size %d required\n",
739 		    emul64_name, (int)(sizeof (header) + sizeof (page1)));
740 		return (EIO);
741 	}
742 
743 	(void) bzero(&header, sizeof (header));
744 	(void) bzero(&page1, sizeof (page1));
745 
746 	header.length = sizeof (header) + sizeof (page1) - 1;
747 	header.bdesc_length = 0;
748 
749 	page1.mode_page.code = DAD_MODE_ERR_RECOV;
750 	page1.mode_page.ps = 1;
751 	page1.mode_page.length = sizeof (page1) - sizeof (struct mode_page);
752 
753 	switch (page_control) {
754 	case MODE_SENSE_PC_CURRENT:
755 	case MODE_SENSE_PC_DEFAULT:
756 	case MODE_SENSE_PC_SAVED:
757 		break;
758 	case MODE_SENSE_PC_CHANGEABLE:
759 		break;
760 	}
761 
762 	(void) bcopy(&header, addr, sizeof (header));
763 	(void) bcopy(&page1, addr + sizeof (header), sizeof (page1));
764 
765 	pkt->pkt_resid = sp->cmd_count - sizeof (page1) - sizeof (header);
766 	rval = 0;
767 
768 	return (rval);
769 }
770 
771 static int
772 bsd_mode_sense_modepage_disco_reco(struct scsi_pkt *pkt)
773 {
774 	struct emul64_cmd	*sp = PKT2CMD(pkt);
775 	union scsi_cdb		*cdb = (union scsi_cdb *)pkt->pkt_cdbp;
776 	int			rval = 0;
777 	uchar_t			*addr = (uchar_t *)sp->cmd_addr;
778 	int			page_control;
779 	struct mode_header	header;
780 	struct mode_disco_reco	page2;
781 
782 	page_control = (cdb->cdb_opaque[2] >> 6) & 0x03;
783 
784 	if (emul64debug) {
785 		cmn_err(CE_CONT, "%s: bsd_mode_sense_modepage_disco_reco: "
786 		    "pc=%d n=%d\n", emul64_name, page_control, sp->cmd_count);
787 	}
788 
789 	if (sp->cmd_count < (sizeof (header) + sizeof (page2))) {
790 		cmn_err(CE_CONT, "%s: bsd_mode_sense_modepage_disco_reco: "
791 		    "size %d required\n",
792 		    emul64_name, (int)(sizeof (header) + sizeof (page2)));
793 		return (EIO);
794 	}
795 
796 	(void) bzero(&header, sizeof (header));
797 	(void) bzero(&page2, sizeof (page2));
798 
799 	header.length = sizeof (header) + sizeof (page2) - 1;
800 	header.bdesc_length = 0;
801 
802 	page2.mode_page.code = MODEPAGE_DISCO_RECO;
803 	page2.mode_page.ps = 1;
804 	page2.mode_page.length = sizeof (page2) - sizeof (struct mode_page);
805 
806 	switch (page_control) {
807 	case MODE_SENSE_PC_CURRENT:
808 	case MODE_SENSE_PC_DEFAULT:
809 	case MODE_SENSE_PC_SAVED:
810 		break;
811 	case MODE_SENSE_PC_CHANGEABLE:
812 		break;
813 	}
814 
815 	(void) bcopy(&header, addr, sizeof (header));
816 	(void) bcopy(&page2, addr + sizeof (header), sizeof (page2));
817 
818 	pkt->pkt_resid = sp->cmd_count - sizeof (page2) - sizeof (header);
819 	rval = 0;
820 
821 	return (rval);
822 }
823 
824 static int
825 bsd_mode_sense_dad_mode_format(struct scsi_pkt *pkt)
826 {
827 	struct emul64_cmd	*sp = PKT2CMD(pkt);
828 	union scsi_cdb		*cdb = (union scsi_cdb *)pkt->pkt_cdbp;
829 	uchar_t			*addr = (uchar_t *)sp->cmd_addr;
830 	emul64_tgt_t		*tgt;
831 	int			page_control;
832 	struct mode_header	header;
833 	struct mode_format	page3;
834 	int			rval = 0;
835 
836 	page_control = (cdb->cdb_opaque[2] >> 6) & 0x03;
837 
838 	if (emul64debug) {
839 		cmn_err(CE_CONT, "%s: bsd_mode_sense_dad_mode_format: "
840 		    "pc=%d n=%d\n", emul64_name, page_control, sp->cmd_count);
841 	}
842 
843 	if (sp->cmd_count < (sizeof (header) + sizeof (page3))) {
844 		cmn_err(CE_CONT, "%s: bsd_mode_sense_dad_mode_format: "
845 		    "size %d required\n",
846 		    emul64_name, (int)(sizeof (header) + sizeof (page3)));
847 		return (EIO);
848 	}
849 
850 	(void) bzero(&header, sizeof (header));
851 	(void) bzero(&page3, sizeof (page3));
852 
853 	header.length = sizeof (header) + sizeof (page3) - 1;
854 	header.bdesc_length = 0;
855 
856 	page3.mode_page.code = DAD_MODE_FORMAT;
857 	page3.mode_page.ps = 1;
858 	page3.mode_page.length = sizeof (page3) - sizeof (struct mode_page);
859 
860 	switch (page_control) {
861 	case MODE_SENSE_PC_CURRENT:
862 	case MODE_SENSE_PC_DEFAULT:
863 	case MODE_SENSE_PC_SAVED:
864 		page3.data_bytes_sect = ushort_to_scsi_ushort(DEV_BSIZE);
865 		page3.interleave = ushort_to_scsi_ushort(1);
866 		EMUL64_MUTEX_ENTER(sp->cmd_emul64);
867 		tgt = find_tgt(sp->cmd_emul64,
868 			pkt->pkt_address.a_target, pkt->pkt_address.a_lun);
869 		EMUL64_MUTEX_EXIT(sp->cmd_emul64);
870 		page3.sect_track = ushort_to_scsi_ushort(tgt->emul64_tgt_nsect);
871 		break;
872 	case MODE_SENSE_PC_CHANGEABLE:
873 		break;
874 	}
875 
876 	(void) bcopy(&header, addr, sizeof (header));
877 	(void) bcopy(&page3, addr + sizeof (header), sizeof (page3));
878 
879 	pkt->pkt_resid = sp->cmd_count - sizeof (page3) - sizeof (header);
880 	rval = 0;
881 
882 	return (rval);
883 }
884 
885 static int
886 bsd_mode_sense_dad_mode_cache(struct scsi_pkt *pkt)
887 {
888 	struct emul64_cmd	*sp = PKT2CMD(pkt);
889 	union scsi_cdb		*cdb = (union scsi_cdb *)pkt->pkt_cdbp;
890 	uchar_t			*addr = (uchar_t *)sp->cmd_addr;
891 	int			page_control;
892 	struct mode_header	header;
893 	struct mode_cache	page8;
894 	int			rval = 0;
895 
896 	page_control = (cdb->cdb_opaque[2] >> 6) & 0x03;
897 
898 	if (emul64debug) {
899 		cmn_err(CE_CONT, "%s: bsd_mode_sense_dad_mode_cache: "
900 		    "pc=%d n=%d\n", emul64_name, page_control, sp->cmd_count);
901 	}
902 
903 	if (sp->cmd_count < (sizeof (header) + sizeof (page8))) {
904 		cmn_err(CE_CONT, "%s: bsd_mode_sense_dad_mode_cache: "
905 		    "size %d required\n",
906 		    emul64_name, (int)(sizeof (header) + sizeof (page8)));
907 		return (EIO);
908 	}
909 
910 	(void) bzero(&header, sizeof (header));
911 	(void) bzero(&page8, sizeof (page8));
912 
913 	header.length = sizeof (header) + sizeof (page8) - 1;
914 	header.bdesc_length = 0;
915 
916 	page8.mode_page.code = DAD_MODE_CACHE;
917 	page8.mode_page.ps = 1;
918 	page8.mode_page.length = sizeof (page8) - sizeof (struct mode_page);
919 
920 	switch (page_control) {
921 	case MODE_SENSE_PC_CURRENT:
922 	case MODE_SENSE_PC_DEFAULT:
923 	case MODE_SENSE_PC_SAVED:
924 		break;
925 	case MODE_SENSE_PC_CHANGEABLE:
926 		break;
927 	}
928 
929 	(void) bcopy(&header, addr, sizeof (header));
930 	(void) bcopy(&page8, addr + sizeof (header), sizeof (page8));
931 
932 	pkt->pkt_resid = sp->cmd_count - sizeof (page8) - sizeof (header);
933 	rval = 0;
934 
935 	return (rval);
936 }
937 
938 /* ARGSUSED 0 */
939 int
940 bsd_scsi_mode_select(struct scsi_pkt *pkt)
941 {
942 	return (0);
943 }
944 
945 int
946 bsd_scsi_read_capacity_8(struct scsi_pkt *pkt)
947 {
948 	struct emul64_cmd	*sp = PKT2CMD(pkt);
949 	emul64_tgt_t		*tgt;
950 	struct scsi_capacity	cap;
951 	int			rval = 0;
952 
953 	EMUL64_MUTEX_ENTER(sp->cmd_emul64);
954 	tgt = find_tgt(sp->cmd_emul64,
955 		pkt->pkt_address.a_target, pkt->pkt_address.a_lun);
956 	EMUL64_MUTEX_EXIT(sp->cmd_emul64);
957 	if (tgt->emul64_tgt_sectors > 0xffffffff)
958 		cap.capacity = 0xffffffff;
959 	else
960 		cap.capacity =
961 		    uint32_to_scsi_uint32(tgt->emul64_tgt_sectors);
962 	cap.lbasize = uint32_to_scsi_uint32((uint_t)DEV_BSIZE);
963 
964 	pkt->pkt_resid = sp->cmd_count - sizeof (struct scsi_capacity);
965 
966 	(void) bcopy(&cap, (caddr_t)sp->cmd_addr,
967 		    sizeof (struct scsi_capacity));
968 	return (rval);
969 }
970 
971 int
972 bsd_scsi_read_capacity_16(struct scsi_pkt *pkt)
973 {
974 	struct emul64_cmd	*sp = PKT2CMD(pkt);
975 	emul64_tgt_t		*tgt;
976 	struct scsi_capacity_16 cap;
977 	int			rval = 0;
978 
979 	EMUL64_MUTEX_ENTER(sp->cmd_emul64);
980 	tgt = find_tgt(sp->cmd_emul64,
981 		pkt->pkt_address.a_target, pkt->pkt_address.a_lun);
982 	EMUL64_MUTEX_EXIT(sp->cmd_emul64);
983 
984 	cap.sc_capacity = uint64_to_scsi_uint64(tgt->emul64_tgt_sectors);
985 	cap.sc_lbasize = uint32_to_scsi_uint32((uint_t)DEV_BSIZE);
986 	cap.sc_rto_en = 0;
987 	cap.sc_prot_en = 0;
988 	cap.sc_rsvd0 = 0;
989 	bzero(&cap.sc_rsvd1[0], sizeof (cap.sc_rsvd1));
990 
991 	pkt->pkt_resid = sp->cmd_count - sizeof (struct scsi_capacity_16);
992 
993 	(void) bcopy(&cap, (caddr_t)sp->cmd_addr,
994 			sizeof (struct scsi_capacity_16));
995 	return (rval);
996 }
997 int
998 bsd_scsi_read_capacity(struct scsi_pkt *pkt)
999 {
1000 	return (bsd_scsi_read_capacity_8(pkt));
1001 }
1002 
1003 
1004 /* ARGSUSED 0 */
1005 int
1006 bsd_scsi_reserve(struct scsi_pkt *pkt)
1007 {
1008 	return (0);
1009 }
1010 
1011 /* ARGSUSED 0 */
1012 int
1013 bsd_scsi_release(struct scsi_pkt *pkt)
1014 {
1015 	return (0);
1016 }
1017 
1018 
1019 int
1020 bsd_scsi_read_defect_list(struct scsi_pkt *pkt)
1021 {
1022 	pkt->pkt_resid = 0;
1023 	return (0);
1024 }
1025 
1026 
1027 /* ARGSUSED 0 */
1028 int
1029 bsd_scsi_reassign_block(struct scsi_pkt *pkt)
1030 {
1031 	return (0);
1032 }
1033 
1034 
1035 static int
1036 bsd_readblks(struct emul64 *emul64, ushort_t a_target, ushort_t a_lun,
1037 		diskaddr_t blkno, int nblks, unsigned char *bufaddr)
1038 {
1039 	emul64_tgt_t	*tgt;
1040 	blklist_t	*blk;
1041 	emul64_rng_overlap_t overlap;
1042 	int		i = 0;
1043 
1044 	if (emul64debug) {
1045 		cmn_err(CE_CONT, "%s: bsd_readblks: "
1046 		    "<%d,%d> blk %llu (0x%llx) nblks %d\n",
1047 		    emul64_name, a_target, a_lun, blkno, blkno, nblks);
1048 	}
1049 
1050 	emul64_yield_check();
1051 
1052 	EMUL64_MUTEX_ENTER(emul64);
1053 	tgt = find_tgt(emul64, a_target, a_lun);
1054 	EMUL64_MUTEX_EXIT(emul64);
1055 	if (tgt == NULL) {
1056 		cmn_err(CE_WARN, "%s: bsd_readblks: no target for %d,%d\n",
1057 		    emul64_name, a_target, a_lun);
1058 		goto unlocked_out;
1059 	}
1060 
1061 	if (emul64_collect_stats) {
1062 		mutex_enter(&emul64_stats_mutex);
1063 		emul64_io_ops++;
1064 		emul64_io_blocks += nblks;
1065 		mutex_exit(&emul64_stats_mutex);
1066 	}
1067 	mutex_enter(&tgt->emul64_tgt_blk_lock);
1068 
1069 	/*
1070 	 * Keep the ioctls from changing the nowrite list for the duration
1071 	 * of this I/O by grabbing emul64_tgt_nw_lock.  This will keep the
1072 	 * results from our call to bsd_tgt_overlap from changing while we
1073 	 * do the I/O.
1074 	 */
1075 	rw_enter(&tgt->emul64_tgt_nw_lock, RW_READER);
1076 
1077 	overlap = bsd_tgt_overlap(tgt, blkno, nblks);
1078 	switch (overlap) {
1079 	case O_SAME:
1080 	case O_SUBSET:
1081 	case O_OVERLAP:
1082 		cmn_err(CE_WARN, "%s: bsd_readblks: "
1083 		    "read to blocked area %lld,%d\n",
1084 		    emul64_name, blkno, nblks);
1085 		rw_exit(&tgt->emul64_tgt_nw_lock);
1086 		goto errout;
1087 	case O_NONE:
1088 		break;
1089 	}
1090 	for (i = 0; i < nblks; i++) {
1091 		if (emul64_debug_blklist)
1092 			cmn_err(CE_CONT, "%s: bsd_readblks: "
1093 			    "%d of %d: blkno %lld\n",
1094 			    emul64_name, i+1, nblks, blkno);
1095 		if (blkno > tgt->emul64_tgt_sectors)
1096 			break;
1097 		blk = bsd_findblk(tgt, blkno, NULL);
1098 		if (blk) {
1099 			(void) bcopy(blk->bl_data, bufaddr, DEV_BSIZE);
1100 		} else {
1101 			(void) bzero(bufaddr, DEV_BSIZE);
1102 		}
1103 		blkno++;
1104 		bufaddr += DEV_BSIZE;
1105 	}
1106 	rw_exit(&tgt->emul64_tgt_nw_lock);
1107 
1108 errout:
1109 	mutex_exit(&tgt->emul64_tgt_blk_lock);
1110 
1111 unlocked_out:
1112 	return ((nblks - i) * DEV_BSIZE);
1113 }
1114 
1115 
1116 static int
1117 bsd_writeblks(struct emul64 *emul64, ushort_t a_target, ushort_t a_lun,
1118 		diskaddr_t blkno, int nblks, unsigned char *bufaddr)
1119 {
1120 	emul64_tgt_t	*tgt;
1121 	blklist_t	*blk;
1122 	emul64_rng_overlap_t overlap;
1123 	avl_index_t	where;
1124 	int		i = 0;
1125 
1126 	if (emul64debug) {
1127 		cmn_err(CE_CONT, "%s: bsd_writeblks: "
1128 		    "<%d,%d> blk %llu (0x%llx) nblks %d\n",
1129 		    emul64_name, a_target, a_lun, blkno, blkno, nblks);
1130 	}
1131 
1132 	emul64_yield_check();
1133 
1134 	EMUL64_MUTEX_ENTER(emul64);
1135 	tgt = find_tgt(emul64, a_target, a_lun);
1136 	EMUL64_MUTEX_EXIT(emul64);
1137 	if (tgt == NULL) {
1138 		cmn_err(CE_WARN, "%s: bsd_writeblks: no target for %d,%d\n",
1139 		    emul64_name, a_target, a_lun);
1140 		goto unlocked_out;
1141 	}
1142 
1143 	if (emul64_collect_stats) {
1144 		mutex_enter(&emul64_stats_mutex);
1145 		emul64_io_ops++;
1146 		emul64_io_blocks += nblks;
1147 		mutex_exit(&emul64_stats_mutex);
1148 	}
1149 	mutex_enter(&tgt->emul64_tgt_blk_lock);
1150 
1151 	/*
1152 	 * Keep the ioctls from changing the nowrite list for the duration
1153 	 * of this I/O by grabbing emul64_tgt_nw_lock.  This will keep the
1154 	 * results from our call to bsd_tgt_overlap from changing while we
1155 	 * do the I/O.
1156 	 */
1157 	rw_enter(&tgt->emul64_tgt_nw_lock, RW_READER);
1158 	overlap = bsd_tgt_overlap(tgt, blkno, nblks);
1159 	switch (overlap) {
1160 	case O_SAME:
1161 	case O_SUBSET:
1162 		if (emul64_collect_stats) {
1163 			mutex_enter(&emul64_stats_mutex);
1164 			emul64_skipped_io++;
1165 			emul64_skipped_blk += nblks;
1166 			mutex_exit(&emul64_stats_mutex);
1167 		}
1168 		rw_exit(&tgt->emul64_tgt_nw_lock);
1169 		mutex_exit(&tgt->emul64_tgt_blk_lock);
1170 		return (0);
1171 	case O_OVERLAP:
1172 	case O_NONE:
1173 		break;
1174 	}
1175 	for (i = 0; i < nblks; i++) {
1176 		if ((overlap == O_NONE) ||
1177 		    (bsd_tgt_overlap(tgt, blkno, 1) == O_NONE)) {
1178 			/*
1179 			 * If there was no overlap for the entire I/O range
1180 			 * or if there is no overlap for this particular
1181 			 * block, then we need to do the write.
1182 			 */
1183 			if (emul64_debug_blklist)
1184 				cmn_err(CE_CONT, "%s: bsd_writeblks: "
1185 				    "%d of %d: blkno %lld\n",
1186 				    emul64_name, i+1, nblks, blkno);
1187 			if (blkno > tgt->emul64_tgt_sectors) {
1188 				cmn_err(CE_WARN, "%s: bsd_writeblks: "
1189 				    "blkno %lld, tgt_sectors %lld\n",
1190 				    emul64_name, blkno,
1191 				    tgt->emul64_tgt_sectors);
1192 				break;
1193 			}
1194 
1195 			blk = bsd_findblk(tgt, blkno, &where);
1196 			if (bcmp(bufaddr, emul64_zeros, DEV_BSIZE) == 0) {
1197 				if (blk) {
1198 					bsd_freeblk(tgt, blk);
1199 				}
1200 			} else {
1201 				if (blk) {
1202 					(void) bcopy(bufaddr, blk->bl_data,
1203 							DEV_BSIZE);
1204 				} else {
1205 					bsd_allocblk(tgt,
1206 							blkno,
1207 							(caddr_t)bufaddr,
1208 							where);
1209 				}
1210 			}
1211 		}
1212 		blkno++;
1213 		bufaddr += DEV_BSIZE;
1214 	}
1215 
1216 	/*
1217 	 * Now that we're done with our I/O, allow the ioctls to change the
1218 	 * nowrite list.
1219 	 */
1220 	rw_exit(&tgt->emul64_tgt_nw_lock);
1221 
1222 errout:
1223 	mutex_exit(&tgt->emul64_tgt_blk_lock);
1224 
1225 unlocked_out:
1226 	return ((nblks - i) * DEV_BSIZE);
1227 }
1228 
1229 emul64_tgt_t *
1230 find_tgt(struct emul64 *emul64, ushort_t a_target, ushort_t a_lun)
1231 {
1232 	emul64_tgt_t	*tgt;
1233 
1234 	tgt = emul64->emul64_tgt;
1235 	while (tgt) {
1236 		if (tgt->emul64_tgt_saddr.a_target == a_target &&
1237 		    tgt->emul64_tgt_saddr.a_lun == a_lun) {
1238 			break;
1239 		}
1240 		tgt = tgt->emul64_tgt_next;
1241 	}
1242 	return (tgt);
1243 
1244 }
1245 
1246 /*
1247  * Free all blocks that are part of the specified range.
1248  */
1249 int
1250 bsd_freeblkrange(emul64_tgt_t *tgt, emul64_range_t *range)
1251 {
1252 	blklist_t	*blk;
1253 	blklist_t	*nextblk;
1254 
1255 	ASSERT(mutex_owned(&tgt->emul64_tgt_blk_lock));
1256 	for (blk = (blklist_t *)avl_first(&tgt->emul64_tgt_data);
1257 		blk != NULL;
1258 		blk = nextblk) {
1259 		/*
1260 		 * We need to get the next block pointer now, because blk
1261 		 * will be freed inside the if statement.
1262 		 */
1263 		nextblk = AVL_NEXT(&tgt->emul64_tgt_data, blk);
1264 
1265 		if (emul64_overlap(range, blk->bl_blkno, (size_t)1) != O_NONE) {
1266 			bsd_freeblk(tgt, blk);
1267 		}
1268 	}
1269 	return (0);
1270 }
1271 
1272 static blklist_t *
1273 bsd_findblk(emul64_tgt_t *tgt, diskaddr_t blkno, avl_index_t *where)
1274 {
1275 	blklist_t	*blk;
1276 	blklist_t	search;
1277 
1278 	ASSERT(mutex_owned(&tgt->emul64_tgt_blk_lock));
1279 
1280 	search.bl_blkno = blkno;
1281 	blk = (blklist_t *)avl_find(&tgt->emul64_tgt_data, &search, where);
1282 	return (blk);
1283 }
1284 
1285 
1286 static void
1287 bsd_allocblk(emul64_tgt_t *tgt,
1288 		diskaddr_t blkno,
1289 		caddr_t data,
1290 		avl_index_t where)
1291 {
1292 	blklist_t	*blk;
1293 
1294 	if (emul64_debug_blklist)
1295 		cmn_err(CE_CONT, "%s: bsd_allocblk: %llu\n",
1296 		    emul64_name, blkno);
1297 
1298 	ASSERT(mutex_owned(&tgt->emul64_tgt_blk_lock));
1299 
1300 	blk = (blklist_t *)kmem_zalloc(sizeof (blklist_t), KM_SLEEP);
1301 	blk->bl_data = (uchar_t *)kmem_zalloc(DEV_BSIZE, KM_SLEEP);
1302 	blk->bl_blkno = blkno;
1303 	(void) bcopy(data, blk->bl_data, DEV_BSIZE);
1304 	avl_insert(&tgt->emul64_tgt_data, (void *) blk, where);
1305 
1306 	if (emul64_collect_stats) {
1307 		mutex_enter(&emul64_stats_mutex);
1308 		emul64_nonzero++;
1309 		tgt->emul64_list_length++;
1310 		if (tgt->emul64_list_length > emul64_max_list_length) {
1311 			emul64_max_list_length = tgt->emul64_list_length;
1312 		}
1313 		mutex_exit(&emul64_stats_mutex);
1314 	}
1315 }
1316 
1317 static void
1318 bsd_freeblk(emul64_tgt_t *tgt, blklist_t *blk)
1319 {
1320 	if (emul64_debug_blklist)
1321 		cmn_err(CE_CONT, "%s: bsd_freeblk: <%d,%d> blk=%lld\n",
1322 		    emul64_name, tgt->emul64_tgt_saddr.a_target,
1323 		    tgt->emul64_tgt_saddr.a_lun, blk->bl_blkno);
1324 
1325 	ASSERT(mutex_owned(&tgt->emul64_tgt_blk_lock));
1326 
1327 	avl_remove(&tgt->emul64_tgt_data, (void *) blk);
1328 	if (emul64_collect_stats) {
1329 		mutex_enter(&emul64_stats_mutex);
1330 		emul64_nonzero--;
1331 		tgt->emul64_list_length--;
1332 		mutex_exit(&emul64_stats_mutex);
1333 	}
1334 	kmem_free(blk->bl_data, DEV_BSIZE);
1335 	kmem_free(blk, sizeof (blklist_t));
1336 }
1337 
1338 /*
1339  * Look for overlap between a nowrite range and a block range.
1340  *
1341  * NOTE:  Callers of this function must hold the tgt->emul64_tgt_nw_lock
1342  *	  lock.  For the purposes of this function, a reader lock is
1343  *	  sufficient.
1344  */
1345 static emul64_rng_overlap_t
1346 bsd_tgt_overlap(emul64_tgt_t *tgt, diskaddr_t blkno, int count)
1347 {
1348 	emul64_nowrite_t	*nw;
1349 	emul64_rng_overlap_t	rv = O_NONE;
1350 
1351 	for (nw = tgt->emul64_tgt_nowrite;
1352 		(nw != NULL) && (rv == O_NONE);
1353 		nw = nw->emul64_nwnext) {
1354 		rv = emul64_overlap(&nw->emul64_blocked,
1355 				    blkno,
1356 				    (size_t)count);
1357 	}
1358 	return (rv);
1359 }
1360 
1361 /*
1362  * Operations that do a lot of I/O, such as RAID 5 initializations, result
1363  * in a CPU bound kernel when the device is an emul64 device.  This makes
1364  * the machine look hung.  To avoid this problem, give up the CPU from time
1365  * to time.
1366  */
1367 
1368 static void
1369 emul64_yield_check()
1370 {
1371 	static uint_t	emul64_io_count = 0;	/* # I/Os since last wait */
1372 	static uint_t	emul64_waiting = FALSE;	/* TRUE -> a thread is in */
1373 						/*   cv_timed wait. */
1374 	clock_t		ticks;
1375 
1376 	if (emul64_yield_enable == 0)
1377 		return;
1378 
1379 	mutex_enter(&emul64_yield_mutex);
1380 
1381 	if (emul64_waiting == TRUE) {
1382 		/*
1383 		 * Another thread has already started the timer.  We'll
1384 		 * just wait here until their time expires, and they
1385 		 * broadcast to us.  When they do that, we'll return and
1386 		 * let our caller do more I/O.
1387 		 */
1388 		cv_wait(&emul64_yield_cv, &emul64_yield_mutex);
1389 	} else if (emul64_io_count++ > emul64_yield_period) {
1390 		/*
1391 		 * Set emul64_waiting to let other threads know that we
1392 		 * have started the timer.
1393 		 */
1394 		emul64_waiting = TRUE;
1395 		emul64_num_delay_called++;
1396 		ticks = drv_usectohz(emul64_yield_length);
1397 		if (ticks == 0)
1398 			ticks = 1;
1399 		(void) cv_timedwait(&emul64_yield_cv,
1400 		    &emul64_yield_mutex, ddi_get_lbolt() + ticks);
1401 		emul64_io_count = 0;
1402 		emul64_waiting = FALSE;
1403 
1404 		/* Broadcast in case others are waiting. */
1405 		cv_broadcast(&emul64_yield_cv);
1406 	}
1407 
1408 	mutex_exit(&emul64_yield_mutex);
1409 }
1410