1 #include <u.h> 2 #include <libc.h> 3 #include <disk.h> 4 5 int scsiverbose; 6 7 #define codefile "/sys/lib/scsicodes" 8 9 static char *codes; 10 static void 11 getcodes(void) 12 { 13 Dir d; 14 int n, fd; 15 16 if(codes != nil) 17 return; 18 19 if(dirstat(codefile, &d) < 0 || (fd = open(codefile, OREAD)) < 0) 20 return; 21 22 codes = emalloc(d.length+1+1); 23 codes[0] = '\n'; /* for searches */ 24 n = readn(fd, codes+1, d.length); 25 close(fd); 26 27 if(n < 0) { 28 free(codes); 29 codes = nil; 30 return; 31 } 32 codes[n] = '\0'; 33 } 34 35 char* 36 scsierror(int asc, int ascq) 37 { 38 char *p, *q; 39 static char search[32]; 40 static char buf[128]; 41 42 getcodes(); 43 44 if(codes) { 45 sprint(search, "\n%.2ux%.2ux ", asc, ascq); 46 if(p = strstr(codes, search)) { 47 p += 6; 48 if((q = strchr(p, '\n')) == nil) 49 q = p+strlen(p); 50 snprint(buf, sizeof buf, "%.*s", (int)(q-p), p); 51 return buf; 52 } 53 54 sprint(search, "\n%.2ux00", asc); 55 if(p = strstr(codes, search)) { 56 p += 6; 57 if((q = strchr(p, '\n')) == nil) 58 q = p+strlen(p); 59 snprint(buf, sizeof buf, "(ascq #%.2ux) %.*s", ascq, (int)(q-p), p); 60 return buf; 61 } 62 } 63 64 sprint(buf, "scsi #%.2ux %.2ux", asc, ascq); 65 return buf; 66 } 67 68 69 int 70 scsicmd(Scsi *s, uchar *cmd, int ccount, void *data, int dcount, int io) 71 { 72 uchar resp[16]; 73 int n; 74 long status; 75 76 if(write(s->rawfd, cmd, ccount) != ccount) { 77 werrstr("cmd write: %r"); 78 return -1; 79 } 80 81 switch(io){ 82 case Sread: 83 n = read(s->rawfd, data, dcount); 84 if(n < 0 && scsiverbose) 85 fprint(2, "dat read: %r: cmd 0x%2.2uX\n", cmd[0]); 86 break; 87 case Swrite: 88 n = write(s->rawfd, data, dcount); 89 if(n != dcount && scsiverbose) 90 fprint(2, "dat write: %r: cmd 0x%2.2uX\n", cmd[0]); 91 break; 92 default: 93 case Snone: 94 n = write(s->rawfd, resp, 0); 95 if(n != 0 && scsiverbose) 96 fprint(2, "none write: %r: cmd 0x%2.2uX\n", cmd[0]); 97 break; 98 } 99 100 memset(resp, 0, sizeof(resp)); 101 if(read(s->rawfd, resp, sizeof(resp)) < 0) { 102 werrstr("resp read: %r\n"); 103 return -1; 104 } 105 106 resp[sizeof(resp)-1] = '\0'; 107 status = atoi((char*)resp); 108 if(status == 0) 109 return n; 110 111 werrstr("cmd %2.2uX: status %luX dcount %d n %d", cmd[0], status, dcount, n); 112 return -1; 113 } 114 115 int 116 scsiready(Scsi *s) 117 { 118 uchar cmd[6], resp[16]; 119 int status, i; 120 121 for(i=0; i<3; i++) { 122 memset(cmd, 0, sizeof(cmd)); 123 cmd[0] = 0x00; /* unit ready */ 124 if(write(s->rawfd, cmd, sizeof(cmd)) != sizeof(cmd)) { 125 if(scsiverbose) 126 fprint(2, "ur cmd write: %r\n"); 127 goto bad; 128 } 129 write(s->rawfd, resp, 0); 130 if(read(s->rawfd, resp, sizeof(resp)) < 0) { 131 if(scsiverbose) 132 fprint(2, "ur resp read: %r\n"); 133 goto bad; 134 } 135 resp[sizeof(resp)-1] = '\0'; 136 status = atoi((char*)resp); 137 if(status == 0 || status == 0x02) 138 return 0; 139 if(scsiverbose) 140 fprint(2, "target: bad status: %x\n", status); 141 bad:; 142 } 143 return -1; 144 } 145 146 int 147 scsi(Scsi *s, uchar *cmd, int ccount, void *v, int dcount, int io) 148 { 149 uchar req[6], sense[255], *data; 150 int tries, code, key, n; 151 char *p; 152 153 data = v; 154 SET(key, code); 155 for(tries=0; tries<2; tries++) { 156 n = scsicmd(s, cmd, ccount, data, dcount, io); 157 if(n >= 0) 158 return n; 159 160 /* 161 * request sense 162 */ 163 memset(req, 0, sizeof(req)); 164 req[0] = 0x03; 165 req[4] = sizeof(sense); 166 memset(sense, 0xFF, sizeof(sense)); 167 if((n=scsicmd(s, req, sizeof(req), sense, sizeof(sense), Sread)) < 14) 168 if(scsiverbose) 169 fprint(2, "reqsense scsicmd %d: %r\n", n); 170 171 if(scsiready(s) < 0) 172 if(scsiverbose) 173 fprint(2, "unit not ready\n"); 174 175 key = sense[2]; 176 code = sense[12]; 177 if(code == 0x17 || code == 0x18) /* recovered errors */ 178 return dcount; 179 if(code == 0x28 && cmd[0] == 0x43) { /* get info and media changed */ 180 s->nchange++; 181 s->changetime = time(0); 182 continue; 183 } 184 } 185 186 /* drive not ready, or medium not present */ 187 if(cmd[0] == 0x43 && key == 2 && (code == 0x3a || code == 0x04)) { 188 s->changetime = 0; 189 return -1; 190 } 191 192 if(cmd[0] == 0x43 && key == 5 && code == 0x24) /* blank media */ 193 return -1; 194 195 p = scsierror(code, sense[13]); 196 197 werrstr("cmd #%.2ux: %s", cmd[0], p); 198 199 if(scsiverbose) 200 fprint(2, "scsi cmd #%.2ux: %.2ux %.2ux %.2ux: %s\n", cmd[0], key, code, sense[13], p); 201 202 // if(key == 0) 203 // return dcount; 204 return -1; 205 } 206 207 Scsi* 208 openscsi(char *dev) 209 { 210 Scsi *s; 211 int rawfd, ctlfd, l, n; 212 char *name, *p, buf[512]; 213 214 l = strlen(dev)+1+3+1; 215 name = emalloc(l); 216 217 snprint(name, l, "%s/raw", dev); 218 if((rawfd = open(name, ORDWR)) < 0) 219 return nil; 220 221 snprint(name, l, "%s/ctl", dev); 222 if((ctlfd = open(name, ORDWR)) < 0) { 223 Error: 224 close(rawfd); 225 return nil; 226 } 227 228 n = readn(ctlfd, buf, sizeof buf); 229 close(ctlfd); 230 if(n <= 0) 231 goto Error; 232 233 if(strncmp(buf, "inquiry ", 8) != 0 || (p = strchr(buf, '\n')) == nil) 234 goto Error; 235 *p = '\0'; 236 237 if((p = strdup(buf+8)) == nil) 238 goto Error; 239 240 s = emalloc(sizeof(*s)); 241 s->rawfd = rawfd; 242 s->inquire = p; 243 s->changetime = time(0); 244 245 if(scsiready(s) < 0){ 246 free(p); 247 goto Error; 248 } 249 250 return s; 251 } 252