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