int i;
va_list arg;
- if(!(DEBUG & DbgPROBE))
+ if(!(DEBUG & DbgPROBE)){
+ USED(cmdport);
+ USED(ctlport);
+ USED(fmt);
return;
+ }
p = buf;
e = buf + sizeof buf;
dev &= ~Lba;
as = ataready(cmdport, ctlport, dev, Bsy|Drq, drdy, 103*1000);
if(as < 0)
- return as;
+ return -1;
outb(cmdport+Command, command);
microdelay(1);
as = ataready(cmdport, ctlport, 0, Bsy, Drq|Err, 400*1000);
- if(as < 0)
- return -1;
- if(as & Err)
+ if(as < 0 || (as & Err))
return as;
-
memset(info, 0, 512);
inss(cmdport+Data, info, 256);
- ataready(cmdport, ctlport, dev, Bsy|Drq, Drdy, 3*1000);
inb(cmdport+Status);
-
return 0;
}
static Drive*
atadrive(SDunit *unit, Drive *drive, int cmdport, int ctlport, int dev)
{
- int as, pkt;
+ int as, pkt, rlo, rhi;
uchar buf[512], oserial[21];
uvlong osectors;
Ctlr *ctlr;
if(DEBUG & DbgIDENTIFY)
print("identify: port %ux dev %.2ux\n", cmdport, dev & ~Lba);
+
atadebug(0, 0, "identify: port 0x%uX dev 0x%2.2uX\n", cmdport, dev);
- pkt = 1;
if(drive != nil){
osectors = drive->sectors;
memmove(oserial, drive->serial, sizeof drive->serial);
osectors = 0;
memset(oserial, 0, sizeof drive->serial);
ctlr = nil;
+
+ /* detect if theres a drive present */
+ outb(cmdport+Dh, dev & ~Lba);
+ microdelay(1);
+ outb(cmdport+Cyllo, 0xAA);
+ outb(cmdport+Cylhi, 0x55);
+ outb(cmdport+Sector, 0xFF);
+ rlo = inb(cmdport+Cyllo);
+ rhi = inb(cmdport+Cylhi);
+ if(rlo != 0xAA && (rlo == 0xFF || rhi != 0x55))
+ return nil;
}
+
+ pkt = 1;
retry:
as = ataidentify(ctlr, cmdport, ctlport, dev, pkt, buf);
if(as < 0)
memmove(drive->info, buf, sizeof(drive->info));
- setfissig(drive, pkt? 0xeb140000: 0x0101);
+ setfissig(drive, pkt ? 0xeb140000 : 0x0101);
drive->sectors = idfeat(drive, drive->info);
drive->secsize = idss(drive, drive->info);
microdelay(2*1000);
}
-static int
-seldev(int dev, int map)
-{
- if((dev & Devs) == Dev0 && map&1)
- return dev;
- if((dev & Devs) == Dev1 && map&2)
- return dev;
- return -1;
-}
-
static SDev*
ataprobe(int cmdport, int ctlport, int irq, int map)
{
+ static int nonlegacy = 'C';
Ctlr* ctlr;
SDev *sdev;
- Drive *drive;
- int dev, error, rhi, rlo;
- static int nonlegacy = 'C';
if(ioalloc(cmdport, 8, 0, "atacmd") < 0) {
print("ataprobe: Cannot allocate %X\n", cmdport);
return nil;
}
- /*
- * Try to detect a floating bus.
- * Bsy should be cleared. If not, see if the cylinder registers
- * are read/write capable.
- * If the master fails, try the slave to catch slave-only
- * configurations.
- * There's no need to restore the tested registers as they will
- * be reset on any detected drives by the Cedd command.
- * All this indicates is that there is at least one drive on the
- * controller; when the non-existent drive is selected in a
- * single-drive configuration the registers of the existing drive
- * are often seen, only command execution fails.
- */
- if((dev = seldev(Dev0, map)) == -1)
- if((dev = seldev(Dev1, map)) == -1)
+ if((ctlr = malloc(sizeof(Ctlr))) == nil)
goto release;
- if(inb(ctlport+As) & Bsy){
- outb(cmdport+Dh, dev);
- microdelay(1);
-trydev1:
- atadebug(cmdport, ctlport, "ataprobe bsy");
- outb(cmdport+Cyllo, 0xAA);
- outb(cmdport+Cylhi, 0x55);
- outb(cmdport+Sector, 0xFF);
- rlo = inb(cmdport+Cyllo);
- rhi = inb(cmdport+Cylhi);
- if(rlo != 0xAA && (rlo == 0xFF || rhi != 0x55)){
- if(dev == Dev1 || (dev = seldev(Dev1, map)) == -1){
-release:
- outb(cmdport+Dc, Nien);
- inb(cmdport+Status);
- /* further measures to prevent irqs? */
- iofree(cmdport);
- iofree(ctlport+As);
- return nil;
- }
- if(ataready(cmdport, ctlport, dev, Bsy, 0, 20*1000) < 0)
- goto trydev1;
- }
- }
-
- /*
- * Disable interrupts on any detected controllers.
- */
- outb(ctlport+Dc, Nien);
-tryedd1:
- if(ataready(cmdport, ctlport, dev, Bsy|Drq, 0, 105*1000) < 0){
- /*
- * There's something there, but it didn't come up clean,
- * so try hitting it with a big stick. The timing here is
- * wrong but this is a last-ditch effort and it sometimes
- * gets some marginal hardware back online.
- */
- atasrst(ctlport);
- if(ataready(cmdport, ctlport, dev, Bsy|Drq, 0, 106*1000) < 0)
- goto release;
- }
-
- /*
- * Can only get here if controller is not busy.
- * If there are drives Bsy will be set within 400nS,
- * must wait 2mS before testing Status.
- * Wait for the command to complete (6 seconds max).
- */
- outb(cmdport+Command, Cedd);
- delay(2);
- if(ataready(cmdport, ctlport, dev, Bsy|Drq, 0, 6*1000*1000) < 0)
+ if((sdev = malloc(sizeof(SDev))) == nil){
+ free(ctlr);
goto release;
-
- /*
- * If bit 0 of the error register is set then the selected drive
- * exists. This is enough to detect single-drive configurations.
- * However, if the master exists there is no way short of executing
- * a command to determine if a slave is present.
- * It appears possible to get here testing Dev0 although it doesn't
- * exist and the EDD won't take, so try again with Dev1.
- */
- error = inb(cmdport+Error);
- atadebug(cmdport, ctlport, "ataprobe: dev %uX", dev);
- if((error & ~0x80) != 0x01){
- if(dev == Dev1)
- goto release;
- if((dev = seldev(Dev1, map)) == -1)
- goto release;
- goto tryedd1;
}
- /*
- * At least one drive is known to exist, try to
- * identify it. If that fails, don't bother checking
- * any further.
- * If the one drive found is Dev0 and the EDD command
- * didn't indicate Dev1 doesn't exist, check for it.
- */
- if((drive = atadrive(0, 0, cmdport, ctlport, dev)) == nil)
- goto release;
- if((ctlr = malloc(sizeof(Ctlr))) == nil){
- free(drive);
- goto release;
- }
- if((sdev = malloc(sizeof(SDev))) == nil){
+ if((map & 2) && (ctlr->drive[1] = atadrive(0, 0, cmdport, ctlport, Dev1)))
+ ctlr->drive[1]->ctlr = ctlr;
+ if((map & 1) && (ctlr->drive[0] = atadrive(0, 0, cmdport, ctlport, Dev0)))
+ ctlr->drive[0]->ctlr = ctlr;
+
+ if(ctlr->drive[0] == nil && ctlr->drive[1] == nil){
+ free(ctlr->drive[0]);
+ free(ctlr->drive[1]);
free(ctlr);
- free(drive);
+ free(sdev);
goto release;
}
- drive->ctlr = ctlr;
- if(dev == Dev0){
- ctlr->drive[0] = drive;
- if(!(error & 0x80)){
- /*
- * Always leave Dh pointing to a valid drive,
- * otherwise a subsequent call to ataready on
- * this controller may try to test a bogus Status.
- * Ataprobe is the only place possibly invalid
- * drives should be selected.
- */
- drive = atadrive(0, 0, cmdport, ctlport, Dev1);
- if(drive != nil){
- drive->ctlr = ctlr;
- ctlr->drive[1] = drive;
- }
- else{
- outb(cmdport+Dh, Dev0);
- microdelay(1);
- }
- }
- }
- else
- ctlr->drive[1] = drive;
ctlr->cmdport = cmdport;
ctlr->ctlport = ctlport;
ctlr->irq = irq;
ctlr->tbdf = BUSUNKNOWN;
- ctlr->command = Cedd; /* debugging */
-
+ ctlr->command = Cnop; /* debugging */
+
switch(cmdport){
default:
sdev->idno = nonlegacy;
ctlr->sdev = sdev;
return sdev;
+
+release:
+ iofree(cmdport);
+ iofree(ctlport+As);
+
+ return nil;
}
static void
atapktio0(Drive *drive, SDreq *r)
{
uchar *cmd;
- int as, cmdport, ctlport, len, rv;
+ int as, len, cmdport, ctlport, rv;
Ctlr *ctlr;
rv = SDok;
return SDnostatus;
ilock(ctlr);
- if(drive->dlen && drive->dmactl && !atadmasetup(drive, drive->dlen)){
+ if(drive->dlen && drive->dmactl && !atadmasetup(drive, drive->dlen))
drive->pktdma = Dma;
- len = 0; /* bytecount should be 0 for dma */
- }else{
+ else
drive->pktdma = 0;
- if(drive->secsize)
- len = 16*drive->secsize;
- else
- len = 0x8000;
- }
+ len = drive->secsize > 0 ? 16*drive->secsize : 0x8000;
outb(cmdport+Features, drive->pktdma);
outb(cmdport+Count, 0);
outb(cmdport+Sector, 0);
outb(cmdport+Command, Cpkt);
microdelay(1);
- as = ataready(cmdport, ctlport, 0, Bsy, Drq|Chk, 4*1000);
+ as = ataready(cmdport, ctlport, 0, Bsy, Drq|Chk, 400*1000);
if(as < 0 || (as & (Bsy|Chk))){
drive->status = as<0 ? 0 : as;
ctlr->curdrive = nil;
atadmastart(ctlr, drive->write);
iunlock(ctlr);
- if(iowait(drive, 30*1000, 0) <= 0){
- ilock(ctlr);
+ while(iowait(drive, 30*1000, 1) == 0)
+ ;
+
+ ilock(ctlr);
+ if(!ctlr->done){
+ rv = SDcheck;
ataabort(drive, 0);
- } else
- ilock(ctlr);
+ }
if(drive->error){
if(drive->pktdma)
atadmastop(ctlr);
}
iunlock(ctlr);
- if(drive->status & Chk){
+ if(rv != SDcheck && drive->status & Chk){
rv = SDcheck;
if(drive->pktdma){
print("atapktio: disabling dma\n");
drive->dmactl = 0;
- rv = SDretry;
}
}
return rv;
case Cws:
case Cwsm:
microdelay(1);
- /* 10*1000 for flash ide drives - maybe detect them? */
- as = ataready(cmdport, ctlport, 0, Bsy, Drq|Err, 10*1000);
+ as = ataready(cmdport, ctlport, 0, Bsy, Drq|Err, 400*1000);
if(as < 0 || (as & Err)){
iunlock(ctlr);
return -1;
SDunit *unit;
unit = r->unit;
- if((ctlr = unit->dev->ctlr) == nil || ctlr->drive[unit->subno] == nil){
- r->status = SDtimeout;
- return SDtimeout;
- }
+ if((ctlr = unit->dev->ctlr) == nil || ctlr->drive[unit->subno] == nil)
+ return r->status = SDtimeout;
drive = ctlr->drive[unit->subno];
qlock(drive);
for(;;){
USED(d);
else if(!isdma){
microdelay(1);
- /* 10*1000 for flash ide drives - maybe detect them? */
- as = ataready(cmdport, ctlport, 0, Bsy, Drq|Err, 10*1000);
+ as = ataready(cmdport, ctlport, 0, Bsy, Drq|Err, 400*1000);
if(as < 0 || (as & Err)){
iunlock(ctlr);
return -1;
if(ctlr->irqack != nil)
ctlr->irqack(ctlr);
iunlock(ctlr);
- if((DEBUG & DbgINL) && ctlr->command != Cedd)
- print("Inil%2.2uX+", ctlr->command);
return;
}
if(status & Err)
case (0x4D69<<16)|0x105A: /* Promise Ultra/133 TX2 */
case (0x3373<<16)|0x105A: /* Promise 20378 RAID */
case (0x3149<<16)|0x1106: /* VIA VT8237 SATA/RAID */
+ case (0x0415<<16)|0x1106: /* VIA VT6415 PATA IDE */
case (0x3112<<16)|0x1095: /* SiL 3112 SATA/RAID */
maxio = 15;
span = 8*1024;
*/
break;
case (0x7441<<16)|0x1022: /* AMD 768 */
- case (0x7800<<16)|0x1022:
/*
* Set:
* 0x41 prefetch, postwrite;
case (0x7111<<16)|0x8086: /* 82371[AE]B (PIIX4[E]) */
maxdma = 0x20000;
break;
+ case (0x1c00<<16)|0x8086: /* SERIES6 SATA */
+ case (0x1c01<<16)|0x8086: /* SERIES6 SATA */
+ case (0x1c08<<16)|0x8086: /* SERIES6 SATA */
+ case (0x1c09<<16)|0x8086: /* SERIES6 SATA */
case (0x2411<<16)|0x8086: /* 82801AA (ICH) */
case (0x2421<<16)|0x8086: /* 82801AB (ICH0) */
case (0x244A<<16)|0x8086: /* 82801BA (ICH2, Mobile) */
case (0x27C5<<16)|0x8086: /* 82801GBM SATA AHCI (ICH7) */
case (0x2850<<16)|0x8086: /* 82801HBM/HEM PATA */
case (0x2820<<16)|0x8086: /* 82801HB/HR/HH/HO SATA IDE */
+ case (0x2825<<16)|0x8086: /* 82801IIH Intel Q35 IDE */
case (0x2828<<16)|0x8086: /* 82801HBM SATA (ICH8-M) */
case (0x2829<<16)|0x8086: /* 82801HBM SATA AHCI (ICH8-M) */
case (0x2920<<16)|0x8086: /* 82801(IB)/IR/IH/IO SATA (ICH9) port 0-3 */
map |= 2;
irqack = ichirqack;
break;
+ case (0x811a<<16)|0x8086: /* Intel SCH (Poulsbo) */
+ map = 1;
+ irqack = ichirqack;
+ break;
}
for(channel = 0; channel < 2; channel++){
if((map & 1<<channel) == 0)
ctlr->maxdma = maxdma;
ctlr->span = span;
ctlr->irqack = irqack;
- if(pi & 0x80)
+ if((pi & 0x80) && (p->mem[4].bar & 0x01))
ctlr->bmiba = (p->mem[4].bar & ~0x01) + channel*8;
if(head != nil)
tail->next = sdev;
atadmaclr(ctlr);
if(ctlr->pcidev != nil)
pcisetbme(ctlr->pcidev);
- ctlr->prdt = mallocalign(Nprd*sizeof(Prd), 4, 0, 64*1024);
+ /* Intel SCH requires 8 byte alignment, though datasheet says 4 m( */
+ ctlr->prdt = mallocalign(Nprd*sizeof(Prd), 8, 0, 64*1024);
}
snprint(name, sizeof(name), "%s (%s)", sdev->name, sdev->ifc->name);
intrenable(ctlr->irq, atainterrupt, ctlr, ctlr->tbdf, name);
if(drive->pkt == 0 && (drive->feat & Dlba) == 0)
p = seprint(p, e, " %d %d %d", drive->c, drive->h, drive->s);
p = seprint(p, e, "\n");
+ p = seprint(p, e, "alignment %d %d\n",
+ drive->secsize<<drive->physshift, drive->physalign);
}
p = seprint(p, e, "missirq %ud\n", drive->missirq);
p = seprint(p, e, "sloop %ud\n", drive->spurloop);