M pc/sdata.c => pc/sdata.c +42 -15
@@ 91,6 91,7 @@ enum { /* Command */
Cidpkt = 0xA1, /* Identify Packet Device */
Crsm = 0xC4, /* Read Multiple */
Cwsm = 0xC5, /* Write Multiple */
+ Csm = 0xC6, /* Set Multiple */
Crdq = 0xC7, /* Read DMA queued */
Crd = 0xC8, /* Read DMA */
Cwd = 0xCA, /* Write DMA */
@@ 225,11 226,12 @@ typedef struct Drive {
int s; /* sector */
int sectors; /* total */
int secsize; /* sector size */
+
+ int dma; /* DMA R/W possible */
+
int block; /* R/W multiple size */
int pior; /* PIO read command */
int piow; /* PIO write command */
- int dma; /* DMA R/W possible */
- int pkt; /* PACKET device, length of pktcmd */
uchar sense[18];
uchar inquiry[48];
@@ 244,6 246,7 @@ typedef struct Drive {
int status;
int error;
+ int pkt; /* PACKET device, length of pktcmd */
uchar pktcmd[16];
int pktdma;
} Drive;
@@ 411,6 414,40 @@ atacsfenabled(Drive* drive, vlong csf)
return 0;
}
+static int
+atasetrwmode(Drive* drive, int cmdport, int ctlport, int dev)
+{
+ int as, block;
+
+ drive->block = drive->secsize;
+ drive->pior = Crs;
+ drive->piow = Cws;
+ if((block = drive->info[Imaxrwm] & 0xFF) == 0)
+ return 0;
+
+ /*
+ * Prior to ATA-4 there was no way to determine the
+ * current block count (now in Irwm).
+ * Sometimes drives come up with the current count set
+ * to 0, so always set a suitable value.
+ */
+ if(ataready(cmdport, ctlport, dev, Bsy|Drq, Drdy, 100*1000) < 0)
+ return 0;
+ outb(cmdport+Sector, block);
+ outb(cmdport+Command, Csf);
+ microdelay(1);
+ as = ataready(cmdport, ctlport, dev, Bsy, Drdy|Df|Err, 1000);
+ if(as < 0 || (as & (Df|Err)))
+ return -1;
+
+ drive->info[Irwm] = 0x100|block;
+ drive->block = block*drive->secsize;
+ drive->pior = Crsm;
+ drive->piow = Cwsm;
+
+ return block;
+}
+
static Drive*
ataidentify(int cmdport, int ctlport, int dev)
{
@@ 471,6 508,8 @@ retry:
*p++ = *sp>>8;
*p++ = *sp++;
}
+
+ drive->secsize = 512;
if((drive->info[Iconfig] & 0xC000) == 0x8000){
if(drive->info[Iconfig] & 0x01)
drive->pkt = 16;
@@ 495,20 534,8 @@ retry:
}
else
drive->sectors = drive->c*drive->h*drive->s;
+ atasetrwmode(drive, cmdport, ctlport, dev);
}
- drive->secsize = 512;
-
- if((drive->info[Imaxrwm] & 0xFF) && (drive->info[Irwm] & 0x0100)){
- drive->block = drive->info[Imaxrwm] & 0x00FF;
- drive->pior = Crsm;
- drive->piow = Cwsm;
- }
- else{
- drive->block = 1;
- drive->pior = Crs;
- drive->piow = Cws;
- }
- drive->block *= drive->secsize;
/*
* Check if any DMA mode enabled.
M port/devbridge.c => port/devbridge.c +1 -1
@@ 30,7 30,7 @@ enum
MaxQ,
Maxbridge= 4,
- Maxport= 32, // power of 2
+ Maxport= 64, // power of 2
CacheHash= 257, // prime
CacheLook= 5, // how many cache entries to examine
CacheSize= (CacheHash+CacheLook-1),
M port/devsd.c => port/devsd.c +22 -30
@@ 328,7 328,7 @@ sd2gen(Chan* c, int i, Dir* dp)
return 1;
case Qraw:
q = (Qid){QID(UNIT(c->qid), PART(c->qid), Qraw), c->qid.vers};
- devdir(c, q, "raw", 0, eve, 0600, dp);
+ devdir(c, q, "raw", 0, eve, CHEXCL|0600, dp);
return 1;
case Qpart:
unit = sdunit[UNIT(c->qid)];
@@ 492,6 492,12 @@ sdopen(Chan* c, int omode)
switch(TYPE(c->qid)){
default:
break;
+ case Qraw:
+ unit = sdunit[UNIT(c->qid)];
+ if(!canlock(&unit->rawinuse))
+ error(Einuse);
+ unit->state = Rawcmd;
+ break;
case Qpart:
unit = sdunit[UNIT(c->qid)];
qlock(&unit->ctl);
@@ 528,11 534,7 @@ sdclose(Chan* c)
break;
case Qraw:
unit = sdunit[UNIT(c->qid)];
- if(canqlock(&unit->raw) || unit->pid == up->pid){
- unit->pid = 0;
- unit->state = Rawcmd;
- qunlock(&unit->raw);
- }
+ unlock(&unit->rawinuse);
break;
case Qpart:
unit = sdunit[UNIT(c->qid)];
@@ 744,23 746,15 @@ sdread(Chan *c, void *a, long n, vlong off)
return l;
case Qraw:
unit = sdunit[UNIT(c->qid)];
- if(canqlock(&unit->raw)){
- qunlock(&unit->raw);
- error(Ebadusefd);
- }
- if(unit->pid != up->pid)
- error(Eperm);
if(unit->state == Rawdata){
unit->state = Rawstatus;
return sdrio(unit->req, a, n);
}
else if(unit->state == Rawstatus){
status = unit->req->status;
- unit->pid = 0;
unit->state = Rawcmd;
free(unit->req);
unit->req = nil;
- qunlock(&unit->raw);
return readnum(0, a, n, status, NUMSIZE);
}
break;
@@ 819,21 813,15 @@ sdwrite(Chan *c, void *a, long n, vlong off)
poperror();
free(cb);
break;
+
case Qraw:
unit = sdunit[UNIT(c->qid)];
- if(canqlock(&unit->raw)){
- if(unit->state != Rawcmd){
- qunlock(&unit->raw);
- error(Ebadusefd);
- }
- if(n < 6 || n > sizeof(req->cmd)){
- qunlock(&unit->raw);
+ switch(unit->state){
+ case Rawcmd:
+ if(n < 6 || n > sizeof(req->cmd))
error(Ebadarg);
- }
- if((req = malloc(sizeof(SDreq))) == nil){
- qunlock(&unit->raw);
+ if((req = malloc(sizeof(SDreq))) == nil)
error(Enomem);
- }
req->unit = unit;
memmove(req->cmd, a, n);
req->clen = n;
@@ 841,12 829,16 @@ sdwrite(Chan *c, void *a, long n, vlong off)
req->status = ~0;
unit->req = req;
- unit->pid = up->pid;
unit->state = Rawdata;
- }
- else{
- if(unit->pid != up->pid)
- error(Eperm);
+ break;
+
+ case Rawstatus:
+ unit->state = Rawcmd;
+ free(unit->req);
+ unit->req = nil;
+ error(Ebadusefd);
+
+ case Rawdata:
if(unit->state != Rawdata)
error(Ebadusefd);
unit->state = Rawstatus;
M port/sd.h => port/sd.h +1 -2
@@ 32,9 32,8 @@ typedef struct SDunit {
int nopen; /* of partitions on this unit */
int changed;
- QLock raw;
+ Lock rawinuse;
int state;
- ulong pid;
SDreq* req;
} SDunit;