19ef1f84bSDavid du Colombier /*
29ef1f84bSDavid du Colombier * Storage Device.
39ef1f84bSDavid du Colombier */
49ef1f84bSDavid du Colombier #include "u.h"
59ef1f84bSDavid du Colombier #include "../port/lib.h"
69ef1f84bSDavid du Colombier #include "mem.h"
79ef1f84bSDavid du Colombier #include "dat.h"
89ef1f84bSDavid du Colombier #include "fns.h"
99ef1f84bSDavid du Colombier #include "io.h"
109ef1f84bSDavid du Colombier #include "ureg.h"
119ef1f84bSDavid du Colombier #include "../port/error.h"
129ef1f84bSDavid du Colombier
139ef1f84bSDavid du Colombier #include "../port/sd.h"
149ef1f84bSDavid du Colombier
159ef1f84bSDavid du Colombier extern Dev sddevtab;
169ef1f84bSDavid du Colombier extern SDifc* sdifc[];
179ef1f84bSDavid du Colombier
189ef1f84bSDavid du Colombier static char devletters[] = "0123456789"
199ef1f84bSDavid du Colombier "abcdefghijklmnopqrstuvwxyz"
209ef1f84bSDavid du Colombier "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
219ef1f84bSDavid du Colombier
229ef1f84bSDavid du Colombier static SDev *devs[sizeof devletters-1];
239ef1f84bSDavid du Colombier static QLock devslock;
249ef1f84bSDavid du Colombier
259ef1f84bSDavid du Colombier enum {
269ef1f84bSDavid du Colombier Rawcmd,
279ef1f84bSDavid du Colombier Rawdata,
289ef1f84bSDavid du Colombier Rawstatus,
299ef1f84bSDavid du Colombier };
309ef1f84bSDavid du Colombier
319ef1f84bSDavid du Colombier enum {
329ef1f84bSDavid du Colombier Qtopdir = 1, /* top level directory */
339ef1f84bSDavid du Colombier Qtopbase,
349ef1f84bSDavid du Colombier Qtopctl = Qtopbase,
359ef1f84bSDavid du Colombier
369ef1f84bSDavid du Colombier Qunitdir, /* directory per unit */
379ef1f84bSDavid du Colombier Qunitbase,
389ef1f84bSDavid du Colombier Qctl = Qunitbase,
399ef1f84bSDavid du Colombier Qraw,
409ef1f84bSDavid du Colombier Qpart,
419ef1f84bSDavid du Colombier
429ef1f84bSDavid du Colombier TypeLOG = 4,
439ef1f84bSDavid du Colombier NType = (1<<TypeLOG),
449ef1f84bSDavid du Colombier TypeMASK = (NType-1),
459ef1f84bSDavid du Colombier TypeSHIFT = 0,
469ef1f84bSDavid du Colombier
479ef1f84bSDavid du Colombier PartLOG = 8,
489ef1f84bSDavid du Colombier NPart = (1<<PartLOG),
499ef1f84bSDavid du Colombier PartMASK = (NPart-1),
509ef1f84bSDavid du Colombier PartSHIFT = TypeLOG,
519ef1f84bSDavid du Colombier
529ef1f84bSDavid du Colombier UnitLOG = 8,
539ef1f84bSDavid du Colombier NUnit = (1<<UnitLOG),
549ef1f84bSDavid du Colombier UnitMASK = (NUnit-1),
559ef1f84bSDavid du Colombier UnitSHIFT = (PartLOG+TypeLOG),
569ef1f84bSDavid du Colombier
579ef1f84bSDavid du Colombier DevLOG = 8,
589ef1f84bSDavid du Colombier NDev = (1 << DevLOG),
599ef1f84bSDavid du Colombier DevMASK = (NDev-1),
609ef1f84bSDavid du Colombier DevSHIFT = (UnitLOG+PartLOG+TypeLOG),
619ef1f84bSDavid du Colombier
629ef1f84bSDavid du Colombier Ncmd = 20,
639ef1f84bSDavid du Colombier };
649ef1f84bSDavid du Colombier
659ef1f84bSDavid du Colombier #define TYPE(q) ((((ulong)(q).path)>>TypeSHIFT) & TypeMASK)
669ef1f84bSDavid du Colombier #define PART(q) ((((ulong)(q).path)>>PartSHIFT) & PartMASK)
679ef1f84bSDavid du Colombier #define UNIT(q) ((((ulong)(q).path)>>UnitSHIFT) & UnitMASK)
689ef1f84bSDavid du Colombier #define DEV(q) ((((ulong)(q).path)>>DevSHIFT) & DevMASK)
699ef1f84bSDavid du Colombier #define QID(d,u, p, t) (((d)<<DevSHIFT)|((u)<<UnitSHIFT)|\
709ef1f84bSDavid du Colombier ((p)<<PartSHIFT)|((t)<<TypeSHIFT))
719ef1f84bSDavid du Colombier
729ef1f84bSDavid du Colombier
739ef1f84bSDavid du Colombier void
sdaddpart(SDunit * unit,char * name,uvlong start,uvlong end)749ef1f84bSDavid du Colombier sdaddpart(SDunit* unit, char* name, uvlong start, uvlong end)
759ef1f84bSDavid du Colombier {
769ef1f84bSDavid du Colombier SDpart *pp;
779ef1f84bSDavid du Colombier int i, partno;
789ef1f84bSDavid du Colombier
799ef1f84bSDavid du Colombier /*
809ef1f84bSDavid du Colombier * Check name not already used
819ef1f84bSDavid du Colombier * and look for a free slot.
829ef1f84bSDavid du Colombier */
839ef1f84bSDavid du Colombier if(unit->part != nil){
849ef1f84bSDavid du Colombier partno = -1;
859ef1f84bSDavid du Colombier for(i = 0; i < unit->npart; i++){
869ef1f84bSDavid du Colombier pp = &unit->part[i];
879ef1f84bSDavid du Colombier if(!pp->valid){
889ef1f84bSDavid du Colombier if(partno == -1)
899ef1f84bSDavid du Colombier partno = i;
909ef1f84bSDavid du Colombier break;
919ef1f84bSDavid du Colombier }
929ef1f84bSDavid du Colombier if(strcmp(name, pp->name) == 0){
939ef1f84bSDavid du Colombier if(pp->start == start && pp->end == end)
949ef1f84bSDavid du Colombier return;
959ef1f84bSDavid du Colombier error(Ebadctl);
969ef1f84bSDavid du Colombier }
979ef1f84bSDavid du Colombier }
989ef1f84bSDavid du Colombier }
999ef1f84bSDavid du Colombier else{
1009ef1f84bSDavid du Colombier if((unit->part = malloc(sizeof(SDpart)*SDnpart)) == nil)
1019ef1f84bSDavid du Colombier error(Enomem);
1029ef1f84bSDavid du Colombier unit->npart = SDnpart;
1039ef1f84bSDavid du Colombier partno = 0;
1049ef1f84bSDavid du Colombier }
1059ef1f84bSDavid du Colombier
1069ef1f84bSDavid du Colombier /*
1079ef1f84bSDavid du Colombier * If no free slot found then increase the
1089ef1f84bSDavid du Colombier * array size (can't get here with unit->part == nil).
1099ef1f84bSDavid du Colombier */
1109ef1f84bSDavid du Colombier if(partno == -1){
1119ef1f84bSDavid du Colombier if(unit->npart >= NPart)
1129ef1f84bSDavid du Colombier error(Enomem);
1139ef1f84bSDavid du Colombier if((pp = malloc(sizeof(SDpart)*(unit->npart+SDnpart))) == nil)
1149ef1f84bSDavid du Colombier error(Enomem);
1159ef1f84bSDavid du Colombier memmove(pp, unit->part, sizeof(SDpart)*unit->npart);
1169ef1f84bSDavid du Colombier free(unit->part);
1179ef1f84bSDavid du Colombier unit->part = pp;
1189ef1f84bSDavid du Colombier partno = unit->npart;
1199ef1f84bSDavid du Colombier unit->npart += SDnpart;
1209ef1f84bSDavid du Colombier }
1219ef1f84bSDavid du Colombier
1229ef1f84bSDavid du Colombier /*
1239ef1f84bSDavid du Colombier * Check size and extent are valid.
1249ef1f84bSDavid du Colombier */
1259ef1f84bSDavid du Colombier if(start > end || end > unit->sectors)
1269ef1f84bSDavid du Colombier error(Eio);
1279ef1f84bSDavid du Colombier pp = &unit->part[partno];
1289ef1f84bSDavid du Colombier pp->start = start;
1299ef1f84bSDavid du Colombier pp->end = end;
1309ef1f84bSDavid du Colombier kstrdup(&pp->name, name);
1319ef1f84bSDavid du Colombier kstrdup(&pp->user, eve);
1329ef1f84bSDavid du Colombier pp->perm = 0640;
1339ef1f84bSDavid du Colombier pp->valid = 1;
1349ef1f84bSDavid du Colombier }
1359ef1f84bSDavid du Colombier
1369ef1f84bSDavid du Colombier static void
sddelpart(SDunit * unit,char * name)1379ef1f84bSDavid du Colombier sddelpart(SDunit* unit, char* name)
1389ef1f84bSDavid du Colombier {
1399ef1f84bSDavid du Colombier int i;
1409ef1f84bSDavid du Colombier SDpart *pp;
1419ef1f84bSDavid du Colombier
1429ef1f84bSDavid du Colombier /*
1439ef1f84bSDavid du Colombier * Look for the partition to delete.
1449ef1f84bSDavid du Colombier * Can't delete if someone still has it open.
1459ef1f84bSDavid du Colombier */
1469ef1f84bSDavid du Colombier pp = unit->part;
1479ef1f84bSDavid du Colombier for(i = 0; i < unit->npart; i++){
1489ef1f84bSDavid du Colombier if(strcmp(name, pp->name) == 0)
1499ef1f84bSDavid du Colombier break;
1509ef1f84bSDavid du Colombier pp++;
1519ef1f84bSDavid du Colombier }
1529ef1f84bSDavid du Colombier if(i >= unit->npart)
1539ef1f84bSDavid du Colombier error(Ebadctl);
1549ef1f84bSDavid du Colombier if(strcmp(up->user, pp->user) && !iseve())
1559ef1f84bSDavid du Colombier error(Eperm);
1569ef1f84bSDavid du Colombier pp->valid = 0;
1579ef1f84bSDavid du Colombier pp->vers++;
1589ef1f84bSDavid du Colombier }
1599ef1f84bSDavid du Colombier
1609ef1f84bSDavid du Colombier static void
sdincvers(SDunit * unit)1619ef1f84bSDavid du Colombier sdincvers(SDunit *unit)
1629ef1f84bSDavid du Colombier {
1639ef1f84bSDavid du Colombier int i;
1649ef1f84bSDavid du Colombier
1659ef1f84bSDavid du Colombier unit->vers++;
1669ef1f84bSDavid du Colombier if(unit->part){
1679ef1f84bSDavid du Colombier for(i = 0; i < unit->npart; i++){
1689ef1f84bSDavid du Colombier unit->part[i].valid = 0;
1699ef1f84bSDavid du Colombier unit->part[i].vers++;
1709ef1f84bSDavid du Colombier }
1719ef1f84bSDavid du Colombier }
1729ef1f84bSDavid du Colombier }
1739ef1f84bSDavid du Colombier
1749ef1f84bSDavid du Colombier static int
sdinitpart(SDunit * unit)1759ef1f84bSDavid du Colombier sdinitpart(SDunit* unit)
1769ef1f84bSDavid du Colombier {
1779ef1f84bSDavid du Colombier int nf;
1789ef1f84bSDavid du Colombier uvlong start, end;
1799ef1f84bSDavid du Colombier char *f[4], *p, *q, buf[10];
1809ef1f84bSDavid du Colombier
1819ef1f84bSDavid du Colombier if(unit->sectors > 0){
1829ef1f84bSDavid du Colombier unit->sectors = unit->secsize = 0;
1839ef1f84bSDavid du Colombier sdincvers(unit);
1849ef1f84bSDavid du Colombier }
1859ef1f84bSDavid du Colombier
1869ef1f84bSDavid du Colombier /* device must be connected or not; other values are trouble */
1879ef1f84bSDavid du Colombier if(unit->inquiry[0] & 0xC0) /* see SDinq0periphqual */
1889ef1f84bSDavid du Colombier return 0;
1899ef1f84bSDavid du Colombier switch(unit->inquiry[0] & SDinq0periphtype){
1909ef1f84bSDavid du Colombier case SDperdisk:
1919ef1f84bSDavid du Colombier case SDperworm:
1929ef1f84bSDavid du Colombier case SDpercd:
1939ef1f84bSDavid du Colombier case SDpermo:
1949ef1f84bSDavid du Colombier break;
1959ef1f84bSDavid du Colombier default:
1969ef1f84bSDavid du Colombier return 0;
1979ef1f84bSDavid du Colombier }
1989ef1f84bSDavid du Colombier
1999ef1f84bSDavid du Colombier if(unit->dev->ifc->online)
2009ef1f84bSDavid du Colombier unit->dev->ifc->online(unit);
2019ef1f84bSDavid du Colombier if(unit->sectors){
2029ef1f84bSDavid du Colombier sdincvers(unit);
2039ef1f84bSDavid du Colombier sdaddpart(unit, "data", 0, unit->sectors);
2049ef1f84bSDavid du Colombier
2059ef1f84bSDavid du Colombier /*
2069ef1f84bSDavid du Colombier * Use partitions passed from boot program,
2079ef1f84bSDavid du Colombier * e.g.
2089ef1f84bSDavid du Colombier * sdC0part=dos 63 123123/plan9 123123 456456
2099ef1f84bSDavid du Colombier * This happens before /boot sets hostname so the
2109ef1f84bSDavid du Colombier * partitions will have the null-string for user.
2119ef1f84bSDavid du Colombier * The gen functions patch it up.
2129ef1f84bSDavid du Colombier */
2139ef1f84bSDavid du Colombier snprint(buf, sizeof buf, "%spart", unit->name);
2149ef1f84bSDavid du Colombier for(p = getconf(buf); p != nil; p = q){
2159ef1f84bSDavid du Colombier if(q = strchr(p, '/'))
2169ef1f84bSDavid du Colombier *q++ = '\0';
2179ef1f84bSDavid du Colombier nf = tokenize(p, f, nelem(f));
2189ef1f84bSDavid du Colombier if(nf < 3)
2199ef1f84bSDavid du Colombier continue;
2209ef1f84bSDavid du Colombier
2219ef1f84bSDavid du Colombier start = strtoull(f[1], 0, 0);
2229ef1f84bSDavid du Colombier end = strtoull(f[2], 0, 0);
2239ef1f84bSDavid du Colombier if(!waserror()){
2249ef1f84bSDavid du Colombier sdaddpart(unit, f[0], start, end);
2259ef1f84bSDavid du Colombier poperror();
2269ef1f84bSDavid du Colombier }
2279ef1f84bSDavid du Colombier }
2289ef1f84bSDavid du Colombier }
2299ef1f84bSDavid du Colombier
2309ef1f84bSDavid du Colombier return 1;
2319ef1f84bSDavid du Colombier }
2329ef1f84bSDavid du Colombier
2339ef1f84bSDavid du Colombier static int
sdindex(int idno)2349ef1f84bSDavid du Colombier sdindex(int idno)
2359ef1f84bSDavid du Colombier {
2369ef1f84bSDavid du Colombier char *p;
2379ef1f84bSDavid du Colombier
2389ef1f84bSDavid du Colombier p = strchr(devletters, idno);
2399ef1f84bSDavid du Colombier if(p == nil)
2409ef1f84bSDavid du Colombier return -1;
2419ef1f84bSDavid du Colombier return p-devletters;
2429ef1f84bSDavid du Colombier }
2439ef1f84bSDavid du Colombier
2449ef1f84bSDavid du Colombier static SDev*
sdgetdev(int idno)2459ef1f84bSDavid du Colombier sdgetdev(int idno)
2469ef1f84bSDavid du Colombier {
2479ef1f84bSDavid du Colombier SDev *sdev;
2489ef1f84bSDavid du Colombier int i;
2499ef1f84bSDavid du Colombier
2509ef1f84bSDavid du Colombier if((i = sdindex(idno)) < 0)
2519ef1f84bSDavid du Colombier return nil;
2529ef1f84bSDavid du Colombier
2539ef1f84bSDavid du Colombier qlock(&devslock);
2549ef1f84bSDavid du Colombier if(sdev = devs[i])
2559ef1f84bSDavid du Colombier incref(&sdev->r);
2569ef1f84bSDavid du Colombier qunlock(&devslock);
2579ef1f84bSDavid du Colombier return sdev;
2589ef1f84bSDavid du Colombier }
2599ef1f84bSDavid du Colombier
2609ef1f84bSDavid du Colombier static SDunit*
sdgetunit(SDev * sdev,int subno)2619ef1f84bSDavid du Colombier sdgetunit(SDev* sdev, int subno)
2629ef1f84bSDavid du Colombier {
2639ef1f84bSDavid du Colombier SDunit *unit;
2649ef1f84bSDavid du Colombier char buf[32];
2659ef1f84bSDavid du Colombier
2669ef1f84bSDavid du Colombier /*
2679ef1f84bSDavid du Colombier * Associate a unit with a given device and sub-unit
2689ef1f84bSDavid du Colombier * number on that device.
2699ef1f84bSDavid du Colombier * The device will be probed if it has not already been
2709ef1f84bSDavid du Colombier * successfully accessed.
2719ef1f84bSDavid du Colombier */
2729ef1f84bSDavid du Colombier qlock(&sdev->unitlock);
2739ef1f84bSDavid du Colombier if(subno > sdev->nunit){
2749ef1f84bSDavid du Colombier qunlock(&sdev->unitlock);
2759ef1f84bSDavid du Colombier return nil;
2769ef1f84bSDavid du Colombier }
2779ef1f84bSDavid du Colombier
2789ef1f84bSDavid du Colombier unit = sdev->unit[subno];
2799ef1f84bSDavid du Colombier if(unit == nil){
2809ef1f84bSDavid du Colombier /*
2819ef1f84bSDavid du Colombier * Probe the unit only once. This decision
2829ef1f84bSDavid du Colombier * may be a little severe and reviewed later.
2839ef1f84bSDavid du Colombier */
2849ef1f84bSDavid du Colombier if(sdev->unitflg[subno]){
2859ef1f84bSDavid du Colombier qunlock(&sdev->unitlock);
2869ef1f84bSDavid du Colombier return nil;
2879ef1f84bSDavid du Colombier }
2889ef1f84bSDavid du Colombier if((unit = malloc(sizeof(SDunit))) == nil){
2899ef1f84bSDavid du Colombier qunlock(&sdev->unitlock);
2909ef1f84bSDavid du Colombier return nil;
2919ef1f84bSDavid du Colombier }
2929ef1f84bSDavid du Colombier sdev->unitflg[subno] = 1;
2939ef1f84bSDavid du Colombier
2949ef1f84bSDavid du Colombier snprint(buf, sizeof(buf), "%s%d", sdev->name, subno);
2959ef1f84bSDavid du Colombier kstrdup(&unit->name, buf);
2969ef1f84bSDavid du Colombier kstrdup(&unit->user, eve);
2979ef1f84bSDavid du Colombier unit->perm = 0555;
2989ef1f84bSDavid du Colombier unit->subno = subno;
2999ef1f84bSDavid du Colombier unit->dev = sdev;
3009ef1f84bSDavid du Colombier
3019ef1f84bSDavid du Colombier if(sdev->enabled == 0 && sdev->ifc->enable)
3029ef1f84bSDavid du Colombier sdev->ifc->enable(sdev);
3039ef1f84bSDavid du Colombier sdev->enabled = 1;
3049ef1f84bSDavid du Colombier
3059ef1f84bSDavid du Colombier /*
3069ef1f84bSDavid du Colombier * No need to lock anything here as this is only
3079ef1f84bSDavid du Colombier * called before the unit is made available in the
3089ef1f84bSDavid du Colombier * sdunit[] array.
3099ef1f84bSDavid du Colombier */
3109ef1f84bSDavid du Colombier if(unit->dev->ifc->verify(unit) == 0){
3119ef1f84bSDavid du Colombier qunlock(&sdev->unitlock);
3129ef1f84bSDavid du Colombier free(unit);
3139ef1f84bSDavid du Colombier return nil;
3149ef1f84bSDavid du Colombier }
3159ef1f84bSDavid du Colombier sdev->unit[subno] = unit;
3169ef1f84bSDavid du Colombier }
3179ef1f84bSDavid du Colombier qunlock(&sdev->unitlock);
3189ef1f84bSDavid du Colombier return unit;
3199ef1f84bSDavid du Colombier }
3209ef1f84bSDavid du Colombier
3219ef1f84bSDavid du Colombier static void
sdreset(void)3229ef1f84bSDavid du Colombier sdreset(void)
3239ef1f84bSDavid du Colombier {
3249ef1f84bSDavid du Colombier int i;
3259ef1f84bSDavid du Colombier SDev *sdev;
3269ef1f84bSDavid du Colombier
3279ef1f84bSDavid du Colombier /*
3289ef1f84bSDavid du Colombier * Probe all known controller types and register any devices found.
3299ef1f84bSDavid du Colombier */
3309ef1f84bSDavid du Colombier for(i = 0; sdifc[i] != nil; i++){
3319ef1f84bSDavid du Colombier if(sdifc[i]->pnp == nil || (sdev = sdifc[i]->pnp()) == nil)
3329ef1f84bSDavid du Colombier continue;
3339ef1f84bSDavid du Colombier sdadddevs(sdev);
3349ef1f84bSDavid du Colombier }
3359ef1f84bSDavid du Colombier }
3369ef1f84bSDavid du Colombier
3379ef1f84bSDavid du Colombier void
sdadddevs(SDev * sdev)3389ef1f84bSDavid du Colombier sdadddevs(SDev *sdev)
3399ef1f84bSDavid du Colombier {
3409ef1f84bSDavid du Colombier int i, j, id;
3419ef1f84bSDavid du Colombier SDev *next;
3429ef1f84bSDavid du Colombier
3439ef1f84bSDavid du Colombier for(; sdev; sdev=next){
3449ef1f84bSDavid du Colombier next = sdev->next;
3459ef1f84bSDavid du Colombier
3469ef1f84bSDavid du Colombier sdev->unit = (SDunit**)malloc(sdev->nunit * sizeof(SDunit*));
3479ef1f84bSDavid du Colombier sdev->unitflg = (int*)malloc(sdev->nunit * sizeof(int));
3489ef1f84bSDavid du Colombier if(sdev->unit == nil || sdev->unitflg == nil){
3499ef1f84bSDavid du Colombier print("sdadddevs: out of memory\n");
3509ef1f84bSDavid du Colombier giveup:
3519ef1f84bSDavid du Colombier free(sdev->unit);
3529ef1f84bSDavid du Colombier free(sdev->unitflg);
3539ef1f84bSDavid du Colombier if(sdev->ifc->clear)
3549ef1f84bSDavid du Colombier sdev->ifc->clear(sdev);
3559ef1f84bSDavid du Colombier free(sdev);
3569ef1f84bSDavid du Colombier continue;
3579ef1f84bSDavid du Colombier }
3589ef1f84bSDavid du Colombier id = sdindex(sdev->idno);
3599ef1f84bSDavid du Colombier if(id == -1){
3609ef1f84bSDavid du Colombier print("sdadddevs: bad id number %d (%C)\n", id, id);
3619ef1f84bSDavid du Colombier goto giveup;
3629ef1f84bSDavid du Colombier }
3639ef1f84bSDavid du Colombier qlock(&devslock);
3649ef1f84bSDavid du Colombier for(i=0; i<nelem(devs); i++){
3659ef1f84bSDavid du Colombier if(devs[j = (id+i)%nelem(devs)] == nil){
3669ef1f84bSDavid du Colombier sdev->idno = devletters[j];
3679ef1f84bSDavid du Colombier devs[j] = sdev;
3689ef1f84bSDavid du Colombier snprint(sdev->name, sizeof sdev->name, "sd%c", devletters[j]);
3699ef1f84bSDavid du Colombier break;
3709ef1f84bSDavid du Colombier }
3719ef1f84bSDavid du Colombier }
3729ef1f84bSDavid du Colombier qunlock(&devslock);
3739ef1f84bSDavid du Colombier if(i == nelem(devs)){
3749ef1f84bSDavid du Colombier print("sdadddevs: out of device letters\n");
3759ef1f84bSDavid du Colombier goto giveup;
3769ef1f84bSDavid du Colombier }
3779ef1f84bSDavid du Colombier }
3789ef1f84bSDavid du Colombier }
3799ef1f84bSDavid du Colombier
3809ef1f84bSDavid du Colombier // void
3819ef1f84bSDavid du Colombier // sdrmdevs(SDev *sdev)
3829ef1f84bSDavid du Colombier // {
3839ef1f84bSDavid du Colombier // char buf[2];
3849ef1f84bSDavid du Colombier //
3859ef1f84bSDavid du Colombier // snprint(buf, sizeof buf, "%c", sdev->idno);
3869ef1f84bSDavid du Colombier // unconfigure(buf);
3879ef1f84bSDavid du Colombier // }
3889ef1f84bSDavid du Colombier
3899ef1f84bSDavid du Colombier void
sdaddallconfs(void (* addconf)(SDunit *))3909ef1f84bSDavid du Colombier sdaddallconfs(void (*addconf)(SDunit *))
3919ef1f84bSDavid du Colombier {
3929ef1f84bSDavid du Colombier int i, u;
3939ef1f84bSDavid du Colombier SDev *sdev;
3949ef1f84bSDavid du Colombier
3959ef1f84bSDavid du Colombier for(i = 0; i < nelem(devs); i++) /* each controller */
3969ef1f84bSDavid du Colombier for(sdev = devs[i]; sdev; sdev = sdev->next)
3979ef1f84bSDavid du Colombier for(u = 0; u < sdev->nunit; u++) /* each drive */
3989ef1f84bSDavid du Colombier (*addconf)(sdev->unit[u]);
3999ef1f84bSDavid du Colombier }
4009ef1f84bSDavid du Colombier
4019ef1f84bSDavid du Colombier static int
sd2gen(Chan * c,int i,Dir * dp)4029ef1f84bSDavid du Colombier sd2gen(Chan* c, int i, Dir* dp)
4039ef1f84bSDavid du Colombier {
4049ef1f84bSDavid du Colombier Qid q;
4059ef1f84bSDavid du Colombier uvlong l;
4069ef1f84bSDavid du Colombier SDpart *pp;
4079ef1f84bSDavid du Colombier SDperm *perm;
4089ef1f84bSDavid du Colombier SDunit *unit;
4099ef1f84bSDavid du Colombier SDev *sdev;
4109ef1f84bSDavid du Colombier int rv;
4119ef1f84bSDavid du Colombier
4129ef1f84bSDavid du Colombier sdev = sdgetdev(DEV(c->qid));
4139ef1f84bSDavid du Colombier assert(sdev);
4149ef1f84bSDavid du Colombier unit = sdev->unit[UNIT(c->qid)];
4159ef1f84bSDavid du Colombier
4169ef1f84bSDavid du Colombier rv = -1;
4179ef1f84bSDavid du Colombier switch(i){
4189ef1f84bSDavid du Colombier case Qctl:
4199ef1f84bSDavid du Colombier mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), PART(c->qid), Qctl),
4209ef1f84bSDavid du Colombier unit->vers, QTFILE);
4219ef1f84bSDavid du Colombier perm = &unit->ctlperm;
4229ef1f84bSDavid du Colombier if(emptystr(perm->user)){
4239ef1f84bSDavid du Colombier kstrdup(&perm->user, eve);
4249ef1f84bSDavid du Colombier perm->perm = 0644; /* nothing secret in ctl */
4259ef1f84bSDavid du Colombier }
4269ef1f84bSDavid du Colombier devdir(c, q, "ctl", 0, perm->user, perm->perm, dp);
4279ef1f84bSDavid du Colombier rv = 1;
4289ef1f84bSDavid du Colombier break;
4299ef1f84bSDavid du Colombier
4309ef1f84bSDavid du Colombier case Qraw:
4319ef1f84bSDavid du Colombier mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), PART(c->qid), Qraw),
4329ef1f84bSDavid du Colombier unit->vers, QTFILE);
4339ef1f84bSDavid du Colombier perm = &unit->rawperm;
4349ef1f84bSDavid du Colombier if(emptystr(perm->user)){
4359ef1f84bSDavid du Colombier kstrdup(&perm->user, eve);
4369ef1f84bSDavid du Colombier perm->perm = DMEXCL|0600;
4379ef1f84bSDavid du Colombier }
4389ef1f84bSDavid du Colombier devdir(c, q, "raw", 0, perm->user, perm->perm, dp);
4399ef1f84bSDavid du Colombier rv = 1;
4409ef1f84bSDavid du Colombier break;
4419ef1f84bSDavid du Colombier
4429ef1f84bSDavid du Colombier case Qpart:
4439ef1f84bSDavid du Colombier pp = &unit->part[PART(c->qid)];
4449ef1f84bSDavid du Colombier l = (pp->end - pp->start) * unit->secsize;
4459ef1f84bSDavid du Colombier mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), PART(c->qid), Qpart),
4469ef1f84bSDavid du Colombier unit->vers+pp->vers, QTFILE);
4479ef1f84bSDavid du Colombier if(emptystr(pp->user))
4489ef1f84bSDavid du Colombier kstrdup(&pp->user, eve);
4499ef1f84bSDavid du Colombier devdir(c, q, pp->name, l, pp->user, pp->perm, dp);
4509ef1f84bSDavid du Colombier rv = 1;
4519ef1f84bSDavid du Colombier break;
4529ef1f84bSDavid du Colombier }
4539ef1f84bSDavid du Colombier
4549ef1f84bSDavid du Colombier decref(&sdev->r);
4559ef1f84bSDavid du Colombier return rv;
4569ef1f84bSDavid du Colombier }
4579ef1f84bSDavid du Colombier
4589ef1f84bSDavid du Colombier static int
sd1gen(Chan * c,int i,Dir * dp)4599ef1f84bSDavid du Colombier sd1gen(Chan* c, int i, Dir* dp)
4609ef1f84bSDavid du Colombier {
4619ef1f84bSDavid du Colombier Qid q;
4629ef1f84bSDavid du Colombier
4639ef1f84bSDavid du Colombier switch(i){
4649ef1f84bSDavid du Colombier case Qtopctl:
4659ef1f84bSDavid du Colombier mkqid(&q, QID(0, 0, 0, Qtopctl), 0, QTFILE);
4669ef1f84bSDavid du Colombier devdir(c, q, "sdctl", 0, eve, 0644, dp); /* no secrets */
4679ef1f84bSDavid du Colombier return 1;
4689ef1f84bSDavid du Colombier }
4699ef1f84bSDavid du Colombier return -1;
4709ef1f84bSDavid du Colombier }
4719ef1f84bSDavid du Colombier
4729ef1f84bSDavid du Colombier static int
sdgen(Chan * c,char *,Dirtab *,int,int s,Dir * dp)4739ef1f84bSDavid du Colombier sdgen(Chan* c, char*, Dirtab*, int, int s, Dir* dp)
4749ef1f84bSDavid du Colombier {
4759ef1f84bSDavid du Colombier Qid q;
4769ef1f84bSDavid du Colombier uvlong l;
4779ef1f84bSDavid du Colombier int i, r;
4789ef1f84bSDavid du Colombier SDpart *pp;
4799ef1f84bSDavid du Colombier SDunit *unit;
4809ef1f84bSDavid du Colombier SDev *sdev;
4819ef1f84bSDavid du Colombier
4829ef1f84bSDavid du Colombier switch(TYPE(c->qid)){
4839ef1f84bSDavid du Colombier case Qtopdir:
4849ef1f84bSDavid du Colombier if(s == DEVDOTDOT){
4859ef1f84bSDavid du Colombier mkqid(&q, QID(0, 0, 0, Qtopdir), 0, QTDIR);
486406c76faSDavid du Colombier snprint(up->genbuf, sizeof up->genbuf, "#%C",
487406c76faSDavid du Colombier sddevtab.dc);
4889ef1f84bSDavid du Colombier devdir(c, q, up->genbuf, 0, eve, 0555, dp);
4899ef1f84bSDavid du Colombier return 1;
4909ef1f84bSDavid du Colombier }
4919ef1f84bSDavid du Colombier
4929ef1f84bSDavid du Colombier if(s+Qtopbase < Qunitdir)
4939ef1f84bSDavid du Colombier return sd1gen(c, s+Qtopbase, dp);
4949ef1f84bSDavid du Colombier s -= (Qunitdir-Qtopbase);
4959ef1f84bSDavid du Colombier
4969ef1f84bSDavid du Colombier qlock(&devslock);
4979ef1f84bSDavid du Colombier for(i=0; i<nelem(devs); i++){
4989ef1f84bSDavid du Colombier if(devs[i]){
4999ef1f84bSDavid du Colombier if(s < devs[i]->nunit)
5009ef1f84bSDavid du Colombier break;
5019ef1f84bSDavid du Colombier s -= devs[i]->nunit;
5029ef1f84bSDavid du Colombier }
5039ef1f84bSDavid du Colombier }
5049ef1f84bSDavid du Colombier
5059ef1f84bSDavid du Colombier if(i == nelem(devs)){
5069ef1f84bSDavid du Colombier /* Run off the end of the list */
5079ef1f84bSDavid du Colombier qunlock(&devslock);
5089ef1f84bSDavid du Colombier return -1;
5099ef1f84bSDavid du Colombier }
5109ef1f84bSDavid du Colombier
5119ef1f84bSDavid du Colombier if((sdev = devs[i]) == nil){
5129ef1f84bSDavid du Colombier qunlock(&devslock);
5139ef1f84bSDavid du Colombier return 0;
5149ef1f84bSDavid du Colombier }
5159ef1f84bSDavid du Colombier
5169ef1f84bSDavid du Colombier incref(&sdev->r);
5179ef1f84bSDavid du Colombier qunlock(&devslock);
5189ef1f84bSDavid du Colombier
5199ef1f84bSDavid du Colombier if((unit = sdev->unit[s]) == nil)
5209ef1f84bSDavid du Colombier if((unit = sdgetunit(sdev, s)) == nil){
5219ef1f84bSDavid du Colombier decref(&sdev->r);
5229ef1f84bSDavid du Colombier return 0;
5239ef1f84bSDavid du Colombier }
5249ef1f84bSDavid du Colombier
5259ef1f84bSDavid du Colombier mkqid(&q, QID(sdev->idno, s, 0, Qunitdir), 0, QTDIR);
5269ef1f84bSDavid du Colombier if(emptystr(unit->user))
5279ef1f84bSDavid du Colombier kstrdup(&unit->user, eve);
5289ef1f84bSDavid du Colombier devdir(c, q, unit->name, 0, unit->user, unit->perm, dp);
5299ef1f84bSDavid du Colombier decref(&sdev->r);
5309ef1f84bSDavid du Colombier return 1;
5319ef1f84bSDavid du Colombier
5329ef1f84bSDavid du Colombier case Qunitdir:
5339ef1f84bSDavid du Colombier if(s == DEVDOTDOT){
5349ef1f84bSDavid du Colombier mkqid(&q, QID(0, 0, 0, Qtopdir), 0, QTDIR);
535406c76faSDavid du Colombier snprint(up->genbuf, sizeof up->genbuf, "#%C",
536406c76faSDavid du Colombier sddevtab.dc);
5379ef1f84bSDavid du Colombier devdir(c, q, up->genbuf, 0, eve, 0555, dp);
5389ef1f84bSDavid du Colombier return 1;
5399ef1f84bSDavid du Colombier }
5409ef1f84bSDavid du Colombier
5419ef1f84bSDavid du Colombier if((sdev = sdgetdev(DEV(c->qid))) == nil){
5429ef1f84bSDavid du Colombier devdir(c, c->qid, "unavailable", 0, eve, 0, dp);
5439ef1f84bSDavid du Colombier return 1;
5449ef1f84bSDavid du Colombier }
5459ef1f84bSDavid du Colombier
5469ef1f84bSDavid du Colombier unit = sdev->unit[UNIT(c->qid)];
5479ef1f84bSDavid du Colombier qlock(&unit->ctl);
5489ef1f84bSDavid du Colombier
5499ef1f84bSDavid du Colombier /*
5509ef1f84bSDavid du Colombier * Check for media change.
5519ef1f84bSDavid du Colombier * If one has already been detected, sectors will be zero.
5529ef1f84bSDavid du Colombier * If there is one waiting to be detected, online
5539ef1f84bSDavid du Colombier * will return > 1.
5549ef1f84bSDavid du Colombier * Online is a bit of a large hammer but does the job.
5559ef1f84bSDavid du Colombier */
5569ef1f84bSDavid du Colombier if(unit->sectors == 0
5579ef1f84bSDavid du Colombier || (unit->dev->ifc->online && unit->dev->ifc->online(unit) > 1))
5589ef1f84bSDavid du Colombier sdinitpart(unit);
5599ef1f84bSDavid du Colombier
5609ef1f84bSDavid du Colombier i = s+Qunitbase;
5619ef1f84bSDavid du Colombier if(i < Qpart){
5629ef1f84bSDavid du Colombier r = sd2gen(c, i, dp);
5639ef1f84bSDavid du Colombier qunlock(&unit->ctl);
5649ef1f84bSDavid du Colombier decref(&sdev->r);
5659ef1f84bSDavid du Colombier return r;
5669ef1f84bSDavid du Colombier }
5679ef1f84bSDavid du Colombier i -= Qpart;
5689ef1f84bSDavid du Colombier if(unit->part == nil || i >= unit->npart){
5699ef1f84bSDavid du Colombier qunlock(&unit->ctl);
5709ef1f84bSDavid du Colombier decref(&sdev->r);
5719ef1f84bSDavid du Colombier break;
5729ef1f84bSDavid du Colombier }
5739ef1f84bSDavid du Colombier pp = &unit->part[i];
5749ef1f84bSDavid du Colombier if(!pp->valid){
5759ef1f84bSDavid du Colombier qunlock(&unit->ctl);
5769ef1f84bSDavid du Colombier decref(&sdev->r);
5779ef1f84bSDavid du Colombier return 0;
5789ef1f84bSDavid du Colombier }
5799ef1f84bSDavid du Colombier l = (pp->end - pp->start) * unit->secsize;
5809ef1f84bSDavid du Colombier mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), i, Qpart),
5819ef1f84bSDavid du Colombier unit->vers+pp->vers, QTFILE);
5829ef1f84bSDavid du Colombier if(emptystr(pp->user))
5839ef1f84bSDavid du Colombier kstrdup(&pp->user, eve);
5849ef1f84bSDavid du Colombier devdir(c, q, pp->name, l, pp->user, pp->perm, dp);
5859ef1f84bSDavid du Colombier qunlock(&unit->ctl);
5869ef1f84bSDavid du Colombier decref(&sdev->r);
5879ef1f84bSDavid du Colombier return 1;
5889ef1f84bSDavid du Colombier case Qraw:
5899ef1f84bSDavid du Colombier case Qctl:
5909ef1f84bSDavid du Colombier case Qpart:
5919ef1f84bSDavid du Colombier if((sdev = sdgetdev(DEV(c->qid))) == nil){
5929ef1f84bSDavid du Colombier devdir(c, q, "unavailable", 0, eve, 0, dp);
5939ef1f84bSDavid du Colombier return 1;
5949ef1f84bSDavid du Colombier }
5959ef1f84bSDavid du Colombier unit = sdev->unit[UNIT(c->qid)];
5969ef1f84bSDavid du Colombier qlock(&unit->ctl);
5979ef1f84bSDavid du Colombier r = sd2gen(c, TYPE(c->qid), dp);
5989ef1f84bSDavid du Colombier qunlock(&unit->ctl);
5999ef1f84bSDavid du Colombier decref(&sdev->r);
6009ef1f84bSDavid du Colombier return r;
6019ef1f84bSDavid du Colombier case Qtopctl:
6029ef1f84bSDavid du Colombier return sd1gen(c, TYPE(c->qid), dp);
6039ef1f84bSDavid du Colombier default:
6049ef1f84bSDavid du Colombier break;
6059ef1f84bSDavid du Colombier }
6069ef1f84bSDavid du Colombier
6079ef1f84bSDavid du Colombier return -1;
6089ef1f84bSDavid du Colombier }
6099ef1f84bSDavid du Colombier
6109ef1f84bSDavid du Colombier static Chan*
sdattach(char * spec)6119ef1f84bSDavid du Colombier sdattach(char* spec)
6129ef1f84bSDavid du Colombier {
6139ef1f84bSDavid du Colombier Chan *c;
6149ef1f84bSDavid du Colombier char *p;
6159ef1f84bSDavid du Colombier SDev *sdev;
6169ef1f84bSDavid du Colombier int idno, subno;
6179ef1f84bSDavid du Colombier
6189ef1f84bSDavid du Colombier if(*spec == '\0'){
6199ef1f84bSDavid du Colombier c = devattach(sddevtab.dc, spec);
6209ef1f84bSDavid du Colombier mkqid(&c->qid, QID(0, 0, 0, Qtopdir), 0, QTDIR);
6219ef1f84bSDavid du Colombier return c;
6229ef1f84bSDavid du Colombier }
6239ef1f84bSDavid du Colombier
6249ef1f84bSDavid du Colombier if(spec[0] != 's' || spec[1] != 'd')
6259ef1f84bSDavid du Colombier error(Ebadspec);
6269ef1f84bSDavid du Colombier idno = spec[2];
6279ef1f84bSDavid du Colombier subno = strtol(&spec[3], &p, 0);
6289ef1f84bSDavid du Colombier if(p == &spec[3])
6299ef1f84bSDavid du Colombier error(Ebadspec);
6309ef1f84bSDavid du Colombier
6319ef1f84bSDavid du Colombier if((sdev=sdgetdev(idno)) == nil)
6329ef1f84bSDavid du Colombier error(Enonexist);
6339ef1f84bSDavid du Colombier if(sdgetunit(sdev, subno) == nil){
6349ef1f84bSDavid du Colombier decref(&sdev->r);
6359ef1f84bSDavid du Colombier error(Enonexist);
6369ef1f84bSDavid du Colombier }
6379ef1f84bSDavid du Colombier
6389ef1f84bSDavid du Colombier c = devattach(sddevtab.dc, spec);
6399ef1f84bSDavid du Colombier mkqid(&c->qid, QID(sdev->idno, subno, 0, Qunitdir), 0, QTDIR);
6409ef1f84bSDavid du Colombier c->devno = (sdev->idno << UnitLOG) + subno;
6419ef1f84bSDavid du Colombier decref(&sdev->r);
6429ef1f84bSDavid du Colombier return c;
6439ef1f84bSDavid du Colombier }
6449ef1f84bSDavid du Colombier
6459ef1f84bSDavid du Colombier static Walkqid*
sdwalk(Chan * c,Chan * nc,char ** name,int nname)6469ef1f84bSDavid du Colombier sdwalk(Chan* c, Chan* nc, char** name, int nname)
6479ef1f84bSDavid du Colombier {
6489ef1f84bSDavid du Colombier return devwalk(c, nc, name, nname, nil, 0, sdgen);
6499ef1f84bSDavid du Colombier }
6509ef1f84bSDavid du Colombier
6519ef1f84bSDavid du Colombier static long
sdstat(Chan * c,uchar * db,long n)6529ef1f84bSDavid du Colombier sdstat(Chan* c, uchar* db, long n)
6539ef1f84bSDavid du Colombier {
6549ef1f84bSDavid du Colombier return devstat(c, db, n, nil, 0, sdgen);
6559ef1f84bSDavid du Colombier }
6569ef1f84bSDavid du Colombier
6579ef1f84bSDavid du Colombier static Chan*
sdopen(Chan * c,int omode)6589ef1f84bSDavid du Colombier sdopen(Chan* c, int omode)
6599ef1f84bSDavid du Colombier {
6609ef1f84bSDavid du Colombier SDpart *pp;
6619ef1f84bSDavid du Colombier SDunit *unit;
6629ef1f84bSDavid du Colombier SDev *sdev;
6639ef1f84bSDavid du Colombier uchar tp;
6649ef1f84bSDavid du Colombier
6659ef1f84bSDavid du Colombier c = devopen(c, omode, 0, 0, sdgen);
6669ef1f84bSDavid du Colombier if((tp = TYPE(c->qid)) != Qctl && tp != Qraw && tp != Qpart)
6679ef1f84bSDavid du Colombier return c;
6689ef1f84bSDavid du Colombier
6699ef1f84bSDavid du Colombier sdev = sdgetdev(DEV(c->qid));
6709ef1f84bSDavid du Colombier if(sdev == nil)
6719ef1f84bSDavid du Colombier error(Enonexist);
6729ef1f84bSDavid du Colombier
6739ef1f84bSDavid du Colombier unit = sdev->unit[UNIT(c->qid)];
6749ef1f84bSDavid du Colombier
6759ef1f84bSDavid du Colombier switch(TYPE(c->qid)){
6769ef1f84bSDavid du Colombier case Qctl:
6779ef1f84bSDavid du Colombier c->qid.vers = unit->vers;
6789ef1f84bSDavid du Colombier break;
6799ef1f84bSDavid du Colombier case Qraw:
6809ef1f84bSDavid du Colombier c->qid.vers = unit->vers;
6819ef1f84bSDavid du Colombier if(TAS(&unit->rawinuse) != 0){
6829ef1f84bSDavid du Colombier c->flag &= ~COPEN;
6839ef1f84bSDavid du Colombier decref(&sdev->r);
6849ef1f84bSDavid du Colombier error(Einuse);
6859ef1f84bSDavid du Colombier }
6869ef1f84bSDavid du Colombier unit->state = Rawcmd;
6879ef1f84bSDavid du Colombier break;
6889ef1f84bSDavid du Colombier case Qpart:
6899ef1f84bSDavid du Colombier qlock(&unit->ctl);
6909ef1f84bSDavid du Colombier if(waserror()){
6919ef1f84bSDavid du Colombier qunlock(&unit->ctl);
6929ef1f84bSDavid du Colombier c->flag &= ~COPEN;
6939ef1f84bSDavid du Colombier decref(&sdev->r);
6949ef1f84bSDavid du Colombier nexterror();
6959ef1f84bSDavid du Colombier }
6969ef1f84bSDavid du Colombier pp = &unit->part[PART(c->qid)];
6979ef1f84bSDavid du Colombier c->qid.vers = unit->vers+pp->vers;
6989ef1f84bSDavid du Colombier qunlock(&unit->ctl);
6999ef1f84bSDavid du Colombier poperror();
7009ef1f84bSDavid du Colombier break;
7019ef1f84bSDavid du Colombier }
7029ef1f84bSDavid du Colombier decref(&sdev->r);
7039ef1f84bSDavid du Colombier return c;
7049ef1f84bSDavid du Colombier }
7059ef1f84bSDavid du Colombier
7069ef1f84bSDavid du Colombier static void
sdclose(Chan * c)7079ef1f84bSDavid du Colombier sdclose(Chan* c)
7089ef1f84bSDavid du Colombier {
7099ef1f84bSDavid du Colombier SDunit *unit;
7109ef1f84bSDavid du Colombier SDev *sdev;
7119ef1f84bSDavid du Colombier
7129ef1f84bSDavid du Colombier if(c->qid.type & QTDIR)
7139ef1f84bSDavid du Colombier return;
7149ef1f84bSDavid du Colombier if(!(c->flag & COPEN))
7159ef1f84bSDavid du Colombier return;
7169ef1f84bSDavid du Colombier
7179ef1f84bSDavid du Colombier switch(TYPE(c->qid)){
7189ef1f84bSDavid du Colombier default:
7199ef1f84bSDavid du Colombier break;
7209ef1f84bSDavid du Colombier case Qraw:
7219ef1f84bSDavid du Colombier sdev = sdgetdev(DEV(c->qid));
7229ef1f84bSDavid du Colombier if(sdev){
7239ef1f84bSDavid du Colombier unit = sdev->unit[UNIT(c->qid)];
7249ef1f84bSDavid du Colombier unit->rawinuse = 0;
7259ef1f84bSDavid du Colombier decref(&sdev->r);
7269ef1f84bSDavid du Colombier }
7279ef1f84bSDavid du Colombier break;
7289ef1f84bSDavid du Colombier }
7299ef1f84bSDavid du Colombier }
7309ef1f84bSDavid du Colombier
7319ef1f84bSDavid du Colombier static long
sdbio(Chan * c,int write,char * a,long len,vlong off)7329ef1f84bSDavid du Colombier sdbio(Chan* c, int write, char* a, long len, vlong off)
7339ef1f84bSDavid du Colombier {
7349ef1f84bSDavid du Colombier int nchange;
7359ef1f84bSDavid du Colombier uchar *b;
7369ef1f84bSDavid du Colombier SDpart *pp;
7379ef1f84bSDavid du Colombier SDunit *unit;
7389ef1f84bSDavid du Colombier SDev *sdev;
7399ef1f84bSDavid du Colombier vlong bno;
7409ef1f84bSDavid du Colombier long l, max, nb, offset;
7419ef1f84bSDavid du Colombier
7429ef1f84bSDavid du Colombier sdev = sdgetdev(DEV(c->qid));
7439ef1f84bSDavid du Colombier if(sdev == nil){
7449ef1f84bSDavid du Colombier decref(&sdev->r);
7459ef1f84bSDavid du Colombier error(Enonexist);
7469ef1f84bSDavid du Colombier }
7479ef1f84bSDavid du Colombier unit = sdev->unit[UNIT(c->qid)];
7489ef1f84bSDavid du Colombier if(unit == nil)
7499ef1f84bSDavid du Colombier error(Enonexist);
7509ef1f84bSDavid du Colombier
7519ef1f84bSDavid du Colombier nchange = 0;
7529ef1f84bSDavid du Colombier qlock(&unit->ctl);
7539ef1f84bSDavid du Colombier while(waserror()){
7549ef1f84bSDavid du Colombier /* notification of media change; go around again */
7559ef1f84bSDavid du Colombier if(strcmp(up->errstr, Eio) == 0 && unit->sectors == 0 && nchange++ == 0){
7569ef1f84bSDavid du Colombier sdinitpart(unit);
7579ef1f84bSDavid du Colombier continue;
7589ef1f84bSDavid du Colombier }
7599ef1f84bSDavid du Colombier
7609ef1f84bSDavid du Colombier /* other errors; give up */
7619ef1f84bSDavid du Colombier qunlock(&unit->ctl);
7629ef1f84bSDavid du Colombier decref(&sdev->r);
7639ef1f84bSDavid du Colombier nexterror();
7649ef1f84bSDavid du Colombier }
7659ef1f84bSDavid du Colombier pp = &unit->part[PART(c->qid)];
7669ef1f84bSDavid du Colombier if(unit->vers+pp->vers != c->qid.vers)
7679ef1f84bSDavid du Colombier error(Echange);
7689ef1f84bSDavid du Colombier
7699ef1f84bSDavid du Colombier /*
7709ef1f84bSDavid du Colombier * Check the request is within bounds.
7719ef1f84bSDavid du Colombier * Removeable drives are locked throughout the I/O
7729ef1f84bSDavid du Colombier * in case the media changes unexpectedly.
7739ef1f84bSDavid du Colombier * Non-removeable drives are not locked during the I/O
7749ef1f84bSDavid du Colombier * to allow the hardware to optimise if it can; this is
7759ef1f84bSDavid du Colombier * a little fast and loose.
7769ef1f84bSDavid du Colombier * It's assumed that non-removeable media parameters
7779ef1f84bSDavid du Colombier * (sectors, secsize) can't change once the drive has
7789ef1f84bSDavid du Colombier * been brought online.
7799ef1f84bSDavid du Colombier */
7809ef1f84bSDavid du Colombier bno = (off/unit->secsize) + pp->start;
7819ef1f84bSDavid du Colombier nb = ((off+len+unit->secsize-1)/unit->secsize) + pp->start - bno;
7829ef1f84bSDavid du Colombier max = SDmaxio/unit->secsize;
7839ef1f84bSDavid du Colombier if(nb > max)
7849ef1f84bSDavid du Colombier nb = max;
7859ef1f84bSDavid du Colombier if(bno+nb > pp->end)
7869ef1f84bSDavid du Colombier nb = pp->end - bno;
7879ef1f84bSDavid du Colombier if(bno >= pp->end || nb == 0){
7889ef1f84bSDavid du Colombier if(write)
7899ef1f84bSDavid du Colombier error(Eio);
7909ef1f84bSDavid du Colombier qunlock(&unit->ctl);
7919ef1f84bSDavid du Colombier decref(&sdev->r);
7929ef1f84bSDavid du Colombier poperror();
7939ef1f84bSDavid du Colombier return 0;
7949ef1f84bSDavid du Colombier }
7959ef1f84bSDavid du Colombier if(!(unit->inquiry[1] & SDinq1removable)){
7969ef1f84bSDavid du Colombier qunlock(&unit->ctl);
7979ef1f84bSDavid du Colombier poperror();
7989ef1f84bSDavid du Colombier }
7999ef1f84bSDavid du Colombier
8009ef1f84bSDavid du Colombier b = sdmalloc(nb*unit->secsize);
8019ef1f84bSDavid du Colombier if(b == nil)
8029ef1f84bSDavid du Colombier error(Enomem);
8039ef1f84bSDavid du Colombier if(waserror()){
8049ef1f84bSDavid du Colombier sdfree(b);
8059ef1f84bSDavid du Colombier if(!(unit->inquiry[1] & SDinq1removable))
8069ef1f84bSDavid du Colombier decref(&sdev->r); /* gadverdamme! */
8079ef1f84bSDavid du Colombier nexterror();
8089ef1f84bSDavid du Colombier }
8099ef1f84bSDavid du Colombier
8109ef1f84bSDavid du Colombier offset = off%unit->secsize;
8119ef1f84bSDavid du Colombier if(offset+len > nb*unit->secsize)
8129ef1f84bSDavid du Colombier len = nb*unit->secsize - offset;
8139ef1f84bSDavid du Colombier if(write){
8149ef1f84bSDavid du Colombier if(offset || (len%unit->secsize)){
8159ef1f84bSDavid du Colombier l = unit->dev->ifc->bio(unit, 0, 0, b, nb, bno);
8169ef1f84bSDavid du Colombier if(l < 0)
8179ef1f84bSDavid du Colombier error(Eio);
8189ef1f84bSDavid du Colombier if(l < (nb*unit->secsize)){
8199ef1f84bSDavid du Colombier nb = l/unit->secsize;
8209ef1f84bSDavid du Colombier l = nb*unit->secsize - offset;
8219ef1f84bSDavid du Colombier if(len > l)
8229ef1f84bSDavid du Colombier len = l;
8239ef1f84bSDavid du Colombier }
8249ef1f84bSDavid du Colombier }
8259ef1f84bSDavid du Colombier memmove(b+offset, a, len);
8269ef1f84bSDavid du Colombier l = unit->dev->ifc->bio(unit, 0, 1, b, nb, bno);
8279ef1f84bSDavid du Colombier if(l < 0)
8289ef1f84bSDavid du Colombier error(Eio);
8299ef1f84bSDavid du Colombier if(l < offset)
8309ef1f84bSDavid du Colombier len = 0;
8319ef1f84bSDavid du Colombier else if(len > l - offset)
8329ef1f84bSDavid du Colombier len = l - offset;
8339ef1f84bSDavid du Colombier }
8349ef1f84bSDavid du Colombier else{
8359ef1f84bSDavid du Colombier l = unit->dev->ifc->bio(unit, 0, 0, b, nb, bno);
8369ef1f84bSDavid du Colombier if(l < 0)
8379ef1f84bSDavid du Colombier error(Eio);
8389ef1f84bSDavid du Colombier if(l < offset)
8399ef1f84bSDavid du Colombier len = 0;
8409ef1f84bSDavid du Colombier else if(len > l - offset)
8419ef1f84bSDavid du Colombier len = l - offset;
8429ef1f84bSDavid du Colombier memmove(a, b+offset, len);
8439ef1f84bSDavid du Colombier }
8449ef1f84bSDavid du Colombier sdfree(b);
8459ef1f84bSDavid du Colombier poperror();
8469ef1f84bSDavid du Colombier
8479ef1f84bSDavid du Colombier if(unit->inquiry[1] & SDinq1removable){
8489ef1f84bSDavid du Colombier qunlock(&unit->ctl);
8499ef1f84bSDavid du Colombier poperror();
8509ef1f84bSDavid du Colombier }
8519ef1f84bSDavid du Colombier
8529ef1f84bSDavid du Colombier decref(&sdev->r);
8539ef1f84bSDavid du Colombier return len;
8549ef1f84bSDavid du Colombier }
8559ef1f84bSDavid du Colombier
8569ef1f84bSDavid du Colombier static long
sdrio(SDreq * r,void * a,long n)8579ef1f84bSDavid du Colombier sdrio(SDreq* r, void* a, long n)
8589ef1f84bSDavid du Colombier {
8599ef1f84bSDavid du Colombier void *data;
8609ef1f84bSDavid du Colombier
8619ef1f84bSDavid du Colombier if(n >= SDmaxio || n < 0)
8629ef1f84bSDavid du Colombier error(Etoobig);
8639ef1f84bSDavid du Colombier
8649ef1f84bSDavid du Colombier data = nil;
8659ef1f84bSDavid du Colombier if(n){
8669ef1f84bSDavid du Colombier if((data = sdmalloc(n)) == nil)
8679ef1f84bSDavid du Colombier error(Enomem);
8689ef1f84bSDavid du Colombier if(r->write)
8699ef1f84bSDavid du Colombier memmove(data, a, n);
8709ef1f84bSDavid du Colombier }
8719ef1f84bSDavid du Colombier r->data = data;
8729ef1f84bSDavid du Colombier r->dlen = n;
8739ef1f84bSDavid du Colombier
8749ef1f84bSDavid du Colombier if(waserror()){
8759ef1f84bSDavid du Colombier sdfree(data);
8769ef1f84bSDavid du Colombier r->data = nil;
8779ef1f84bSDavid du Colombier nexterror();
8789ef1f84bSDavid du Colombier }
8799ef1f84bSDavid du Colombier
8809ef1f84bSDavid du Colombier if(r->unit->dev->ifc->rio(r) != SDok)
8819ef1f84bSDavid du Colombier error(Eio);
8829ef1f84bSDavid du Colombier
8839ef1f84bSDavid du Colombier if(!r->write && r->rlen > 0)
8849ef1f84bSDavid du Colombier memmove(a, data, r->rlen);
8859ef1f84bSDavid du Colombier sdfree(data);
8869ef1f84bSDavid du Colombier r->data = nil;
8879ef1f84bSDavid du Colombier poperror();
8889ef1f84bSDavid du Colombier
8899ef1f84bSDavid du Colombier return r->rlen;
8909ef1f84bSDavid du Colombier }
8919ef1f84bSDavid du Colombier
8929ef1f84bSDavid du Colombier /*
8939ef1f84bSDavid du Colombier * SCSI simulation for non-SCSI devices
8949ef1f84bSDavid du Colombier */
8959ef1f84bSDavid du Colombier int
sdsetsense(SDreq * r,int status,int key,int asc,int ascq)8969ef1f84bSDavid du Colombier sdsetsense(SDreq *r, int status, int key, int asc, int ascq)
8979ef1f84bSDavid du Colombier {
8989ef1f84bSDavid du Colombier int len;
8999ef1f84bSDavid du Colombier SDunit *unit;
9009ef1f84bSDavid du Colombier
9019ef1f84bSDavid du Colombier unit = r->unit;
9029ef1f84bSDavid du Colombier unit->sense[2] = key;
9039ef1f84bSDavid du Colombier unit->sense[12] = asc;
9049ef1f84bSDavid du Colombier unit->sense[13] = ascq;
9059ef1f84bSDavid du Colombier
9069ef1f84bSDavid du Colombier r->status = status;
9079ef1f84bSDavid du Colombier if(status == SDcheck && !(r->flags & SDnosense)){
9089ef1f84bSDavid du Colombier /* request sense case from sdfakescsi */
9099ef1f84bSDavid du Colombier len = sizeof unit->sense;
9109ef1f84bSDavid du Colombier if(len > sizeof r->sense-1)
9119ef1f84bSDavid du Colombier len = sizeof r->sense-1;
9129ef1f84bSDavid du Colombier memmove(r->sense, unit->sense, len);
9139ef1f84bSDavid du Colombier unit->sense[2] = 0;
9149ef1f84bSDavid du Colombier unit->sense[12] = 0;
9159ef1f84bSDavid du Colombier unit->sense[13] = 0;
9169ef1f84bSDavid du Colombier r->flags |= SDvalidsense;
9179ef1f84bSDavid du Colombier return SDok;
9189ef1f84bSDavid du Colombier }
9199ef1f84bSDavid du Colombier return status;
9209ef1f84bSDavid du Colombier }
9219ef1f84bSDavid du Colombier
9229ef1f84bSDavid du Colombier int
sdmodesense(SDreq * r,uchar * cmd,void * info,int ilen)9239ef1f84bSDavid du Colombier sdmodesense(SDreq *r, uchar *cmd, void *info, int ilen)
9249ef1f84bSDavid du Colombier {
9259ef1f84bSDavid du Colombier int len;
9269ef1f84bSDavid du Colombier uchar *data;
9279ef1f84bSDavid du Colombier
9289ef1f84bSDavid du Colombier /*
9299ef1f84bSDavid du Colombier * Fake a vendor-specific request with page code 0,
9309ef1f84bSDavid du Colombier * return the drive info.
9319ef1f84bSDavid du Colombier */
9329ef1f84bSDavid du Colombier if((cmd[2] & 0x3F) != 0 && (cmd[2] & 0x3F) != 0x3F)
9339ef1f84bSDavid du Colombier return sdsetsense(r, SDcheck, 0x05, 0x24, 0);
9349ef1f84bSDavid du Colombier len = (cmd[7]<<8)|cmd[8];
9359ef1f84bSDavid du Colombier if(len == 0)
9369ef1f84bSDavid du Colombier return SDok;
9379ef1f84bSDavid du Colombier if(len < 8+ilen)
9389ef1f84bSDavid du Colombier return sdsetsense(r, SDcheck, 0x05, 0x1A, 0);
9399ef1f84bSDavid du Colombier if(r->data == nil || r->dlen < len)
9409ef1f84bSDavid du Colombier return sdsetsense(r, SDcheck, 0x05, 0x20, 1);
9419ef1f84bSDavid du Colombier data = r->data;
9429ef1f84bSDavid du Colombier memset(data, 0, 8);
9439ef1f84bSDavid du Colombier data[0] = ilen>>8;
9449ef1f84bSDavid du Colombier data[1] = ilen;
9459ef1f84bSDavid du Colombier if(ilen)
9469ef1f84bSDavid du Colombier memmove(data+8, info, ilen);
9479ef1f84bSDavid du Colombier r->rlen = 8+ilen;
9489ef1f84bSDavid du Colombier return sdsetsense(r, SDok, 0, 0, 0);
9499ef1f84bSDavid du Colombier }
9509ef1f84bSDavid du Colombier
9519ef1f84bSDavid du Colombier int
sdfakescsi(SDreq * r,void * info,int ilen)9529ef1f84bSDavid du Colombier sdfakescsi(SDreq *r, void *info, int ilen)
9539ef1f84bSDavid du Colombier {
9549ef1f84bSDavid du Colombier uchar *cmd, *p;
9559ef1f84bSDavid du Colombier uvlong len;
9569ef1f84bSDavid du Colombier SDunit *unit;
9579ef1f84bSDavid du Colombier
9589ef1f84bSDavid du Colombier cmd = r->cmd;
9599ef1f84bSDavid du Colombier r->rlen = 0;
9609ef1f84bSDavid du Colombier unit = r->unit;
9619ef1f84bSDavid du Colombier
9629ef1f84bSDavid du Colombier /*
9639ef1f84bSDavid du Colombier * Rewrite read(6)/write(6) into read(10)/write(10).
9649ef1f84bSDavid du Colombier */
9659ef1f84bSDavid du Colombier switch(cmd[0]){
966a72b0d60SDavid du Colombier case ScmdRead:
967a72b0d60SDavid du Colombier case ScmdWrite:
9689ef1f84bSDavid du Colombier cmd[9] = 0;
9699ef1f84bSDavid du Colombier cmd[8] = cmd[4];
9709ef1f84bSDavid du Colombier cmd[7] = 0;
9719ef1f84bSDavid du Colombier cmd[6] = 0;
9729ef1f84bSDavid du Colombier cmd[5] = cmd[3];
9739ef1f84bSDavid du Colombier cmd[4] = cmd[2];
9749ef1f84bSDavid du Colombier cmd[3] = cmd[1] & 0x0F;
9759ef1f84bSDavid du Colombier cmd[2] = 0;
9769ef1f84bSDavid du Colombier cmd[1] &= 0xE0;
9779ef1f84bSDavid du Colombier cmd[0] |= 0x20;
9789ef1f84bSDavid du Colombier break;
9799ef1f84bSDavid du Colombier }
9809ef1f84bSDavid du Colombier
9819ef1f84bSDavid du Colombier /*
9829ef1f84bSDavid du Colombier * Map SCSI commands into ATA commands for discs.
9839ef1f84bSDavid du Colombier * Fail any command with a LUN except INQUIRY which
9849ef1f84bSDavid du Colombier * will return 'logical unit not supported'.
9859ef1f84bSDavid du Colombier */
986a72b0d60SDavid du Colombier if((cmd[1]>>5) && cmd[0] != ScmdInq)
9879ef1f84bSDavid du Colombier return sdsetsense(r, SDcheck, 0x05, 0x25, 0);
9889ef1f84bSDavid du Colombier
9899ef1f84bSDavid du Colombier switch(cmd[0]){
9909ef1f84bSDavid du Colombier default:
9919ef1f84bSDavid du Colombier return sdsetsense(r, SDcheck, 0x05, 0x20, 0);
9929ef1f84bSDavid du Colombier
993a72b0d60SDavid du Colombier case ScmdTur: /* test unit ready */
9949ef1f84bSDavid du Colombier return sdsetsense(r, SDok, 0, 0, 0);
9959ef1f84bSDavid du Colombier
996a72b0d60SDavid du Colombier case ScmdRsense: /* request sense */
9979ef1f84bSDavid du Colombier if(cmd[4] < sizeof unit->sense)
9989ef1f84bSDavid du Colombier len = cmd[4];
9999ef1f84bSDavid du Colombier else
10009ef1f84bSDavid du Colombier len = sizeof unit->sense;
10019ef1f84bSDavid du Colombier if(r->data && r->dlen >= len){
10029ef1f84bSDavid du Colombier memmove(r->data, unit->sense, len);
10039ef1f84bSDavid du Colombier r->rlen = len;
10049ef1f84bSDavid du Colombier }
10059ef1f84bSDavid du Colombier return sdsetsense(r, SDok, 0, 0, 0);
10069ef1f84bSDavid du Colombier
1007a72b0d60SDavid du Colombier case ScmdInq: /* inquiry */
10089ef1f84bSDavid du Colombier if(cmd[4] < sizeof unit->inquiry)
10099ef1f84bSDavid du Colombier len = cmd[4];
10109ef1f84bSDavid du Colombier else
10119ef1f84bSDavid du Colombier len = sizeof unit->inquiry;
10129ef1f84bSDavid du Colombier if(r->data && r->dlen >= len){
10139ef1f84bSDavid du Colombier memmove(r->data, unit->inquiry, len);
10149ef1f84bSDavid du Colombier r->rlen = len;
10159ef1f84bSDavid du Colombier }
10169ef1f84bSDavid du Colombier return sdsetsense(r, SDok, 0, 0, 0);
10179ef1f84bSDavid du Colombier
1018a72b0d60SDavid du Colombier case ScmdStart: /* start/stop unit */
10199ef1f84bSDavid du Colombier /*
10209ef1f84bSDavid du Colombier * nop for now, can use power management later.
10219ef1f84bSDavid du Colombier */
10229ef1f84bSDavid du Colombier return sdsetsense(r, SDok, 0, 0, 0);
10239ef1f84bSDavid du Colombier
1024a72b0d60SDavid du Colombier case ScmdRcapacity: /* read capacity */
10259ef1f84bSDavid du Colombier if((cmd[1] & 0x01) || cmd[2] || cmd[3])
10269ef1f84bSDavid du Colombier return sdsetsense(r, SDcheck, 0x05, 0x24, 0);
10279ef1f84bSDavid du Colombier if(r->data == nil || r->dlen < 8)
10289ef1f84bSDavid du Colombier return sdsetsense(r, SDcheck, 0x05, 0x20, 1);
10299ef1f84bSDavid du Colombier
10309ef1f84bSDavid du Colombier /*
10319ef1f84bSDavid du Colombier * Read capacity returns the LBA of the last sector.
10329ef1f84bSDavid du Colombier */
10339ef1f84bSDavid du Colombier len = unit->sectors - 1;
10349ef1f84bSDavid du Colombier p = r->data;
10359ef1f84bSDavid du Colombier *p++ = len>>24;
10369ef1f84bSDavid du Colombier *p++ = len>>16;
10379ef1f84bSDavid du Colombier *p++ = len>>8;
10389ef1f84bSDavid du Colombier *p++ = len;
10399ef1f84bSDavid du Colombier len = 512;
10409ef1f84bSDavid du Colombier *p++ = len>>24;
10419ef1f84bSDavid du Colombier *p++ = len>>16;
10429ef1f84bSDavid du Colombier *p++ = len>>8;
10439ef1f84bSDavid du Colombier *p++ = len;
10449ef1f84bSDavid du Colombier r->rlen = p - (uchar*)r->data;
10459ef1f84bSDavid du Colombier return sdsetsense(r, SDok, 0, 0, 0);
10469ef1f84bSDavid du Colombier
1047a72b0d60SDavid du Colombier case ScmdRcapacity16: /* long read capacity */
10489ef1f84bSDavid du Colombier if((cmd[1] & 0x01) || cmd[2] || cmd[3])
10499ef1f84bSDavid du Colombier return sdsetsense(r, SDcheck, 0x05, 0x24, 0);
10509ef1f84bSDavid du Colombier if(r->data == nil || r->dlen < 8)
10519ef1f84bSDavid du Colombier return sdsetsense(r, SDcheck, 0x05, 0x20, 1);
10529ef1f84bSDavid du Colombier /*
10539ef1f84bSDavid du Colombier * Read capcity returns the LBA of the last sector.
10549ef1f84bSDavid du Colombier */
10559ef1f84bSDavid du Colombier len = unit->sectors - 1;
10569ef1f84bSDavid du Colombier p = r->data;
10579ef1f84bSDavid du Colombier *p++ = len>>56;
10589ef1f84bSDavid du Colombier *p++ = len>>48;
10599ef1f84bSDavid du Colombier *p++ = len>>40;
10609ef1f84bSDavid du Colombier *p++ = len>>32;
10619ef1f84bSDavid du Colombier *p++ = len>>24;
10629ef1f84bSDavid du Colombier *p++ = len>>16;
10639ef1f84bSDavid du Colombier *p++ = len>>8;
10649ef1f84bSDavid du Colombier *p++ = len;
10659ef1f84bSDavid du Colombier len = 512;
10669ef1f84bSDavid du Colombier *p++ = len>>24;
10679ef1f84bSDavid du Colombier *p++ = len>>16;
10689ef1f84bSDavid du Colombier *p++ = len>>8;
10699ef1f84bSDavid du Colombier *p++ = len;
10709ef1f84bSDavid du Colombier r->rlen = p - (uchar*)r->data;
10719ef1f84bSDavid du Colombier return sdsetsense(r, SDok, 0, 0, 0);
10729ef1f84bSDavid du Colombier
1073a72b0d60SDavid du Colombier case ScmdMsense10: /* mode sense */
10749ef1f84bSDavid du Colombier return sdmodesense(r, cmd, info, ilen);
10759ef1f84bSDavid du Colombier
1076a72b0d60SDavid du Colombier case ScmdExtread:
1077a72b0d60SDavid du Colombier case ScmdExtwrite:
1078a72b0d60SDavid du Colombier case ScmdRead16:
1079a72b0d60SDavid du Colombier case ScmdWrite16:
10809ef1f84bSDavid du Colombier return SDnostatus;
10819ef1f84bSDavid du Colombier }
10829ef1f84bSDavid du Colombier }
10839ef1f84bSDavid du Colombier
1084*465c1891SDavid du Colombier int
sdfakescsirw(SDreq * r,uvlong * llba,int * nsec,int * rwp)1085*465c1891SDavid du Colombier sdfakescsirw(SDreq *r, uvlong *llba, int *nsec, int *rwp)
1086*465c1891SDavid du Colombier {
1087*465c1891SDavid du Colombier uchar *c;
1088*465c1891SDavid du Colombier int rw, count;
1089*465c1891SDavid du Colombier uvlong lba;
1090*465c1891SDavid du Colombier
1091*465c1891SDavid du Colombier c = r->cmd;
1092*465c1891SDavid du Colombier rw = 0;
1093*465c1891SDavid du Colombier if((c[0] & 0xf) == 0xa)
1094*465c1891SDavid du Colombier rw = 1;
1095*465c1891SDavid du Colombier switch(c[0]){
1096*465c1891SDavid du Colombier case 0x08: /* read6 */
1097*465c1891SDavid du Colombier case 0x0a:
1098*465c1891SDavid du Colombier lba = (c[1] & 0xf)<<16 | c[2]<<8 | c[3];
1099*465c1891SDavid du Colombier count = c[4];
1100*465c1891SDavid du Colombier break;
1101*465c1891SDavid du Colombier case 0x28: /* read10 */
1102*465c1891SDavid du Colombier case 0x2a:
1103*465c1891SDavid du Colombier lba = c[2]<<24 | c[3]<<16 | c[4]<<8 | c[5];
1104*465c1891SDavid du Colombier count = c[7]<<8 | c[8];
1105*465c1891SDavid du Colombier break;
1106*465c1891SDavid du Colombier case 0xa8: /* read12 */
1107*465c1891SDavid du Colombier case 0xaa:
1108*465c1891SDavid du Colombier lba = c[2]<<24 | c[3]<<16 | c[4]<<8 | c[5];
1109*465c1891SDavid du Colombier count = c[6]<<24 | c[7]<<16 | c[8]<<8 | c[9];
1110*465c1891SDavid du Colombier break;
1111*465c1891SDavid du Colombier case 0x88: /* read16 */
1112*465c1891SDavid du Colombier case 0x8a:
1113*465c1891SDavid du Colombier /* ata commands only go to 48-bit lba */
1114*465c1891SDavid du Colombier if(c[2] || c[3])
1115*465c1891SDavid du Colombier return sdsetsense(r, SDcheck, 3, 0xc, 2);
1116*465c1891SDavid du Colombier lba = (uvlong)c[4]<<40 | (uvlong)c[5]<<32;
1117*465c1891SDavid du Colombier lba |= c[6]<<24 | c[7]<<16 | c[8]<<8 | c[9];
1118*465c1891SDavid du Colombier count = c[10]<<24 | c[11]<<16 | c[12]<<8 | c[13];
1119*465c1891SDavid du Colombier break;
1120*465c1891SDavid du Colombier default:
1121*465c1891SDavid du Colombier print("%s: bad cmd 0x%.2ux\n", r->unit->name, c[0]);
1122*465c1891SDavid du Colombier r->status = sdsetsense(r, SDcheck, 0x05, 0x20, 0);
1123*465c1891SDavid du Colombier return SDcheck;
1124*465c1891SDavid du Colombier }
1125*465c1891SDavid du Colombier if(r->data == nil)
1126*465c1891SDavid du Colombier return SDok;
1127*465c1891SDavid du Colombier if(r->dlen < count * r->unit->secsize)
1128*465c1891SDavid du Colombier count = r->dlen/r->unit->secsize;
1129*465c1891SDavid du Colombier if(rwp)
1130*465c1891SDavid du Colombier *rwp = rw;
1131*465c1891SDavid du Colombier *llba = lba;
1132*465c1891SDavid du Colombier *nsec = count;
1133*465c1891SDavid du Colombier return SDnostatus;
1134*465c1891SDavid du Colombier }
1135*465c1891SDavid du Colombier
11369ef1f84bSDavid du Colombier static long
sdread(Chan * c,void * a,long n,vlong off)11379ef1f84bSDavid du Colombier sdread(Chan *c, void *a, long n, vlong off)
11389ef1f84bSDavid du Colombier {
11399ef1f84bSDavid du Colombier char *p, *e, *buf;
11409ef1f84bSDavid du Colombier SDpart *pp;
11419ef1f84bSDavid du Colombier SDunit *unit;
11429ef1f84bSDavid du Colombier SDev *sdev;
11439ef1f84bSDavid du Colombier long offset;
11449ef1f84bSDavid du Colombier int i, l, m, status;
11459ef1f84bSDavid du Colombier
11469ef1f84bSDavid du Colombier offset = off;
11479ef1f84bSDavid du Colombier switch(TYPE(c->qid)){
11489ef1f84bSDavid du Colombier default:
11499ef1f84bSDavid du Colombier error(Eperm);
11509ef1f84bSDavid du Colombier case Qtopctl:
11519ef1f84bSDavid du Colombier m = 64*1024; /* room for register dumps */
11529ef1f84bSDavid du Colombier p = buf = malloc(m);
11539ef1f84bSDavid du Colombier if(p == nil)
11549ef1f84bSDavid du Colombier error(Enomem);
11559ef1f84bSDavid du Colombier e = p + m;
11569ef1f84bSDavid du Colombier qlock(&devslock);
11579ef1f84bSDavid du Colombier for(i = 0; i < nelem(devs); i++){
11589ef1f84bSDavid du Colombier sdev = devs[i];
11599ef1f84bSDavid du Colombier if(sdev && sdev->ifc->rtopctl)
11609ef1f84bSDavid du Colombier p = sdev->ifc->rtopctl(sdev, p, e);
11619ef1f84bSDavid du Colombier }
11629ef1f84bSDavid du Colombier qunlock(&devslock);
11639ef1f84bSDavid du Colombier n = readstr(offset, a, n, buf);
11649ef1f84bSDavid du Colombier free(buf);
11659ef1f84bSDavid du Colombier return n;
11669ef1f84bSDavid du Colombier
11679ef1f84bSDavid du Colombier case Qtopdir:
11689ef1f84bSDavid du Colombier case Qunitdir:
11699ef1f84bSDavid du Colombier return devdirread(c, a, n, 0, 0, sdgen);
11709ef1f84bSDavid du Colombier
11719ef1f84bSDavid du Colombier case Qctl:
11729ef1f84bSDavid du Colombier sdev = sdgetdev(DEV(c->qid));
11739ef1f84bSDavid du Colombier if(sdev == nil)
11749ef1f84bSDavid du Colombier error(Enonexist);
11759ef1f84bSDavid du Colombier
11769ef1f84bSDavid du Colombier unit = sdev->unit[UNIT(c->qid)];
11779ef1f84bSDavid du Colombier m = 16*1024; /* room for register dumps */
11789ef1f84bSDavid du Colombier p = malloc(m);
11799ef1f84bSDavid du Colombier if(p == nil)
11809ef1f84bSDavid du Colombier error(Enomem);
11819ef1f84bSDavid du Colombier l = snprint(p, m, "inquiry %.48s\n",
11829ef1f84bSDavid du Colombier (char*)unit->inquiry+8);
11839ef1f84bSDavid du Colombier qlock(&unit->ctl);
11849ef1f84bSDavid du Colombier /*
11859ef1f84bSDavid du Colombier * If there's a device specific routine it must
11869ef1f84bSDavid du Colombier * provide all information pertaining to night geometry
11879ef1f84bSDavid du Colombier * and the garscadden trains.
11889ef1f84bSDavid du Colombier */
11899ef1f84bSDavid du Colombier if(unit->dev->ifc->rctl)
11909ef1f84bSDavid du Colombier l += unit->dev->ifc->rctl(unit, p+l, m-l);
11919ef1f84bSDavid du Colombier if(unit->sectors == 0)
11929ef1f84bSDavid du Colombier sdinitpart(unit);
11939ef1f84bSDavid du Colombier if(unit->sectors){
11949ef1f84bSDavid du Colombier if(unit->dev->ifc->rctl == nil)
11959ef1f84bSDavid du Colombier l += snprint(p+l, m-l,
11969ef1f84bSDavid du Colombier "geometry %llud %lud\n",
11979ef1f84bSDavid du Colombier unit->sectors, unit->secsize);
11989ef1f84bSDavid du Colombier pp = unit->part;
11999ef1f84bSDavid du Colombier for(i = 0; i < unit->npart; i++){
12009ef1f84bSDavid du Colombier if(pp->valid)
12019ef1f84bSDavid du Colombier l += snprint(p+l, m-l,
12029ef1f84bSDavid du Colombier "part %s %llud %llud\n",
12039ef1f84bSDavid du Colombier pp->name, pp->start, pp->end);
12049ef1f84bSDavid du Colombier pp++;
12059ef1f84bSDavid du Colombier }
12069ef1f84bSDavid du Colombier }
12079ef1f84bSDavid du Colombier qunlock(&unit->ctl);
12089ef1f84bSDavid du Colombier decref(&sdev->r);
12099ef1f84bSDavid du Colombier l = readstr(offset, a, n, p);
12109ef1f84bSDavid du Colombier free(p);
12119ef1f84bSDavid du Colombier return l;
12129ef1f84bSDavid du Colombier
12139ef1f84bSDavid du Colombier case Qraw:
12149ef1f84bSDavid du Colombier sdev = sdgetdev(DEV(c->qid));
12159ef1f84bSDavid du Colombier if(sdev == nil)
12169ef1f84bSDavid du Colombier error(Enonexist);
12179ef1f84bSDavid du Colombier
12189ef1f84bSDavid du Colombier unit = sdev->unit[UNIT(c->qid)];
12199ef1f84bSDavid du Colombier qlock(&unit->raw);
12209ef1f84bSDavid du Colombier if(waserror()){
12219ef1f84bSDavid du Colombier qunlock(&unit->raw);
12229ef1f84bSDavid du Colombier decref(&sdev->r);
12239ef1f84bSDavid du Colombier nexterror();
12249ef1f84bSDavid du Colombier }
12259ef1f84bSDavid du Colombier if(unit->state == Rawdata){
12269ef1f84bSDavid du Colombier unit->state = Rawstatus;
12279ef1f84bSDavid du Colombier i = sdrio(unit->req, a, n);
12289ef1f84bSDavid du Colombier }
12299ef1f84bSDavid du Colombier else if(unit->state == Rawstatus){
12309ef1f84bSDavid du Colombier status = unit->req->status;
12319ef1f84bSDavid du Colombier unit->state = Rawcmd;
12329ef1f84bSDavid du Colombier free(unit->req);
12339ef1f84bSDavid du Colombier unit->req = nil;
12349ef1f84bSDavid du Colombier i = readnum(0, a, n, status, NUMSIZE);
12359ef1f84bSDavid du Colombier } else
12369ef1f84bSDavid du Colombier i = 0;
12379ef1f84bSDavid du Colombier qunlock(&unit->raw);
12389ef1f84bSDavid du Colombier decref(&sdev->r);
12399ef1f84bSDavid du Colombier poperror();
12409ef1f84bSDavid du Colombier return i;
12419ef1f84bSDavid du Colombier
12429ef1f84bSDavid du Colombier case Qpart:
12439ef1f84bSDavid du Colombier return sdbio(c, 0, a, n, off);
12449ef1f84bSDavid du Colombier }
12459ef1f84bSDavid du Colombier }
12469ef1f84bSDavid du Colombier
12479ef1f84bSDavid du Colombier static void legacytopctl(Cmdbuf*);
12489ef1f84bSDavid du Colombier
12499ef1f84bSDavid du Colombier static long
sdwrite(Chan * c,void * a,long n,vlong off)12509ef1f84bSDavid du Colombier sdwrite(Chan* c, void* a, long n, vlong off)
12519ef1f84bSDavid du Colombier {
12529ef1f84bSDavid du Colombier char *f0;
12539ef1f84bSDavid du Colombier int i;
12549ef1f84bSDavid du Colombier uvlong end, start;
12559ef1f84bSDavid du Colombier Cmdbuf *cb;
12569ef1f84bSDavid du Colombier SDifc *ifc;
12579ef1f84bSDavid du Colombier SDreq *req;
12589ef1f84bSDavid du Colombier SDunit *unit;
12599ef1f84bSDavid du Colombier SDev *sdev;
12609ef1f84bSDavid du Colombier
12619ef1f84bSDavid du Colombier switch(TYPE(c->qid)){
12629ef1f84bSDavid du Colombier default:
12639ef1f84bSDavid du Colombier error(Eperm);
12649ef1f84bSDavid du Colombier case Qtopctl:
12659ef1f84bSDavid du Colombier cb = parsecmd(a, n);
12669ef1f84bSDavid du Colombier if(waserror()){
12679ef1f84bSDavid du Colombier free(cb);
12689ef1f84bSDavid du Colombier nexterror();
12699ef1f84bSDavid du Colombier }
12709ef1f84bSDavid du Colombier if(cb->nf == 0)
12719ef1f84bSDavid du Colombier error("empty control message");
12729ef1f84bSDavid du Colombier f0 = cb->f[0];
12739ef1f84bSDavid du Colombier cb->f++;
12749ef1f84bSDavid du Colombier cb->nf--;
12759ef1f84bSDavid du Colombier if(strcmp(f0, "config") == 0){
12769ef1f84bSDavid du Colombier /* wormhole into ugly legacy interface */
12779ef1f84bSDavid du Colombier legacytopctl(cb);
12789ef1f84bSDavid du Colombier poperror();
12799ef1f84bSDavid du Colombier free(cb);
12809ef1f84bSDavid du Colombier break;
12819ef1f84bSDavid du Colombier }
12829ef1f84bSDavid du Colombier /*
12839ef1f84bSDavid du Colombier * "ata arg..." invokes sdifc[i]->wtopctl(nil, cb),
12849ef1f84bSDavid du Colombier * where sdifc[i]->name=="ata" and cb contains the args.
12859ef1f84bSDavid du Colombier */
12869ef1f84bSDavid du Colombier ifc = nil;
12879ef1f84bSDavid du Colombier sdev = nil;
12889ef1f84bSDavid du Colombier for(i=0; sdifc[i]; i++){
12899ef1f84bSDavid du Colombier if(strcmp(sdifc[i]->name, f0) == 0){
12909ef1f84bSDavid du Colombier ifc = sdifc[i];
12919ef1f84bSDavid du Colombier sdev = nil;
12929ef1f84bSDavid du Colombier goto subtopctl;
12939ef1f84bSDavid du Colombier }
12949ef1f84bSDavid du Colombier }
12959ef1f84bSDavid du Colombier /*
12969ef1f84bSDavid du Colombier * "sd1 arg..." invokes sdifc[i]->wtopctl(sdev, cb),
12979ef1f84bSDavid du Colombier * where sdifc[i] and sdev match controller letter "1",
12989ef1f84bSDavid du Colombier * and cb contains the args.
12999ef1f84bSDavid du Colombier */
13009ef1f84bSDavid du Colombier if(f0[0]=='s' && f0[1]=='d' && f0[2] && f0[3] == 0){
13019ef1f84bSDavid du Colombier if((sdev = sdgetdev(f0[2])) != nil){
13029ef1f84bSDavid du Colombier ifc = sdev->ifc;
13039ef1f84bSDavid du Colombier goto subtopctl;
13049ef1f84bSDavid du Colombier }
13059ef1f84bSDavid du Colombier }
13069ef1f84bSDavid du Colombier error("unknown interface");
13079ef1f84bSDavid du Colombier
13089ef1f84bSDavid du Colombier subtopctl:
13099ef1f84bSDavid du Colombier if(waserror()){
13109ef1f84bSDavid du Colombier if(sdev)
13119ef1f84bSDavid du Colombier decref(&sdev->r);
13129ef1f84bSDavid du Colombier nexterror();
13139ef1f84bSDavid du Colombier }
13149ef1f84bSDavid du Colombier if(ifc->wtopctl)
13159ef1f84bSDavid du Colombier ifc->wtopctl(sdev, cb);
13169ef1f84bSDavid du Colombier else
13179ef1f84bSDavid du Colombier error(Ebadctl);
13189ef1f84bSDavid du Colombier poperror();
13199ef1f84bSDavid du Colombier poperror();
13209ef1f84bSDavid du Colombier if(sdev)
13219ef1f84bSDavid du Colombier decref(&sdev->r);
13229ef1f84bSDavid du Colombier free(cb);
13239ef1f84bSDavid du Colombier break;
13249ef1f84bSDavid du Colombier
13259ef1f84bSDavid du Colombier case Qctl:
13269ef1f84bSDavid du Colombier cb = parsecmd(a, n);
13279ef1f84bSDavid du Colombier sdev = sdgetdev(DEV(c->qid));
13289ef1f84bSDavid du Colombier if(sdev == nil)
13299ef1f84bSDavid du Colombier error(Enonexist);
13309ef1f84bSDavid du Colombier unit = sdev->unit[UNIT(c->qid)];
13319ef1f84bSDavid du Colombier
13329ef1f84bSDavid du Colombier qlock(&unit->ctl);
13339ef1f84bSDavid du Colombier if(waserror()){
13349ef1f84bSDavid du Colombier qunlock(&unit->ctl);
13359ef1f84bSDavid du Colombier decref(&sdev->r);
13369ef1f84bSDavid du Colombier free(cb);
13379ef1f84bSDavid du Colombier nexterror();
13389ef1f84bSDavid du Colombier }
13399ef1f84bSDavid du Colombier if(unit->vers != c->qid.vers)
13409ef1f84bSDavid du Colombier error(Echange);
13419ef1f84bSDavid du Colombier
13429ef1f84bSDavid du Colombier if(cb->nf < 1)
13439ef1f84bSDavid du Colombier error(Ebadctl);
13449ef1f84bSDavid du Colombier if(strcmp(cb->f[0], "part") == 0){
13459ef1f84bSDavid du Colombier if(cb->nf != 4)
13469ef1f84bSDavid du Colombier error(Ebadctl);
13479ef1f84bSDavid du Colombier if(unit->sectors == 0 && !sdinitpart(unit))
13489ef1f84bSDavid du Colombier error(Eio);
13499ef1f84bSDavid du Colombier start = strtoull(cb->f[2], 0, 0);
13509ef1f84bSDavid du Colombier end = strtoull(cb->f[3], 0, 0);
13519ef1f84bSDavid du Colombier sdaddpart(unit, cb->f[1], start, end);
13529ef1f84bSDavid du Colombier }
13539ef1f84bSDavid du Colombier else if(strcmp(cb->f[0], "delpart") == 0){
13549ef1f84bSDavid du Colombier if(cb->nf != 2 || unit->part == nil)
13559ef1f84bSDavid du Colombier error(Ebadctl);
13569ef1f84bSDavid du Colombier sddelpart(unit, cb->f[1]);
13579ef1f84bSDavid du Colombier }
13589ef1f84bSDavid du Colombier else if(unit->dev->ifc->wctl)
13599ef1f84bSDavid du Colombier unit->dev->ifc->wctl(unit, cb);
13609ef1f84bSDavid du Colombier else
13619ef1f84bSDavid du Colombier error(Ebadctl);
13629ef1f84bSDavid du Colombier qunlock(&unit->ctl);
13639ef1f84bSDavid du Colombier decref(&sdev->r);
13649ef1f84bSDavid du Colombier poperror();
13659ef1f84bSDavid du Colombier free(cb);
13669ef1f84bSDavid du Colombier break;
13679ef1f84bSDavid du Colombier
13689ef1f84bSDavid du Colombier case Qraw:
13699ef1f84bSDavid du Colombier sdev = sdgetdev(DEV(c->qid));
13709ef1f84bSDavid du Colombier if(sdev == nil)
13719ef1f84bSDavid du Colombier error(Enonexist);
13729ef1f84bSDavid du Colombier unit = sdev->unit[UNIT(c->qid)];
13739ef1f84bSDavid du Colombier qlock(&unit->raw);
13749ef1f84bSDavid du Colombier if(waserror()){
13759ef1f84bSDavid du Colombier qunlock(&unit->raw);
13769ef1f84bSDavid du Colombier decref(&sdev->r);
13779ef1f84bSDavid du Colombier nexterror();
13789ef1f84bSDavid du Colombier }
13799ef1f84bSDavid du Colombier switch(unit->state){
13809ef1f84bSDavid du Colombier case Rawcmd:
13819ef1f84bSDavid du Colombier if(n < 6 || n > sizeof(req->cmd))
13829ef1f84bSDavid du Colombier error(Ebadarg);
13839ef1f84bSDavid du Colombier if((req = malloc(sizeof(SDreq))) == nil)
13849ef1f84bSDavid du Colombier error(Enomem);
13859ef1f84bSDavid du Colombier req->unit = unit;
13869ef1f84bSDavid du Colombier memmove(req->cmd, a, n);
13879ef1f84bSDavid du Colombier req->clen = n;
13889ef1f84bSDavid du Colombier req->flags = SDnosense;
13899ef1f84bSDavid du Colombier req->status = ~0;
13909ef1f84bSDavid du Colombier
13919ef1f84bSDavid du Colombier unit->req = req;
13929ef1f84bSDavid du Colombier unit->state = Rawdata;
13939ef1f84bSDavid du Colombier break;
13949ef1f84bSDavid du Colombier
13959ef1f84bSDavid du Colombier case Rawstatus:
13969ef1f84bSDavid du Colombier unit->state = Rawcmd;
13979ef1f84bSDavid du Colombier free(unit->req);
13989ef1f84bSDavid du Colombier unit->req = nil;
13999ef1f84bSDavid du Colombier error(Ebadusefd);
14009ef1f84bSDavid du Colombier
14019ef1f84bSDavid du Colombier case Rawdata:
14029ef1f84bSDavid du Colombier unit->state = Rawstatus;
14039ef1f84bSDavid du Colombier unit->req->write = 1;
14049ef1f84bSDavid du Colombier n = sdrio(unit->req, a, n);
14059ef1f84bSDavid du Colombier }
14069ef1f84bSDavid du Colombier qunlock(&unit->raw);
14079ef1f84bSDavid du Colombier decref(&sdev->r);
14089ef1f84bSDavid du Colombier poperror();
14099ef1f84bSDavid du Colombier break;
14109ef1f84bSDavid du Colombier case Qpart:
14119ef1f84bSDavid du Colombier return sdbio(c, 1, a, n, off);
14129ef1f84bSDavid du Colombier }
14139ef1f84bSDavid du Colombier
14149ef1f84bSDavid du Colombier return n;
14159ef1f84bSDavid du Colombier }
14169ef1f84bSDavid du Colombier
14179ef1f84bSDavid du Colombier static long
sdwstat(Chan * c,uchar * dp,long n)14189ef1f84bSDavid du Colombier sdwstat(Chan* c, uchar* dp, long n)
14199ef1f84bSDavid du Colombier {
14209ef1f84bSDavid du Colombier Dir *d;
14219ef1f84bSDavid du Colombier SDpart *pp;
14229ef1f84bSDavid du Colombier SDperm *perm;
14239ef1f84bSDavid du Colombier SDunit *unit;
14249ef1f84bSDavid du Colombier SDev *sdev;
14259ef1f84bSDavid du Colombier
14269ef1f84bSDavid du Colombier if(c->qid.type & QTDIR)
14279ef1f84bSDavid du Colombier error(Eperm);
14289ef1f84bSDavid du Colombier
14299ef1f84bSDavid du Colombier sdev = sdgetdev(DEV(c->qid));
14309ef1f84bSDavid du Colombier if(sdev == nil)
14319ef1f84bSDavid du Colombier error(Enonexist);
14329ef1f84bSDavid du Colombier unit = sdev->unit[UNIT(c->qid)];
14339ef1f84bSDavid du Colombier qlock(&unit->ctl);
14349ef1f84bSDavid du Colombier d = nil;
14359ef1f84bSDavid du Colombier if(waserror()){
14369ef1f84bSDavid du Colombier free(d);
14379ef1f84bSDavid du Colombier qunlock(&unit->ctl);
14389ef1f84bSDavid du Colombier decref(&sdev->r);
14399ef1f84bSDavid du Colombier nexterror();
14409ef1f84bSDavid du Colombier }
14419ef1f84bSDavid du Colombier
14429ef1f84bSDavid du Colombier switch(TYPE(c->qid)){
14439ef1f84bSDavid du Colombier default:
14449ef1f84bSDavid du Colombier error(Eperm);
14459ef1f84bSDavid du Colombier case Qctl:
14469ef1f84bSDavid du Colombier perm = &unit->ctlperm;
14479ef1f84bSDavid du Colombier break;
14489ef1f84bSDavid du Colombier case Qraw:
14499ef1f84bSDavid du Colombier perm = &unit->rawperm;
14509ef1f84bSDavid du Colombier break;
14519ef1f84bSDavid du Colombier case Qpart:
14529ef1f84bSDavid du Colombier pp = &unit->part[PART(c->qid)];
14539ef1f84bSDavid du Colombier if(unit->vers+pp->vers != c->qid.vers)
14549ef1f84bSDavid du Colombier error(Enonexist);
14559ef1f84bSDavid du Colombier perm = &pp->SDperm;
14569ef1f84bSDavid du Colombier break;
14579ef1f84bSDavid du Colombier }
14589ef1f84bSDavid du Colombier
14599ef1f84bSDavid du Colombier if(strcmp(up->user, perm->user) && !iseve())
14609ef1f84bSDavid du Colombier error(Eperm);
14619ef1f84bSDavid du Colombier
14629ef1f84bSDavid du Colombier d = smalloc(sizeof(Dir)+n);
14639ef1f84bSDavid du Colombier n = convM2D(dp, n, &d[0], (char*)&d[1]);
14649ef1f84bSDavid du Colombier if(n == 0)
14659ef1f84bSDavid du Colombier error(Eshortstat);
14669ef1f84bSDavid du Colombier if(!emptystr(d[0].uid))
14679ef1f84bSDavid du Colombier kstrdup(&perm->user, d[0].uid);
14689ef1f84bSDavid du Colombier if(d[0].mode != ~0UL)
14699ef1f84bSDavid du Colombier perm->perm = (perm->perm & ~0777) | (d[0].mode & 0777);
14709ef1f84bSDavid du Colombier
14719ef1f84bSDavid du Colombier free(d);
14729ef1f84bSDavid du Colombier qunlock(&unit->ctl);
14739ef1f84bSDavid du Colombier decref(&sdev->r);
14749ef1f84bSDavid du Colombier poperror();
14759ef1f84bSDavid du Colombier return n;
14769ef1f84bSDavid du Colombier }
14779ef1f84bSDavid du Colombier
14789ef1f84bSDavid du Colombier static int
configure(char * spec,DevConf * cf)14799ef1f84bSDavid du Colombier configure(char* spec, DevConf* cf)
14809ef1f84bSDavid du Colombier {
14819ef1f84bSDavid du Colombier SDev *s, *sdev;
14829ef1f84bSDavid du Colombier char *p;
14839ef1f84bSDavid du Colombier int i;
14849ef1f84bSDavid du Colombier
14859ef1f84bSDavid du Colombier if(sdindex(*spec) < 0)
14869ef1f84bSDavid du Colombier error("bad sd spec");
14879ef1f84bSDavid du Colombier
14889ef1f84bSDavid du Colombier if((p = strchr(cf->type, '/')) != nil)
14899ef1f84bSDavid du Colombier *p++ = '\0';
14909ef1f84bSDavid du Colombier
14919ef1f84bSDavid du Colombier for(i = 0; sdifc[i] != nil; i++)
14929ef1f84bSDavid du Colombier if(strcmp(sdifc[i]->name, cf->type) == 0)
14939ef1f84bSDavid du Colombier break;
14949ef1f84bSDavid du Colombier if(sdifc[i] == nil)
14959ef1f84bSDavid du Colombier error("sd type not found");
14969ef1f84bSDavid du Colombier if(p)
14979ef1f84bSDavid du Colombier *(p-1) = '/';
14989ef1f84bSDavid du Colombier
14999ef1f84bSDavid du Colombier if(sdifc[i]->probe == nil)
15009ef1f84bSDavid du Colombier error("sd type cannot probe");
15019ef1f84bSDavid du Colombier
15029ef1f84bSDavid du Colombier sdev = sdifc[i]->probe(cf);
15039ef1f84bSDavid du Colombier for(s=sdev; s; s=s->next)
15049ef1f84bSDavid du Colombier s->idno = *spec;
15059ef1f84bSDavid du Colombier sdadddevs(sdev);
15069ef1f84bSDavid du Colombier return 0;
15079ef1f84bSDavid du Colombier }
15089ef1f84bSDavid du Colombier
15099ef1f84bSDavid du Colombier static int
unconfigure(char * spec)15109ef1f84bSDavid du Colombier unconfigure(char* spec)
15119ef1f84bSDavid du Colombier {
15129ef1f84bSDavid du Colombier int i;
15139ef1f84bSDavid du Colombier SDev *sdev;
15149ef1f84bSDavid du Colombier SDunit *unit;
15159ef1f84bSDavid du Colombier
15169ef1f84bSDavid du Colombier if((i = sdindex(*spec)) < 0)
15179ef1f84bSDavid du Colombier error(Enonexist);
15189ef1f84bSDavid du Colombier
15199ef1f84bSDavid du Colombier qlock(&devslock);
15209ef1f84bSDavid du Colombier if((sdev = devs[i]) == nil){
15219ef1f84bSDavid du Colombier qunlock(&devslock);
15229ef1f84bSDavid du Colombier error(Enonexist);
15239ef1f84bSDavid du Colombier }
15249ef1f84bSDavid du Colombier if(sdev->r.ref){
15259ef1f84bSDavid du Colombier qunlock(&devslock);
15269ef1f84bSDavid du Colombier error(Einuse);
15279ef1f84bSDavid du Colombier }
15289ef1f84bSDavid du Colombier devs[i] = nil;
15299ef1f84bSDavid du Colombier qunlock(&devslock);
15309ef1f84bSDavid du Colombier
15319ef1f84bSDavid du Colombier /* make sure no interrupts arrive anymore before removing resources */
15329ef1f84bSDavid du Colombier if(sdev->enabled && sdev->ifc->disable)
15339ef1f84bSDavid du Colombier sdev->ifc->disable(sdev);
15349ef1f84bSDavid du Colombier
15359ef1f84bSDavid du Colombier for(i = 0; i != sdev->nunit; i++){
15369ef1f84bSDavid du Colombier if(unit = sdev->unit[i]){
15379ef1f84bSDavid du Colombier free(unit->name);
15389ef1f84bSDavid du Colombier free(unit->user);
15399ef1f84bSDavid du Colombier free(unit);
15409ef1f84bSDavid du Colombier }
15419ef1f84bSDavid du Colombier }
15429ef1f84bSDavid du Colombier
15439ef1f84bSDavid du Colombier if(sdev->ifc->clear)
15449ef1f84bSDavid du Colombier sdev->ifc->clear(sdev);
15459ef1f84bSDavid du Colombier free(sdev);
15469ef1f84bSDavid du Colombier return 0;
15479ef1f84bSDavid du Colombier }
15489ef1f84bSDavid du Colombier
15499ef1f84bSDavid du Colombier static int
sdconfig(int on,char * spec,DevConf * cf)15509ef1f84bSDavid du Colombier sdconfig(int on, char* spec, DevConf* cf)
15519ef1f84bSDavid du Colombier {
15529ef1f84bSDavid du Colombier if(on)
15539ef1f84bSDavid du Colombier return configure(spec, cf);
15549ef1f84bSDavid du Colombier return unconfigure(spec);
15559ef1f84bSDavid du Colombier }
15569ef1f84bSDavid du Colombier
15579ef1f84bSDavid du Colombier Dev sddevtab = {
15589ef1f84bSDavid du Colombier 'S',
15599ef1f84bSDavid du Colombier "sd",
15609ef1f84bSDavid du Colombier
15619ef1f84bSDavid du Colombier sdreset,
15629ef1f84bSDavid du Colombier devinit,
15639ef1f84bSDavid du Colombier devshutdown,
15649ef1f84bSDavid du Colombier sdattach,
15659ef1f84bSDavid du Colombier sdwalk,
15669ef1f84bSDavid du Colombier sdstat,
15679ef1f84bSDavid du Colombier sdopen,
15689ef1f84bSDavid du Colombier devcreate,
15699ef1f84bSDavid du Colombier sdclose,
15709ef1f84bSDavid du Colombier sdread,
15719ef1f84bSDavid du Colombier devbread,
15729ef1f84bSDavid du Colombier sdwrite,
15739ef1f84bSDavid du Colombier devbwrite,
15749ef1f84bSDavid du Colombier devremove,
15759ef1f84bSDavid du Colombier sdwstat,
15769ef1f84bSDavid du Colombier devpower,
15779ef1f84bSDavid du Colombier sdconfig, /* probe; only called for pcmcia-like devices */
15789ef1f84bSDavid du Colombier };
15799ef1f84bSDavid du Colombier
15809ef1f84bSDavid du Colombier /*
15819ef1f84bSDavid du Colombier * This is wrong for so many reasons. This code must go.
15829ef1f84bSDavid du Colombier */
15839ef1f84bSDavid du Colombier typedef struct Confdata Confdata;
15849ef1f84bSDavid du Colombier struct Confdata {
15859ef1f84bSDavid du Colombier int on;
15869ef1f84bSDavid du Colombier char* spec;
15879ef1f84bSDavid du Colombier DevConf cf;
15889ef1f84bSDavid du Colombier };
15899ef1f84bSDavid du Colombier
15909ef1f84bSDavid du Colombier static void
parseswitch(Confdata * cd,char * option)15919ef1f84bSDavid du Colombier parseswitch(Confdata* cd, char* option)
15929ef1f84bSDavid du Colombier {
15939ef1f84bSDavid du Colombier if(!strcmp("on", option))
15949ef1f84bSDavid du Colombier cd->on = 1;
15959ef1f84bSDavid du Colombier else if(!strcmp("off", option))
15969ef1f84bSDavid du Colombier cd->on = 0;
15979ef1f84bSDavid du Colombier else
15989ef1f84bSDavid du Colombier error(Ebadarg);
15999ef1f84bSDavid du Colombier }
16009ef1f84bSDavid du Colombier
16019ef1f84bSDavid du Colombier static void
parsespec(Confdata * cd,char * option)16029ef1f84bSDavid du Colombier parsespec(Confdata* cd, char* option)
16039ef1f84bSDavid du Colombier {
16049ef1f84bSDavid du Colombier if(strlen(option) > 1)
16059ef1f84bSDavid du Colombier error(Ebadarg);
16069ef1f84bSDavid du Colombier cd->spec = option;
16079ef1f84bSDavid du Colombier }
16089ef1f84bSDavid du Colombier
16099ef1f84bSDavid du Colombier static Devport*
getnewport(DevConf * dc)16109ef1f84bSDavid du Colombier getnewport(DevConf* dc)
16119ef1f84bSDavid du Colombier {
16129ef1f84bSDavid du Colombier Devport *p;
16139ef1f84bSDavid du Colombier
16149ef1f84bSDavid du Colombier p = (Devport *)malloc((dc->nports + 1) * sizeof(Devport));
16159ef1f84bSDavid du Colombier if(p == nil)
16169ef1f84bSDavid du Colombier error(Enomem);
16179ef1f84bSDavid du Colombier if(dc->nports > 0){
16189ef1f84bSDavid du Colombier memmove(p, dc->ports, dc->nports * sizeof(Devport));
16199ef1f84bSDavid du Colombier free(dc->ports);
16209ef1f84bSDavid du Colombier }
16219ef1f84bSDavid du Colombier dc->ports = p;
16229ef1f84bSDavid du Colombier p = &dc->ports[dc->nports++];
16239ef1f84bSDavid du Colombier p->size = -1;
16249ef1f84bSDavid du Colombier p->port = (ulong)-1;
16259ef1f84bSDavid du Colombier return p;
16269ef1f84bSDavid du Colombier }
16279ef1f84bSDavid du Colombier
16289ef1f84bSDavid du Colombier static void
parseport(Confdata * cd,char * option)16299ef1f84bSDavid du Colombier parseport(Confdata* cd, char* option)
16309ef1f84bSDavid du Colombier {
16319ef1f84bSDavid du Colombier char *e;
16329ef1f84bSDavid du Colombier Devport *p;
16339ef1f84bSDavid du Colombier
16349ef1f84bSDavid du Colombier if(cd->cf.nports == 0 || cd->cf.ports[cd->cf.nports-1].port != (ulong)-1)
16359ef1f84bSDavid du Colombier p = getnewport(&cd->cf);
16369ef1f84bSDavid du Colombier else
16379ef1f84bSDavid du Colombier p = &cd->cf.ports[cd->cf.nports-1];
16389ef1f84bSDavid du Colombier p->port = strtol(option, &e, 0);
16399ef1f84bSDavid du Colombier if(e == nil || *e != '\0')
16409ef1f84bSDavid du Colombier error(Ebadarg);
16419ef1f84bSDavid du Colombier }
16429ef1f84bSDavid du Colombier
16439ef1f84bSDavid du Colombier static void
parsesize(Confdata * cd,char * option)16449ef1f84bSDavid du Colombier parsesize(Confdata* cd, char* option)
16459ef1f84bSDavid du Colombier {
16469ef1f84bSDavid du Colombier char *e;
16479ef1f84bSDavid du Colombier Devport *p;
16489ef1f84bSDavid du Colombier
16499ef1f84bSDavid du Colombier if(cd->cf.nports == 0 || cd->cf.ports[cd->cf.nports-1].size != -1)
16509ef1f84bSDavid du Colombier p = getnewport(&cd->cf);
16519ef1f84bSDavid du Colombier else
16529ef1f84bSDavid du Colombier p = &cd->cf.ports[cd->cf.nports-1];
16539ef1f84bSDavid du Colombier p->size = (int)strtol(option, &e, 0);
16549ef1f84bSDavid du Colombier if(e == nil || *e != '\0')
16559ef1f84bSDavid du Colombier error(Ebadarg);
16569ef1f84bSDavid du Colombier }
16579ef1f84bSDavid du Colombier
16589ef1f84bSDavid du Colombier static void
parseirq(Confdata * cd,char * option)16599ef1f84bSDavid du Colombier parseirq(Confdata* cd, char* option)
16609ef1f84bSDavid du Colombier {
16619ef1f84bSDavid du Colombier char *e;
16629ef1f84bSDavid du Colombier
16639ef1f84bSDavid du Colombier cd->cf.intnum = strtoul(option, &e, 0);
16649ef1f84bSDavid du Colombier if(e == nil || *e != '\0')
16659ef1f84bSDavid du Colombier error(Ebadarg);
16669ef1f84bSDavid du Colombier }
16679ef1f84bSDavid du Colombier
16689ef1f84bSDavid du Colombier static void
parsetype(Confdata * cd,char * option)16699ef1f84bSDavid du Colombier parsetype(Confdata* cd, char* option)
16709ef1f84bSDavid du Colombier {
16719ef1f84bSDavid du Colombier cd->cf.type = option;
16729ef1f84bSDavid du Colombier }
16739ef1f84bSDavid du Colombier
16749ef1f84bSDavid du Colombier static struct {
16759ef1f84bSDavid du Colombier char *name;
16769ef1f84bSDavid du Colombier void (*parse)(Confdata*, char*);
16779ef1f84bSDavid du Colombier } options[] = {
16789ef1f84bSDavid du Colombier "switch", parseswitch,
16799ef1f84bSDavid du Colombier "spec", parsespec,
16809ef1f84bSDavid du Colombier "port", parseport,
16819ef1f84bSDavid du Colombier "size", parsesize,
16829ef1f84bSDavid du Colombier "irq", parseirq,
16839ef1f84bSDavid du Colombier "type", parsetype,
16849ef1f84bSDavid du Colombier };
16859ef1f84bSDavid du Colombier
16869ef1f84bSDavid du Colombier static void
legacytopctl(Cmdbuf * cb)16879ef1f84bSDavid du Colombier legacytopctl(Cmdbuf *cb)
16889ef1f84bSDavid du Colombier {
16899ef1f84bSDavid du Colombier char *opt;
16909ef1f84bSDavid du Colombier int i, j;
16919ef1f84bSDavid du Colombier Confdata cd;
16929ef1f84bSDavid du Colombier
16939ef1f84bSDavid du Colombier memset(&cd, 0, sizeof cd);
16949ef1f84bSDavid du Colombier cd.on = -1;
16959ef1f84bSDavid du Colombier for(i=0; i<cb->nf; i+=2){
16969ef1f84bSDavid du Colombier if(i+2 > cb->nf)
16979ef1f84bSDavid du Colombier error(Ebadarg);
16989ef1f84bSDavid du Colombier opt = cb->f[i];
16999ef1f84bSDavid du Colombier for(j=0; j<nelem(options); j++)
17009ef1f84bSDavid du Colombier if(strcmp(opt, options[j].name) == 0){
17019ef1f84bSDavid du Colombier options[j].parse(&cd, cb->f[i+1]);
17029ef1f84bSDavid du Colombier break;
17039ef1f84bSDavid du Colombier }
17049ef1f84bSDavid du Colombier if(j == nelem(options))
17059ef1f84bSDavid du Colombier error(Ebadarg);
17069ef1f84bSDavid du Colombier }
17079ef1f84bSDavid du Colombier /* this has been rewritten to accomodate sdaoe */
17089ef1f84bSDavid du Colombier if(cd.on < 0 || cd.spec == 0)
17099ef1f84bSDavid du Colombier error(Ebadarg);
17109ef1f84bSDavid du Colombier if(cd.on && cd.cf.type == nil)
17119ef1f84bSDavid du Colombier error(Ebadarg);
17129ef1f84bSDavid du Colombier sdconfig(cd.on, cd.spec, &cd.cf);
17139ef1f84bSDavid du Colombier }
1714