137da2899SCharles.Forsythimplement ScsiIO; 237da2899SCharles.Forsyth 337da2899SCharles.Forsyth# adapted from /sys/src/libdisk on Plan 9: subject to Lucent Public License 1.02 437da2899SCharles.Forsyth 537da2899SCharles.Forsythinclude "sys.m"; 637da2899SCharles.Forsyth sys: Sys; 737da2899SCharles.Forsyth 837da2899SCharles.Forsythinclude "bufio.m"; 937da2899SCharles.Forsyth bufio: Bufio; 1037da2899SCharles.Forsyth Iobuf: import bufio; 1137da2899SCharles.Forsyth 1237da2899SCharles.Forsythinclude "daytime.m"; 1337da2899SCharles.Forsyth daytime: Daytime; 1437da2899SCharles.Forsyth 1537da2899SCharles.Forsythinclude "scsiio.m"; 1637da2899SCharles.Forsyth 1737da2899SCharles.Forsythscsiverbose := 0; 1837da2899SCharles.Forsyth 1937da2899SCharles.ForsythCodefile: con "/lib/scsicodes"; 2037da2899SCharles.Forsyth 2137da2899SCharles.ForsythCode: adt { 2237da2899SCharles.Forsyth v: int; # (asc<<8) | ascq 2337da2899SCharles.Forsyth s: string; 2437da2899SCharles.Forsyth}; 2537da2899SCharles.Forsythcodes: array of Code; 2637da2899SCharles.Forsyth 2737da2899SCharles.Forsythinit(verbose: int) 2837da2899SCharles.Forsyth{ 2937da2899SCharles.Forsyth sys = load Sys Sys->PATH; 3037da2899SCharles.Forsyth bufio = load Bufio Bufio->PATH; 3137da2899SCharles.Forsyth daytime = load Daytime Daytime->PATH; 3237da2899SCharles.Forsyth 3337da2899SCharles.Forsyth scsiverbose = verbose; 3437da2899SCharles.Forsyth getcodes(); 3537da2899SCharles.Forsyth} 3637da2899SCharles.Forsyth 3737da2899SCharles.Forsythgetcodes() 3837da2899SCharles.Forsyth{ 3937da2899SCharles.Forsyth fd := bufio->open(Codefile, Sys->OREAD); 4037da2899SCharles.Forsyth if(fd == nil) 4137da2899SCharles.Forsyth return; 4237da2899SCharles.Forsyth 4337da2899SCharles.Forsyth codes = array[256] of Code; 4437da2899SCharles.Forsyth nc := 0; 4537da2899SCharles.Forsyth while((s := fd.gets('\n')) != nil){ 4637da2899SCharles.Forsyth if(s[0] == '#' || s[0] == '\n') 4737da2899SCharles.Forsyth continue; 4837da2899SCharles.Forsyth s = s[0: len s-1]; # trim '\n' 4937da2899SCharles.Forsyth m: string; 5037da2899SCharles.Forsyth for(i := 0; i < len s; i++) 5137da2899SCharles.Forsyth if(s[i] == ' '){ 5237da2899SCharles.Forsyth m = s[i+1:]; 5337da2899SCharles.Forsyth break; 5437da2899SCharles.Forsyth } 5537da2899SCharles.Forsyth c := Code(tohex(s), m); 5637da2899SCharles.Forsyth if(nc >= len codes){ 5737da2899SCharles.Forsyth ct := array[nc + 20] of Code; 5837da2899SCharles.Forsyth ct[0:] = codes; 5937da2899SCharles.Forsyth codes = ct; 6037da2899SCharles.Forsyth } 6137da2899SCharles.Forsyth codes[nc++] = c; 6237da2899SCharles.Forsyth } 6337da2899SCharles.Forsyth codes = codes[0:nc]; 6437da2899SCharles.Forsyth} 6537da2899SCharles.Forsyth 6637da2899SCharles.Forsythtohex(s: string): int 6737da2899SCharles.Forsyth{ 6837da2899SCharles.Forsyth n := 0; 6937da2899SCharles.Forsyth j := 0; 7037da2899SCharles.Forsyth for(i := 0; i < len s && j < 4; i++){ 7137da2899SCharles.Forsyth if(s[i] == '/') 7237da2899SCharles.Forsyth continue; 7337da2899SCharles.Forsyth d := hex(s[i]); 7437da2899SCharles.Forsyth if(d < 0) 7537da2899SCharles.Forsyth return -1; 7637da2899SCharles.Forsyth n = (n<<4) | d; 7737da2899SCharles.Forsyth j++; 7837da2899SCharles.Forsyth } 7937da2899SCharles.Forsyth return n; 8037da2899SCharles.Forsyth} 8137da2899SCharles.Forsyth 8237da2899SCharles.Forsythhex(c: int): int 8337da2899SCharles.Forsyth{ 8437da2899SCharles.Forsyth if(c >= '0' && c <= '9') 8537da2899SCharles.Forsyth return c-'0'; 8637da2899SCharles.Forsyth if(c >= 'A' && c <= 'F') 8737da2899SCharles.Forsyth return c-'A' + 10; 8837da2899SCharles.Forsyth if(c >= 'a' && c <= 'f') 8937da2899SCharles.Forsyth return c-'a' + 10; 9037da2899SCharles.Forsyth return -1; 9137da2899SCharles.Forsyth} 9237da2899SCharles.Forsyth 9337da2899SCharles.Forsythscsierror(asc: int, ascq: int): string 9437da2899SCharles.Forsyth{ 9537da2899SCharles.Forsyth t := -1; 9637da2899SCharles.Forsyth for(i := 0; i < len codes; i++){ 9737da2899SCharles.Forsyth if(codes[i].v == ((asc<<8) | ascq)) 9837da2899SCharles.Forsyth return codes[i].s; 9937da2899SCharles.Forsyth if(codes[i].v == (asc<<8)) 10037da2899SCharles.Forsyth t = i; 10137da2899SCharles.Forsyth } 10237da2899SCharles.Forsyth if(t >= 0) 10337da2899SCharles.Forsyth return sys->sprint("(ascq #%.2ux) %s", ascq, codes[t].s); 10437da2899SCharles.Forsyth return sys->sprint("scsi #%.2ux %.2ux", asc, ascq); 10537da2899SCharles.Forsyth} 10637da2899SCharles.Forsyth 10737da2899SCharles.Forsyth_scsicmd(s: ref Scsi, cmd: array of byte, data: array of byte, io: int, dolock: int): int 10837da2899SCharles.Forsyth{ 10937da2899SCharles.Forsyth if(dolock) 11037da2899SCharles.Forsyth qlock(s); 11137da2899SCharles.Forsyth dcount := len data; 11237da2899SCharles.Forsyth if(sys->write(s.rawfd, cmd, len cmd) != len cmd) { 11337da2899SCharles.Forsyth sys->werrstr("cmd write: %r"); 11437da2899SCharles.Forsyth if(dolock) 11537da2899SCharles.Forsyth qunlock(s); 11637da2899SCharles.Forsyth return -1; 11737da2899SCharles.Forsyth } 11837da2899SCharles.Forsyth 11937da2899SCharles.Forsyth n: int; 12037da2899SCharles.Forsyth resp := array[16] of byte; 12137da2899SCharles.Forsyth case io { 12237da2899SCharles.Forsyth Sread => 12337da2899SCharles.Forsyth n = sys->read(s.rawfd, data, dcount); 12437da2899SCharles.Forsyth if(n < 0 && scsiverbose) 12537da2899SCharles.Forsyth sys->fprint(sys->fildes(2), "dat read: %r: cmd %#2.2uX\n", int cmd[0]); 12637da2899SCharles.Forsyth Swrite => 12737da2899SCharles.Forsyth n = sys->write(s.rawfd, data, dcount); 12837da2899SCharles.Forsyth if(n != dcount && scsiverbose) 12937da2899SCharles.Forsyth sys->fprint(sys->fildes(2), "dat write: %r: cmd %#2.2uX\n", int cmd[0]); 13037da2899SCharles.Forsyth Snone or * => 13137da2899SCharles.Forsyth n = sys->write(s.rawfd, resp, 0); 13237da2899SCharles.Forsyth if(n != 0 && scsiverbose) 13337da2899SCharles.Forsyth sys->fprint(sys->fildes(2), "none write: %r: cmd %#2.2uX\n", int cmd[0]); 13437da2899SCharles.Forsyth } 13537da2899SCharles.Forsyth 13637da2899SCharles.Forsyth m := sys->read(s.rawfd, resp, len resp); 13737da2899SCharles.Forsyth if(dolock) 13837da2899SCharles.Forsyth qunlock(s); 13937da2899SCharles.Forsyth if(m < 0){ 14037da2899SCharles.Forsyth sys->werrstr("resp read: %r\n"); 14137da2899SCharles.Forsyth return -1; 14237da2899SCharles.Forsyth } 14337da2899SCharles.Forsyth status := int string resp[0:m]; 14437da2899SCharles.Forsyth if(status == 0) 14537da2899SCharles.Forsyth return n; 14637da2899SCharles.Forsyth 14737da2899SCharles.Forsyth sys->werrstr(sys->sprint("cmd %2.2uX: status %uX dcount %d n %d", int cmd[0], status, dcount, n)); 14837da2899SCharles.Forsyth return -1; 14937da2899SCharles.Forsyth} 15037da2899SCharles.Forsyth 15137da2899SCharles.ForsythScsi.rawcmd(s: self ref Scsi, cmd: array of byte, data: array of byte, io: int): int 15237da2899SCharles.Forsyth{ 15337da2899SCharles.Forsyth return _scsicmd(s, cmd, data, io, 1); 15437da2899SCharles.Forsyth} 15537da2899SCharles.Forsyth 15637da2899SCharles.Forsyth_scsiready(s: ref Scsi, dolock: int): int 15737da2899SCharles.Forsyth{ 15837da2899SCharles.Forsyth if(dolock) 15937da2899SCharles.Forsyth qlock(s); 16037da2899SCharles.Forsyth for(i:=0; i<3; i++) { 16137da2899SCharles.Forsyth cmd := array[6] of {0 => byte 16r00, * => byte 0}; # test unit ready 16237da2899SCharles.Forsyth if(sys->write(s.rawfd, cmd, len cmd) != len cmd) { 16337da2899SCharles.Forsyth if(scsiverbose) 16437da2899SCharles.Forsyth sys->fprint(sys->fildes(2), "ur cmd write: %r\n"); 16537da2899SCharles.Forsyth continue; 16637da2899SCharles.Forsyth } 16737da2899SCharles.Forsyth resp := array[16] of byte; 16837da2899SCharles.Forsyth sys->write(s.rawfd, resp, 0); 16937da2899SCharles.Forsyth m := sys->read(s.rawfd, resp, len resp); 17037da2899SCharles.Forsyth if(m < 0){ 17137da2899SCharles.Forsyth if(scsiverbose) 17237da2899SCharles.Forsyth sys->fprint(sys->fildes(2), "ur resp read: %r\n"); 17337da2899SCharles.Forsyth continue; # retry 17437da2899SCharles.Forsyth } 17537da2899SCharles.Forsyth status := int string resp[0:m]; 17637da2899SCharles.Forsyth if(status == 0 || status == 16r02) { 17737da2899SCharles.Forsyth if(dolock) 17837da2899SCharles.Forsyth qunlock(s); 17937da2899SCharles.Forsyth return 0; 18037da2899SCharles.Forsyth } 18137da2899SCharles.Forsyth if(scsiverbose) 18237da2899SCharles.Forsyth sys->fprint(sys->fildes(2), "target: bad status: %x\n", status); 18337da2899SCharles.Forsyth } 18437da2899SCharles.Forsyth if(dolock) 18537da2899SCharles.Forsyth qunlock(s); 18637da2899SCharles.Forsyth return -1; 18737da2899SCharles.Forsyth} 18837da2899SCharles.Forsyth 18937da2899SCharles.ForsythScsi.ready(s: self ref Scsi): int 19037da2899SCharles.Forsyth{ 19137da2899SCharles.Forsyth return _scsiready(s, 1); 19237da2899SCharles.Forsyth} 19337da2899SCharles.Forsyth 19437da2899SCharles.ForsythScsi.cmd(s: self ref Scsi, cmd: array of byte, data: array of byte, io: int): int 19537da2899SCharles.Forsyth{ 19637da2899SCharles.Forsyth dcount := len data; 19737da2899SCharles.Forsyth code := 0; 19837da2899SCharles.Forsyth key := 0; 19937da2899SCharles.Forsyth qlock(s); 20037da2899SCharles.Forsyth sense: array of byte; 20137da2899SCharles.Forsyth for(tries:=0; tries<2; tries++) { 20237da2899SCharles.Forsyth n := _scsicmd(s, cmd, data, io, 0); 20337da2899SCharles.Forsyth if(n >= 0) { 20437da2899SCharles.Forsyth qunlock(s); 20537da2899SCharles.Forsyth return n; 20637da2899SCharles.Forsyth } 20737da2899SCharles.Forsyth 20837da2899SCharles.Forsyth # 20937da2899SCharles.Forsyth # request sense 21037da2899SCharles.Forsyth # 21137da2899SCharles.Forsyth sense = array[255] of {* => byte 16rFF}; # TO DO: usb mass storage devices might inist on less 21237da2899SCharles.Forsyth req := array[6] of {0 => byte 16r03, 4 => byte len sense, * => byte 0}; 21337da2899SCharles.Forsyth if((n=_scsicmd(s, req, sense, Sread, 0)) < 14) 21437da2899SCharles.Forsyth if(scsiverbose) 21537da2899SCharles.Forsyth sys->fprint(sys->fildes(2), "reqsense scsicmd %d: %r\n", n); 21637da2899SCharles.Forsyth 21737da2899SCharles.Forsyth if(_scsiready(s, 0) < 0) 21837da2899SCharles.Forsyth if(scsiverbose) 21937da2899SCharles.Forsyth sys->fprint(sys->fildes(2), "unit not ready\n"); 22037da2899SCharles.Forsyth 22137da2899SCharles.Forsyth key = int sense[2]; 22237da2899SCharles.Forsyth code = int sense[12]; 22337da2899SCharles.Forsyth if(code == 16r17 || code == 16r18) { # recovered errors 22437da2899SCharles.Forsyth qunlock(s); 22537da2899SCharles.Forsyth return dcount; 22637da2899SCharles.Forsyth } 22737da2899SCharles.Forsyth if(code == 16r28 && int cmd[0] == 16r43) { # get info and media changed 22837da2899SCharles.Forsyth s.nchange++; 22937da2899SCharles.Forsyth s.changetime = daytime->now(); 23037da2899SCharles.Forsyth continue; 23137da2899SCharles.Forsyth } 23237da2899SCharles.Forsyth } 23337da2899SCharles.Forsyth 23437da2899SCharles.Forsyth # drive not ready, or medium not present 23537da2899SCharles.Forsyth if(cmd[0] == byte 16r43 && key == 2 && (code == 16r3a || code == 16r04)) { 23637da2899SCharles.Forsyth s.changetime = 0; 23737da2899SCharles.Forsyth qunlock(s); 23837da2899SCharles.Forsyth return -1; 23937da2899SCharles.Forsyth } 24037da2899SCharles.Forsyth qunlock(s); 24137da2899SCharles.Forsyth 24237da2899SCharles.Forsyth if(cmd[0] == byte 16r43 && key == 5 && code == 16r24) # blank media 24337da2899SCharles.Forsyth return -1; 24437da2899SCharles.Forsyth 24537da2899SCharles.Forsyth p := scsierror(code, int sense[13]); 24637da2899SCharles.Forsyth 24737da2899SCharles.Forsyth sys->werrstr(sys->sprint("cmd #%.2ux: %s", int cmd[0], p)); 24837da2899SCharles.Forsyth 24937da2899SCharles.Forsyth if(scsiverbose) 25037da2899SCharles.Forsyth sys->fprint(sys->fildes(2), "scsi cmd #%.2ux: %.2ux %.2ux %.2ux: %s\n", int cmd[0], key, code, int sense[13], p); 25137da2899SCharles.Forsyth 25237da2899SCharles.Forsyth# if(key == 0) 25337da2899SCharles.Forsyth# return dcount; 25437da2899SCharles.Forsyth return -1; 25537da2899SCharles.Forsyth} 25637da2899SCharles.Forsyth 25737da2899SCharles.ForsythScsi.open(dev: string): ref Scsi 25837da2899SCharles.Forsyth{ 25937da2899SCharles.Forsyth rawfd := sys->open(dev+"/raw", Sys->ORDWR); 26037da2899SCharles.Forsyth if(rawfd == nil) 26137da2899SCharles.Forsyth return nil; 26237da2899SCharles.Forsyth ctlfd := sys->open(dev+"/ctl", Sys->ORDWR); 26337da2899SCharles.Forsyth if(ctlfd == nil) 26437da2899SCharles.Forsyth return nil; 26537da2899SCharles.Forsyth 26637da2899SCharles.Forsyth buf := array[512] of byte; 267*a6011949SCharles.Forsyth n := sys->readn(ctlfd, buf, len buf); 26837da2899SCharles.Forsyth if(n < 8){ 26937da2899SCharles.Forsyth if(n >= 0) 27037da2899SCharles.Forsyth sys->werrstr("error reading ctl file"); 27137da2899SCharles.Forsyth return nil; 27237da2899SCharles.Forsyth } 27337da2899SCharles.Forsyth ctlfd = nil; 27437da2899SCharles.Forsyth 27537da2899SCharles.Forsyth for(i := 0; i < n; i++) 27637da2899SCharles.Forsyth if(buf[i] == byte '\n') 27737da2899SCharles.Forsyth break; 27837da2899SCharles.Forsyth inq := string buf[0:i]; 27937da2899SCharles.Forsyth if(i >= n || inq[0:8] != "inquiry "){ 28037da2899SCharles.Forsyth sys->werrstr("invalid inquiry string"); 28137da2899SCharles.Forsyth return nil; 28237da2899SCharles.Forsyth } 28337da2899SCharles.Forsyth s := ref Scsi; 28437da2899SCharles.Forsyth s.lock = chan[1] of int; 28537da2899SCharles.Forsyth s.rawfd = rawfd; 28637da2899SCharles.Forsyth s.inquire = inq[8:]; 28737da2899SCharles.Forsyth s.changetime = daytime->now(); 28837da2899SCharles.Forsyth 28937da2899SCharles.Forsyth if(s.ready() < 0) 29037da2899SCharles.Forsyth return nil; 29137da2899SCharles.Forsyth 29237da2899SCharles.Forsyth return s; 29337da2899SCharles.Forsyth} 29437da2899SCharles.Forsyth 29537da2899SCharles.Forsythqlock(s: ref Scsi) 29637da2899SCharles.Forsyth{ 29737da2899SCharles.Forsyth s.lock <-= 1; 29837da2899SCharles.Forsyth} 29937da2899SCharles.Forsyth 30037da2899SCharles.Forsythqunlock(s: ref Scsi) 30137da2899SCharles.Forsyth{ 30237da2899SCharles.Forsyth <-s.lock; 30337da2899SCharles.Forsyth} 304