Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 88057
b: refs/heads/master
c: 1fce5e5
h: refs/heads/master
i:
  88055: 0f70c85
v: v3
  • Loading branch information
Ke Wei authored and James Bottomley committed Mar 28, 2008
1 parent 9a2c5c4 commit 0ca3884
Show file tree
Hide file tree
Showing 2 changed files with 171 additions and 58 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6ed
refs/heads/master: 1fce5e5da03b18505179882be27cc697f24d6b58
227 changes: 170 additions & 57 deletions trunk/drivers/scsi/mvsas.c
Original file line number Diff line number Diff line change
Expand Up @@ -1218,10 +1218,63 @@ static void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events)

static void mvs_int_sata(struct mvs_info *mvi)
{
/* FIXME */
u32 tmp;
void __iomem *regs = mvi->regs;
tmp = mr32(INT_STAT_SRS);
mw32(INT_STAT_SRS, tmp & 0xFFFF);
}

static void mvs_slot_reset(struct mvs_info *mvi, struct sas_task *task,
u32 slot_idx)
{
void __iomem *regs = mvi->regs;
struct domain_device *dev = task->dev;
struct asd_sas_port *sas_port = dev->port;
struct mvs_port *port = mvi->slot_info[slot_idx].port;
u32 reg_set, phy_mask;

if (!sas_protocol_ata(task->task_proto)) {
reg_set = 0;
phy_mask = (port->wide_port_phymap) ? port->wide_port_phymap :
sas_port->phy_mask;
} else {
reg_set = port->taskfileset;
phy_mask = sas_port->phy_mask;
}
mvi->tx[mvi->tx_prod] = cpu_to_le32(TXQ_MODE_I | slot_idx |
(TXQ_CMD_SLOT_RESET << TXQ_CMD_SHIFT) |
(phy_mask << TXQ_PHY_SHIFT) |
(reg_set << TXQ_SRS_SHIFT));

mw32(TX_PROD_IDX, mvi->tx_prod);
mvi->tx_prod = (mvi->tx_prod + 1) & (MVS_CHIP_SLOT_SZ - 1);
}

static void mvs_slot_free(struct mvs_info *mvi, struct sas_task *task,
static int mvs_sata_done(struct mvs_info *mvi, struct sas_task *task,
u32 slot_idx, int err)
{
struct mvs_port *port = mvi->slot_info[slot_idx].port;
struct task_status_struct *tstat = &task->task_status;
struct ata_task_resp *resp = (struct ata_task_resp *)tstat->buf;
int stat = SAM_GOOD;

resp->frame_len = sizeof(struct dev_to_host_fis);
memcpy(&resp->ending_fis[0],
SATA_RECEIVED_D2H_FIS(port->taskfileset),
sizeof(struct dev_to_host_fis));
tstat->buf_valid_size = sizeof(*resp);
if (unlikely(err))
stat = SAS_PROTO_RESPONSE;
return stat;
}

static void mvs_slot_free(struct mvs_info *mvi, u32 rx_desc)
{
u32 slot_idx = rx_desc & RXQ_SLOT_MASK;
mvs_tag_clear(mvi, slot_idx);
}

static void mvs_slot_task_free(struct mvs_info *mvi, struct sas_task *task,
struct mvs_slot_info *slot, u32 slot_idx)
{
if (!sas_protocol_ata(task->task_proto))
Expand All @@ -1244,38 +1297,58 @@ static void mvs_slot_free(struct mvs_info *mvi, struct sas_task *task,
/* do nothing */
break;
}

list_del(&slot->list);
task->lldd_task = NULL;
slot->task = NULL;
mvs_tag_clear(mvi, slot_idx);
slot->port = NULL;
}

static void mvs_slot_err(struct mvs_info *mvi, struct sas_task *task,
static int mvs_slot_err(struct mvs_info *mvi, struct sas_task *task,
u32 slot_idx)
{
struct mvs_slot_info *slot = &mvi->slot_info[slot_idx];
u64 err_dw0 = *(u32 *) slot->response;
void __iomem *regs = mvi->regs;
u32 tmp;
u32 err_dw0 = le32_to_cpu(*(u32 *) (slot->response));
u32 err_dw1 = le32_to_cpu(*(u32 *) (slot->response + 4));
int stat = SAM_CHECK_COND;

if (err_dw0 & CMD_ISS_STPD)
if (sas_protocol_ata(task->task_proto)) {
tmp = mr32(INT_STAT_SRS);
mw32(INT_STAT_SRS, tmp & 0xFFFF);
}
if (err_dw1 & SLOT_BSY_ERR) {
stat = SAS_QUEUE_FULL;
mvs_slot_reset(mvi, task, slot_idx);
}
switch (task->task_proto) {
case SAS_PROTOCOL_SSP:
break;
case SAS_PROTOCOL_SMP:
break;
case SAS_PROTOCOL_SATA:
case SAS_PROTOCOL_STP:
case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
if (err_dw0 & TFILE_ERR)
stat = mvs_sata_done(mvi, task, slot_idx, 1);
break;
default:
break;
}

mvs_hba_sb_dump(mvi, slot_idx, task->task_proto);
mvs_hexdump(16, (u8 *) slot->response, 0);
return stat;
}

static int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc)
static int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags)
{
u32 slot_idx = rx_desc & RXQ_SLOT_MASK;
struct mvs_slot_info *slot = &mvi->slot_info[slot_idx];
struct sas_task *task = slot->task;
struct task_status_struct *tstat = &task->task_status;
struct mvs_port *port = &mvi->port[task->dev->port->id];
struct task_status_struct *tstat;
struct mvs_port *port;
bool aborted;
void *to;

if (unlikely(!task || !task->lldd_task))
return -1;

mvs_hba_cq_dump(mvi);

spin_lock(&task->task_state_lock);
aborted = task->task_state_flags & SAS_TASK_STATE_ABORTED;
if (!aborted) {
Expand All @@ -1285,22 +1358,27 @@ static int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc)
}
spin_unlock(&task->task_state_lock);

