5 #include "../port/lib.h"
11 #include "../port/error.h"
13 #include "../port/sd.h"
16 extern SDifc* sdifc[];
18 static char Echange[] = "media or partition has changed";
19 static char Enoata[] = "raw ata commands not supported";
20 static char Enoscsi[] = "raw scsi commands not supported";
22 static char devletters[] = "0123456789"
23 "abcdefghijklmnopqrstuvwxyz"
24 "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
26 static SDev *devs[sizeof devletters-1];
27 static QLock devslock;
28 static SDunit topctlunit;
41 Qtopdir = 1, /* top level directory */
45 Qunitdir, /* directory per unit */
65 UnitSHIFT = (PartLOG+TypeLOG),
70 DevSHIFT = (UnitLOG+PartLOG+TypeLOG),
75 #define TYPE(q) ((((ulong)(q).path)>>TypeSHIFT) & TypeMASK)
76 #define PART(q) ((((ulong)(q).path)>>PartSHIFT) & PartMASK)
77 #define UNIT(q) ((((ulong)(q).path)>>UnitSHIFT) & UnitMASK)
78 #define DEV(q) ((((ulong)(q).path)>>DevSHIFT) & DevMASK)
79 #define QID(d,u, p, t) (((d)<<DevSHIFT)|((u)<<UnitSHIFT)|\
80 ((p)<<PartSHIFT)|((t)<<TypeSHIFT))
84 sdaddpart(SDunit* unit, char* name, uvlong start, uvlong end)
90 * Check name not already used
91 * and look for a free slot.
93 if(unit->part != nil){
95 for(i = 0; i < unit->npart; i++){
102 if(strcmp(name, pp->name) == 0){
103 if(pp->start == start && pp->end == end)
110 if((unit->part = malloc(sizeof(SDpart)*SDnpart)) == nil)
112 unit->npart = SDnpart;
117 * If no free slot found then increase the
118 * array size (can't get here with unit->part == nil).
121 if(unit->npart >= NPart)
123 if((pp = malloc(sizeof(SDpart)*(unit->npart+SDnpart))) == nil)
125 memmove(pp, unit->part, sizeof(SDpart)*unit->npart);
128 partno = unit->npart;
129 unit->npart += SDnpart;
133 * Check size and extent are valid.
135 if(start > end || end > unit->sectors)
137 pp = &unit->part[partno];
140 kstrdup(&pp->name, name);
141 kstrdup(&pp->user, eve);
147 sddelpart(SDunit* unit, char* name)
153 * Look for the partition to delete.
154 * Can't delete if someone still has it open.
157 for(i = 0; i < unit->npart; i++){
158 if(strcmp(name, pp->name) == 0)
164 if(strcmp(up->user, pp->user) && !iseve())
171 sdincvers(SDunit *unit)
177 for(i = 0; i < unit->npart; i++){
178 unit->part[i].valid = 0;
179 unit->part[i].vers++;
185 sdinitpart(SDunit* unit)
189 char *f[4], *p, *q, buf[10];
191 if(unit->sectors > 0){
192 unit->sectors = unit->secsize = 0;
196 if(unit->inquiry[0] & 0xC0)
198 switch(unit->inquiry[0] & 0x1F){
200 case 0x04: /* WORM */
201 case 0x05: /* CD-ROM */
208 if(unit->dev->ifc->online)
209 unit->dev->ifc->online(unit);
212 sdaddpart(unit, "data", 0, unit->sectors);
215 * Use partitions passed from boot program,
217 * sdC0part=dos 63 123123/plan9 123123 456456
218 * This happens before /boot sets hostname so the
219 * partitions will have the null-string for user.
220 * The gen functions patch it up.
222 snprint(buf, sizeof buf, "%spart", unit->name);
223 for(p = getconf(buf); p != nil; p = q){
224 if(q = strchr(p, '/'))
226 nf = tokenize(p, f, nelem(f));
230 start = strtoull(f[1], 0, 0);
231 end = strtoull(f[2], 0, 0);
233 sdaddpart(unit, f[0], start, end);
247 p = strchr(devletters, idno);
259 if((i = sdindex(idno)) < 0)
270 sdgetunit(SDev* sdev, int subno)
276 * Associate a unit with a given device and sub-unit
277 * number on that device.
278 * The device will be probed if it has not already been
279 * successfully accessed.
281 qlock(&sdev->unitlock);
282 if(subno > sdev->nunit){
283 qunlock(&sdev->unitlock);
287 unit = sdev->unit[subno];
290 * Probe the unit only once. This decision
291 * may be a little severe and reviewed later.
293 if(sdev->unitflg[subno]){
294 qunlock(&sdev->unitlock);
297 if((unit = malloc(sizeof(SDunit))) == nil){
298 qunlock(&sdev->unitlock);
301 sdev->unitflg[subno] = 1;
303 snprint(buf, sizeof buf, "%s%x", sdev->name, subno);
304 kstrdup(&unit->name, buf);
305 kstrdup(&unit->user, eve);
310 if(sdev->enabled == 0 && sdev->ifc->enable)
311 sdev->ifc->enable(sdev);
315 * No need to lock anything here as this is only
316 * called before the unit is made available in the
319 if(unit->dev->ifc->verify(unit) == 0){
320 qunlock(&sdev->unitlock);
324 sdev->unit[subno] = unit;
326 qunlock(&sdev->unitlock);
336 * Probe all known controller types and register any devices found.
338 for(i = 0; sdifc[i] != nil; i++){
339 if(sdifc[i]->pnp == nil)
341 sdadddevs(sdifc[i]->pnp());
346 sdadddevs(SDev *sdev)
351 for(; sdev; sdev=next){
354 sdev->unit = malloc(sdev->nunit * sizeof(SDunit*));
355 sdev->unitflg = malloc(sdev->nunit * sizeof(int));
356 if(sdev->unit == nil || sdev->unitflg == nil){
357 print("sdadddevs: out of memory\n");
362 sdev->ifc->clear(sdev);
366 id = sdindex(sdev->idno);
368 print("sdadddevs: bad id number %d (%C)\n", id, id);
372 for(i=0; i<nelem(devs); i++){
373 if(devs[j = (id+i)%nelem(devs)] == nil){
374 sdev->idno = devletters[j];
376 snprint(sdev->name, sizeof sdev->name, "sd%c", devletters[j]);
381 if(i == nelem(devs)){
382 print("sdadddevs: out of device letters\n");
389 // sdrmdevs(SDev *sdev)
393 // snprint(buf, sizeof buf, "%c", sdev->idno);
398 sd2gen(Chan* c, int i, Dir* dp)
409 sdev = sdgetdev(DEV(c->qid));
411 unit = sdev->unit[UNIT(c->qid)];
416 mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), PART(c->qid), Qctl),
418 perm = &unit->ctlperm;
419 if(emptystr(perm->user)){
420 kstrdup(&perm->user, eve);
423 devdir(c, q, "ctl", 0, perm->user, perm->perm, dp);
428 mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), PART(c->qid), Qraw),
430 perm = &unit->rawperm;
431 if(emptystr(perm->user)){
432 kstrdup(&perm->user, eve);
433 perm->perm = DMEXCL|0600;
435 devdir(c, q, "raw", 0, perm->user, perm->perm, dp);
440 pp = &unit->part[PART(c->qid)];
441 l = (pp->end - pp->start) * unit->secsize;
442 mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), PART(c->qid), Qpart),
443 unit->vers+pp->vers, QTFILE);
444 if(emptystr(pp->user))
445 kstrdup(&pp->user, eve);
446 devdir(c, q, pp->name, l, pp->user, pp->perm, dp);
451 if(t >= unit->nefile)
453 mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), PART(c->qid), Qextra),
456 if(emptystr(e->user))
457 kstrdup(&e->user, eve);
458 devdir(c, q, e->name, 0, e->user, e->perm, dp);
468 sd1gen(Chan* c, int i, Dir* dp)
475 mkqid(&q, QID(0, 0, 0, Qtopctl), 0, QTFILE);
476 qlock(&topctlunit.ctl);
477 p = &topctlunit.ctlperm;
478 if(p->user == nil || p->user[0] == 0){
479 kstrdup(&p->name, "sdctl");
480 kstrdup(&p->user, eve);
483 devdir(c, q, p->name, 0, p->user, p->perm, dp);
484 qunlock(&topctlunit.ctl);
491 efilegen(Chan *c, SDunit *unit, int i, Dir *dp)
497 if(unit->nefile == 0 || i >= unit->nefile)
502 if(emptystr(e->user))
503 kstrdup(&e->user, eve);
504 mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), i, Qextra),
506 devdir(c, q, e->name, 0, e->user, e->perm, dp);
511 sdgen(Chan* c, char*, Dirtab*, int, int s, Dir* dp)
520 switch(TYPE(c->qid)){
523 mkqid(&q, QID(0, 0, 0, Qtopdir), 0, QTDIR);
524 sprint(up->genbuf, "#%C", sddevtab.dc);
525 devdir(c, q, up->genbuf, 0, eve, 0555, dp);
529 if(s+Qtopbase < Qunitdir)
530 return sd1gen(c, s+Qtopbase, dp);
531 s -= (Qunitdir-Qtopbase);
534 for(i=0; i<nelem(devs); i++){
536 if(s < devs[i]->nunit)
542 if(i == nelem(devs)){
543 /* Run off the end of the list */
548 if((sdev = devs[i]) == nil){
556 if((unit = sdev->unit[s]) == nil)
557 if((unit = sdgetunit(sdev, s)) == nil){
562 mkqid(&q, QID(sdev->idno, s, 0, Qunitdir), 0, QTDIR);
563 if(emptystr(unit->user))
564 kstrdup(&unit->user, eve);
565 devdir(c, q, unit->name, 0, unit->user, unit->perm, dp);
571 mkqid(&q, QID(0, 0, 0, Qtopdir), 0, QTDIR);
572 sprint(up->genbuf, "#%C", sddevtab.dc);
573 devdir(c, q, up->genbuf, 0, eve, 0555, dp);
577 if((sdev = sdgetdev(DEV(c->qid))) == nil){
578 devdir(c, c->qid, "unavailable", 0, eve, 0, dp);
582 unit = sdev->unit[UNIT(c->qid)];
586 * Check for media change.
587 * If one has already been detected, sectors will be zero.
588 * If there is one waiting to be detected, online
590 * Online is a bit of a large hammer but does the job.
592 if(unit->sectors == 0
593 || (unit->dev->ifc->online && unit->dev->ifc->online(unit) > 1))
598 r = sd2gen(c, i, dp);
604 if(unit->part == nil || i >= unit->npart){
605 r = efilegen(c, unit, i, dp);
611 if(!pp->valid || unit->sectors == 0){
616 l = (pp->end - pp->start) * (uvlong)unit->secsize;
617 mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), i, Qpart),
618 unit->vers+pp->vers, QTFILE);
619 if(emptystr(pp->user))
620 kstrdup(&pp->user, eve);
621 devdir(c, q, pp->name, l, pp->user, pp->perm, dp);
629 if((sdev = sdgetdev(DEV(c->qid))) == nil){
630 devdir(c, q, "unavailable", 0, eve, 0, dp);
633 unit = sdev->unit[UNIT(c->qid)];
635 r = sd2gen(c, TYPE(c->qid), dp);
640 return sd1gen(c, TYPE(c->qid), dp);
657 c = devattach(sddevtab.dc, spec);
658 mkqid(&c->qid, QID(0, 0, 0, Qtopdir), 0, QTDIR);
662 if(spec[0] != 's' || spec[1] != 'd')
665 subno = strtol(&spec[3], &p, 0);
669 if((sdev=sdgetdev(idno)) == nil)
671 if(sdgetunit(sdev, subno) == nil){
676 c = devattach(sddevtab.dc, spec);
677 mkqid(&c->qid, QID(sdev->idno, subno, 0, Qunitdir), 0, QTDIR);
678 c->dev = (sdev->idno << UnitLOG) + subno;
684 sdwalk(Chan* c, Chan* nc, char** name, int nname)
686 return devwalk(c, nc, name, nname, nil, 0, sdgen);
690 sdstat(Chan* c, uchar* db, int n)
692 return devstat(c, db, n, nil, 0, sdgen);
696 sdopen(Chan* c, int omode)
703 c = devopen(c, omode, 0, 0, sdgen);
704 if((tp = TYPE(c->qid)) != Qctl && tp != Qraw && tp != Qpart)
707 sdev = sdgetdev(DEV(c->qid));
711 unit = sdev->unit[UNIT(c->qid)];
713 switch(TYPE(c->qid)){
715 c->qid.vers = unit->vers;
718 c->qid.vers = unit->vers;
719 if(tas(&unit->rawinuse) != 0){
724 unit->state = Rawcmd;
734 pp = &unit->part[PART(c->qid)];
735 c->qid.vers = unit->vers+pp->vers;
750 if(c->qid.type & QTDIR)
752 if(!(c->flag & COPEN))
755 switch(TYPE(c->qid)){
759 sdev = sdgetdev(DEV(c->qid));
761 unit = sdev->unit[UNIT(c->qid)];
769 #define iskaddr(a) ((uintptr)(a) > KZERO)
772 sdbio(Chan* c, int write, char* a, long len, uvlong off)
774 int nchange, hard, allocd;
780 ulong max, nb, offset;
783 sdev = sdgetdev(DEV(c->qid));
788 unit = sdev->unit[UNIT(c->qid)];
795 /* notification of media change; go around again */
796 if(strcmp(up->errstr, Eio) == 0 && unit->sectors == 0 && nchange++ == 0){
801 /* other errors; give up */
806 pp = &unit->part[PART(c->qid)];
807 if(unit->vers+pp->vers != c->qid.vers)
811 * Check the request is within bounds.
812 * Removeable drives are locked throughout the I/O
813 * in case the media changes unexpectedly.
814 * Non-removeable drives are not locked during the I/O
815 * to allow the hardware to optimise if it can; this is
816 * a little fast and loose.
817 * It's assumed that non-removeable media parameters
818 * (sectors, secsize) can't change once the drive has
819 * been brought online.
821 bno = (off/unit->secsize) + pp->start;
822 nb = ((off+len+unit->secsize-1)/unit->secsize) + pp->start - bno;
823 max = SDmaxio/unit->secsize;
828 if(bno >= pp->end || nb == 0){
836 if(!(unit->inquiry[1] & 0x80)){
841 offset = off%unit->secsize;
842 if(offset+len > nb*unit->secsize)
843 len = nb*unit->secsize - offset;
844 hard = offset || write && len%unit->secsize;
846 if(iskaddr(a) && !hard) {
850 b = sdmalloc(nb*unit->secsize);
858 if(!(unit->inquiry[1] & 0x80))
859 decref(&sdev->r); /* gadverdamme! */
865 l = unit->dev->ifc->bio(unit, 0, 0, b, nb, bno);
868 if(l < (nb*unit->secsize)){
869 nb = l/unit->secsize;
870 l = nb*unit->secsize - offset;
876 memmove(b+offset, a, len);
877 l = unit->dev->ifc->bio(unit, 0, 1, b, nb, bno);
882 else if(len > l - offset)
886 l = unit->dev->ifc->bio(unit, 0, 0, b, nb, bno);
891 else if(len > l - offset)
894 memmove(a, b+offset, len);
900 if(unit->inquiry[1] & 0x80){
910 sdrio(SDreq* r, void* a, long n)
918 if(n >= SDmaxio || n < 0)
921 if(u->haversense && r->cmd[0] == 0x03){
923 r->rlen = sizeof u->rsense;
926 memmove(a, u->rsense, r->rlen);
932 if(n > 0 && (data = sdmalloc(n)) == nil)
939 if(r->write && n > 0)
944 if(r->proto == SData){
945 f = u->dev->ifc->ataio;
948 f = u->dev->ifc->rio;
954 if(r->flags & SDvalidsense){
955 memmove(u->rsense, r->sense, sizeof u->rsense);
961 if(!r->write && r->rlen > 0)
962 memmove(a, data, r->rlen);
971 * SCSI simulation for non-SCSI devices
973 * see /sys/src/cmd/scuzz/sense.c for information on key.
974 * see /sys/lib/scsicodes for asc:ascq codes
977 sdsetsense(SDreq *r, int status, int key, int asc, int ascq)
983 unit->sense[2] = key;
984 unit->sense[12] = asc;
985 unit->sense[13] = ascq;
988 if(status == SDcheck && !(r->flags & SDnosense)){
989 /* request sense case from sdfakescsi */
990 len = sizeof unit->sense;
991 if(len > sizeof r->sense-1)
992 len = sizeof r->sense-1;
993 memmove(r->sense, unit->sense, len);
997 r->flags |= SDvalidsense;
1004 sdfakescsi(SDreq *r)
1015 * Map SCSI commands into ATA commands for discs.
1016 * Fail any command with a LUN except INQUIRY which
1017 * will return 'logical unit not supported'.
1019 if((cmd[1]>>5) && cmd[0] != 0x12)
1020 return sdsetsense(r, SDcheck, 0x05, 0x25, 0);
1024 return sdsetsense(r, SDcheck, 0x05, 0x20, 0);
1026 case 0x00: /* test unit ready */
1027 return sdsetsense(r, SDok, 0, 0, 0);
1029 case 0x03: /* request sense */
1030 if(cmd[4] < sizeof unit->sense)
1033 len = sizeof unit->sense;
1034 if(r->data && r->dlen >= len){
1035 memmove(r->data, unit->sense, len);
1038 return sdsetsense(r, SDok, 0, 0, 0);
1040 case 0x12: /* inquiry */
1041 if(cmd[4] < sizeof unit->inquiry)
1044 len = sizeof unit->inquiry;
1045 if(r->data && r->dlen >= len){
1046 memmove(r->data, unit->inquiry, len);
1049 return sdsetsense(r, SDok, 0, 0, 0);
1051 case 0x1B: /* start/stop unit */
1053 * nop for now, can use power management later.
1055 return sdsetsense(r, SDok, 0, 0, 0);
1057 case 0x25: /* read capacity */
1058 if((cmd[1] & 0x01) || cmd[2] || cmd[3])
1059 return sdsetsense(r, SDcheck, 0x05, 0x24, 0);
1060 if(r->data == nil || r->dlen < 8)
1061 return sdsetsense(r, SDcheck, 0x05, 0x20, 1);
1064 * Read capacity returns the LBA of the last sector.
1066 len = unit->sectors;
1074 len = unit->secsize;
1079 r->rlen = p - (uchar*)r->data;
1080 return sdsetsense(r, SDok, 0, 0, 0);
1082 case 0x9E: /* long read capacity */
1083 if((cmd[1] & 0x01) || cmd[2] || cmd[3])
1084 return sdsetsense(r, SDcheck, 0x05, 0x24, 0);
1085 if(r->data == nil || r->dlen < 8)
1086 return sdsetsense(r, SDcheck, 0x05, 0x20, 1);
1088 * Read capcity returns the LBA of the last sector.
1090 len = unit->sectors;
1102 len = unit->secsize;
1107 r->rlen = p - (uchar*)r->data;
1108 return sdsetsense(r, SDok, 0, 0, 0);
1109 case 0x08: /* read6 */
1110 case 0x0a: /* write6 */
1111 case 0x28: /* read10 */
1112 case 0x2a: /* write10 */
1113 case 0xa8: /* read12 */
1114 case 0xaa: /* write12 */
1115 case 0x88: /* read16 */
1116 case 0x8a: /* write16 */
1122 sdfakescsirw(SDreq *r, uvlong *llba, int *nsec, int *rwp)
1130 if((c[0] & 0xf) == 0xa)
1133 case 0x08: /* read6 */
1135 lba = (c[1] & 0xf)<<16 | c[2]<<8 | c[3];
1138 case 0x28: /* read10 */
1140 lba = c[2]<<24 | c[3]<<16 | c[4]<<8 | c[5];
1141 count = c[7]<<8 | c[8];
1143 case 0xa8: /* read12 */
1145 lba = c[2]<<24 | c[3]<<16 | c[4]<<8 | c[5];
1146 count = c[6]<<24 | c[7]<<16 | c[8]<<8 | c[9];
1148 case 0x88: /* read16 */
1150 /* ata commands only go to 48-bit lba */
1152 return sdsetsense(r, SDcheck, 3, 0xc, 2);
1153 lba = (uvlong)c[4]<<40 | (uvlong)c[5]<<32;
1154 lba |= c[6]<<24 | c[7]<<16 | c[8]<<8 | c[9];
1155 count = c[10]<<24 | c[11]<<16 | c[12]<<8 | c[13];
1158 print("%s: bad cmd 0x%.2ux\n", r->unit->name, c[0]);
1159 r->status = sdsetsense(r, SDcheck, 0x05, 0x20, 0);
1164 if(r->dlen < count * r->unit->secsize)
1165 count = r->dlen/r->unit->secsize;
1174 extrarw(int write, Chan *c, void *a, long n, vlong off)
1181 sdev = sdgetdev(DEV(c->qid));
1188 unit = sdev->unit[UNIT(c->qid)];
1189 if(unit->vers != c->qid.vers)
1191 unit = sdev->unit[UNIT(c->qid)];
1193 if(i >= unit->nefile)
1195 f = unit->efile[i].r;
1197 f = unit->efile[i].w;
1198 if(i >= unit->nefile || f == nil)
1200 n = f(unit, c, a, n, off);
1207 deftopctl(SDev *s, char *p, char *e)
1209 return seprint(p, e, "sd%c %s %d units\n", s->idno, s->ifc->name, s->nunit);
1213 sdread(Chan *c, void *a, long n, vlong off)
1221 int i, l, m, status;
1224 switch(TYPE(c->qid)){
1228 m = 64*1024; /* room for register dumps */
1229 p = buf = malloc(m);
1233 for(i = 0; i < nelem(devs); i++){
1235 if(sdev && sdev->ifc->rtopctl)
1236 p = sdev->ifc->rtopctl(sdev, p, e);
1238 p = deftopctl(sdev, p, e);
1241 n = readstr(off, a, n, buf);
1247 return devdirread(c, a, n, 0, 0, sdgen);
1250 sdev = sdgetdev(DEV(c->qid));
1254 unit = sdev->unit[UNIT(c->qid)];
1255 m = 16*1024; /* room for register dumps */
1257 l = snprint(p, m, "inquiry %.48s\n",
1258 (char*)unit->inquiry+8);
1261 * If there's a device specific routine it must
1262 * provide all information pertaining to night geometry
1263 * and the garscadden trains.
1265 if(unit->dev->ifc->rctl)
1266 l += unit->dev->ifc->rctl(unit, p+l, m-l);
1267 if(unit->sectors == 0)
1270 if(unit->dev->ifc->rctl == nil)
1271 l += snprint(p+l, m-l,
1272 "geometry %llud %lud\n",
1273 unit->sectors, unit->secsize);
1275 for(i = 0; i < unit->npart; i++){
1277 l += snprint(p+l, m-l,
1278 "part %s %llud %llud\n",
1279 pp->name, pp->start, pp->end);
1283 qunlock(&unit->ctl);
1285 l = readstr(offset, a, n, p);
1290 sdev = sdgetdev(DEV(c->qid));
1294 unit = sdev->unit[UNIT(c->qid)];
1297 qunlock(&unit->raw);
1301 if(unit->state == Rawdata){
1302 unit->state = Rawstatus;
1307 else if(unit->state == Rawstatus){
1310 unit->state = Rawcmd;
1312 if(r->proto == SData){
1320 memmove(p + Ahdrsz, r->cmd, i - Ahdrsz);
1322 i = readnum(0, a, n, status, NUMSIZE);
1327 qunlock(&unit->raw);
1332 return sdbio(c, 0, a, n, off);
1334 return extrarw(0, c, a, n, off);
1338 static void legacytopctl(Cmdbuf*);
1341 sdwrite(Chan* c, void* a, long n, vlong off)
1344 int i, atacdb, proto, ataproto;
1353 switch(TYPE(c->qid)){
1357 cb = parsecmd(a, n);
1363 error("empty control message");
1367 if(strcmp(f0, "config") == 0){
1368 /* wormhole into ugly legacy interface */
1375 * "ata arg..." invokes sdifc[i]->wtopctl(nil, cb),
1376 * where sdifc[i]->name=="ata" and cb contains the args.
1380 for(i=0; sdifc[i]; i++){
1381 if(strcmp(sdifc[i]->name, f0) == 0){
1388 * "sd1 arg..." invokes sdifc[i]->wtopctl(sdev, cb),
1389 * where sdifc[i] and sdev match controller letter "1",
1390 * and cb contains the args.
1392 if(f0[0]=='s' && f0[1]=='d' && f0[2] && f0[3] == 0){
1393 if((sdev = sdgetdev(f0[2])) != nil){
1398 error("unknown interface");
1407 ifc->wtopctl(sdev, cb);
1418 cb = parsecmd(a, n);
1419 sdev = sdgetdev(DEV(c->qid));
1422 unit = sdev->unit[UNIT(c->qid)];
1426 qunlock(&unit->ctl);
1431 if(unit->vers != c->qid.vers)
1436 if(strcmp(cb->f[0], "part") == 0){
1439 if(unit->sectors == 0 && !sdinitpart(unit))
1441 start = strtoull(cb->f[2], 0, 0);
1442 end = strtoull(cb->f[3], 0, 0);
1443 sdaddpart(unit, cb->f[1], start, end);
1445 else if(strcmp(cb->f[0], "delpart") == 0){
1446 if(cb->nf != 2 || unit->part == nil)
1448 sddelpart(unit, cb->f[1]);
1450 else if(unit->dev->ifc->wctl)
1451 unit->dev->ifc->wctl(unit, cb);
1454 qunlock(&unit->ctl);
1464 sdev = sdgetdev(DEV(c->qid));
1467 unit = sdev->unit[UNIT(c->qid)];
1470 qunlock(&unit->raw);
1474 switch(unit->state){
1476 /* sneaky ata commands */
1478 if(n > 1 && *u == 0xff){
1485 if(n < 6 || n > sizeof(req->cmd))
1487 if((req = malloc(sizeof(SDreq))) == nil)
1494 memmove(req->cmd, a, n);
1497 /* req->flags = SDnosense; */
1500 req->ataproto = ataproto;
1502 unit->state = Rawdata;
1507 unit->state = Rawcmd;
1513 unit->state = Rawstatus;
1516 n = sdrio(req, a, n);
1519 qunlock(&unit->raw);
1523 return sdbio(c, 1, a, n, off);
1525 return extrarw(1, c, a, n, off);
1532 sdwstat(Chan* c, uchar* dp, int n)
1540 if(c->qid.type & QTDIR)
1542 if(TYPE(c->qid) == Qtopctl){
1546 sdev = sdgetdev(DEV(c->qid));
1549 unit = sdev->unit[UNIT(c->qid)];
1556 qunlock(&unit->ctl);
1562 switch(TYPE(c->qid)){
1567 perm = &unit->ctlperm;
1570 perm = &unit->rawperm;
1573 pp = &unit->part[PART(c->qid)];
1574 if(unit->vers+pp->vers != c->qid.vers)
1580 if(strcmp(up->user, perm->user) && !iseve())
1583 d = smalloc(sizeof(Dir)+n);
1584 n = convM2D(dp, n, &d[0], (char*)&d[1]);
1587 if(d->atime != ~0 || d->mtime != ~0 || d->length != ~0)
1589 if(!emptystr(d[0].muid) || !emptystr(d[0].name))
1591 if(!emptystr(d[0].uid))
1592 kstrdup(&perm->user, d[0].uid);
1593 if(!emptystr(d[0].gid) && strcmp(d[0].gid, eve) != 0)
1595 if(d[0].mode != ~0UL)
1596 perm->perm = (perm->perm & ~0777) | (d[0].mode & 0777);
1600 qunlock(&unit->ctl);
1608 configure(char* spec, DevConf* cf)
1614 if(sdindex(*spec) < 0)
1615 error("bad sd spec");
1617 if((p = strchr(cf->type, '/')) != nil)
1620 for(i = 0; sdifc[i] != nil; i++)
1621 if(strcmp(sdifc[i]->name, cf->type) == 0)
1624 error("sd type not found");
1628 if(sdifc[i]->probe == nil)
1629 error("sd type cannot probe");
1631 sdev = sdifc[i]->probe(cf);
1632 for(s=sdev; s; s=s->next)
1639 unconfigure(char* spec)
1645 if((i = sdindex(*spec)) < 0)
1649 if((sdev = devs[i]) == nil){
1660 /* make sure no interrupts arrive anymore before removing resources */
1661 if(sdev->enabled && sdev->ifc->disable)
1662 sdev->ifc->disable(sdev);
1664 for(i = 0; i != sdev->nunit; i++){
1665 if(unit = sdev->unit[i]){
1672 if(sdev->ifc->clear)
1673 sdev->ifc->clear(sdev);
1679 sdconfig(int on, char* spec, DevConf* cf)
1682 return configure(spec, cf);
1683 return unconfigure(spec);
1687 sdaddfile(SDunit *unit, char *s, int perm, char *u, SDrw *r, SDrw *w)
1696 for(i = 0; i < unit->nefile; i++)
1697 if(strcmp(unit->efile[i].name, s) == 0)
1699 if(i >= nelem(unit->efile)){
1703 if(i >= unit->nefile)
1704 unit->nefile = i + 1;
1705 e = unit->efile + i;
1707 kstrdup(&e->name, s);
1709 kstrdup(&e->user, u);
1723 for(i = 0; i < nelem(devs); i++){
1727 if(sd->ifc->disable == nil){
1728 print("#S/sd%c: no disable function\n", devletters[i]);
1731 sd->ifc->disable(sd);
1759 * This is wrong for so many reasons. This code must go.
1761 typedef struct Confdata Confdata;
1769 parseswitch(Confdata* cd, char* option)
1771 if(!strcmp("on", option))
1773 else if(!strcmp("off", option))
1780 parsespec(Confdata* cd, char* option)
1782 if(strlen(option) > 1)
1788 getnewport(DevConf* dc)
1792 p = malloc((dc->nports + 1) * sizeof(Devport));
1794 memmove(p, dc->ports, dc->nports * sizeof(Devport));
1798 p = &dc->ports[dc->nports++];
1800 p->port = (ulong)-1;
1805 parseport(Confdata* cd, char* option)
1810 if(cd->cf.nports == 0 || cd->cf.ports[cd->cf.nports-1].port != (ulong)-1)
1811 p = getnewport(&cd->cf);
1813 p = &cd->cf.ports[cd->cf.nports-1];
1814 p->port = strtol(option, &e, 0);
1815 if(e == nil || *e != '\0')
1820 parsesize(Confdata* cd, char* option)
1825 if(cd->cf.nports == 0 || cd->cf.ports[cd->cf.nports-1].size != -1)
1826 p = getnewport(&cd->cf);
1828 p = &cd->cf.ports[cd->cf.nports-1];
1829 p->size = (int)strtol(option, &e, 0);
1830 if(e == nil || *e != '\0')
1835 parseirq(Confdata* cd, char* option)
1839 cd->cf.intnum = strtoul(option, &e, 0);
1840 if(e == nil || *e != '\0')
1845 parsetype(Confdata* cd, char* option)
1847 cd->cf.type = option;
1852 void (*parse)(Confdata*, char*);
1854 "switch", parseswitch,
1863 legacytopctl(Cmdbuf *cb)
1869 memset(&cd, 0, sizeof cd);
1871 for(i=0; i<cb->nf; i+=2){
1875 for(j=0; j<nelem(options); j++)
1876 if(strcmp(opt, options[j].name) == 0){
1877 options[j].parse(&cd, cb->f[i+1]);
1880 if(j == nelem(options))
1883 if(cd.on < 0 || cd.spec == 0)
1885 if(cd.on && cd.cf.type == nil)
1887 sdconfig(cd.on, cd.spec, &cd.cf);