diff options
| author | Xin LI <delphij@FreeBSD.org> | 2007-12-09 19:27:19 +0000 |
|---|---|---|
| committer | Xin LI <delphij@FreeBSD.org> | 2007-12-09 19:27:19 +0000 |
| commit | 2e79acad5f96c3a54ec7b577b68af17bfdd04233 (patch) | |
| tree | dd183f8d4610185aa99556a1b40d2fc4a1ec55d9 | |
| parent | ef3bafb1ea76b040584081ae244530715dee1d39 (diff) | |
Notes
| -rw-r--r-- | sys/dev/ata/ata-chipset.c | 172 | ||||
| -rw-r--r-- | sys/dev/ata/ata-disk.c | 2 |
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); |
