sdscsi.c (7937B)
1 #include "u.h" 2 #include "lib.h" 3 #include "mem.h" 4 #include "dat.h" 5 #include "fns.h" 6 #include "io.h" 7 #include "ureg.h" 8 #include "error.h" 9 10 #include "sd.h" 11 12 static int 13 scsitest(SDreq* r) 14 { 15 r->write = 0; 16 memset(r->cmd, 0, sizeof(r->cmd)); 17 r->cmd[1] = r->lun<<5; 18 r->clen = 6; 19 r->data = nil; 20 r->dlen = 0; 21 r->flags = 0; 22 23 r->status = ~0; 24 25 return r->unit->dev->ifc->rio(r); 26 } 27 28 int 29 scsiverify(SDunit* unit) 30 { 31 SDreq *r; 32 int i, status; 33 uchar *inquiry; 34 35 if((r = malloc(sizeof(SDreq))) == nil) 36 return 0; 37 if((inquiry = sdmalloc(sizeof(unit->inquiry))) == nil){ 38 free(r); 39 return 0; 40 } 41 r->unit = unit; 42 r->lun = 0; /* ??? */ 43 44 memset(unit->inquiry, 0, sizeof(unit->inquiry)); 45 r->write = 0; 46 r->cmd[0] = 0x12; 47 r->cmd[1] = r->lun<<5; 48 r->cmd[4] = sizeof(unit->inquiry)-1; 49 r->clen = 6; 50 r->data = inquiry; 51 r->dlen = sizeof(unit->inquiry)-1; 52 r->flags = 0; 53 54 r->status = ~0; 55 if(unit->dev->ifc->rio(r) != SDok){ 56 free(r); 57 return 0; 58 } 59 memmove(unit->inquiry, inquiry, r->dlen); 60 free(inquiry); 61 62 status = 0; 63 for(i = 0; i < 3; i++){ 64 while((status = scsitest(r)) == SDbusy) 65 ; 66 if(status == SDok || status != SDcheck) 67 break; 68 if(!(r->flags & SDvalidsense)) 69 break; 70 if((r->sense[2] & 0x0F) != 0x02) 71 continue; 72 73 /* 74 * Unit is 'not ready'. 75 * If it is in the process of becoming ready or needs 76 * an initialising command, set status so it will be spun-up 77 * below. 78 * If there's no medium, that's OK too, but don't 79 * try to spin it up. 80 */ 81 if(r->sense[12] == 0x04){ 82 if(r->sense[13] == 0x02 || r->sense[13] == 0x01){ 83 status = SDok; 84 break; 85 } 86 } 87 if(r->sense[12] == 0x3A) 88 break; 89 } 90 91 if(status == SDok){ 92 /* 93 * Try to ensure a direct-access device is spinning. 94 * Don't wait for completion, ignore the result. 95 */ 96 if((unit->inquiry[0] & 0x1F) == 0){ 97 memset(r->cmd, 0, sizeof(r->cmd)); 98 r->write = 0; 99 r->cmd[0] = 0x1B; 100 r->cmd[1] = (r->lun<<5)|0x01; 101 r->cmd[4] = 1; 102 r->clen = 6; 103 r->data = nil; 104 r->dlen = 0; 105 r->flags = 0; 106 107 r->status = ~0; 108 unit->dev->ifc->rio(r); 109 } 110 } 111 free(r); 112 113 if(status == SDok || status == SDcheck) 114 return 1; 115 return 0; 116 } 117 118 static int 119 scsirio(SDreq* r) 120 { 121 /* 122 * Perform an I/O request, returning 123 * -1 failure 124 * 0 ok 125 * 1 no medium present 126 * 2 retry 127 * The contents of r may be altered so the 128 * caller should re-initialise if necesary. 129 */ 130 r->status = ~0; 131 switch(r->unit->dev->ifc->rio(r)){ 132 default: 133 break; 134 case SDcheck: 135 if(!(r->flags & SDvalidsense)) 136 break; 137 switch(r->sense[2] & 0x0F){ 138 case 0x00: /* no sense */ 139 case 0x01: /* recovered error */ 140 return 2; 141 case 0x06: /* check condition */ 142 /* 143 * 0x28 - not ready to ready transition, 144 * medium may have changed. 145 * 0x29 - power on or some type of reset. 146 */ 147 if(r->sense[12] == 0x28 && r->sense[13] == 0) 148 return 2; 149 if(r->sense[12] == 0x29) 150 return 2; 151 break; 152 case 0x02: /* not ready */ 153 /* 154 * If no medium present, bail out. 155 * If unit is becoming ready, rather than not 156 * not ready, wait a little then poke it again. */ 157 if(r->sense[12] == 0x3A) 158 break; 159 if(r->sense[12] != 0x04 || r->sense[13] != 0x01) 160 break; 161 162 while(waserror()) 163 ; 164 tsleep(&up->sleep, return0, 0, 500); 165 poperror(); 166 scsitest(r); 167 return 2; 168 default: 169 break; 170 } 171 break; 172 case SDok: 173 return 0; 174 } 175 return -1; 176 } 177 178 int 179 scsionline(SDunit* unit) 180 { 181 SDreq *r; 182 uchar *p; 183 int ok, retries; 184 185 if((r = malloc(sizeof(SDreq))) == nil) 186 return 0; 187 if((p = sdmalloc(8)) == nil){ 188 free(r); 189 return 0; 190 } 191 192 ok = 0; 193 194 r->unit = unit; 195 r->lun = 0; /* ??? */ 196 for(retries = 0; retries < 10; retries++){ 197 /* 198 * Read-capacity is mandatory for DA, WORM, CD-ROM and 199 * MO. It may return 'not ready' if type DA is not 200 * spun up, type MO or type CD-ROM are not loaded or just 201 * plain slow getting their act together after a reset. 202 */ 203 r->write = 0; 204 memset(r->cmd, 0, sizeof(r->cmd)); 205 r->cmd[0] = 0x25; 206 r->cmd[1] = r->lun<<5; 207 r->clen = 10; 208 r->data = p; 209 r->dlen = 8; 210 r->flags = 0; 211 212 r->status = ~0; 213 switch(scsirio(r)){ 214 default: 215 break; 216 case 0: 217 unit->sectors = (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3]; 218 unit->secsize = (p[4]<<24)|(p[5]<<16)|(p[6]<<8)|p[7]; 219 220 /* 221 * Some ATAPI CD readers lie about the block size. 222 * Since we don't read audio via this interface 223 * it's okay to always fudge this. 224 */ 225 if(unit->secsize == 2352) 226 unit->secsize = 2048; 227 /* 228 * Devices with removable media may return 0 sectors 229 * when they have empty media (e.g. sata dvd writers); 230 * if so, keep the count zero. 231 * 232 * Read-capacity returns the LBA of the last sector, 233 * therefore the number of sectors must be incremented. 234 */ 235 if(unit->sectors != 0) 236 unit->sectors++; 237 ok = 1; 238 break; 239 case 1: 240 ok = 1; 241 break; 242 case 2: 243 continue; 244 } 245 break; 246 } 247 free(p); 248 free(r); 249 250 if(ok) 251 return ok+retries; 252 else 253 return 0; 254 } 255 256 int 257 scsiexec(SDunit* unit, int write, uchar* cmd, int clen, void* data, int* dlen) 258 { 259 SDreq *r; 260 int status; 261 262 if((r = malloc(sizeof(SDreq))) == nil) 263 return SDmalloc; 264 r->unit = unit; 265 r->lun = cmd[1]>>5; /* ??? */ 266 r->write = write; 267 memmove(r->cmd, cmd, clen); 268 r->clen = clen; 269 r->data = data; 270 if(dlen) 271 r->dlen = *dlen; 272 r->flags = 0; 273 274 r->status = ~0; 275 276 /* 277 * Call the device-specific I/O routine. 278 * There should be no calls to 'error()' below this 279 * which percolate back up. 280 */ 281 switch(status = unit->dev->ifc->rio(r)){ 282 case SDok: 283 if(dlen) 284 *dlen = r->rlen; 285 /*FALLTHROUGH*/ 286 case SDcheck: 287 /*FALLTHROUGH*/ 288 default: 289 /* 290 * It's more complicated than this. There are conditions 291 * which are 'ok' but for which the returned status code 292 * is not 'SDok'. 293 * Also, not all conditions require a reqsense, might 294 * need to do a reqsense here and make it available to the 295 * caller somehow. 296 * 297 * MaƱana. 298 */ 299 break; 300 } 301 sdfree(r); 302 303 return status; 304 } 305 306 static void 307 scsifmt10(SDreq *r, int write, int lun, ulong nb, uvlong bno) 308 { 309 uchar *c; 310 311 c = r->cmd; 312 if(write == 0) 313 c[0] = 0x28; 314 else 315 c[0] = 0x2A; 316 c[1] = lun<<5; 317 c[2] = bno>>24; 318 c[3] = bno>>16; 319 c[4] = bno>>8; 320 c[5] = bno; 321 c[6] = 0; 322 c[7] = nb>>8; 323 c[8] = nb; 324 c[9] = 0; 325 326 r->clen = 10; 327 } 328 329 static void 330 scsifmt16(SDreq *r, int write, int lun, ulong nb, uvlong bno) 331 { 332 uchar *c; 333 334 c = r->cmd; 335 if(write == 0) 336 c[0] = 0x88; 337 else 338 c[0] = 0x8A; 339 c[1] = lun<<5; /* so wrong */ 340 c[2] = bno>>56; 341 c[3] = bno>>48; 342 c[4] = bno>>40; 343 c[5] = bno>>32; 344 c[6] = bno>>24; 345 c[7] = bno>>16; 346 c[8] = bno>>8; 347 c[9] = bno; 348 c[10] = nb>>24; 349 c[11] = nb>>16; 350 c[12] = nb>>8; 351 c[13] = nb; 352 c[14] = 0; 353 c[15] = 0; 354 355 r->clen = 16; 356 } 357 358 long 359 scsibio(SDunit* unit, int lun, int write, void* data, long nb, uvlong bno) 360 { 361 SDreq *r; 362 long rlen; 363 364 if((r = malloc(sizeof(SDreq))) == nil) 365 error(Enomem); 366 r->unit = unit; 367 r->lun = lun; 368 again: 369 r->write = write; 370 if(bno >= (1ULL<<32)) 371 scsifmt16(r, write, lun, nb, bno); 372 else 373 scsifmt10(r, write, lun, nb, bno); 374 r->data = data; 375 r->dlen = nb*unit->secsize; 376 r->flags = 0; 377 378 r->status = ~0; 379 switch(scsirio(r)){ 380 default: 381 rlen = -1; 382 break; 383 case 0: 384 rlen = r->rlen; 385 break; 386 case 2: 387 rlen = -1; 388 if(!(r->flags & SDvalidsense)) 389 break; 390 switch(r->sense[2] & 0x0F){ 391 default: 392 break; 393 case 0x01: /* recovered error */ 394 print("%s: recovered error at sector %llud\n", 395 unit->perm.name, bno); 396 rlen = r->rlen; 397 break; 398 case 0x06: /* check condition */ 399 /* 400 * Check for a removeable media change. 401 * If so, mark it by zapping the geometry info 402 * to force an online request. 403 */ 404 if(r->sense[12] != 0x28 || r->sense[13] != 0) 405 break; 406 if(unit->inquiry[1] & 0x80) 407 unit->sectors = 0; 408 break; 409 case 0x02: /* not ready */ 410 /* 411 * If unit is becoming ready, 412 * rather than not not ready, try again. 413 */ 414 if(r->sense[12] == 0x04 && r->sense[13] == 0x01) 415 goto again; 416 break; 417 } 418 break; 419 } 420 free(r); 421 422 return rlen; 423 } 424