scsi.c (6112B)
1 /* 2 * Now thread-safe. 3 * 4 * The codeqlock guarantees that once codes != nil, that pointer will never 5 * change nor become invalid. 6 * 7 * The QLock in the Scsi structure moderates access to the raw device. 8 * We should probably export some of the already-locked routines, but 9 * there hasn't been a need. 10 */ 11 12 #include <u.h> 13 #include <libc.h> 14 #include <disk.h> 15 16 int scsiverbose; 17 18 #define codefile "/sys/lib/scsicodes" 19 20 static char *codes; 21 static QLock codeqlock; 22 23 static void 24 getcodes(void) 25 { 26 Dir *d; 27 int n, fd; 28 29 if(codes != nil) 30 return; 31 32 qlock(&codeqlock); 33 if(codes != nil) { 34 qunlock(&codeqlock); 35 return; 36 } 37 38 if((d = dirstat(codefile)) == nil || (fd = open(codefile, OREAD)) < 0) { 39 qunlock(&codeqlock); 40 return; 41 } 42 43 codes = malloc(1+d->length+1); 44 if(codes == nil) { 45 close(fd); 46 qunlock(&codeqlock); 47 free(d); 48 return; 49 } 50 51 codes[0] = '\n'; /* for searches */ 52 n = readn(fd, codes+1, d->length); 53 close(fd); 54 free(d); 55 56 if(n < 0) { 57 free(codes); 58 codes = nil; 59 qunlock(&codeqlock); 60 return; 61 } 62 codes[n] = '\0'; 63 qunlock(&codeqlock); 64 } 65 66 char* 67 scsierror(int asc, int ascq) 68 { 69 char *p, *q; 70 static char search[32]; 71 static char buf[128]; 72 73 getcodes(); 74 75 if(codes) { 76 sprint(search, "\n%.2ux%.2ux ", asc, ascq); 77 if(p = strstr(codes, search)) { 78 p += 6; 79 if((q = strchr(p, '\n')) == nil) 80 q = p+strlen(p); 81 snprint(buf, sizeof buf, "%.*s", (int)(q-p), p); 82 return buf; 83 } 84 85 sprint(search, "\n%.2ux00", asc); 86 if(p = strstr(codes, search)) { 87 p += 6; 88 if((q = strchr(p, '\n')) == nil) 89 q = p+strlen(p); 90 snprint(buf, sizeof buf, "(ascq #%.2ux) %.*s", ascq, (int)(q-p), p); 91 return buf; 92 } 93 } 94 95 sprint(buf, "scsi #%.2ux %.2ux", asc, ascq); 96 return buf; 97 } 98 99 100 static int 101 _scsicmd(Scsi *s, uchar *cmd, int ccount, void *data, int dcount, int io, int dolock) 102 { 103 uchar resp[16]; 104 int n; 105 long status; 106 107 if(dolock) 108 qlock(&s->lk); 109 if(write(s->rawfd, cmd, ccount) != ccount) { 110 werrstr("cmd write: %r"); 111 if(dolock) 112 qunlock(&s->lk); 113 return -1; 114 } 115 116 switch(io){ 117 case Sread: 118 n = read(s->rawfd, data, dcount); 119 if(n < 0 && scsiverbose) 120 fprint(2, "dat read: %r: cmd 0x%2.2uX\n", cmd[0]); 121 break; 122 case Swrite: 123 n = write(s->rawfd, data, dcount); 124 if(n != dcount && scsiverbose) 125 fprint(2, "dat write: %r: cmd 0x%2.2uX\n", cmd[0]); 126 break; 127 default: 128 case Snone: 129 n = write(s->rawfd, resp, 0); 130 if(n != 0 && scsiverbose) 131 fprint(2, "none write: %r: cmd 0x%2.2uX\n", cmd[0]); 132 break; 133 } 134 135 memset(resp, 0, sizeof(resp)); 136 if(read(s->rawfd, resp, sizeof(resp)) < 0) { 137 werrstr("resp read: %r\n"); 138 if(dolock) 139 qunlock(&s->lk); 140 return -1; 141 } 142 if(dolock) 143 qunlock(&s->lk); 144 145 resp[sizeof(resp)-1] = '\0'; 146 status = atoi((char*)resp); 147 if(status == 0) 148 return n; 149 150 werrstr("cmd %2.2uX: status %luX dcount %d n %d", cmd[0], status, dcount, n); 151 return -1; 152 } 153 154 int 155 scsicmd(Scsi *s, uchar *cmd, int ccount, void *data, int dcount, int io) 156 { 157 return _scsicmd(s, cmd, ccount, data, dcount, io, 1); 158 } 159 160 static int 161 _scsiready(Scsi *s, int dolock) 162 { 163 uchar cmd[6], resp[16]; 164 int status, i; 165 166 if(dolock) 167 qlock(&s->lk); 168 for(i=0; i<3; i++) { 169 memset(cmd, 0, sizeof(cmd)); 170 cmd[0] = 0x00; /* unit ready */ 171 if(write(s->rawfd, cmd, sizeof(cmd)) != sizeof(cmd)) { 172 if(scsiverbose) 173 fprint(2, "ur cmd write: %r\n"); 174 goto bad; 175 } 176 write(s->rawfd, resp, 0); 177 if(read(s->rawfd, resp, sizeof(resp)) < 0) { 178 if(scsiverbose) 179 fprint(2, "ur resp read: %r\n"); 180 goto bad; 181 } 182 resp[sizeof(resp)-1] = '\0'; 183 status = atoi((char*)resp); 184 if(status == 0 || status == 0x02) { 185 if(dolock) 186 qunlock(&s->lk); 187 return 0; 188 } 189 if(scsiverbose) 190 fprint(2, "target: bad status: %x\n", status); 191 bad:; 192 } 193 if(dolock) 194 qunlock(&s->lk); 195 return -1; 196 } 197 198 int 199 scsiready(Scsi *s) 200 { 201 return _scsiready(s, 1); 202 } 203 204 int 205 scsi(Scsi *s, uchar *cmd, int ccount, void *v, int dcount, int io) 206 { 207 uchar req[6], sense[255], *data; 208 int tries, code, key, n; 209 char *p; 210 211 data = v; 212 SET(key); SET(code); 213 qlock(&s->lk); 214 for(tries=0; tries<2; tries++) { 215 n = _scsicmd(s, cmd, ccount, data, dcount, io, 0); 216 if(n >= 0) { 217 qunlock(&s->lk); 218 return n; 219 } 220 221 /* 222 * request sense 223 */ 224 memset(req, 0, sizeof(req)); 225 req[0] = 0x03; 226 req[4] = sizeof(sense); 227 memset(sense, 0xFF, sizeof(sense)); 228 if((n=_scsicmd(s, req, sizeof(req), sense, sizeof(sense), Sread, 0)) < 14) 229 if(scsiverbose) 230 fprint(2, "reqsense scsicmd %d: %r\n", n); 231 232 if(_scsiready(s, 0) < 0) 233 if(scsiverbose) 234 fprint(2, "unit not ready\n"); 235 236 key = sense[2]; 237 code = sense[12]; 238 if(code == 0x17 || code == 0x18) { /* recovered errors */ 239 qunlock(&s->lk); 240 return dcount; 241 } 242 if(code == 0x28 && cmd[0] == 0x43) { /* get info and media changed */ 243 s->nchange++; 244 s->changetime = time(0); 245 continue; 246 } 247 } 248 249 /* drive not ready, or medium not present */ 250 if(cmd[0] == 0x43 && key == 2 && (code == 0x3a || code == 0x04)) { 251 s->changetime = 0; 252 qunlock(&s->lk); 253 return -1; 254 } 255 qunlock(&s->lk); 256 257 if(cmd[0] == 0x43 && key == 5 && code == 0x24) /* blank media */ 258 return -1; 259 260 p = scsierror(code, sense[13]); 261 262 werrstr("cmd #%.2ux: %s", cmd[0], p); 263 264 if(scsiverbose) 265 fprint(2, "scsi cmd #%.2ux: %.2ux %.2ux %.2ux: %s\n", cmd[0], key, code, sense[13], p); 266 267 /* if(key == 0) */ 268 /* return dcount; */ 269 return -1; 270 } 271 272 Scsi* 273 openscsi(char *dev) 274 { 275 Scsi *s; 276 int rawfd, ctlfd, l, n; 277 char *name, *p, buf[512]; 278 279 l = strlen(dev)+1+3+1; 280 name = malloc(l); 281 if(name == nil) 282 return nil; 283 284 snprint(name, l, "%s/raw", dev); 285 if((rawfd = open(name, ORDWR)) < 0) { 286 free(name); 287 return nil; 288 } 289 290 snprint(name, l, "%s/ctl", dev); 291 if((ctlfd = open(name, ORDWR)) < 0) { 292 free(name); 293 Error: 294 close(rawfd); 295 return nil; 296 } 297 free(name); 298 299 n = readn(ctlfd, buf, sizeof buf); 300 close(ctlfd); 301 if(n <= 0) 302 goto Error; 303 304 if(strncmp(buf, "inquiry ", 8) != 0 || (p = strchr(buf, '\n')) == nil) 305 goto Error; 306 *p = '\0'; 307 308 if((p = strdup(buf+8)) == nil) 309 goto Error; 310 311 s = malloc(sizeof(*s)); 312 if(s == nil) { 313 Error1: 314 free(p); 315 goto Error; 316 } 317 memset(s, 0, sizeof(*s)); 318 319 s->rawfd = rawfd; 320 s->inquire = p; 321 s->changetime = time(0); 322 323 if(scsiready(s) < 0) 324 goto Error1; 325 326 return s; 327 }