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