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);
4864e3613abSDavid du Colombier snprint(up->genbuf, sizeof up->genbuf, "#%C",
4874e3613abSDavid 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);
5354e3613abSDavid du Colombier snprint(up->genbuf, sizeof up->genbuf, "#%C",
5364e3613abSDavid 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]){
967fef25afaSDavid du Colombier case ScmdRead:
968fef25afaSDavid du Colombier case ScmdWrite:
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 */
987fef25afaSDavid du Colombier if((cmd[1]>>5) && cmd[0] != ScmdInq)
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
994fef25afaSDavid du Colombier case ScmdTur: /* test unit ready */
9954de34a7eSDavid du Colombier return sdsetsense(r, SDok, 0, 0, 0);
9964de34a7eSDavid du Colombier
997fef25afaSDavid du Colombier case ScmdRsense: /* 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
1008fef25afaSDavid du Colombier case ScmdInq: /* 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
1019fef25afaSDavid du Colombier case ScmdStart: /* 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
1025fef25afaSDavid du Colombier case ScmdRcapacity: /* 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
1048fef25afaSDavid du Colombier case ScmdRcapacity16: /* 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
1074fef25afaSDavid du Colombier case ScmdMsense10: /* mode sense */
10754de34a7eSDavid du Colombier return sdmodesense(r, cmd, info, ilen);
10764de34a7eSDavid du Colombier
1077fef25afaSDavid du Colombier case ScmdExtread:
1078fef25afaSDavid du Colombier case ScmdExtwrite:
1079fef25afaSDavid du Colombier case ScmdRead16:
1080fef25afaSDavid du Colombier case ScmdWrite16:
10814de34a7eSDavid du Colombier return SDnostatus;
10824de34a7eSDavid du Colombier }
10834de34a7eSDavid du Colombier }
10844de34a7eSDavid du Colombier
1085*5a0d9eb8SDavid du Colombier int
sdfakescsirw(SDreq * r,uvlong * llba,int * nsec,int * rwp)1086*5a0d9eb8SDavid du Colombier sdfakescsirw(SDreq *r, uvlong *llba, int *nsec, int *rwp)
1087*5a0d9eb8SDavid du Colombier {
1088*5a0d9eb8SDavid du Colombier uchar *c;
1089*5a0d9eb8SDavid du Colombier int rw, count;
1090*5a0d9eb8SDavid du Colombier uvlong lba;
1091*5a0d9eb8SDavid du Colombier
1092*5a0d9eb8SDavid du Colombier c = r->cmd;
1093*5a0d9eb8SDavid du Colombier rw = 0;
1094*5a0d9eb8SDavid du Colombier if((c[0] & 0xf) == 0xa)
1095*5a0d9eb8SDavid du Colombier rw = 1;
1096*5a0d9eb8SDavid du Colombier switch(c[0]){
1097*5a0d9eb8SDavid du Colombier case 0x08: /* read6 */
1098*5a0d9eb8SDavid du Colombier case 0x0a:
1099*5a0d9eb8SDavid du Colombier lba = (c[1] & 0xf)<<16 | c[2]<<8 | c[3];
1100*5a0d9eb8SDavid du Colombier count = c[4];
1101*5a0d9eb8SDavid du Colombier break;
1102*5a0d9eb8SDavid du Colombier case 0x28: /* read10 */
1103*5a0d9eb8SDavid du Colombier case 0x2a:
1104*5a0d9eb8SDavid du Colombier lba = c[2]<<24 | c[3]<<16 | c[4]<<8 | c[5];
1105*5a0d9eb8SDavid du Colombier count = c[7]<<8 | c[8];
1106*5a0d9eb8SDavid du Colombier break;
1107*5a0d9eb8SDavid du Colombier case 0xa8: /* read12 */
1108*5a0d9eb8SDavid du Colombier case 0xaa:
1109*5a0d9eb8SDavid du Colombier lba = c[2]<<24 | c[3]<<16 | c[4]<<8 | c[5];
1110*5a0d9eb8SDavid du Colombier count = c[6]<<24 | c[7]<<16 | c[8]<<8 | c[9];
1111*5a0d9eb8SDavid du Colombier break;
1112*5a0d9eb8SDavid du Colombier case 0x88: /* read16 */
1113*5a0d9eb8SDavid du Colombier case 0x8a:
1114*5a0d9eb8SDavid du Colombier /* ata commands only go to 48-bit lba */
1115*5a0d9eb8SDavid du Colombier if(c[2] || c[3])
1116*5a0d9eb8SDavid du Colombier return sdsetsense(r, SDcheck, 3, 0xc, 2);
1117*5a0d9eb8SDavid du Colombier lba = (uvlong)c[4]<<40 | (uvlong)c[5]<<32;
1118*5a0d9eb8SDavid du Colombier lba |= c[6]<<24 | c[7]<<16 | c[8]<<8 | c[9];
1119*5a0d9eb8SDavid du Colombier count = c[10]<<24 | c[11]<<16 | c[12]<<8 | c[13];
1120*5a0d9eb8SDavid du Colombier break;
1121*5a0d9eb8SDavid du Colombier default:
1122*5a0d9eb8SDavid du Colombier print("%s: bad cmd 0x%.2ux\n", r->unit->name, c[0]);
1123*5a0d9eb8SDavid du Colombier r->status = sdsetsense(r, SDcheck, 0x05, 0x20, 0);
1124*5a0d9eb8SDavid du Colombier return SDcheck;
1125*5a0d9eb8SDavid du Colombier }
1126*5a0d9eb8SDavid du Colombier if(r->data == nil)
1127*5a0d9eb8SDavid du Colombier return SDok;
1128*5a0d9eb8SDavid du Colombier if(r->dlen < count * r->unit->secsize)
1129*5a0d9eb8SDavid du Colombier count = r->dlen/r->unit->secsize;
1130*5a0d9eb8SDavid du Colombier if(rwp)
1131*5a0d9eb8SDavid du Colombier *rwp = rw;
1132*5a0d9eb8SDavid du Colombier *llba = lba;
1133*5a0d9eb8SDavid du Colombier *nsec = count;
1134*5a0d9eb8SDavid du Colombier return SDnostatus;
1135*5a0d9eb8SDavid du Colombier }
1136*5a0d9eb8SDavid du Colombier
11377dd7cddfSDavid du Colombier static long
sdread(Chan * c,void * a,long n,vlong off)11387dd7cddfSDavid du Colombier sdread(Chan *c, void *a, long n, vlong off)
11397dd7cddfSDavid du Colombier {
11409a747e4fSDavid du Colombier char *p, *e, *buf;
11417dd7cddfSDavid du Colombier SDpart *pp;
11427dd7cddfSDavid du Colombier SDunit *unit;
11439a747e4fSDavid du Colombier SDev *sdev;
11447dd7cddfSDavid du Colombier ulong offset;
11454de34a7eSDavid du Colombier int i, l, m, status;
11467dd7cddfSDavid du Colombier
11477dd7cddfSDavid du Colombier offset = off;
11487dd7cddfSDavid du Colombier switch(TYPE(c->qid)){
11497dd7cddfSDavid du Colombier default:
11507dd7cddfSDavid du Colombier error(Eperm);
11514de34a7eSDavid du Colombier case Qtopctl:
11524de34a7eSDavid du Colombier m = 64*1024; /* room for register dumps */
11534de34a7eSDavid du Colombier p = buf = malloc(m);
1154aa72973aSDavid du Colombier if(p == nil)
1155aa72973aSDavid du Colombier error(Enomem);
11564de34a7eSDavid du Colombier e = p + m;
11579a747e4fSDavid du Colombier qlock(&devslock);
11584de34a7eSDavid du Colombier for(i = 0; i < nelem(devs); i++){
11594de34a7eSDavid du Colombier sdev = devs[i];
11604de34a7eSDavid du Colombier if(sdev && sdev->ifc->rtopctl)
11614de34a7eSDavid du Colombier p = sdev->ifc->rtopctl(sdev, p, e);
11629a747e4fSDavid du Colombier }
11639a747e4fSDavid du Colombier qunlock(&devslock);
11649a747e4fSDavid du Colombier n = readstr(off, a, n, buf);
11659a747e4fSDavid du Colombier free(buf);
11669a747e4fSDavid du Colombier return n;
11679a747e4fSDavid du Colombier
11687dd7cddfSDavid du Colombier case Qtopdir:
11697dd7cddfSDavid du Colombier case Qunitdir:
11707dd7cddfSDavid du Colombier return devdirread(c, a, n, 0, 0, sdgen);
11719a747e4fSDavid du Colombier
11727dd7cddfSDavid du Colombier case Qctl:
11739a747e4fSDavid du Colombier sdev = sdgetdev(DEV(c->qid));
11749a747e4fSDavid du Colombier if(sdev == nil)
11759a747e4fSDavid du Colombier error(Enonexist);
11769a747e4fSDavid du Colombier
11779a747e4fSDavid du Colombier unit = sdev->unit[UNIT(c->qid)];
11784de34a7eSDavid du Colombier m = 16*1024; /* room for register dumps */
11794de34a7eSDavid du Colombier p = malloc(m);
1180aa72973aSDavid du Colombier if(p == nil)
1181aa72973aSDavid du Colombier error(Enomem);
11824de34a7eSDavid du Colombier l = snprint(p, m, "inquiry %.48s\n",
11837dd7cddfSDavid du Colombier (char*)unit->inquiry+8);
11847dd7cddfSDavid du Colombier qlock(&unit->ctl);
11857dd7cddfSDavid du Colombier /*
11867dd7cddfSDavid du Colombier * If there's a device specific routine it must
11877dd7cddfSDavid du Colombier * provide all information pertaining to night geometry
11887dd7cddfSDavid du Colombier * and the garscadden trains.
11897dd7cddfSDavid du Colombier */
11907dd7cddfSDavid du Colombier if(unit->dev->ifc->rctl)
11914de34a7eSDavid du Colombier l += unit->dev->ifc->rctl(unit, p+l, m-l);
1192223a736eSDavid du Colombier if(unit->sectors == 0)
1193223a736eSDavid du Colombier sdinitpart(unit);
1194223a736eSDavid du Colombier if(unit->sectors){
11957dd7cddfSDavid du Colombier if(unit->dev->ifc->rctl == nil)
11964de34a7eSDavid du Colombier l += snprint(p+l, m-l,
119717629263SDavid du Colombier "geometry %llud %lud\n",
11987dd7cddfSDavid du Colombier unit->sectors, unit->secsize);
11997dd7cddfSDavid du Colombier pp = unit->part;
120059cc4ca5SDavid du Colombier for(i = 0; i < unit->npart; i++){
12017dd7cddfSDavid du Colombier if(pp->valid)
12024de34a7eSDavid du Colombier l += snprint(p+l, m-l,
120317629263SDavid du Colombier "part %s %llud %llud\n",
12049a747e4fSDavid du Colombier pp->name, pp->start, pp->end);
12057dd7cddfSDavid du Colombier pp++;
12067dd7cddfSDavid du Colombier }
12077dd7cddfSDavid du Colombier }
12087dd7cddfSDavid du Colombier qunlock(&unit->ctl);
12099a747e4fSDavid du Colombier decref(&sdev->r);
12107dd7cddfSDavid du Colombier l = readstr(offset, a, n, p);
12117dd7cddfSDavid du Colombier free(p);
12127dd7cddfSDavid du Colombier return l;
12139a747e4fSDavid du Colombier
12147dd7cddfSDavid du Colombier case Qraw:
12159a747e4fSDavid du Colombier sdev = sdgetdev(DEV(c->qid));
12169a747e4fSDavid du Colombier if(sdev == nil)
12179a747e4fSDavid du Colombier error(Enonexist);
12189a747e4fSDavid du Colombier
12199a747e4fSDavid du Colombier unit = sdev->unit[UNIT(c->qid)];
122080ee5cbfSDavid du Colombier qlock(&unit->raw);
122180ee5cbfSDavid du Colombier if(waserror()){
122280ee5cbfSDavid du Colombier qunlock(&unit->raw);
12239a747e4fSDavid du Colombier decref(&sdev->r);
122480ee5cbfSDavid du Colombier nexterror();
122580ee5cbfSDavid du Colombier }
12267dd7cddfSDavid du Colombier if(unit->state == Rawdata){
12277dd7cddfSDavid du Colombier unit->state = Rawstatus;
122880ee5cbfSDavid du Colombier i = sdrio(unit->req, a, n);
12297dd7cddfSDavid du Colombier }
12307dd7cddfSDavid du Colombier else if(unit->state == Rawstatus){
12317dd7cddfSDavid du Colombier status = unit->req->status;
12327dd7cddfSDavid du Colombier unit->state = Rawcmd;
12337dd7cddfSDavid du Colombier free(unit->req);
12347dd7cddfSDavid du Colombier unit->req = nil;
123580ee5cbfSDavid du Colombier i = readnum(0, a, n, status, NUMSIZE);
123680ee5cbfSDavid du Colombier } else
123780ee5cbfSDavid du Colombier i = 0;
123880ee5cbfSDavid du Colombier qunlock(&unit->raw);
12399a747e4fSDavid du Colombier decref(&sdev->r);
124080ee5cbfSDavid du Colombier poperror();
124180ee5cbfSDavid du Colombier return i;
12429a747e4fSDavid du Colombier
12437dd7cddfSDavid du Colombier case Qpart:
12447dd7cddfSDavid du Colombier return sdbio(c, 0, a, n, off);
12457dd7cddfSDavid du Colombier }
12467dd7cddfSDavid du Colombier }
12477dd7cddfSDavid du Colombier
12484de34a7eSDavid du Colombier static void legacytopctl(Cmdbuf*);
12499a747e4fSDavid du Colombier
12507dd7cddfSDavid du Colombier static long
sdwrite(Chan * c,void * a,long n,vlong off)12517dd7cddfSDavid du Colombier sdwrite(Chan* c, void* a, long n, vlong off)
12527dd7cddfSDavid du Colombier {
12534de34a7eSDavid du Colombier char *f0;
12544de34a7eSDavid du Colombier int i;
125517629263SDavid du Colombier uvlong end, start;
12567dd7cddfSDavid du Colombier Cmdbuf *cb;
12574de34a7eSDavid du Colombier SDifc *ifc;
12587dd7cddfSDavid du Colombier SDreq *req;
12597dd7cddfSDavid du Colombier SDunit *unit;
12609a747e4fSDavid du Colombier SDev *sdev;
12617dd7cddfSDavid du Colombier
12627dd7cddfSDavid du Colombier switch(TYPE(c->qid)){
12637dd7cddfSDavid du Colombier default:
12647dd7cddfSDavid du Colombier error(Eperm);
12654de34a7eSDavid du Colombier case Qtopctl:
12664de34a7eSDavid du Colombier cb = parsecmd(a, n);
12674de34a7eSDavid du Colombier if(waserror()){
12684de34a7eSDavid du Colombier free(cb);
12694de34a7eSDavid du Colombier nexterror();
12709a747e4fSDavid du Colombier }
12714de34a7eSDavid du Colombier if(cb->nf == 0)
12724de34a7eSDavid du Colombier error("empty control message");
12734de34a7eSDavid du Colombier f0 = cb->f[0];
12744de34a7eSDavid du Colombier cb->f++;
12754de34a7eSDavid du Colombier cb->nf--;
12764de34a7eSDavid du Colombier if(strcmp(f0, "config") == 0){
12774de34a7eSDavid du Colombier /* wormhole into ugly legacy interface */
12784de34a7eSDavid du Colombier legacytopctl(cb);
12794de34a7eSDavid du Colombier poperror();
12804de34a7eSDavid du Colombier free(cb);
12819a747e4fSDavid du Colombier break;
12829a747e4fSDavid du Colombier }
1283d649fdd7SDavid du Colombier /*
1284d649fdd7SDavid du Colombier * "ata arg..." invokes sdifc[i]->wtopctl(nil, cb),
1285d649fdd7SDavid du Colombier * where sdifc[i]->name=="ata" and cb contains the args.
1286d649fdd7SDavid du Colombier */
12874de34a7eSDavid du Colombier ifc = nil;
12884de34a7eSDavid du Colombier sdev = nil;
12894de34a7eSDavid du Colombier for(i=0; sdifc[i]; i++){
12904de34a7eSDavid du Colombier if(strcmp(sdifc[i]->name, f0) == 0){
12914de34a7eSDavid du Colombier ifc = sdifc[i];
12924de34a7eSDavid du Colombier sdev = nil;
12934de34a7eSDavid du Colombier goto subtopctl;
12944de34a7eSDavid du Colombier }
12954de34a7eSDavid du Colombier }
1296d649fdd7SDavid du Colombier /*
1297d649fdd7SDavid du Colombier * "sd1 arg..." invokes sdifc[i]->wtopctl(sdev, cb),
1298d649fdd7SDavid du Colombier * where sdifc[i] and sdev match controller letter "1",
1299d649fdd7SDavid du Colombier * and cb contains the args.
1300d649fdd7SDavid du Colombier */
13014de34a7eSDavid du Colombier if(f0[0]=='s' && f0[1]=='d' && f0[2] && f0[3] == 0){
13024de34a7eSDavid du Colombier if((sdev = sdgetdev(f0[2])) != nil){
13034de34a7eSDavid du Colombier ifc = sdev->ifc;
13044de34a7eSDavid du Colombier goto subtopctl;
13054de34a7eSDavid du Colombier }
13064de34a7eSDavid du Colombier }
13074de34a7eSDavid du Colombier error("unknown interface");
13084de34a7eSDavid du Colombier
13094de34a7eSDavid du Colombier subtopctl:
13104de34a7eSDavid du Colombier if(waserror()){
13114de34a7eSDavid du Colombier if(sdev)
13124de34a7eSDavid du Colombier decref(&sdev->r);
13134de34a7eSDavid du Colombier nexterror();
13144de34a7eSDavid du Colombier }
13154de34a7eSDavid du Colombier if(ifc->wtopctl)
13164de34a7eSDavid du Colombier ifc->wtopctl(sdev, cb);
13174de34a7eSDavid du Colombier else
13184de34a7eSDavid du Colombier error(Ebadctl);
13194de34a7eSDavid du Colombier poperror();
13204de34a7eSDavid du Colombier poperror();
13219e8a50a9SDavid du Colombier if (sdev)
13224de34a7eSDavid du Colombier decref(&sdev->r);
13234de34a7eSDavid du Colombier free(cb);
13244de34a7eSDavid du Colombier break;
13254de34a7eSDavid du Colombier
13267dd7cddfSDavid du Colombier case Qctl:
13277dd7cddfSDavid du Colombier cb = parsecmd(a, n);
13289a747e4fSDavid du Colombier sdev = sdgetdev(DEV(c->qid));
13299a747e4fSDavid du Colombier if(sdev == nil)
13309a747e4fSDavid du Colombier error(Enonexist);
13319a747e4fSDavid du Colombier unit = sdev->unit[UNIT(c->qid)];
13327dd7cddfSDavid du Colombier
13337dd7cddfSDavid du Colombier qlock(&unit->ctl);
13347dd7cddfSDavid du Colombier if(waserror()){
13357dd7cddfSDavid du Colombier qunlock(&unit->ctl);
13369a747e4fSDavid du Colombier decref(&sdev->r);
13377dd7cddfSDavid du Colombier free(cb);
13387dd7cddfSDavid du Colombier nexterror();
13397dd7cddfSDavid du Colombier }
1340223a736eSDavid du Colombier if(unit->vers != c->qid.vers)
13414de34a7eSDavid du Colombier error(Echange);
13427dd7cddfSDavid du Colombier
13437dd7cddfSDavid du Colombier if(cb->nf < 1)
13447dd7cddfSDavid du Colombier error(Ebadctl);
13457dd7cddfSDavid du Colombier if(strcmp(cb->f[0], "part") == 0){
1346223a736eSDavid du Colombier if(cb->nf != 4)
13477dd7cddfSDavid du Colombier error(Ebadctl);
13487dd7cddfSDavid du Colombier if(unit->sectors == 0 && !sdinitpart(unit))
13497dd7cddfSDavid du Colombier error(Eio);
135017629263SDavid du Colombier start = strtoull(cb->f[2], 0, 0);
135117629263SDavid du Colombier end = strtoull(cb->f[3], 0, 0);
13527dd7cddfSDavid du Colombier sdaddpart(unit, cb->f[1], start, end);
13537dd7cddfSDavid du Colombier }
13547dd7cddfSDavid du Colombier else if(strcmp(cb->f[0], "delpart") == 0){
13557dd7cddfSDavid du Colombier if(cb->nf != 2 || unit->part == nil)
13567dd7cddfSDavid du Colombier error(Ebadctl);
13577dd7cddfSDavid du Colombier sddelpart(unit, cb->f[1]);
13587dd7cddfSDavid du Colombier }
13597dd7cddfSDavid du Colombier else if(unit->dev->ifc->wctl)
13607dd7cddfSDavid du Colombier unit->dev->ifc->wctl(unit, cb);
13617dd7cddfSDavid du Colombier else
13627dd7cddfSDavid du Colombier error(Ebadctl);
13637dd7cddfSDavid du Colombier qunlock(&unit->ctl);
13649a747e4fSDavid du Colombier decref(&sdev->r);
13657dd7cddfSDavid du Colombier poperror();
13667dd7cddfSDavid du Colombier free(cb);
13677dd7cddfSDavid du Colombier break;
13687dd7cddfSDavid du Colombier
13697dd7cddfSDavid du Colombier case Qraw:
13709a747e4fSDavid du Colombier sdev = sdgetdev(DEV(c->qid));
13719a747e4fSDavid du Colombier if(sdev == nil)
13729a747e4fSDavid du Colombier error(Enonexist);
13739a747e4fSDavid du Colombier unit = sdev->unit[UNIT(c->qid)];
137480ee5cbfSDavid du Colombier qlock(&unit->raw);
137580ee5cbfSDavid du Colombier if(waserror()){
137680ee5cbfSDavid du Colombier qunlock(&unit->raw);
13779a747e4fSDavid du Colombier decref(&sdev->r);
137880ee5cbfSDavid du Colombier nexterror();
137980ee5cbfSDavid du Colombier }
13807dd7cddfSDavid du Colombier switch(unit->state){
13817dd7cddfSDavid du Colombier case Rawcmd:
13827dd7cddfSDavid du Colombier if(n < 6 || n > sizeof(req->cmd))
13837dd7cddfSDavid du Colombier error(Ebadarg);
13847dd7cddfSDavid du Colombier if((req = malloc(sizeof(SDreq))) == nil)
13857dd7cddfSDavid du Colombier error(Enomem);
13867dd7cddfSDavid du Colombier req->unit = unit;
13877dd7cddfSDavid du Colombier memmove(req->cmd, a, n);
13887dd7cddfSDavid du Colombier req->clen = n;
13897dd7cddfSDavid du Colombier req->flags = SDnosense;
13907dd7cddfSDavid du Colombier req->status = ~0;
13917dd7cddfSDavid du Colombier
13927dd7cddfSDavid du Colombier unit->req = req;
13937dd7cddfSDavid du Colombier unit->state = Rawdata;
13947dd7cddfSDavid du Colombier break;
13957dd7cddfSDavid du Colombier
13967dd7cddfSDavid du Colombier case Rawstatus:
13977dd7cddfSDavid du Colombier unit->state = Rawcmd;
13987dd7cddfSDavid du Colombier free(unit->req);
13997dd7cddfSDavid du Colombier unit->req = nil;
14007dd7cddfSDavid du Colombier error(Ebadusefd);
14017dd7cddfSDavid du Colombier
14027dd7cddfSDavid du Colombier case Rawdata:
14037dd7cddfSDavid du Colombier unit->state = Rawstatus;
14047dd7cddfSDavid du Colombier unit->req->write = 1;
140580ee5cbfSDavid du Colombier n = sdrio(unit->req, a, n);
14067dd7cddfSDavid du Colombier }
140780ee5cbfSDavid du Colombier qunlock(&unit->raw);
14089a747e4fSDavid du Colombier decref(&sdev->r);
140980ee5cbfSDavid du Colombier poperror();
14109a747e4fSDavid du Colombier break;
14117dd7cddfSDavid du Colombier case Qpart:
14127dd7cddfSDavid du Colombier return sdbio(c, 1, a, n, off);
14137dd7cddfSDavid du Colombier }
14147dd7cddfSDavid du Colombier
14157dd7cddfSDavid du Colombier return n;
14167dd7cddfSDavid du Colombier }
14177dd7cddfSDavid du Colombier
14189a747e4fSDavid du Colombier static int
sdwstat(Chan * c,uchar * dp,int n)14199a747e4fSDavid du Colombier sdwstat(Chan* c, uchar* dp, int n)
14207dd7cddfSDavid du Colombier {
14219a747e4fSDavid du Colombier Dir *d;
14227dd7cddfSDavid du Colombier SDpart *pp;
142359cc4ca5SDavid du Colombier SDperm *perm;
14247dd7cddfSDavid du Colombier SDunit *unit;
14259a747e4fSDavid du Colombier SDev *sdev;
14267dd7cddfSDavid du Colombier
14279a747e4fSDavid du Colombier if(c->qid.type & QTDIR)
14287dd7cddfSDavid du Colombier error(Eperm);
14297dd7cddfSDavid du Colombier
14309a747e4fSDavid du Colombier sdev = sdgetdev(DEV(c->qid));
14319a747e4fSDavid du Colombier if(sdev == nil)
14329a747e4fSDavid du Colombier error(Enonexist);
14339a747e4fSDavid du Colombier unit = sdev->unit[UNIT(c->qid)];
14347dd7cddfSDavid du Colombier qlock(&unit->ctl);
14359a747e4fSDavid du Colombier d = nil;
14367dd7cddfSDavid du Colombier if(waserror()){
14379a747e4fSDavid du Colombier free(d);
14387dd7cddfSDavid du Colombier qunlock(&unit->ctl);
14399a747e4fSDavid du Colombier decref(&sdev->r);
14407dd7cddfSDavid du Colombier nexterror();
14417dd7cddfSDavid du Colombier }
14427dd7cddfSDavid du Colombier
144359cc4ca5SDavid du Colombier switch(TYPE(c->qid)){
144459cc4ca5SDavid du Colombier default:
144559cc4ca5SDavid du Colombier error(Eperm);
144659cc4ca5SDavid du Colombier case Qctl:
144759cc4ca5SDavid du Colombier perm = &unit->ctlperm;
144859cc4ca5SDavid du Colombier break;
144959cc4ca5SDavid du Colombier case Qraw:
145059cc4ca5SDavid du Colombier perm = &unit->rawperm;
145159cc4ca5SDavid du Colombier break;
145259cc4ca5SDavid du Colombier case Qpart:
14537dd7cddfSDavid du Colombier pp = &unit->part[PART(c->qid)];
1454223a736eSDavid du Colombier if(unit->vers+pp->vers != c->qid.vers)
14557dd7cddfSDavid du Colombier error(Enonexist);
145659cc4ca5SDavid du Colombier perm = &pp->SDperm;
145759cc4ca5SDavid du Colombier break;
145859cc4ca5SDavid du Colombier }
14597dd7cddfSDavid du Colombier
14609a747e4fSDavid du Colombier if(strcmp(up->user, perm->user) && !iseve())
146159cc4ca5SDavid du Colombier error(Eperm);
14627dd7cddfSDavid du Colombier
14639a747e4fSDavid du Colombier d = smalloc(sizeof(Dir)+n);
14649a747e4fSDavid du Colombier n = convM2D(dp, n, &d[0], (char*)&d[1]);
14659a747e4fSDavid du Colombier if(n == 0)
14669a747e4fSDavid du Colombier error(Eshortstat);
14679a747e4fSDavid du Colombier if(!emptystr(d[0].uid))
14689a747e4fSDavid du Colombier kstrdup(&perm->user, d[0].uid);
14699a747e4fSDavid du Colombier if(d[0].mode != ~0UL)
14709a747e4fSDavid du Colombier perm->perm = (perm->perm & ~0777) | (d[0].mode & 0777);
14719a747e4fSDavid du Colombier
14729a747e4fSDavid du Colombier free(d);
14737dd7cddfSDavid du Colombier qunlock(&unit->ctl);
14749a747e4fSDavid du Colombier decref(&sdev->r);
14757dd7cddfSDavid du Colombier poperror();
14769a747e4fSDavid du Colombier return n;
14779a747e4fSDavid du Colombier }
14789a747e4fSDavid du Colombier
14799a747e4fSDavid du Colombier static int
configure(char * spec,DevConf * cf)14809a747e4fSDavid du Colombier configure(char* spec, DevConf* cf)
14819a747e4fSDavid du Colombier {
14824de34a7eSDavid du Colombier SDev *s, *sdev;
14834de34a7eSDavid du Colombier char *p;
14844de34a7eSDavid du Colombier int i;
14854de34a7eSDavid du Colombier
14864de34a7eSDavid du Colombier if(sdindex(*spec) < 0)
14874de34a7eSDavid du Colombier error("bad sd spec");
14889a747e4fSDavid du Colombier
14899a747e4fSDavid du Colombier if((p = strchr(cf->type, '/')) != nil)
14909a747e4fSDavid du Colombier *p++ = '\0';
14919a747e4fSDavid du Colombier
14929a747e4fSDavid du Colombier for(i = 0; sdifc[i] != nil; i++)
14934de34a7eSDavid du Colombier if(strcmp(sdifc[i]->name, cf->type) == 0)
14949a747e4fSDavid du Colombier break;
14959a747e4fSDavid du Colombier if(sdifc[i] == nil)
14964de34a7eSDavid du Colombier error("sd type not found");
14974de34a7eSDavid du Colombier if(p)
14984de34a7eSDavid du Colombier *(p-1) = '/';
14999a747e4fSDavid du Colombier
15004de34a7eSDavid du Colombier if(sdifc[i]->probe == nil)
15014de34a7eSDavid du Colombier error("sd type cannot probe");
15029a747e4fSDavid du Colombier
15034de34a7eSDavid du Colombier sdev = sdifc[i]->probe(cf);
15044de34a7eSDavid du Colombier for(s=sdev; s; s=s->next)
15054de34a7eSDavid du Colombier s->idno = *spec;
15064de34a7eSDavid du Colombier sdadddevs(sdev);
15079a747e4fSDavid du Colombier return 0;
15089a747e4fSDavid du Colombier }
15099a747e4fSDavid du Colombier
15109a747e4fSDavid du Colombier static int
unconfigure(char * spec)15119a747e4fSDavid du Colombier unconfigure(char* spec)
15129a747e4fSDavid du Colombier {
15139a747e4fSDavid du Colombier int i;
15149a747e4fSDavid du Colombier SDev *sdev;
15154de34a7eSDavid du Colombier SDunit *unit;
15169a747e4fSDavid du Colombier
15174de34a7eSDavid du Colombier if((i = sdindex(*spec)) < 0)
15189a747e4fSDavid du Colombier error(Enonexist);
15199a747e4fSDavid du Colombier
15204de34a7eSDavid du Colombier qlock(&devslock);
15214de34a7eSDavid du Colombier if((sdev = devs[i]) == nil){
15224de34a7eSDavid du Colombier qunlock(&devslock);
15234de34a7eSDavid du Colombier error(Enonexist);
15244de34a7eSDavid du Colombier }
15254de34a7eSDavid du Colombier if(sdev->r.ref){
15264de34a7eSDavid du Colombier qunlock(&devslock);
15279a747e4fSDavid du Colombier error(Einuse);
15284de34a7eSDavid du Colombier }
15294de34a7eSDavid du Colombier devs[i] = nil;
15304de34a7eSDavid du Colombier qunlock(&devslock);
15319a747e4fSDavid du Colombier
15329a747e4fSDavid du Colombier /* make sure no interrupts arrive anymore before removing resources */
15339a747e4fSDavid du Colombier if(sdev->enabled && sdev->ifc->disable)
15349a747e4fSDavid du Colombier sdev->ifc->disable(sdev);
15359a747e4fSDavid du Colombier
15364de34a7eSDavid du Colombier for(i = 0; i != sdev->nunit; i++){
15374de34a7eSDavid du Colombier if(unit = sdev->unit[i]){
15389a747e4fSDavid du Colombier free(unit->name);
15399a747e4fSDavid du Colombier free(unit->user);
15409a747e4fSDavid du Colombier free(unit);
15419a747e4fSDavid du Colombier }
15424de34a7eSDavid du Colombier }
15439a747e4fSDavid du Colombier
15449a747e4fSDavid du Colombier if(sdev->ifc->clear)
15459a747e4fSDavid du Colombier sdev->ifc->clear(sdev);
15464de34a7eSDavid du Colombier free(sdev);
15479a747e4fSDavid du Colombier return 0;
15489a747e4fSDavid du Colombier }
15499a747e4fSDavid du Colombier
15509a747e4fSDavid du Colombier static int
sdconfig(int on,char * spec,DevConf * cf)15519a747e4fSDavid du Colombier sdconfig(int on, char* spec, DevConf* cf)
15529a747e4fSDavid du Colombier {
15539a747e4fSDavid du Colombier if(on)
15549a747e4fSDavid du Colombier return configure(spec, cf);
15559a747e4fSDavid du Colombier return unconfigure(spec);
15567dd7cddfSDavid du Colombier }
15577dd7cddfSDavid du Colombier
15587dd7cddfSDavid du Colombier Dev sddevtab = {
15597dd7cddfSDavid du Colombier 'S',
15607dd7cddfSDavid du Colombier "sd",
15617dd7cddfSDavid du Colombier
15627dd7cddfSDavid du Colombier sdreset,
15637dd7cddfSDavid du Colombier devinit,
15649a747e4fSDavid du Colombier devshutdown,
15657dd7cddfSDavid du Colombier sdattach,
15667dd7cddfSDavid du Colombier sdwalk,
15677dd7cddfSDavid du Colombier sdstat,
15687dd7cddfSDavid du Colombier sdopen,
15697dd7cddfSDavid du Colombier devcreate,
15707dd7cddfSDavid du Colombier sdclose,
15717dd7cddfSDavid du Colombier sdread,
15727dd7cddfSDavid du Colombier devbread,
15737dd7cddfSDavid du Colombier sdwrite,
15747dd7cddfSDavid du Colombier devbwrite,
15757dd7cddfSDavid du Colombier devremove,
15767dd7cddfSDavid du Colombier sdwstat,
15779a747e4fSDavid du Colombier devpower,
1578aa72973aSDavid du Colombier sdconfig, /* probe; only called for pcmcia-like devices */
15797dd7cddfSDavid du Colombier };
15804de34a7eSDavid du Colombier
15814de34a7eSDavid du Colombier /*
15824de34a7eSDavid du Colombier * This is wrong for so many reasons. This code must go.
15834de34a7eSDavid du Colombier */
15844de34a7eSDavid du Colombier typedef struct Confdata Confdata;
15854de34a7eSDavid du Colombier struct Confdata {
15864de34a7eSDavid du Colombier int on;
15874de34a7eSDavid du Colombier char* spec;
15884de34a7eSDavid du Colombier DevConf cf;
15894de34a7eSDavid du Colombier };
15904de34a7eSDavid du Colombier
15914de34a7eSDavid du Colombier static void
parseswitch(Confdata * cd,char * option)15924de34a7eSDavid du Colombier parseswitch(Confdata* cd, char* option)
15934de34a7eSDavid du Colombier {
15944de34a7eSDavid du Colombier if(!strcmp("on", option))
15954de34a7eSDavid du Colombier cd->on = 1;
15964de34a7eSDavid du Colombier else if(!strcmp("off", option))
15974de34a7eSDavid du Colombier cd->on = 0;
15984de34a7eSDavid du Colombier else
15994de34a7eSDavid du Colombier error(Ebadarg);
16004de34a7eSDavid du Colombier }
16014de34a7eSDavid du Colombier
16024de34a7eSDavid du Colombier static void
parsespec(Confdata * cd,char * option)16034de34a7eSDavid du Colombier parsespec(Confdata* cd, char* option)
16044de34a7eSDavid du Colombier {
16054de34a7eSDavid du Colombier if(strlen(option) > 1)
16064de34a7eSDavid du Colombier error(Ebadarg);
16074de34a7eSDavid du Colombier cd->spec = option;
16084de34a7eSDavid du Colombier }
16094de34a7eSDavid du Colombier
16104de34a7eSDavid du Colombier static Devport*
getnewport(DevConf * dc)16114de34a7eSDavid du Colombier getnewport(DevConf* dc)
16124de34a7eSDavid du Colombier {
16134de34a7eSDavid du Colombier Devport *p;
16144de34a7eSDavid du Colombier
16154de34a7eSDavid du Colombier p = (Devport *)malloc((dc->nports + 1) * sizeof(Devport));
1616aa72973aSDavid du Colombier if(p == nil)
1617aa72973aSDavid du Colombier error(Enomem);
16184de34a7eSDavid du Colombier if(dc->nports > 0){
16194de34a7eSDavid du Colombier memmove(p, dc->ports, dc->nports * sizeof(Devport));
16204de34a7eSDavid du Colombier free(dc->ports);
16214de34a7eSDavid du Colombier }
16224de34a7eSDavid du Colombier dc->ports = p;
16234de34a7eSDavid du Colombier p = &dc->ports[dc->nports++];
16244de34a7eSDavid du Colombier p->size = -1;
16254de34a7eSDavid du Colombier p->port = (ulong)-1;
16264de34a7eSDavid du Colombier return p;
16274de34a7eSDavid du Colombier }
16284de34a7eSDavid du Colombier
16294de34a7eSDavid du Colombier static void
parseport(Confdata * cd,char * option)16304de34a7eSDavid du Colombier parseport(Confdata* cd, char* option)
16314de34a7eSDavid du Colombier {
16324de34a7eSDavid du Colombier char *e;
16334de34a7eSDavid du Colombier Devport *p;
16344de34a7eSDavid du Colombier
16354de34a7eSDavid du Colombier if(cd->cf.nports == 0 || cd->cf.ports[cd->cf.nports-1].port != (ulong)-1)
16364de34a7eSDavid du Colombier p = getnewport(&cd->cf);
16374de34a7eSDavid du Colombier else
16384de34a7eSDavid du Colombier p = &cd->cf.ports[cd->cf.nports-1];
16394de34a7eSDavid du Colombier p->port = strtol(option, &e, 0);
16404de34a7eSDavid du Colombier if(e == nil || *e != '\0')
16414de34a7eSDavid du Colombier error(Ebadarg);
16424de34a7eSDavid du Colombier }
16434de34a7eSDavid du Colombier
16444de34a7eSDavid du Colombier static void
parsesize(Confdata * cd,char * option)16454de34a7eSDavid du Colombier parsesize(Confdata* cd, char* option)
16464de34a7eSDavid du Colombier {
16474de34a7eSDavid du Colombier char *e;
16484de34a7eSDavid du Colombier Devport *p;
16494de34a7eSDavid du Colombier
16504de34a7eSDavid du Colombier if(cd->cf.nports == 0 || cd->cf.ports[cd->cf.nports-1].size != -1)
16514de34a7eSDavid du Colombier p = getnewport(&cd->cf);
16524de34a7eSDavid du Colombier else
16534de34a7eSDavid du Colombier p = &cd->cf.ports[cd->cf.nports-1];
16544de34a7eSDavid du Colombier p->size = (int)strtol(option, &e, 0);
16554de34a7eSDavid du Colombier if(e == nil || *e != '\0')
16564de34a7eSDavid du Colombier error(Ebadarg);
16574de34a7eSDavid du Colombier }
16584de34a7eSDavid du Colombier
16594de34a7eSDavid du Colombier static void
parseirq(Confdata * cd,char * option)16604de34a7eSDavid du Colombier parseirq(Confdata* cd, char* option)
16614de34a7eSDavid du Colombier {
16624de34a7eSDavid du Colombier char *e;
16634de34a7eSDavid du Colombier
16644de34a7eSDavid du Colombier cd->cf.intnum = strtoul(option, &e, 0);
16654de34a7eSDavid du Colombier if(e == nil || *e != '\0')
16664de34a7eSDavid du Colombier error(Ebadarg);
16674de34a7eSDavid du Colombier }
16684de34a7eSDavid du Colombier
16694de34a7eSDavid du Colombier static void
parsetype(Confdata * cd,char * option)16704de34a7eSDavid du Colombier parsetype(Confdata* cd, char* option)
16714de34a7eSDavid du Colombier {
16724de34a7eSDavid du Colombier cd->cf.type = option;
16734de34a7eSDavid du Colombier }
16744de34a7eSDavid du Colombier
16754de34a7eSDavid du Colombier static struct {
16764de34a7eSDavid du Colombier char *name;
16774de34a7eSDavid du Colombier void (*parse)(Confdata*, char*);
16784de34a7eSDavid du Colombier } options[] = {
16794de34a7eSDavid du Colombier "switch", parseswitch,
16804de34a7eSDavid du Colombier "spec", parsespec,
16814de34a7eSDavid du Colombier "port", parseport,
16824de34a7eSDavid du Colombier "size", parsesize,
16834de34a7eSDavid du Colombier "irq", parseirq,
16844de34a7eSDavid du Colombier "type", parsetype,
16854de34a7eSDavid du Colombier };
16864de34a7eSDavid du Colombier
16874de34a7eSDavid du Colombier static void
legacytopctl(Cmdbuf * cb)16884de34a7eSDavid du Colombier legacytopctl(Cmdbuf *cb)
16894de34a7eSDavid du Colombier {
16904de34a7eSDavid du Colombier char *opt;
16914de34a7eSDavid du Colombier int i, j;
16924de34a7eSDavid du Colombier Confdata cd;
16934de34a7eSDavid du Colombier
16944de34a7eSDavid du Colombier memset(&cd, 0, sizeof cd);
16954de34a7eSDavid du Colombier cd.on = -1;
16964de34a7eSDavid du Colombier for(i=0; i<cb->nf; i+=2){
16974de34a7eSDavid du Colombier if(i+2 > cb->nf)
16984de34a7eSDavid du Colombier error(Ebadarg);
16994de34a7eSDavid du Colombier opt = cb->f[i];
17004de34a7eSDavid du Colombier for(j=0; j<nelem(options); j++)
17014de34a7eSDavid du Colombier if(strcmp(opt, options[j].name) == 0){
17024de34a7eSDavid du Colombier options[j].parse(&cd, cb->f[i+1]);
17034de34a7eSDavid du Colombier break;
17044de34a7eSDavid du Colombier }
17054de34a7eSDavid du Colombier if(j == nelem(options))
17064de34a7eSDavid du Colombier error(Ebadarg);
17074de34a7eSDavid du Colombier }
1708479935bcSDavid du Colombier /* this has been rewritten to accomodate sdaoe */
1709479935bcSDavid du Colombier if(cd.on < 0 || cd.spec == 0)
17104de34a7eSDavid du Colombier error(Ebadarg);
1711479935bcSDavid du Colombier if(cd.on && cd.cf.type == nil)
17124de34a7eSDavid du Colombier error(Ebadarg);
17134de34a7eSDavid du Colombier sdconfig(cd.on, cd.spec, &cd.cf);
17144de34a7eSDavid du Colombier }
1715