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 see the diagnostics if we boot with debug enabled. 10 * 11 * BUGS: 12 * no luns 13 * and incomplete in many other ways 14 */ 15 16 #include <u.h> 17 #include <libc.h> 18 #include <fcall.h> 19 #include <disk.h> 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 extern int diskdebug; 206 207 long 208 SRread(ScsiReq *rp, void *buf, long nbytes) 209 { 210 uchar cmd[10]; 211 long n; 212 213 if(rp->lbsize == 0 || (nbytes % rp->lbsize) || nbytes > Maxiosize){ 214 if(diskdebug) 215 if (nbytes % rp->lbsize) 216 fprint(2, "disk: i/o size %ld %% %ld != 0\n", 217 nbytes, rp->lbsize); 218 else 219 fprint(2, "disk: i/o size %ld > %d\n", 220 nbytes, Maxiosize); 221 rp->status = Status_BADARG; 222 return -1; 223 } 224 225 /* set up scsi read cmd */ 226 cmd[0] = ScmdRead; 227 if(rp->flags & Fseqdev) 228 rp->cmd.count = seqdevrw(rp, cmd, nbytes); 229 else 230 rp->cmd.count = dirdevrw(rp, cmd, nbytes); 231 rp->cmd.p = cmd; 232 rp->data.p = buf; 233 rp->data.count = nbytes; 234 rp->data.write = 0; 235 236 /* issue it */ 237 n = SRrequest(rp); 238 if(n != -1){ /* it worked? */ 239 rp->offset += n / rp->lbsize; 240 return n; 241 } 242 243 /* request failed; maybe we just read a short record? */ 244 if (exabyte) { 245 fprint(2, "read error\n"); 246 rp->status = STcheck; 247 return n; 248 } 249 if(rp->status != Status_SD || !(rp->sense[0] & Sd0valid)) 250 return -1; 251 /* compute # of bytes not read */ 252 n = GETBELONG(rp->sense+3) * rp->lbsize; 253 if(!(rp->flags & Fseqdev)) 254 return -1; 255 256 /* device is a tape or something similar */ 257 if (rp->sense[2] == Sd2filemark || rp->sense[2] == 0x08 || 258 rp->sense[2] & Sd2ili && n > 0) 259 rp->data.count = nbytes - n; 260 else 261 return -1; 262 n = rp->data.count; 263 if (!rp->readblock++ || debug) 264 fprint(2, "SRread: tape data count %ld%s\n", n, 265 (rp->sense[2] & Sd2ili? " with ILI": "")); 266 rp->status = STok; 267 rp->offset += n / rp->lbsize; 268 return n; 269 } 270 271 long 272 SRwrite(ScsiReq *rp, void *buf, long nbytes) 273 { 274 uchar cmd[10]; 275 long n; 276 277 if(rp->lbsize == 0 || (nbytes % rp->lbsize) || nbytes > Maxiosize){ 278 if(diskdebug) 279 if (nbytes % rp->lbsize) 280 fprint(2, "disk: i/o size %ld %% %ld != 0\n", 281 nbytes, rp->lbsize); 282 else 283 fprint(2, "disk: i/o size %ld > %d\n", 284 nbytes, Maxiosize); 285 rp->status = Status_BADARG; 286 return -1; 287 } 288 289 /* set up scsi write cmd */ 290 cmd[0] = ScmdWrite; 291 if(rp->flags & Fseqdev) 292 rp->cmd.count = seqdevrw(rp, cmd, nbytes); 293 else 294 rp->cmd.count = dirdevrw(rp, cmd, nbytes); 295 rp->cmd.p = cmd; 296 rp->data.p = buf; 297 rp->data.count = nbytes; 298 rp->data.write = 1; 299 300 /* issue it */ 301 if((n = SRrequest(rp)) == -1){ 302 if (exabyte) { 303 fprint(2, "write error\n"); 304 rp->status = STcheck; 305 return n; 306 } 307 if(rp->status != Status_SD || rp->sense[2] != Sd2eom) 308 return -1; 309 if(rp->sense[0] & Sd0valid){ 310 n -= GETBELONG(rp->sense+3) * rp->lbsize; 311 rp->data.count = nbytes - n; 312 } 313 else 314 rp->data.count = nbytes; 315 n = rp->data.count; 316 } 317 rp->offset += n / rp->lbsize; 318 return n; 319 } 320 321 long 322 SRseek(ScsiReq *rp, long offset, int type) 323 { 324 uchar cmd[10]; 325 326 switch(type){ 327 328 case 0: 329 break; 330 331 case 1: 332 offset += rp->offset; 333 if(offset >= 0) 334 break; 335 /*FALLTHROUGH*/ 336 337 default: 338 if(diskdebug) 339 fprint(2, "disk: seek failed\n"); 340 rp->status = Status_BADARG; 341 return -1; 342 } 343 memset(cmd, 0, sizeof cmd); 344 if(offset <= Max24off && (rp->flags & Frw10) == 0){ 345 cmd[0] = ScmdSeek; 346 PUTBE24(cmd+1, offset & Max24off); 347 rp->cmd.count = 6; 348 }else{ 349 cmd[0] = ScmdExtseek; 350 PUTBELONG(cmd+2, offset); 351 rp->cmd.count = 10; 352 } 353 rp->cmd.p = cmd; 354 rp->data.p = cmd; 355 rp->data.count = 0; 356 rp->data.write = 1; 357 SRrequest(rp); 358 if(rp->status == STok) { 359 rp->offset = offset; 360 return offset; 361 } 362 return -1; 363 } 364 365 long 366 SRfilemark(ScsiReq *rp, ulong howmany) 367 { 368 uchar cmd[6]; 369 370 memset(cmd, 0, sizeof cmd); 371 cmd[0] = ScmdFmark; 372 PUTBE24(cmd+2, howmany); 373 rp->cmd.p = cmd; 374 rp->cmd.count = sizeof cmd; 375 rp->data.p = cmd; 376 rp->data.count = 0; 377 rp->data.write = 1; 378 return SRrequest(rp); 379 } 380 381 long 382 SRspace(ScsiReq *rp, uchar code, long howmany) 383 { 384 uchar cmd[6]; 385 386 memset(cmd, 0, sizeof cmd); 387 cmd[0] = ScmdSpace; 388 cmd[1] = code; 389 PUTBE24(cmd+2, howmany); 390 rp->cmd.p = cmd; 391 rp->cmd.count = sizeof cmd; 392 rp->data.p = cmd; 393 rp->data.count = 0; 394 rp->data.write = 1; 395 /* 396 * what about rp->offset? 397 */ 398 return SRrequest(rp); 399 } 400 401 long 402 SRinquiry(ScsiReq *rp) 403 { 404 uchar cmd[6]; 405 406 memset(cmd, 0, sizeof cmd); 407 cmd[0] = ScmdInq; 408 cmd[4] = sizeof rp->inquiry; 409 rp->cmd.p = cmd; 410 rp->cmd.count = sizeof cmd; 411 memset(rp->inquiry, 0, sizeof rp->inquiry); 412 rp->data.p = rp->inquiry; 413 rp->data.count = sizeof rp->inquiry; 414 rp->data.write = 0; 415 if(SRrequest(rp) >= 0){ 416 rp->flags |= Finqok; 417 return 0; 418 } 419 rp->flags &= ~Finqok; 420 return -1; 421 } 422 423 long 424 SRmodeselect6(ScsiReq *rp, uchar *list, long nbytes) 425 { 426 uchar cmd[6]; 427 428 memset(cmd, 0, sizeof cmd); 429 cmd[0] = ScmdMselect6; 430 if((rp->flags & Finqok) && (rp->inquiry[2] & 0x07) >= 2) 431 cmd[1] = 0x10; 432 cmd[4] = nbytes; 433 rp->cmd.p = cmd; 434 rp->cmd.count = sizeof cmd; 435 rp->data.p = list; 436 rp->data.count = nbytes; 437 rp->data.write = 1; 438 return SRrequest(rp); 439 } 440 441 long 442 SRmodeselect10(ScsiReq *rp, uchar *list, long nbytes) 443 { 444 uchar cmd[10]; 445 446 memset(cmd, 0, sizeof cmd); 447 if((rp->flags & Finqok) && (rp->inquiry[2] & 0x07) >= 2) 448 cmd[1] = 0x10; 449 cmd[0] = ScmdMselect10; 450 cmd[7] = nbytes>>8; 451 cmd[8] = nbytes; 452 rp->cmd.p = cmd; 453 rp->cmd.count = sizeof cmd; 454 rp->data.p = list; 455 rp->data.count = nbytes; 456 rp->data.write = 1; 457 return SRrequest(rp); 458 } 459 460 long 461 SRmodesense6(ScsiReq *rp, uchar page, uchar *list, long nbytes) 462 { 463 uchar cmd[6]; 464 465 memset(cmd, 0, sizeof cmd); 466 cmd[0] = ScmdMsense6; 467 cmd[2] = page; 468 cmd[4] = nbytes; 469 rp->cmd.p = cmd; 470 rp->cmd.count = sizeof cmd; 471 rp->data.p = list; 472 rp->data.count = nbytes; 473 rp->data.write = 0; 474 return SRrequest(rp); 475 } 476 477 long 478 SRmodesense10(ScsiReq *rp, uchar page, uchar *list, long nbytes) 479 { 480 uchar cmd[10]; 481 482 memset(cmd, 0, sizeof cmd); 483 cmd[0] = ScmdMsense10; 484 cmd[2] = page; 485 cmd[7] = nbytes>>8; 486 cmd[8] = nbytes; 487 rp->cmd.p = cmd; 488 rp->cmd.count = sizeof cmd; 489 rp->data.p = list; 490 rp->data.count = nbytes; 491 rp->data.write = 0; 492 return SRrequest(rp); 493 } 494 495 long 496 SRstart(ScsiReq *rp, uchar code) 497 { 498 uchar cmd[6]; 499 500 memset(cmd, 0, sizeof cmd); 501 cmd[0] = ScmdStart; 502 cmd[4] = code; 503 rp->cmd.p = cmd; 504 rp->cmd.count = sizeof cmd; 505 rp->data.p = cmd; 506 rp->data.count = 0; 507 rp->data.write = 1; 508 return SRrequest(rp); 509 } 510 511 long 512 SRrcapacity(ScsiReq *rp, uchar *data) 513 { 514 uchar cmd[10]; 515 516 memset(cmd, 0, sizeof cmd); 517 cmd[0] = ScmdRcapacity; 518 rp->cmd.p = cmd; 519 rp->cmd.count = sizeof cmd; 520 rp->data.p = data; 521 rp->data.count = 8; 522 rp->data.write = 0; 523 return SRrequest(rp); 524 } 525 526 long 527 SRrcapacity16(ScsiReq *rp, uchar *data) 528 { 529 uchar cmd[16]; 530 uint i; 531 532 i = 32; 533 memset(cmd, 0, sizeof cmd); 534 cmd[0] = ScmdRcapacity16; 535 cmd[1] = 0x10; 536 cmd[10] = i>>24; 537 cmd[11] = i>>16; 538 cmd[12] = i>>8; 539 cmd[13] = i; 540 541 rp->cmd.p = cmd; 542 rp->cmd.count = sizeof cmd; 543 rp->data.p = data; 544 rp->data.count = i; 545 rp->data.write = 0; 546 return SRrequest(rp); 547 } 548 549 void 550 scsidebug(int d) 551 { 552 debug = d; 553 if(debug) 554 fprint(2, "scsidebug on\n"); 555 } 556 557 static long 558 request(int fd, ScsiPtr *cmd, ScsiPtr *data, int *status) 559 { 560 long n, r; 561 char buf[16]; 562 563 /* this was an experiment but it seems to be a good idea */ 564 *status = STok; 565 566 /* send SCSI command */ 567 if(write(fd, cmd->p, cmd->count) != cmd->count){ 568 fprint(2, "scsireq: write cmd: %r\n"); 569 *status = Status_SW; 570 return -1; 571 } 572 573 /* read or write actual data */ 574 werrstr(""); 575 // alarm(5*1000); 576 if(data->write) 577 n = write(fd, data->p, data->count); 578 else { 579 n = read(fd, data->p, data->count); 580 if (n < 0) 581 memset(data->p, 0, data->count); 582 else if (n < data->count) 583 memset(data->p + n, 0, data->count - n); 584 } 585 // alarm(0); 586 if (n != data->count && n <= 0) { 587 if (debug) 588 fprint(2, 589 "request: tried to %s %ld bytes of data for cmd 0x%x but got %r\n", 590 (data->write? "write": "read"), 591 data->count, cmd->p[0]); 592 } else if (n != data->count && (data->write || debug)) 593 fprint(2, "request: %s %ld of %ld bytes of actual data\n", 594 (data->write? "wrote": "read"), n, data->count); 595 596 /* read status */ 597 buf[0] = '\0'; 598 r = read(fd, buf, sizeof buf-1); 599 if(exabyte && r <= 0 || !exabyte && r < 0){ 600 fprint(2, "scsireq: read status: %r\n"); 601 *status = Status_SW; 602 return -1; 603 } 604 if (r >= 0) 605 buf[r] = '\0'; 606 *status = atoi(buf); 607 if(n < 0 && (exabyte || *status != STcheck)) 608 fprint(2, "scsireq: status 0x%2.2uX: data transfer: %r\n", 609 *status); 610 return n; 611 } 612 613 static char* 614 seprintcmd(char *s, char* e, char *cmd, int count, int args) 615 { 616 uint c; 617 618 if(count < 6) 619 return seprint(s, e, "<short cmd>"); 620 c = cmd[0]; 621 if(scmdnames[c] != nil) 622 s = seprint(s, e, "%s", scmdnames[c]); 623 else 624 s = seprint(s, e, "cmd:%#02uX", c); 625 if(args != 0) 626 switch(c){ 627 case ScmdRsense: 628 case ScmdInq: 629 case ScmdMselect6: 630 case ScmdMsense6: 631 s = seprint(s, e, " sz %d", cmd[4]); 632 break; 633 case ScmdSpace: 634 s = seprint(s, e, " code %d", cmd[1]); 635 break; 636 case ScmdStart: 637 s = seprint(s, e, " code %d", cmd[4]); 638 break; 639 640 } 641 return s; 642 } 643 644 static char* 645 seprintdata(char *s, char *se, uchar *p, int count) 646 { 647 int i; 648 649 if(count == 0) 650 return s; 651 for(i = 0; i < 20 && i < count; i++) 652 s = seprint(s, se, " %02x", p[i]); 653 return s; 654 } 655 656 static void 657 SRdumpReq(ScsiReq *rp) 658 { 659 char buf[128]; 660 char *s; 661 char *se; 662 663 se = buf+sizeof(buf); 664 s = seprint(buf, se, "lun %d ", rp->lun); 665 s = seprintcmd(s, se, (char*)rp->cmd.p, rp->cmd.count, 1); 666 s = seprint(s, se, " [%ld]", rp->data.count); 667 if(rp->cmd.write) 668 seprintdata(s, se, rp->data.p, rp->data.count); 669 fprint(2, "scsi⇒ %s\n", buf); 670 } 671 672 static void 673 SRdumpRep(ScsiReq *rp) 674 { 675 char buf[128]; 676 char *s; 677 char *se; 678 679 se = buf+sizeof(buf); 680 s = seprint(buf, se, "lun %d ", rp->lun); 681 s = seprintcmd(s, se, (char*)rp->cmd.p, rp->cmd.count, 0); 682 switch(rp->status){ 683 case STok: 684 s = seprint(s, se, " good [%ld] ", rp->data.count); 685 if(rp->cmd.write == 0) 686 s = seprintdata(s, se, rp->data.p, rp->data.count); 687 break; 688 case STnomem: 689 s = seprint(s, se, " buffer allocation failed"); 690 break; 691 case STharderr: 692 s = seprint(s, se, " controller error"); 693 break; 694 case STtimeout: 695 s = seprint(s, se, " bus timeout"); 696 break; 697 case STcheck: 698 s = seprint(s, se, " check condition"); 699 break; 700 case STcondmet: 701 s = seprint(s, se, " condition met/good"); 702 break; 703 case STbusy: 704 s = seprint(s, se, " busy"); 705 break; 706 case STintok: 707 s = seprint(s, se, " intermediate/good"); 708 break; 709 case STintcondmet: 710 s = seprint(s, se, " intermediate/condition met/good"); 711 break; 712 case STresconf: 713 s = seprint(s, se, " reservation conflict"); 714 break; 715 case STterminated: 716 s = seprint(s, se, " command terminated"); 717 break; 718 case STqfull: 719 s = seprint(s, se, " queue full"); 720 break; 721 default: 722 s = seprint(s, se, " sts=%#x", rp->status); 723 } 724 USED(s); 725 fprint(2, "scsi← %s\n", buf); 726 } 727 728 static char* 729 scsierr(ScsiReq *rp) 730 { 731 int ec; 732 733 switch(rp->status){ 734 case 0: 735 return ""; 736 case Status_SD: 737 ec = (rp->sense[12] << 8) | rp->sense[13]; 738 return scsierrmsg(ec); 739 case Status_SW: 740 return "software error"; 741 case Status_BADARG: 742 return "bad argument"; 743 case Status_RO: 744 return "device is read only"; 745 default: 746 return "unknown"; 747 } 748 } 749 750 static void 751 SRdumpErr(ScsiReq *rp) 752 { 753 char buf[128]; 754 char *se; 755 756 se = buf+sizeof(buf); 757 seprintcmd(buf, se, (char*)rp->cmd.p, rp->cmd.count, 0); 758 fprint(2, "\t%s status: %s\n", buf, scsierr(rp)); 759 } 760 761 long 762 SRrequest(ScsiReq *rp) 763 { 764 long n; 765 int status; 766 767 retry: 768 if(debug) 769 SRdumpReq(rp); 770 if(rp->flags&Fusb) 771 n = umsrequest(rp->umsc, &rp->cmd, &rp->data, &status); 772 else 773 n = request(rp->fd, &rp->cmd, &rp->data, &status); 774 rp->status = status; 775 if(status == STok) 776 rp->data.count = n; 777 if(debug) 778 SRdumpRep(rp); 779 switch(status){ 780 case STok: 781 break; 782 case STcheck: 783 if(rp->cmd.p[0] != ScmdRsense && SRreqsense(rp) != -1) 784 rp->status = Status_SD; 785 if(debug || exabyte) 786 SRdumpErr(rp); 787 werrstr("%s", scsierr(rp)); 788 return -1; 789 case STbusy: 790 sleep(1000); /* TODO: try a shorter sleep? */ 791 goto retry; 792 default: 793 if(debug || exabyte) 794 SRdumpErr(rp); 795 werrstr("%s", scsierr(rp)); 796 return -1; 797 } 798 return n; 799 } 800 801 int 802 SRclose(ScsiReq *rp) 803 { 804 if((rp->flags & Fopen) == 0){ 805 if(diskdebug) 806 fprint(2, "disk: closing closed file\n"); 807 rp->status = Status_BADARG; 808 return -1; 809 } 810 close(rp->fd); 811 rp->flags = 0; 812 return 0; 813 } 814 815 static int 816 dirdevopen(ScsiReq *rp) 817 { 818 uvlong blocks; 819 uchar data[8+4+20]; /* 16-byte result: lba, blksize, reserved */ 820 821 memset(data, 0, sizeof data); 822 if(SRstart(rp, 1) == -1 || SRrcapacity(rp, data) == -1) 823 return -1; 824 rp->lbsize = GETBELONG(data+4); 825 blocks = GETBELONG(data); 826 if(debug) 827 fprint(2, "disk: dirdevopen: 10-byte logical block size %lud, " 828 "# blocks %llud\n", rp->lbsize, blocks); 829 if(blocks == 0xffffffff){ 830 if(SRrcapacity16(rp, data) == -1) 831 return -1; 832 rp->lbsize = GETBELONG(data + 8); 833 blocks = (vlong)GETBELONG(data)<<32 | GETBELONG(data + 4); 834 if(debug) 835 fprint(2, "disk: dirdevopen: 16-byte logical block size" 836 " %lud, # blocks %llud\n", rp->lbsize, blocks); 837 } 838 /* some newer dev's don't support 6-byte commands */ 839 if(blocks > Max24off && !force6bytecmds) 840 rp->flags |= Frw10; 841 return 0; 842 } 843 844 static int 845 seqdevopen(ScsiReq *rp) 846 { 847 uchar mode[16], limits[6]; 848 849 if(SRrblimits(rp, limits) == -1) 850 return -1; 851 if(limits[1] == 0 && limits[2] == limits[4] && limits[3] == limits[5]){ 852 rp->flags |= Fbfixed; 853 rp->lbsize = limits[4]<<8 | limits[5]; 854 if(debug) 855 fprint(2, "disk: seqdevopen: 10-byte logical block size %lud\n", 856 rp->lbsize); 857 return 0; 858 } 859 /* 860 * On some older hardware the optional 10-byte 861 * modeselect command isn't implemented. 862 */ 863 if (force6bytecmds) 864 rp->flags |= Fmode6; 865 if(!(rp->flags & Fmode6)){ 866 /* try 10-byte command first */ 867 memset(mode, 0, sizeof mode); 868 mode[3] = 0x10; /* device-specific param. */ 869 mode[7] = 8; /* block descriptor length */ 870 /* 871 * exabytes can't handle this, and 872 * modeselect(10) is optional. 873 */ 874 if(SRmodeselect10(rp, mode, sizeof mode) != -1){ 875 rp->lbsize = 1; 876 return 0; /* success */ 877 } 878 /* can't do 10-byte commands, back off to 6-byte ones */ 879 rp->flags |= Fmode6; 880 } 881 882 /* 6-byte command */ 883 memset(mode, 0, sizeof mode); 884 mode[2] = 0x10; /* device-specific param. */ 885 mode[3] = 8; /* block descriptor length */ 886 /* 887 * bsd sez exabytes need this bit (NBE: no busy enable) in 888 * vendor-specific page (0), but so far we haven't needed it. 889 mode[12] |= 8; 890 */ 891 if(SRmodeselect6(rp, mode, 4+8) == -1) 892 return -1; 893 rp->lbsize = 1; 894 return 0; 895 } 896 897 static int 898 wormdevopen(ScsiReq *rp) 899 { 900 long status; 901 uchar list[MaxDirData]; 902 903 if (SRstart(rp, 1) == -1 || 904 (status = SRmodesense10(rp, Allmodepages, list, sizeof list)) == -1) 905 return -1; 906 /* nbytes = list[0]<<8 | list[1]; */ 907 908 /* # of bytes of block descriptors of 8 bytes each; not even 1? */ 909 if((list[6]<<8 | list[7]) < 8) 910 rp->lbsize = 2048; 911 else 912 /* last 3 bytes of block 0 descriptor */ 913 rp->lbsize = GETBE24(list+13); 914 if(debug) 915 fprint(2, "disk: wormdevopen: 10-byte logical block size %lud\n", 916 rp->lbsize); 917 return status; 918 } 919 920 int 921 SRopenraw(ScsiReq *rp, char *unit) 922 { 923 char name[128]; 924 925 if(rp->flags & Fopen){ 926 if(diskdebug) 927 fprint(2, "disk: opening open file\n"); 928 rp->status = Status_BADARG; 929 return -1; 930 } 931 memset(rp, 0, sizeof *rp); 932 rp->unit = unit; 933 934 snprint(name, sizeof name, "%s/raw", unit); 935 if((rp->fd = open(name, ORDWR)) == -1){ 936 rp->status = STtimeout; 937 return -1; 938 } 939 rp->flags = Fopen; 940 return 0; 941 } 942 943 int 944 SRopen(ScsiReq *rp, char *unit) 945 { 946 if(SRopenraw(rp, unit) == -1) 947 return -1; 948 SRready(rp); 949 if(SRinquiry(rp) >= 0){ 950 switch(rp->inquiry[0]){ 951 952 default: 953 fprint(2, "unknown device type 0x%.2x\n", rp->inquiry[0]); 954 rp->status = Status_SW; 955 break; 956 957 case Devdir: 958 case Devcd: 959 case Devmo: 960 if(dirdevopen(rp) == -1) 961 break; 962 return 0; 963 964 case Devseq: 965 rp->flags |= Fseqdev; 966 if(seqdevopen(rp) == -1) 967 break; 968 return 0; 969 970 case Devprint: 971 rp->flags |= Fprintdev; 972 return 0; 973 974 case Devworm: 975 rp->flags |= Fwormdev; 976 if(wormdevopen(rp) == -1) 977 break; 978 return 0; 979 980 case Devjuke: 981 rp->flags |= Fchanger; 982 return 0; 983 } 984 } 985 SRclose(rp); 986 return -1; 987 } 988