Add preliminary SATA ATAPI support for sii 3132/3124 chips.

This commit is contained in:
sos 2007-11-23 08:17:14 +00:00
parent c5a1cf34b3
commit 9d7c423748
2 changed files with 81 additions and 38 deletions

View File

@ -4621,12 +4621,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 +4633,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 +4669,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 +4682,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 +4693,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 +4721,26 @@ ata_siiprb_begin_transaction(struct ata_request *request)
return ATA_OP_FINISHED;
}
/* setup transfer type */
if (request->flags & ATA_R_ATAPI) {
struct ata_device *atadev = device_get_softc(request->dev);
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
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)) {
struct ata_siiprb_dma_prdentry *prd;
if (request->flags & ATA_R_ATAPI)
prd = &prb->u.atapi.prd[0];
else
prd = &prb->u.ata.prd[0];
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 +4769,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 +4777,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 +4817,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 +4842,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 +4875,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 +4896,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) */

View File

@ -391,6 +391,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);