diff options
| author | Alexander Motin <mav@FreeBSD.org> | 2009-12-02 10:32:34 +0000 |
|---|---|---|
| committer | Alexander Motin <mav@FreeBSD.org> | 2009-12-02 10:32:34 +0000 |
| commit | 03b5c37446e98d28424d501baf5fdca99e4d3f62 (patch) | |
| tree | b59006fe49c8b5cac1c0e186eb5ed08a12272834 /sys/dev/ahci | |
| parent | 7e7ac267c9d95820990dbf395438521bbed8ba2a (diff) | |
Notes
Diffstat (limited to 'sys/dev/ahci')
| -rw-r--r-- | sys/dev/ahci/ahci.c | 112 | ||||
| -rw-r--r-- | sys/dev/ahci/ahci.h | 12 |
2 files changed, 87 insertions, 37 deletions
diff --git a/sys/dev/ahci/ahci.c b/sys/dev/ahci/ahci.c index 459aa64a4654..3f6c9fcdd886 100644 --- a/sys/dev/ahci/ahci.c +++ b/sys/dev/ahci/ahci.c @@ -72,7 +72,7 @@ static void ahci_dmasetprd(void *arg, bus_dma_segment_t *segs, int nsegs, int er static void ahci_execute_transaction(struct ahci_slot *slot); static void ahci_timeout(struct ahci_slot *slot); static void ahci_end_transaction(struct ahci_slot *slot, enum ahci_err_type et); -static int ahci_setup_fis(struct ahci_cmd_tab *ctp, union ccb *ccb, int tag); +static int ahci_setup_fis(device_t dev, struct ahci_cmd_tab *ctp, union ccb *ccb, int tag); static void ahci_dmainit(device_t dev); static void ahci_dmasetupc_cb(void *xsc, bus_dma_segment_t *segs, int nsegs, int error); static void ahci_dmafini(device_t dev); @@ -776,7 +776,7 @@ ahci_ch_attach(device_t dev) struct ahci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ahci_channel *ch = device_get_softc(dev); struct cam_devq *devq; - int rid, error; + int rid, error, i, sata_rev = 0; ch->dev = dev; ch->unit = (intptr_t)device_get_ivars(dev); @@ -795,9 +795,16 @@ ahci_ch_attach(device_t dev) pci_get_subvendor(ctlr->dev) == 0x1043 && pci_get_subdevice(ctlr->dev) == 0x81e4 && ch->unit == 0) - ch->sata_rev = 1; + sata_rev = 1; resource_int_value(device_get_name(dev), - device_get_unit(dev), "sata_rev", &ch->sata_rev); + device_get_unit(dev), "sata_rev", &sata_rev); + for (i = 0; i < 16; i++) { + ch->user[i].revision = sata_rev; + ch->user[i].mode = 0; + ch->user[i].bytecount = 8192; + ch->user[i].tags = ch->numslots; + ch->curr[i] = ch->user[i]; + } rid = ch->unit; if (!(ch->r_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE))) @@ -1275,6 +1282,10 @@ ahci_check_collision(device_t dev, union ccb *ccb) if (ch->numtslots != 0 && ch->taggedtarget != ccb->ccb_h.target_id) return (1); + /* Tagged command while we have no supported tag free. */ + if (((~ch->oslots) & (0xffffffff >> (32 - + ch->curr[ccb->ccb_h.target_id].tags))) == 0) + return (1); } else { /* Untagged command while tagged are active. */ if (ch->numrslots != 0 && ch->numtslots != 0) @@ -1298,15 +1309,21 @@ ahci_begin_transaction(device_t dev, union ccb *ccb) { struct ahci_channel *ch = device_get_softc(dev); struct ahci_slot *slot; - int tag; + int tag, tags; /* Choose empty slot. */ + tags = ch->numslots; + if ((ccb->ccb_h.func_code == XPT_ATA_IO) && + (ccb->ataio.cmd.flags & CAM_ATAIO_FPDMA)) + tags = ch->curr[ccb->ccb_h.target_id].tags; tag = ch->lastslot; - while (ch->slot[tag].state != AHCI_SLOT_EMPTY) { - if (++tag >= ch->numslots) + while (1) { + if (tag >= tags) tag = 0; - KASSERT(tag != ch->lastslot, ("ahci: ALL SLOTS BUSY!")); - } + if (ch->slot[tag].state == AHCI_SLOT_EMPTY) + break; + tag++; + }; ch->lastslot = tag; /* Occupy chosen slot. */ slot = &ch->slot[tag]; @@ -1315,6 +1332,7 @@ ahci_begin_transaction(device_t dev, union ccb *ccb) if (ch->numrslots == 0 && ch->pm_level > 3) callout_stop(&ch->pm_timer); /* Update channel stats. */ + ch->oslots |= (1 << slot->slot); ch->numrslots++; if ((ccb->ccb_h.func_code == XPT_ATA_IO) && (ccb->ataio.cmd.flags & CAM_ATAIO_FPDMA)) { @@ -1392,7 +1410,7 @@ ahci_execute_transaction(struct ahci_slot *slot) ctp = (struct ahci_cmd_tab *) (ch->dma.work + AHCI_CT_OFFSET + (AHCI_CT_SIZE * slot->slot)); /* Setup the FIS for this request */ - if (!(fis_size = ahci_setup_fis(ctp, ccb, slot->slot))) { + if (!(fis_size = ahci_setup_fis(dev, ctp, ccb, slot->slot))) { device_printf(ch->dev, "Setting up SATA FIS failed\n"); ahci_end_transaction(slot, AHCI_ERR_INVALID); return; @@ -1635,6 +1653,7 @@ ahci_end_transaction(struct ahci_slot *slot, enum ahci_err_type et) ccb->ccb_h.status |= CAM_REQ_CMP_ERR; } /* Free slot. */ + ch->oslots &= ~(1 << slot->slot); ch->rslots &= ~(1 << slot->slot); ch->aslots &= ~(1 << slot->slot); slot->state = AHCI_SLOT_EMPTY; @@ -1664,7 +1683,7 @@ ahci_end_transaction(struct ahci_slot *slot, enum ahci_err_type et) } else xpt_done(ccb); /* Unfreeze frozen command. */ - if (ch->frozen && ch->numrslots == 0) { + if (ch->frozen && !ahci_check_collision(dev, ch->frozen)) { union ccb *fccb = ch->frozen; ch->frozen = NULL; ahci_begin_transaction(dev, fccb); @@ -1964,8 +1983,9 @@ ahci_reset(device_t dev) } static int -ahci_setup_fis(struct ahci_cmd_tab *ctp, union ccb *ccb, int tag) +ahci_setup_fis(device_t dev, struct ahci_cmd_tab *ctp, union ccb *ccb, int tag) { + struct ahci_channel *ch = device_get_softc(dev); u_int8_t *fis = &ctp->cfis[0]; bzero(ctp->cfis, 64); @@ -1974,7 +1994,8 @@ ahci_setup_fis(struct ahci_cmd_tab *ctp, union ccb *ccb, int tag) if (ccb->ccb_h.func_code == XPT_SCSI_IO) { fis[1] |= 0x80; fis[2] = ATA_PACKET_CMD; - if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) + if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE && + ch->curr[ccb->ccb_h.target_id].mode >= ATA_DMA) fis[3] = ATA_F_DMA; else { fis[5] = ccb->csio.dxfer_len; @@ -2054,6 +2075,7 @@ static int ahci_sata_phy_reset(device_t dev, int quick) { struct ahci_channel *ch = device_get_softc(dev); + int sata_rev; uint32_t val; if (quick) { @@ -2064,11 +2086,12 @@ ahci_sata_phy_reset(device_t dev, int quick) if (bootverbose) device_printf(dev, "hardware reset ...\n"); - if (ch->sata_rev == 1) + sata_rev = ch->user[ch->pm_present ? 15 : 0].revision; + if (sata_rev == 1) val = ATA_SC_SPD_SPEED_GEN1; - else if (ch->sata_rev == 2) + else if (sata_rev == 2) val = ATA_SC_SPD_SPEED_GEN2; - else if (ch->sata_rev == 3) + else if (sata_rev == 3) val = ATA_SC_SPD_SPEED_GEN3; else val = 0; @@ -2125,10 +2148,22 @@ ahciaction(struct cam_sim *sim, union ccb *ccb) case XPT_SET_TRAN_SETTINGS: { struct ccb_trans_settings *cts = &ccb->cts; + struct ahci_device *d; - if (cts->xport_specific.sata.valid & CTS_SATA_VALID_PM) { + if (cts->type == CTS_TYPE_CURRENT_SETTINGS) + d = &ch->curr[ccb->ccb_h.target_id]; + else + d = &ch->user[ccb->ccb_h.target_id]; + if (cts->xport_specific.sata.valid & CTS_SATA_VALID_REVISION) + d->revision = cts->xport_specific.sata.revision; + if (cts->xport_specific.sata.valid & CTS_SATA_VALID_MODE) + d->mode = cts->xport_specific.sata.mode; + if (cts->xport_specific.sata.valid & CTS_SATA_VALID_BYTECOUNT) + d->bytecount = min(8192, cts->xport_specific.sata.bytecount); + if (cts->xport_specific.sata.valid & CTS_SATA_VALID_TAGS) + d->tags = min(ch->numslots, cts->xport_specific.sata.tags); + if (cts->xport_specific.sata.valid & CTS_SATA_VALID_PM) ch->pm_present = cts->xport_specific.sata.pm_present; - } ccb->ccb_h.status = CAM_REQ_CMP; xpt_done(ccb); break; @@ -2137,36 +2172,41 @@ ahciaction(struct cam_sim *sim, union ccb *ccb) /* Get default/user set transfer settings for the target */ { struct ccb_trans_settings *cts = &ccb->cts; + struct ahci_device *d; uint32_t status; + if (cts->type == CTS_TYPE_CURRENT_SETTINGS) + d = &ch->curr[ccb->ccb_h.target_id]; + else + d = &ch->user[ccb->ccb_h.target_id]; cts->protocol = PROTO_ATA; cts->protocol_version = PROTO_VERSION_UNSPECIFIED; cts->transport = XPORT_SATA; cts->transport_version = XPORT_VERSION_UNSPECIFIED; cts->proto_specific.valid = 0; cts->xport_specific.sata.valid = 0; - if (cts->type == CTS_TYPE_CURRENT_SETTINGS) + if (cts->type == CTS_TYPE_CURRENT_SETTINGS && + (ccb->ccb_h.target_id == 15 || + (ccb->ccb_h.target_id == 0 && !ch->pm_present))) { status = ATA_INL(ch->r_mem, AHCI_P_SSTS) & ATA_SS_SPD_MASK; - else - status = ATA_INL(ch->r_mem, AHCI_P_SCTL) & ATA_SC_SPD_MASK; - if (status & ATA_SS_SPD_GEN3) { - cts->xport_specific.sata.bitrate = 600000; - cts->xport_specific.sata.valid |= CTS_SATA_VALID_SPEED; - } else if (status & ATA_SS_SPD_GEN2) { - cts->xport_specific.sata.bitrate = 300000; - cts->xport_specific.sata.valid |= CTS_SATA_VALID_SPEED; - } else if (status & ATA_SS_SPD_GEN1) { - cts->xport_specific.sata.bitrate = 150000; - cts->xport_specific.sata.valid |= CTS_SATA_VALID_SPEED; - } - if (cts->type == CTS_TYPE_CURRENT_SETTINGS) { - cts->xport_specific.sata.pm_present = - (ATA_INL(ch->r_mem, AHCI_P_CMD) & AHCI_P_CMD_PMA) ? - 1 : 0; + if (status & 0x0f0) { + cts->xport_specific.sata.revision = + (status & 0x0f0) >> 4; + cts->xport_specific.sata.valid |= + CTS_SATA_VALID_REVISION; + } } else { - cts->xport_specific.sata.pm_present = ch->pm_present; + cts->xport_specific.sata.revision = d->revision; + cts->xport_specific.sata.valid |= CTS_SATA_VALID_REVISION; } + cts->xport_specific.sata.mode = d->mode; + cts->xport_specific.sata.valid |= CTS_SATA_VALID_MODE; + cts->xport_specific.sata.bytecount = d->bytecount; + cts->xport_specific.sata.valid |= CTS_SATA_VALID_BYTECOUNT; + cts->xport_specific.sata.pm_present = ch->pm_present; cts->xport_specific.sata.valid |= CTS_SATA_VALID_PM; + cts->xport_specific.sata.tags = d->tags; + cts->xport_specific.sata.valid |= CTS_SATA_VALID_TAGS; ccb->ccb_h.status = CAM_REQ_CMP; xpt_done(ccb); break; diff --git a/sys/dev/ahci/ahci.h b/sys/dev/ahci/ahci.h index cda907812dfe..e11f84f489d3 100644 --- a/sys/dev/ahci/ahci.h +++ b/sys/dev/ahci/ahci.h @@ -340,6 +340,13 @@ struct ahci_slot { struct callout timeout; /* Execution timeout */ }; +struct ahci_device { + int revision; + int mode; + u_int bytecount; + u_int tags; +}; + /* structure describing an ATA channel */ struct ahci_channel { device_t dev; /* Device handle */ @@ -355,13 +362,13 @@ struct ahci_channel { int quirks; int numslots; /* Number of present slots */ int pm_level; /* power management level */ - int sata_rev; /* Maximum allowed SATA generation */ struct ahci_slot slot[AHCI_MAX_SLOTS]; union ccb *hold[AHCI_MAX_SLOTS]; struct mtx mtx; /* state lock */ int devices; /* What is present */ int pm_present; /* PM presence reported */ + uint32_t oslots; /* Occupied slots */ uint32_t rslots; /* Running slots */ uint32_t aslots; /* Slots with atomic commands */ int numrslots; /* Number of running slots */ @@ -372,6 +379,9 @@ struct ahci_channel { int taggedtarget; /* Last tagged target */ union ccb *frozen; /* Frozen command */ struct callout pm_timer; /* Power management events */ + + struct ahci_device user[16]; /* User-specified settings */ + struct ahci_device curr[16]; /* Current settings */ }; /* structure describing a AHCI controller */ |
