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