[inferno-kirkwood] push by mechiel@ueber.net - in identify(), get more info about the disk.... on 2010-09-01 21:42 GMT

1 view
Skip to first unread message

inferno-...@googlecode.com

unread,
Sep 1, 2010, 5:42:52 PM9/1/10
to inferno-kirk...@googlegroups.com
Revision: 51e0f3322d
Author: Mechiel Lukkien <mec...@ueber.net>
Date: Wed Sep 1 14:41:58 2010
Log: in identify(), get more info about the disk.

it can now also detect whether the disk does ncq.
code still assumes that all disks do ncq, it also doesn't store any
of the identified info yet.
http://code.google.com/p/inferno-kirkwood/source/detail?r=51e0f3322d

Modified:
/devsata.c

=======================================
--- /devsata.c Wed Aug 25 14:36:10 2010
+++ /devsata.c Wed Sep 1 14:41:58 2010
@@ -4,6 +4,10 @@
for now we'll assume ncq "first party dma" read/write commands (very old
sata disks won't work).

todo:
+- figure out what to do with the tag in the responses from the response
queue. for ncq.
+- read ata/atapi signature in registers after reset?
+- get interrupt when device sends registers. so we can check for BSY
then, or start reading data, etc.
+- detect whether packet command is accepted. try if packet commands work.
- properly wait until device is no longer busy during startup
- proper locking, wait for free edma slot.
- look at cache flushes around dma
@@ -16,8 +20,7 @@
- hotplug, at least handle disconnects
- abstract for multiple ports (add controller struct to functions)
- in satainit(), only start the disk init, don't wait for it to be ready?
faster booting, seems it takes controller/disk some time to init after
reset.
-- support for non-ncq drives, by normal dma commands?
-- for large i/o requests, could have always two ops scheduled: less
waiting, still no hogging.
+- support for non-ncq drives, by normal dma commands? should support
setting iomode: pio dma satancq. commands should ata for now. could be
atapi-mmc or atapi-scsi too. not good for this chip because dma with atapi
is not supported by the chip and pio is slow.
*/

#include "u.h"
@@ -87,7 +90,7 @@
uvlong sectors;
};

-static ulong satadone;
+static volatile ulong satadone;
static QLock reqsl;
static Rendez reqsr[32];
static Req *reqs;
@@ -132,7 +135,6 @@
Dev2mem = 1<<5, /* direction of command */
Cacheempty = 1<<6, /* edma cache empty */
EdmaIdle = 1<<7, /* edma idle (but disk can have command pending) */
-#define IOID(v) (((v)>>16)&(1<<6)-1) /* io id of last command */

/* host controller interrupt */
Sata0err = 1<<0,
@@ -247,9 +249,6 @@
hr->intr = 0;
sr->edma.intre = 0;

- if(sr->edma.ncqdone)
- iprint("ncqdone %#lux\n", sr->edma.ncqdone);
- diprint("ncqdone %#lux\n", sr->edma.ncqdone);
diprint("reqin %#lux reqout %#lux respin %#lux respout %#lux\n",
sr->edma.reqin, sr->edma.reqout, sr->edma.respin, sr->edma.respout);

dcinv(resps, 32*sizeof resps[0]);
@@ -259,10 +258,9 @@
if(in == out)
break;
w = resps[in].idflags & MASK(5);
- if(w != in && 0)
+ if(w != in)
iprint("response, in %lud, tag %lud\n", in, w);
- /* determine which request is done. maybe from ncqdone. wakeup its
caller. */
- /* xxx check tag in idflags? */
+ /* determine which request is done, wakeup its caller. */
satadone |= 1<<out;
diprint("new resp out %lud (in %lud), satadone now %#lux\n", out, in,
satadone);
/* xxx check for error */
@@ -318,7 +316,7 @@
/* xxx don't blindly reset registers later */
hr->intrmainena &= ~(Sata1err|Sata1done|Sata1dmadone);

