1 /* 2 * Storage Device. 3 */ 4 #include "u.h" 5 #include "../port/lib.h" 6 #include "mem.h" 7 #include "dat.h" 8 #include "fns.h" 9 #include "io.h" 10 #include "ureg.h" 11 #include "../port/error.h" 12 13 #include "../port/sd.h" 14 15 extern Dev sddevtab; 16 extern SDifc* sdifc[]; 17 18 static char Echange[] = "media or partition has changed"; 19 20 static char devletters[] = "0123456789" 21 "abcdefghijklmnopqrstuvwxyz" 22 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 23 24 static SDev *devs[sizeof devletters-1]; 25 static QLock devslock; 26 27 enum { 28 Rawcmd, 29 Rawdata, 30 Rawstatus, 31 }; 32 33 enum { 34 Qtopdir = 1, /* top level directory */ 35 Qtopbase, 36 Qtopctl = Qtopbase, 37 38 Qunitdir, /* directory per unit */ 39 Qunitbase, 40 Qctl = Qunitbase, 41 Qraw, 42 Qpart, 43 44 TypeLOG = 4, 45 NType = (1<<TypeLOG), 46 TypeMASK = (NType-1), 47 TypeSHIFT = 0, 48 49 PartLOG = 8, 50 NPart = (1<<PartLOG), 51 PartMASK = (NPart-1), 52 PartSHIFT = TypeLOG, 53 54 UnitLOG = 8, 55 NUnit = (1<<UnitLOG), 56 UnitMASK = (NUnit-1), 57 UnitSHIFT = (PartLOG+TypeLOG), 58 59 DevLOG = 8, 60 NDev = (1 << DevLOG), 61 DevMASK = (NDev-1), 62 DevSHIFT = (UnitLOG+PartLOG+TypeLOG), 63 64 Ncmd = 20, 65 }; 66 67 #define TYPE(q) ((((ulong)(q).path)>>TypeSHIFT) & TypeMASK) 68 #define PART(q) ((((ulong)(q).path)>>PartSHIFT) & PartMASK) 69 #define UNIT(q) ((((ulong)(q).path)>>UnitSHIFT) & UnitMASK) 70 #define DEV(q) ((((ulong)(q).path)>>DevSHIFT) & DevMASK) 71 #define QID(d,u, p, t) (((d)<<DevSHIFT)|((u)<<UnitSHIFT)|\ 72 ((p)<<PartSHIFT)|((t)<<TypeSHIFT)) 73 74 75 void 76 sdaddpart(SDunit* unit, char* name, uvlong start, uvlong end) 77 { 78 SDpart *pp; 79 int i, partno; 80 81 /* 82 * Check name not already used 83 * and look for a free slot. 84 */ 85 if(unit->part != nil){ 86 partno = -1; 87 for(i = 0; i < unit->npart; i++){ 88 pp = &unit->part[i]; 89 if(!pp->valid){ 90 if(partno == -1) 91 partno = i; 92 break; 93 } 94 if(strcmp(name, pp->name) == 0){ 95 if(pp->start == start && pp->end == end) 96 return; 97 error(Ebadctl); 98 } 99 } 100 } 101 else{ 102 if((unit->part = malloc(sizeof(SDpart)*SDnpart)) == nil) 103 error(Enomem); 104 unit->npart = SDnpart; 105 partno = 0; 106 } 107 108 /* 109 * If no free slot found then increase the 110 * array size (can't get here with unit->part == nil). 111 */ 112 if(partno == -1){ 113 if(unit->npart >= NPart) 114 error(Enomem); 115 if((pp = malloc(sizeof(SDpart)*(unit->npart+SDnpart))) == nil) 116 error(Enomem); 117 memmove(pp, unit->part, sizeof(SDpart)*unit->npart); 118 free(unit->part); 119 unit->part = pp; 120 partno = unit->npart; 121 unit->npart += SDnpart; 122 } 123 124 /* 125 * Check size and extent are valid. 126 */ 127 if(start > end || end > unit->sectors) 128 error(Eio); 129 pp = &unit->part[partno]; 130 pp->start = start; 131 pp->end = end; 132 kstrdup(&pp->name, name); 133 kstrdup(&pp->user, eve); 134 pp->perm = 0640; 135 pp->valid = 1; 136 } 137 138 static void 139 sddelpart(SDunit* unit, char* name) 140 { 141 int i; 142 SDpart *pp; 143 144 /* 145 * Look for the partition to delete. 146 * Can't delete if someone still has it open. 147 */ 148 pp = unit->part; 149 for(i = 0; i < unit->npart; i++){ 150 if(strcmp(name, pp->name) == 0) 151 break; 152 pp++; 153 } 154 if(i >= unit->npart) 155 error(Ebadctl); 156 if(strcmp(up->user, pp->user) && !iseve()) 157 error(Eperm); 158 pp->valid = 0; 159 pp->vers++; 160 } 161 162 static void 163 sdincvers(SDunit *unit) 164 { 165 int i; 166 167 unit->vers++; 168 if(unit->part){ 169 for(i = 0; i < unit->npart; i++){ 170 unit->part[i].valid = 0; 171 unit->part[i].vers++; 172 } 173 } 174 } 175 176 static int 177 sdinitpart(SDunit* unit) 178 { 179 int nf; 180 uvlong start, end; 181 char *f[4], *p, *q, buf[10]; 182 183 if(unit->sectors > 0){ 184 unit->sectors = unit->secsize = 0; 185 sdincvers(unit); 186 } 187 188 /* device must be connected or not; other values are trouble */ 189 if(unit->inquiry[0] & 0xC0) /* see SDinq0periphqual */ 190 return 0; 191 switch(unit->inquiry[0] & SDinq0periphtype){ 192 case SDperdisk: 193 case SDperworm: 194 case SDpercd: 195 case SDpermo: 196 break; 197 default: 198 return 0; 199 } 200 201 if(unit->dev->ifc->online) 202 unit->dev->ifc->online(unit); 203 if(unit->sectors){ 204 sdincvers(unit); 205 sdaddpart(unit, "data", 0, unit->sectors); 206 207 /* 208 * Use partitions passed from boot program, 209 * e.g. 210 * sdC0part=dos 63 123123/plan9 123123 456456 211 * This happens before /boot sets hostname so the 212 * partitions will have the null-string for user. 213 * The gen functions patch it up. 214 */ 215 snprint(buf, sizeof buf, "%spart", unit->name); 216 for(p = getconf(buf); p != nil; p = q){ 217 if(q = strchr(p, '/')) 218 *q++ = '\0'; 219 nf = tokenize(p, f, nelem(f)); 220 if(nf < 3) 221 continue; 222 223 start = strtoull(f[1], 0, 0); 224 end = strtoull(f[2], 0, 0); 225 if(!waserror()){ 226 sdaddpart(unit, f[0], start, end); 227 poperror(); 228 } 229 } 230 } 231 232 return 1; 233 } 234 235 static int 236 sdindex(int idno) 237 { 238 char *p; 239 240 p = strchr(devletters, idno); 241 if(p == nil) 242 return -1; 243 return p-devletters; 244 } 245 246 static SDev* 247 sdgetdev(int idno) 248 { 249 SDev *sdev; 250 int i; 251 252 if((i = sdindex(idno)) < 0) 253 return nil; 254 255 qlock(&devslock); 256 if(sdev = devs[i]) 257 incref(&sdev->r); 258 qunlock(&devslock); 259 return sdev; 260 } 261 262 static SDunit* 263 sdgetunit(SDev* sdev, int subno) 264 { 265 SDunit *unit; 266 char buf[32]; 267 268 /* 269 * Associate a unit with a given device and sub-unit 270 * number on that device. 271 * The device will be probed if it has not already been 272 * successfully accessed. 273 */ 274 qlock(&sdev->unitlock); 275 if(subno > sdev->nunit){ 276 qunlock(&sdev->unitlock); 277 return nil; 278 } 279 280 unit = sdev->unit[subno]; 281 if(unit == nil){ 282 /* 283 * Probe the unit only once. This decision 284 * may be a little severe and reviewed later. 285 */ 286 if(sdev->unitflg[subno]){ 287 qunlock(&sdev->unitlock); 288 return nil; 289 } 290 if((unit = malloc(sizeof(SDunit))) == nil){ 291 qunlock(&sdev->unitlock); 292 return nil; 293 } 294 sdev->unitflg[subno] = 1; 295 296 snprint(buf, sizeof(buf), "%s%d", sdev->name, subno); 297 kstrdup(&unit->name, buf); 298 kstrdup(&unit->user, eve); 299 unit->perm = 0555; 300 unit->subno = subno; 301 unit->dev = sdev; 302 303 if(sdev->enabled == 0 && sdev->ifc->enable) 304 sdev->ifc->enable(sdev); 305 sdev->enabled = 1; 306 307 /* 308 * No need to lock anything here as this is only 309 * called before the unit is made available in the 310 * sdunit[] array. 311 */ 312 if(unit->dev->ifc->verify(unit) == 0){ 313 qunlock(&sdev->unitlock); 314 free(unit); 315 return nil; 316 } 317 sdev->unit[subno] = unit; 318 } 319 qunlock(&sdev->unitlock); 320 return unit; 321 } 322 323 static void 324 sdreset(void) 325 { 326 int i; 327 SDev *sdev; 328 329 /* 330 * Probe all known controller types and register any devices found. 331 */ 332 for(i = 0; sdifc[i] != nil; i++){ 333 if(sdifc[i]->pnp == nil || (sdev = sdifc[i]->pnp()) == nil) 334 continue; 335 sdadddevs(sdev); 336 } 337 } 338 339 void 340 sdadddevs(SDev *sdev) 341 { 342 int i, j, id; 343 SDev *next; 344 345 for(; sdev; sdev=next){ 346 next = sdev->next; 347 348 sdev->unit = (SDunit**)malloc(sdev->nunit * sizeof(SDunit*)); 349 sdev->unitflg = (int*)malloc(sdev->nunit * sizeof(int)); 350 if(sdev->unit == nil || sdev->unitflg == nil){ 351 print("sdadddevs: out of memory\n"); 352 giveup: 353 free(sdev->unit); 354 free(sdev->unitflg); 355 if(sdev->ifc->clear) 356 sdev->ifc->clear(sdev); 357 free(sdev); 358 continue; 359 } 360 id = sdindex(sdev->idno); 361 if(id == -1){ 362 print("sdadddevs: bad id number %d (%C)\n", id, id); 363 goto giveup; 364 } 365 qlock(&devslock); 366 for(i=0; i<nelem(devs); i++){ 367 if(devs[j = (id+i)%nelem(devs)] == nil){ 368 sdev->idno = devletters[j]; 369 devs[j] = sdev; 370 snprint(sdev->name, sizeof sdev->name, "sd%c", devletters[j]); 371 break; 372 } 373 } 374 qunlock(&devslock); 375 if(i == nelem(devs)){ 376 print("sdadddevs: out of device letters\n"); 377 goto giveup; 378 } 379 } 380 } 381 382 // void 383 // sdrmdevs(SDev *sdev) 384 // { 385 // char buf[2]; 386 // 387 // snprint(buf, sizeof buf, "%c", sdev->idno); 388 // unconfigure(buf); 389 // } 390 391 void 392 sdaddallconfs(void (*addconf)(SDunit *)) 393 { 394 int i, u; 395 SDev *sdev; 396 397 for(i = 0; i < nelem(devs); i++) /* each controller */ 398 for(sdev = devs[i]; sdev; sdev = sdev->next) 399 for(u = 0; u < sdev->nunit; u++) /* each drive */ 400 (*addconf)(sdev->unit[u]); 401 } 402 403 static int 404 sd2gen(Chan* c, int i, Dir* dp) 405 { 406 Qid q; 407 uvlong l; 408 SDpart *pp; 409 SDperm *perm; 410 SDunit *unit; 411 SDev *sdev; 412 int rv; 413 414 sdev = sdgetdev(DEV(c->qid)); 415 assert(sdev); 416 unit = sdev->unit[UNIT(c->qid)]; 417 418 rv = -1; 419 switch(i){ 420 case Qctl: 421 mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), PART(c->qid), Qctl), 422 unit->vers, QTFILE); 423 perm = &unit->ctlperm; 424 if(emptystr(perm->user)){ 425 kstrdup(&perm->user, eve); 426 perm->perm = 0644; /* nothing secret in ctl */ 427 } 428 devdir(c, q, "ctl", 0, perm->user, perm->perm, dp); 429 rv = 1; 430 break; 431 432 case Qraw: 433 mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), PART(c->qid), Qraw), 434 unit->vers, QTFILE); 435 perm = &unit->rawperm; 436 if(emptystr(perm->user)){ 437 kstrdup(&perm->user, eve); 438 perm->perm = DMEXCL|0600; 439 } 440 devdir(c, q, "raw", 0, perm->user, perm->perm, dp); 441 rv = 1; 442 break; 443 444 case Qpart: 445 pp = &unit->part[PART(c->qid)]; 446 l = (pp->end - pp->start) * unit->secsize; 447 mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), PART(c->qid), Qpart), 448 unit->vers+pp->vers, QTFILE); 449 if(emptystr(pp->user)) 450 kstrdup(&pp->user, eve); 451 devdir(c, q, pp->name, l, pp->user, pp->perm, dp); 452 rv = 1; 453 break; 454 } 455 456 decref(&sdev->r); 457 return rv; 458 } 459 460 static int 461 sd1gen(Chan* c, int i, Dir* dp) 462 { 463 Qid q; 464 465 switch(i){ 466 case Qtopctl: 467 mkqid(&q, QID(0, 0, 0, Qtopctl), 0, QTFILE); 468 devdir(c, q, "sdctl", 0, eve, 0644, dp); /* no secrets */ 469 return 1; 470 } 471 return -1; 472 } 473 474 static int 475 sdgen(Chan* c, char*, Dirtab*, int, int s, Dir* dp) 476 { 477 Qid q; 478 uvlong l; 479 int i, r; 480 SDpart *pp; 481 SDunit *unit; 482 SDev *sdev; 483 484 switch(TYPE(c->qid)){ 485 case Qtopdir: 486 if(s == DEVDOTDOT){ 487 mkqid(&q, QID(0, 0, 0, Qtopdir), 0, QTDIR); 488 sprint(up->genbuf, "#%C", sddevtab.dc); 489 devdir(c, q, up->genbuf, 0, eve, 0555, dp); 490 return 1; 491 } 492 493 if(s+Qtopbase < Qunitdir) 494 return sd1gen(c, s+Qtopbase, dp); 495 s -= (Qunitdir-Qtopbase); 496 497 qlock(&devslock); 498 for(i=0; i<nelem(devs); i++){ 499 if(devs[i]){ 500 if(s < devs[i]->nunit) 501 break; 502 s -= devs[i]->nunit; 503 } 504 } 505 506 if(i == nelem(devs)){ 507 /* Run off the end of the list */ 508 qunlock(&devslock); 509 return -1; 510 } 511 512 if((sdev = devs[i]) == nil){ 513 qunlock(&devslock); 514 return 0; 515 } 516 517 incref(&sdev->r); 518 qunlock(&devslock); 519 520 if((unit = sdev->unit[s]) == nil) 521 if((unit = sdgetunit(sdev, s)) == nil){ 522 decref(&sdev->r); 523 return 0; 524 } 525 526 mkqid(&q, QID(sdev->idno, s, 0, Qunitdir), 0, QTDIR); 527 if(emptystr(unit->user)) 528 kstrdup(&unit->user, eve); 529 devdir(c, q, unit->name, 0, unit->user, unit->perm, dp); 530 decref(&sdev->r); 531 return 1; 532 533 case Qunitdir: 534 if(s == DEVDOTDOT){ 535 mkqid(&q, QID(0, 0, 0, Qtopdir), 0, QTDIR); 536 sprint(up->genbuf, "#%C", sddevtab.dc); 537 devdir(c, q, up->genbuf, 0, eve, 0555, dp); 538 return 1; 539 } 540 541 if((sdev = sdgetdev(DEV(c->qid))) == nil){ 542 devdir(c, c->qid, "unavailable", 0, eve, 0, dp); 543 return 1; 544 } 545 546 unit = sdev->unit[UNIT(c->qid)]; 547 qlock(&unit->ctl); 548 549 /* 550 * Check for media change. 551 * If one has already been detected, sectors will be zero. 552 * If there is one waiting to be detected, online 553 * will return > 1. 554 * Online is a bit of a large hammer but does the job. 555 */ 556 if(unit->sectors == 0 557 || (unit->dev->ifc->online && unit->dev->ifc->online(unit) > 1)) 558 sdinitpart(unit); 559 560 i = s+Qunitbase; 561 if(i < Qpart){ 562 r = sd2gen(c, i, dp); 563 qunlock(&unit->ctl); 564 decref(&sdev->r); 565 return r; 566 } 567 i -= Qpart; 568 if(unit->part == nil || i >= unit->npart){ 569 qunlock(&unit->ctl); 570 decref(&sdev->r); 571 break; 572 } 573 pp = &unit->part[i]; 574 if(!pp->valid){ 575 qunlock(&unit->ctl); 576 decref(&sdev->r); 577 return 0; 578 } 579 l = (pp->end - pp->start) * unit->secsize; 580 mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), i, Qpart), 581 unit->vers+pp->vers, QTFILE); 582 if(emptystr(pp->user)) 583 kstrdup(&pp->user, eve); 584 devdir(c, q, pp->name, l, pp->user, pp->perm, dp); 585 qunlock(&unit->ctl); 586 decref(&sdev->r); 587 return 1; 588 case Qraw: 589 case Qctl: 590 case Qpart: 591 if((sdev = sdgetdev(DEV(c->qid))) == nil){ 592 devdir(c, q, "unavailable", 0, eve, 0, dp); 593 return 1; 594 } 595 unit = sdev->unit[UNIT(c->qid)]; 596 qlock(&unit->ctl); 597 r = sd2gen(c, TYPE(c->qid), dp); 598 qunlock(&unit->ctl); 599 decref(&sdev->r); 600 return r; 601 case Qtopctl: 602 return sd1gen(c, TYPE(c->qid), dp); 603 default: 604 break; 605 } 606 607 return -1; 608 } 609 610 static Chan* 611 sdattach(char* spec) 612 { 613 Chan *c; 614 char *p; 615 SDev *sdev; 616 int idno, subno; 617 618 if(*spec == '\0'){ 619 c = devattach(sddevtab.dc, spec); 620 mkqid(&c->qid, QID(0, 0, 0, Qtopdir), 0, QTDIR); 621 return c; 622 } 623 624 if(spec[0] != 's' || spec[1] != 'd') 625 error(Ebadspec); 626 idno = spec[2]; 627 subno = strtol(&spec[3], &p, 0); 628 if(p == &spec[3]) 629 error(Ebadspec); 630 631 if((sdev=sdgetdev(idno)) == nil) 632 error(Enonexist); 633 if(sdgetunit(sdev, subno) == nil){ 634 decref(&sdev->r); 635 error(Enonexist); 636 } 637 638 c = devattach(sddevtab.dc, spec); 639 mkqid(&c->qid, QID(sdev->idno, subno, 0, Qunitdir), 0, QTDIR); 640 c->dev = (sdev->idno << UnitLOG) + subno; 641 decref(&sdev->r); 642 return c; 643 } 644 645 static Walkqid* 646 sdwalk(Chan* c, Chan* nc, char** name, int nname) 647 { 648 return devwalk(c, nc, name, nname, nil, 0, sdgen); 649 } 650 651 static int 652 sdstat(Chan* c, uchar* db, int n) 653 { 654 return devstat(c, db, n, nil, 0, sdgen); 655 } 656 657 static Chan* 658 sdopen(Chan* c, int omode) 659 { 660 SDpart *pp; 661 SDunit *unit; 662 SDev *sdev; 663 uchar tp; 664 665 c = devopen(c, omode, 0, 0, sdgen); 666 if((tp = TYPE(c->qid)) != Qctl && tp != Qraw && tp != Qpart) 667 return c; 668 669 sdev = sdgetdev(DEV(c->qid)); 670 if(sdev == nil) 671 error(Enonexist); 672 673 unit = sdev->unit[UNIT(c->qid)]; 674 675 switch(TYPE(c->qid)){ 676 case Qctl: 677 c->qid.vers = unit->vers; 678 break; 679 case Qraw: 680 c->qid.vers = unit->vers; 681 if(tas(&unit->rawinuse) != 0){ 682 c->flag &= ~COPEN; 683 decref(&sdev->r); 684 error(Einuse); 685 } 686 unit->state = Rawcmd; 687 break; 688 case Qpart: 689 qlock(&unit->ctl); 690 if(waserror()){ 691 qunlock(&unit->ctl); 692 c->flag &= ~COPEN; 693 decref(&sdev->r); 694 nexterror(); 695 } 696 pp = &unit->part[PART(c->qid)]; 697 c->qid.vers = unit->vers+pp->vers; 698 qunlock(&unit->ctl); 699 poperror(); 700 break; 701 } 702 decref(&sdev->r); 703 return c; 704 } 705 706 static void 707 sdclose(Chan* c) 708 { 709 SDunit *unit; 710 SDev *sdev; 711 712 if(c->qid.type & QTDIR) 713 return; 714 if(!(c->flag & COPEN)) 715 return; 716 717 switch(TYPE(c->qid)){ 718 default: 719 break; 720 case Qraw: 721 sdev = sdgetdev(DEV(c->qid)); 722 if(sdev){ 723 unit = sdev->unit[UNIT(c->qid)]; 724 unit->rawinuse = 0; 725 decref(&sdev->r); 726 } 727 break; 728 } 729 } 730 731 static long 732 sdbio(Chan* c, int write, char* a, long len, uvlong off) 733 { 734 int nchange; 735 long l; 736 uchar *b; 737 SDpart *pp; 738 SDunit *unit; 739 SDev *sdev; 740 ulong max, nb, offset; 741 uvlong bno; 742 743 sdev = sdgetdev(DEV(c->qid)); 744 if(sdev == nil){ 745 decref(&sdev->r); 746 error(Enonexist); 747 } 748 unit = sdev->unit[UNIT(c->qid)]; 749 if(unit == nil) 750 error(Enonexist); 751 752 nchange = 0; 753 qlock(&unit->ctl); 754 while(waserror()){ 755 /* notification of media change; go around again */ 756 if(strcmp(up->errstr, Eio) == 0 && unit->sectors == 0 && nchange++ == 0){ 757 sdinitpart(unit); 758 continue; 759 } 760 761 /* other errors; give up */ 762 qunlock(&unit->ctl); 763 decref(&sdev->r); 764 nexterror(); 765 } 766 pp = &unit->part[PART(c->qid)]; 767 if(unit->vers+pp->vers != c->qid.vers) 768 error(Echange); 769 770 /* 771 * Check the request is within bounds. 772 * Removeable drives are locked throughout the I/O 773 * in case the media changes unexpectedly. 774 * Non-removeable drives are not locked during the I/O 775 * to allow the hardware to optimise if it can; this is 776 * a little fast and loose. 777 * It's assumed that non-removeable media parameters 778 * (sectors, secsize) can't change once the drive has 779 * been brought online. 780 */ 781 bno = (off/unit->secsize) + pp->start; 782 nb = ((off+len+unit->secsize-1)/unit->secsize) + pp->start - bno; 783 max = SDmaxio/unit->secsize; 784 if(nb > max) 785 nb = max; 786 if(bno+nb > pp->end) 787 nb = pp->end - bno; 788 if(bno >= pp->end || nb == 0){ 789 if(write) 790 error(Eio); 791 qunlock(&unit->ctl); 792 decref(&sdev->r); 793 poperror(); 794 return 0; 795 } 796 if(!(unit->inquiry[1] & SDinq1removable)){ 797 qunlock(&unit->ctl); 798 poperror(); 799 } 800 801 b = sdmalloc(nb*unit->secsize); 802 if(b == nil) 803 error(Enomem); 804 if(waserror()){ 805 sdfree(b); 806 if(!(unit->inquiry[1] & SDinq1removable)) 807 decref(&sdev->r); /* gadverdamme! */ 808 nexterror(); 809 } 810 811 offset = off%unit->secsize; 812 if(offset+len > nb*unit->secsize) 813 len = nb*unit->secsize - offset; 814 if(write){ 815 if(offset || (len%unit->secsize)){ 816 l = unit->dev->ifc->bio(unit, 0, 0, b, nb, bno); 817 if(l < 0) 818 error(Eio); 819 if(l < (nb*unit->secsize)){ 820 nb = l/unit->secsize; 821 l = nb*unit->secsize - offset; 822 if(len > l) 823 len = l; 824 } 825 } 826 memmove(b+offset, a, len); 827 l = unit->dev->ifc->bio(unit, 0, 1, b, nb, bno); 828 if(l < 0) 829 error(Eio); 830 if(l < offset) 831 len = 0; 832 else if(len > l - offset) 833 len = l - offset; 834 } 835 else{ 836 l = unit->dev->ifc->bio(unit, 0, 0, b, nb, bno); 837 if(l < 0) 838 error(Eio); 839 if(l < offset) 840 len = 0; 841 else if(len > l - offset) 842 len = l - offset; 843 memmove(a, b+offset, len); 844 } 845 sdfree(b); 846 poperror(); 847 848 if(unit->inquiry[1] & SDinq1removable){ 849 qunlock(&unit->ctl); 850 poperror(); 851 } 852 853 decref(&sdev->r); 854 return len; 855 } 856 857 static long 858 sdrio(SDreq* r, void* a, long n) 859 { 860 void *data; 861 862 if(n >= SDmaxio || n < 0) 863 error(Etoobig); 864 865 data = nil; 866 if(n){ 867 if((data = sdmalloc(n)) == nil) 868 error(Enomem); 869 if(r->write) 870 memmove(data, a, n); 871 } 872 r->data = data; 873 r->dlen = n; 874 875 if(waserror()){ 876 sdfree(data); 877 r->data = nil; 878 nexterror(); 879 } 880 881 if(r->unit->dev->ifc->rio(r) != SDok) 882 error(Eio); 883 884 if(!r->write && r->rlen > 0) 885 memmove(a, data, r->rlen); 886 sdfree(data); 887 r->data = nil; 888 poperror(); 889 890 return r->rlen; 891 } 892 893 /* 894 * SCSI simulation for non-SCSI devices 895 */ 896 int 897 sdsetsense(SDreq *r, int status, int key, int asc, int ascq) 898 { 899 int len; 900 SDunit *unit; 901 902 unit = r->unit; 903 unit->sense[2] = key; 904 unit->sense[12] = asc; 905 unit->sense[13] = ascq; 906 907 r->status = status; 908 if(status == SDcheck && !(r->flags & SDnosense)){ 909 /* request sense case from sdfakescsi */ 910 len = sizeof unit->sense; 911 if(len > sizeof r->sense-1) 912 len = sizeof r->sense-1; 913 memmove(r->sense, unit->sense, len); 914 unit->sense[2] = 0; 915 unit->sense[12] = 0; 916 unit->sense[13] = 0; 917 r->flags |= SDvalidsense; 918 return SDok; 919 } 920 return status; 921 } 922 923 int 924 sdmodesense(SDreq *r, uchar *cmd, void *info, int ilen) 925 { 926 int len; 927 uchar *data; 928 929 /* 930 * Fake a vendor-specific request with page code 0, 931 * return the drive info. 932 */ 933 if((cmd[2] & 0x3F) != 0 && (cmd[2] & 0x3F) != 0x3F) 934 return sdsetsense(r, SDcheck, 0x05, 0x24, 0); 935 len = (cmd[7]<<8)|cmd[8]; 936 if(len == 0) 937 return SDok; 938 if(len < 8+ilen) 939 return sdsetsense(r, SDcheck, 0x05, 0x1A, 0); 940 if(r->data == nil || r->dlen < len) 941 return sdsetsense(r, SDcheck, 0x05, 0x20, 1); 942 data = r->data; 943 memset(data, 0, 8); 944 data[0] = ilen>>8; 945 data[1] = ilen; 946 if(ilen) 947 memmove(data+8, info, ilen); 948 r->rlen = 8+ilen; 949 return sdsetsense(r, SDok, 0, 0, 0); 950 } 951 952 int 953 sdfakescsi(SDreq *r, void *info, int ilen) 954 { 955 uchar *cmd, *p; 956 uvlong len; 957 SDunit *unit; 958 959 cmd = r->cmd; 960 r->rlen = 0; 961 unit = r->unit; 962 963 /* 964 * Rewrite read(6)/write(6) into read(10)/write(10). 965 */ 966 switch(cmd[0]){ 967 case 0x08: /* read */ 968 case 0x0A: /* write */ 969 cmd[9] = 0; 970 cmd[8] = cmd[4]; 971 cmd[7] = 0; 972 cmd[6] = 0; 973 cmd[5] = cmd[3]; 974 cmd[4] = cmd[2]; 975 cmd[3] = cmd[1] & 0x0F; 976 cmd[2] = 0; 977 cmd[1] &= 0xE0; 978 cmd[0] |= 0x20; 979 break; 980 } 981 982 /* 983 * Map SCSI commands into ATA commands for discs. 984 * Fail any command with a LUN except INQUIRY which 985 * will return 'logical unit not supported'. 986 */ 987 if((cmd[1]>>5) && cmd[0] != 0x12) 988 return sdsetsense(r, SDcheck, 0x05, 0x25, 0); 989 990 switch(cmd[0]){ 991 default: 992 return sdsetsense(r, SDcheck, 0x05, 0x20, 0); 993 994 case 0x00: /* test unit ready */ 995 return sdsetsense(r, SDok, 0, 0, 0); 996 997 case 0x03: /* request sense */ 998 if(cmd[4] < sizeof unit->sense) 999 len = cmd[4]; 1000 else 1001 len = sizeof unit->sense; 1002 if(r->data && r->dlen >= len){ 1003 memmove(r->data, unit->sense, len); 1004 r->rlen = len; 1005 } 1006 return sdsetsense(r, SDok, 0, 0, 0); 1007 1008 case 0x12: /* inquiry */ 1009 if(cmd[4] < sizeof unit->inquiry) 1010 len = cmd[4]; 1011 else 1012 len = sizeof unit->inquiry; 1013 if(r->data && r->dlen >= len){ 1014 memmove(r->data, unit->inquiry, len); 1015 r->rlen = len; 1016 } 1017 return sdsetsense(r, SDok, 0, 0, 0); 1018 1019 case 0x1B: /* start/stop unit */ 1020 /* 1021 * nop for now, can use power management later. 1022 */ 1023 return sdsetsense(r, SDok, 0, 0, 0); 1024 1025 case 0x25: /* read capacity */ 1026 if((cmd[1] & 0x01) || cmd[2] || cmd[3]) 1027 return sdsetsense(r, SDcheck, 0x05, 0x24, 0); 1028 if(r->data == nil || r->dlen < 8) 1029 return sdsetsense(r, SDcheck, 0x05, 0x20, 1); 1030 1031 /* 1032 * Read capacity returns the LBA of the last sector. 1033 */ 1034 len = unit->sectors - 1; 1035 p = r->data; 1036 *p++ = len>>24; 1037 *p++ = len>>16; 1038 *p++ = len>>8; 1039 *p++ = len; 1040 len = 512; 1041 *p++ = len>>24; 1042 *p++ = len>>16; 1043 *p++ = len>>8; 1044 *p++ = len; 1045 r->rlen = p - (uchar*)r->data; 1046 return sdsetsense(r, SDok, 0, 0, 0); 1047 1048 case 0x9E: /* long read capacity */ 1049 if((cmd[1] & 0x01) || cmd[2] || cmd[3]) 1050 return sdsetsense(r, SDcheck, 0x05, 0x24, 0); 1051 if(r->data == nil || r->dlen < 8) 1052 return sdsetsense(r, SDcheck, 0x05, 0x20, 1); 1053 /* 1054 * Read capcity returns the LBA of the last sector. 1055 */ 1056 len = unit->sectors - 1; 1057 p = r->data; 1058 *p++ = len>>56; 1059 *p++ = len>>48; 1060 *p++ = len>>40; 1061 *p++ = len>>32; 1062 *p++ = len>>24; 1063 *p++ = len>>16; 1064 *p++ = len>>8; 1065 *p++ = len; 1066 len = 512; 1067 *p++ = len>>24; 1068 *p++ = len>>16; 1069 *p++ = len>>8; 1070 *p++ = len; 1071 r->rlen = p - (uchar*)r->data; 1072 return sdsetsense(r, SDok, 0, 0, 0); 1073 1074 case 0x5A: /* mode sense */ 1075 return sdmodesense(r, cmd, info, ilen); 1076 1077 case 0x28: /* read */ 1078 case 0x2A: /* write */ 1079 case 0x88: /* read16 */ 1080 case 0x8a: /* write16 */ 1081 return SDnostatus; 1082 } 1083 } 1084 1085 static long 1086 sdread(Chan *c, void *a, long n, vlong off) 1087 { 1088 char *p, *e, *buf; 1089 SDpart *pp; 1090 SDunit *unit; 1091 SDev *sdev; 1092 ulong offset; 1093 int i, l, m, status; 1094 1095 offset = off; 1096 switch(TYPE(c->qid)){ 1097 default: 1098 error(Eperm); 1099 case Qtopctl: 1100 m = 64*1024; /* room for register dumps */ 1101 p = buf = malloc(m); 1102 if(p == nil) 1103 error(Enomem); 1104 e = p + m; 1105 qlock(&devslock); 1106 for(i = 0; i < nelem(devs); i++){ 1107 sdev = devs[i]; 1108 if(sdev && sdev->ifc->rtopctl) 1109 p = sdev->ifc->rtopctl(sdev, p, e); 1110 } 1111 qunlock(&devslock); 1112 n = readstr(off, a, n, buf); 1113 free(buf); 1114 return n; 1115 1116 case Qtopdir: 1117 case Qunitdir: 1118 return devdirread(c, a, n, 0, 0, sdgen); 1119 1120 case Qctl: 1121 sdev = sdgetdev(DEV(c->qid)); 1122 if(sdev == nil) 1123 error(Enonexist); 1124 1125 unit = sdev->unit[UNIT(c->qid)]; 1126 m = 16*1024; /* room for register dumps */ 1127 p = malloc(m); 1128 if(p == nil) 1129 error(Enomem); 1130 l = snprint(p, m, "inquiry %.48s\n", 1131 (char*)unit->inquiry+8); 1132 qlock(&unit->ctl); 1133 /* 1134 * If there's a device specific routine it must 1135 * provide all information pertaining to night geometry 1136 * and the garscadden trains. 1137 */ 1138 if(unit->dev->ifc->rctl) 1139 l += unit->dev->ifc->rctl(unit, p+l, m-l); 1140 if(unit->sectors == 0) 1141 sdinitpart(unit); 1142 if(unit->sectors){ 1143 if(unit->dev->ifc->rctl == nil) 1144 l += snprint(p+l, m-l, 1145 "geometry %llud %lud\n", 1146 unit->sectors, unit->secsize); 1147 pp = unit->part; 1148 for(i = 0; i < unit->npart; i++){ 1149 if(pp->valid) 1150 l += snprint(p+l, m-l, 1151 "part %s %llud %llud\n", 1152 pp->name, pp->start, pp->end); 1153 pp++; 1154 } 1155 } 1156 qunlock(&unit->ctl); 1157 decref(&sdev->r); 1158 l = readstr(offset, a, n, p); 1159 free(p); 1160 return l; 1161 1162 case Qraw: 1163 sdev = sdgetdev(DEV(c->qid)); 1164 if(sdev == nil) 1165 error(Enonexist); 1166 1167 unit = sdev->unit[UNIT(c->qid)]; 1168 qlock(&unit->raw); 1169 if(waserror()){ 1170 qunlock(&unit->raw); 1171 decref(&sdev->r); 1172 nexterror(); 1173 } 1174 if(unit->state == Rawdata){ 1175 unit->state = Rawstatus; 1176 i = sdrio(unit->req, a, n); 1177 } 1178 else if(unit->state == Rawstatus){ 1179 status = unit->req->status; 1180 unit->state = Rawcmd; 1181 free(unit->req); 1182 unit->req = nil; 1183 i = readnum(0, a, n, status, NUMSIZE); 1184 } else 1185 i = 0; 1186 qunlock(&unit->raw); 1187 decref(&sdev->r); 1188 poperror(); 1189 return i; 1190 1191 case Qpart: 1192 return sdbio(c, 0, a, n, off); 1193 } 1194 } 1195 1196 static void legacytopctl(Cmdbuf*); 1197 1198 static long 1199 sdwrite(Chan* c, void* a, long n, vlong off) 1200 { 1201 char *f0; 1202 int i; 1203 uvlong end, start; 1204 Cmdbuf *cb; 1205 SDifc *ifc; 1206 SDreq *req; 1207 SDunit *unit; 1208 SDev *sdev; 1209 1210 switch(TYPE(c->qid)){ 1211 default: 1212 error(Eperm); 1213 case Qtopctl: 1214 cb = parsecmd(a, n); 1215 if(waserror()){ 1216 free(cb); 1217 nexterror(); 1218 } 1219 if(cb->nf == 0) 1220 error("empty control message"); 1221 f0 = cb->f[0]; 1222 cb->f++; 1223 cb->nf--; 1224 if(strcmp(f0, "config") == 0){ 1225 /* wormhole into ugly legacy interface */ 1226 legacytopctl(cb); 1227 poperror(); 1228 free(cb); 1229 break; 1230 } 1231 /* 1232 * "ata arg..." invokes sdifc[i]->wtopctl(nil, cb), 1233 * where sdifc[i]->name=="ata" and cb contains the args. 1234 */ 1235 ifc = nil; 1236 sdev = nil; 1237 for(i=0; sdifc[i]; i++){ 1238 if(strcmp(sdifc[i]->name, f0) == 0){ 1239 ifc = sdifc[i]; 1240 sdev = nil; 1241 goto subtopctl; 1242 } 1243 } 1244 /* 1245 * "sd1 arg..." invokes sdifc[i]->wtopctl(sdev, cb), 1246 * where sdifc[i] and sdev match controller letter "1", 1247 * and cb contains the args. 1248 */ 1249 if(f0[0]=='s' && f0[1]=='d' && f0[2] && f0[3] == 0){ 1250 if((sdev = sdgetdev(f0[2])) != nil){ 1251 ifc = sdev->ifc; 1252 goto subtopctl; 1253 } 1254 } 1255 error("unknown interface"); 1256 1257 subtopctl: 1258 if(waserror()){ 1259 if(sdev) 1260 decref(&sdev->r); 1261 nexterror(); 1262 } 1263 if(ifc->wtopctl) 1264 ifc->wtopctl(sdev, cb); 1265 else 1266 error(Ebadctl); 1267 poperror(); 1268 poperror(); 1269 if (sdev) 1270 decref(&sdev->r); 1271 free(cb); 1272 break; 1273 1274 case Qctl: 1275 cb = parsecmd(a, n); 1276 sdev = sdgetdev(DEV(c->qid)); 1277 if(sdev == nil) 1278 error(Enonexist); 1279 unit = sdev->unit[UNIT(c->qid)]; 1280 1281 qlock(&unit->ctl); 1282 if(waserror()){ 1283 qunlock(&unit->ctl); 1284 decref(&sdev->r); 1285 free(cb); 1286 nexterror(); 1287 } 1288 if(unit->vers != c->qid.vers) 1289 error(Echange); 1290 1291 if(cb->nf < 1) 1292 error(Ebadctl); 1293 if(strcmp(cb->f[0], "part") == 0){ 1294 if(cb->nf != 4) 1295 error(Ebadctl); 1296 if(unit->sectors == 0 && !sdinitpart(unit)) 1297 error(Eio); 1298 start = strtoull(cb->f[2], 0, 0); 1299 end = strtoull(cb->f[3], 0, 0); 1300 sdaddpart(unit, cb->f[1], start, end); 1301 } 1302 else if(strcmp(cb->f[0], "delpart") == 0){ 1303 if(cb->nf != 2 || unit->part == nil) 1304 error(Ebadctl); 1305 sddelpart(unit, cb->f[1]); 1306 } 1307 else if(unit->dev->ifc->wctl) 1308 unit->dev->ifc->wctl(unit, cb); 1309 else 1310 error(Ebadctl); 1311 qunlock(&unit->ctl); 1312 decref(&sdev->r); 1313 poperror(); 1314 free(cb); 1315 break; 1316 1317 case Qraw: 1318 sdev = sdgetdev(DEV(c->qid)); 1319 if(sdev == nil) 1320 error(Enonexist); 1321 unit = sdev->unit[UNIT(c->qid)]; 1322 qlock(&unit->raw); 1323 if(waserror()){ 1324 qunlock(&unit->raw); 1325 decref(&sdev->r); 1326 nexterror(); 1327 } 1328 switch(unit->state){ 1329 case Rawcmd: 1330 if(n < 6 || n > sizeof(req->cmd)) 1331 error(Ebadarg); 1332 if((req = malloc(sizeof(SDreq))) == nil) 1333 error(Enomem); 1334 req->unit = unit; 1335 memmove(req->cmd, a, n); 1336 req->clen = n; 1337 req->flags = SDnosense; 1338 req->status = ~0; 1339 1340 unit->req = req; 1341 unit->state = Rawdata; 1342 break; 1343 1344 case Rawstatus: 1345 unit->state = Rawcmd; 1346 free(unit->req); 1347 unit->req = nil; 1348 error(Ebadusefd); 1349 1350 case Rawdata: 1351 unit->state = Rawstatus; 1352 unit->req->write = 1; 1353 n = sdrio(unit->req, a, n); 1354 } 1355 qunlock(&unit->raw); 1356 decref(&sdev->r); 1357 poperror(); 1358 break; 1359 case Qpart: 1360 return sdbio(c, 1, a, n, off); 1361 } 1362 1363 return n; 1364 } 1365 1366 static int 1367 sdwstat(Chan* c, uchar* dp, int n) 1368 { 1369 Dir *d; 1370 SDpart *pp; 1371 SDperm *perm; 1372 SDunit *unit; 1373 SDev *sdev; 1374 1375 if(c->qid.type & QTDIR) 1376 error(Eperm); 1377 1378 sdev = sdgetdev(DEV(c->qid)); 1379 if(sdev == nil) 1380 error(Enonexist); 1381 unit = sdev->unit[UNIT(c->qid)]; 1382 qlock(&unit->ctl); 1383 d = nil; 1384 if(waserror()){ 1385 free(d); 1386 qunlock(&unit->ctl); 1387 decref(&sdev->r); 1388 nexterror(); 1389 } 1390 1391 switch(TYPE(c->qid)){ 1392 default: 1393 error(Eperm); 1394 case Qctl: 1395 perm = &unit->ctlperm; 1396 break; 1397 case Qraw: 1398 perm = &unit->rawperm; 1399 break; 1400 case Qpart: 1401 pp = &unit->part[PART(c->qid)]; 1402 if(unit->vers+pp->vers != c->qid.vers) 1403 error(Enonexist); 1404 perm = &pp->SDperm; 1405 break; 1406 } 1407 1408 if(strcmp(up->user, perm->user) && !iseve()) 1409 error(Eperm); 1410 1411 d = smalloc(sizeof(Dir)+n); 1412 n = convM2D(dp, n, &d[0], (char*)&d[1]); 1413 if(n == 0) 1414 error(Eshortstat); 1415 if(!emptystr(d[0].uid)) 1416 kstrdup(&perm->user, d[0].uid); 1417 if(d[0].mode != ~0UL) 1418 perm->perm = (perm->perm & ~0777) | (d[0].mode & 0777); 1419 1420 free(d); 1421 qunlock(&unit->ctl); 1422 decref(&sdev->r); 1423 poperror(); 1424 return n; 1425 } 1426 1427 static int 1428 configure(char* spec, DevConf* cf) 1429 { 1430 SDev *s, *sdev; 1431 char *p; 1432 int i; 1433 1434 if(sdindex(*spec) < 0) 1435 error("bad sd spec"); 1436 1437 if((p = strchr(cf->type, '/')) != nil) 1438 *p++ = '\0'; 1439 1440 for(i = 0; sdifc[i] != nil; i++) 1441 if(strcmp(sdifc[i]->name, cf->type) == 0) 1442 break; 1443 if(sdifc[i] == nil) 1444 error("sd type not found"); 1445 if(p) 1446 *(p-1) = '/'; 1447 1448 if(sdifc[i]->probe == nil) 1449 error("sd type cannot probe"); 1450 1451 sdev = sdifc[i]->probe(cf); 1452 for(s=sdev; s; s=s->next) 1453 s->idno = *spec; 1454 sdadddevs(sdev); 1455 return 0; 1456 } 1457 1458 static int 1459 unconfigure(char* spec) 1460 { 1461 int i; 1462 SDev *sdev; 1463 SDunit *unit; 1464 1465 if((i = sdindex(*spec)) < 0) 1466 error(Enonexist); 1467 1468 qlock(&devslock); 1469 if((sdev = devs[i]) == nil){ 1470 qunlock(&devslock); 1471 error(Enonexist); 1472 } 1473 if(sdev->r.ref){ 1474 qunlock(&devslock); 1475 error(Einuse); 1476 } 1477 devs[i] = nil; 1478 qunlock(&devslock); 1479 1480 /* make sure no interrupts arrive anymore before removing resources */ 1481 if(sdev->enabled && sdev->ifc->disable) 1482 sdev->ifc->disable(sdev); 1483 1484 for(i = 0; i != sdev->nunit; i++){ 1485 if(unit = sdev->unit[i]){ 1486 free(unit->name); 1487 free(unit->user); 1488 free(unit); 1489 } 1490 } 1491 1492 if(sdev->ifc->clear) 1493 sdev->ifc->clear(sdev); 1494 free(sdev); 1495 return 0; 1496 } 1497 1498 static int 1499 sdconfig(int on, char* spec, DevConf* cf) 1500 { 1501 if(on) 1502 return configure(spec, cf); 1503 return unconfigure(spec); 1504 } 1505 1506 Dev sddevtab = { 1507 'S', 1508 "sd", 1509 1510 sdreset, 1511 devinit, 1512 devshutdown, 1513 sdattach, 1514 sdwalk, 1515 sdstat, 1516 sdopen, 1517 devcreate, 1518 sdclose, 1519 sdread, 1520 devbread, 1521 sdwrite, 1522 devbwrite, 1523 devremove, 1524 sdwstat, 1525 devpower, 1526 sdconfig, /* probe; only called for pcmcia-like devices */ 1527 }; 1528 1529 /* 1530 * This is wrong for so many reasons. This code must go. 1531 */ 1532 typedef struct Confdata Confdata; 1533 struct Confdata { 1534 int on; 1535 char* spec; 1536 DevConf cf; 1537 }; 1538 1539 static void 1540 parseswitch(Confdata* cd, char* option) 1541 { 1542 if(!strcmp("on", option)) 1543 cd->on = 1; 1544 else if(!strcmp("off", option)) 1545 cd->on = 0; 1546 else 1547 error(Ebadarg); 1548 } 1549 1550 static void 1551 parsespec(Confdata* cd, char* option) 1552 { 1553 if(strlen(option) > 1) 1554 error(Ebadarg); 1555 cd->spec = option; 1556 } 1557 1558 static Devport* 1559 getnewport(DevConf* dc) 1560 { 1561 Devport *p; 1562 1563 p = (Devport *)malloc((dc->nports + 1) * sizeof(Devport)); 1564 if(p == nil) 1565 error(Enomem); 1566 if(dc->nports > 0){ 1567 memmove(p, dc->ports, dc->nports * sizeof(Devport)); 1568 free(dc->ports); 1569 } 1570 dc->ports = p; 1571 p = &dc->ports[dc->nports++]; 1572 p->size = -1; 1573 p->port = (ulong)-1; 1574 return p; 1575 } 1576 1577 static void 1578 parseport(Confdata* cd, char* option) 1579 { 1580 char *e; 1581 Devport *p; 1582 1583 if(cd->cf.nports == 0 || cd->cf.ports[cd->cf.nports-1].port != (ulong)-1) 1584 p = getnewport(&cd->cf); 1585 else 1586 p = &cd->cf.ports[cd->cf.nports-1]; 1587 p->port = strtol(option, &e, 0); 1588 if(e == nil || *e != '\0') 1589 error(Ebadarg); 1590 } 1591 1592 static void 1593 parsesize(Confdata* cd, char* option) 1594 { 1595 char *e; 1596 Devport *p; 1597 1598 if(cd->cf.nports == 0 || cd->cf.ports[cd->cf.nports-1].size != -1) 1599 p = getnewport(&cd->cf); 1600 else 1601 p = &cd->cf.ports[cd->cf.nports-1]; 1602 p->size = (int)strtol(option, &e, 0); 1603 if(e == nil || *e != '\0') 1604 error(Ebadarg); 1605 } 1606 1607 static void 1608 parseirq(Confdata* cd, char* option) 1609 { 1610 char *e; 1611 1612 cd->cf.intnum = strtoul(option, &e, 0); 1613 if(e == nil || *e != '\0') 1614 error(Ebadarg); 1615 } 1616 1617 static void 1618 parsetype(Confdata* cd, char* option) 1619 { 1620 cd->cf.type = option; 1621 } 1622 1623 static struct { 1624 char *name; 1625 void (*parse)(Confdata*, char*); 1626 } options[] = { 1627 "switch", parseswitch, 1628 "spec", parsespec, 1629 "port", parseport, 1630 "size", parsesize, 1631 "irq", parseirq, 1632 "type", parsetype, 1633 }; 1634 1635 static void 1636 legacytopctl(Cmdbuf *cb) 1637 { 1638 char *opt; 1639 int i, j; 1640 Confdata cd; 1641 1642 memset(&cd, 0, sizeof cd); 1643 cd.on = -1; 1644 for(i=0; i<cb->nf; i+=2){ 1645 if(i+2 > cb->nf) 1646 error(Ebadarg); 1647 opt = cb->f[i]; 1648 for(j=0; j<nelem(options); j++) 1649 if(strcmp(opt, options[j].name) == 0){ 1650 options[j].parse(&cd, cb->f[i+1]); 1651 break; 1652 } 1653 if(j == nelem(options)) 1654 error(Ebadarg); 1655 } 1656 /* this has been rewritten to accomodate sdaoe */ 1657 if(cd.on < 0 || cd.spec == 0) 1658 error(Ebadarg); 1659 if(cd.on && cd.cf.type == nil) 1660 error(Ebadarg); 1661 sdconfig(cd.on, cd.spec, &cd.cf); 1662 } 1663