17dd7cddfSDavid du Colombier /*
27dd7cddfSDavid du Colombier * Storage Device.
37dd7cddfSDavid du Colombier */
47dd7cddfSDavid du Colombier #include "u.h"
57dd7cddfSDavid du Colombier #include "../port/lib.h"
67dd7cddfSDavid du Colombier #include "mem.h"
77dd7cddfSDavid du Colombier #include "dat.h"
87dd7cddfSDavid du Colombier #include "fns.h"
97dd7cddfSDavid du Colombier #include "io.h"
107dd7cddfSDavid du Colombier #include "ureg.h"
117dd7cddfSDavid du Colombier #include "../port/error.h"
127dd7cddfSDavid du Colombier
1380ee5cbfSDavid du Colombier #include "../port/sd.h"
147dd7cddfSDavid du Colombier
157dd7cddfSDavid du Colombier extern Dev sddevtab;
167dd7cddfSDavid du Colombier extern SDifc* sdifc[];
177dd7cddfSDavid du Colombier
184de34a7eSDavid du Colombier static char devletters[] = "0123456789"
194de34a7eSDavid du Colombier "abcdefghijklmnopqrstuvwxyz"
204de34a7eSDavid du Colombier "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
214de34a7eSDavid du Colombier
224de34a7eSDavid du Colombier static SDev *devs[sizeof devletters-1];
234de34a7eSDavid du Colombier static QLock devslock;
247dd7cddfSDavid du Colombier
257dd7cddfSDavid du Colombier enum {
267dd7cddfSDavid du Colombier Rawcmd,
277dd7cddfSDavid du Colombier Rawdata,
287dd7cddfSDavid du Colombier Rawstatus,
297dd7cddfSDavid du Colombier };
307dd7cddfSDavid du Colombier
317dd7cddfSDavid du Colombier enum {
327dd7cddfSDavid du Colombier Qtopdir = 1, /* top level directory */
337dd7cddfSDavid du Colombier Qtopbase,
349a747e4fSDavid du Colombier Qtopctl = Qtopbase,
357dd7cddfSDavid du Colombier
367dd7cddfSDavid du Colombier Qunitdir, /* directory per unit */
377dd7cddfSDavid du Colombier Qunitbase,
387dd7cddfSDavid du Colombier Qctl = Qunitbase,
397dd7cddfSDavid du Colombier Qraw,
407dd7cddfSDavid du Colombier Qpart,
419a747e4fSDavid du Colombier
429a747e4fSDavid du Colombier TypeLOG = 4,
439a747e4fSDavid du Colombier NType = (1<<TypeLOG),
449a747e4fSDavid du Colombier TypeMASK = (NType-1),
459a747e4fSDavid du Colombier TypeSHIFT = 0,
469a747e4fSDavid du Colombier
479a747e4fSDavid du Colombier PartLOG = 8,
489a747e4fSDavid du Colombier NPart = (1<<PartLOG),
499a747e4fSDavid du Colombier PartMASK = (NPart-1),
509a747e4fSDavid du Colombier PartSHIFT = TypeLOG,
519a747e4fSDavid du Colombier
529a747e4fSDavid du Colombier UnitLOG = 8,
539a747e4fSDavid du Colombier NUnit = (1<<UnitLOG),
549a747e4fSDavid du Colombier UnitMASK = (NUnit-1),
559a747e4fSDavid du Colombier UnitSHIFT = (PartLOG+TypeLOG),
569a747e4fSDavid du Colombier
579a747e4fSDavid du Colombier DevLOG = 8,
589a747e4fSDavid du Colombier NDev = (1 << DevLOG),
599a747e4fSDavid du Colombier DevMASK = (NDev-1),
609a747e4fSDavid du Colombier DevSHIFT = (UnitLOG+PartLOG+TypeLOG),
619a747e4fSDavid du Colombier
629a747e4fSDavid du Colombier Ncmd = 20,
637dd7cddfSDavid du Colombier };
647dd7cddfSDavid du Colombier
659a747e4fSDavid du Colombier #define TYPE(q) ((((ulong)(q).path)>>TypeSHIFT) & TypeMASK)
669a747e4fSDavid du Colombier #define PART(q) ((((ulong)(q).path)>>PartSHIFT) & PartMASK)
679a747e4fSDavid du Colombier #define UNIT(q) ((((ulong)(q).path)>>UnitSHIFT) & UnitMASK)
689a747e4fSDavid du Colombier #define DEV(q) ((((ulong)(q).path)>>DevSHIFT) & DevMASK)
699a747e4fSDavid du Colombier #define QID(d,u, p, t) (((d)<<DevSHIFT)|((u)<<UnitSHIFT)|\
709a747e4fSDavid du Colombier ((p)<<PartSHIFT)|((t)<<TypeSHIFT))
719a747e4fSDavid du Colombier
727dd7cddfSDavid du Colombier
732210c76eSDavid du Colombier void
sdaddpart(SDunit * unit,char * name,uvlong start,uvlong end)7417629263SDavid du Colombier sdaddpart(SDunit* unit, char* name, uvlong start, uvlong end)
757dd7cddfSDavid du Colombier {
767dd7cddfSDavid du Colombier SDpart *pp;
777dd7cddfSDavid du Colombier int i, partno;
787dd7cddfSDavid du Colombier
797dd7cddfSDavid du Colombier /*
807dd7cddfSDavid du Colombier * Check name not already used
817dd7cddfSDavid du Colombier * and look for a free slot.
827dd7cddfSDavid du Colombier */
837dd7cddfSDavid du Colombier if(unit->part != nil){
847dd7cddfSDavid du Colombier partno = -1;
8559cc4ca5SDavid du Colombier for(i = 0; i < unit->npart; i++){
867dd7cddfSDavid du Colombier pp = &unit->part[i];
877dd7cddfSDavid du Colombier if(!pp->valid){
887dd7cddfSDavid du Colombier if(partno == -1)
897dd7cddfSDavid du Colombier partno = i;
907dd7cddfSDavid du Colombier break;
917dd7cddfSDavid du Colombier }
929a747e4fSDavid du Colombier if(strcmp(name, pp->name) == 0){
937dd7cddfSDavid du Colombier if(pp->start == start && pp->end == end)
947dd7cddfSDavid du Colombier return;
957dd7cddfSDavid du Colombier error(Ebadctl);
967dd7cddfSDavid du Colombier }
977dd7cddfSDavid du Colombier }
987dd7cddfSDavid du Colombier }
997dd7cddfSDavid du Colombier else{
1007dd7cddfSDavid du Colombier if((unit->part = malloc(sizeof(SDpart)*SDnpart)) == nil)
1017dd7cddfSDavid du Colombier error(Enomem);
10259cc4ca5SDavid du Colombier unit->npart = SDnpart;
1037dd7cddfSDavid du Colombier partno = 0;
1047dd7cddfSDavid du Colombier }
1057dd7cddfSDavid du Colombier
1067dd7cddfSDavid du Colombier /*
10759cc4ca5SDavid du Colombier * If no free slot found then increase the
10859cc4ca5SDavid du Colombier * array size (can't get here with unit->part == nil).
1097dd7cddfSDavid du Colombier */
11059cc4ca5SDavid du Colombier if(partno == -1){
1119a747e4fSDavid du Colombier if(unit->npart >= NPart)
1129a747e4fSDavid du Colombier error(Enomem);
11359cc4ca5SDavid du Colombier if((pp = malloc(sizeof(SDpart)*(unit->npart+SDnpart))) == nil)
11459cc4ca5SDavid du Colombier error(Enomem);
11559cc4ca5SDavid du Colombier memmove(pp, unit->part, sizeof(SDpart)*unit->npart);
11659cc4ca5SDavid du Colombier free(unit->part);
11759cc4ca5SDavid du Colombier unit->part = pp;
11859cc4ca5SDavid du Colombier partno = unit->npart;
11959cc4ca5SDavid du Colombier unit->npart += SDnpart;
12059cc4ca5SDavid du Colombier }
12159cc4ca5SDavid du Colombier
12259cc4ca5SDavid du Colombier /*
12359cc4ca5SDavid du Colombier * Check size and extent are valid.
12459cc4ca5SDavid du Colombier */
125223a736eSDavid du Colombier if(start > end || end > unit->sectors)
1267dd7cddfSDavid du Colombier error(Eio);
1277dd7cddfSDavid du Colombier pp = &unit->part[partno];
1287dd7cddfSDavid du Colombier pp->start = start;
1297dd7cddfSDavid du Colombier pp->end = end;
1309a747e4fSDavid du Colombier kstrdup(&pp->name, name);
1319a747e4fSDavid du Colombier kstrdup(&pp->user, eve);
1327dd7cddfSDavid du Colombier pp->perm = 0640;
1337dd7cddfSDavid du Colombier pp->valid = 1;
1347dd7cddfSDavid du Colombier }
1357dd7cddfSDavid du Colombier
1367dd7cddfSDavid du Colombier static void
sddelpart(SDunit * unit,char * name)1377dd7cddfSDavid du Colombier sddelpart(SDunit* unit, char* name)
1387dd7cddfSDavid du Colombier {
1397dd7cddfSDavid du Colombier int i;
1407dd7cddfSDavid du Colombier SDpart *pp;
1417dd7cddfSDavid du Colombier
1427dd7cddfSDavid du Colombier /*
1437dd7cddfSDavid du Colombier * Look for the partition to delete.
1447dd7cddfSDavid du Colombier * Can't delete if someone still has it open.
1457dd7cddfSDavid du Colombier */
1467dd7cddfSDavid du Colombier pp = unit->part;
14759cc4ca5SDavid du Colombier for(i = 0; i < unit->npart; i++){
1489a747e4fSDavid du Colombier if(strcmp(name, pp->name) == 0)
1497dd7cddfSDavid du Colombier break;
1507dd7cddfSDavid du Colombier pp++;
1517dd7cddfSDavid du Colombier }
15259cc4ca5SDavid du Colombier if(i >= unit->npart)
1537dd7cddfSDavid du Colombier error(Ebadctl);
1549a747e4fSDavid du Colombier if(strcmp(up->user, pp->user) && !iseve())
1559a747e4fSDavid du Colombier error(Eperm);
1567dd7cddfSDavid du Colombier pp->valid = 0;
157223a736eSDavid du Colombier pp->vers++;
1587dd7cddfSDavid du Colombier }
1597dd7cddfSDavid du Colombier
160d95be1c0SDavid du Colombier static void
sdincvers(SDunit * unit)161d95be1c0SDavid du Colombier sdincvers(SDunit *unit)
1627dd7cddfSDavid du Colombier {
163d95be1c0SDavid du Colombier int i;
1647dd7cddfSDavid du Colombier
165223a736eSDavid du Colombier unit->vers++;
1667dd7cddfSDavid du Colombier if(unit->part){
16759cc4ca5SDavid du Colombier for(i = 0; i < unit->npart; i++){
168223a736eSDavid du Colombier unit->part[i].valid = 0;
169223a736eSDavid du Colombier unit->part[i].vers++;
170223a736eSDavid du Colombier }
1717dd7cddfSDavid du Colombier }
172d95be1c0SDavid du Colombier }
173d95be1c0SDavid du Colombier
174d95be1c0SDavid du Colombier static int
sdinitpart(SDunit * unit)175d95be1c0SDavid du Colombier sdinitpart(SDunit* unit)
176d95be1c0SDavid du Colombier {
177d95be1c0SDavid du Colombier int nf;
17817629263SDavid du Colombier uvlong start, end;
179d95be1c0SDavid du Colombier char *f[4], *p, *q, buf[10];
180d95be1c0SDavid du Colombier
181d95be1c0SDavid du Colombier if(unit->sectors > 0){
182d95be1c0SDavid du Colombier unit->sectors = unit->secsize = 0;
183d95be1c0SDavid du Colombier sdincvers(unit);
184d95be1c0SDavid du Colombier }
1857dd7cddfSDavid du Colombier
18627522402SDavid du Colombier /* device must be connected or not; other values are trouble */
18727522402SDavid du Colombier if(unit->inquiry[0] & 0xC0) /* see SDinq0periphqual */
1887dd7cddfSDavid du Colombier return 0;
18927522402SDavid du Colombier switch(unit->inquiry[0] & SDinq0periphtype){
19027522402SDavid du Colombier case SDperdisk:
19127522402SDavid du Colombier case SDperworm:
19227522402SDavid du Colombier case SDpercd:
19327522402SDavid du Colombier case SDpermo:
1947dd7cddfSDavid du Colombier break;
1957dd7cddfSDavid du Colombier default:
1967dd7cddfSDavid du Colombier return 0;
1977dd7cddfSDavid du Colombier }
1987dd7cddfSDavid du Colombier
1997dd7cddfSDavid du Colombier if(unit->dev->ifc->online)
2007dd7cddfSDavid du Colombier unit->dev->ifc->online(unit);
2017dd7cddfSDavid du Colombier if(unit->sectors){
202d95be1c0SDavid du Colombier sdincvers(unit);
2037dd7cddfSDavid du Colombier sdaddpart(unit, "data", 0, unit->sectors);
2047dd7cddfSDavid du Colombier
2057dd7cddfSDavid du Colombier /*
2067dd7cddfSDavid du Colombier * Use partitions passed from boot program,
2077dd7cddfSDavid du Colombier * e.g.
2087dd7cddfSDavid du Colombier * sdC0part=dos 63 123123/plan9 123123 456456
2097dd7cddfSDavid du Colombier * This happens before /boot sets hostname so the
2107dd7cddfSDavid du Colombier * partitions will have the null-string for user.
2117dd7cddfSDavid du Colombier * The gen functions patch it up.
2127dd7cddfSDavid du Colombier */
2137dd7cddfSDavid du Colombier snprint(buf, sizeof buf, "%spart", unit->name);
2147dd7cddfSDavid du Colombier for(p = getconf(buf); p != nil; p = q){
2157dd7cddfSDavid du Colombier if(q = strchr(p, '/'))
2167dd7cddfSDavid du Colombier *q++ = '\0';
2179a747e4fSDavid du Colombier nf = tokenize(p, f, nelem(f));
2187dd7cddfSDavid du Colombier if(nf < 3)
2197dd7cddfSDavid du Colombier continue;
2207dd7cddfSDavid du Colombier
22117629263SDavid du Colombier start = strtoull(f[1], 0, 0);
22217629263SDavid du Colombier end = strtoull(f[2], 0, 0);
2237dd7cddfSDavid du Colombier if(!waserror()){
2247dd7cddfSDavid du Colombier sdaddpart(unit, f[0], start, end);
2257dd7cddfSDavid du Colombier poperror();
2267dd7cddfSDavid du Colombier }
2277dd7cddfSDavid du Colombier }
2287dd7cddfSDavid du Colombier }
2297dd7cddfSDavid du Colombier
2307dd7cddfSDavid du Colombier return 1;
2317dd7cddfSDavid du Colombier }
2327dd7cddfSDavid du Colombier
2334de34a7eSDavid du Colombier static int
sdindex(int idno)2344de34a7eSDavid du Colombier sdindex(int idno)
2354de34a7eSDavid du Colombier {
2364de34a7eSDavid du Colombier char *p;
2374de34a7eSDavid du Colombier
2384de34a7eSDavid du Colombier p = strchr(devletters, idno);
2394de34a7eSDavid du Colombier if(p == nil)
2404de34a7eSDavid du Colombier return -1;
2414de34a7eSDavid du Colombier return p-devletters;
2424de34a7eSDavid du Colombier }
2434de34a7eSDavid du Colombier
2449a747e4fSDavid du Colombier static SDev*
sdgetdev(int idno)2459a747e4fSDavid du Colombier sdgetdev(int idno)
2469a747e4fSDavid du Colombier {
2479a747e4fSDavid du Colombier SDev *sdev;
2489a747e4fSDavid du Colombier int i;
2499a747e4fSDavid du Colombier
2504de34a7eSDavid du Colombier if((i = sdindex(idno)) < 0)
2514de34a7eSDavid du Colombier return nil;
2529a747e4fSDavid du Colombier
2534de34a7eSDavid du Colombier qlock(&devslock);
2544de34a7eSDavid du Colombier if(sdev = devs[i])
2559a747e4fSDavid du Colombier incref(&sdev->r);
2569a747e4fSDavid du Colombier qunlock(&devslock);
2579a747e4fSDavid du Colombier return sdev;
2589a747e4fSDavid du Colombier }
2599a747e4fSDavid du Colombier
2607dd7cddfSDavid du Colombier static SDunit*
sdgetunit(SDev * sdev,int subno)2617dd7cddfSDavid du Colombier sdgetunit(SDev* sdev, int subno)
2627dd7cddfSDavid du Colombier {
2637dd7cddfSDavid du Colombier SDunit *unit;
2649a747e4fSDavid du Colombier char buf[32];
2657dd7cddfSDavid du Colombier
2667dd7cddfSDavid du Colombier /*
2677dd7cddfSDavid du Colombier * Associate a unit with a given device and sub-unit
2687dd7cddfSDavid du Colombier * number on that device.
2697dd7cddfSDavid du Colombier * The device will be probed if it has not already been
2707dd7cddfSDavid du Colombier * successfully accessed.
2717dd7cddfSDavid du Colombier */
2729a747e4fSDavid du Colombier qlock(&sdev->unitlock);
2739a747e4fSDavid du Colombier if(subno > sdev->nunit){
2749a747e4fSDavid du Colombier qunlock(&sdev->unitlock);
2759a747e4fSDavid du Colombier return nil;
2769a747e4fSDavid du Colombier }
2779a747e4fSDavid du Colombier
2789a747e4fSDavid du Colombier unit = sdev->unit[subno];
2797dd7cddfSDavid du Colombier if(unit == nil){
2807dd7cddfSDavid du Colombier /*
2817dd7cddfSDavid du Colombier * Probe the unit only once. This decision
2827dd7cddfSDavid du Colombier * may be a little severe and reviewed later.
2837dd7cddfSDavid du Colombier */
2849a747e4fSDavid du Colombier if(sdev->unitflg[subno]){
2859a747e4fSDavid du Colombier qunlock(&sdev->unitlock);
2867dd7cddfSDavid du Colombier return nil;
2877dd7cddfSDavid du Colombier }
2887dd7cddfSDavid du Colombier if((unit = malloc(sizeof(SDunit))) == nil){
2899a747e4fSDavid du Colombier qunlock(&sdev->unitlock);
2907dd7cddfSDavid du Colombier return nil;
2917dd7cddfSDavid du Colombier }
2929a747e4fSDavid du Colombier sdev->unitflg[subno] = 1;
2937dd7cddfSDavid du Colombier
2949a747e4fSDavid du Colombier snprint(buf, sizeof(buf), "%s%d", sdev->name, subno);
2959a747e4fSDavid du Colombier kstrdup(&unit->name, buf);
2969a747e4fSDavid du Colombier kstrdup(&unit->user, eve);
29759cc4ca5SDavid du Colombier unit->perm = 0555;
2987dd7cddfSDavid du Colombier unit->subno = subno;
2997dd7cddfSDavid du Colombier unit->dev = sdev;
3007dd7cddfSDavid du Colombier
301dc5a79c1SDavid du Colombier if(sdev->enabled == 0 && sdev->ifc->enable)
302dc5a79c1SDavid du Colombier sdev->ifc->enable(sdev);
303dc5a79c1SDavid du Colombier sdev->enabled = 1;
304dc5a79c1SDavid du Colombier
3057dd7cddfSDavid du Colombier /*
3067dd7cddfSDavid du Colombier * No need to lock anything here as this is only
3077dd7cddfSDavid du Colombier * called before the unit is made available in the
3087dd7cddfSDavid du Colombier * sdunit[] array.
3097dd7cddfSDavid du Colombier */
3107dd7cddfSDavid du Colombier if(unit->dev->ifc->verify(unit) == 0){
3119a747e4fSDavid du Colombier qunlock(&sdev->unitlock);
3127dd7cddfSDavid du Colombier free(unit);
3137dd7cddfSDavid du Colombier return nil;
3147dd7cddfSDavid du Colombier }
3159a747e4fSDavid du Colombier sdev->unit[subno] = unit;
3167dd7cddfSDavid du Colombier }
3179a747e4fSDavid du Colombier qunlock(&sdev->unitlock);
3187dd7cddfSDavid du Colombier return unit;
3197dd7cddfSDavid du Colombier }
3207dd7cddfSDavid du Colombier
3217dd7cddfSDavid du Colombier static void
sdreset(void)3227dd7cddfSDavid du Colombier sdreset(void)
3237dd7cddfSDavid du Colombier {
3247dd7cddfSDavid du Colombier int i;
3254de34a7eSDavid du Colombier SDev *sdev;
3267dd7cddfSDavid du Colombier
3277dd7cddfSDavid du Colombier /*
3284de34a7eSDavid du Colombier * Probe all known controller types and register any devices found.
3297dd7cddfSDavid du Colombier */
3307dd7cddfSDavid du Colombier for(i = 0; sdifc[i] != nil; i++){
3317dd7cddfSDavid du Colombier if(sdifc[i]->pnp == nil || (sdev = sdifc[i]->pnp()) == nil)
3327dd7cddfSDavid du Colombier continue;
3334de34a7eSDavid du Colombier sdadddevs(sdev);
3347dd7cddfSDavid du Colombier }
3357dd7cddfSDavid du Colombier }
3367dd7cddfSDavid du Colombier
3374de34a7eSDavid du Colombier void
sdadddevs(SDev * sdev)3384de34a7eSDavid du Colombier sdadddevs(SDev *sdev)
3394de34a7eSDavid du Colombier {
3404de34a7eSDavid du Colombier int i, j, id;
3414de34a7eSDavid du Colombier SDev *next;
3427dd7cddfSDavid du Colombier
3434de34a7eSDavid du Colombier for(; sdev; sdev=next){
3444de34a7eSDavid du Colombier next = sdev->next;
3454de34a7eSDavid du Colombier
3464de34a7eSDavid du Colombier sdev->unit = (SDunit**)malloc(sdev->nunit * sizeof(SDunit*));
3474de34a7eSDavid du Colombier sdev->unitflg = (int*)malloc(sdev->nunit * sizeof(int));
3484de34a7eSDavid du Colombier if(sdev->unit == nil || sdev->unitflg == nil){
3494de34a7eSDavid du Colombier print("sdadddevs: out of memory\n");
3504de34a7eSDavid du Colombier giveup:
3514de34a7eSDavid du Colombier free(sdev->unit);
3524de34a7eSDavid du Colombier free(sdev->unitflg);
3534de34a7eSDavid du Colombier if(sdev->ifc->clear)
3544de34a7eSDavid du Colombier sdev->ifc->clear(sdev);
3554de34a7eSDavid du Colombier free(sdev);
3564de34a7eSDavid du Colombier continue;
3577dd7cddfSDavid du Colombier }
3584de34a7eSDavid du Colombier id = sdindex(sdev->idno);
3594de34a7eSDavid du Colombier if(id == -1){
3604de34a7eSDavid du Colombier print("sdadddevs: bad id number %d (%C)\n", id, id);
3614de34a7eSDavid du Colombier goto giveup;
3624de34a7eSDavid du Colombier }
3634de34a7eSDavid du Colombier qlock(&devslock);
3644de34a7eSDavid du Colombier for(i=0; i<nelem(devs); i++){
3654de34a7eSDavid du Colombier if(devs[j = (id+i)%nelem(devs)] == nil){
3664de34a7eSDavid du Colombier sdev->idno = devletters[j];
3674de34a7eSDavid du Colombier devs[j] = sdev;
3684de34a7eSDavid du Colombier snprint(sdev->name, sizeof sdev->name, "sd%c", devletters[j]);
3694de34a7eSDavid du Colombier break;
3704de34a7eSDavid du Colombier }
3714de34a7eSDavid du Colombier }
3724de34a7eSDavid du Colombier qunlock(&devslock);
3734de34a7eSDavid du Colombier if(i == nelem(devs)){
3744de34a7eSDavid du Colombier print("sdadddevs: out of device letters\n");
3754de34a7eSDavid du Colombier goto giveup;
3764de34a7eSDavid du Colombier }
3779a747e4fSDavid du Colombier }
3787dd7cddfSDavid du Colombier }
3797dd7cddfSDavid du Colombier
38017629263SDavid du Colombier // void
38117629263SDavid du Colombier // sdrmdevs(SDev *sdev)
38217629263SDavid du Colombier // {
38317629263SDavid du Colombier // char buf[2];
38417629263SDavid du Colombier //
38517629263SDavid du Colombier // snprint(buf, sizeof buf, "%c", sdev->idno);
38617629263SDavid du Colombier // unconfigure(buf);
38717629263SDavid du Colombier // }
38817629263SDavid du Colombier
3892210c76eSDavid du Colombier void
sdaddallconfs(void (* addconf)(SDunit *))3902210c76eSDavid du Colombier sdaddallconfs(void (*addconf)(SDunit *))
3912210c76eSDavid du Colombier {
3922210c76eSDavid du Colombier int i, u;
3932210c76eSDavid du Colombier SDev *sdev;
3942210c76eSDavid du Colombier
3952210c76eSDavid du Colombier for(i = 0; i < nelem(devs); i++) /* each controller */
3962210c76eSDavid du Colombier for(sdev = devs[i]; sdev; sdev = sdev->next)
3972210c76eSDavid du Colombier for(u = 0; u < sdev->nunit; u++) /* each drive */
3982210c76eSDavid du Colombier (*addconf)(sdev->unit[u]);
3992210c76eSDavid du Colombier }
4002210c76eSDavid du Colombier
4017dd7cddfSDavid du Colombier static int
sd2gen(Chan * c,int i,Dir * dp)4027dd7cddfSDavid du Colombier sd2gen(Chan* c, int i, Dir* dp)
4037dd7cddfSDavid du Colombier {
4047dd7cddfSDavid du Colombier Qid q;
40517629263SDavid du Colombier uvlong l;
4067dd7cddfSDavid du Colombier SDpart *pp;
40759cc4ca5SDavid du Colombier SDperm *perm;
4087dd7cddfSDavid du Colombier SDunit *unit;
4099a747e4fSDavid du Colombier SDev *sdev;
4109a747e4fSDavid du Colombier int rv;
4117dd7cddfSDavid du Colombier
4129a747e4fSDavid du Colombier sdev = sdgetdev(DEV(c->qid));
4139a747e4fSDavid du Colombier assert(sdev);
4149a747e4fSDavid du Colombier unit = sdev->unit[UNIT(c->qid)];
4159a747e4fSDavid du Colombier
4169a747e4fSDavid du Colombier rv = -1;
4177dd7cddfSDavid du Colombier switch(i){
4187dd7cddfSDavid du Colombier case Qctl:
4199a747e4fSDavid du Colombier mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), PART(c->qid), Qctl),
4209a747e4fSDavid du Colombier unit->vers, QTFILE);
42159cc4ca5SDavid du Colombier perm = &unit->ctlperm;
4229a747e4fSDavid du Colombier if(emptystr(perm->user)){
4239a747e4fSDavid du Colombier kstrdup(&perm->user, eve);
42427522402SDavid du Colombier perm->perm = 0644; /* nothing secret in ctl */
42559cc4ca5SDavid du Colombier }
42659cc4ca5SDavid du Colombier devdir(c, q, "ctl", 0, perm->user, perm->perm, dp);
4279a747e4fSDavid du Colombier rv = 1;
4289a747e4fSDavid du Colombier break;
4299a747e4fSDavid du Colombier
4307dd7cddfSDavid du Colombier case Qraw:
4319a747e4fSDavid du Colombier mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), PART(c->qid), Qraw),
4329a747e4fSDavid du Colombier unit->vers, QTFILE);
43359cc4ca5SDavid du Colombier perm = &unit->rawperm;
4349a747e4fSDavid du Colombier if(emptystr(perm->user)){
4359a747e4fSDavid du Colombier kstrdup(&perm->user, eve);
4369a747e4fSDavid du Colombier perm->perm = DMEXCL|0600;
43759cc4ca5SDavid du Colombier }
43859cc4ca5SDavid du Colombier devdir(c, q, "raw", 0, perm->user, perm->perm, dp);
4399a747e4fSDavid du Colombier rv = 1;
4409a747e4fSDavid du Colombier break;
4419a747e4fSDavid du Colombier
4427dd7cddfSDavid du Colombier case Qpart:
4437dd7cddfSDavid du Colombier pp = &unit->part[PART(c->qid)];
44417629263SDavid du Colombier l = (pp->end - pp->start) * unit->secsize;
4459a747e4fSDavid du Colombier mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), PART(c->qid), Qpart),
4469a747e4fSDavid du Colombier unit->vers+pp->vers, QTFILE);
4479a747e4fSDavid du Colombier if(emptystr(pp->user))
4489a747e4fSDavid du Colombier kstrdup(&pp->user, eve);
4497dd7cddfSDavid du Colombier devdir(c, q, pp->name, l, pp->user, pp->perm, dp);
4509a747e4fSDavid du Colombier rv = 1;
4519a747e4fSDavid du Colombier break;
4529a747e4fSDavid du Colombier }
4539a747e4fSDavid du Colombier
4549a747e4fSDavid du Colombier decref(&sdev->r);
4559a747e4fSDavid du Colombier return rv;
4569a747e4fSDavid du Colombier }
4579a747e4fSDavid du Colombier
4589a747e4fSDavid du Colombier static int
sd1gen(Chan * c,int i,Dir * dp)4599a747e4fSDavid du Colombier sd1gen(Chan* c, int i, Dir* dp)
4609a747e4fSDavid du Colombier {
4619a747e4fSDavid du Colombier Qid q;
4629a747e4fSDavid du Colombier
4639a747e4fSDavid du Colombier switch(i){
4649a747e4fSDavid du Colombier case Qtopctl:
4659a747e4fSDavid du Colombier mkqid(&q, QID(0, 0, 0, Qtopctl), 0, QTFILE);
46627522402SDavid du Colombier devdir(c, q, "sdctl", 0, eve, 0644, dp); /* no secrets */
4679a747e4fSDavid du Colombier return 1;
4687dd7cddfSDavid du Colombier }
4697dd7cddfSDavid du Colombier return -1;
4707dd7cddfSDavid du Colombier }
4717dd7cddfSDavid du Colombier
4727dd7cddfSDavid du Colombier static int
sdgen(Chan * c,char *,Dirtab *,int,int s,Dir * dp)4739a747e4fSDavid du Colombier sdgen(Chan* c, char*, Dirtab*, int, int s, Dir* dp)
4747dd7cddfSDavid du Colombier {
4757dd7cddfSDavid du Colombier Qid q;
47617629263SDavid du Colombier uvlong l;
4777dd7cddfSDavid du Colombier int i, r;
4787dd7cddfSDavid du Colombier SDpart *pp;
4797dd7cddfSDavid du Colombier SDunit *unit;
4809a747e4fSDavid du Colombier SDev *sdev;
4817dd7cddfSDavid du Colombier
4827dd7cddfSDavid du Colombier switch(TYPE(c->qid)){
4837dd7cddfSDavid du Colombier case Qtopdir:
4847dd7cddfSDavid du Colombier if(s == DEVDOTDOT){
4853c917a9eSDavid du Colombier mkqid(&q, QID(0, 0, 0, Qtopdir), 0, QTDIR);
486*4e3613abSDavid du Colombier snprint(up->genbuf, sizeof up->genbuf, "#%C",
487*4e3613abSDavid du Colombier sddevtab.dc);
4889a747e4fSDavid du Colombier devdir(c, q, up->genbuf, 0, eve, 0555, dp);
4897dd7cddfSDavid du Colombier return 1;
4907dd7cddfSDavid du Colombier }
4919a747e4fSDavid du Colombier
4924de34a7eSDavid du Colombier if(s+Qtopbase < Qunitdir)
4939a747e4fSDavid du Colombier return sd1gen(c, s+Qtopbase, dp);
4944de34a7eSDavid du Colombier s -= (Qunitdir-Qtopbase);
4959a747e4fSDavid du Colombier
4969a747e4fSDavid du Colombier qlock(&devslock);
4974de34a7eSDavid du Colombier for(i=0; i<nelem(devs); i++){
4984de34a7eSDavid du Colombier if(devs[i]){
4994de34a7eSDavid du Colombier if(s < devs[i]->nunit)
5009a747e4fSDavid du Colombier break;
5014de34a7eSDavid du Colombier s -= devs[i]->nunit;
5024de34a7eSDavid du Colombier }
5039a747e4fSDavid du Colombier }
5049a747e4fSDavid du Colombier
5054de34a7eSDavid du Colombier if(i == nelem(devs)){
5064de34a7eSDavid du Colombier /* Run off the end of the list */
5079a747e4fSDavid du Colombier qunlock(&devslock);
5089a747e4fSDavid du Colombier return -1;
5099a747e4fSDavid du Colombier }
5109a747e4fSDavid du Colombier
5114de34a7eSDavid du Colombier if((sdev = devs[i]) == nil){
5129a747e4fSDavid du Colombier qunlock(&devslock);
5137dd7cddfSDavid du Colombier return 0;
51459cc4ca5SDavid du Colombier }
5159a747e4fSDavid du Colombier
5169a747e4fSDavid du Colombier incref(&sdev->r);
5179a747e4fSDavid du Colombier qunlock(&devslock);
5189a747e4fSDavid du Colombier
5199a747e4fSDavid du Colombier if((unit = sdev->unit[s]) == nil)
5209a747e4fSDavid du Colombier if((unit = sdgetunit(sdev, s)) == nil){
5219a747e4fSDavid du Colombier decref(&sdev->r);
5229a747e4fSDavid du Colombier return 0;
5237dd7cddfSDavid du Colombier }
5249a747e4fSDavid du Colombier
5259a747e4fSDavid du Colombier mkqid(&q, QID(sdev->idno, s, 0, Qunitdir), 0, QTDIR);
5269a747e4fSDavid du Colombier if(emptystr(unit->user))
5279a747e4fSDavid du Colombier kstrdup(&unit->user, eve);
5289a747e4fSDavid du Colombier devdir(c, q, unit->name, 0, unit->user, unit->perm, dp);
5299a747e4fSDavid du Colombier decref(&sdev->r);
5309a747e4fSDavid du Colombier return 1;
5319a747e4fSDavid du Colombier
5327dd7cddfSDavid du Colombier case Qunitdir:
5337dd7cddfSDavid du Colombier if(s == DEVDOTDOT){
5343c917a9eSDavid du Colombier mkqid(&q, QID(0, 0, 0, Qtopdir), 0, QTDIR);
535*4e3613abSDavid du Colombier snprint(up->genbuf, sizeof up->genbuf, "#%C",
536*4e3613abSDavid du Colombier sddevtab.dc);
5379a747e4fSDavid du Colombier devdir(c, q, up->genbuf, 0, eve, 0555, dp);
5387dd7cddfSDavid du Colombier return 1;
5397dd7cddfSDavid du Colombier }
5409a747e4fSDavid du Colombier
5419a747e4fSDavid du Colombier if((sdev = sdgetdev(DEV(c->qid))) == nil){
542ec46fab0SDavid du Colombier devdir(c, c->qid, "unavailable", 0, eve, 0, dp);
5439a747e4fSDavid du Colombier return 1;
5449a747e4fSDavid du Colombier }
5459a747e4fSDavid du Colombier
5469a747e4fSDavid du Colombier unit = sdev->unit[UNIT(c->qid)];
5477dd7cddfSDavid du Colombier qlock(&unit->ctl);
548223a736eSDavid du Colombier
549223a736eSDavid du Colombier /*
550223a736eSDavid du Colombier * Check for media change.
551223a736eSDavid du Colombier * If one has already been detected, sectors will be zero.
55259cc4ca5SDavid du Colombier * If there is one waiting to be detected, online
55359cc4ca5SDavid du Colombier * will return > 1.
554223a736eSDavid du Colombier * Online is a bit of a large hammer but does the job.
555223a736eSDavid du Colombier */
55659cc4ca5SDavid du Colombier if(unit->sectors == 0
55759cc4ca5SDavid du Colombier || (unit->dev->ifc->online && unit->dev->ifc->online(unit) > 1))
5587dd7cddfSDavid du Colombier sdinitpart(unit);
559223a736eSDavid du Colombier
5607dd7cddfSDavid du Colombier i = s+Qunitbase;
5617dd7cddfSDavid du Colombier if(i < Qpart){
5627dd7cddfSDavid du Colombier r = sd2gen(c, i, dp);
5637dd7cddfSDavid du Colombier qunlock(&unit->ctl);
5649a747e4fSDavid du Colombier decref(&sdev->r);
5657dd7cddfSDavid du Colombier return r;
5667dd7cddfSDavid du Colombier }
5677dd7cddfSDavid du Colombier i -= Qpart;
56859cc4ca5SDavid du Colombier if(unit->part == nil || i >= unit->npart){
5697dd7cddfSDavid du Colombier qunlock(&unit->ctl);
5709a747e4fSDavid du Colombier decref(&sdev->r);
5717dd7cddfSDavid du Colombier break;
5727dd7cddfSDavid du Colombier }
5737dd7cddfSDavid du Colombier pp = &unit->part[i];
574223a736eSDavid du Colombier if(!pp->valid){
5757dd7cddfSDavid du Colombier qunlock(&unit->ctl);
5769a747e4fSDavid du Colombier decref(&sdev->r);
5777dd7cddfSDavid du Colombier return 0;
5787dd7cddfSDavid du Colombier }
57917629263SDavid du Colombier l = (pp->end - pp->start) * unit->secsize;
5809a747e4fSDavid du Colombier mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), i, Qpart),
5819a747e4fSDavid du Colombier unit->vers+pp->vers, QTFILE);
5829a747e4fSDavid du Colombier if(emptystr(pp->user))
5839a747e4fSDavid du Colombier kstrdup(&pp->user, eve);
5847dd7cddfSDavid du Colombier devdir(c, q, pp->name, l, pp->user, pp->perm, dp);
5857dd7cddfSDavid du Colombier qunlock(&unit->ctl);
5869a747e4fSDavid du Colombier decref(&sdev->r);
5877dd7cddfSDavid du Colombier return 1;
5887dd7cddfSDavid du Colombier case Qraw:
5897dd7cddfSDavid du Colombier case Qctl:
5907dd7cddfSDavid du Colombier case Qpart:
5919a747e4fSDavid du Colombier if((sdev = sdgetdev(DEV(c->qid))) == nil){
5929a747e4fSDavid du Colombier devdir(c, q, "unavailable", 0, eve, 0, dp);
5939a747e4fSDavid du Colombier return 1;
5949a747e4fSDavid du Colombier }
5959a747e4fSDavid du Colombier unit = sdev->unit[UNIT(c->qid)];
5967dd7cddfSDavid du Colombier qlock(&unit->ctl);
5977dd7cddfSDavid du Colombier r = sd2gen(c, TYPE(c->qid), dp);
5987dd7cddfSDavid du Colombier qunlock(&unit->ctl);
5999a747e4fSDavid du Colombier decref(&sdev->r);
6007dd7cddfSDavid du Colombier return r;
6019a747e4fSDavid du Colombier case Qtopctl:
6029a747e4fSDavid du Colombier return sd1gen(c, TYPE(c->qid), dp);
6037dd7cddfSDavid du Colombier default:
6047dd7cddfSDavid du Colombier break;
6057dd7cddfSDavid du Colombier }
6067dd7cddfSDavid du Colombier
6077dd7cddfSDavid du Colombier return -1;
6087dd7cddfSDavid du Colombier }
6097dd7cddfSDavid du Colombier
6107dd7cddfSDavid du Colombier static Chan*
sdattach(char * spec)6117dd7cddfSDavid du Colombier sdattach(char* spec)
6127dd7cddfSDavid du Colombier {
6137dd7cddfSDavid du Colombier Chan *c;
6147dd7cddfSDavid du Colombier char *p;
6157dd7cddfSDavid du Colombier SDev *sdev;
6164de34a7eSDavid du Colombier int idno, subno;
6177dd7cddfSDavid du Colombier
6184de34a7eSDavid du Colombier if(*spec == '\0'){
6197dd7cddfSDavid du Colombier c = devattach(sddevtab.dc, spec);
6209a747e4fSDavid du Colombier mkqid(&c->qid, QID(0, 0, 0, Qtopdir), 0, QTDIR);
6217dd7cddfSDavid du Colombier return c;
6227dd7cddfSDavid du Colombier }
6237dd7cddfSDavid du Colombier
6247dd7cddfSDavid du Colombier if(spec[0] != 's' || spec[1] != 'd')
6257dd7cddfSDavid du Colombier error(Ebadspec);
6267dd7cddfSDavid du Colombier idno = spec[2];
6277dd7cddfSDavid du Colombier subno = strtol(&spec[3], &p, 0);
6287dd7cddfSDavid du Colombier if(p == &spec[3])
6297dd7cddfSDavid du Colombier error(Ebadspec);
6309a747e4fSDavid du Colombier
6314de34a7eSDavid du Colombier if((sdev=sdgetdev(idno)) == nil)
6324de34a7eSDavid du Colombier error(Enonexist);
6334de34a7eSDavid du Colombier if(sdgetunit(sdev, subno) == nil){
6344de34a7eSDavid du Colombier decref(&sdev->r);
6357dd7cddfSDavid du Colombier error(Enonexist);
6369a747e4fSDavid du Colombier }
6377dd7cddfSDavid du Colombier
6387dd7cddfSDavid du Colombier c = devattach(sddevtab.dc, spec);
6399a747e4fSDavid du Colombier mkqid(&c->qid, QID(sdev->idno, subno, 0, Qunitdir), 0, QTDIR);
6409a747e4fSDavid du Colombier c->dev = (sdev->idno << UnitLOG) + subno;
6419a747e4fSDavid du Colombier decref(&sdev->r);
6427dd7cddfSDavid du Colombier return c;
6437dd7cddfSDavid du Colombier }
6447dd7cddfSDavid du Colombier
6459a747e4fSDavid du Colombier static Walkqid*
sdwalk(Chan * c,Chan * nc,char ** name,int nname)6469a747e4fSDavid du Colombier sdwalk(Chan* c, Chan* nc, char** name, int nname)
6477dd7cddfSDavid du Colombier {
6489a747e4fSDavid du Colombier return devwalk(c, nc, name, nname, nil, 0, sdgen);
6497dd7cddfSDavid du Colombier }
6507dd7cddfSDavid du Colombier
6517dd7cddfSDavid du Colombier static int
sdstat(Chan * c,uchar * db,int n)6529a747e4fSDavid du Colombier sdstat(Chan* c, uchar* db, int n)
6537dd7cddfSDavid du Colombier {
6549a747e4fSDavid du Colombier return devstat(c, db, n, nil, 0, sdgen);
6557dd7cddfSDavid du Colombier }
6567dd7cddfSDavid du Colombier
6577dd7cddfSDavid du Colombier static Chan*
sdopen(Chan * c,int omode)6587dd7cddfSDavid du Colombier sdopen(Chan* c, int omode)
6597dd7cddfSDavid du Colombier {
6607dd7cddfSDavid du Colombier SDpart *pp;
6617dd7cddfSDavid du Colombier SDunit *unit;
6629a747e4fSDavid du Colombier SDev *sdev;
6639a747e4fSDavid du Colombier uchar tp;
6647dd7cddfSDavid du Colombier
6657dd7cddfSDavid du Colombier c = devopen(c, omode, 0, 0, sdgen);
6669a747e4fSDavid du Colombier if((tp = TYPE(c->qid)) != Qctl && tp != Qraw && tp != Qpart)
6679a747e4fSDavid du Colombier return c;
6689a747e4fSDavid du Colombier
6699a747e4fSDavid du Colombier sdev = sdgetdev(DEV(c->qid));
6709a747e4fSDavid du Colombier if(sdev == nil)
6719a747e4fSDavid du Colombier error(Enonexist);
6722cca75a1SDavid du Colombier
6739a747e4fSDavid du Colombier unit = sdev->unit[UNIT(c->qid)];
6749a747e4fSDavid du Colombier
6757dd7cddfSDavid du Colombier switch(TYPE(c->qid)){
676223a736eSDavid du Colombier case Qctl:
677223a736eSDavid du Colombier c->qid.vers = unit->vers;
678223a736eSDavid du Colombier break;
6797dd7cddfSDavid du Colombier case Qraw:
680223a736eSDavid du Colombier c->qid.vers = unit->vers;
6819a747e4fSDavid du Colombier if(tas(&unit->rawinuse) != 0){
6827dd7cddfSDavid du Colombier c->flag &= ~COPEN;
6832cca75a1SDavid du Colombier decref(&sdev->r);
6847dd7cddfSDavid du Colombier error(Einuse);
6857dd7cddfSDavid du Colombier }
6867dd7cddfSDavid du Colombier unit->state = Rawcmd;
6877dd7cddfSDavid du Colombier break;
6887dd7cddfSDavid du Colombier case Qpart:
6897dd7cddfSDavid du Colombier qlock(&unit->ctl);
6907dd7cddfSDavid du Colombier if(waserror()){
6917dd7cddfSDavid du Colombier qunlock(&unit->ctl);
6927dd7cddfSDavid du Colombier c->flag &= ~COPEN;
6932cca75a1SDavid du Colombier decref(&sdev->r);
6947dd7cddfSDavid du Colombier nexterror();
6957dd7cddfSDavid du Colombier }
6967dd7cddfSDavid du Colombier pp = &unit->part[PART(c->qid)];
697223a736eSDavid du Colombier c->qid.vers = unit->vers+pp->vers;
6987dd7cddfSDavid du Colombier qunlock(&unit->ctl);
6997dd7cddfSDavid du Colombier poperror();
7007dd7cddfSDavid du Colombier break;
7017dd7cddfSDavid du Colombier }
7029a747e4fSDavid du Colombier decref(&sdev->r);
7037dd7cddfSDavid du Colombier return c;
7047dd7cddfSDavid du Colombier }
7057dd7cddfSDavid du Colombier
7067dd7cddfSDavid du Colombier static void
sdclose(Chan * c)7077dd7cddfSDavid du Colombier sdclose(Chan* c)
7087dd7cddfSDavid du Colombier {
7097dd7cddfSDavid du Colombier SDunit *unit;
7109a747e4fSDavid du Colombier SDev *sdev;
7117dd7cddfSDavid du Colombier
7129a747e4fSDavid du Colombier if(c->qid.type & QTDIR)
7137dd7cddfSDavid du Colombier return;
7147dd7cddfSDavid du Colombier if(!(c->flag & COPEN))
7157dd7cddfSDavid du Colombier return;
7167dd7cddfSDavid du Colombier
7177dd7cddfSDavid du Colombier switch(TYPE(c->qid)){
7187dd7cddfSDavid du Colombier default:
7197dd7cddfSDavid du Colombier break;
7207dd7cddfSDavid du Colombier case Qraw:
7219a747e4fSDavid du Colombier sdev = sdgetdev(DEV(c->qid));
7229a747e4fSDavid du Colombier if(sdev){
7239a747e4fSDavid du Colombier unit = sdev->unit[UNIT(c->qid)];
7249a747e4fSDavid du Colombier unit->rawinuse = 0;
7259a747e4fSDavid du Colombier decref(&sdev->r);
7269a747e4fSDavid du Colombier }
7277dd7cddfSDavid du Colombier break;
7287dd7cddfSDavid du Colombier }
7297dd7cddfSDavid du Colombier }
7307dd7cddfSDavid du Colombier
7317dd7cddfSDavid du Colombier static long
sdbio(Chan * c,int write,char * a,long len,uvlong off)73217629263SDavid du Colombier sdbio(Chan* c, int write, char* a, long len, uvlong off)
7337dd7cddfSDavid du Colombier {
734223a736eSDavid du Colombier int nchange;
7357dd7cddfSDavid du Colombier long l;
7367dd7cddfSDavid du Colombier uchar *b;
7377dd7cddfSDavid du Colombier SDpart *pp;
7387dd7cddfSDavid du Colombier SDunit *unit;
7399a747e4fSDavid du Colombier SDev *sdev;
74017629263SDavid du Colombier ulong max, nb, offset;
74117629263SDavid du Colombier uvlong bno;
7427dd7cddfSDavid du Colombier
7439a747e4fSDavid du Colombier sdev = sdgetdev(DEV(c->qid));
7442cca75a1SDavid du Colombier if(sdev == nil){
7452cca75a1SDavid du Colombier decref(&sdev->r);
7469a747e4fSDavid du Colombier error(Enonexist);
7472cca75a1SDavid du Colombier }
7489a747e4fSDavid du Colombier unit = sdev->unit[UNIT(c->qid)];
7499a747e4fSDavid du Colombier if(unit == nil)
7509a747e4fSDavid du Colombier error(Enonexist);
7517dd7cddfSDavid du Colombier
752223a736eSDavid du Colombier nchange = 0;
7537dd7cddfSDavid du Colombier qlock(&unit->ctl);
754223a736eSDavid du Colombier while(waserror()){
755223a736eSDavid du Colombier /* notification of media change; go around again */
7569a747e4fSDavid du Colombier if(strcmp(up->errstr, Eio) == 0 && unit->sectors == 0 && nchange++ == 0){
757223a736eSDavid du Colombier sdinitpart(unit);
758223a736eSDavid du Colombier continue;
759223a736eSDavid du Colombier }
760223a736eSDavid du Colombier
761223a736eSDavid du Colombier /* other errors; give up */
7627dd7cddfSDavid du Colombier qunlock(&unit->ctl);
7639a747e4fSDavid du Colombier decref(&sdev->r);
7647dd7cddfSDavid du Colombier nexterror();
7657dd7cddfSDavid du Colombier }
766223a736eSDavid du Colombier pp = &unit->part[PART(c->qid)];
767223a736eSDavid du Colombier if(unit->vers+pp->vers != c->qid.vers)
7684de34a7eSDavid du Colombier error(Echange);
7697dd7cddfSDavid du Colombier
7707dd7cddfSDavid du Colombier /*
7717dd7cddfSDavid du Colombier * Check the request is within bounds.
7727dd7cddfSDavid du Colombier * Removeable drives are locked throughout the I/O
7737dd7cddfSDavid du Colombier * in case the media changes unexpectedly.
7747dd7cddfSDavid du Colombier * Non-removeable drives are not locked during the I/O
7757dd7cddfSDavid du Colombier * to allow the hardware to optimise if it can; this is
7767dd7cddfSDavid du Colombier * a little fast and loose.
7777dd7cddfSDavid du Colombier * It's assumed that non-removeable media parameters
7787dd7cddfSDavid du Colombier * (sectors, secsize) can't change once the drive has
7797dd7cddfSDavid du Colombier * been brought online.
7807dd7cddfSDavid du Colombier */
7817dd7cddfSDavid du Colombier bno = (off/unit->secsize) + pp->start;
7827dd7cddfSDavid du Colombier nb = ((off+len+unit->secsize-1)/unit->secsize) + pp->start - bno;
7837dd7cddfSDavid du Colombier max = SDmaxio/unit->secsize;
7847dd7cddfSDavid du Colombier if(nb > max)
7857dd7cddfSDavid du Colombier nb = max;
7867dd7cddfSDavid du Colombier if(bno+nb > pp->end)
7877dd7cddfSDavid du Colombier nb = pp->end - bno;
7887dd7cddfSDavid du Colombier if(bno >= pp->end || nb == 0){
7897dd7cddfSDavid du Colombier if(write)
7907dd7cddfSDavid du Colombier error(Eio);
7917dd7cddfSDavid du Colombier qunlock(&unit->ctl);
7929a747e4fSDavid du Colombier decref(&sdev->r);
7937dd7cddfSDavid du Colombier poperror();
7947dd7cddfSDavid du Colombier return 0;
7957dd7cddfSDavid du Colombier }
79627522402SDavid du Colombier if(!(unit->inquiry[1] & SDinq1removable)){
7977dd7cddfSDavid du Colombier qunlock(&unit->ctl);
7987dd7cddfSDavid du Colombier poperror();
7997dd7cddfSDavid du Colombier }
8007dd7cddfSDavid du Colombier
8017dd7cddfSDavid du Colombier b = sdmalloc(nb*unit->secsize);
8027dd7cddfSDavid du Colombier if(b == nil)
8037dd7cddfSDavid du Colombier error(Enomem);
8047dd7cddfSDavid du Colombier if(waserror()){
8057dd7cddfSDavid du Colombier sdfree(b);
80627522402SDavid du Colombier if(!(unit->inquiry[1] & SDinq1removable))
8079a747e4fSDavid du Colombier decref(&sdev->r); /* gadverdamme! */
8087dd7cddfSDavid du Colombier nexterror();
8097dd7cddfSDavid du Colombier }
8107dd7cddfSDavid du Colombier
8117dd7cddfSDavid du Colombier offset = off%unit->secsize;
8129a747e4fSDavid du Colombier if(offset+len > nb*unit->secsize)
8139a747e4fSDavid du Colombier len = nb*unit->secsize - offset;
8147dd7cddfSDavid du Colombier if(write){
8157dd7cddfSDavid du Colombier if(offset || (len%unit->secsize)){
8167dd7cddfSDavid du Colombier l = unit->dev->ifc->bio(unit, 0, 0, b, nb, bno);
8177dd7cddfSDavid du Colombier if(l < 0)
8187dd7cddfSDavid du Colombier error(Eio);
8197dd7cddfSDavid du Colombier if(l < (nb*unit->secsize)){
8207dd7cddfSDavid du Colombier nb = l/unit->secsize;
8217dd7cddfSDavid du Colombier l = nb*unit->secsize - offset;
8227dd7cddfSDavid du Colombier if(len > l)
8237dd7cddfSDavid du Colombier len = l;
8247dd7cddfSDavid du Colombier }
8257dd7cddfSDavid du Colombier }
8267dd7cddfSDavid du Colombier memmove(b+offset, a, len);
8277dd7cddfSDavid du Colombier l = unit->dev->ifc->bio(unit, 0, 1, b, nb, bno);
8287dd7cddfSDavid du Colombier if(l < 0)
8297dd7cddfSDavid du Colombier error(Eio);
8307dd7cddfSDavid du Colombier if(l < offset)
8317dd7cddfSDavid du Colombier len = 0;
8327dd7cddfSDavid du Colombier else if(len > l - offset)
8337dd7cddfSDavid du Colombier len = l - offset;
8347dd7cddfSDavid du Colombier }
8357dd7cddfSDavid du Colombier else{
8367dd7cddfSDavid du Colombier l = unit->dev->ifc->bio(unit, 0, 0, b, nb, bno);
8377dd7cddfSDavid du Colombier if(l < 0)
8387dd7cddfSDavid du Colombier error(Eio);
8397dd7cddfSDavid du Colombier if(l < offset)
8407dd7cddfSDavid du Colombier len = 0;
8417dd7cddfSDavid du Colombier else if(len > l - offset)
8427dd7cddfSDavid du Colombier len = l - offset;
8437dd7cddfSDavid du Colombier memmove(a, b+offset, len);
8447dd7cddfSDavid du Colombier }
8457dd7cddfSDavid du Colombier sdfree(b);
8467dd7cddfSDavid du Colombier poperror();
8477dd7cddfSDavid du Colombier
84827522402SDavid du Colombier if(unit->inquiry[1] & SDinq1removable){
8497dd7cddfSDavid du Colombier qunlock(&unit->ctl);
8507dd7cddfSDavid du Colombier poperror();
8517dd7cddfSDavid du Colombier }
8527dd7cddfSDavid du Colombier
8539a747e4fSDavid du Colombier decref(&sdev->r);
8547dd7cddfSDavid du Colombier return len;
8557dd7cddfSDavid du Colombier }
8567dd7cddfSDavid du Colombier
8577dd7cddfSDavid du Colombier static long
sdrio(SDreq * r,void * a,long n)8587dd7cddfSDavid du Colombier sdrio(SDreq* r, void* a, long n)
8597dd7cddfSDavid du Colombier {
8607dd7cddfSDavid du Colombier void *data;
8617dd7cddfSDavid du Colombier
8627dd7cddfSDavid du Colombier if(n >= SDmaxio || n < 0)
8637dd7cddfSDavid du Colombier error(Etoobig);
8647dd7cddfSDavid du Colombier
8657dd7cddfSDavid du Colombier data = nil;
8667dd7cddfSDavid du Colombier if(n){
8677dd7cddfSDavid du Colombier if((data = sdmalloc(n)) == nil)
8687dd7cddfSDavid du Colombier error(Enomem);
8697dd7cddfSDavid du Colombier if(r->write)
8707dd7cddfSDavid du Colombier memmove(data, a, n);
8717dd7cddfSDavid du Colombier }
8727dd7cddfSDavid du Colombier r->data = data;
8737dd7cddfSDavid du Colombier r->dlen = n;
8747dd7cddfSDavid du Colombier
8757dd7cddfSDavid du Colombier if(waserror()){
8767dd7cddfSDavid du Colombier sdfree(data);
8777dd7cddfSDavid du Colombier r->data = nil;
8787dd7cddfSDavid du Colombier nexterror();
8797dd7cddfSDavid du Colombier }
8807dd7cddfSDavid du Colombier
8817dd7cddfSDavid du Colombier if(r->unit->dev->ifc->rio(r) != SDok)
8827dd7cddfSDavid du Colombier error(Eio);
8837dd7cddfSDavid du Colombier
8847dd7cddfSDavid du Colombier if(!r->write && r->rlen > 0)
8857dd7cddfSDavid du Colombier memmove(a, data, r->rlen);
8867dd7cddfSDavid du Colombier sdfree(data);
8877dd7cddfSDavid du Colombier r->data = nil;
8887dd7cddfSDavid du Colombier poperror();
8897dd7cddfSDavid du Colombier
8907dd7cddfSDavid du Colombier return r->rlen;
8917dd7cddfSDavid du Colombier }
8927dd7cddfSDavid du Colombier
8934de34a7eSDavid du Colombier /*
8944de34a7eSDavid du Colombier * SCSI simulation for non-SCSI devices
8954de34a7eSDavid du Colombier */
8964de34a7eSDavid du Colombier int
sdsetsense(SDreq * r,int status,int key,int asc,int ascq)8974de34a7eSDavid du Colombier sdsetsense(SDreq *r, int status, int key, int asc, int ascq)
8984de34a7eSDavid du Colombier {
8994de34a7eSDavid du Colombier int len;
9004de34a7eSDavid du Colombier SDunit *unit;
9014de34a7eSDavid du Colombier
9024de34a7eSDavid du Colombier unit = r->unit;
9034de34a7eSDavid du Colombier unit->sense[2] = key;
9044de34a7eSDavid du Colombier unit->sense[12] = asc;
9054de34a7eSDavid du Colombier unit->sense[13] = ascq;
9064de34a7eSDavid du Colombier
9075e1edbcaSDavid du Colombier r->status = status;
9084de34a7eSDavid du Colombier if(status == SDcheck && !(r->flags & SDnosense)){
9094de34a7eSDavid du Colombier /* request sense case from sdfakescsi */
9104de34a7eSDavid du Colombier len = sizeof unit->sense;
9114de34a7eSDavid du Colombier if(len > sizeof r->sense-1)
9124de34a7eSDavid du Colombier len = sizeof r->sense-1;
9134de34a7eSDavid du Colombier memmove(r->sense, unit->sense, len);
9144de34a7eSDavid du Colombier unit->sense[2] = 0;
9154de34a7eSDavid du Colombier unit->sense[12] = 0;
9164de34a7eSDavid du Colombier unit->sense[13] = 0;
9174de34a7eSDavid du Colombier r->flags |= SDvalidsense;
9184de34a7eSDavid du Colombier return SDok;
9194de34a7eSDavid du Colombier }
9204de34a7eSDavid du Colombier return status;
9214de34a7eSDavid du Colombier }
9224de34a7eSDavid du Colombier
9234de34a7eSDavid du Colombier int
sdmodesense(SDreq * r,uchar * cmd,void * info,int ilen)9244de34a7eSDavid du Colombier sdmodesense(SDreq *r, uchar *cmd, void *info, int ilen)
9254de34a7eSDavid du Colombier {
9264de34a7eSDavid du Colombier int len;
9274de34a7eSDavid du Colombier uchar *data;
9284de34a7eSDavid du Colombier
9294de34a7eSDavid du Colombier /*
9304de34a7eSDavid du Colombier * Fake a vendor-specific request with page code 0,
9314de34a7eSDavid du Colombier * return the drive info.
9324de34a7eSDavid du Colombier */
9334de34a7eSDavid du Colombier if((cmd[2] & 0x3F) != 0 && (cmd[2] & 0x3F) != 0x3F)
9344de34a7eSDavid du Colombier return sdsetsense(r, SDcheck, 0x05, 0x24, 0);
9354de34a7eSDavid du Colombier len = (cmd[7]<<8)|cmd[8];
9364de34a7eSDavid du Colombier if(len == 0)
9374de34a7eSDavid du Colombier return SDok;
9384de34a7eSDavid du Colombier if(len < 8+ilen)
9394de34a7eSDavid du Colombier return sdsetsense(r, SDcheck, 0x05, 0x1A, 0);
9404de34a7eSDavid du Colombier if(r->data == nil || r->dlen < len)
9414de34a7eSDavid du Colombier return sdsetsense(r, SDcheck, 0x05, 0x20, 1);
9424de34a7eSDavid du Colombier data = r->data;
9434de34a7eSDavid du Colombier memset(data, 0, 8);
9444de34a7eSDavid du Colombier data[0] = ilen>>8;
9454de34a7eSDavid du Colombier data[1] = ilen;
9464de34a7eSDavid du Colombier if(ilen)
9474de34a7eSDavid du Colombier memmove(data+8, info, ilen);
9484de34a7eSDavid du Colombier r->rlen = 8+ilen;
9494de34a7eSDavid du Colombier return sdsetsense(r, SDok, 0, 0, 0);
9504de34a7eSDavid du Colombier }
9514de34a7eSDavid du Colombier
9524de34a7eSDavid du Colombier int
sdfakescsi(SDreq * r,void * info,int ilen)9534de34a7eSDavid du Colombier sdfakescsi(SDreq *r, void *info, int ilen)
9544de34a7eSDavid du Colombier {
9554de34a7eSDavid du Colombier uchar *cmd, *p;
9564de34a7eSDavid du Colombier uvlong len;
9574de34a7eSDavid du Colombier SDunit *unit;
9584de34a7eSDavid du Colombier
9594de34a7eSDavid du Colombier cmd = r->cmd;
9604de34a7eSDavid du Colombier r->rlen = 0;
9614de34a7eSDavid du Colombier unit = r->unit;
9624de34a7eSDavid du Colombier
9634de34a7eSDavid du Colombier /*
9644de34a7eSDavid du Colombier * Rewrite read(6)/write(6) into read(10)/write(10).
9654de34a7eSDavid du Colombier */
9664de34a7eSDavid du Colombier switch(cmd[0]){
9674de34a7eSDavid du Colombier case 0x08: /* read */
9684de34a7eSDavid du Colombier case 0x0A: /* write */
9694de34a7eSDavid du Colombier cmd[9] = 0;
9704de34a7eSDavid du Colombier cmd[8] = cmd[4];
9714de34a7eSDavid du Colombier cmd[7] = 0;
9724de34a7eSDavid du Colombier cmd[6] = 0;
9734de34a7eSDavid du Colombier cmd[5] = cmd[3];
9744de34a7eSDavid du Colombier cmd[4] = cmd[2];
9754de34a7eSDavid du Colombier cmd[3] = cmd[1] & 0x0F;
9764de34a7eSDavid du Colombier cmd[2] = 0;
9774de34a7eSDavid du Colombier cmd[1] &= 0xE0;
9784de34a7eSDavid du Colombier cmd[0] |= 0x20;
9794de34a7eSDavid du Colombier break;
9804de34a7eSDavid du Colombier }
9814de34a7eSDavid du Colombier
9824de34a7eSDavid du Colombier /*
9834de34a7eSDavid du Colombier * Map SCSI commands into ATA commands for discs.
9844de34a7eSDavid du Colombier * Fail any command with a LUN except INQUIRY which
9854de34a7eSDavid du Colombier * will return 'logical unit not supported'.
9864de34a7eSDavid du Colombier */
9874de34a7eSDavid du Colombier if((cmd[1]>>5) && cmd[0] != 0x12)
9884de34a7eSDavid du Colombier return sdsetsense(r, SDcheck, 0x05, 0x25, 0);
9894de34a7eSDavid du Colombier
9904de34a7eSDavid du Colombier switch(cmd[0]){
9914de34a7eSDavid du Colombier default:
9924de34a7eSDavid du Colombier return sdsetsense(r, SDcheck, 0x05, 0x20, 0);
9934de34a7eSDavid du Colombier
9944de34a7eSDavid du Colombier case 0x00: /* test unit ready */
9954de34a7eSDavid du Colombier return sdsetsense(r, SDok, 0, 0, 0);
9964de34a7eSDavid du Colombier
9974de34a7eSDavid du Colombier case 0x03: /* request sense */
9984de34a7eSDavid du Colombier if(cmd[4] < sizeof unit->sense)
9994de34a7eSDavid du Colombier len = cmd[4];
10004de34a7eSDavid du Colombier else
10014de34a7eSDavid du Colombier len = sizeof unit->sense;
10024de34a7eSDavid du Colombier if(r->data && r->dlen >= len){
10034de34a7eSDavid du Colombier memmove(r->data, unit->sense, len);
10044de34a7eSDavid du Colombier r->rlen = len;
10054de34a7eSDavid du Colombier }
10064de34a7eSDavid du Colombier return sdsetsense(r, SDok, 0, 0, 0);
10074de34a7eSDavid du Colombier
10084de34a7eSDavid du Colombier case 0x12: /* inquiry */
10094de34a7eSDavid du Colombier if(cmd[4] < sizeof unit->inquiry)
10104de34a7eSDavid du Colombier len = cmd[4];
10114de34a7eSDavid du Colombier else
10124de34a7eSDavid du Colombier len = sizeof unit->inquiry;
10134de34a7eSDavid du Colombier if(r->data && r->dlen >= len){
1014d95be1c0SDavid du Colombier memmove(r->data, unit->inquiry, len);
10154de34a7eSDavid du Colombier r->rlen = len;
10164de34a7eSDavid du Colombier }
10174de34a7eSDavid du Colombier return sdsetsense(r, SDok, 0, 0, 0);
10184de34a7eSDavid du Colombier
10194de34a7eSDavid du Colombier case 0x1B: /* start/stop unit */
10204de34a7eSDavid du Colombier /*
10214de34a7eSDavid du Colombier * nop for now, can use power management later.
10224de34a7eSDavid du Colombier */
10234de34a7eSDavid du Colombier return sdsetsense(r, SDok, 0, 0, 0);
10244de34a7eSDavid du Colombier
10254de34a7eSDavid du Colombier case 0x25: /* read capacity */
10264de34a7eSDavid du Colombier if((cmd[1] & 0x01) || cmd[2] || cmd[3])
10274de34a7eSDavid du Colombier return sdsetsense(r, SDcheck, 0x05, 0x24, 0);
10284de34a7eSDavid du Colombier if(r->data == nil || r->dlen < 8)
10294de34a7eSDavid du Colombier return sdsetsense(r, SDcheck, 0x05, 0x20, 1);
10304de34a7eSDavid du Colombier
10314de34a7eSDavid du Colombier /*
10324de34a7eSDavid du Colombier * Read capacity returns the LBA of the last sector.
10334de34a7eSDavid du Colombier */
10344de34a7eSDavid du Colombier len = unit->sectors - 1;
10354de34a7eSDavid du Colombier p = r->data;
10364de34a7eSDavid du Colombier *p++ = len>>24;
10374de34a7eSDavid du Colombier *p++ = len>>16;
10384de34a7eSDavid du Colombier *p++ = len>>8;
10394de34a7eSDavid du Colombier *p++ = len;
10404de34a7eSDavid du Colombier len = 512;
10414de34a7eSDavid du Colombier *p++ = len>>24;
10424de34a7eSDavid du Colombier *p++ = len>>16;
10434de34a7eSDavid du Colombier *p++ = len>>8;
10444de34a7eSDavid du Colombier *p++ = len;
10454de34a7eSDavid du Colombier r->rlen = p - (uchar*)r->data;
10464de34a7eSDavid du Colombier return sdsetsense(r, SDok, 0, 0, 0);
10474de34a7eSDavid du Colombier
10484de34a7eSDavid du Colombier case 0x9E: /* long read capacity */
10494de34a7eSDavid du Colombier if((cmd[1] & 0x01) || cmd[2] || cmd[3])
10504de34a7eSDavid du Colombier return sdsetsense(r, SDcheck, 0x05, 0x24, 0);
10514de34a7eSDavid du Colombier if(r->data == nil || r->dlen < 8)
10524de34a7eSDavid du Colombier return sdsetsense(r, SDcheck, 0x05, 0x20, 1);
10534de34a7eSDavid du Colombier /*
10544de34a7eSDavid du Colombier * Read capcity returns the LBA of the last sector.
10554de34a7eSDavid du Colombier */
10564de34a7eSDavid du Colombier len = unit->sectors - 1;
10574de34a7eSDavid du Colombier p = r->data;
10584de34a7eSDavid du Colombier *p++ = len>>56;
10594de34a7eSDavid du Colombier *p++ = len>>48;
10604de34a7eSDavid du Colombier *p++ = len>>40;
10614de34a7eSDavid du Colombier *p++ = len>>32;
10624de34a7eSDavid du Colombier *p++ = len>>24;
10634de34a7eSDavid du Colombier *p++ = len>>16;
10644de34a7eSDavid du Colombier *p++ = len>>8;
10654de34a7eSDavid du Colombier *p++ = len;
10664de34a7eSDavid du Colombier len = 512;
10674de34a7eSDavid du Colombier *p++ = len>>24;
10684de34a7eSDavid du Colombier *p++ = len>>16;
10694de34a7eSDavid du Colombier *p++ = len>>8;
10704de34a7eSDavid du Colombier *p++ = len;
10714de34a7eSDavid du Colombier r->rlen = p - (uchar*)r->data;
10724de34a7eSDavid du Colombier return sdsetsense(r, SDok, 0, 0, 0);
10734de34a7eSDavid du Colombier
10744de34a7eSDavid du Colombier case 0x5A: /* mode sense */
10754de34a7eSDavid du Colombier return sdmodesense(r, cmd, info, ilen);
10764de34a7eSDavid du Colombier
10774de34a7eSDavid du Colombier case 0x28: /* read */
10784de34a7eSDavid du Colombier case 0x2A: /* write */
107917629263SDavid du Colombier case 0x88: /* read16 */
108017629263SDavid du Colombier case 0x8a: /* write16 */
10814de34a7eSDavid du Colombier return SDnostatus;
10824de34a7eSDavid du Colombier }
10834de34a7eSDavid du Colombier }
10844de34a7eSDavid du Colombier
10857dd7cddfSDavid du Colombier static long
sdread(Chan * c,void * a,long n,vlong off)10867dd7cddfSDavid du Colombier sdread(Chan *c, void *a, long n, vlong off)
10877dd7cddfSDavid du Colombier {
10889a747e4fSDavid du Colombier char *p, *e, *buf;
10897dd7cddfSDavid du Colombier SDpart *pp;
10907dd7cddfSDavid du Colombier SDunit *unit;
10919a747e4fSDavid du Colombier SDev *sdev;
10927dd7cddfSDavid du Colombier ulong offset;
10934de34a7eSDavid du Colombier int i, l, m, status;
10947dd7cddfSDavid du Colombier
10957dd7cddfSDavid du Colombier offset = off;
10967dd7cddfSDavid du Colombier switch(TYPE(c->qid)){
10977dd7cddfSDavid du Colombier default:
10987dd7cddfSDavid du Colombier error(Eperm);
10994de34a7eSDavid du Colombier case Qtopctl:
11004de34a7eSDavid du Colombier m = 64*1024; /* room for register dumps */
11014de34a7eSDavid du Colombier p = buf = malloc(m);
1102aa72973aSDavid du Colombier if(p == nil)
1103aa72973aSDavid du Colombier error(Enomem);
11044de34a7eSDavid du Colombier e = p + m;
11059a747e4fSDavid du Colombier qlock(&devslock);
11064de34a7eSDavid du Colombier for(i = 0; i < nelem(devs); i++){
11074de34a7eSDavid du Colombier sdev = devs[i];
11084de34a7eSDavid du Colombier if(sdev && sdev->ifc->rtopctl)
11094de34a7eSDavid du Colombier p = sdev->ifc->rtopctl(sdev, p, e);
11109a747e4fSDavid du Colombier }
11119a747e4fSDavid du Colombier qunlock(&devslock);
11129a747e4fSDavid du Colombier n = readstr(off, a, n, buf);
11139a747e4fSDavid du Colombier free(buf);
11149a747e4fSDavid du Colombier return n;
11159a747e4fSDavid du Colombier
11167dd7cddfSDavid du Colombier case Qtopdir:
11177dd7cddfSDavid du Colombier case Qunitdir:
11187dd7cddfSDavid du Colombier return devdirread(c, a, n, 0, 0, sdgen);
11199a747e4fSDavid du Colombier
11207dd7cddfSDavid du Colombier case Qctl:
11219a747e4fSDavid du Colombier sdev = sdgetdev(DEV(c->qid));
11229a747e4fSDavid du Colombier if(sdev == nil)
11239a747e4fSDavid du Colombier error(Enonexist);
11249a747e4fSDavid du Colombier
11259a747e4fSDavid du Colombier unit = sdev->unit[UNIT(c->qid)];
11264de34a7eSDavid du Colombier m = 16*1024; /* room for register dumps */
11274de34a7eSDavid du Colombier p = malloc(m);
1128aa72973aSDavid du Colombier if(p == nil)
1129aa72973aSDavid du Colombier error(Enomem);
11304de34a7eSDavid du Colombier l = snprint(p, m, "inquiry %.48s\n",
11317dd7cddfSDavid du Colombier (char*)unit->inquiry+8);
11327dd7cddfSDavid du Colombier qlock(&unit->ctl);
11337dd7cddfSDavid du Colombier /*
11347dd7cddfSDavid du Colombier * If there's a device specific routine it must
11357dd7cddfSDavid du Colombier * provide all information pertaining to night geometry
11367dd7cddfSDavid du Colombier * and the garscadden trains.
11377dd7cddfSDavid du Colombier */
11387dd7cddfSDavid du Colombier if(unit->dev->ifc->rctl)
11394de34a7eSDavid du Colombier l += unit->dev->ifc->rctl(unit, p+l, m-l);
1140223a736eSDavid du Colombier if(unit->sectors == 0)
1141223a736eSDavid du Colombier sdinitpart(unit);
1142223a736eSDavid du Colombier if(unit->sectors){
11437dd7cddfSDavid du Colombier if(unit->dev->ifc->rctl == nil)
11444de34a7eSDavid du Colombier l += snprint(p+l, m-l,
114517629263SDavid du Colombier "geometry %llud %lud\n",
11467dd7cddfSDavid du Colombier unit->sectors, unit->secsize);
11477dd7cddfSDavid du Colombier pp = unit->part;
114859cc4ca5SDavid du Colombier for(i = 0; i < unit->npart; i++){
11497dd7cddfSDavid du Colombier if(pp->valid)
11504de34a7eSDavid du Colombier l += snprint(p+l, m-l,
115117629263SDavid du Colombier "part %s %llud %llud\n",
11529a747e4fSDavid du Colombier pp->name, pp->start, pp->end);
11537dd7cddfSDavid du Colombier pp++;
11547dd7cddfSDavid du Colombier }
11557dd7cddfSDavid du Colombier }
11567dd7cddfSDavid du Colombier qunlock(&unit->ctl);
11579a747e4fSDavid du Colombier decref(&sdev->r);
11587dd7cddfSDavid du Colombier l = readstr(offset, a, n, p);
11597dd7cddfSDavid du Colombier free(p);
11607dd7cddfSDavid du Colombier return l;
11619a747e4fSDavid du Colombier
11627dd7cddfSDavid du Colombier case Qraw:
11639a747e4fSDavid du Colombier sdev = sdgetdev(DEV(c->qid));
11649a747e4fSDavid du Colombier if(sdev == nil)
11659a747e4fSDavid du Colombier error(Enonexist);
11669a747e4fSDavid du Colombier
11679a747e4fSDavid du Colombier unit = sdev->unit[UNIT(c->qid)];
116880ee5cbfSDavid du Colombier qlock(&unit->raw);
116980ee5cbfSDavid du Colombier if(waserror()){
117080ee5cbfSDavid du Colombier qunlock(&unit->raw);
11719a747e4fSDavid du Colombier decref(&sdev->r);
117280ee5cbfSDavid du Colombier nexterror();
117380ee5cbfSDavid du Colombier }
11747dd7cddfSDavid du Colombier if(unit->state == Rawdata){
11757dd7cddfSDavid du Colombier unit->state = Rawstatus;
117680ee5cbfSDavid du Colombier i = sdrio(unit->req, a, n);
11777dd7cddfSDavid du Colombier }
11787dd7cddfSDavid du Colombier else if(unit->state == Rawstatus){
11797dd7cddfSDavid du Colombier status = unit->req->status;
11807dd7cddfSDavid du Colombier unit->state = Rawcmd;
11817dd7cddfSDavid du Colombier free(unit->req);
11827dd7cddfSDavid du Colombier unit->req = nil;
118380ee5cbfSDavid du Colombier i = readnum(0, a, n, status, NUMSIZE);
118480ee5cbfSDavid du Colombier } else
118580ee5cbfSDavid du Colombier i = 0;
118680ee5cbfSDavid du Colombier qunlock(&unit->raw);
11879a747e4fSDavid du Colombier decref(&sdev->r);
118880ee5cbfSDavid du Colombier poperror();
118980ee5cbfSDavid du Colombier return i;
11909a747e4fSDavid du Colombier
11917dd7cddfSDavid du Colombier case Qpart:
11927dd7cddfSDavid du Colombier return sdbio(c, 0, a, n, off);
11937dd7cddfSDavid du Colombier }
11947dd7cddfSDavid du Colombier }
11957dd7cddfSDavid du Colombier
11964de34a7eSDavid du Colombier static void legacytopctl(Cmdbuf*);
11979a747e4fSDavid du Colombier
11987dd7cddfSDavid du Colombier static long
sdwrite(Chan * c,void * a,long n,vlong off)11997dd7cddfSDavid du Colombier sdwrite(Chan* c, void* a, long n, vlong off)
12007dd7cddfSDavid du Colombier {
12014de34a7eSDavid du Colombier char *f0;
12024de34a7eSDavid du Colombier int i;
120317629263SDavid du Colombier uvlong end, start;
12047dd7cddfSDavid du Colombier Cmdbuf *cb;
12054de34a7eSDavid du Colombier SDifc *ifc;
12067dd7cddfSDavid du Colombier SDreq *req;
12077dd7cddfSDavid du Colombier SDunit *unit;
12089a747e4fSDavid du Colombier SDev *sdev;
12097dd7cddfSDavid du Colombier
12107dd7cddfSDavid du Colombier switch(TYPE(c->qid)){
12117dd7cddfSDavid du Colombier default:
12127dd7cddfSDavid du Colombier error(Eperm);
12134de34a7eSDavid du Colombier case Qtopctl:
12144de34a7eSDavid du Colombier cb = parsecmd(a, n);
12154de34a7eSDavid du Colombier if(waserror()){
12164de34a7eSDavid du Colombier free(cb);
12174de34a7eSDavid du Colombier nexterror();
12189a747e4fSDavid du Colombier }
12194de34a7eSDavid du Colombier if(cb->nf == 0)
12204de34a7eSDavid du Colombier error("empty control message");
12214de34a7eSDavid du Colombier f0 = cb->f[0];
12224de34a7eSDavid du Colombier cb->f++;
12234de34a7eSDavid du Colombier cb->nf--;
12244de34a7eSDavid du Colombier if(strcmp(f0, "config") == 0){
12254de34a7eSDavid du Colombier /* wormhole into ugly legacy interface */
12264de34a7eSDavid du Colombier legacytopctl(cb);
12274de34a7eSDavid du Colombier poperror();
12284de34a7eSDavid du Colombier free(cb);
12299a747e4fSDavid du Colombier break;
12309a747e4fSDavid du Colombier }
1231d649fdd7SDavid du Colombier /*
1232d649fdd7SDavid du Colombier * "ata arg..." invokes sdifc[i]->wtopctl(nil, cb),
1233d649fdd7SDavid du Colombier * where sdifc[i]->name=="ata" and cb contains the args.
1234d649fdd7SDavid du Colombier */
12354de34a7eSDavid du Colombier ifc = nil;
12364de34a7eSDavid du Colombier sdev = nil;
12374de34a7eSDavid du Colombier for(i=0; sdifc[i]; i++){
12384de34a7eSDavid du Colombier if(strcmp(sdifc[i]->name, f0) == 0){
12394de34a7eSDavid du Colombier ifc = sdifc[i];
12404de34a7eSDavid du Colombier sdev = nil;
12414de34a7eSDavid du Colombier goto subtopctl;
12424de34a7eSDavid du Colombier }
12434de34a7eSDavid du Colombier }
1244d649fdd7SDavid du Colombier /*
1245d649fdd7SDavid du Colombier * "sd1 arg..." invokes sdifc[i]->wtopctl(sdev, cb),
1246d649fdd7SDavid du Colombier * where sdifc[i] and sdev match controller letter "1",
1247d649fdd7SDavid du Colombier * and cb contains the args.
1248d649fdd7SDavid du Colombier */
12494de34a7eSDavid du Colombier if(f0[0]=='s' && f0[1]=='d' && f0[2] && f0[3] == 0){
12504de34a7eSDavid du Colombier if((sdev = sdgetdev(f0[2])) != nil){
12514de34a7eSDavid du Colombier ifc = sdev->ifc;
12524de34a7eSDavid du Colombier goto subtopctl;
12534de34a7eSDavid du Colombier }
12544de34a7eSDavid du Colombier }
12554de34a7eSDavid du Colombier error("unknown interface");
12564de34a7eSDavid du Colombier
12574de34a7eSDavid du Colombier subtopctl:
12584de34a7eSDavid du Colombier if(waserror()){
12594de34a7eSDavid du Colombier if(sdev)
12604de34a7eSDavid du Colombier decref(&sdev->r);
12614de34a7eSDavid du Colombier nexterror();
12624de34a7eSDavid du Colombier }
12634de34a7eSDavid du Colombier if(ifc->wtopctl)
12644de34a7eSDavid du Colombier ifc->wtopctl(sdev, cb);
12654de34a7eSDavid du Colombier else
12664de34a7eSDavid du Colombier error(Ebadctl);
12674de34a7eSDavid du Colombier poperror();
12684de34a7eSDavid du Colombier poperror();
12699e8a50a9SDavid du Colombier if (sdev)
12704de34a7eSDavid du Colombier decref(&sdev->r);
12714de34a7eSDavid du Colombier free(cb);
12724de34a7eSDavid du Colombier break;
12734de34a7eSDavid du Colombier
12747dd7cddfSDavid du Colombier case Qctl:
12757dd7cddfSDavid du Colombier cb = parsecmd(a, n);
12769a747e4fSDavid du Colombier sdev = sdgetdev(DEV(c->qid));
12779a747e4fSDavid du Colombier if(sdev == nil)
12789a747e4fSDavid du Colombier error(Enonexist);
12799a747e4fSDavid du Colombier unit = sdev->unit[UNIT(c->qid)];
12807dd7cddfSDavid du Colombier
12817dd7cddfSDavid du Colombier qlock(&unit->ctl);
12827dd7cddfSDavid du Colombier if(waserror()){
12837dd7cddfSDavid du Colombier qunlock(&unit->ctl);
12849a747e4fSDavid du Colombier decref(&sdev->r);
12857dd7cddfSDavid du Colombier free(cb);
12867dd7cddfSDavid du Colombier nexterror();
12877dd7cddfSDavid du Colombier }
1288223a736eSDavid du Colombier if(unit->vers != c->qid.vers)
12894de34a7eSDavid du Colombier error(Echange);
12907dd7cddfSDavid du Colombier
12917dd7cddfSDavid du Colombier if(cb->nf < 1)
12927dd7cddfSDavid du Colombier error(Ebadctl);
12937dd7cddfSDavid du Colombier if(strcmp(cb->f[0], "part") == 0){
1294223a736eSDavid du Colombier if(cb->nf != 4)
12957dd7cddfSDavid du Colombier error(Ebadctl);
12967dd7cddfSDavid du Colombier if(unit->sectors == 0 && !sdinitpart(unit))
12977dd7cddfSDavid du Colombier error(Eio);
129817629263SDavid du Colombier start = strtoull(cb->f[2], 0, 0);
129917629263SDavid du Colombier end = strtoull(cb->f[3], 0, 0);
13007dd7cddfSDavid du Colombier sdaddpart(unit, cb->f[1], start, end);
13017dd7cddfSDavid du Colombier }
13027dd7cddfSDavid du Colombier else if(strcmp(cb->f[0], "delpart") == 0){
13037dd7cddfSDavid du Colombier if(cb->nf != 2 || unit->part == nil)
13047dd7cddfSDavid du Colombier error(Ebadctl);
13057dd7cddfSDavid du Colombier sddelpart(unit, cb->f[1]);
13067dd7cddfSDavid du Colombier }
13077dd7cddfSDavid du Colombier else if(unit->dev->ifc->wctl)
13087dd7cddfSDavid du Colombier unit->dev->ifc->wctl(unit, cb);
13097dd7cddfSDavid du Colombier else
13107dd7cddfSDavid du Colombier error(Ebadctl);
13117dd7cddfSDavid du Colombier qunlock(&unit->ctl);
13129a747e4fSDavid du Colombier decref(&sdev->r);
13137dd7cddfSDavid du Colombier poperror();
13147dd7cddfSDavid du Colombier free(cb);
13157dd7cddfSDavid du Colombier break;
13167dd7cddfSDavid du Colombier
13177dd7cddfSDavid du Colombier case Qraw:
13189a747e4fSDavid du Colombier sdev = sdgetdev(DEV(c->qid));
13199a747e4fSDavid du Colombier if(sdev == nil)
13209a747e4fSDavid du Colombier error(Enonexist);
13219a747e4fSDavid du Colombier unit = sdev->unit[UNIT(c->qid)];
132280ee5cbfSDavid du Colombier qlock(&unit->raw);
132380ee5cbfSDavid du Colombier if(waserror()){
132480ee5cbfSDavid du Colombier qunlock(&unit->raw);
13259a747e4fSDavid du Colombier decref(&sdev->r);
132680ee5cbfSDavid du Colombier nexterror();
132780ee5cbfSDavid du Colombier }
13287dd7cddfSDavid du Colombier switch(unit->state){
13297dd7cddfSDavid du Colombier case Rawcmd:
13307dd7cddfSDavid du Colombier if(n < 6 || n > sizeof(req->cmd))
13317dd7cddfSDavid du Colombier error(Ebadarg);
13327dd7cddfSDavid du Colombier if((req = malloc(sizeof(SDreq))) == nil)
13337dd7cddfSDavid du Colombier error(Enomem);
13347dd7cddfSDavid du Colombier req->unit = unit;
13357dd7cddfSDavid du Colombier memmove(req->cmd, a, n);
13367dd7cddfSDavid du Colombier req->clen = n;
13377dd7cddfSDavid du Colombier req->flags = SDnosense;
13387dd7cddfSDavid du Colombier req->status = ~0;
13397dd7cddfSDavid du Colombier
13407dd7cddfSDavid du Colombier unit->req = req;
13417dd7cddfSDavid du Colombier unit->state = Rawdata;
13427dd7cddfSDavid du Colombier break;
13437dd7cddfSDavid du Colombier
13447dd7cddfSDavid du Colombier case Rawstatus:
13457dd7cddfSDavid du Colombier unit->state = Rawcmd;
13467dd7cddfSDavid du Colombier free(unit->req);
13477dd7cddfSDavid du Colombier unit->req = nil;
13487dd7cddfSDavid du Colombier error(Ebadusefd);
13497dd7cddfSDavid du Colombier
13507dd7cddfSDavid du Colombier case Rawdata:
13517dd7cddfSDavid du Colombier unit->state = Rawstatus;
13527dd7cddfSDavid du Colombier unit->req->write = 1;
135380ee5cbfSDavid du Colombier n = sdrio(unit->req, a, n);
13547dd7cddfSDavid du Colombier }
135580ee5cbfSDavid du Colombier qunlock(&unit->raw);
13569a747e4fSDavid du Colombier decref(&sdev->r);
135780ee5cbfSDavid du Colombier poperror();
13589a747e4fSDavid du Colombier break;
13597dd7cddfSDavid du Colombier case Qpart:
13607dd7cddfSDavid du Colombier return sdbio(c, 1, a, n, off);
13617dd7cddfSDavid du Colombier }
13627dd7cddfSDavid du Colombier
13637dd7cddfSDavid du Colombier return n;
13647dd7cddfSDavid du Colombier }
13657dd7cddfSDavid du Colombier
13669a747e4fSDavid du Colombier static int
sdwstat(Chan * c,uchar * dp,int n)13679a747e4fSDavid du Colombier sdwstat(Chan* c, uchar* dp, int n)
13687dd7cddfSDavid du Colombier {
13699a747e4fSDavid du Colombier Dir *d;
13707dd7cddfSDavid du Colombier SDpart *pp;
137159cc4ca5SDavid du Colombier SDperm *perm;
13727dd7cddfSDavid du Colombier SDunit *unit;
13739a747e4fSDavid du Colombier SDev *sdev;
13747dd7cddfSDavid du Colombier
13759a747e4fSDavid du Colombier if(c->qid.type & QTDIR)
13767dd7cddfSDavid du Colombier error(Eperm);
13777dd7cddfSDavid du Colombier
13789a747e4fSDavid du Colombier sdev = sdgetdev(DEV(c->qid));
13799a747e4fSDavid du Colombier if(sdev == nil)
13809a747e4fSDavid du Colombier error(Enonexist);
13819a747e4fSDavid du Colombier unit = sdev->unit[UNIT(c->qid)];
13827dd7cddfSDavid du Colombier qlock(&unit->ctl);
13839a747e4fSDavid du Colombier d = nil;
13847dd7cddfSDavid du Colombier if(waserror()){
13859a747e4fSDavid du Colombier free(d);
13867dd7cddfSDavid du Colombier qunlock(&unit->ctl);
13879a747e4fSDavid du Colombier decref(&sdev->r);
13887dd7cddfSDavid du Colombier nexterror();
13897dd7cddfSDavid du Colombier }
13907dd7cddfSDavid du Colombier
139159cc4ca5SDavid du Colombier switch(TYPE(c->qid)){
139259cc4ca5SDavid du Colombier default:
139359cc4ca5SDavid du Colombier error(Eperm);
139459cc4ca5SDavid du Colombier case Qctl:
139559cc4ca5SDavid du Colombier perm = &unit->ctlperm;
139659cc4ca5SDavid du Colombier break;
139759cc4ca5SDavid du Colombier case Qraw:
139859cc4ca5SDavid du Colombier perm = &unit->rawperm;
139959cc4ca5SDavid du Colombier break;
140059cc4ca5SDavid du Colombier case Qpart:
14017dd7cddfSDavid du Colombier pp = &unit->part[PART(c->qid)];
1402223a736eSDavid du Colombier if(unit->vers+pp->vers != c->qid.vers)
14037dd7cddfSDavid du Colombier error(Enonexist);
140459cc4ca5SDavid du Colombier perm = &pp->SDperm;
140559cc4ca5SDavid du Colombier break;
140659cc4ca5SDavid du Colombier }
14077dd7cddfSDavid du Colombier
14089a747e4fSDavid du Colombier if(strcmp(up->user, perm->user) && !iseve())
140959cc4ca5SDavid du Colombier error(Eperm);
14107dd7cddfSDavid du Colombier
14119a747e4fSDavid du Colombier d = smalloc(sizeof(Dir)+n);
14129a747e4fSDavid du Colombier n = convM2D(dp, n, &d[0], (char*)&d[1]);
14139a747e4fSDavid du Colombier if(n == 0)
14149a747e4fSDavid du Colombier error(Eshortstat);
14159a747e4fSDavid du Colombier if(!emptystr(d[0].uid))
14169a747e4fSDavid du Colombier kstrdup(&perm->user, d[0].uid);
14179a747e4fSDavid du Colombier if(d[0].mode != ~0UL)
14189a747e4fSDavid du Colombier perm->perm = (perm->perm & ~0777) | (d[0].mode & 0777);
14199a747e4fSDavid du Colombier
14209a747e4fSDavid du Colombier free(d);
14217dd7cddfSDavid du Colombier qunlock(&unit->ctl);
14229a747e4fSDavid du Colombier decref(&sdev->r);
14237dd7cddfSDavid du Colombier poperror();
14249a747e4fSDavid du Colombier return n;
14259a747e4fSDavid du Colombier }
14269a747e4fSDavid du Colombier
14279a747e4fSDavid du Colombier static int
configure(char * spec,DevConf * cf)14289a747e4fSDavid du Colombier configure(char* spec, DevConf* cf)
14299a747e4fSDavid du Colombier {
14304de34a7eSDavid du Colombier SDev *s, *sdev;
14314de34a7eSDavid du Colombier char *p;
14324de34a7eSDavid du Colombier int i;
14334de34a7eSDavid du Colombier
14344de34a7eSDavid du Colombier if(sdindex(*spec) < 0)
14354de34a7eSDavid du Colombier error("bad sd spec");
14369a747e4fSDavid du Colombier
14379a747e4fSDavid du Colombier if((p = strchr(cf->type, '/')) != nil)
14389a747e4fSDavid du Colombier *p++ = '\0';
14399a747e4fSDavid du Colombier
14409a747e4fSDavid du Colombier for(i = 0; sdifc[i] != nil; i++)
14414de34a7eSDavid du Colombier if(strcmp(sdifc[i]->name, cf->type) == 0)
14429a747e4fSDavid du Colombier break;
14439a747e4fSDavid du Colombier if(sdifc[i] == nil)
14444de34a7eSDavid du Colombier error("sd type not found");
14454de34a7eSDavid du Colombier if(p)
14464de34a7eSDavid du Colombier *(p-1) = '/';
14479a747e4fSDavid du Colombier
14484de34a7eSDavid du Colombier if(sdifc[i]->probe == nil)
14494de34a7eSDavid du Colombier error("sd type cannot probe");
14509a747e4fSDavid du Colombier
14514de34a7eSDavid du Colombier sdev = sdifc[i]->probe(cf);
14524de34a7eSDavid du Colombier for(s=sdev; s; s=s->next)
14534de34a7eSDavid du Colombier s->idno = *spec;
14544de34a7eSDavid du Colombier sdadddevs(sdev);
14559a747e4fSDavid du Colombier return 0;
14569a747e4fSDavid du Colombier }
14579a747e4fSDavid du Colombier
14589a747e4fSDavid du Colombier static int
unconfigure(char * spec)14599a747e4fSDavid du Colombier unconfigure(char* spec)
14609a747e4fSDavid du Colombier {
14619a747e4fSDavid du Colombier int i;
14629a747e4fSDavid du Colombier SDev *sdev;
14634de34a7eSDavid du Colombier SDunit *unit;
14649a747e4fSDavid du Colombier
14654de34a7eSDavid du Colombier if((i = sdindex(*spec)) < 0)
14669a747e4fSDavid du Colombier error(Enonexist);
14679a747e4fSDavid du Colombier
14684de34a7eSDavid du Colombier qlock(&devslock);
14694de34a7eSDavid du Colombier if((sdev = devs[i]) == nil){
14704de34a7eSDavid du Colombier qunlock(&devslock);
14714de34a7eSDavid du Colombier error(Enonexist);
14724de34a7eSDavid du Colombier }
14734de34a7eSDavid du Colombier if(sdev->r.ref){
14744de34a7eSDavid du Colombier qunlock(&devslock);
14759a747e4fSDavid du Colombier error(Einuse);
14764de34a7eSDavid du Colombier }
14774de34a7eSDavid du Colombier devs[i] = nil;
14784de34a7eSDavid du Colombier qunlock(&devslock);
14799a747e4fSDavid du Colombier
14809a747e4fSDavid du Colombier /* make sure no interrupts arrive anymore before removing resources */
14819a747e4fSDavid du Colombier if(sdev->enabled && sdev->ifc->disable)
14829a747e4fSDavid du Colombier sdev->ifc->disable(sdev);
14839a747e4fSDavid du Colombier
14844de34a7eSDavid du Colombier for(i = 0; i != sdev->nunit; i++){
14854de34a7eSDavid du Colombier if(unit = sdev->unit[i]){
14869a747e4fSDavid du Colombier free(unit->name);
14879a747e4fSDavid du Colombier free(unit->user);
14889a747e4fSDavid du Colombier free(unit);
14899a747e4fSDavid du Colombier }
14904de34a7eSDavid du Colombier }
14919a747e4fSDavid du Colombier
14929a747e4fSDavid du Colombier if(sdev->ifc->clear)
14939a747e4fSDavid du Colombier sdev->ifc->clear(sdev);
14944de34a7eSDavid du Colombier free(sdev);
14959a747e4fSDavid du Colombier return 0;
14969a747e4fSDavid du Colombier }
14979a747e4fSDavid du Colombier
14989a747e4fSDavid du Colombier static int
sdconfig(int on,char * spec,DevConf * cf)14999a747e4fSDavid du Colombier sdconfig(int on, char* spec, DevConf* cf)
15009a747e4fSDavid du Colombier {
15019a747e4fSDavid du Colombier if(on)
15029a747e4fSDavid du Colombier return configure(spec, cf);
15039a747e4fSDavid du Colombier return unconfigure(spec);
15047dd7cddfSDavid du Colombier }
15057dd7cddfSDavid du Colombier
15067dd7cddfSDavid du Colombier Dev sddevtab = {
15077dd7cddfSDavid du Colombier 'S',
15087dd7cddfSDavid du Colombier "sd",
15097dd7cddfSDavid du Colombier
15107dd7cddfSDavid du Colombier sdreset,
15117dd7cddfSDavid du Colombier devinit,
15129a747e4fSDavid du Colombier devshutdown,
15137dd7cddfSDavid du Colombier sdattach,
15147dd7cddfSDavid du Colombier sdwalk,
15157dd7cddfSDavid du Colombier sdstat,
15167dd7cddfSDavid du Colombier sdopen,
15177dd7cddfSDavid du Colombier devcreate,
15187dd7cddfSDavid du Colombier sdclose,
15197dd7cddfSDavid du Colombier sdread,
15207dd7cddfSDavid du Colombier devbread,
15217dd7cddfSDavid du Colombier sdwrite,
15227dd7cddfSDavid du Colombier devbwrite,
15237dd7cddfSDavid du Colombier devremove,
15247dd7cddfSDavid du Colombier sdwstat,
15259a747e4fSDavid du Colombier devpower,
1526aa72973aSDavid du Colombier sdconfig, /* probe; only called for pcmcia-like devices */
15277dd7cddfSDavid du Colombier };
15284de34a7eSDavid du Colombier
15294de34a7eSDavid du Colombier /*
15304de34a7eSDavid du Colombier * This is wrong for so many reasons. This code must go.
15314de34a7eSDavid du Colombier */
15324de34a7eSDavid du Colombier typedef struct Confdata Confdata;
15334de34a7eSDavid du Colombier struct Confdata {
15344de34a7eSDavid du Colombier int on;
15354de34a7eSDavid du Colombier char* spec;
15364de34a7eSDavid du Colombier DevConf cf;
15374de34a7eSDavid du Colombier };
15384de34a7eSDavid du Colombier
15394de34a7eSDavid du Colombier static void
parseswitch(Confdata * cd,char * option)15404de34a7eSDavid du Colombier parseswitch(Confdata* cd, char* option)
15414de34a7eSDavid du Colombier {
15424de34a7eSDavid du Colombier if(!strcmp("on", option))
15434de34a7eSDavid du Colombier cd->on = 1;
15444de34a7eSDavid du Colombier else if(!strcmp("off", option))
15454de34a7eSDavid du Colombier cd->on = 0;
15464de34a7eSDavid du Colombier else
15474de34a7eSDavid du Colombier error(Ebadarg);
15484de34a7eSDavid du Colombier }
15494de34a7eSDavid du Colombier
15504de34a7eSDavid du Colombier static void
parsespec(Confdata * cd,char * option)15514de34a7eSDavid du Colombier parsespec(Confdata* cd, char* option)
15524de34a7eSDavid du Colombier {
15534de34a7eSDavid du Colombier if(strlen(option) > 1)
15544de34a7eSDavid du Colombier error(Ebadarg);
15554de34a7eSDavid du Colombier cd->spec = option;
15564de34a7eSDavid du Colombier }
15574de34a7eSDavid du Colombier
15584de34a7eSDavid du Colombier static Devport*
getnewport(DevConf * dc)15594de34a7eSDavid du Colombier getnewport(DevConf* dc)
15604de34a7eSDavid du Colombier {
15614de34a7eSDavid du Colombier Devport *p;
15624de34a7eSDavid du Colombier
15634de34a7eSDavid du Colombier p = (Devport *)malloc((dc->nports + 1) * sizeof(Devport));
1564aa72973aSDavid du Colombier if(p == nil)
1565aa72973aSDavid du Colombier error(Enomem);
15664de34a7eSDavid du Colombier if(dc->nports > 0){
15674de34a7eSDavid du Colombier memmove(p, dc->ports, dc->nports * sizeof(Devport));
15684de34a7eSDavid du Colombier free(dc->ports);
15694de34a7eSDavid du Colombier }
15704de34a7eSDavid du Colombier dc->ports = p;
15714de34a7eSDavid du Colombier p = &dc->ports[dc->nports++];
15724de34a7eSDavid du Colombier p->size = -1;
15734de34a7eSDavid du Colombier p->port = (ulong)-1;
15744de34a7eSDavid du Colombier return p;
15754de34a7eSDavid du Colombier }
15764de34a7eSDavid du Colombier
15774de34a7eSDavid du Colombier static void
parseport(Confdata * cd,char * option)15784de34a7eSDavid du Colombier parseport(Confdata* cd, char* option)
15794de34a7eSDavid du Colombier {
15804de34a7eSDavid du Colombier char *e;
15814de34a7eSDavid du Colombier Devport *p;
15824de34a7eSDavid du Colombier
15834de34a7eSDavid du Colombier if(cd->cf.nports == 0 || cd->cf.ports[cd->cf.nports-1].port != (ulong)-1)
15844de34a7eSDavid du Colombier p = getnewport(&cd->cf);
15854de34a7eSDavid du Colombier else
15864de34a7eSDavid du Colombier p = &cd->cf.ports[cd->cf.nports-1];
15874de34a7eSDavid du Colombier p->port = strtol(option, &e, 0);
15884de34a7eSDavid du Colombier if(e == nil || *e != '\0')
15894de34a7eSDavid du Colombier error(Ebadarg);
15904de34a7eSDavid du Colombier }
15914de34a7eSDavid du Colombier
15924de34a7eSDavid du Colombier static void
parsesize(Confdata * cd,char * option)15934de34a7eSDavid du Colombier parsesize(Confdata* cd, char* option)
15944de34a7eSDavid du Colombier {
15954de34a7eSDavid du Colombier char *e;
15964de34a7eSDavid du Colombier Devport *p;
15974de34a7eSDavid du Colombier
15984de34a7eSDavid du Colombier if(cd->cf.nports == 0 || cd->cf.ports[cd->cf.nports-1].size != -1)
15994de34a7eSDavid du Colombier p = getnewport(&cd->cf);
16004de34a7eSDavid du Colombier else
16014de34a7eSDavid du Colombier p = &cd->cf.ports[cd->cf.nports-1];
16024de34a7eSDavid du Colombier p->size = (int)strtol(option, &e, 0);
16034de34a7eSDavid du Colombier if(e == nil || *e != '\0')
16044de34a7eSDavid du Colombier error(Ebadarg);
16054de34a7eSDavid du Colombier }
16064de34a7eSDavid du Colombier
16074de34a7eSDavid du Colombier static void
parseirq(Confdata * cd,char * option)16084de34a7eSDavid du Colombier parseirq(Confdata* cd, char* option)
16094de34a7eSDavid du Colombier {
16104de34a7eSDavid du Colombier char *e;
16114de34a7eSDavid du Colombier
16124de34a7eSDavid du Colombier cd->cf.intnum = strtoul(option, &e, 0);
16134de34a7eSDavid du Colombier if(e == nil || *e != '\0')
16144de34a7eSDavid du Colombier error(Ebadarg);
16154de34a7eSDavid du Colombier }
16164de34a7eSDavid du Colombier
16174de34a7eSDavid du Colombier static void
parsetype(Confdata * cd,char * option)16184de34a7eSDavid du Colombier parsetype(Confdata* cd, char* option)
16194de34a7eSDavid du Colombier {
16204de34a7eSDavid du Colombier cd->cf.type = option;
16214de34a7eSDavid du Colombier }
16224de34a7eSDavid du Colombier
16234de34a7eSDavid du Colombier static struct {
16244de34a7eSDavid du Colombier char *name;
16254de34a7eSDavid du Colombier void (*parse)(Confdata*, char*);
16264de34a7eSDavid du Colombier } options[] = {
16274de34a7eSDavid du Colombier "switch", parseswitch,
16284de34a7eSDavid du Colombier "spec", parsespec,
16294de34a7eSDavid du Colombier "port", parseport,
16304de34a7eSDavid du Colombier "size", parsesize,
16314de34a7eSDavid du Colombier "irq", parseirq,
16324de34a7eSDavid du Colombier "type", parsetype,
16334de34a7eSDavid du Colombier };
16344de34a7eSDavid du Colombier
16354de34a7eSDavid du Colombier static void
legacytopctl(Cmdbuf * cb)16364de34a7eSDavid du Colombier legacytopctl(Cmdbuf *cb)
16374de34a7eSDavid du Colombier {
16384de34a7eSDavid du Colombier char *opt;
16394de34a7eSDavid du Colombier int i, j;
16404de34a7eSDavid du Colombier Confdata cd;
16414de34a7eSDavid du Colombier
16424de34a7eSDavid du Colombier memset(&cd, 0, sizeof cd);
16434de34a7eSDavid du Colombier cd.on = -1;
16444de34a7eSDavid du Colombier for(i=0; i<cb->nf; i+=2){
16454de34a7eSDavid du Colombier if(i+2 > cb->nf)
16464de34a7eSDavid du Colombier error(Ebadarg);
16474de34a7eSDavid du Colombier opt = cb->f[i];
16484de34a7eSDavid du Colombier for(j=0; j<nelem(options); j++)
16494de34a7eSDavid du Colombier if(strcmp(opt, options[j].name) == 0){
16504de34a7eSDavid du Colombier options[j].parse(&cd, cb->f[i+1]);
16514de34a7eSDavid du Colombier break;
16524de34a7eSDavid du Colombier }
16534de34a7eSDavid du Colombier if(j == nelem(options))
16544de34a7eSDavid du Colombier error(Ebadarg);
16554de34a7eSDavid du Colombier }
1656479935bcSDavid du Colombier /* this has been rewritten to accomodate sdaoe */
1657479935bcSDavid du Colombier if(cd.on < 0 || cd.spec == 0)
16584de34a7eSDavid du Colombier error(Ebadarg);
1659479935bcSDavid du Colombier if(cd.on && cd.cf.type == nil)
16604de34a7eSDavid du Colombier error(Ebadarg);
16614de34a7eSDavid du Colombier sdconfig(cd.on, cd.spec, &cd.cf);
16624de34a7eSDavid du Colombier }
1663