if (aborted)
if (aborted) {
mvs_slot_task_free(mvi, task, slot, slot_idx);
mvs_slot_free(mvi, rx_desc);
return -1;
}

port = slot->port;
tstat = &task->task_status;
memset(tstat, 0, sizeof(*tstat));
tstat->resp = SAS_TASK_COMPLETE;


if (unlikely(!port->port_attached)) {
tstat->stat = SAS_PHY_DOWN;
if (unlikely(!port->port_attached || flags)) {
mvs_slot_err(mvi, task, slot_idx);
if (!sas_protocol_ata(task->task_proto))
tstat->stat = SAS_PHY_DOWN;
goto out;
}

/* error info record present */
if ((rx_desc & RXQ_ERR) && (*(u64 *) slot->response)) {
tstat->stat = SAM_CHECK_COND;
mvs_slot_err(mvi, task, slot_idx);
if (unlikely((rx_desc & RXQ_ERR) && (*(u64 *) slot->response))) {
tstat->stat = mvs_slot_err(mvi, task, slot_idx);
goto out;
}

Expand Down Expand Up @@ -1337,21 +1415,7 @@ static int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc)
case SAS_PROTOCOL_SATA:
case SAS_PROTOCOL_STP:
case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: {
struct ata_task_resp *resp =
(struct ata_task_resp *)tstat->buf;

if ((rx_desc & (RXQ_DONE | RXQ_ERR | RXQ_ATTN)) ==
RXQ_DONE)
tstat->stat = SAM_GOOD;
else
tstat->stat = SAM_CHECK_COND;

resp->frame_len = sizeof(struct dev_to_host_fis);
memcpy(&resp->ending_fis[0],
SATA_RECEIVED_D2H_FIS(port->taskfileset),
sizeof(struct dev_to_host_fis));
if (resp->ending_fis[2] & ATA_ERR)
mvs_hexdump(16, resp->ending_fis, 0);
tstat->stat = mvs_sata_done(mvi, task, slot_idx, 0);
break;
}

Expand All @@ -1361,11 +1425,34 @@ static int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc)
}

out:
mvs_slot_free(mvi, task, slot, slot_idx);
mvs_slot_task_free(mvi, task, slot, slot_idx);
if (unlikely(tstat->stat != SAS_QUEUE_FULL))
mvs_slot_free(mvi, rx_desc);

spin_unlock(&mvi->lock);
task->task_done(task);
spin_lock(&mvi->lock);
return tstat->stat;
}

static void mvs_release_task(struct mvs_info *mvi, int phy_no)
{
struct list_head *pos, *n;
struct mvs_slot_info *slot;
struct mvs_phy *phy = &mvi->phy[phy_no];
struct mvs_port *port = phy->port;
u32 rx_desc;

if (!port)
return;

list_for_each_safe(pos, n, &port->list) {
slot = container_of(pos, struct mvs_slot_info, list);
rx_desc = (u32) (slot - mvi->slot_info);
mvs_slot_complete(mvi, rx_desc, 1);
}
}

