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