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 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * pseudo scsi disk driver 30 */ 31 32 #include <sys/scsi/scsi.h> 33 #include <sys/ddi.h> 34 #include <sys/sunddi.h> 35 #include <sys/kmem.h> 36 #include <sys/taskq.h> 37 #include <sys/disp.h> 38 #include <sys/types.h> 39 #include <sys/buf.h> 40 41 #include <sys/emul64.h> 42 #include <sys/emul64cmd.h> 43 #include <sys/emul64var.h> 44 45 /* 46 * Mode sense/select page control 47 */ 48 #define MODE_SENSE_PC_CURRENT 0 49 #define MODE_SENSE_PC_CHANGEABLE 1 50 #define MODE_SENSE_PC_DEFAULT 2 51 #define MODE_SENSE_PC_SAVED 3 52 53 /* 54 * Byte conversion macros 55 */ 56 #if defined(_BIG_ENDIAN) 57 #define ushort_to_scsi_ushort(n) (n) 58 #define uint32_to_scsi_uint32(n) (n) 59 #define uint64_to_scsi_uint64(n) (n) 60 #elif defined(_LITTLE_ENDIAN) 61 62 #define ushort_to_scsi_ushort(n) \ 63 ((((n) & 0x00ff) << 8) | \ 64 (((n) & 0xff00) >> 8)) 65 66 #define uint32_to_scsi_uint32(n) \ 67 ((((n) & 0x000000ff) << 24) | \ 68 (((n) & 0x0000ff00) << 8) | \ 69 (((n) & 0x00ff0000) >> 8) | \ 70 (((n) & 0xff000000) >> 24)) 71 #define uint64_to_scsi_uint64(n) \ 72 ((((n) & 0x00000000000000ff) << 56) | \ 73 (((n) & 0x000000000000ff00) << 40) | \ 74 (((n) & 0x0000000000ff0000) << 24) | \ 75 (((n) & 0x00000000ff000000) << 8) | \ 76 (((n) & 0x000000ff00000000) >> 8) | \ 77 (((n) & 0x0000ff0000000000) >> 24) | \ 78 (((n) & 0x00ff000000000000) >> 40) | \ 79 (((n) & 0xff00000000000000) >> 56)) 80 #else 81 error no _BIG_ENDIAN or _LITTLE_ENDIAN 82 #endif 83 #define uint_to_byte0(n) ((n) & 0xff) 84 #define uint_to_byte1(n) (((n)>>8) & 0xff) 85 #define uint_to_byte2(n) (((n)>>16) & 0xff) 86 #define uint_to_byte3(n) (((n)>>24) & 0xff) 87 88 /* 89 * struct prop_map 90 * 91 * This structure maps a property name to the place to store its value. 92 */ 93 struct prop_map { 94 char *pm_name; /* Name of the property. */ 95 int *pm_value; /* Place to store the value. */ 96 }; 97 98 static int emul64_debug_blklist = 0; 99 100 /* 101 * Some interesting statistics. These are protected by the 102 * emul64_stats_mutex. It would be nice to have an ioctl to print them out, 103 * but we don't have the development time for that now. You can at least 104 * look at them with adb. 105 */ 106 107 int emul64_collect_stats = 1; /* Collect stats if non-zero */ 108 kmutex_t emul64_stats_mutex; /* Protect these variables */ 109 long emul64_nowrite_count = 0; /* # active nowrite ranges */ 110 static uint64_t emul64_skipped_io = 0; /* Skipped I/O operations, because of */ 111 /* EMUL64_WRITE_OFF. */ 112 static uint64_t emul64_skipped_blk = 0; /* Skipped blocks because of */ 113 /* EMUL64_WRITE_OFF. */ 114 static uint64_t emul64_io_ops = 0; /* Total number of I/O operations */ 115 /* including skipped and actual. */ 116 static uint64_t emul64_io_blocks = 0; /* Total number of blocks involved */ 117 /* in I/O operations. */ 118 static uint64_t emul64_nonzero = 0; /* Number of non-zero data blocks */ 119 /* currently held in memory */ 120 static uint64_t emul64_max_list_length = 0; /* Maximum size of a linked */ 121 /* list of non-zero blocks. */ 122 uint64_t emul64_taskq_max = 0; /* emul64_scsi_start uses the taskq */ 123 /* mechanism to dispatch work. */ 124 /* If the number of entries in the */ 125 /* exceeds the maximum for the queue */ 126 /* the queue a 1 second delay is */ 127 /* encountered in taskq_ent_alloc. */ 128 /* This counter counts the number */ 129 /* times that this happens. */ 130 131 /* 132 * Since emul64 does no physical I/O, operations that would normally be I/O 133 * intensive become CPU bound. An example of this is RAID 5 134 * initialization. When the kernel becomes CPU bound, it looks as if the 135 * machine is hung. 136 * 137 * To avoid this problem, we provide a function, emul64_yield_check, that does a 138 * delay from time to time to yield up the CPU. The following variables 139 * are tunables for this algorithm. 140 * 141 * emul64_num_delay_called Number of times we called delay. This is 142 * not really a tunable. Rather it is a 143 * counter that provides useful information 144 * for adjusting the tunables. 145 * emul64_yield_length Number of microseconds to yield the CPU. 146 * emul64_yield_period Number of I/O operations between yields. 147 * emul64_yield_enable emul64 will yield the CPU, only if this 148 * variable contains a non-zero value. This 149 * allows the yield functionality to be turned 150 * off for experimentation purposes. 151 * 152 * The value of 1000 for emul64_yield_period has been determined by 153 * experience with running the tests. 154 */ 155 static uint64_t emul64_num_delay_called = 0; 156 static int emul64_yield_length = 1000; 157 static int emul64_yield_period = 1000; 158 static int emul64_yield_enable = 1; 159 static kmutex_t emul64_yield_mutex; 160 static kcondvar_t emul64_yield_cv; 161 162 /* 163 * This array establishes a set of tunable variables that can be set by 164 * defining properties in the emul64.conf file. 165 */ 166 struct prop_map emul64_properties[] = { 167 "emul64_collect_stats", &emul64_collect_stats, 168 "emul64_yield_length", &emul64_yield_length, 169 "emul64_yield_period", &emul64_yield_period, 170 "emul64_yield_enable", &emul64_yield_enable, 171 "emul64_max_task", &emul64_max_task, 172 "emul64_task_nthreads", &emul64_task_nthreads 173 }; 174 175 static unsigned char *emul64_zeros = NULL; /* Block of 0s for comparison */ 176 177 extern void emul64_check_cond(struct scsi_pkt *pkt, uchar_t key, 178 uchar_t asc, uchar_t ascq); 179 /* ncyl=250000 acyl=2 nhead=24 nsect=357 */ 180 uint_t dkg_rpm = 3600; 181 182 static int bsd_mode_sense_dad_mode_geometry(struct scsi_pkt *); 183 static int bsd_mode_sense_dad_mode_err_recov(struct scsi_pkt *); 184 static int bsd_mode_sense_modepage_disco_reco(struct scsi_pkt *); 185 static int bsd_mode_sense_dad_mode_format(struct scsi_pkt *); 186 static int bsd_mode_sense_dad_mode_cache(struct scsi_pkt *); 187 static int bsd_readblks(struct emul64 *, ushort_t, ushort_t, diskaddr_t, 188 int, unsigned char *); 189 static int bsd_writeblks(struct emul64 *, ushort_t, ushort_t, diskaddr_t, 190 int, unsigned char *); 191 emul64_tgt_t *find_tgt(struct emul64 *, ushort_t, ushort_t); 192 static blklist_t *bsd_findblk(emul64_tgt_t *, diskaddr_t, avl_index_t *); 193 static void bsd_allocblk(emul64_tgt_t *, diskaddr_t, caddr_t, avl_index_t); 194 static void bsd_freeblk(emul64_tgt_t *, blklist_t *); 195 static void emul64_yield_check(); 196 static emul64_rng_overlap_t bsd_tgt_overlap(emul64_tgt_t *, diskaddr_t, int); 197 198 char *emul64_name = "emul64"; 199 200 201 /* 202 * Initialize globals in this file. 203 */ 204 void 205 emul64_bsd_init() 206 { 207 emul64_zeros = (unsigned char *) kmem_zalloc(DEV_BSIZE, KM_SLEEP); 208 mutex_init(&emul64_stats_mutex, NULL, MUTEX_DRIVER, NULL); 209 mutex_init(&emul64_yield_mutex, NULL, MUTEX_DRIVER, NULL); 210 cv_init(&emul64_yield_cv, NULL, CV_DRIVER, NULL); 211 } 212 213 /* 214 * Clean up globals in this file. 215 */ 216 void 217 emul64_bsd_fini() 218 { 219 cv_destroy(&emul64_yield_cv); 220 mutex_destroy(&emul64_yield_mutex); 221 mutex_destroy(&emul64_stats_mutex); 222 if (emul64_zeros != NULL) { 223 kmem_free(emul64_zeros, DEV_BSIZE); 224 emul64_zeros = NULL; 225 } 226 } 227 228 /* 229 * Attempt to get the values of the properties that are specified in the 230 * emul64_properties array. If the property exists, copy its value to the 231 * specified location. All the properties have been assigned default 232 * values in this driver, so if we cannot get the property that is not a 233 * problem. 234 */ 235 void 236 emul64_bsd_get_props(dev_info_t *dip) 237 { 238 uint_t count; 239 uint_t i; 240 struct prop_map *pmp; 241 int *properties; 242 243 for (pmp = emul64_properties, i = 0; 244 i < sizeof (emul64_properties) / sizeof (struct prop_map); 245 i++, pmp++) { 246 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 247 DDI_PROP_DONTPASS, 248 pmp->pm_name, &properties, 249 &count) == DDI_PROP_SUCCESS) { 250 if (count >= 1) { 251 *pmp->pm_value = *properties; 252 } 253 ddi_prop_free((void *) properties); 254 } 255 } 256 } 257 258 int 259 emul64_bsd_blkcompare(const void *a1, const void *b1) 260 { 261 blklist_t *a = (blklist_t *)a1; 262 blklist_t *b = (blklist_t *)b1; 263 264 if (a->bl_blkno < b->bl_blkno) 265 return (-1); 266 if (a->bl_blkno == b->bl_blkno) 267 return (0); 268 return (1); 269 } 270 271 /* ARGSUSED 0 */ 272 int 273 bsd_scsi_start_stop_unit(struct scsi_pkt *pkt) 274 { 275 return (0); 276 } 277 278 /* ARGSUSED 0 */ 279 int 280 bsd_scsi_test_unit_ready(struct scsi_pkt *pkt) 281 { 282 return (0); 283 } 284 285 /* ARGSUSED 0 */ 286 int 287 bsd_scsi_request_sense(struct scsi_pkt *pkt) 288 { 289 return (0); 290 } 291 292 int 293 bsd_scsi_inq_page0(struct scsi_pkt *pkt, uchar_t pqdtype) 294 { 295 struct emul64_cmd *sp = PKT2CMD(pkt); 296 297 if (sp->cmd_count < 6) { 298 cmn_err(CE_CONT, "%s: bsd_scsi_inq_page0: size %d required\n", 299 emul64_name, 6); 300 return (EIO); 301 } 302 303 sp->cmd_addr[0] = pqdtype; /* periph qual., dtype */ 304 sp->cmd_addr[1] = 0; /* page code */ 305 sp->cmd_addr[2] = 0; /* reserved */ 306 sp->cmd_addr[3] = 6 - 3; /* length */ 307 sp->cmd_addr[4] = 0; /* 1st page */ 308 sp->cmd_addr[5] = 0x83; /* 2nd page */ 309 310 pkt->pkt_resid = sp->cmd_count - 6; 311 return (0); 312 } 313 314 int 315 bsd_scsi_inq_page83(struct scsi_pkt *pkt, uchar_t pqdtype) 316 { 317 struct emul64 *emul64 = PKT2EMUL64(pkt); 318 struct emul64_cmd *sp = PKT2CMD(pkt); 319 int instance = ddi_get_instance(emul64->emul64_dip); 320 321 if (sp->cmd_count < 22) { 322 cmn_err(CE_CONT, "%s: bsd_scsi_inq_page83: size %d required\n", 323 emul64_name, 22); 324 return (EIO); 325 } 326 327 sp->cmd_addr[0] = pqdtype; /* periph qual., dtype */ 328 sp->cmd_addr[1] = 0x83; /* page code */ 329 sp->cmd_addr[2] = 0; /* reserved */ 330 sp->cmd_addr[3] = (22 - 8) + 4; /* length */ 331 332 sp->cmd_addr[4] = 1; /* code set - binary */ 333 sp->cmd_addr[5] = 3; /* association and device ID type 3 */ 334 sp->cmd_addr[6] = 0; /* reserved */ 335 sp->cmd_addr[7] = 22 - 8; /* ID length */ 336 337 sp->cmd_addr[8] = 0xde; /* @8: identifier, byte 0 */ 338 sp->cmd_addr[9] = 0xca; 339 sp->cmd_addr[10] = 0xde; 340 sp->cmd_addr[11] = 0x80; 341 342 sp->cmd_addr[12] = 0xba; 343 sp->cmd_addr[13] = 0xbe; 344 sp->cmd_addr[14] = 0xab; 345 sp->cmd_addr[15] = 0xba; 346 /* @22: */ 347 348 /* 349 * Instances seem to be assigned sequentially, so it unlikely that we 350 * will have more than 65535 of them. 351 */ 352 sp->cmd_addr[16] = uint_to_byte1(instance); 353 sp->cmd_addr[17] = uint_to_byte0(instance); 354 sp->cmd_addr[18] = uint_to_byte1(TGT(sp)); 355 sp->cmd_addr[19] = uint_to_byte0(TGT(sp)); 356 sp->cmd_addr[20] = uint_to_byte1(LUN(sp)); 357 sp->cmd_addr[21] = uint_to_byte0(LUN(sp)); 358 359 pkt->pkt_resid = sp->cmd_count - 22; 360 return (0); 361 } 362 363 int 364 bsd_scsi_inquiry(struct scsi_pkt *pkt) 365 { 366 struct emul64_cmd *sp = PKT2CMD(pkt); 367 union scsi_cdb *cdb = (union scsi_cdb *)pkt->pkt_cdbp; 368 emul64_tgt_t *tgt; 369 uchar_t pqdtype; 370 struct scsi_inquiry inq; 371 372 EMUL64_MUTEX_ENTER(sp->cmd_emul64); 373 tgt = find_tgt(sp->cmd_emul64, 374 pkt->pkt_address.a_target, pkt->pkt_address.a_lun); 375 EMUL64_MUTEX_EXIT(sp->cmd_emul64); 376 377 if (sp->cmd_count < sizeof (inq)) { 378 cmn_err(CE_CONT, "%s: bsd_scsi_inquiry: size %d required\n", 379 emul64_name, (int)sizeof (inq)); 380 return (EIO); 381 } 382 383 if (cdb->cdb_opaque[1] & 0xfc) { 384 cmn_err(CE_WARN, "%s: bsd_scsi_inquiry: 0x%x", 385 emul64_name, cdb->cdb_opaque[1]); 386 emul64_check_cond(pkt, 0x5, 0x24, 0x0); /* inv. fld in cdb */ 387 return (0); 388 } 389 390 pqdtype = tgt->emul64_tgt_dtype; 391 if (cdb->cdb_opaque[1] & 0x1) { 392 switch (cdb->cdb_opaque[2]) { 393 case 0x00: 394 return (bsd_scsi_inq_page0(pkt, pqdtype)); 395 case 0x83: 396 return (bsd_scsi_inq_page83(pkt, pqdtype)); 397 default: 398 cmn_err(CE_WARN, "%s: bsd_scsi_inquiry: " 399 "unsupported 0x%x", 400 emul64_name, cdb->cdb_opaque[2]); 401 return (0); 402 } 403 } 404 405 /* set up the inquiry data we return */ 406 (void) bzero((void *)&inq, sizeof (inq)); 407 408 inq.inq_dtype = pqdtype; 409 inq.inq_ansi = 2; 410 inq.inq_rdf = 2; 411 inq.inq_len = sizeof (inq) - 4; 412 inq.inq_wbus16 = 1; 413 inq.inq_cmdque = 1; 414 415 (void) bcopy(tgt->emul64_tgt_inq, inq.inq_vid, 416 sizeof (tgt->emul64_tgt_inq)); 417 (void) bcopy("1", inq.inq_revision, 2); 418 (void) bcopy((void *)&inq, sp->cmd_addr, sizeof (inq)); 419 420 pkt->pkt_resid = sp->cmd_count - sizeof (inq); 421 return (0); 422 } 423 424 /* ARGSUSED 0 */ 425 int 426 bsd_scsi_format(struct scsi_pkt *pkt) 427 { 428 return (0); 429 } 430 431 int 432 bsd_scsi_io(struct scsi_pkt *pkt) 433 { 434 struct emul64_cmd *sp = PKT2CMD(pkt); 435 union scsi_cdb *cdb = (union scsi_cdb *)pkt->pkt_cdbp; 436 diskaddr_t lblkno; 437 int nblks; 438 439 switch (cdb->scc_cmd) { 440 case SCMD_READ: 441 lblkno = (uint32_t)GETG0ADDR(cdb); 442 nblks = GETG0COUNT(cdb); 443 pkt->pkt_resid = bsd_readblks(sp->cmd_emul64, 444 pkt->pkt_address.a_target, 445 pkt->pkt_address.a_lun, 446 lblkno, nblks, sp->cmd_addr); 447 if (emul64debug) { 448 cmn_err(CE_CONT, "%s: bsd_scsi_io: " 449 "read g0 blk=%lld (0x%llx) nblks=%d\n", 450 emul64_name, lblkno, lblkno, nblks); 451 } 452 break; 453 case SCMD_WRITE: 454 lblkno = (uint32_t)GETG0ADDR(cdb); 455 nblks = GETG0COUNT(cdb); 456 pkt->pkt_resid = bsd_writeblks(sp->cmd_emul64, 457 pkt->pkt_address.a_target, 458 pkt->pkt_address.a_lun, 459 lblkno, nblks, sp->cmd_addr); 460 if (emul64debug) { 461 cmn_err(CE_CONT, "%s: bsd_scsi_io: " 462 "write g0 blk=%lld (0x%llx) nblks=%d\n", 463 emul64_name, lblkno, lblkno, nblks); 464 } 465 break; 466 case SCMD_READ_G1: 467 lblkno = (uint32_t)GETG1ADDR(cdb); 468 nblks = GETG1COUNT(cdb); 469 pkt->pkt_resid = bsd_readblks(sp->cmd_emul64, 470 pkt->pkt_address.a_target, 471 pkt->pkt_address.a_lun, 472 lblkno, nblks, sp->cmd_addr); 473 if (emul64debug) { 474 cmn_err(CE_CONT, "%s: bsd_scsi_io: " 475 "read g1 blk=%lld (0x%llx) nblks=%d\n", 476 emul64_name, lblkno, lblkno, nblks); 477 } 478 break; 479 case SCMD_WRITE_G1: 480 lblkno = (uint32_t)GETG1ADDR(cdb); 481 nblks = GETG1COUNT(cdb); 482 pkt->pkt_resid = bsd_writeblks(sp->cmd_emul64, 483 pkt->pkt_address.a_target, 484 pkt->pkt_address.a_lun, 485 lblkno, nblks, sp->cmd_addr); 486 if (emul64debug) { 487 cmn_err(CE_CONT, "%s: bsd_scsi_io: " 488 "write g1 blk=%lld (0x%llx) nblks=%d\n", 489 emul64_name, lblkno, lblkno, nblks); 490 } 491 break; 492 case SCMD_READ_G4: 493 lblkno = GETG4ADDR(cdb); 494 lblkno <<= 32; 495 lblkno |= (uint32_t)GETG4ADDRTL(cdb); 496 nblks = GETG4COUNT(cdb); 497 pkt->pkt_resid = bsd_readblks(sp->cmd_emul64, 498 pkt->pkt_address.a_target, 499 pkt->pkt_address.a_lun, 500 lblkno, nblks, sp->cmd_addr); 501 if (emul64debug) { 502 cmn_err(CE_CONT, "%s: bsd_scsi_io: " 503 "read g4 blk=%lld (0x%llx) nblks=%d\n", 504 emul64_name, lblkno, lblkno, nblks); 505 } 506 break; 507 case SCMD_WRITE_G4: 508 lblkno = GETG4ADDR(cdb); 509 lblkno <<= 32; 510 lblkno |= (uint32_t)GETG4ADDRTL(cdb); 511 nblks = GETG4COUNT(cdb); 512 pkt->pkt_resid = bsd_writeblks(sp->cmd_emul64, 513 pkt->pkt_address.a_target, 514 pkt->pkt_address.a_lun, 515 lblkno, nblks, sp->cmd_addr); 516 if (emul64debug) { 517 cmn_err(CE_CONT, "%s: bsd_scsi_io: " 518 "write g4 blk=%lld (0x%llx) nblks=%d\n", 519 emul64_name, lblkno, lblkno, nblks); 520 } 521 break; 522 default: 523 cmn_err(CE_WARN, "%s: bsd_scsi_io: unhandled I/O: 0x%x", 524 emul64_name, cdb->scc_cmd); 525 break; 526 } 527 528 if (pkt->pkt_resid != 0) 529 cmn_err(CE_WARN, "%s: bsd_scsi_io: " 530 "pkt_resid: 0x%lx, lblkno %lld, nblks %d", 531 emul64_name, pkt->pkt_resid, lblkno, nblks); 532 533 return (0); 534 } 535 536 int 537 bsd_scsi_log_sense(struct scsi_pkt *pkt) 538 { 539 union scsi_cdb *cdb = (union scsi_cdb *)pkt->pkt_cdbp; 540 struct emul64_cmd *sp = PKT2CMD(pkt); 541 int page_code; 542 543 if (sp->cmd_count < 9) { 544 cmn_err(CE_CONT, "%s: bsd_scsi_log_sense size %d required\n", 545 emul64_name, 9); 546 return (EIO); 547 } 548 549 page_code = cdb->cdb_opaque[2] & 0x3f; 550 if (page_code) { 551 cmn_err(CE_CONT, "%s: bsd_scsi_log_sense: " 552 "page 0x%x not supported\n", emul64_name, page_code); 553 emul64_check_cond(pkt, 0x5, 0x24, 0x0); /* inv. fld in cdb */ 554 return (0); 555 } 556 557 sp->cmd_addr[0] = 0; /* page code */ 558 sp->cmd_addr[1] = 0; /* reserved */ 559 sp->cmd_addr[2] = 0; /* MSB of page length */ 560 sp->cmd_addr[3] = 8 - 3; /* LSB of page length */ 561 562 sp->cmd_addr[4] = 0; /* MSB of parameter code */ 563 sp->cmd_addr[5] = 0; /* LSB of parameter code */ 564 sp->cmd_addr[6] = 0; /* parameter control byte */ 565 sp->cmd_addr[7] = 4 - 3; /* parameter length */ 566 sp->cmd_addr[8] = 0x0; /* parameter value */ 567 568 pkt->pkt_resid = sp->cmd_count - 9; 569 return (0); 570 } 571 572 int 573 bsd_scsi_mode_sense(struct scsi_pkt *pkt) 574 { 575 union scsi_cdb *cdb = (union scsi_cdb *)pkt->pkt_cdbp; 576 int page_control; 577 int page_code; 578 int rval = 0; 579 580 switch (cdb->scc_cmd) { 581 case SCMD_MODE_SENSE: 582 page_code = cdb->cdb_opaque[2] & 0x3f; 583 page_control = (cdb->cdb_opaque[2] >> 6) & 0x03; 584 if (emul64debug) { 585 cmn_err(CE_CONT, "%s: bsd_scsi_mode_sense: " 586 "page=0x%x control=0x%x nbytes=%d\n", 587 emul64_name, page_code, page_control, 588 GETG0COUNT(cdb)); 589 } 590 break; 591 case SCMD_MODE_SENSE_G1: 592 page_code = cdb->cdb_opaque[2] & 0x3f; 593 page_control = (cdb->cdb_opaque[2] >> 6) & 0x03; 594 if (emul64debug) { 595 cmn_err(CE_CONT, "%s: bsd_scsi_mode_sense: " 596 "page=0x%x control=0x%x nbytes=%d\n", 597 emul64_name, page_code, page_control, 598 GETG1COUNT(cdb)); 599 } 600 break; 601 default: 602 cmn_err(CE_CONT, "%s: bsd_scsi_mode_sense: " 603 "cmd 0x%x not supported\n", emul64_name, cdb->scc_cmd); 604 return (EIO); 605 } 606 607 switch (page_code) { 608 case DAD_MODE_GEOMETRY: 609 rval = bsd_mode_sense_dad_mode_geometry(pkt); 610 break; 611 case DAD_MODE_ERR_RECOV: 612 rval = bsd_mode_sense_dad_mode_err_recov(pkt); 613 break; 614 case MODEPAGE_DISCO_RECO: 615 rval = bsd_mode_sense_modepage_disco_reco(pkt); 616 break; 617 case DAD_MODE_FORMAT: 618 rval = bsd_mode_sense_dad_mode_format(pkt); 619 break; 620 case DAD_MODE_CACHE: 621 rval = bsd_mode_sense_dad_mode_cache(pkt); 622 break; 623 default: 624 cmn_err(CE_CONT, "%s: bsd_scsi_mode_sense: " 625 "page 0x%x not supported\n", emul64_name, page_code); 626 rval = EIO; 627 break; 628 } 629 630 return (rval); 631 } 632 633 634 static int 635 bsd_mode_sense_dad_mode_geometry(struct scsi_pkt *pkt) 636 { 637 struct emul64_cmd *sp = PKT2CMD(pkt); 638 union scsi_cdb *cdb = (union scsi_cdb *)pkt->pkt_cdbp; 639 uchar_t *addr = (uchar_t *)sp->cmd_addr; 640 emul64_tgt_t *tgt; 641 int page_control; 642 struct mode_header header; 643 struct mode_geometry page4; 644 int ncyl; 645 int rval = 0; 646 647 page_control = (cdb->cdb_opaque[2] >> 6) & 0x03; 648 649 if (emul64debug) { 650 cmn_err(CE_CONT, "%s: bsd_mode_sense_dad_mode_geometry: " 651 "pc=%d n=%d\n", emul64_name, page_control, sp->cmd_count); 652 } 653 654 if (sp->cmd_count < (sizeof (header) + sizeof (page4))) { 655 cmn_err(CE_CONT, "%s: bsd_mode_sense_dad_mode_geometry: " 656 "size %d required\n", 657 emul64_name, (int)(sizeof (header) + sizeof (page4))); 658 return (EIO); 659 } 660 661 (void) bzero(&header, sizeof (header)); 662 (void) bzero(&page4, sizeof (page4)); 663 664 header.length = sizeof (header) + sizeof (page4) - 1; 665 header.bdesc_length = 0; 666 667 page4.mode_page.code = DAD_MODE_GEOMETRY; 668 page4.mode_page.ps = 1; 669 page4.mode_page.length = sizeof (page4) - sizeof (struct mode_page); 670 671 switch (page_control) { 672 case MODE_SENSE_PC_CURRENT: 673 case MODE_SENSE_PC_DEFAULT: 674 case MODE_SENSE_PC_SAVED: 675 EMUL64_MUTEX_ENTER(sp->cmd_emul64); 676 tgt = find_tgt(sp->cmd_emul64, 677 pkt->pkt_address.a_target, pkt->pkt_address.a_lun); 678 EMUL64_MUTEX_EXIT(sp->cmd_emul64); 679 ncyl = tgt->emul64_tgt_ncyls; 680 page4.cyl_ub = uint_to_byte2(ncyl); 681 page4.cyl_mb = uint_to_byte1(ncyl); 682 page4.cyl_lb = uint_to_byte0(ncyl); 683 page4.heads = uint_to_byte0(tgt->emul64_tgt_nheads); 684 page4.rpm = ushort_to_scsi_ushort(dkg_rpm); 685 break; 686 case MODE_SENSE_PC_CHANGEABLE: 687 page4.cyl_ub = 0xff; 688 page4.cyl_mb = 0xff; 689 page4.cyl_lb = 0xff; 690 page4.heads = 0xff; 691 page4.rpm = 0xffff; 692 break; 693 } 694 695 (void) bcopy(&header, addr, sizeof (header)); 696 (void) bcopy(&page4, addr + sizeof (header), sizeof (page4)); 697 698 pkt->pkt_resid = sp->cmd_count - sizeof (page4) - sizeof (header); 699 rval = 0; 700 701 return (rval); 702 } 703 704 static int 705 bsd_mode_sense_dad_mode_err_recov(struct scsi_pkt *pkt) 706 { 707 struct emul64_cmd *sp = PKT2CMD(pkt); 708 union scsi_cdb *cdb = (union scsi_cdb *)pkt->pkt_cdbp; 709 uchar_t *addr = (uchar_t *)sp->cmd_addr; 710 int page_control; 711 struct mode_header header; 712 struct mode_err_recov page1; 713 int rval = 0; 714 715 page_control = (cdb->cdb_opaque[2] >> 6) & 0x03; 716 717 if (emul64debug) { 718 cmn_err(CE_CONT, "%s: bsd_mode_sense_dad_mode_err_recov: " 719 "pc=%d n=%d\n", emul64_name, page_control, sp->cmd_count); 720 } 721 722 if (sp->cmd_count < (sizeof (header) + sizeof (page1))) { 723 cmn_err(CE_CONT, "%s: bsd_mode_sense_dad_mode_err_recov: " 724 "size %d required\n", 725 emul64_name, (int)(sizeof (header) + sizeof (page1))); 726 return (EIO); 727 } 728 729 (void) bzero(&header, sizeof (header)); 730 (void) bzero(&page1, sizeof (page1)); 731 732 header.length = sizeof (header) + sizeof (page1) - 1; 733 header.bdesc_length = 0; 734 735 page1.mode_page.code = DAD_MODE_ERR_RECOV; 736 page1.mode_page.ps = 1; 737 page1.mode_page.length = sizeof (page1) - sizeof (struct mode_page); 738 739 switch (page_control) { 740 case MODE_SENSE_PC_CURRENT: 741 case MODE_SENSE_PC_DEFAULT: 742 case MODE_SENSE_PC_SAVED: 743 break; 744 case MODE_SENSE_PC_CHANGEABLE: 745 break; 746 } 747 748 (void) bcopy(&header, addr, sizeof (header)); 749 (void) bcopy(&page1, addr + sizeof (header), sizeof (page1)); 750 751 pkt->pkt_resid = sp->cmd_count - sizeof (page1) - sizeof (header); 752 rval = 0; 753 754 return (rval); 755 } 756 757 static int 758 bsd_mode_sense_modepage_disco_reco(struct scsi_pkt *pkt) 759 { 760 struct emul64_cmd *sp = PKT2CMD(pkt); 761 union scsi_cdb *cdb = (union scsi_cdb *)pkt->pkt_cdbp; 762 int rval = 0; 763 uchar_t *addr = (uchar_t *)sp->cmd_addr; 764 int page_control; 765 struct mode_header header; 766 struct mode_disco_reco page2; 767 768 page_control = (cdb->cdb_opaque[2] >> 6) & 0x03; 769 770 if (emul64debug) { 771 cmn_err(CE_CONT, "%s: bsd_mode_sense_modepage_disco_reco: " 772 "pc=%d n=%d\n", emul64_name, page_control, sp->cmd_count); 773 } 774 775 if (sp->cmd_count < (sizeof (header) + sizeof (page2))) { 776 cmn_err(CE_CONT, "%s: bsd_mode_sense_modepage_disco_reco: " 777 "size %d required\n", 778 emul64_name, (int)(sizeof (header) + sizeof (page2))); 779 return (EIO); 780 } 781 782 (void) bzero(&header, sizeof (header)); 783 (void) bzero(&page2, sizeof (page2)); 784 785 header.length = sizeof (header) + sizeof (page2) - 1; 786 header.bdesc_length = 0; 787 788 page2.mode_page.code = MODEPAGE_DISCO_RECO; 789 page2.mode_page.ps = 1; 790 page2.mode_page.length = sizeof (page2) - sizeof (struct mode_page); 791 792 switch (page_control) { 793 case MODE_SENSE_PC_CURRENT: 794 case MODE_SENSE_PC_DEFAULT: 795 case MODE_SENSE_PC_SAVED: 796 break; 797 case MODE_SENSE_PC_CHANGEABLE: 798 break; 799 } 800 801 (void) bcopy(&header, addr, sizeof (header)); 802 (void) bcopy(&page2, addr + sizeof (header), sizeof (page2)); 803 804 pkt->pkt_resid = sp->cmd_count - sizeof (page2) - sizeof (header); 805 rval = 0; 806 807 return (rval); 808 } 809 810 static int 811 bsd_mode_sense_dad_mode_format(struct scsi_pkt *pkt) 812 { 813 struct emul64_cmd *sp = PKT2CMD(pkt); 814 union scsi_cdb *cdb = (union scsi_cdb *)pkt->pkt_cdbp; 815 uchar_t *addr = (uchar_t *)sp->cmd_addr; 816 emul64_tgt_t *tgt; 817 int page_control; 818 struct mode_header header; 819 struct mode_format page3; 820 int rval = 0; 821 822 page_control = (cdb->cdb_opaque[2] >> 6) & 0x03; 823 824 if (emul64debug) { 825 cmn_err(CE_CONT, "%s: bsd_mode_sense_dad_mode_format: " 826 "pc=%d n=%d\n", emul64_name, page_control, sp->cmd_count); 827 } 828 829 if (sp->cmd_count < (sizeof (header) + sizeof (page3))) { 830 cmn_err(CE_CONT, "%s: bsd_mode_sense_dad_mode_format: " 831 "size %d required\n", 832 emul64_name, (int)(sizeof (header) + sizeof (page3))); 833 return (EIO); 834 } 835 836 (void) bzero(&header, sizeof (header)); 837 (void) bzero(&page3, sizeof (page3)); 838 839 header.length = sizeof (header) + sizeof (page3) - 1; 840 header.bdesc_length = 0; 841 842 page3.mode_page.code = DAD_MODE_FORMAT; 843 page3.mode_page.ps = 1; 844 page3.mode_page.length = sizeof (page3) - sizeof (struct mode_page); 845 846 switch (page_control) { 847 case MODE_SENSE_PC_CURRENT: 848 case MODE_SENSE_PC_DEFAULT: 849 case MODE_SENSE_PC_SAVED: 850 page3.data_bytes_sect = ushort_to_scsi_ushort(DEV_BSIZE); 851 page3.interleave = ushort_to_scsi_ushort(1); 852 EMUL64_MUTEX_ENTER(sp->cmd_emul64); 853 tgt = find_tgt(sp->cmd_emul64, 854 pkt->pkt_address.a_target, pkt->pkt_address.a_lun); 855 EMUL64_MUTEX_EXIT(sp->cmd_emul64); 856 page3.sect_track = ushort_to_scsi_ushort(tgt->emul64_tgt_nsect); 857 break; 858 case MODE_SENSE_PC_CHANGEABLE: 859 break; 860 } 861 862 (void) bcopy(&header, addr, sizeof (header)); 863 (void) bcopy(&page3, addr + sizeof (header), sizeof (page3)); 864 865 pkt->pkt_resid = sp->cmd_count - sizeof (page3) - sizeof (header); 866 rval = 0; 867 868 return (rval); 869 } 870 871 static int 872 bsd_mode_sense_dad_mode_cache(struct scsi_pkt *pkt) 873 { 874 struct emul64_cmd *sp = PKT2CMD(pkt); 875 union scsi_cdb *cdb = (union scsi_cdb *)pkt->pkt_cdbp; 876 uchar_t *addr = (uchar_t *)sp->cmd_addr; 877 int page_control; 878 struct mode_header header; 879 struct mode_cache page8; 880 int rval = 0; 881 882 page_control = (cdb->cdb_opaque[2] >> 6) & 0x03; 883 884 if (emul64debug) { 885 cmn_err(CE_CONT, "%s: bsd_mode_sense_dad_mode_cache: " 886 "pc=%d n=%d\n", emul64_name, page_control, sp->cmd_count); 887 } 888 889 if (sp->cmd_count < (sizeof (header) + sizeof (page8))) { 890 cmn_err(CE_CONT, "%s: bsd_mode_sense_dad_mode_cache: " 891 "size %d required\n", 892 emul64_name, (int)(sizeof (header) + sizeof (page8))); 893 return (EIO); 894 } 895 896 (void) bzero(&header, sizeof (header)); 897 (void) bzero(&page8, sizeof (page8)); 898 899 header.length = sizeof (header) + sizeof (page8) - 1; 900 header.bdesc_length = 0; 901 902 page8.mode_page.code = DAD_MODE_CACHE; 903 page8.mode_page.ps = 1; 904 page8.mode_page.length = sizeof (page8) - sizeof (struct mode_page); 905 906 switch (page_control) { 907 case MODE_SENSE_PC_CURRENT: 908 case MODE_SENSE_PC_DEFAULT: 909 case MODE_SENSE_PC_SAVED: 910 break; 911 case MODE_SENSE_PC_CHANGEABLE: 912 break; 913 } 914 915 (void) bcopy(&header, addr, sizeof (header)); 916 (void) bcopy(&page8, addr + sizeof (header), sizeof (page8)); 917 918 pkt->pkt_resid = sp->cmd_count - sizeof (page8) - sizeof (header); 919 rval = 0; 920 921 return (rval); 922 } 923 924 /* ARGSUSED 0 */ 925 int 926 bsd_scsi_mode_select(struct scsi_pkt *pkt) 927 { 928 return (0); 929 } 930 931 int 932 bsd_scsi_read_capacity_8(struct scsi_pkt *pkt) 933 { 934 struct emul64_cmd *sp = PKT2CMD(pkt); 935 emul64_tgt_t *tgt; 936 struct scsi_capacity cap; 937 int rval = 0; 938 939 EMUL64_MUTEX_ENTER(sp->cmd_emul64); 940 tgt = find_tgt(sp->cmd_emul64, 941 pkt->pkt_address.a_target, pkt->pkt_address.a_lun); 942 EMUL64_MUTEX_EXIT(sp->cmd_emul64); 943 if (tgt->emul64_tgt_sectors > 0xffffffff) 944 cap.capacity = 0xffffffff; 945 else 946 cap.capacity = 947 uint32_to_scsi_uint32(tgt->emul64_tgt_sectors); 948 cap.lbasize = uint32