Bunch of microoptimizations to reduce dereferences and cache collisions.
This commit is contained in:
parent
7105bcbd70
commit
07b6763268
@ -61,31 +61,31 @@ static void ahci_ch_pm(void *arg);
|
|||||||
static void ahci_ch_intr(void *arg);
|
static void ahci_ch_intr(void *arg);
|
||||||
static void ahci_ch_intr_direct(void *arg);
|
static void ahci_ch_intr_direct(void *arg);
|
||||||
static void ahci_ch_intr_main(struct ahci_channel *ch, uint32_t istatus);
|
static void ahci_ch_intr_main(struct ahci_channel *ch, uint32_t istatus);
|
||||||
static void ahci_begin_transaction(device_t dev, union ccb *ccb);
|
static void ahci_begin_transaction(struct ahci_channel *ch, union ccb *ccb);
|
||||||
static void ahci_dmasetprd(void *arg, bus_dma_segment_t *segs, int nsegs, int error);
|
static void ahci_dmasetprd(void *arg, bus_dma_segment_t *segs, int nsegs, int error);
|
||||||
static void ahci_execute_transaction(struct ahci_slot *slot);
|
static void ahci_execute_transaction(struct ahci_slot *slot);
|
||||||
static void ahci_timeout(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 void ahci_end_transaction(struct ahci_slot *slot, enum ahci_err_type et);
|
||||||
static int ahci_setup_fis(device_t dev, struct ahci_cmd_tab *ctp, union ccb *ccb, int tag);
|
static int ahci_setup_fis(struct ahci_channel *ch, struct ahci_cmd_tab *ctp, union ccb *ccb, int tag);
|
||||||
static void ahci_dmainit(device_t dev);
|
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_dmasetupc_cb(void *xsc, bus_dma_segment_t *segs, int nsegs, int error);
|
||||||
static void ahci_dmafini(device_t dev);
|
static void ahci_dmafini(device_t dev);
|
||||||
static void ahci_slotsalloc(device_t dev);
|
static void ahci_slotsalloc(device_t dev);
|
||||||
static void ahci_slotsfree(device_t dev);
|
static void ahci_slotsfree(device_t dev);
|
||||||
static void ahci_reset(device_t dev);
|
static void ahci_reset(struct ahci_channel *ch);
|
||||||
static void ahci_start(device_t dev, int fbs);
|
static void ahci_start(struct ahci_channel *ch, int fbs);
|
||||||
static void ahci_stop(device_t dev);
|
static void ahci_stop(struct ahci_channel *ch);
|
||||||
static void ahci_clo(device_t dev);
|
static void ahci_clo(struct ahci_channel *ch);
|
||||||
static void ahci_start_fr(device_t dev);
|
static void ahci_start_fr(struct ahci_channel *ch);
|
||||||
static void ahci_stop_fr(device_t dev);
|
static void ahci_stop_fr(struct ahci_channel *ch);
|
||||||
|
|
||||||
static int ahci_sata_connect(struct ahci_channel *ch);
|
static int ahci_sata_connect(struct ahci_channel *ch);
|
||||||
static int ahci_sata_phy_reset(device_t dev);
|
static int ahci_sata_phy_reset(struct ahci_channel *ch);
|
||||||
static int ahci_wait_ready(device_t dev, int t, int t0);
|
static int ahci_wait_ready(struct ahci_channel *ch, int t, int t0);
|
||||||
|
|
||||||
static void ahci_issue_recovery(device_t dev);
|
static void ahci_issue_recovery(struct ahci_channel *ch);
|
||||||
static void ahci_process_read_log(device_t dev, union ccb *ccb);
|
static void ahci_process_read_log(struct ahci_channel *ch, union ccb *ccb);
|
||||||
static void ahci_process_request_sense(device_t dev, union ccb *ccb);
|
static void ahci_process_request_sense(struct ahci_channel *ch, union ccb *ccb);
|
||||||
|
|
||||||
static void ahciaction(struct cam_sim *sim, union ccb *ccb);
|
static void ahciaction(struct cam_sim *sim, union ccb *ccb);
|
||||||
static void ahcipoll(struct cam_sim *sim);
|
static void ahcipoll(struct cam_sim *sim);
|
||||||
@ -669,7 +669,7 @@ ahci_ch_attach(device_t dev)
|
|||||||
}
|
}
|
||||||
if ((bus_setup_intr(dev, ch->r_irq, ATA_INTR_FLAGS, NULL,
|
if ((bus_setup_intr(dev, ch->r_irq, ATA_INTR_FLAGS, NULL,
|
||||||
ctlr->direct ? ahci_ch_intr_direct : ahci_ch_intr,
|
ctlr->direct ? ahci_ch_intr_direct : ahci_ch_intr,
|
||||||
dev, &ch->ih))) {
|
ch, &ch->ih))) {
|
||||||
device_printf(dev, "Unable to setup interrupt\n");
|
device_printf(dev, "Unable to setup interrupt\n");
|
||||||
error = ENXIO;
|
error = ENXIO;
|
||||||
goto err1;
|
goto err1;
|
||||||
@ -698,7 +698,7 @@ ahci_ch_attach(device_t dev)
|
|||||||
}
|
}
|
||||||
/* Construct SIM entry */
|
/* Construct SIM entry */
|
||||||
ch->sim = cam_sim_alloc(ahciaction, ahcipoll, "ahcich", ch,
|
ch->sim = cam_sim_alloc(ahciaction, ahcipoll, "ahcich", ch,
|
||||||
device_get_unit(dev), &ch->mtx,
|
device_get_unit(dev), (struct mtx *)&ch->mtx,
|
||||||
min(2, ch->numslots),
|
min(2, ch->numslots),
|
||||||
(ch->caps & AHCI_CAP_SNCQ) ? ch->numslots : 0,
|
(ch->caps & AHCI_CAP_SNCQ) ? ch->numslots : 0,
|
||||||
devq);
|
devq);
|
||||||
@ -722,7 +722,7 @@ ahci_ch_attach(device_t dev)
|
|||||||
if (ch->pm_level > 3) {
|
if (ch->pm_level > 3) {
|
||||||
callout_reset(&ch->pm_timer,
|
callout_reset(&ch->pm_timer,
|
||||||
(ch->pm_level == 4) ? hz / 1000 : hz / 8,
|
(ch->pm_level == 4) ? hz / 1000 : hz / 8,
|
||||||
ahci_ch_pm, dev);
|
ahci_ch_pm, ch);
|
||||||
}
|
}
|
||||||
mtx_unlock(&ch->mtx);
|
mtx_unlock(&ch->mtx);
|
||||||
return (0);
|
return (0);
|
||||||
@ -792,8 +792,8 @@ ahci_ch_init(device_t dev)
|
|||||||
(AHCI_P_CMD_ACTIVE | AHCI_P_CMD_POD | AHCI_P_CMD_SUD |
|
(AHCI_P_CMD_ACTIVE | AHCI_P_CMD_POD | AHCI_P_CMD_SUD |
|
||||||
((ch->pm_level == 2 || ch->pm_level == 3) ? AHCI_P_CMD_ALPE : 0) |
|
((ch->pm_level == 2 || ch->pm_level == 3) ? AHCI_P_CMD_ALPE : 0) |
|
||||||
((ch->pm_level > 2) ? AHCI_P_CMD_ASP : 0 )));
|
((ch->pm_level > 2) ? AHCI_P_CMD_ASP : 0 )));
|
||||||
ahci_start_fr(dev);
|
ahci_start_fr(ch);
|
||||||
ahci_start(dev, 1);
|
ahci_start(ch, 1);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -805,8 +805,8 @@ ahci_ch_deinit(device_t dev)
|
|||||||
/* Disable port interrupts. */
|
/* Disable port interrupts. */
|
||||||
ATA_OUTL(ch->r_mem, AHCI_P_IE, 0);
|
ATA_OUTL(ch->r_mem, AHCI_P_IE, 0);
|
||||||
/* Reset command register. */
|
/* Reset command register. */
|
||||||
ahci_stop(dev);
|
ahci_stop(ch);
|
||||||
ahci_stop_fr(dev);
|
ahci_stop_fr(ch);
|
||||||
ATA_OUTL(ch->r_mem, AHCI_P_CMD, 0);
|
ATA_OUTL(ch->r_mem, AHCI_P_CMD, 0);
|
||||||
/* Allow everything, including partial and slumber modes. */
|
/* Allow everything, including partial and slumber modes. */
|
||||||
ATA_OUTL(ch->r_mem, AHCI_P_SCTL, 0);
|
ATA_OUTL(ch->r_mem, AHCI_P_SCTL, 0);
|
||||||
@ -845,7 +845,7 @@ ahci_ch_resume(device_t dev)
|
|||||||
|
|
||||||
mtx_lock(&ch->mtx);
|
mtx_lock(&ch->mtx);
|
||||||
ahci_ch_init(dev);
|
ahci_ch_init(dev);
|
||||||
ahci_reset(dev);
|
ahci_reset(ch);
|
||||||
xpt_release_simq(ch->sim, TRUE);
|
xpt_release_simq(ch->sim, TRUE);
|
||||||
mtx_unlock(&ch->mtx);
|
mtx_unlock(&ch->mtx);
|
||||||
return (0);
|
return (0);
|
||||||
@ -976,7 +976,7 @@ ahci_slotsalloc(device_t dev)
|
|||||||
for (i = 0; i < ch->numslots; i++) {
|
for (i = 0; i < ch->numslots; i++) {
|
||||||
struct ahci_slot *slot = &ch->slot[i];
|
struct ahci_slot *slot = &ch->slot[i];
|
||||||
|
|
||||||
slot->dev = dev;
|
slot->ch = ch;
|
||||||
slot->slot = i;
|
slot->slot = i;
|
||||||
slot->state = AHCI_SLOT_EMPTY;
|
slot->state = AHCI_SLOT_EMPTY;
|
||||||
slot->ccb = NULL;
|
slot->ccb = NULL;
|
||||||
@ -1006,9 +1006,8 @@ ahci_slotsfree(device_t dev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ahci_phy_check_events(device_t dev, u_int32_t serr)
|
ahci_phy_check_events(struct ahci_channel *ch, u_int32_t serr)
|
||||||
{
|
{
|
||||||
struct ahci_channel *ch = device_get_softc(dev);
|
|
||||||
|
|
||||||
if (((ch->pm_level == 0) && (serr & ATA_SE_PHY_CHANGED)) ||
|
if (((ch->pm_level == 0) && (serr & ATA_SE_PHY_CHANGED)) ||
|
||||||
((ch->pm_level != 0 || ch->listening) && (serr & ATA_SE_EXCHANGED))) {
|
((ch->pm_level != 0 || ch->listening) && (serr & ATA_SE_EXCHANGED))) {
|
||||||
@ -1017,11 +1016,11 @@ ahci_phy_check_events(device_t dev, u_int32_t serr)
|
|||||||
|
|
||||||
if (bootverbose) {
|
if (bootverbose) {
|
||||||
if ((status & ATA_SS_DET_MASK) != ATA_SS_DET_NO_DEVICE)
|
if ((status & ATA_SS_DET_MASK) != ATA_SS_DET_NO_DEVICE)
|
||||||
device_printf(dev, "CONNECT requested\n");
|
device_printf(ch->dev, "CONNECT requested\n");
|
||||||
else
|
else
|
||||||
device_printf(dev, "DISCONNECT requested\n");
|
device_printf(ch->dev, "DISCONNECT requested\n");
|
||||||
}
|
}
|
||||||
ahci_reset(dev);
|
ahci_reset(ch);
|
||||||
if ((ccb = xpt_alloc_ccb_nowait()) == NULL)
|
if ((ccb = xpt_alloc_ccb_nowait()) == NULL)
|
||||||
return (0);
|
return (0);
|
||||||
if (xpt_create_path(&ccb->ccb_h.path, NULL,
|
if (xpt_create_path(&ccb->ccb_h.path, NULL,
|
||||||
@ -1037,11 +1036,11 @@ ahci_phy_check_events(device_t dev, u_int32_t serr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ahci_cpd_check_events(device_t dev)
|
ahci_cpd_check_events(struct ahci_channel *ch)
|
||||||
{
|
{
|
||||||
struct ahci_channel *ch = device_get_softc(dev);
|
|
||||||
u_int32_t status;
|
u_int32_t status;
|
||||||
union ccb *ccb;
|
union ccb *ccb;
|
||||||
|
device_t dev;
|
||||||
|
|
||||||
if (ch->pm_level == 0)
|
if (ch->pm_level == 0)
|
||||||
return;
|
return;
|
||||||
@ -1051,12 +1050,13 @@ ahci_cpd_check_events(device_t dev)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (bootverbose) {
|
if (bootverbose) {
|
||||||
|
dev = ch->dev;
|
||||||
if (status & AHCI_P_CMD_CPS) {
|
if (status & AHCI_P_CMD_CPS) {
|
||||||
device_printf(dev, "COLD CONNECT requested\n");
|
device_printf(dev, "COLD CONNECT requested\n");
|
||||||
} else
|
} else
|
||||||
device_printf(dev, "COLD DISCONNECT requested\n");
|
device_printf(dev, "COLD DISCONNECT requested\n");
|
||||||
}
|
}
|
||||||
ahci_reset(dev);
|
ahci_reset(ch);
|
||||||
if ((ccb = xpt_alloc_ccb_nowait()) == NULL)
|
if ((ccb = xpt_alloc_ccb_nowait()) == NULL)
|
||||||
return;
|
return;
|
||||||
if (xpt_create_path(&ccb->ccb_h.path, NULL, cam_sim_path(ch->sim),
|
if (xpt_create_path(&ccb->ccb_h.path, NULL, cam_sim_path(ch->sim),
|
||||||
@ -1068,16 +1068,15 @@ ahci_cpd_check_events(device_t dev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ahci_notify_events(device_t dev, u_int32_t status)
|
ahci_notify_events(struct ahci_channel *ch, u_int32_t status)
|
||||||
{
|
{
|
||||||
struct ahci_channel *ch = device_get_softc(dev);
|
|
||||||
struct cam_path *dpath;
|
struct cam_path *dpath;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (ch->caps & AHCI_CAP_SSNTF)
|
if (ch->caps & AHCI_CAP_SSNTF)
|
||||||
ATA_OUTL(ch->r_mem, AHCI_P_SNTF, status);
|
ATA_OUTL(ch->r_mem, AHCI_P_SNTF, status);
|
||||||
if (bootverbose)
|
if (bootverbose)
|
||||||
device_printf(dev, "SNTF 0x%04x\n", status);
|
device_printf(ch->dev, "SNTF 0x%04x\n", status);
|
||||||
for (i = 0; i < 16; i++) {
|
for (i = 0; i < 16; i++) {
|
||||||
if ((status & (1 << i)) == 0)
|
if ((status & (1 << i)) == 0)
|
||||||
continue;
|
continue;
|
||||||
@ -1106,8 +1105,7 @@ ahci_done(struct ahci_channel *ch, union ccb *ccb)
|
|||||||
static void
|
static void
|
||||||
ahci_ch_intr(void *arg)
|
ahci_ch_intr(void *arg)
|
||||||
{
|
{
|
||||||
device_t dev = (device_t)arg;
|
struct ahci_channel *ch = (struct ahci_channel *)arg;
|
||||||
struct ahci_channel *ch = device_get_softc(dev);
|
|
||||||
uint32_t istatus;
|
uint32_t istatus;
|
||||||
|
|
||||||
/* Read interrupt statuses. */
|
/* Read interrupt statuses. */
|
||||||
@ -1123,8 +1121,7 @@ ahci_ch_intr(void *arg)
|
|||||||
static void
|
static void
|
||||||
ahci_ch_intr_direct(void *arg)
|
ahci_ch_intr_direct(void *arg)
|
||||||
{
|
{
|
||||||
device_t dev = (device_t)arg;
|
struct ahci_channel *ch = (struct ahci_channel *)arg;
|
||||||
struct ahci_channel *ch = device_get_softc(dev);
|
|
||||||
struct ccb_hdr *ccb_h;
|
struct ccb_hdr *ccb_h;
|
||||||
uint32_t istatus;
|
uint32_t istatus;
|
||||||
|
|
||||||
@ -1147,8 +1144,7 @@ ahci_ch_intr_direct(void *arg)
|
|||||||
static void
|
static void
|
||||||
ahci_ch_pm(void *arg)
|
ahci_ch_pm(void *arg)
|
||||||
{
|
{
|
||||||
device_t dev = (device_t)arg;
|
struct ahci_channel *ch = (struct ahci_channel *)arg;
|
||||||
struct ahci_channel *ch = device_get_softc(dev);
|
|
||||||
uint32_t work;
|
uint32_t work;
|
||||||
|
|
||||||
if (ch->numrslots != 0)
|
if (ch->numrslots != 0)
|
||||||
@ -1164,7 +1160,6 @@ ahci_ch_pm(void *arg)
|
|||||||
static void
|
static void
|
||||||
ahci_ch_intr_main(struct ahci_channel *ch, uint32_t istatus)
|
ahci_ch_intr_main(struct ahci_channel *ch, uint32_t istatus)
|
||||||
{
|
{
|
||||||
device_t dev = ch->dev;
|
|
||||||
uint32_t cstatus, serr = 0, sntf = 0, ok, err;
|
uint32_t cstatus, serr = 0, sntf = 0, ok, err;
|
||||||
enum ahci_err_type et;
|
enum ahci_err_type et;
|
||||||
int i, ccs, port, reset = 0;
|
int i, ccs, port, reset = 0;
|
||||||
@ -1206,12 +1201,12 @@ ahci_ch_intr_main(struct ahci_channel *ch, uint32_t istatus)
|
|||||||
serr = ATA_INL(ch->r_mem, AHCI_P_SERR);
|
serr = ATA_INL(ch->r_mem, AHCI_P_SERR);
|
||||||
if (serr) {
|
if (serr) {
|
||||||
ATA_OUTL(ch->r_mem, AHCI_P_SERR, serr);
|
ATA_OUTL(ch->r_mem, AHCI_P_SERR, serr);
|
||||||
reset = ahci_phy_check_events(dev, serr);
|
reset = ahci_phy_check_events(ch, serr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Process cold presence detection events */
|
/* Process cold presence detection events */
|
||||||
if ((istatus & AHCI_P_IX_CPD) && !reset)
|
if ((istatus & AHCI_P_IX_CPD) && !reset)
|
||||||
ahci_cpd_check_events(dev);
|
ahci_cpd_check_events(ch);
|
||||||
/* Process command errors */
|
/* Process command errors */
|
||||||
if (istatus & (AHCI_P_IX_OF | AHCI_P_IX_IF |
|
if (istatus & (AHCI_P_IX_OF | AHCI_P_IX_IF |
|
||||||
AHCI_P_IX_HBD | AHCI_P_IX_HBF | AHCI_P_IX_TFE)) {
|
AHCI_P_IX_HBD | AHCI_P_IX_HBF | AHCI_P_IX_TFE)) {
|
||||||
@ -1306,14 +1301,13 @@ ahci_ch_intr_main(struct ahci_channel *ch, uint32_t istatus)
|
|||||||
}
|
}
|
||||||
/* Process NOTIFY events */
|
/* Process NOTIFY events */
|
||||||
if (sntf)
|
if (sntf)
|
||||||
ahci_notify_events(dev, sntf);
|
ahci_notify_events(ch, sntf);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Must be called with channel locked. */
|
/* Must be called with channel locked. */
|
||||||
static int
|
static int
|
||||||
ahci_check_collision(device_t dev, union ccb *ccb)
|
ahci_check_collision(struct ahci_channel *ch, union ccb *ccb)
|
||||||
{
|
{
|
||||||
struct ahci_channel *ch = device_get_softc(dev);
|
|
||||||
int t = ccb->ccb_h.target_id;
|
int t = ccb->ccb_h.target_id;
|
||||||
|
|
||||||
if ((ccb->ccb_h.func_code == XPT_ATA_IO) &&
|
if ((ccb->ccb_h.func_code == XPT_ATA_IO) &&
|
||||||
@ -1362,9 +1356,8 @@ ahci_check_collision(device_t dev, union ccb *ccb)
|
|||||||
|
|
||||||
/* Must be called with channel locked. */
|
/* Must be called with channel locked. */
|
||||||
static void
|
static void
|
||||||
ahci_begin_transaction(device_t dev, union ccb *ccb)
|
ahci_begin_transaction(struct ahci_channel *ch, union ccb *ccb)
|
||||||
{
|
{
|
||||||
struct ahci_channel *ch = device_get_softc(dev);
|
|
||||||
struct ahci_slot *slot;
|
struct ahci_slot *slot;
|
||||||
int tag, tags;
|
int tag, tags;
|
||||||
|
|
||||||
@ -1373,14 +1366,14 @@ ahci_begin_transaction(device_t dev, union ccb *ccb)
|
|||||||
if ((ccb->ccb_h.func_code == XPT_ATA_IO) &&
|
if ((ccb->ccb_h.func_code == XPT_ATA_IO) &&
|
||||||
(ccb->ataio.cmd.flags & CAM_ATAIO_FPDMA))
|
(ccb->ataio.cmd.flags & CAM_ATAIO_FPDMA))
|
||||||
tags = ch->curr[ccb->ccb_h.target_id].tags;
|
tags = ch->curr[ccb->ccb_h.target_id].tags;
|
||||||
tag = ch->lastslot;
|
if (ch->lastslot + 1 < tags)
|
||||||
while (1) {
|
tag = ffs(~(ch->oslots >> (ch->lastslot + 1)));
|
||||||
if (tag >= tags)
|
else
|
||||||
tag = 0;
|
tag = 0;
|
||||||
if (ch->slot[tag].state == AHCI_SLOT_EMPTY)
|
if (tag == 0 || tag + ch->lastslot >= tags)
|
||||||
break;
|
tag = ffs(~ch->oslots) - 1;
|
||||||
tag++;
|
else
|
||||||
};
|
tag += ch->lastslot;
|
||||||
ch->lastslot = tag;
|
ch->lastslot = tag;
|
||||||
/* Occupy chosen slot. */
|
/* Occupy chosen slot. */
|
||||||
slot = &ch->slot[tag];
|
slot = &ch->slot[tag];
|
||||||
@ -1389,7 +1382,7 @@ ahci_begin_transaction(device_t dev, union ccb *ccb)
|
|||||||
if (ch->numrslots == 0 && ch->pm_level > 3)
|
if (ch->numrslots == 0 && ch->pm_level > 3)
|
||||||
callout_stop(&ch->pm_timer);
|
callout_stop(&ch->pm_timer);
|
||||||
/* Update channel stats. */
|
/* Update channel stats. */
|
||||||
ch->oslots |= (1 << slot->slot);
|
ch->oslots |= (1 << tag);
|
||||||
ch->numrslots++;
|
ch->numrslots++;
|
||||||
ch->numrslotspd[ccb->ccb_h.target_id]++;
|
ch->numrslotspd[ccb->ccb_h.target_id]++;
|
||||||
if ((ccb->ccb_h.func_code == XPT_ATA_IO) &&
|
if ((ccb->ccb_h.func_code == XPT_ATA_IO) &&
|
||||||
@ -1400,14 +1393,15 @@ ahci_begin_transaction(device_t dev, union ccb *ccb)
|
|||||||
}
|
}
|
||||||
if ((ccb->ccb_h.func_code == XPT_ATA_IO) &&
|
if ((ccb->ccb_h.func_code == XPT_ATA_IO) &&
|
||||||
(ccb->ataio.cmd.flags & (CAM_ATAIO_CONTROL | CAM_ATAIO_NEEDRESULT)))
|
(ccb->ataio.cmd.flags & (CAM_ATAIO_CONTROL | CAM_ATAIO_NEEDRESULT)))
|
||||||
ch->aslots |= (1 << slot->slot);
|
ch->aslots |= (1 << tag);
|
||||||
slot->dma.nsegs = 0;
|
|
||||||
if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
|
if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
|
||||||
slot->state = AHCI_SLOT_LOADING;
|
slot->state = AHCI_SLOT_LOADING;
|
||||||
bus_dmamap_load_ccb(ch->dma.data_tag, slot->dma.data_map, ccb,
|
bus_dmamap_load_ccb(ch->dma.data_tag, slot->dma.data_map, ccb,
|
||||||
ahci_dmasetprd, slot, 0);
|
ahci_dmasetprd, slot, 0);
|
||||||
} else
|
} else {
|
||||||
|
slot->dma.nsegs = 0;
|
||||||
ahci_execute_transaction(slot);
|
ahci_execute_transaction(slot);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Locked by busdma engine. */
|
/* Locked by busdma engine. */
|
||||||
@ -1415,13 +1409,13 @@ static void
|
|||||||
ahci_dmasetprd(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
|
ahci_dmasetprd(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
|
||||||
{
|
{
|
||||||
struct ahci_slot *slot = arg;
|
struct ahci_slot *slot = arg;
|
||||||
struct ahci_channel *ch = device_get_softc(slot->dev);
|
struct ahci_channel *ch = slot->ch;
|
||||||
struct ahci_cmd_tab *ctp;
|
struct ahci_cmd_tab *ctp;
|
||||||
struct ahci_dma_prd *prd;
|
struct ahci_dma_prd *prd;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
device_printf(slot->dev, "DMA load error\n");
|
device_printf(ch->dev, "DMA load error\n");
|
||||||
ahci_end_transaction(slot, AHCI_ERR_INVALID);
|
ahci_end_transaction(slot, AHCI_ERR_INVALID);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1446,8 +1440,7 @@ ahci_dmasetprd(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
|
|||||||
static void
|
static void
|
||||||
ahci_execute_transaction(struct ahci_slot *slot)
|
ahci_execute_transaction(struct ahci_slot *slot)
|
||||||
{
|
{
|
||||||
device_t dev = slot->dev;
|
struct ahci_channel *ch = slot->ch;
|
||||||
struct ahci_channel *ch = device_get_softc(dev);
|
|
||||||
struct ahci_cmd_tab *ctp;
|
struct ahci_cmd_tab *ctp;
|
||||||
struct ahci_cmd_list *clp;
|
struct ahci_cmd_list *clp;
|
||||||
union ccb *ccb = slot->ccb;
|
union ccb *ccb = slot->ccb;
|
||||||
@ -1460,7 +1453,7 @@ ahci_execute_transaction(struct ahci_slot *slot)
|
|||||||
ctp = (struct ahci_cmd_tab *)
|
ctp = (struct ahci_cmd_tab *)
|
||||||
(ch->dma.work + AHCI_CT_OFFSET + (AHCI_CT_SIZE * slot->slot));
|
(ch->dma.work + AHCI_CT_OFFSET + (AHCI_CT_SIZE * slot->slot));
|
||||||
/* Setup the FIS for this request */
|
/* Setup the FIS for this request */
|
||||||
if (!(fis_size = ahci_setup_fis(dev, ctp, ccb, slot->slot))) {
|
if (!(fis_size = ahci_setup_fis(ch, ctp, ccb, slot->slot))) {
|
||||||
device_printf(ch->dev, "Setting up SATA FIS failed\n");
|
device_printf(ch->dev, "Setting up SATA FIS failed\n");
|
||||||
ahci_end_transaction(slot, AHCI_ERR_INVALID);
|
ahci_end_transaction(slot, AHCI_ERR_INVALID);
|
||||||
return;
|
return;
|
||||||
@ -1481,9 +1474,9 @@ ahci_execute_transaction(struct ahci_slot *slot)
|
|||||||
if (ccb->ataio.cmd.control & ATA_A_RESET) {
|
if (ccb->ataio.cmd.control & ATA_A_RESET) {
|
||||||
softreset = 1;
|
softreset = 1;
|
||||||
/* Kick controller into sane state */
|
/* Kick controller into sane state */
|
||||||
ahci_stop(dev);
|
ahci_stop(ch);
|
||||||
ahci_clo(dev);
|
ahci_clo(ch);
|
||||||
ahci_start(dev, 0);
|
ahci_start(ch, 0);
|
||||||
clp->cmd_flags |= AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY;
|
clp->cmd_flags |= AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY;
|
||||||
} else {
|
} else {
|
||||||
softreset = 2;
|
softreset = 2;
|
||||||
@ -1561,9 +1554,9 @@ ahci_execute_transaction(struct ahci_slot *slot)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (timeout && (count >= timeout)) {
|
if (timeout && (count >= timeout)) {
|
||||||
device_printf(dev, "Poll timeout on slot %d port %d\n",
|
device_printf(ch->dev, "Poll timeout on slot %d port %d\n",
|
||||||
slot->slot, port);
|
slot->slot, port);
|
||||||
device_printf(dev, "is %08x cs %08x ss %08x "
|
device_printf(ch->dev, "is %08x cs %08x ss %08x "
|
||||||
"rs %08x tfd %02x serr %08x cmd %08x\n",
|
"rs %08x tfd %02x serr %08x cmd %08x\n",
|
||||||
ATA_INL(ch->r_mem, AHCI_P_IS),
|
ATA_INL(ch->r_mem, AHCI_P_IS),
|
||||||
ATA_INL(ch->r_mem, AHCI_P_CI),
|
ATA_INL(ch->r_mem, AHCI_P_CI),
|
||||||
@ -1588,9 +1581,8 @@ ahci_execute_transaction(struct ahci_slot *slot)
|
|||||||
|
|
||||||
/* Must be called with channel locked. */
|
/* Must be called with channel locked. */
|
||||||
static void
|
static void
|
||||||
ahci_process_timeout(device_t dev)
|
ahci_process_timeout(struct ahci_channel *ch)
|
||||||
{
|
{
|
||||||
struct ahci_channel *ch = device_get_softc(dev);
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
mtx_assert(&ch->mtx, MA_OWNED);
|
mtx_assert(&ch->mtx, MA_OWNED);
|
||||||
@ -1605,9 +1597,8 @@ ahci_process_timeout(device_t dev)
|
|||||||
|
|
||||||
/* Must be called with channel locked. */
|
/* Must be called with channel locked. */
|
||||||
static void
|
static void
|
||||||
ahci_rearm_timeout(device_t dev)
|
ahci_rearm_timeout(struct ahci_channel *ch)
|
||||||
{
|
{
|
||||||
struct ahci_channel *ch = device_get_softc(dev);
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
mtx_assert(&ch->mtx, MA_OWNED);
|
mtx_assert(&ch->mtx, MA_OWNED);
|
||||||
@ -1629,8 +1620,8 @@ ahci_rearm_timeout(device_t dev)
|
|||||||
static void
|
static void
|
||||||
ahci_timeout(struct ahci_slot *slot)
|
ahci_timeout(struct ahci_slot *slot)
|
||||||
{
|
{
|
||||||
device_t dev = slot->dev;
|
struct ahci_channel *ch = slot->ch;
|
||||||
struct ahci_channel *ch = device_get_softc(dev);
|
device_t dev = ch->dev;
|
||||||
uint32_t sstatus;
|
uint32_t sstatus;
|
||||||
int ccs;
|
int ccs;
|
||||||
int i;
|
int i;
|
||||||
@ -1697,7 +1688,7 @@ ahci_timeout(struct ahci_slot *slot)
|
|||||||
xpt_freeze_simq(ch->sim, 1);
|
xpt_freeze_simq(ch->sim, 1);
|
||||||
ch->toslots |= (1 << slot->slot);
|
ch->toslots |= (1 << slot->slot);
|
||||||
if ((ch->rslots & ~ch->toslots) == 0)
|
if ((ch->rslots & ~ch->toslots) == 0)
|
||||||
ahci_process_timeout(dev);
|
ahci_process_timeout(ch);
|
||||||
else
|
else
|
||||||
device_printf(dev, " ... waiting for slots %08x\n",
|
device_printf(dev, " ... waiting for slots %08x\n",
|
||||||
ch->rslots & ~ch->toslots);
|
ch->rslots & ~ch->toslots);
|
||||||
@ -1708,8 +1699,7 @@ ahci_timeout(struct ahci_slot *slot)
|
|||||||
static void
|
static void
|
||||||
ahci_end_transaction(struct ahci_slot *slot, enum ahci_err_type et)
|
ahci_end_transaction(struct ahci_slot *slot, enum ahci_err_type et)
|
||||||
{
|
{
|
||||||
device_t dev = slot->dev;
|
struct ahci_channel *ch = slot->ch;
|
||||||
struct ahci_channel *ch = device_get_softc(dev);
|
|
||||||
union ccb *ccb = slot->ccb;
|
union ccb *ccb = slot->ccb;
|
||||||
struct ahci_cmd_list *clp;
|
struct ahci_cmd_list *clp;
|
||||||
int lastto;
|
int lastto;
|
||||||
@ -1867,15 +1857,15 @@ ahci_end_transaction(struct ahci_slot *slot, enum ahci_err_type et)
|
|||||||
(ccb->ataio.cmd.control & ATA_A_RESET) &&
|
(ccb->ataio.cmd.control & ATA_A_RESET) &&
|
||||||
et == AHCI_ERR_NONE) {
|
et == AHCI_ERR_NONE) {
|
||||||
ccb->ataio.cmd.control &= ~ATA_A_RESET;
|
ccb->ataio.cmd.control &= ~ATA_A_RESET;
|
||||||
ahci_begin_transaction(dev, ccb);
|
ahci_begin_transaction(ch, ccb);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* If it was our READ LOG command - process it. */
|
/* If it was our READ LOG command - process it. */
|
||||||
if (ccb->ccb_h.recovery_type == RECOVERY_READ_LOG) {
|
if (ccb->ccb_h.recovery_type == RECOVERY_READ_LOG) {
|
||||||
ahci_process_read_log(dev, ccb);
|
ahci_process_read_log(ch, ccb);
|
||||||
/* If it was our REQUEST SENSE command - process it. */
|
/* If it was our REQUEST SENSE command - process it. */
|
||||||
} else if (ccb->ccb_h.recovery_type == RECOVERY_REQUEST_SENSE) {
|
} else if (ccb->ccb_h.recovery_type == RECOVERY_REQUEST_SENSE) {
|
||||||
ahci_process_request_sense(dev, ccb);
|
ahci_process_request_sense(ch, ccb);
|
||||||
/* If it was NCQ or ATAPI command error, put result on hold. */
|
/* If it was NCQ or ATAPI command error, put result on hold. */
|
||||||
} else if (et == AHCI_ERR_NCQ ||
|
} else if (et == AHCI_ERR_NCQ ||
|
||||||
((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_SCSI_STATUS_ERROR &&
|
((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_SCSI_STATUS_ERROR &&
|
||||||
@ -1888,27 +1878,27 @@ ahci_end_transaction(struct ahci_slot *slot, enum ahci_err_type et)
|
|||||||
if (ch->rslots == 0) {
|
if (ch->rslots == 0) {
|
||||||
/* if there was fatal error - reset port. */
|
/* if there was fatal error - reset port. */
|
||||||
if (ch->toslots != 0 || ch->fatalerr) {
|
if (ch->toslots != 0 || ch->fatalerr) {
|
||||||
ahci_reset(dev);
|
ahci_reset(ch);
|
||||||
} else {
|
} else {
|
||||||
/* if we have slots in error, we can reinit port. */
|
/* if we have slots in error, we can reinit port. */
|
||||||
if (ch->eslots != 0) {
|
if (ch->eslots != 0) {
|
||||||
ahci_stop(dev);
|
ahci_stop(ch);
|
||||||
ahci_clo(dev);
|
ahci_clo(ch);
|
||||||
ahci_start(dev, 1);
|
ahci_start(ch, 1);
|
||||||
}
|
}
|
||||||
/* if there commands on hold, we can do READ LOG. */
|
/* if there commands on hold, we can do READ LOG. */
|
||||||
if (!ch->recoverycmd && ch->numhslots)
|
if (!ch->recoverycmd && ch->numhslots)
|
||||||
ahci_issue_recovery(dev);
|
ahci_issue_recovery(ch);
|
||||||
}
|
}
|
||||||
/* If all the rest of commands are in timeout - give them chance. */
|
/* If all the rest of commands are in timeout - give them chance. */
|
||||||
} else if ((ch->rslots & ~ch->toslots) == 0 &&
|
} else if ((ch->rslots & ~ch->toslots) == 0 &&
|
||||||
et != AHCI_ERR_TIMEOUT)
|
et != AHCI_ERR_TIMEOUT)
|
||||||
ahci_rearm_timeout(dev);
|
ahci_rearm_timeout(ch);
|
||||||
/* Unfreeze frozen command. */
|
/* Unfreeze frozen command. */
|
||||||
if (ch->frozen && !ahci_check_collision(dev, ch->frozen)) {
|
if (ch->frozen && !ahci_check_collision(ch, ch->frozen)) {
|
||||||
union ccb *fccb = ch->frozen;
|
union ccb *fccb = ch->frozen;
|
||||||
ch->frozen = NULL;
|
ch->frozen = NULL;
|
||||||
ahci_begin_transaction(dev, fccb);
|
ahci_begin_transaction(ch, fccb);
|
||||||
xpt_release_simq(ch->sim, TRUE);
|
xpt_release_simq(ch->sim, TRUE);
|
||||||
}
|
}
|
||||||
/* Start PM timer. */
|
/* Start PM timer. */
|
||||||
@ -1920,9 +1910,8 @@ ahci_end_transaction(struct ahci_slot *slot, enum ahci_err_type et)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ahci_issue_recovery(device_t dev)
|
ahci_issue_recovery(struct ahci_channel *ch)
|
||||||
{
|
{
|
||||||
struct ahci_channel *ch = device_get_softc(dev);
|
|
||||||
union ccb *ccb;
|
union ccb *ccb;
|
||||||
struct ccb_ataio *ataio;
|
struct ccb_ataio *ataio;
|
||||||
struct ccb_scsiio *csio;
|
struct ccb_scsiio *csio;
|
||||||
@ -1935,7 +1924,7 @@ ahci_issue_recovery(device_t dev)
|
|||||||
}
|
}
|
||||||
ccb = xpt_alloc_ccb_nowait();
|
ccb = xpt_alloc_ccb_nowait();
|
||||||
if (ccb == NULL) {
|
if (ccb == NULL) {
|
||||||
device_printf(dev, "Unable to allocate recovery command\n");
|
device_printf(ch->dev, "Unable to allocate recovery command\n");
|
||||||
completeall:
|
completeall:
|
||||||
/* We can't do anything -- complete held commands. */
|
/* We can't do anything -- complete held commands. */
|
||||||
for (i = 0; i < ch->numslots; i++) {
|
for (i = 0; i < ch->numslots; i++) {
|
||||||
@ -1947,7 +1936,7 @@ ahci_issue_recovery(device_t dev)
|
|||||||
ch->hold[i] = NULL;
|
ch->hold[i] = NULL;
|
||||||
ch->numhslots--;
|
ch->numhslots--;
|
||||||
}
|
}
|
||||||
ahci_reset(dev);
|
ahci_reset(ch);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ccb->ccb_h = ch->hold[i]->ccb_h; /* Reuse old header. */
|
ccb->ccb_h = ch->hold[i]->ccb_h; /* Reuse old header. */
|
||||||
@ -1961,7 +1950,7 @@ ahci_issue_recovery(device_t dev)
|
|||||||
ataio->data_ptr = malloc(512, M_AHCI, M_NOWAIT);
|
ataio->data_ptr = malloc(512, M_AHCI, M_NOWAIT);
|
||||||
if (ataio->data_ptr == NULL) {
|
if (ataio->data_ptr == NULL) {
|
||||||
xpt_free_ccb(ccb);
|
xpt_free_ccb(ccb);
|
||||||
device_printf(dev,
|
device_printf(ch->dev,
|
||||||
"Unable to allocate memory for READ LOG command\n");
|
"Unable to allocate memory for READ LOG command\n");
|
||||||
goto completeall;
|
goto completeall;
|
||||||
}
|
}
|
||||||
@ -1993,13 +1982,12 @@ ahci_issue_recovery(device_t dev)
|
|||||||
/* Freeze SIM while doing recovery. */
|
/* Freeze SIM while doing recovery. */
|
||||||
ch->recoverycmd = 1;
|
ch->recoverycmd = 1;
|
||||||
xpt_freeze_simq(ch->sim, 1);
|
xpt_freeze_simq(ch->sim, 1);
|
||||||
ahci_begin_transaction(dev, ccb);
|
ahci_begin_transaction(ch, ccb);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ahci_process_read_log(device_t dev, union ccb *ccb)
|
ahci_process_read_log(struct ahci_channel *ch, union ccb *ccb)
|
||||||
{
|
{
|
||||||
struct ahci_channel *ch = device_get_softc(dev);
|
|
||||||
uint8_t *data;
|
uint8_t *data;
|
||||||
struct ata_res *res;
|
struct ata_res *res;
|
||||||
int i;
|
int i;
|
||||||
@ -2037,9 +2025,9 @@ ahci_process_read_log(device_t dev, union ccb *ccb)
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)
|
if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)
|
||||||
device_printf(dev, "Error while READ LOG EXT\n");
|
device_printf(ch->dev, "Error while READ LOG EXT\n");
|
||||||
else if ((data[0] & 0x80) == 0) {
|
else if ((data[0] & 0x80) == 0) {
|
||||||
device_printf(dev, "Non-queued command error in READ LOG EXT\n");
|
device_printf(ch->dev, "Non-queued command error in READ LOG EXT\n");
|
||||||
}
|
}
|
||||||
for (i = 0; i < ch->numslots; i++) {
|
for (i = 0; i < ch->numslots; i++) {
|
||||||
if (!ch->hold[i])
|
if (!ch->hold[i])
|
||||||
@ -2057,9 +2045,8 @@ ahci_process_read_log(device_t dev, union ccb *ccb)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ahci_process_request_sense(device_t dev, union ccb *ccb)
|
ahci_process_request_sense(struct ahci_channel *ch, union ccb *ccb)
|
||||||
{
|
{
|
||||||
struct ahci_channel *ch = device_get_softc(dev);
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
ch->recoverycmd = 0;
|
ch->recoverycmd = 0;
|
||||||
@ -2079,9 +2066,8 @@ ahci_process_request_sense(device_t dev, union ccb *ccb)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ahci_start(device_t dev, int fbs)
|
ahci_start(struct ahci_channel *ch, int fbs)
|
||||||
{
|
{
|
||||||
struct ahci_channel *ch = device_get_softc(dev);
|
|
||||||
u_int32_t cmd;
|
u_int32_t cmd;
|
||||||
|
|
||||||
/* Clear SATA error register */
|
/* Clear SATA error register */
|
||||||
@ -2102,9 +2088,8 @@ ahci_start(device_t dev, int fbs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ahci_stop(device_t dev)
|
ahci_stop(struct ahci_channel *ch)
|
||||||
{
|
{
|
||||||
struct ahci_channel *ch = device_get_softc(dev);
|
|
||||||
u_int32_t cmd;
|
u_int32_t cmd;
|
||||||
int timeout;
|
int timeout;
|
||||||
|
|
||||||
@ -2116,7 +2101,7 @@ ahci_stop(device_t dev)
|
|||||||
do {
|
do {
|
||||||
DELAY(10);
|
DELAY(10);
|
||||||
if (timeout++ > 50000) {
|
if (timeout++ > 50000) {
|
||||||
device_printf(dev, "stopping AHCI engine failed\n");
|
device_printf(ch->dev, "stopping AHCI engine failed\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} while (ATA_INL(ch->r_mem, AHCI_P_CMD) & AHCI_P_CMD_CR);
|
} while (ATA_INL(ch->r_mem, AHCI_P_CMD) & AHCI_P_CMD_CR);
|
||||||
@ -2124,9 +2109,8 @@ ahci_stop(device_t dev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ahci_clo(device_t dev)
|
ahci_clo(struct ahci_channel *ch)
|
||||||
{
|
{
|
||||||
struct ahci_channel *ch = device_get_softc(dev);
|
|
||||||
u_int32_t cmd;
|
u_int32_t cmd;
|
||||||
int timeout;
|
int timeout;
|
||||||
|
|
||||||
@ -2139,7 +2123,7 @@ ahci_clo(device_t dev)
|
|||||||
do {
|
do {
|
||||||
DELAY(10);
|
DELAY(10);
|
||||||
if (timeout++ > 50000) {
|
if (timeout++ > 50000) {
|
||||||
device_printf(dev, "executing CLO failed\n");
|
device_printf(ch->dev, "executing CLO failed\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} while (ATA_INL(ch->r_mem, AHCI_P_CMD) & AHCI_P_CMD_CLO);
|
} while (ATA_INL(ch->r_mem, AHCI_P_CMD) & AHCI_P_CMD_CLO);
|
||||||
@ -2147,9 +2131,8 @@ ahci_clo(device_t dev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ahci_stop_fr(device_t dev)
|
ahci_stop_fr(struct ahci_channel *ch)
|
||||||
{
|
{
|
||||||
struct ahci_channel *ch = device_get_softc(dev);
|
|
||||||
u_int32_t cmd;
|
u_int32_t cmd;
|
||||||
int timeout;
|
int timeout;
|
||||||
|
|
||||||
@ -2161,16 +2144,15 @@ ahci_stop_fr(device_t dev)
|
|||||||
do {
|
do {
|
||||||
DELAY(10);
|
DELAY(10);
|
||||||
if (timeout++ > 50000) {
|
if (timeout++ > 50000) {
|
||||||
device_printf(dev, "stopping AHCI FR engine failed\n");
|
device_printf(ch->dev, "stopping AHCI FR engine failed\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} while (ATA_INL(ch->r_mem, AHCI_P_CMD) & AHCI_P_CMD_FR);
|
} while (ATA_INL(ch->r_mem, AHCI_P_CMD) & AHCI_P_CMD_FR);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ahci_start_fr(device_t dev)
|
ahci_start_fr(struct ahci_channel *ch)
|
||||||
{
|
{
|
||||||
struct ahci_channel *ch = device_get_softc(dev);
|
|
||||||
u_int32_t cmd;
|
u_int32_t cmd;
|
||||||
|
|
||||||
/* Start FIS reception on this channel */
|
/* Start FIS reception on this channel */
|
||||||
@ -2179,9 +2161,8 @@ ahci_start_fr(device_t dev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ahci_wait_ready(device_t dev, int t, int t0)
|
ahci_wait_ready(struct ahci_channel *ch, int t, int t0)
|
||||||
{
|
{
|
||||||
struct ahci_channel *ch = device_get_softc(dev);
|
|
||||||
int timeout = 0;
|
int timeout = 0;
|
||||||
uint32_t val;
|
uint32_t val;
|
||||||
|
|
||||||
@ -2189,7 +2170,7 @@ ahci_wait_ready(device_t dev, int t, int t0)
|
|||||||
(ATA_S_BUSY | ATA_S_DRQ)) {
|
(ATA_S_BUSY | ATA_S_DRQ)) {
|
||||||
if (timeout > t) {
|
if (timeout > t) {
|
||||||
if (t != 0) {
|
if (t != 0) {
|
||||||
device_printf(dev,
|
device_printf(ch->dev,
|
||||||
"AHCI reset: device not ready after %dms "
|
"AHCI reset: device not ready after %dms "
|
||||||
"(tfd = %08x)\n",
|
"(tfd = %08x)\n",
|
||||||
MAX(t, 0) + t0, val);
|
MAX(t, 0) + t0, val);
|
||||||
@ -2200,7 +2181,7 @@ ahci_wait_ready(device_t dev, int t, int t0)
|
|||||||
timeout++;
|
timeout++;
|
||||||
}
|
}
|
||||||
if (bootverbose)
|
if (bootverbose)
|
||||||
device_printf(dev, "AHCI reset: device ready after %dms\n",
|
device_printf(ch->dev, "AHCI reset: device ready after %dms\n",
|
||||||
timeout + t0);
|
timeout + t0);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
@ -2208,22 +2189,21 @@ ahci_wait_ready(device_t dev, int t, int t0)
|
|||||||
static void
|
static void
|
||||||
ahci_reset_to(void *arg)
|
ahci_reset_to(void *arg)
|
||||||
{
|
{
|
||||||
device_t dev = arg;
|
struct ahci_channel *ch = arg;
|
||||||
struct ahci_channel *ch = device_get_softc(dev);
|
|
||||||
|
|
||||||
if (ch->resetting == 0)
|
if (ch->resetting == 0)
|
||||||
return;
|
return;
|
||||||
ch->resetting--;
|
ch->resetting--;
|
||||||
if (ahci_wait_ready(dev, ch->resetting == 0 ? -1 : 0,
|
if (ahci_wait_ready(ch, ch->resetting == 0 ? -1 : 0,
|
||||||
(310 - ch->resetting) * 100) == 0) {
|
(310 - ch->resetting) * 100) == 0) {
|
||||||
ch->resetting = 0;
|
ch->resetting = 0;
|
||||||
ahci_start(dev, 1);
|
ahci_start(ch, 1);
|
||||||
xpt_release_simq(ch->sim, TRUE);
|
xpt_release_simq(ch->sim, TRUE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (ch->resetting == 0) {
|
if (ch->resetting == 0) {
|
||||||
ahci_clo(dev);
|
ahci_clo(ch);
|
||||||
ahci_start(dev, 1);
|
ahci_start(ch, 1);
|
||||||
xpt_release_simq(ch->sim, TRUE);
|
xpt_release_simq(ch->sim, TRUE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -2231,15 +2211,14 @@ ahci_reset_to(void *arg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ahci_reset(device_t dev)
|
ahci_reset(struct ahci_channel *ch)
|
||||||
{
|
{
|
||||||
struct ahci_channel *ch = device_get_softc(dev);
|
struct ahci_controller *ctlr = device_get_softc(device_get_parent(ch->dev));
|
||||||
struct ahci_controller *ctlr = device_get_softc(device_get_parent(dev));
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
xpt_freeze_simq(ch->sim, 1);
|
xpt_freeze_simq(ch->sim, 1);
|
||||||
if (bootverbose)
|
if (bootverbose)
|
||||||
device_printf(dev, "AHCI reset...\n");
|
device_printf(ch->dev, "AHCI reset...\n");
|
||||||
/* Forget about previous reset. */
|
/* Forget about previous reset. */
|
||||||
if (ch->resetting) {
|
if (ch->resetting) {
|
||||||
ch->resetting = 0;
|
ch->resetting = 0;
|
||||||
@ -2258,7 +2237,7 @@ ahci_reset(device_t dev)
|
|||||||
ahci_done(ch, fccb);
|
ahci_done(ch, fccb);
|
||||||
}
|
}
|
||||||
/* Kill the engine and requeue all running commands. */
|
/* Kill the engine and requeue all running commands. */
|
||||||
ahci_stop(dev);
|
ahci_stop(ch);
|
||||||
for (i = 0; i < ch->numslots; i++) {
|
for (i = 0; i < ch->numslots; i++) {
|
||||||
/* Do we have a running request on slot? */
|
/* Do we have a running request on slot? */
|
||||||
if (ch->slot[i].state < AHCI_SLOT_RUNNING)
|
if (ch->slot[i].state < AHCI_SLOT_RUNNING)
|
||||||
@ -2284,9 +2263,9 @@ ahci_reset(device_t dev)
|
|||||||
/* Disable port interrupts */
|
/* Disable port interrupts */
|
||||||
ATA_OUTL(ch->r_mem, AHCI_P_IE, 0);
|
ATA_OUTL(ch->r_mem, AHCI_P_IE, 0);
|
||||||
/* Reset and reconnect PHY, */
|
/* Reset and reconnect PHY, */
|
||||||
if (!ahci_sata_phy_reset(dev)) {
|
if (!ahci_sata_phy_reset(ch)) {
|
||||||
if (bootverbose)
|
if (bootverbose)
|
||||||
device_printf(dev,
|
device_printf(ch->dev,
|
||||||
"AHCI reset: device not found\n");
|
"AHCI reset: device not found\n");
|
||||||
ch->devices = 0;
|
ch->devices = 0;
|
||||||
/* Enable wanted port interrupts */
|
/* Enable wanted port interrupts */
|
||||||
@ -2297,11 +2276,11 @@ ahci_reset(device_t dev)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (bootverbose)
|
if (bootverbose)
|
||||||
device_printf(dev, "AHCI reset: device found\n");
|
device_printf(ch->dev, "AHCI reset: device found\n");
|
||||||
/* Wait for clearing busy status. */
|
/* Wait for clearing busy status. */
|
||||||
if (ahci_wait_ready(dev, dumping ? 31000 : 0, 0)) {
|
if (ahci_wait_ready(ch, dumping ? 31000 : 0, 0)) {
|
||||||
if (dumping)
|
if (dumping)
|
||||||
ahci_clo(dev);
|
ahci_clo(ch);
|
||||||
else
|
else
|
||||||
ch->resetting = 310;
|
ch->resetting = 310;
|
||||||
}
|
}
|
||||||
@ -2315,17 +2294,16 @@ ahci_reset(device_t dev)
|
|||||||
AHCI_P_IX_DP | AHCI_P_IX_UF | (ctlr->ccc ? 0 : AHCI_P_IX_SDB) |
|
AHCI_P_IX_DP | AHCI_P_IX_UF | (ctlr->ccc ? 0 : AHCI_P_IX_SDB) |
|
||||||
AHCI_P_IX_DS | AHCI_P_IX_PS | (ctlr->ccc ? 0 : AHCI_P_IX_DHR)));
|
AHCI_P_IX_DS | AHCI_P_IX_PS | (ctlr->ccc ? 0 : AHCI_P_IX_DHR)));
|
||||||
if (ch->resetting)
|
if (ch->resetting)
|
||||||
callout_reset(&ch->reset_timer, hz / 10, ahci_reset_to, dev);
|
callout_reset(&ch->reset_timer, hz / 10, ahci_reset_to, ch);
|
||||||
else {
|
else {
|
||||||
ahci_start(dev, 1);
|
ahci_start(ch, 1);
|
||||||
xpt_release_simq(ch->sim, TRUE);
|
xpt_release_simq(ch->sim, TRUE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ahci_setup_fis(device_t dev, struct ahci_cmd_tab *ctp, union ccb *ccb, int tag)
|
ahci_setup_fis(struct ahci_channel *ch, 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];
|
u_int8_t *fis = &ctp->cfis[0];
|
||||||
|
|
||||||
bzero(fis, 20);
|
bzero(fis, 20);
|
||||||
@ -2417,9 +2395,8 @@ ahci_sata_connect(struct ahci_channel *ch)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ahci_sata_phy_reset(device_t dev)
|
ahci_sata_phy_reset(struct ahci_channel *ch)
|
||||||
{
|
{
|
||||||
struct ahci_channel *ch = device_get_softc(dev);
|
|
||||||
int sata_rev;
|
int sata_rev;
|
||||||
uint32_t val;
|
uint32_t val;
|
||||||
|
|
||||||
@ -2459,9 +2436,8 @@ ahci_sata_phy_reset(device_t dev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ahci_check_ids(device_t dev, union ccb *ccb)
|
ahci_check_ids(struct ahci_channel *ch, union ccb *ccb)
|
||||||
{
|
{
|
||||||
struct ahci_channel *ch = device_get_softc(dev);
|
|
||||||
|
|
||||||
if (ccb->ccb_h.target_id > ((ch->caps & AHCI_CAP_SPM) ? 15 : 0)) {
|
if (ccb->ccb_h.target_id > ((ch->caps & AHCI_CAP_SPM) ? 15 : 0)) {
|
||||||
ccb->ccb_h.status = CAM_TID_INVALID;
|
ccb->ccb_h.status = CAM_TID_INVALID;
|
||||||
@ -2479,19 +2455,17 @@ ahci_check_ids(device_t dev, union ccb *ccb)
|
|||||||
static void
|
static void
|
||||||
ahciaction(struct cam_sim *sim, union ccb *ccb)
|
ahciaction(struct cam_sim *sim, union ccb *ccb)
|
||||||
{
|
{
|
||||||
device_t dev, parent;
|
|
||||||
struct ahci_channel *ch;
|
struct ahci_channel *ch;
|
||||||
|
|
||||||
CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("ahciaction func_code=%x\n",
|
CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("ahciaction func_code=%x\n",
|
||||||
ccb->ccb_h.func_code));
|
ccb->ccb_h.func_code));
|
||||||
|
|
||||||
ch = (struct ahci_channel *)cam_sim_softc(sim);
|
ch = (struct ahci_channel *)cam_sim_softc(sim);
|
||||||
dev = ch->dev;
|
|
||||||
switch (ccb->ccb_h.func_code) {
|
switch (ccb->ccb_h.func_code) {
|
||||||
/* Common cases first */
|
/* Common cases first */
|
||||||
case XPT_ATA_IO: /* Execute the requested I/O operation */
|
case XPT_ATA_IO: /* Execute the requested I/O operation */
|
||||||
case XPT_SCSI_IO:
|
case XPT_SCSI_IO:
|
||||||
if (ahci_check_ids(dev, ccb))
|
if (ahci_check_ids(ch, ccb))
|
||||||
return;
|
return;
|
||||||
if (ch->devices == 0 ||
|
if (ch->devices == 0 ||
|
||||||
(ch->pm_present == 0 &&
|
(ch->pm_present == 0 &&
|
||||||
@ -2501,14 +2475,14 @@ ahciaction(struct cam_sim *sim, union ccb *ccb)
|
|||||||
}
|
}
|
||||||
ccb->ccb_h.recovery_type = RECOVERY_NONE;
|
ccb->ccb_h.recovery_type = RECOVERY_NONE;
|
||||||
/* Check for command collision. */
|
/* Check for command collision. */
|
||||||
if (ahci_check_collision(dev, ccb)) {
|
if (ahci_check_collision(ch, ccb)) {
|
||||||
/* Freeze command. */
|
/* Freeze command. */
|
||||||
ch->frozen = ccb;
|
ch->frozen = ccb;
|
||||||
/* We have only one frozen slot, so freeze simq also. */
|
/* We have only one frozen slot, so freeze simq also. */
|
||||||
xpt_freeze_simq(ch->sim, 1);
|
xpt_freeze_simq(ch->sim, 1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ahci_begin_transaction(dev, ccb);
|
ahci_begin_transaction(ch, ccb);
|
||||||
return;
|
return;
|
||||||
case XPT_EN_LUN: /* Enable LUN as a target */
|
case XPT_EN_LUN: /* Enable LUN as a target */
|
||||||
case XPT_TARGET_IO: /* Execute target I/O request */
|
case XPT_TARGET_IO: /* Execute target I/O request */
|
||||||
@ -2523,7 +2497,7 @@ ahciaction(struct cam_sim *sim, union ccb *ccb)
|
|||||||
struct ccb_trans_settings *cts = &ccb->cts;
|
struct ccb_trans_settings *cts = &ccb->cts;
|
||||||
struct ahci_device *d;
|
struct ahci_device *d;
|
||||||
|
|
||||||
if (ahci_check_ids(dev, ccb))
|
if (ahci_check_ids(ch, ccb))
|
||||||
return;
|
return;
|
||||||
if (cts->type == CTS_TYPE_CURRENT_SETTINGS)
|
if (cts->type == CTS_TYPE_CURRENT_SETTINGS)
|
||||||
d = &ch->curr[ccb->ccb_h.target_id];
|
d = &ch->curr[ccb->ccb_h.target_id];
|
||||||
@ -2553,7 +2527,7 @@ ahciaction(struct cam_sim *sim, union ccb *ccb)
|
|||||||
struct ahci_device *d;
|
struct ahci_device *d;
|
||||||
uint32_t status;
|
uint32_t status;
|
||||||
|
|
||||||
if (ahci_check_ids(dev, ccb))
|
if (ahci_check_ids(ch, ccb))
|
||||||
return;
|
return;
|
||||||
if (cts->type == CTS_TYPE_CURRENT_SETTINGS)
|
if (cts->type == CTS_TYPE_CURRENT_SETTINGS)
|
||||||
d = &ch->curr[ccb->ccb_h.target_id];
|
d = &ch->curr[ccb->ccb_h.target_id];
|
||||||
@ -2610,7 +2584,7 @@ ahciaction(struct cam_sim *sim, union ccb *ccb)
|
|||||||
}
|
}
|
||||||
case XPT_RESET_BUS: /* Reset the specified SCSI bus */
|
case XPT_RESET_BUS: /* Reset the specified SCSI bus */
|
||||||
case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */
|
case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */
|
||||||
ahci_reset(dev);
|
ahci_reset(ch);
|
||||||
ccb->ccb_h.status = CAM_REQ_CMP;
|
ccb->ccb_h.status = CAM_REQ_CMP;
|
||||||
break;
|
break;
|
||||||
case XPT_TERM_IO: /* Terminate the I/O process */
|
case XPT_TERM_IO: /* Terminate the I/O process */
|
||||||
@ -2621,7 +2595,6 @@ ahciaction(struct cam_sim *sim, union ccb *ccb)
|
|||||||
{
|
{
|
||||||
struct ccb_pathinq *cpi = &ccb->cpi;
|
struct ccb_pathinq *cpi = &ccb->cpi;
|
||||||
|
|
||||||
parent = device_get_parent(dev);
|
|
||||||
cpi->version_num = 1; /* XXX??? */
|
cpi->version_num = 1; /* XXX??? */
|
||||||
cpi->hba_inquiry = PI_SDTR_ABLE;
|
cpi->hba_inquiry = PI_SDTR_ABLE;
|
||||||
if (ch->caps & AHCI_CAP_SNCQ)
|
if (ch->caps & AHCI_CAP_SNCQ)
|
||||||
@ -2678,7 +2651,7 @@ ahcipoll(struct cam_sim *sim)
|
|||||||
if (ch->resetting != 0 &&
|
if (ch->resetting != 0 &&
|
||||||
(--ch->resetpolldiv <= 0 || !callout_pending(&ch->reset_timer))) {
|
(--ch->resetpolldiv <= 0 || !callout_pending(&ch->reset_timer))) {
|
||||||
ch->resetpolldiv = 1000;
|
ch->resetpolldiv = 1000;
|
||||||
ahci_reset_to(ch->dev);
|
ahci_reset_to(ch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MODULE_VERSION(ahci, 1);
|
MODULE_VERSION(ahci, 1);
|
||||||
|
@ -375,7 +375,7 @@ enum ahci_slot_states {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct ahci_slot {
|
struct ahci_slot {
|
||||||
device_t dev; /* Device handle */
|
struct ahci_channel *ch; /* Channel */
|
||||||
u_int8_t slot; /* Number of this slot */
|
u_int8_t slot; /* Number of this slot */
|
||||||
enum ahci_slot_states state; /* Slot state */
|
enum ahci_slot_states state; /* Slot state */
|
||||||
union ccb *ccb; /* CCB occupying slot */
|
union ccb *ccb; /* CCB occupying slot */
|
||||||
@ -422,20 +422,19 @@ struct ahci_channel {
|
|||||||
int quirks;
|
int quirks;
|
||||||
int numslots; /* Number of present slots */
|
int numslots; /* Number of present slots */
|
||||||
int pm_level; /* power management level */
|
int pm_level; /* power management level */
|
||||||
|
|
||||||
struct ahci_slot slot[AHCI_MAX_SLOTS];
|
|
||||||
union ccb *hold[AHCI_MAX_SLOTS];
|
|
||||||
struct mtx mtx; /* state lock */
|
|
||||||
STAILQ_HEAD(, ccb_hdr) doneq; /* queue of completed CCBs */
|
|
||||||
int batch; /* doneq is in use */
|
|
||||||
int devices; /* What is present */
|
int devices; /* What is present */
|
||||||
int pm_present; /* PM presence reported */
|
int pm_present; /* PM presence reported */
|
||||||
int fbs_enabled; /* FIS-based switching enabled */
|
int fbs_enabled; /* FIS-based switching enabled */
|
||||||
|
|
||||||
|
union ccb *hold[AHCI_MAX_SLOTS];
|
||||||
|
struct ahci_slot slot[AHCI_MAX_SLOTS];
|
||||||
uint32_t oslots; /* Occupied slots */
|
uint32_t oslots; /* Occupied slots */
|
||||||
uint32_t rslots; /* Running slots */
|
uint32_t rslots; /* Running slots */
|
||||||
uint32_t aslots; /* Slots with atomic commands */
|
uint32_t aslots; /* Slots with atomic commands */
|
||||||
uint32_t eslots; /* Slots in error */
|
uint32_t eslots; /* Slots in error */
|
||||||
uint32_t toslots; /* Slots in timeout */
|
uint32_t toslots; /* Slots in timeout */
|
||||||
|
int lastslot; /* Last used slot */
|
||||||
|
int taggedtarget; /* Last tagged target */
|
||||||
int numrslots; /* Number of running slots */
|
int numrslots; /* Number of running slots */
|
||||||
int numrslotspd[16];/* Number of running slots per dev */
|
int numrslotspd[16];/* Number of running slots per dev */
|
||||||
int numtslots; /* Number of tagged slots */
|
int numtslots; /* Number of tagged slots */
|
||||||
@ -443,8 +442,6 @@ struct ahci_channel {
|
|||||||
int numhslots; /* Number of held slots */
|
int numhslots; /* Number of held slots */
|
||||||
int recoverycmd; /* Our READ LOG active */
|
int recoverycmd; /* Our READ LOG active */
|
||||||
int fatalerr; /* Fatal error happend */
|
int fatalerr; /* Fatal error happend */
|
||||||
int lastslot; /* Last used slot */
|
|
||||||
int taggedtarget; /* Last tagged target */
|
|
||||||
int resetting; /* Hard-reset in progress. */
|
int resetting; /* Hard-reset in progress. */
|
||||||
int resetpolldiv; /* Hard-reset poll divider. */
|
int resetpolldiv; /* Hard-reset poll divider. */
|
||||||
int listening; /* SUD bit is cleared. */
|
int listening; /* SUD bit is cleared. */
|
||||||
@ -455,6 +452,10 @@ struct ahci_channel {
|
|||||||
|
|
||||||
struct ahci_device user[16]; /* User-specified settings */
|
struct ahci_device user[16]; /* User-specified settings */
|
||||||
struct ahci_device curr[16]; /* Current settings */
|
struct ahci_device curr[16]; /* Current settings */
|
||||||
|
|
||||||
|
struct mtx_padalign mtx; /* state lock */
|
||||||
|
STAILQ_HEAD(, ccb_hdr) doneq; /* queue of completed CCBs */
|
||||||
|
int batch; /* doneq is in use */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ahci_enclosure {
|
struct ahci_enclosure {
|
||||||
|
@ -344,7 +344,7 @@ ahci_em_led(void *priv, int onoff)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ahci_check_ids(device_t dev, union ccb *ccb)
|
ahci_check_ids(union ccb *ccb)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (ccb->ccb_h.target_id != 0) {
|
if (ccb->ccb_h.target_id != 0) {
|
||||||
@ -554,7 +554,7 @@ ahciemaction(struct cam_sim *sim, union ccb *ccb)
|
|||||||
dev = enc->dev;
|
dev = enc->dev;
|
||||||
switch (ccb->ccb_h.func_code) {
|
switch (ccb->ccb_h.func_code) {
|
||||||
case XPT_ATA_IO: /* Execute the requested I/O operation */
|
case XPT_ATA_IO: /* Execute the requested I/O operation */
|
||||||
if (ahci_check_ids(dev, ccb))
|
if (ahci_check_ids(ccb))
|
||||||
return;
|
return;
|
||||||
ahci_em_begin_transaction(dev, ccb);
|
ahci_em_begin_transaction(dev, ccb);
|
||||||
return;
|
return;
|
||||||
|
Loading…
Reference in New Issue
Block a user