- diprint("pio, status %#lux\n", a->status);
+ diprint("ata, status %#lux\n", a->status);
a->feat = feat;
a->sectors = sectors;
a->lbalow = (lba>>0) & 0xff;
@@ -367,6 +365,71 @@
memmove(p, p+i, j+1-i);
p[j+1-i] = 0;
}
+
+
+/* output of "identify device", 256 16-bit words. */
+enum {
+ /* some words are only valid when bit 15 is 0 and bit 14 is 1. */
+ Fvalidmask = 3<<14,
+ Fvalid = 1<<14,
+
+ /* capabilities. these should be 1 for sata devices. */
+ Fcaplba = 1<<9,
+ Fcapdma = 1<<8,
+
+ /* ata commands supported (word 82), enabled (word 85) */
+ Feat0ServiceIntr = 1<<8,
+ Feat0Writecache = 1<<5,
+ Feat0Packet = 1<<4,
+ Feat0PowerMgmt = 1<<3,
+ Feat0SMART = 1<<0,
+
+ /* ata commands supported (word 83), enabled (word 86) */
+ Feat1FlushCachExt = 1<<13,
+ Feat1FlushCache = 1<<12,
+ Feat1Addr48 = 1<<10,
+ Feat1AAM = 1<<9, /* automatic acoustic management */
+ Feat1SetFeatReq = 1<<6,
+ Feat1PowerupStandby = 1<<5,
+ Feat1AdvPowerMgmt = 1<<3,
+
+ /* ata commands supported (word 84), enabled (word 87) */
+ Feat2WWName64 = 1<<8,
+ Feat2Logging = 1<<5,
+ Feat2SMARTselftest = 1<<1,
+ Feat2SMARTerrorlog = 1<<0,
+
+ /* logical/physical sectors, word 106 */
+ MultiLogicalSectors = 1<<13, /* multiple logical sectors per physical
sector */
+ LargeLogicalSectors = 1<<12, /* logical sector larger than 512 bytes */
+ LogicalPerPhyslog2mask = (1<<4)-1,
+
+ /* sata capabilities, word 76 */
+ SataCapNCQ = 1<<8,
+ SataCapGen2 = 1<<2,
+ SataCapGen1 = 1<<1,
+
+ /* nvcache capabilities, word 214 */
+ NvcacheEnabled = 1<<4,
+ NvcachePMEnabled = 1<<1,
+ NvcachePMSup = 1<<0,
+};
+
+
+typedef struct Atadev Atadev;
+struct Atadev {
+ ushort major;
+ ushort minor;
+ ushort cmdset[6]; /* words 83-87. first three are for "supported", last
three for "enabled". */
+ ushort sectorflags; /* word 106 */
+ uvlong wwn; /* world wide name, unique. 0 if not supported. */
+ ushort sectorsize; /* logical sector size */
+ ushort satacap;
+ ushort nvcachecap;
+ ulong nvcachelblocks; /* in logical blocks */
+ ushort rpm; /* 0 for unknown, 1 for non-rotating device, other for rpm */
+};
+

static int
identify(void)
@@ -374,8 +437,8 @@
uchar c;
uchar buf[512];
int i;
- ulong v;
- int qdepth;
+ ushort w;
+ Atadev dev;

atacmd(0xec, 0, 0, 0, 0, Dev2host, buf);

@@ -398,25 +461,80 @@
disk.sectors |= (uvlong)g16(buf+101*2)<<16;
disk.sectors |= (uvlong)g16(buf+102*2)<<32;

