123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631 |
- /*
- * Storage Device.
- */
- #include "u.h"
- #include "mem.h"
- #include "lib.h"
- #include "dat.h"
- #include "fns.h"
- #include "io.h"
- #include "ureg.h"
- #include "error.h"
- #include "sd.h"
- #include "fs.h"
- #define parttrace 0
- extern SDifc* sdifc[];
- static SDev* sdlist;
- static SDunit** sdunit;
- static int sdnunit;
- static int _sdmask;
- static int cdmask;
- static int sdmask;
- enum {
- Rawcmd,
- Rawdata,
- Rawstatus,
- };
- void
- sdaddpart(SDunit* unit, char* name, uvlong start, uvlong end)
- {
- SDpart *pp;
- int i, partno;
- if(parttrace)
- print("add %d %s %s %lld %lld\n", unit->npart, unit->name, name, start, end);
- /*
- * Check name not already used
- * and look for a free slot.
- */
- if(unit->part != nil){
- partno = -1;
- for(i = 0; i < SDnpart; i++){
- pp = &unit->part[i];
- if(!pp->valid){
- if(partno == -1)
- partno = i;
- break;
- }
- if(strcmp(name, pp->name) == 0){
- if(pp->start == start && pp->end == end){
- if(parttrace)
- print("already present\n");
- return;
- }
- }
- }
- }else{
- if((unit->part = malloc(sizeof(SDpart)*SDnpart)) == nil){
- if(parttrace)
- print("malloc failed\n");
- return;
- }
- partno = 0;
- }
- /*
- * Check there is a free slot and size and extent are valid.
- */
- if(partno == -1 || start > end || end > unit->sectors){
- print("cannot add %s!%s [%llud,%llud) to disk [0,%llud): %s\n",
- unit->name, name, start, end, unit->sectors,
- partno==-1 ? "no free partitions" : "partition boundaries out of range");
- return;
- }
- pp = &unit->part[partno];
- pp->start = start;
- pp->end = end;
- strncpy(pp->name, name, NAMELEN);
- pp->valid = 1;
- unit->npart++;
- }
- void
- sddelpart(SDunit* unit, char* name)
- {
- int i;
- SDpart *pp;
- if(parttrace)
- print("del %d %s %s\n", unit->npart, unit->name, name);
- /*
- * Look for the partition to delete.
- * Can't delete if someone still has it open.
- * If it's the last valid partition zap the
- * whole table.
- */
- pp = unit->part;
- for(i = 0; i < SDnpart; i++){
- if(strncmp(name, pp->name, NAMELEN) == 0)
- break;
- pp++;
- }
- if(i >= SDnpart)
- return;
- pp->valid = 0;
- unit->npart--;
- if(unit->npart == 0){
- free(unit->part);
- unit->part = nil;
- }
- }
- static int
- sdinitpart(SDunit* unit)
- {
- unit->sectors = unit->secsize = 0;
- unit->npart = 0;
- if(unit->part){
- free(unit->part);
- unit->part = nil;
- }
- if(unit->inquiry[0] & 0xC0)
- return 0;
- switch(unit->inquiry[0] & 0x1F){
- case 0x00: /* DA */
- case 0x04: /* WORM */
- case 0x05: /* CD-ROM */
- case 0x07: /* MO */
- break;
- default:
- return 0;
- }
- if(unit->dev->ifc->online == nil || unit->dev->ifc->online(unit) == 0)
- return 0;
- sdaddpart(unit, "data", 0, unit->sectors);
- return 1;
- }
- static SDunit*
- sdgetunit(SDev* sdev, int subno)
- {
- int index;
- SDunit *unit;
- /*
- * Associate a unit with a given device and sub-unit
- * number on that device.
- * The device will be probed if it has not already been
- * successfully accessed.
- */
- qlock(&sdqlock);
- index = sdev->index+subno;
- unit = sdunit[index];
- if(unit == nil){
- if((unit = malloc(sizeof(SDunit))) == nil){
- qunlock(&sdqlock);
- return nil;
- }
- if(sdev->enabled == 0 && sdev->ifc->enable)
- sdev->ifc->enable(sdev);
- sdev->enabled = 1;
- snprint(unit->name, NAMELEN, "sd%c%d", sdev->idno, subno);
- unit->subno = subno;
- unit->dev = sdev;
- /*
- * No need to lock anything here as this is only
- * called before the unit is made available in the
- * sdunit[] array.
- */
- if(unit->dev->ifc->verify(unit) == 0){
- qunlock(&sdqlock);
- free(unit);
- return nil;
- }
- sdunit[index] = unit;
- }
- qunlock(&sdqlock);
- return unit;
- }
- static SDunit*
- sdindex2unit(int index)
- {
- SDev *sdev;
- /*
- * Associate a unit with a given index into the top-level
- * device directory.
- * The device will be probed if it has not already been
- * successfully accessed.
- */
- for(sdev = sdlist; sdev != nil; sdev = sdev->next){
- if(index >= sdev->index && index < sdev->index+sdev->nunit)
- return sdgetunit(sdev, index-sdev->index);
- }
- return nil;
- }
- static void
- _sddetach(void)
- {
- SDev *sdev;
- for(sdev = sdlist; sdev != nil; sdev = sdev->next){
- if(sdev->enabled == 0)
- continue;
- if(sdev->ifc->disable)
- sdev->ifc->disable(sdev);
- sdev->enabled = 0;
- }
- }
- static void
- sddump(void)
- {
- SDev *sdev;
- print("sdevs:\n");
- for(sdev = sdlist; sdev != nil; sdev = sdev->next){
- print("sdev %c index %d nunit %d: ",
- sdev->idno, sdev->index, sdev->nunit);
- print("\n");
- }
- }
- static int
- _sdinit(void)
- {
- ulong m;
- int i;
- SDev *sdev, *tail;
- SDunit *unit;
- /*
- * Probe all configured controllers and make a list
- * of devices found, accumulating a possible maximum number
- * of units attached and marking each device with an index
- * into the linear top-level directory array of units.
- */
- tail = nil;
- for(i = 0; sdifc[i] != nil; i++){
- if((sdev = sdifc[i]->pnp()) == nil)
- continue;
- if(sdlist != nil)
- tail->next = sdev;
- else
- sdlist = sdev;
- for(tail = sdev; tail->next != nil; tail = tail->next){
- tail->index = sdnunit;
- sdnunit += tail->nunit;
- }
- tail->index = sdnunit;
- sdnunit += tail->nunit;
- }
- /*
- * Legacy and option code goes here. This will be hard...
- */
- /*
- * The maximum number of possible units is known, allocate
- * placeholders for their datastructures; the units will be
- * probed and structures allocated when attached.
- * Allocate controller names for the different types.
- */
- if(sdnunit == 0)
- return 0;
- if((sdunit = malloc(sdnunit*sizeof(SDunit*))) == nil)
- return 0;
- sddetach = _sddetach;
- for(i = 0; sdifc[i] != nil; i++){
- if(sdifc[i]->id)
- sdifc[i]->id(sdlist);
- }
- if (0)
- sddump();
- m = 0;
- cdmask = sdmask = 0;
- for(i=0; i<sdnunit && i < 32; i++) {
- unit = sdindex2unit(i);
- if(unit == nil)
- continue;
- sdinitpart(unit);
- partition(unit);
- if(unit->npart > 0){ /* BUG */
- if((unit->inquiry[0] & 0x1F) == 0x05)
- cdmask |= (1<<i);
- else
- sdmask |= (1<<i);
- m |= (1<<i);
- }
- }
- //notesdinfo();
- _sdmask = m;
- return m;
- }
- int
- cdinit(void)
- {
- if(sdnunit == 0)
- _sdinit();
- return cdmask;
- }
- int
- sdinit(void)
- {
- if(sdnunit == 0)
- _sdinit();
- return sdmask;
- }
- void
- sdinitdev(int i, char *s)
- {
- SDunit *unit;
- unit = sdindex2unit(i);
- strcpy(s, unit->name);
- }
- void
- sdprintdevs(int i)
- {
- char *s;
- SDunit *unit;
- unit = sdindex2unit(i);
- for(i=0; i<unit->npart; i++){
- s = unit->part[i].name;
- if(strncmp(s, "dos", 3) == 0
- || strncmp(s, "9fat", 4) == 0
- || strncmp(s, "fs", 2) == 0)
- print(" %s!%s", unit->name, s);
- }
- }
- SDpart*
- sdfindpart(SDunit *unit, char *name)
- {
- int i;
- if(parttrace)
- print("findpart %d %s %s\t\n", unit->npart, unit->name, name);
- for(i=0; i<unit->npart; i++) {
- if(parttrace)
- print("%s...", unit->part[i].name);
- if(strcmp(unit->part[i].name, name) == 0){
- if(parttrace)
- print("\n");
- return &unit->part[i];
- }
- }
- if(parttrace)
- print("not found\n");
- return nil;
- }
- typedef struct Scsicrud Scsicrud;
- struct Scsicrud {
- Fs fs;
- vlong offset;
- SDunit *unit;
- SDpart *part;
- };
- long
- sdread(Fs *vcrud, void *v, long n)
- {
- Scsicrud *crud;
- long x;
- crud = (Scsicrud*)vcrud;
- x = sdbio(crud->unit, crud->part, v, n, crud->offset);
- if(x > 0)
- crud->offset += x;
- return x;
- }
- vlong
- sdseek(Fs *vcrud, vlong seek)
- {
- ((Scsicrud*)vcrud)->offset = seek;
- return seek;
- }
- void*
- sdgetfspart(int i, char *s, int chatty)
- {
- SDunit *unit;
- SDpart *p;
- Scsicrud *crud;
- if(cdmask&(1<<i)){
- if(strcmp(s, "cdboot") != 0)
- return nil;
- }else if(sdmask&(1<<i)){
- if(strcmp(s, "cdboot") == 0)
- return nil;
- }
- unit = sdindex2unit(i);
- if((p = sdfindpart(unit, s)) == nil){
- if(chatty)
- print("unknown partition %s!%s\n", unit->name, s);
- return nil;
- }
- if(p->crud == nil) {
- crud = malloc(sizeof(Scsicrud));
- crud->fs.dev = i;
- crud->fs.diskread = sdread;
- crud->fs.diskseek = sdseek;
- // crud->start = 0;
- crud->unit = unit;
- crud->part = p;
- if(dosinit(&crud->fs) < 0 && dosinit(&crud->fs) < 0 && kfsinit(&crud->fs) < 0){
- if(chatty)
- print("partition %s!%s does not contain a DOS or KFS file system\n",
- unit->name, s);
- return nil;
- }
- p->crud = crud;
- }
- return p->crud;
- }
- /*
- * Leave partitions around for devsd to pick up.
- * (Needed by boot process; more extensive
- * partitioning is done by termrc or cpurc).
- */
- void
- sdaddconf(int i)
- {
- SDunit *unit;
- SDpart *pp;
- unit = sdindex2unit(i);
-
- /*
- * If there were no partitions (just data and partition), don't bother.
- */
- if(unit->npart<= 1 || (unit->npart==2 && strcmp(unit->part[1].name, "partition")==0))
- return;
- addconf("%spart=", unit->name);
- for(i=1, pp=&unit->part[i]; i<unit->npart; i++, pp++) /* skip 0, which is "data" */
- addconf("%s%s %lld %lld", i==1 ? "" : "/", pp->name,
- pp->start, pp->end);
- addconf("\n");
- }
- int
- sdboot(int dev, char *pname, Boot *b)
- {
- char *file;
- Fs *fs;
- if((file = strchr(pname, '!')) == nil) {
- print("syntax is sdC0!partition!file\n");
- return -1;
- }
- *file++ = '\0';
- fs = sdgetfspart(dev, pname, 1);
- if(fs == nil)
- return -1;
- return fsboot(fs, file, b);
- }
- long
- sdbio(SDunit *unit, SDpart *pp, void* va, long len, vlong off)
- {
- long l;
- ulong bno, max, nb, offset;
- static uchar *b;
- char *a;
- static ulong bsz;
- a = va;
- memset(a, 0xDA, len);
- qlock(&unit->ctl);
- if(unit->changed){
- qunlock(&unit->ctl);
- return 0;
- }
- /*
- * Check the request is within bounds.
- * Removeable drives are locked throughout the I/O
- * in case the media changes unexpectedly.
- * Non-removeable drives are not locked during the I/O
- * to allow the hardware to optimise if it can; this is
- * a little fast and loose.
- * It's assumed that non-removable media parameters
- * (sectors, secsize) can't change once the drive has
- * been brought online.
- */
- if (unit->secsize == 0)
- panic("sdbio: zero sector size");
- bno = (off/unit->secsize) + pp->start;
- nb = ((off+len+unit->secsize-1)/unit->secsize) + pp->start - bno;
- max = SDmaxio/unit->secsize;
- if(nb > max)
- nb = max;
- if(bno+nb > pp->end)
- nb = pp->end - bno;
- if(bno >= pp->end || nb == 0){
- qunlock(&unit->ctl);
- return 0;
- }
- if(!(unit->inquiry[1] & 0x80))
- qunlock(&unit->ctl);
- if(bsz < nb*unit->secsize){
- b = malloc(nb*unit->secsize);
- bsz = nb*unit->secsize;
- }
- // b = sdmalloc(nb*unit->secsize);
- // if(b == nil)
- // return 0;
- offset = off%unit->secsize;
- if((l = unit->dev->ifc->bio(unit, 0, 0, b, nb, bno)) < 0) {
- // sdfree(b);
- return 0;
- }
- if(l < offset)
- len = 0;
- else if(len > l - offset)
- len = l - offset;
- if(len)
- memmove(a, b+offset, len);
- // sdfree(b);
- if(unit->inquiry[1] & 0x80)
- qunlock(&unit->ctl);
- return len;
- }
- #ifdef DMA
- long
- sdrio(SDreq *r, void* a, long n)
- {
- if(n >= SDmaxio || n < 0)
- return 0;
- r->data = nil;
- if(n){
- if((r->data = malloc(n)) == nil)
- return 0;
- if(r->write)
- memmove(r->data, a, n);
- }
- r->dlen = n;
- if(r->unit->dev->ifc->rio(r) != SDok){
- // cgascreenputs("1", 1);
- if(r->data != nil){
- sdfree(r->data);
- r->data = nil;
- }
- return 0;
- }
- // cgascreenputs("2", 1);
- if(!r->write && r->rlen > 0)
- memmove(a, r->data, r->rlen);
- // cgascreenputs("3", 1);
- if(r->data != nil){
- sdfree(r->data);
- r->data = nil;
- }
- // cgascreenputs("4", 1);
- return r->rlen;
- }
- #endif /* DMA */
- void
- sleep(void*, int (*fn)(void*), void *v)
- {
- int x;
- x = spllo();
- while(!fn(v))
- ;
- splx(x);
- }
- void
- tsleep(void*, int (*fn)(void*), void *v, int msec)
- {
- int x;
- ulong start;
- x = spllo();
- for(start = m->ticks; TK2MS(m->ticks - start) < msec && !fn(v); )
- ;
- splx(x);
- }
- void*
- sdmalloc(void *p, ulong sz)
- {
- if(p != nil) {
- memset(p, 0, sz);
- return p;
- }
- return malloc(sz);
- }
|