/* * read-only sd driver for BIOS devices with partitions. * will probably only work with bootstrap kernels, as the normal kernel * deals directly with the clock and disk controllers, which seems * to confuse many BIOSes. * * devbios must be initialised first and no disks may be accessed * via non-BIOS means. */ #include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" #include "ureg.h" #include "pool.h" #include "../port/error.h" #include "../port/netif.h" #include "../port/sd.h" #include "dosfs.h" #include long biosread0(Bootfs *, void *, long); vlong biosseek(Bootfs *fs, vlong off); extern SDifc sdbiosifc; extern int biosndevs; uchar * putbeul(ulong ul, uchar *p) { *p++ = ul >> 24; *p++ = ul >> 16; *p++ = ul >> 8; *p++ = ul; return p; } uchar * putbeuvl(uvlong uvl, uchar *p) { *p++ = uvl >> 56; *p++ = uvl >> 48; *p++ = uvl >> 40; *p++ = uvl >> 32; *p++ = uvl >> 24; *p++ = uvl >> 16; *p++ = uvl >> 8; *p++ = uvl; return p; } int biosverify(SDunit* ) { if (!biosinited) return 0; return 1; } int biosonline(SDunit* unit) { uint subno = unit->subno; if (!biosinited) panic("sdbios: biosonline: sdbios not inited"); if (unit == nil) return 0; unit->secsize = biossectsz(subno); if (unit->secsize <= 0) { print("sdbios: biosonline: implausible sector size on medium\n"); return 0; } unit->sectors = biossize(subno); if (unit->sectors <= 0) { unit->sectors = 0; print("sdbios: biosonline: no sectors on medium\n"); return 0; } return 1; } static int biosrio(SDreq* r) { int nb; long got; vlong off; uchar *p; Bootfs fs; /* just for fs->dev, which is zero */ SDunit *unit; if (!biosinited) return SDeio; unit = r->unit; /* * Most SCSI commands can be passed unchanged except for * the padding on the end. The few which require munging * are not used internally. Mode select/sense(6) could be * converted to the 10-byte form but it's not worth the * effort. Read/write(6) are easy. */ r->rlen = 0; r->status = SDok; switch(r->cmd[0]){ case ScmdRead: case ScmdExtread: if (r->cmd[0] == ScmdRead) panic("biosrio: ScmdRead read op"); off = r->cmd[2]<<24 | r->cmd[3]<<16 | r->cmd[4]<<8 | r->cmd[5]; nb = r->cmd[7]<<8 | r->cmd[8]; /* often 4 */ USED(nb); /* is nb*unit->secsize == r->dlen? */ memset(&fs, 0, sizeof fs); biosseek(&fs, off * unit->secsize); got = biosread0(&fs, r->data, r->dlen); if (got < 0) r->status = SDeio; else r->rlen = got; break; case ScmdWrite: case ScmdExtwrite: r->status = SDeio; /* boot programs don't write */ break; /* * Read capacity returns the LBA of the last sector. */ case ScmdRcapacity: p = putbeul(r->unit->sectors - 1, r->data); r->data = putbeul(r->unit->secsize, p); return SDok; case ScmdRcapacity16: p = putbeuvl(r->unit->sectors - 1, r->data); r->data = putbeul(r->unit->secsize, p); return SDok; /* ignore others */ } return r->status; } /* this is called between biosreset and biosinit */ static SDev* biospnp(void) { SDev *sdev; if (!biosinited) panic("sdbios: biospnp: bios devbios not yet inited"); if((sdev = malloc(sizeof(SDev))) != nil) { sdev->ifc = &sdbiosifc; sdev->idno = 'B'; sdev->nunit = biosndevs; iprint("sdbios: biospnp: %d unit(s) at sd%C0\n", sdev->nunit, sdev->idno); } return sdev; } SDifc sdbiosifc = { "bios", /* name */ biospnp, /* pnp */ nil, /* legacy */ nil, /* enable */ nil, /* disable */ biosverify, /* verify */ biosonline, /* online */ biosrio, /* rio */ nil, /* rctl */ nil, /* wctl */ scsibio, /* bio */ nil, /* probe */ nil, /* clear */ nil, /* rtopctl */ nil, /* wtopctl */ };