1 /* 2 * Storage Device. 3 */ 4 #include "u.h" 5 #include "mem.h" 6 #include "lib.h" 7 #include "dat.h" 8 #include "fns.h" 9 #include "io.h" 10 #include "ureg.h" 11 #include "error.h" 12 13 #include "sd.h" 14 #include "fs.h" 15 16 #define parttrace 0 17 18 19 extern SDifc* sdifc[]; 20 21 static SDev* sdlist; 22 static SDunit** sdunit; 23 static int sdnunit; 24 static int _sdmask; 25 static int cdmask; 26 static int sdmask; 27 28 enum { 29 Rawcmd, 30 Rawdata, 31 Rawstatus, 32 }; 33 34 void 35 sdaddpart(SDunit* unit, char* name, uvlong start, uvlong end) 36 { 37 SDpart *pp; 38 int i, partno; 39 40 if(parttrace) 41 print("add %d %s %s %lld %lld\n", unit->npart, unit->name, name, start, end); 42 /* 43 * Check name not already used 44 * and look for a free slot. 45 */ 46 if(unit->part != nil){ 47 partno = -1; 48 for(i = 0; i < SDnpart; i++){ 49 pp = &unit->part[i]; 50 if(!pp->valid){ 51 if(partno == -1) 52 partno = i; 53 break; 54 } 55 if(strcmp(name, pp->name) == 0){ 56 if(pp->start == start && pp->end == end){ 57 if(parttrace) 58 print("already present\n"); 59 return; 60 } 61 } 62 } 63 }else{ 64 if((unit->part = malloc(sizeof(SDpart)*SDnpart)) == nil){ 65 if(parttrace) 66 print("malloc failed\n"); 67 return; 68 } 69 partno = 0; 70 } 71 72 /* 73 * Check there is a free slot and size and extent are valid. 74 */ 75 if(partno == -1 || start > end || end > unit->sectors){ 76 print("cannot add %s!%s [%llud,%llud) to disk [0,%llud): %s\n", 77 unit->name, name, start, end, unit->sectors, 78 partno==-1 ? "no free partitions" : "partition boundaries out of range"); 79 return; 80 } 81 pp = &unit->part[partno]; 82 pp->start = start; 83 pp->end = end; 84 strncpy(pp->name, name, NAMELEN); 85 pp->valid = 1; 86 unit->npart++; 87 } 88 89 void 90 sddelpart(SDunit* unit, char* name) 91 { 92 int i; 93 SDpart *pp; 94 95 if(parttrace) 96 print("del %d %s %s\n", unit->npart, unit->name, name); 97 /* 98 * Look for the partition to delete. 99 * Can't delete if someone still has it open. 100 * If it's the last valid partition zap the 101 * whole table. 102 */ 103 pp = unit->part; 104 for(i = 0; i < SDnpart; i++){ 105 if(strncmp(name, pp->name, NAMELEN) == 0) 106 break; 107 pp++; 108 } 109 if(i >= SDnpart) 110 return; 111 pp->valid = 0; 112 113 unit->npart--; 114 if(unit->npart == 0){ 115 free(unit->part); 116 unit->part = nil; 117 } 118 } 119 120 static int 121 sdinitpart(SDunit* unit) 122 { 123 unit->sectors = unit->secsize = 0; 124 unit->npart = 0; 125 if(unit->part){ 126 free(unit->part); 127 unit->part = nil; 128 } 129 130 if(unit->inquiry[0] & 0xC0) 131 return 0; 132 switch(unit->inquiry[0] & 0x1F){ 133 case 0x00: /* DA */ 134 case 0x04: /* WORM */ 135 case 0x05: /* CD-ROM */ 136 case 0x07: /* MO */ 137 break; 138 default: 139 return 0; 140 } 141 142 if(unit->dev->ifc->online == nil || unit->dev->ifc->online(unit) == 0) 143 return 0; 144 sdaddpart(unit, "data", 0, unit->sectors); 145 return 1; 146 } 147 148 static SDunit* 149 sdgetunit(SDev* sdev, int subno) 150 { 151 int index; 152 SDunit *unit; 153 154 /* 155 * Associate a unit with a given device and sub-unit 156 * number on that device. 157 * The device will be probed if it has not already been 158 * successfully accessed. 159 */ 160 qlock(&sdqlock); 161 index = sdev->index+subno; 162 unit = sdunit[index]; 163 if(unit == nil){ 164 if((unit = malloc(sizeof(SDunit))) == nil){ 165 qunlock(&sdqlock); 166 return nil; 167 } 168 169 if(sdev->enabled == 0 && sdev->ifc->enable) 170 sdev->ifc->enable(sdev); 171 sdev->enabled = 1; 172 173 snprint(unit->name, NAMELEN, "sd%c%d", sdev->idno, subno); 174 unit->subno = subno; 175 unit->dev = sdev; 176 177 /* 178 * No need to lock anything here as this is only 179 * called before the unit is made available in the 180 * sdunit[] array. 181 */ 182 if(unit->dev->ifc->verify(unit) == 0){ 183 qunlock(&sdqlock); 184 free(unit); 185 return nil; 186 } 187 sdunit[index] = unit; 188 } 189 qunlock(&sdqlock); 190 191 return unit; 192 } 193 194 static SDunit* 195 sdindex2unit(int index) 196 { 197 SDev *sdev; 198 199 /* 200 * Associate a unit with a given index into the top-level 201 * device directory. 202 * The device will be probed if it has not already been 203 * successfully accessed. 204 */ 205 for(sdev = sdlist; sdev != nil; sdev = sdev->next){ 206 if(index >= sdev->index && index < sdev->index+sdev->nunit) 207 return sdgetunit(sdev, index-sdev->index); 208 } 209 210 return nil; 211 } 212 213 static void 214 _sddetach(void) 215 { 216 SDev *sdev; 217 218 for(sdev = sdlist; sdev != nil; sdev = sdev->next){ 219 if(sdev->enabled == 0) 220 continue; 221 if(sdev->ifc->disable) 222 sdev->ifc->disable(sdev); 223 sdev->enabled = 0; 224 } 225 } 226 227 static void 228 sddump(void) 229 { 230 SDev *sdev; 231 232 print("sdevs:\n"); 233 for(sdev = sdlist; sdev != nil; sdev = sdev->next){ 234 print("sdev %c index %d nunit %d: ", 235 sdev->idno, sdev->index, sdev->nunit); 236 print("\n"); 237 } 238 } 239 240 static int 241 _sdinit(void) 242 { 243 ulong m; 244 int i; 245 SDev *sdev, *tail; 246 SDunit *unit; 247 248 /* 249 * Probe all configured controllers and make a list 250 * of devices found, accumulating a possible maximum number 251 * of units attached and marking each device with an index 252 * into the linear top-level directory array of units. 253 */ 254 tail = nil; 255 for(i = 0; sdifc[i] != nil; i++){ 256 if((sdev = sdifc[i]->pnp()) == nil) 257 continue; 258 if(sdlist != nil) 259 tail->next = sdev; 260 else 261 sdlist = sdev; 262 for(tail = sdev; tail->next != nil; tail = tail->next){ 263 tail->index = sdnunit; 264 sdnunit += tail->nunit; 265 } 266 tail->index = sdnunit; 267 sdnunit += tail->nunit; 268 } 269 /* 270 * Legacy and option code goes here. This will be hard... 271 */ 272 273 /* 274 * The maximum number of possible units is known, allocate 275 * placeholders for their datastructures; the units will be 276 * probed and structures allocated when attached. 277 * Allocate controller names for the different types. 278 */ 279 if(sdnunit == 0) 280 return 0; 281 if((sdunit = malloc(sdnunit*sizeof(SDunit*))) == nil) 282 return 0; 283 sddetach = _sddetach; 284 285 for(i = 0; sdifc[i] != nil; i++){ 286 if(sdifc[i]->id) 287 sdifc[i]->id(sdlist); 288 } 289 if (0) 290 sddump(); 291 292 m = 0; 293 cdmask = sdmask = 0; 294 for(i=0; i<sdnunit && i < 32; i++) { 295 unit = sdindex2unit(i); 296 if(unit == nil) 297 continue; 298 sdinitpart(unit); 299 partition(unit); 300 if(unit->npart > 0){ /* BUG */ 301 if((unit->inquiry[0] & 0x1F) == 0x05) 302 cdmask |= (1<<i); 303 else 304 sdmask |= (1<<i); 305 m |= (1<<i); 306 } 307 } 308 309 //notesdinfo(); 310 _sdmask = m; 311 return m; 312 } 313 314 int 315 cdinit(void) 316 { 317 if(sdnunit == 0) 318 _sdinit(); 319 return cdmask; 320 } 321 322 int 323 sdinit(void) 324 { 325 if(sdnunit == 0) 326 _sdinit(); 327 return sdmask; 328 } 329 330 void 331 sdinitdev(int i, char *s) 332 { 333 SDunit *unit; 334 335 unit = sdindex2unit(i); 336 strcpy(s, unit->name); 337 } 338 339 void 340 sdprintdevs(int i) 341 { 342 char *s; 343 SDunit *unit; 344 345 unit = sdindex2unit(i); 346 for(i=0; i<unit->npart; i++){ 347 s = unit->part[i].name; 348 if(strncmp(s, "dos", 3) == 0 349 || strncmp(s, "9fat", 4) == 0 350 || strncmp(s, "fs", 2) == 0) 351 print(" %s!%s", unit->name, s); 352 } 353 } 354 355 SDpart* 356 sdfindpart(SDunit *unit, char *name) 357 { 358 int i; 359 360 if(parttrace) 361 print("findpart %d %s %s\t\n", unit->npart, unit->name, name); 362 for(i=0; i<unit->npart; i++) { 363 if(parttrace) 364 print("%s...", unit->part[i].name); 365 if(strcmp(unit->part[i].name, name) == 0){ 366 if(parttrace) 367 print("\n"); 368 return &unit->part[i]; 369 } 370 } 371 if(parttrace) 372 print("not found\n"); 373 return nil; 374 } 375 376 typedef struct Scsicrud Scsicrud; 377 struct Scsicrud { 378 Fs fs; 379 vlong offset; 380 SDunit *unit; 381 SDpart *part; 382 }; 383 384 long 385 sdread(Fs *vcrud, void *v, long n) 386 { 387 Scsicrud *crud; 388 long x; 389 390 crud = (Scsicrud*)vcrud; 391 x = sdbio(crud->unit, crud->part, v, n, crud->offset); 392 if(x > 0) 393 crud->offset += x; 394 return x; 395 } 396 397 vlong 398 sdseek(Fs *vcrud, vlong seek) 399 { 400 ((Scsicrud*)vcrud)->offset = seek; 401 return seek; 402 } 403 404 void* 405 sdgetfspart(int i, char *s, int chatty) 406 { 407 SDunit *unit; 408 SDpart *p; 409 Scsicrud *crud; 410 411 if(cdmask&(1<<i)){ 412 if(strcmp(s, "cdboot") != 0) 413 return nil; 414 }else if(sdmask&(1<<i)){ 415 if(strcmp(s, "cdboot") == 0) 416 return nil; 417 } 418 419 unit = sdindex2unit(i); 420 if((p = sdfindpart(unit, s)) == nil){ 421 if(chatty) 422 print("unknown partition %s!%s\n", unit->name, s); 423 return nil; 424 } 425 if(p->crud == nil) { 426 crud = malloc(sizeof(Scsicrud)); 427 crud->fs.dev = i; 428 crud->fs.diskread = sdread; 429 crud->fs.diskseek = sdseek; 430 // crud->start = 0; 431 crud->unit = unit; 432 crud->part = p; 433 if(dosinit(&crud->fs) < 0 && dosinit(&crud->fs) < 0 && kfsinit(&crud->fs) < 0){ 434 if(chatty) 435 print("partition %s!%s does not contain a DOS or KFS file system\n", 436 unit->name, s); 437 return nil; 438 } 439 p->crud = crud; 440 } 441 return p->crud; 442 } 443 444 /* 445 * Leave partitions around for devsd to pick up. 446 * (Needed by boot process; more extensive 447 * partitioning is done by termrc or cpurc). 448 */ 449 void 450 sdaddconf(int i) 451 { 452 SDunit *unit; 453 SDpart *pp; 454 455 unit = sdindex2unit(i); 456 457 /* 458 * If there were no partitions (just data and partition), don't bother. 459 */ 460 if(unit->npart<= 1 || (unit->npart==2 && strcmp(unit->part[1].name, "partition")==0)) 461 return; 462 463 addconf("%spart=", unit->name); 464 for(i=1, pp=&unit->part[i]; i<unit->npart; i++, pp++) /* skip 0, which is "data" */ 465 addconf("%s%s %lld %lld", i==1 ? "" : "/", pp->name, 466 pp->start, pp->end); 467 addconf("\n"); 468 } 469 470 int 471 sdboot(int dev, char *pname, Boot *b) 472 { 473 char *file; 474 Fs *fs; 475 476 if((file = strchr(pname, '!')) == nil) { 477 print("syntax is sdC0!partition!file\n"); 478 return -1; 479 } 480 *file++ = '\0'; 481 482 fs = sdgetfspart(dev, pname, 1); 483 if(fs == nil) 484 return -1; 485 486 return fsboot(fs, file, b); 487 } 488 489 long 490 sdbio(SDunit *unit, SDpart *pp, void* va, long len, vlong off) 491 { 492 long l; 493 ulong bno, max, nb, offset; 494 static uchar *b; 495 char *a; 496 static ulong bsz; 497 498 a = va; 499 memset(a, 0xDA, len); 500 qlock(&unit->ctl); 501 if(unit->changed){ 502 qunlock(&unit->ctl); 503 return 0; 504 } 505 506 /* 507 * Check the request is within bounds. 508 * Removeable drives are locked throughout the I/O 509 * in case the media changes unexpectedly. 510 * Non-removeable drives are not locked during the I/O 511 * to allow the hardware to optimise if it can; this is 512 * a little fast and loose. 513 * It's assumed that non-removable media parameters 514 * (sectors, secsize) can't change once the drive has 515 * been brought online. 516 */ 517 bno = (off/unit->secsize) + pp->start; 518 nb = ((off+len+unit->secsize-1)/unit->secsize) + pp->start - bno; 519 max = SDmaxio/unit->secsize; 520 if(nb > max) 521 nb = max; 522 if(bno+nb > pp->end) 523 nb = pp->end - bno; 524 if(bno >= pp->end || nb == 0){ 525 qunlock(&unit->ctl); 526 return 0; 527 } 528 if(!(unit->inquiry[1] & 0x80)) 529 qunlock(&unit->ctl); 530 531 if(bsz < nb*unit->secsize){ 532 b = malloc(nb*unit->secsize); 533 bsz = nb*unit->secsize; 534 } 535 // b = sdmalloc(nb*unit->secsize); 536 // if(b == nil) 537 // return 0; 538 539 offset = off%unit->secsize; 540 if((l = unit->dev->ifc->bio(unit, 0, 0, b, nb, bno)) < 0) { 541 // sdfree(b); 542 return 0; 543 } 544 545 if(l < offset) 546 len = 0; 547 else if(len > l - offset) 548 len = l - offset; 549 if(len) 550 memmove(a, b+offset, len); 551 // sdfree(b); 552 553 if(unit->inquiry[1] & 0x80) 554 qunlock(&unit->ctl); 555 556 return len; 557 } 558 559 #ifdef DMA 560 long 561 sdrio(SDreq *r, void* a, long n) 562 { 563 if(n >= SDmaxio || n < 0) 564 return 0; 565 566 r->data = nil; 567 if(n){ 568 if((r->data = malloc(n)) == nil) 569 return 0; 570 if(r->write) 571 memmove(r->data, a, n); 572 } 573 r->dlen = n; 574 575 if(r->unit->dev->ifc->rio(r) != SDok){ 576 // cgascreenputs("1", 1); 577 if(r->data != nil){ 578 sdfree(r->data); 579 r->data = nil; 580 } 581 return 0; 582 } 583 // cgascreenputs("2", 1); 584 585 if(!r->write && r->rlen > 0) 586 memmove(a, r->data, r->rlen); 587 // cgascreenputs("3", 1); 588 if(r->data != nil){ 589 sdfree(r->data); 590 r->data = nil; 591 } 592 593 // cgascreenputs("4", 1); 594 return r->rlen; 595 } 596 #endif /* DMA */ 597 598 void 599 sleep(void*, int (*fn)(void*), void *v) 600 { 601 int x; 602 x = spllo(); 603 while(!fn(v)) 604 ; 605 splx(x); 606 return; 607 } 608 609 void 610 tsleep(void*, int (*fn)(void*), void *v, int msec) 611 { 612 int x; 613 ulong start; 614 615 x = spllo(); 616 for(start = m->ticks; TK2MS(m->ticks - start) < msec 617 && !fn(v); ) 618 ; 619 splx(x); 620 return; 621 } 622 623 void* 624 sdmalloc(void *p, ulong sz) 625 { 626 if(p != nil) { 627 memset(p, 0, sz); 628 return p; 629 } 630 return malloc(sz); 631 } 632