1 /* 2 * This is /sys/src/cmd/scuzz/scsireq.c 3 * changed to add more debug support, to keep 4 * disk compiling without a scuzz that includes these changes. 5 * Also, this includes minor tweaks for usb: 6 * we set req.lun/unit to rp->lun/unit in SRreqsense 7 * we set the rp->sense[0] bit Sd0valid in SRreqsense 8 * This does not use libdisk to retrieve the scsi error to make 9 * user we see the diagnostics if we boot with debug enabled. 10 * 11 */ 12 13 #include <u.h> 14 #include <libc.h> 15 /* 16 * BUGS: 17 * no luns 18 * and incomplete in many other ways 19 */ 20 #include "scsireq.h" 21 22 enum { 23 Debug = 0, 24 }; 25 26 /* 27 * exabyte tape drives, at least old ones like the 8200 and 8505, 28 * are dumb: you have to read the exact block size on the tape, 29 * they don't take 10-byte SCSI commands, and various other fine points. 30 */ 31 extern int exabyte, force6bytecmds; 32 33 static int debug = Debug; 34 35 static char *scmdnames[256] = { 36 [ScmdTur] "Tur", 37 [ScmdRewind] "Rewind", 38 [ScmdRsense] "Rsense", 39 [ScmdFormat] "Format", 40 [ScmdRblimits] "Rblimits", 41 [ScmdRead] "Read", 42 [ScmdWrite] "Write", 43 [ScmdSeek] "Seek", 44 [ScmdFmark] "Fmark", 45 [ScmdSpace] "Space", 46 [ScmdInq] "Inq", 47 [ScmdMselect6] "Mselect6", 48 [ScmdMselect10] "Mselect10", 49 [ScmdMsense6] "Msense6", 50 [ScmdMsense10] "Msense10", 51 [ScmdStart] "Start", 52 [ScmdRcapacity] "Rcapacity", 53 [ScmdRcapacity16] "Rcap16", 54 [ScmdExtread] "Extread", 55 [ScmdExtwrite] "Extwrite", 56 [ScmdExtseek] "Extseek", 57 58 [ScmdSynccache] "Synccache", 59 [ScmdRTOC] "RTOC", 60 [ScmdRdiscinfo] "Rdiscinfo", 61 [ScmdRtrackinfo] "Rtrackinfo", 62 [ScmdReserve] "Reserve", 63 [ScmdBlank] "Blank", 64 65 [ScmdCDpause] "CDpause", 66 [ScmdCDstop] "CDstop", 67 [ScmdCDplay] "CDplay", 68 [ScmdCDload] "CDload", 69 [ScmdCDscan] "CDscan", 70 [ScmdCDstatus] "CDstatus", 71 [Scmdgetconf] "getconf", 72 }; 73 74 long 75 SRready(ScsiReq *rp) 76 { 77 uchar cmd[6]; 78 79 memset(cmd, 0, sizeof cmd); 80 rp->cmd.p = cmd; 81 rp->cmd.count = sizeof cmd; 82 rp->data.p = cmd; 83 rp->data.count = 0; 84 rp->data.write = 1; 85 return SRrequest(rp); 86 } 87 88 long 89 SRrewind(ScsiReq *rp) 90 { 91 uchar cmd[6]; 92 93 memset(cmd, 0, sizeof cmd); 94 cmd[0] = ScmdRewind; 95 rp->cmd.p = cmd; 96 rp->cmd.count = sizeof cmd; 97 rp->data.p = cmd; 98 rp->data.count = 0; 99 rp->data.write = 1; 100 if(SRrequest(rp) >= 0){ 101 rp->offset = 0; 102 return 0; 103 } 104 return -1; 105 } 106 107 long 108 SRreqsense(ScsiReq *rp) 109 { 110 uchar cmd[6]; 111 ScsiReq req; 112 long status; 113 114 if(rp->status == Status_SD){ 115 rp->status = STok; 116 return 0; 117 } 118 memset(cmd, 0, sizeof cmd); 119 cmd[0] = ScmdRsense; 120 cmd[4] = sizeof(req.sense); 121 memset(&req, 0, sizeof(req)); 122 if(rp->flags&Fusb) 123 req.flags |= Fusb; 124 req.lun = rp->lun; 125 req.unit = rp->unit; 126 req.fd = rp->fd; 127 req.umsc = rp->umsc; 128 req.cmd.p = cmd; 129 req.cmd.count = sizeof cmd; 130 req.data.p = rp->sense; 131 req.data.count = sizeof(rp->sense); 132 req.data.write = 0; 133 status = SRrequest(&req); 134 rp->status = req.status; 135 if(status != -1) 136 rp->sense[0] |= Sd0valid; 137 return status; 138 } 139 140 long 141 SRformat(ScsiReq *rp) 142 { 143 uchar cmd[6]; 144 145 memset(cmd, 0, sizeof cmd); 146 cmd[0] = ScmdFormat; 147 rp->cmd.p = cmd; 148 rp->cmd.count = sizeof cmd; 149 rp->data.p = cmd; 150 rp->data.count = 6; 151 rp->data.write = 0; 152 return SRrequest(rp); 153 } 154 155 long 156 SRrblimits(ScsiReq *rp, uchar *list) 157 { 158 uchar cmd[6]; 159 160 memset(cmd, 0, sizeof cmd); 161 cmd[0] = ScmdRblimits; 162 rp->cmd.p = cmd; 163 rp->cmd.count = sizeof cmd; 164 rp->data.p = list; 165 rp->data.count = 6; 166 rp->data.write = 0; 167 return SRrequest(rp); 168 } 169 170 static int 171 dirdevrw(ScsiReq *rp, uchar *cmd, long nbytes) 172 { 173 long n; 174 175 n = nbytes / rp->lbsize; 176 if(rp->offset <= Max24off && n <= 256 && (rp->flags & Frw10) == 0){ 177 PUTBE24(cmd+1, rp->offset); 178 cmd[4] = n; 179 cmd[5] = 0; 180 return 6; 181 } 182 cmd[0] |= ScmdExtread; 183 cmd[1] = 0; 184 PUTBELONG(cmd+2, rp->offset); 185 cmd[6] = 0; 186 cmd[7] = n>>8; 187 cmd[8] = n; 188 cmd[9] = 0; 189 return 10; 190 } 191 192 static int 193 seqdevrw(ScsiReq *rp, uchar *cmd, long nbytes) 194 { 195 long n; 196 197 /* don't set Cmd1sili; we want the ILI bit instead of a fatal error */ 198 cmd[1] = rp->flags&Fbfixed? Cmd1fixed: 0; 199 n = nbytes / rp->lbsize; 200 PUTBE24(cmd+2, n); 201 cmd[5] = 0; 202 return 6; 203 } 204 205 long 206 SRread(ScsiReq *rp, void *buf, long nbytes) 207 { 208 uchar cmd[10]; 209 long n; 210 211 if((nbytes % rp->lbsize) || nbytes > maxiosize){ 212 rp->status = Status_BADARG; 213 return -1; 214 } 215 216 /* set up scsi read cmd */ 217 cmd[0] = ScmdRead; 218 if(rp->flags & Fseqdev) 219 rp->cmd.count = seqdevrw(rp, cmd, nbytes); 220 else 221 rp->cmd.count = dirdevrw(rp, cmd, nbytes); 222 rp->cmd.p = cmd; 223 rp->data.p = buf; 224 rp->data.count = nbytes; 225 rp->data.write = 0; 226 227 /* issue it */ 228 n = SRrequest(rp); 229 if(n != -1){ /* it worked? */ 230 rp->offset += n / rp->lbsize; 231 return n; 232 } 233 234 /* request failed; maybe we just read a short record? */ 235 if (exabyte) { 236 fprint(2, "read error\n"); 237 rp->status = STcheck; 238 return n; 239 } 240 if(rp->status != Status_SD || !(rp->sense[0] & Sd0valid)) 241 return -1; 242 /* compute # of bytes not read */ 243 n = GETBELONG(rp->sense+3) * rp->lbsize; 244 if(!(rp->flags & Fseqdev)) 245 return -1; 246 247 /* device is a tape or something similar */ 248 if (rp->sense[2] == Sd2filemark || rp->sense[2] == 0x08 || 249 rp->sense[2] & Sd2ili && n > 0) 250 rp->data.count = nbytes - n; 251 else 252 return -1; 253 n = rp->data.count; 254 if (!rp->readblock++ || debug) 255 fprint(2, "SRread: tape data count %ld%s\n", n, 256 (rp->sense[2] & Sd2ili? " with ILI": "")); 257 rp->status = STok; 258 rp->offset += n / rp->lbsize; 259 return n; 260 } 261 262 long 263 SRwrite(ScsiReq *rp, void *buf, long nbytes) 264 { 265 uchar cmd[10]; 266 long n; 267 268 if((nbytes % rp->lbsize) || nbytes > maxiosize){ 269 rp->status = Status_BADARG; 270 return -1; 271 } 272 273 /* set up scsi write cmd */ 274 cmd[0] = ScmdWrite; 275 if(rp->flags & Fseqdev) 276 rp->cmd.count = seqdevrw(rp, cmd, nbytes); 277 else 278 rp->cmd.count = dirdevrw(rp, cmd, nbytes); 279 rp->cmd.p = cmd; 280 rp->data.p = buf; 281 rp->data.count = nbytes; 282 rp->data.write = 1; 283 284 /* issue it */ 285 if((n = SRrequest(rp)) == -1){ 286 if (exabyte) { 287 fprint(2, "write error\n"); 288 rp->status = STcheck; 289 return n; 290 } 291 if(rp->status != Status_SD || rp->sense[2] != Sd2eom) 292 return -1; 293 if(rp->sense[0] & Sd0valid){ 294 n -= GETBELONG(rp->sense+3) * rp->lbsize; 295 rp->data.count = nbytes - n; 296 } 297 else 298 rp->data.count = nbytes; 299 n = rp->data.count; 300 } 301 rp->offset += n / rp->lbsize; 302 return n; 303 } 304 305 long 306 SRseek(ScsiReq *rp, long offset, int type) 307 { 308 uchar cmd[10]; 309 310 switch(type){ 311 312 case 0: 313 break; 314 315 case 1: 316 offset += rp->offset; 317 if(offset >= 0) 318 break; 319 /*FALLTHROUGH*/ 320 321 default: 322 rp->status = Status_BADARG; 323 return -1; 324 } 325 memset(cmd, 0, sizeof cmd); 326 if(offset <= Max24off && (rp->flags & Frw10) == 0){ 327 cmd[0] = ScmdSeek; 328 PUTBE24(cmd+1, offset & Max24off); 329 rp->cmd.count = 6; 330 }else{ 331 cmd[0] = ScmdExtseek; 332 PUTBELONG(cmd+2, offset); 333 rp->cmd.count = 10; 334 } 335 rp->cmd.p = cmd; 336 rp->data.p = cmd; 337 rp->data.count = 0; 338 rp->data.write = 1; 339 SRrequest(rp); 340 if(rp->status == STok) 341 return rp->offset = offset; 342 return -1; 343 } 344 345 long 346 SRfilemark(ScsiReq *rp, ulong howmany) 347 { 348 uchar cmd[6]; 349 350 memset(cmd, 0, sizeof cmd); 351 cmd[0] = ScmdFmark; 352 PUTBE24(cmd+2, howmany); 353 rp->cmd.p = cmd; 354 rp->cmd.count = sizeof cmd; 355 rp->data.p = cmd; 356 rp->data.count = 0; 357 rp->data.write = 1; 358 return SRrequest(rp); 359 } 360 361 long 362 SRspace(ScsiReq *rp, uchar code, long howmany) 363 { 364 uchar cmd[6]; 365 366 memset(cmd, 0, sizeof cmd); 367 cmd[0] = ScmdSpace; 368 cmd[1] = code; 369 PUTBE24(cmd+2, howmany); 370 rp->cmd.p = cmd; 371 rp->cmd.count = sizeof cmd; 372 rp->data.p = cmd; 373 rp->data.count = 0; 374 rp->data.write = 1; 375 /* 376 * what about rp->offset? 377 */ 378 return SRrequest(rp); 379 } 380 381 long 382 SRinquiry(ScsiReq *rp) 383 { 384 uchar cmd[6]; 385 386 memset(cmd, 0, sizeof cmd); 387 cmd[0] = ScmdInq; 388 cmd[4] = sizeof rp->inquiry; 389 rp->cmd.p = cmd; 390 rp->cmd.count = sizeof cmd; 391 memset(rp->inquiry, 0, sizeof rp->inquiry); 392 rp->data.p = rp->inquiry; 393 rp->data.count = sizeof rp->inquiry; 394 rp->data.write = 0; 395 if(SRrequest(rp) >= 0){ 396 rp->flags |= Finqok; 397 return 0; 398 } 399 rp->flags &= ~Finqok; 400 return -1; 401 } 402 403 long 404 SRmodeselect6(ScsiReq *rp, uchar *list, long nbytes) 405 { 406 uchar cmd[6]; 407 408 memset(cmd, 0, sizeof cmd); 409 cmd[0] = ScmdMselect6; 410 if((rp->flags & Finqok) && (rp->inquiry[2] & 0x07) >= 2) 411 cmd[1] = 0x10; 412 cmd[4] = nbytes; 413 rp->cmd.p = cmd; 414 rp->cmd.count = sizeof cmd; 415 rp->data.p = list; 416 rp->data.count = nbytes; 417 rp->data.write = 1; 418 return SRrequest(rp); 419 } 420 421 long 422 SRmodeselect10(ScsiReq *rp, uchar *list, long nbytes) 423 { 424 uchar cmd[10]; 425 426 memset(cmd, 0, sizeof cmd); 427 if((rp->flags & Finqok) && (rp->inquiry[2] & 0x07) >= 2) 428 cmd[1] = 0x10; 429 cmd[0] = ScmdMselect10; 430 cmd[7] = nbytes>>8; 431 cmd[8] = nbytes; 432 rp->cmd.p = cmd; 433 rp->cmd.count = sizeof cmd; 434 rp->data.p = list; 435 rp->data.count = nbytes; 436 rp->data.write = 1; 437 return SRrequest(rp); 438 } 439 440 long 441 SRmodesense6(ScsiReq *rp, uchar page, uchar *list, long nbytes) 442 { 443 uchar cmd[6]; 444 445 memset(cmd, 0, sizeof cmd); 446 cmd[0] = ScmdMsense6; 447 cmd[2] = page; 448 cmd[4] = nbytes; 449 rp->cmd.p = cmd; 450 rp->cmd.count = sizeof cmd; 451 rp->data.p = list; 452 rp->data.count = nbytes; 453 rp->data.write = 0; 454 return SRrequest(rp); 455 } 456 457 long 458 SRmodesense10(ScsiReq *rp, uchar page, uchar *list, long nbytes) 459 { 460 uchar cmd[10]; 461 462 memset(cmd, 0, sizeof cmd); 463 cmd[0] = ScmdMsense10; 464 cmd[2] = page; 465 cmd[7] = nbytes>>8; 466 cmd[8] = nbytes; 467 rp->cmd.p = cmd; 468 rp->cmd.count = sizeof cmd; 469 rp->data.p = list; 470 rp->data.count = nbytes; 471 rp->data.write = 0; 472 return SRrequest(rp); 473 } 474 475 long 476 SRstart(ScsiReq *rp, uchar code) 477 { 478 uchar cmd[6]; 479 480 memset(cmd, 0, sizeof cmd); 481 cmd[0] = ScmdStart; 482 cmd[4] = code; 483 rp->cmd.p = cmd; 484 rp->cmd.count = sizeof cmd; 485 rp->data.p = cmd; 486 rp->data.count = 0; 487 rp->data.write = 1; 488 return SRrequest(rp); 489 } 490 491 long 492 SRrcapacity(ScsiReq *rp, uchar *data) 493 { 494 uchar cmd[10]; 495 496 memset(cmd, 0, sizeof cmd); 497 cmd[0] = ScmdRcapacity; 498 rp->cmd.p = cmd; 499 rp->cmd.count = sizeof cmd; 500 rp->data.p = data; 501 rp->data.count = 8; 502 rp->data.write = 0; 503 return SRrequest(rp); 504 } 505 506 long 507 SRrcapacity16(ScsiReq *rp, uchar *data) 508 { 509 uchar cmd[16]; 510 uint i; 511 512 i = 32; 513 memset(cmd, 0, sizeof cmd); 514 cmd[0] = ScmdRcapacity16; 515 cmd[1] = 0x10; 516 cmd[10] = i>>24; 517 cmd[11] = i>>16; 518 cmd[12] = i>>8; 519 cmd[13] = i; 520 521 rp->cmd.p = cmd; 522 rp->cmd.count = sizeof cmd; 523 rp->data.p = data; 524 rp->data.count = i; 525 rp->data.write = 0; 526 return SRrequest(rp); 527 } 528 529 void 530 scsidebug(int d) 531 { 532 debug = d; 533 if(debug) 534 fprint(2, "scsidebug on\n"); 535 } 536 537 static long 538 request(int fd, ScsiPtr *cmd, ScsiPtr *data, int *status) 539 { 540 long n, r; 541 char buf[16]; 542 543 /* this was an experiment but it seems to be a good idea */ 544 *status = STok; 545 546 /* send SCSI command */ 547 if(write(fd, cmd->p, cmd->count) != cmd->count){ 548 fprint(2, "scsireq: write cmd: %r\n"); 549 *status = Status_SW; 550 return -1; 551 } 552 553 /* read or write actual data */ 554 werrstr(""); 555 if(data->write) 556 n = write(fd, data->p, data->count); 557 else { 558 n = read(fd, data->p, data->count); 559 if (n < 0) 560 memset(data->p, 0, data->count); 561 else if (n < data->count) 562 memset(data->p + n, 0, data->count - n); 563 } 564 if (n != data->count && n <= 0) { 565 if (debug) 566 fprint(2, 567 "request: tried to %s %ld bytes of data for cmd 0x%x but got %r\n", 568 (data->write? "write": "read"), 569 data->count, cmd->p[0]); 570 } else if (n != data->count && (data->write || debug)) 571 fprint(2, "request: %s %ld of %ld bytes of actual data\n", 572 (data->write? "wrote": "read"), n, data->count); 573 574 /* read status */ 575 buf[0] = '\0'; 576 r = read(fd, buf, sizeof buf-1); 577 if(exabyte && r <= 0 || !exabyte && r < 0){ 578 fprint(2, "scsireq: read status: %r\n"); 579 *status = Status_SW; 580 return -1; 581 } 582 if (r >= 0) 583 buf[r] = '\0'; 584 *status = atoi(buf); 585 if(n < 0 && (exabyte || *status != STcheck)) 586 fprint(2, "scsireq: status 0x%2.2uX: data transfer: %r\n", 587 *status); 588 return n; 589 } 590 591 static char* 592 seprintcmd(char *s, char* e, char *cmd, int count, int args) 593 { 594 uint c; 595 596 if(count < 6) 597 return seprint(s, e, "<short cmd>"); 598 c = cmd[0]; 599 if(scmdnames[c] != nil) 600 s = seprint(s, e, "%s", scmdnames[c]); 601 else 602 s = seprint(s, e, "cmd:%#02uX", c); 603 if(args != 0) 604 switch(c){ 605 case ScmdRsense: 606 case ScmdInq: 607 case ScmdMselect6: 608 case ScmdMsense6: 609 s = seprint(s, e, " sz %d", cmd[4]); 610 break; 611 case ScmdSpace: 612 s = seprint(s, e, " code %d", cmd[1]); 613 break; 614 case ScmdStart: 615 s = seprint(s, e, " code %d", cmd[4]); 616 break; 617 618 } 619 return s; 620 } 621 622 static char* 623 seprintdata(char *s, char *se, uchar *p, int count) 624 { 625 int i; 626 627 if(count == 0) 628 return s; 629 for(i = 0; i < 20 && i < count; i++) 630 s = seprint(s, se, " %02x", p[i]); 631 return s; 632 } 633 634 static void 635 SRdumpReq(ScsiReq *rp) 636 { 637 char buf[128]; 638 char *s; 639 char *se; 640 641 se = buf+sizeof(buf); 642 s = seprint(buf, se, "lun %d ", rp->lun); 643 s = seprintcmd(s, se, (char*)rp->cmd.p, rp->cmd.count, 1); 644 s = seprint(s, se, " [%ld]", rp->data.count); 645 if(rp->cmd.write) 646 seprintdata(s, se, rp->data.p, rp->data.count); 647 fprint(2, "scsi⇒ %s\n", buf); 648 } 649 650 static void 651 SRdumpRep(ScsiReq *rp) 652 { 653 char buf[128]; 654 char *s; 655 char *se; 656 657 se = buf+sizeof(buf); 658 s = seprint(buf, se, "lun %d ", rp->lun); 659 s = seprintcmd(s, se, (char*)rp->cmd.p, rp->cmd.count, 0); 660 switch(rp->status){ 661 case STok: 662 s = seprint(s, se, " good [%ld] ", rp->data.count); 663 if(rp->cmd.write == 0) 664 s = seprintdata(s, se, rp->data.p, rp->data.count); 665 break; 666 case STnomem: 667 s = seprint(s, se, " buffer allocation failed"); 668 break; 669 case STharderr: 670 s = seprint(s, se, " controller error"); 671 break; 672 case STtimeout: 673 s = seprint(s, se, " bus timeout"); 674 break; 675 case STcheck: 676 s = seprint(s, se, " check condition"); 677 break; 678 case STcondmet: 679 s = seprint(s, se, " condition met/good"); 680 break; 681 case STbusy: 682 s = seprint(s, se, " busy"); 683 break; 684 case STintok: 685 s = seprint(s, se, " intermediate/good"); 686 break; 687 case STintcondmet: 688 s = seprint(s, se, " intermediate/condition met/good"); 689 break; 690 case STresconf: 691 s = seprint(s, se, " reservation conflict"); 692 break; 693 case STterminated: 694 s = seprint(s, se, " command terminated"); 695 break; 696 case STqfull: 697 s = seprint(s, se, " queue full"); 698 break; 699 default: 700 s = seprint(s, se, " sts=%#x", rp->status); 701 } 702 USED(s); 703 fprint(2, "scsi← %s\n", buf); 704 } 705 706 static char* 707 scsierr(ScsiReq *rp) 708 { 709 int ec; 710 711 switch(rp->status){ 712 case 0: 713 return ""; 714 case Status_SD: 715 ec = (rp->sense[12] << 8) | rp->sense[13]; 716 return scsierrmsg(ec); 717 case Status_SW: 718 return "software error"; 719 case Status_BADARG: 720 return "bad argument"; 721 case Status_RO: 722 return "device is read only"; 723 default: 724 return "unknown"; 725 } 726 } 727 728 static void 729 SRdumpErr(ScsiReq *rp) 730 { 731 char buf[128]; 732 char *se; 733 734 se = buf+sizeof(buf); 735 seprintcmd(buf, se, (char*)rp->cmd.p, rp->cmd.count, 0); 736 print("\t%s status: %s\n", buf, scsierr(rp)); 737 } 738 739 long 740 SRrequest(ScsiReq *rp) 741 { 742 long n; 743 int status; 744 745 retry: 746 if(debug) 747 SRdumpReq(rp); 748 if(rp->flags&Fusb) 749 n = umsrequest(rp->umsc, &rp->cmd, &rp->data, &status); 750 else 751 n = request(rp->fd, &rp->cmd, &rp->data, &status); 752 rp->status = status; 753 if(status == STok) 754 rp->data.count = n; 755 if(debug) 756 SRdumpRep(rp); 757 switch(status){ 758 case STok: 759 break; 760 case STcheck: 761 if(rp->cmd.p[0] != ScmdRsense && SRreqsense(rp) != -1) 762 rp->status = Status_SD; 763 if(debug || exabyte) 764 SRdumpErr(rp); 765 werrstr("%s", scsierr(rp)); 766 return -1; 767 case STbusy: 768 sleep(1000); 769 goto retry; 770 default: 771 if(debug || exabyte) 772 SRdumpErr(rp); 773 werrstr("%s", scsierr(rp)); 774 return -1; 775 } 776 return n; 777 } 778 779 int 780 SRclose(ScsiReq *rp) 781 { 782 if((rp->flags & Fopen) == 0){ 783 rp->status = Status_BADARG; 784 return -1; 785 } 786 close(rp->fd); 787 rp->flags = 0; 788 return 0; 789 } 790 791 static int 792 dirdevopen(ScsiReq *rp) 793 { 794 ulong blocks; 795 uchar data[8]; 796 797 if(SRstart(rp, 1) == -1 || SRrcapacity(rp, data) == -1) 798 return -1; 799 rp->lbsize = GETBELONG(data+4); 800 blocks = GETBELONG(data); 801 if(blocks == 0xffffffff){ 802 if(SRrcapacity16(rp, data) == -1) 803 return -1; 804 rp->lbsize = GETBELONG(data + 8); 805 blocks = (vlong)GETBELONG(data)<<32 | GETBELONG(data + 4); 806 } 807 /* some newer dev's don't support 6-byte commands */ 808 if(blocks > Max24off && !force6bytecmds) 809 rp->flags |= Frw10; 810 return 0; 811 } 812 813 static int 814 seqdevopen(ScsiReq *rp) 815 { 816 uchar mode[16], limits[6]; 817 818 if(SRrblimits(rp, limits) == -1) 819 return -1; 820 if(limits[1] == 0 && limits[2] == limits[4] && limits[3] == limits[5]){ 821 rp->flags |= Fbfixed; 822 rp->lbsize = limits[4]<<8 | limits[5]; 823 return 0; 824 } 825 /* 826 * On some older hardware the optional 10-byte 827 * modeselect command isn't implemented. 828 */ 829 if (force6bytecmds) 830 rp->flags |= Fmode6; 831 if(!(rp->flags & Fmode6)){ 832 /* try 10-byte command first */ 833 memset(mode, 0, sizeof mode); 834 mode[3] = 0x10; /* device-specific param. */ 835 mode[7] = 8; /* block descriptor length */ 836 /* 837 * exabytes can't handle this, and 838 * modeselect(10) is optional. 839 */ 840 if(SRmodeselect10(rp, mode, sizeof mode) != -1){ 841 rp->lbsize = 1; 842 return 0; /* success */ 843 } 844 /* can't do 10-byte commands, back off to 6-byte ones */ 845 rp->flags |= Fmode6; 846 } 847 848 /* 6-byte command */ 849 memset(mode, 0, sizeof mode); 850 mode[2] = 0x10; /* device-specific param. */ 851 mode[3] = 8; /* block descriptor length */ 852 /* 853 * bsd sez exabytes need this bit (NBE: no busy enable) in 854 * vendor-specific page (0), but so far we haven't needed it. 855 mode[12] |= 8; 856 */ 857 if(SRmodeselect6(rp, mode, 4+8) == -1) 858 return -1; 859 rp->lbsize = 1; 860 return 0; 861 } 862 863 static int 864 wormdevopen(ScsiReq *rp) 865 { 866 long status; 867 uchar list[MaxDirData]; 868 869 if (SRstart(rp, 1) == -1 || 870 (status = SRmodesense10(rp, Allmodepages, list, sizeof list)) == -1) 871 return -1; 872 /* nbytes = list[0]<<8 | list[1]; */ 873 874 /* # of bytes of block descriptors of 8 bytes each; not even 1? */ 875 if((list[6]<<8 | list[7]) < 8) 876 rp->lbsize = 2048; 877 else 878 /* last 3 bytes of block 0 descriptor */ 879 rp->lbsize = GETBE24(list+13); 880 return status; 881 } 882 883 int 884 SRopenraw(ScsiReq *rp, char *unit) 885 { 886 char name[128]; 887 888 if(rp->flags & Fopen){ 889 rp->status = Status_BADARG; 890 return -1; 891 } 892 memset(rp, 0, sizeof *rp); 893 rp->unit = unit; 894 895 sprint(name, "%s/raw", unit); 896 897 if((rp->fd = open(name, ORDWR)) == -1){ 898 rp->status = STtimeout; 899 return -1; 900 } 901 rp->flags = Fopen; 902 return 0; 903 } 904 905 int 906 SRopen(ScsiReq *rp, char *unit) 907 { 908 if(SRopenraw(rp, unit) == -1) 909 return -1; 910 SRready(rp); 911 if(SRinquiry(rp) >= 0){ 912 switch(rp->inquiry[0]){ 913 914 default: 915 fprint(2, "unknown device type 0x%.2x\n", rp->inquiry[0]); 916 rp->status = Status_SW; 917 break; 918 919 case Devdir: 920 case Devcd: 921 case Devmo: 922 if(dirdevopen(rp) == -1) 923 break; 924 return 0; 925 926 case Devseq: 927 rp->flags |= Fseqdev; 928 if(seqdevopen(rp) == -1) 929 break; 930 return 0; 931 932 case Devprint: 933 rp->flags |= Fprintdev; 934 return 0; 935 936 case Devworm: 937 rp->flags |= Fwormdev; 938 if(wormdevopen(rp) == -1) 939 break; 940 return 0; 941 942 case Devjuke: 943 rp->flags |= Fchanger; 944 return 0; 945 } 946 } 947 SRclose(rp); 948 return -1; 949 } 950