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 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 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 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 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 270 bsd_scsi_start_stop_unit(struct scsi_pkt *pkt) 271 { 272 return (0); 273 } 274 275 /* ARGSUSED 0 */ 276 int 277 bsd_scsi_test_unit_ready(struct scsi_pkt *pkt) 278 { 279 return (0); 280 } 281 282 /* ARGSUSED 0 */ 283 int 284 bsd_scsi_request_sense(struct scsi_pkt *pkt) 285 { 286 return (0); 287 } 288 289 int 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 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 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 423 bsd_scsi_format(struct scsi_pkt *pkt) 424 { 425 return (0); 426 } 427 428 int 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 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 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 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 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 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 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 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 917 bsd_scsi_mode_select(struct scsi_pkt *pkt) 918 { 919 return (0); 920 } 921 922 int 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 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 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 983 bsd_scsi_reserve(struct scsi_pkt *pkt) 984 { 985 return (0); 986 } 987 988 /* ARGSUSED 0 */ 989 int 990 bsd_scsi_release(struct scsi_pkt *pkt) 991 { 992 return (0); 993 } 994 995 996 int 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 1006 bsd_scsi_reassign_block(struct scsi_pkt *pkt) 1007 { 1008 return (0); 1009 } 1010 1011 1012 static int 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 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 * 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 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 * 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 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 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 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 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 }