static void mvs_int_full(struct mvs_info *mvi)
{
void __iomem *regs = mvi->regs;
Expand Down Expand Up @@ -1400,40 +1487,43 @@ static int mvs_int_rx(struct mvs_info *mvi, bool self_clear)
* we don't have to stall the CPU reading that register.
* The actual RX ring is offset by one dword, due to this.
*/
rx_prod_idx = mr32(RX_CONS_IDX) & RX_RING_SZ_MASK;
if (rx_prod_idx == 0xfff) { /* h/w hasn't touched RX ring yet */
mvi->rx_cons = 0xfff;
rx_prod_idx = mvi->rx_cons;
mvi->rx_cons = le32_to_cpu(mvi->rx[0]);
if (mvi->rx_cons == 0xfff) /* h/w hasn't touched RX ring yet */
return 0;
}

/* The CMPL_Q may come late, read from register and try again
* note: if coalescing is enabled,
* it will need to read from register every time for sure
*/
if (mvi->rx_cons == rx_prod_idx)
return 0;
mvi->rx_cons = mr32(RX_CONS_IDX) & RX_RING_SZ_MASK;

if (mvi->rx_cons == 0xfff)
mvi->rx_cons = MVS_RX_RING_SZ - 1;
if (mvi->rx_cons == rx_prod_idx)
return 0;

while (mvi->rx_cons != rx_prod_idx) {

/* increment our internal RX consumer pointer */
mvi->rx_cons = (mvi->rx_cons + 1) & (MVS_RX_RING_SZ - 1);

rx_desc = le32_to_cpu(mvi->rx[mvi->rx_cons + 1]);
rx_prod_idx = (rx_prod_idx + 1) & (MVS_RX_RING_SZ - 1);

mvs_hba_cq_dump(mvi);
rx_desc = le32_to_cpu(mvi->rx[rx_prod_idx + 1]);

if (likely(rx_desc & RXQ_DONE))
mvs_slot_complete(mvi, rx_desc);
mvs_slot_complete(mvi, rx_desc, 0);
if (rx_desc & RXQ_ATTN) {
attn = true;
dev_printk(KERN_DEBUG, &pdev->dev, "ATTN %X\n",
rx_desc);
} else if (rx_desc & RXQ_ERR) {
if (!(rx_desc & RXQ_DONE))
mvs_slot_complete(mvi, rx_desc, 0);
dev_printk(KERN_DEBUG, &pdev->dev, "RXQ_ERR %X\n",
rx_desc);
} else if (rx_desc & RXQ_SLOT_RESET) {
dev_printk(KERN_DEBUG, &pdev->dev, "Slot reset[%X]\n",
rx_desc);
mvs_slot_free(mvi, rx_desc);
}
}

Expand All @@ -1443,6 +1533,23 @@ static int mvs_int_rx(struct mvs_info *mvi, bool self_clear)
return 0;
}

#ifdef MVS_USE_TASKLET
static void mvs_tasklet(unsigned long data)
{
struct mvs_info *mvi = (struct mvs_info *) data;
unsigned long flags;

spin_lock_irqsave(&mvi->lock, flags);

#ifdef MVS_DISABLE_MSI
mvs_int_full(mvi);
#else
mvs_int_rx(mvi, true);
#endif
spin_unlock_irqrestore(&mvi->lock, flags);
}
#endif

static irqreturn_t mvs_interrupt(int irq, void *opaque)
{
struct mvs_info *mvi = opaque;
Expand All @@ -1451,18 +1558,21 @@ static irqreturn_t mvs_interrupt(int irq, void *opaque)

stat = mr32(GBL_INT_STAT);

/* clear CMD_CMPLT ASAP */
mw32_f(INT_STAT, CINT_DONE);

if (stat == 0 || stat == 0xffffffff)
return IRQ_NONE;

/* clear CMD_CMPLT ASAP */
mw32_f(INT_STAT, CINT_DONE);

#ifndef MVS_USE_TASKLET
spin_lock(&mvi->lock);

mvs_int_full(mvi);

spin_unlock(&mvi->lock);

#else
tasklet_schedule(&mvi->tasklet);
#endif
return IRQ_HANDLED;
}

Expand All @@ -1471,12 +1581,15 @@ static irqreturn_t mvs_msi_interrupt(int irq, void *opaque)
{
struct mvs_info *mvi = opaque;

#ifndef MVS_USE_TASKLET
spin_lock(&mvi->lock);

mvs_int_rx(mvi, true);

spin_unlock(&mvi->lock);

#else
tasklet_schedule(&mvi->tasklet);
#endif
return IRQ_HANDLED;
}
#endif
Expand Down

0 comments on commit 0ca3884

Please sign in to comment.