summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXin LI <delphij@FreeBSD.org>2007-12-09 19:27:19 +0000
committerXin LI <delphij@FreeBSD.org>2007-12-09 19:27:19 +0000
commit2e79acad5f96c3a54ec7b577b68af17bfdd04233 (patch)
treedd183f8d4610185aa99556a1b40d2fc4a1ec55d9
parentef3bafb1ea76b040584081ae244530715dee1d39 (diff)
Notes
-rw-r--r--sys/dev/ata/ata-chipset.c172
-rw-r--r--sys/dev/ata/ata-disk.c2
2 files changed, 133 insertions, 41 deletions
diff --git a/sys/dev/ata/ata-chipset.c b/sys/dev/ata/ata-chipset.c
index 47594d8d7e72..10603d06a3bb 100644
--- a/sys/dev/ata/ata-chipset.c
+++ b/sys/dev/ata/ata-chipset.c
@@ -96,6 +96,7 @@ static int ata_intel_allocate(device_t dev);
static void ata_intel_reset(device_t dev);
static void ata_intel_old_setmode(device_t dev, int mode);
static void ata_intel_new_setmode(device_t dev, int mode);
+static void ata_intel_sata_setmode(device_t dev, int mode);
static int ata_intel_31244_allocate(device_t dev);
static int ata_intel_31244_status(device_t dev);
static int ata_intel_31244_command(struct ata_request *request);
@@ -1859,8 +1860,15 @@ ata_intel_chipinit(device_t dev)
(pci_read_config(dev, 0x90, 1) & 0xc0) &&
(ata_ahci_chipinit(dev) != ENXIO))
return 0;
-
- ctlr->setmode = ata_sata_setmode;
+
+ /* if BAR(5) is IO it should point to SATA interface registers */
+ ctlr->r_type2 = SYS_RES_IOPORT;
+ ctlr->r_rid2 = PCIR_BAR(5);
+ if ((ctlr->r_res2 = bus_alloc_resource_any(dev, ctlr->r_type2,
+ &ctlr->r_rid2, RF_ACTIVE)))
+ ctlr->setmode = ata_intel_sata_setmode;
+ else
+ ctlr->setmode = ata_sata_setmode;
/* enable PCI interrupt */
pci_write_config(dev, PCIR_COMMAND,
@@ -1872,12 +1880,21 @@ ata_intel_chipinit(device_t dev)
static int
ata_intel_allocate(device_t dev)
{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
struct ata_channel *ch = device_get_softc(dev);
/* setup the usual register normal pci style */
if (ata_pci_allocate(dev))
return ENXIO;
+ /* if r_res2 is valid it points to SATA interface registers */
+ if (ctlr->r_res2) {
+ ch->r_io[ATA_IDX_ADDR].res = ctlr->r_res2;
+ ch->r_io[ATA_IDX_ADDR].offset = 0x00;
+ ch->r_io[ATA_IDX_DATA].res = ctlr->r_res2;
+ ch->r_io[ATA_IDX_DATA].offset = 0x04;
+ }
+
ch->flags |= ATA_ALWAYS_DMASTAT;
return 0;
}
@@ -2004,6 +2021,38 @@ ata_intel_new_setmode(device_t dev, int mode)
atadev->mode = mode;
}
+static void
+ata_intel_sata_setmode(device_t dev, int mode)
+{
+ struct ata_device *atadev = device_get_softc(dev);
+
+ if (atadev->param.satacapabilities != 0x0000 &&
+ atadev->param.satacapabilities != 0xffff) {
+
+ struct ata_channel *ch = device_get_softc(device_get_parent(dev));
+ int devno = (ch->unit << 1) + ATA_DEV(atadev->unit);
+
+ /* on some drives we need to set the transfer mode */
+ ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0,
+ ata_limit_mode(dev, mode, ATA_UDMA6));
+
+ /* set ATA_SSTATUS register offset */
+ ATA_IDX_OUTL(ch, ATA_IDX_ADDR, devno * 0x100);
+
+ /* query SATA STATUS for the speed */
+ if ((ATA_IDX_INL(ch, ATA_IDX_DATA) & ATA_SS_CONWELL_MASK) ==
+ ATA_SS_CONWELL_GEN2)
+ atadev->mode = ATA_SA300;
+ else
+ atadev->mode = ATA_SA150;
+ }
+ else {
+ mode = ata_limit_mode(dev, mode, ATA_UDMA5);
+ if (!ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode))
+ atadev->mode = mode;
+ }
+}
+
static int
ata_intel_31244_allocate(device_t dev)
{
@@ -2260,7 +2309,7 @@ ata_jmicron_chipinit(device_t dev)
pci_write_config(dev, 0x40, 0x80c0a131, 4);
pci_write_config(dev, 0x80, 0x01200000, 4);
- if ((error = ata_ahci_chipinit(dev)))
+ if (ctlr->chip->cfg1 && (error = ata_ahci_chipinit(dev)))
return error;
ctlr->allocate = ata_jmicron_allocate;
@@ -4621,12 +4670,11 @@ struct ata_siiprb_dma_prdentry {
} __packed;
struct ata_siiprb_ata_command {
- u_int32_t reserved0;
struct ata_siiprb_dma_prdentry prd[126];
} __packed;
struct ata_siiprb_atapi_command {
- u_int8_t cdb[16];
+ u_int8_t ccb[16];
struct ata_siiprb_dma_prdentry prd[125];
} __packed;
@@ -4634,7 +4682,7 @@ struct ata_siiprb_command {
u_int16_t control;
u_int16_t protocol_override;
u_int32_t transfer_count;
- u_int8_t fis[20];
+ u_int8_t fis[24];
union {
struct ata_siiprb_ata_command ata;
struct ata_siiprb_atapi_command atapi;
@@ -4670,9 +4718,10 @@ ata_siiprb_status(device_t dev)
{
struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
struct ata_channel *ch = device_get_softc(dev);
+ u_int32_t action = ATA_INL(ctlr->r_res1, 0x0044);
int offset = ch->unit * 0x2000;
- if ((ATA_INL(ctlr->r_res1, 0x0044) & (1 << ch->unit))) {
+ if (action & (1 << ch->unit)) {
u_int32_t istatus = ATA_INL(ctlr->r_res2, 0x1008 + offset);
/* do we have any PHY events ? */
@@ -4682,7 +4731,7 @@ ata_siiprb_status(device_t dev)
ATA_OUTL(ctlr->r_res2, 0x1008 + offset, istatus);
/* do we have any device action ? */
- return (istatus & 0x00000001);
+ return (istatus & 0x00000003);
}
return 0;
}
@@ -4693,10 +4742,17 @@ ata_siiprb_begin_transaction(struct ata_request *request)
struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev));
struct ata_channel *ch = device_get_softc(device_get_parent(request->dev));
struct ata_siiprb_command *prb;
+ struct ata_siiprb_dma_prdentry *prd;
int offset = ch->unit * 0x2000;
u_int64_t prb_bus;
int tag = 0, dummy;
+ /* SOS XXX */
+ if (request->u.ata.command == ATA_DEVICE_RESET) {
+ request->result = 0;
+ return ATA_OP_FINISHED;
+ }
+
/* check for 48 bit access and convert if needed */
ata_modify_if_48bit(request);
@@ -4714,14 +4770,26 @@ ata_siiprb_begin_transaction(struct ata_request *request)
return ATA_OP_FINISHED;
}
- /* if request moves data setup and load SG list */
- if (request->flags & (ATA_R_READ | ATA_R_WRITE)) {
- struct ata_siiprb_dma_prdentry *prd;
+ /* setup transfer type */
+ if (request->flags & ATA_R_ATAPI) {
+ struct ata_device *atadev = device_get_softc(request->dev);
- if (request->flags & ATA_R_ATAPI)
- prd = &prb->u.atapi.prd[0];
+ bcopy(request->u.atapi.ccb, prb->u.atapi.ccb, 16);
+ if ((atadev->param.config & ATA_PROTO_MASK) == ATA_PROTO_ATAPI_12)
+ ATA_OUTL(ctlr->r_res2, 0x1004 + offset, 0x00000020);
else
- prd = &prb->u.ata.prd[0];
+ ATA_OUTL(ctlr->r_res2, 0x1000 + offset, 0x00000020);
+ if (request->flags & ATA_R_READ)
+ prb->control = htole16(0x0010);
+ if (request->flags & ATA_R_WRITE)
+ prb->control = htole16(0x0020);
+ prd = &prb->u.atapi.prd[0];
+ }
+ else
+ prd = &prb->u.ata.prd[0];
+
+ /* if request moves data setup and load SG list */
+ if (request->flags & (ATA_R_READ | ATA_R_WRITE)) {
if (ch->dma->load(ch->dev, request->data, request->bytecount,
request->flags & ATA_R_READ, prd, &dummy)) {
device_printf(request->dev, "setting up DMA failed\n");
@@ -4750,7 +4818,7 @@ ata_siiprb_end_transaction(struct ata_request *request)
struct ata_channel *ch = device_get_softc(device_get_parent(request->dev));
struct ata_siiprb_command *prb;
int offset = ch->unit * 0x2000;
- int error, tag = 0;
+ int error, timeout, tag = 0;
/* kill the timeout */
callout_stop(&request->callout);
@@ -4758,10 +4826,37 @@ ata_siiprb_end_transaction(struct ata_request *request)
prb = (struct ata_siiprb_command *)
((u_int8_t *)rman_get_virtual(ctlr->r_res2) + (tag << 7) + offset);
- /* if error status get details */
- request->status = prb->fis[2];
- if (request->status & ATA_S_ERROR)
- request->error = prb->fis[3];
+ /* any controller errors flagged ? */
+ if ((error = ATA_INL(ctlr->r_res2, 0x1024 + offset))) {
+ if (bootverbose)
+ printf("ata_siiprb_end_transaction %s error=%08x\n",
+ ata_cmd2str(request), error);
+
+ /* if device error status get details */
+ if (error == 1 || error == 2) {
+ request->status = prb->fis[2];
+ if (request->status & ATA_S_ERROR)
+ request->error = prb->fis[3];
+ }
+
+ /* SOS XXX handle other controller errors here */
+
+ /* initialize port */
+ ATA_OUTL(ctlr->r_res2, 0x1000 + offset, 0x00000004);
+
+ /* poll for port ready */
+ for (timeout = 0; timeout < 1000; timeout++) {
+ DELAY(1000);
+ if (ATA_INL(ctlr->r_res2, 0x1008 + offset) & 0x00040000)
+ break;
+ }
+ if (bootverbose) {
+ if (timeout >= 1000)
+ device_printf(ch->dev, "port initialize timeout\n");
+ else
+ device_printf(ch->dev, "port initialize time=%dms\n", timeout);
+ }
+ }
/* update progress */
if (!(request->status & ATA_S_ERROR) && !(request->flags & ATA_R_TIMEOUT)) {
@@ -4771,12 +4866,6 @@ ata_siiprb_end_transaction(struct ata_request *request)
request->donecount = request->bytecount;
}
- /* any controller errors flagged ? */
- if ((error = ATA_INL(ctlr->r_res2, 0x1024 + offset))) {
- printf("ata_siiprb_end_transaction %s error=%08x\n",
- ata_cmd2str(request), error);
- }
-
/* release SG list etc */
ch->dma->unload(ch->dev);
@@ -4802,17 +4891,17 @@ ata_siiprb_reset(device_t dev)
/* poll for channel ready */
for (timeout = 0; timeout < 1000; timeout++) {
- if ((status = ATA_INL(ctlr->r_res2, 0x1000 + offset)) & 0x00040000)
+ if ((status = ATA_INL(ctlr->r_res2, 0x1008 + offset)) & 0x00040000)
break;
DELAY(1000);
}
- if (timeout >= 1000) {
- device_printf(ch->dev, "channel HW reset timeout reset failure\n");
- ch->devices = 0;
- goto finish;
+
+ if (bootverbose) {
+ if (timeout >= 1000)
+ device_printf(ch->dev, "channel HW reset timeout\n");
+ else
+ device_printf(ch->dev, "channel HW reset time=%dms\n", timeout);
}
- if (bootverbose)
- device_printf(ch->dev, "channel HW reset time=%dms\n", timeout * 1);
/* reset phy */
if (!ata_sata_phy_reset(dev)) {
@@ -4835,8 +4924,8 @@ ata_siiprb_reset(device_t dev)
ATA_OUTL(ctlr->r_res2,
0x1c04 + offset + (tag * sizeof(u_int64_t)), prb_bus>>32);
- /* poll for channel ready */
- for (timeout = 0; timeout < 1000; timeout++) {
+ /* poll for command finished */
+ for (timeout = 0; timeout < 10000; timeout++) {
DELAY(1000);
if ((status = ATA_INL(ctlr->r_res2, 0x1008 + offset)) & 0x00010000)
break;
@@ -4856,24 +4945,25 @@ ata_siiprb_reset(device_t dev)
signature =
prb->fis[12]|(prb->fis[4]<<8)|(prb->fis[5]<<16)|(prb->fis[6]<<24);
if (bootverbose)
- device_printf(ch->dev, "signature=%08x\n", signature);
+ device_printf(ch->dev, "SIGNATURE=%08x\n", signature);
switch (signature) {
- case 0xeb140101:
- ch->devices = ATA_ATAPI_MASTER;
- device_printf(ch->dev, "SATA ATAPI devices not supported yet\n");
- ch->devices = 0;
+ case 0x00000101:
+ ch->devices = ATA_ATA_MASTER;
break;
case 0x96690101:
ch->devices = ATA_PORTMULTIPLIER;
device_printf(ch->dev, "Portmultipliers not supported yet\n");
ch->devices = 0;
break;
- case 0x00000101:
- ch->devices = ATA_ATA_MASTER;
+ case 0xeb140101:
+ ch->devices = ATA_ATAPI_MASTER;
break;
default:
ch->devices = 0;
}
+ if (bootverbose)
+ device_printf(dev, "siiprb_reset devices=0x%b\n", ch->devices,
+ "\20\4ATAPI_SLAVE\3ATAPI_MASTER\2ATA_SLAVE\1ATA_MASTER");
finish:
/* clear interrupt(s) */
diff --git a/sys/dev/ata/ata-disk.c b/sys/dev/ata/ata-disk.c
index 270276753afc..0288337ea57c 100644
--- a/sys/dev/ata/ata-disk.c
+++ b/sys/dev/ata/ata-disk.c
@@ -369,6 +369,8 @@ ad_describe(device_t dev)
else {
if (!strncmp(atadev->param.model, "ST", 2))
strcpy(vendor, "Seagate ");
+ else if (!strncmp(atadev->param.model, "HDS", 3))
+ strcpy(vendor, "Hitachi ");
else
strcpy(vendor, "");
strncpy(product, atadev->param.model, 40);