- v = g16(buf+83*2);
- if((v & (1<<10)) == 0) {
- dprint("lba48 not supported (word 83 %#lux)\n", v);
+ w = g16(buf+49*2);
+ if((w & Fcapdma) == 0 || (w & Fcaplba) == 0) {
+ dprint("disk does not support dma and/or lba\n");
return -1;
}

- v = g16(buf+75*2);
- qdepth = 1+(v&MASK(5));
- USED(qdepth);
-
- /* xxx check ncq support, how? */
+ dev.major = g16(buf+80*2);
+ dev.minor = g16(buf+81*2);
+ for(i = 0; i < 6; i++) {
+ dev.cmdset[i] = g16(buf+(82+i)*2);
+ }
+ if((dev.cmdset[1] & Fvalidmask) != Fvalid)
+ dev.cmdset[1] = 0;
+ if((dev.cmdset[2] & Fvalidmask) != Fvalid)
+ dev.cmdset[2] = 0;
+ if((dev.cmdset[3+2] & Fvalidmask) != Fvalid)
+ dev.cmdset[3+2] = 0;
+
+ if((dev.cmdset[3+1] & Feat1Addr48) == 0) {
+ dprint("disk does not have lba48 enabled\n");
+ return -1;
+ }
+
+ dev.sectorflags = g16(buf+106*2);
+ dev.sectorsize = 512;
+ if((dev.sectorflags & Fvalidmask) != Fvalid)
+ dev.sectorflags = 0;
+ if(dev.sectorflags & LargeLogicalSectors)
+ dev.sectorsize = 2 * (g16(buf+117*2)<<16 | g16(buf+118*2)<<0);
+
+ dev.wwn = 0;
+ if((dev.cmdset[2] & Feat2WWName64) && (dev.cmdset[3+2] & Feat2WWName64))
+ dev.wwn = (uvlong)g16(buf+108*2)<<48 | (uvlong)g16(buf+109*2)<<32 |
(uvlong)g16(buf+110*2)<<16 | (uvlong)g16(buf+111*2)<<0;
+
+ dev.satacap = g16(buf+76*2);
+ if(dev.satacap == 0xffff)
+ dev.satacap = 0;
+
+ dev.nvcachecap = g16(buf+214*2);
+ dev.nvcachelblocks = g16(buf+215*2)<<16 | g16(buf+216*2)<<0;
+
+ dev.rpm = g16(buf+217*2);
+ /* check for "reserved" range in ata8-acs, set to 0 unknown if so */
+ if(dev.rpm > 1 && dev.rpm < 0x400 || dev.rpm == 0xffff)
+ dev.rpm = 0;

if(satadebug) {
dprint("model %q\n", disk.model);
dprint("serial %q\n", disk.serial);
dprint("firmware %q\n", disk.firmware);
dprint("sectors %llud\n", disk.sectors);
- dprint("size %llud bytes\n", disk.sectors*512);
- dprint("size %llud gb\n", disk.sectors*512/(1024*1024*1024));
+ dprint("size %llud bytes, %llud gb\n", disk.sectors*512,
disk.sectors*512/(1024*1024*1024));
+ dprint("ata/atapi versions %hux/%hux\n", dev.major, dev.minor);
+ dprint("sectorflags:%s%s\n",
+ (dev.sectorflags & MultiLogicalSectors) ? " MultiLogicalSectors" : "",
+ (dev.sectorflags & LargeLogicalSectors) ? " LargeLogicalSectors" : "");
+ dprint("logical sector size %d\n", dev.sectorsize);
+ dprint("sata cap:%s%s%s\n",
+ (dev.satacap & SataCapNCQ) ? " ncq" : "",
+ (dev.satacap & SataCapGen2) ? " 3.0gbps" : "",
+ (dev.satacap & SataCapGen1) ? " 1.5gbps" : "");
+ dprint("cmdset %04hux %04hux %04hux %04hux %04hux %04hux\n",
+ dev.cmdset[0], dev.cmdset[1], dev.cmdset[2], dev.cmdset[3],
dev.cmdset[4], dev.cmdset[5]);
+ dprint(" disabled: %04hux %04hux %04hux\n",
+ dev.cmdset[0] & ~dev.cmdset[3+0],
+ dev.cmdset[1] & ~dev.cmdset[3+1],
+ dev.cmdset[2] & ~dev.cmdset[3+2]);
+ dprint("wwn %llux\n", dev.wwn);
+ dprint("nvcache cap:%s%s%s\n",
+ (dev.nvcachecap & NvcacheEnabled) ? " NvcacheEnabled" : "",
+ (dev.nvcachecap & NvcachePMEnabled) ? " NvcachePMEnabled" : "",
+ (dev.nvcachecap & NvcachePMSup) ? " NvcachePMSup" : "");
+ dprint("nvcache lblocks: %lud\n", dev.nvcachelblocks);
+ dprint("rpm %hud\n", dev.rpm);
}
satadir[Qdata].length = disk.sectors*512;
disk.valid = 1;
@@ -442,15 +560,15 @@
e = p+n;

p = seprint(p, e, "ata:\n");
- p = seprint(p, e, " data %04lux\n", a->data);
- p = seprint(p, e, " feat/error %02lux\n", a->feat);
- p = seprint(p, e, " sectors %02lux\n", a->sectors);
- p = seprint(p, e, " lbalow %02lux\n", a->lbalow);
- p = seprint(p, e, " lbamid %02lux\n", a->lbamid);
- p = seprint(p, e, " lbahigh %02lux\n", a->lbahigh);
- p = seprint(p, e, " dev %02lux\n", a->dev);
- p = seprint(p, e, " cmd/status %02lux\n", a->cmd);
- p = seprint(p, e, " ctl %02lux\n", a->ctl);
+ p = seprint(p, e, " data %04lux\n", a->data);
+ p = seprint(p, e, " feat/error %02lux\n", a->feat);
+ p = seprint(p, e, " sectors %02lux\n", a->sectors);
+ p = seprint(p, e, " lbalow %02lux\n", a->lbalow);
+ p = seprint(p, e, " lbamid %02lux\n", a->lbamid);
+ p = seprint(p, e, " lbahigh %02lux\n", a->lbahigh);
+ p = seprint(p, e, " dev %02lux\n", a->dev);
+ p = seprint(p, e, " status/cmd %02lux\n", a->cmd);
+ p = seprint(p, e, " altstatus/ctl %02lux\n", a->ctl);
USED(p);

dprint("%s", buf);
@@ -590,12 +708,6 @@

sr->ifc.ifccfg &= ~Ignorebsy;

-if(0) {
- tsleep(&up->sleep, return0, nil, 500);
- dprint("ata after real reset\n");
- atadump();
-}
-
dprint("sr->ifc.sstatus before ata identify %#lux\n", sr->ifc.sstatus);

/* xxx horrible, should properly wait during command execution, until
device no longer busy */
@@ -917,17 +1029,24 @@
rq->ata[2] = (lbahi<<0)|(nshi<<24); /* 24 bit lba previous, feat
ext/previous */
rq->ata[3] = ((i<<3)<<0)|(0<<8); /* sectors current (tag), previous */
dcwbinv(rq, sizeof rq[0]);
- sr->ifc.fiscfg = (1<<6)-1;
- sr->ifc.fisintr = ~0;
- sr->ifc.fisintrena = 0;

diprint("io, using slot %d, off %llud\n", i, off);
v = 1<<i;
satadone &= ~v;
sr->edma.reqin = (ulong)&reqs[reqnext];
if((sr->edma.cmd & EdmaEnable) == 0) {
- sr->edma.cfg |= ECFGncq|0x1f; /* 0x1f for queue depth? */
+ /* xxx verify that DET in sstatus is 3 */
+
+ /* clear edma intr error, and satahc interrupt dmaXdone */
+
+ sr->edma.cfg = (sr->edma.cfg & ~ECFGqueue) | ECFGncq;
+
+ sr->ifc.fisintr = ~0;
+ sr->ifc.fisintrena = 0;
+ sr->ifc.fiscfg = (1<<6)-1;
+
sr->edma.cmd = EdmaEnable;
+ regreadl(&sr->edma.cmd);
}
qunlock(&reqsl);

Reply all
Reply to author
Forward
0 new messages