@@ 97,6 97,7 @@ enum { /* Command */
Crd = 0xC8, /* Read DMA */
Cwd = 0xCA, /* Write DMA */
Cwdq = 0xCC, /* Write DMA queued */
+ Cstandby = 0xE2, /* Standby */
Cid = 0xEC, /* Identify Device */
Csf = 0xEF, /* Set Features */
};
@@ 167,12 168,8 @@ enum { /* offsets into the identify info. */
Iqdepth = 75, /* max. queue depth */
Imajor = 80, /* major version number */
Iminor = 81, /* minor version number */
- Icmdset0 = 82, /* command sets supported */
- Icmdset1 = 83, /* command sets supported */
- Icmdset2 = 84, /* command sets supported extension */
- Icmdset3 = 85, /* command sets enabled */
- Icmdset4 = 86, /* command sets enabled */
- Icmdset5 = 87, /* command sets enabled extension */
+ Icsfs = 82, /* command set/feature supported */
+ Icsfe = 85, /* command set/feature enabled */
Iudma = 88, /* ultra DMA mode */
Ierase = 89, /* time for security erase */
Ieerase = 90, /* time for enhanced security erase */
@@ 395,15 392,21 @@ ataready(int cmdport, int ctlport, int dev, int reset, int ready, int micro)
}
static int
-atacsfenabled(Drive* drive, vlong csf)
+atacsf(Drive* drive, vlong csf, int supported)
{
+ ushort *info;
int cmdset, i, x;
+ if(supported)
+ info = &drive->info[Icsfs];
+ else
+ info = &drive->info[Icsfe];
+
for(i = 0; i < 3; i++){
x = (csf>>(16*i)) & 0xFFFF;
if(x == 0)
continue;
- cmdset = drive->info[Icmdset3+i];
+ cmdset = info[i];
if(cmdset == 0 || cmdset == 0xFFFF)
return 0;
return cmdset & x;
@@ 413,21 416,9 @@ atacsfenabled(Drive* drive, vlong csf)
}
static int
-atasf(int cmdport, int ctlport, int dev, uchar* command)
+atadone(void* arg)
{
- int as, i;
-
- if(ataready(cmdport, ctlport, dev, Bsy|Drq, Drdy, 108*1000) < 0)
- return -1;
-
- for(i = Features; i < Dh; i++)
- outb(cmdport+i, command[i]);
- outb(cmdport+Command, Csf);
- microdelay(100);
- as = ataready(cmdport, ctlport, 0, Bsy, Drdy|Df|Err, 109*1000);
- if(as < 0 || (as & (Df|Err)))
- return -1;
- return 0;
+ return ((Ctlr*)arg)->done;
}
static int
@@ 527,7 518,7 @@ ataidentify(int cmdport, int ctlport, int dev, int pkt, void* info)
for(i = 0; i < 256; i++){
if(i && (i%16) == 0)
print("\n");
- print("%4.4uX ", *sp);
+ print(" %4.4uX", *sp);
sp++;
}
print("\n");
@@ 797,6 788,39 @@ atasetsense(Drive* drive, int status, int key, int asc, int ascq)
}
static int
+atastandby(Drive* drive, int period)
+{
+ Ctlr* ctlr;
+ int cmdport, done;
+
+ ctlr = drive->ctlr;
+ drive->command = Cstandby;
+ qlock(ctlr);
+
+ cmdport = ctlr->cmdport;
+ ilock(ctlr);
+ outb(cmdport+Count, period);
+ outb(cmdport+Dh, drive->dev);
+ ctlr->done = 0;
+ ctlr->curdrive = drive;
+ ctlr->command = Cstandby; /* debugging */
+ outb(cmdport+Command, Cstandby);
+ iunlock(ctlr);
+
+ while(waserror())
+ ;
+ tsleep(ctlr, atadone, ctlr, 30*1000);
+ poperror();
+
+ done = ctlr->done;
+ qunlock(ctlr);
+
+ if(!done || (drive->status & Err))
+ return atasetsense(drive, SDcheck, 4, 8, drive->error);
+ return SDok;
+}
+
+static int
atamodesense(Drive* drive, uchar* cmd)
{
int len;
@@ 865,7 889,7 @@ ataabort(Drive* drive, int dolock)
*/
if(dolock)
ilock(drive->ctlr);
- if(atacsfenabled(drive, 0x0000000000004000LL))
+ if(atacsf(drive, 0x0000000000004000LL, 0))
atanop(drive, 0);
else{
atasrst(drive->ctlr->ctlport);
@@ 982,12 1006,6 @@ atadmainterrupt(Drive* drive, int count)
ctlr->done = 1;
}
-static int
-atapktiodone(void* arg)
-{
- return ((Ctlr*)arg)->done;
-}
-
static void
atapktinterrupt(Drive* drive)
{
@@ 1092,9 1110,9 @@ atapktio(Drive* drive, uchar* cmd, int clen)
while(waserror())
;
if(!drive->pktdma)
- sleep(ctlr, atapktiodone, ctlr);
+ sleep(ctlr, atadone, ctlr);
else for(timeo = 0; !ctlr->done; timeo++){
- tsleep(ctlr, atapktiodone, ctlr, 1000);
+ tsleep(ctlr, atadone, ctlr, 1000);
if(ctlr->done)
break;
ilock(ctlr);
@@ 1122,12 1140,6 @@ atapktio(Drive* drive, uchar* cmd, int clen)
}
static int
-atageniodone(void* arg)
-{
- return ((Ctlr*)arg)->done;
-}
-
-static int
atageniostart(Drive* drive, int lba)
{
Ctlr *ctlr;
@@ 1325,7 1337,7 @@ atagenio(Drive* drive, uchar* cmd, int)
while(waserror())
;
- tsleep(ctlr, atageniodone, ctlr, 10*1000);
+ tsleep(ctlr, atadone, ctlr, 30*1000);
poperror();
if(!ctlr->done){
/*
@@ 1336,6 1348,7 @@ atagenio(Drive* drive, uchar* cmd, int)
*/
atadumpstate(drive, cmd, lba, count);
ataabort(drive, 1);
+ qunlock(ctlr);
return atagenioretry(drive);
}
@@ 1540,6 1553,10 @@ atainterrupt(Ureg*, void* arg)
case Cwd:
atadmainterrupt(drive, drive->count*drive->secsize);
break;
+
+ case Cstandby:
+ ctlr->done = 1;
+ break;
}
iunlock(ctlr);
@@ 1776,6 1793,7 @@ atarctl(SDunit* unit, char* p, int l)
static int
atawctl(SDunit* unit, Cmdbuf* cb)
{
+ int period;
Ctlr *ctlr;
Drive *drive;
@@ 1815,6 1833,20 @@ atawctl(SDunit* unit, Cmdbuf* cb)
else
error(Ebadctl);
}
+ else if(strcmp(cb->f[0], "standby") == 0){
+ switch(cb->nf){
+ default:
+ error(Ebadctl);
+ case 2:
+ period = strtol(cb->f[1], 0, 0);
+ if(period && (period < 30 || period > 240*5))
+ error(Ebadctl);
+ period /= 5;
+ break;
+ }
+ if(atastandby(drive, period) != SDok)
+ error(Ebadctl);
+ }
else
error(Ebadctl);
qunlock(drive);