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