return MVS_ID_NOT_MAPPED;
}
-static u32 mvs_get_ncq_tag(struct sas_task *task)
+static u32 mvs_get_ncq_tag(struct sas_task *task, u32 *tag)
{
- u32 tag = 0;
struct ata_queued_cmd *qc = task->uldd_task;
- if (qc)
- tag = qc->tag;
+ if (qc) {
+ if (qc->tf.command == ATA_CMD_FPDMA_WRITE ||
+ qc->tf.command == ATA_CMD_FPDMA_READ) {
+ *tag = qc->tag;
+ return 1;
+ }
+ }
- return tag;
+ return 0;
}
static int mvs_task_prep_ata(struct mvs_info *mvi,
hdr->flags = cpu_to_le32(flags);
/* FIXME: the low order order 5 bits for the TAG if enable NCQ */
- if (task->ata_task.use_ncq) {
- hdr->tags = cpu_to_le32(mvs_get_ncq_tag(task));
- /*Fill in task file */
- task->ata_task.fis.sector_count = hdr->tags << 3;
- } else
+ if (task->ata_task.use_ncq && mvs_get_ncq_tag(task, &hdr->tags))
+ task->ata_task.fis.sector_count |= hdr->tags << 3;
+ else
hdr->tags = cpu_to_le32(tag);
hdr->data_len = cpu_to_le32(task->total_xfer_len);
u32 flags;
u32 resp_len, req_len, i, tag = tei->tag;
const u32 max_resp_len = SB_RFB_MAX;
+ u8 phy_mask;
slot = &mvi->slot_info[tag];
+ phy_mask = (port->wide_port_phymap) ? port->wide_port_phymap :
+ task->dev->port->phy_mask;
slot->tx = mvi->tx_prod;
mvi->tx[mvi->tx_prod] = cpu_to_le32(TXQ_MODE_I | tag |
(TXQ_CMD_SSP << TXQ_CMD_SHIFT) |
- (port->wide_port_phymap << TXQ_PHY_SHIFT));
+ (phy_mask << TXQ_PHY_SHIFT));
flags = MCH_RETRY;
if (task->ssp_task.enable_first_burst) {
void __iomem *regs = mvi->regs;
struct mvs_task_exec_info tei;
struct sas_task *t = task;
+ struct mvs_slot_info *slot;
u32 tag = 0xdeadbeef, rc, n_elem = 0;
unsigned long flags;
u32 n = num, pass = 0;
spin_lock_irqsave(&mvi->lock, flags);
-
do {
+ dev = t->dev;
tei.port = &mvi->port[dev->port->id];
if (!tei.port->port_attached) {
- struct task_status_struct *ts = &t->task_status;
- ts->stat = SAS_PHY_DOWN;
- t->task_done(t);
- rc = 0;
- goto exec_exit;
+ if (sas_protocol_ata(t->task_proto)) {
+ rc = SAS_PHY_DOWN;
+ goto out_done;
+ } else {
+ struct task_status_struct *ts = &t->task_status;
+ ts->resp = SAS_TASK_UNDELIVERED;
+ ts->stat = SAS_PHY_DOWN;
+ t->task_done(t);
+ if (n > 1)
+ t = list_entry(t->list.next,
+ struct sas_task, list);
+ continue;
+ }
}
+
if (!sas_protocol_ata(t->task_proto)) {
if (t->num_scatter) {
n_elem = pci_map_sg(mvi->pdev, t->scatter,
if (rc)
goto err_out;
- mvi->slot_info[tag].task = t;
- mvi->slot_info[tag].n_elem = n_elem;
- memset(mvi->slot_info[tag].buf, 0, MVS_SLOT_BUF_SZ);
+ slot = &mvi->slot_info[tag];
+ t->lldd_task = NULL;
+ slot->n_elem = n_elem;
+ memset(slot->buf, 0, MVS_SLOT_BUF_SZ);
tei.task = t;
tei.hdr = &mvi->slot[tag];
tei.tag = tag;
if (rc)
goto err_out_tag;
+ slot->task = t;
+ slot->port = tei.port;
+ t->lldd_task = (void *) slot;
+ list_add_tail(&slot->list, &slot->port->list);
/* TODO: select normal or high priority */
spin_lock(&t->task_state_lock);
t->task_state_flags |= SAS_TASK_AT_INITIATOR;
spin_unlock(&t->task_state_lock);
- if (n == 1) {
- spin_unlock_irqrestore(&mvi->lock, flags);
- mw32(TX_PROD_IDX, mvi->tx_prod);
- }
mvs_hba_memory_dump(mvi, tag, t->task_proto);
++pass;
mvi->tx_prod = (mvi->tx_prod + 1) & (MVS_CHIP_SLOT_SZ - 1);
-
- if (n == 1)
- break;
-
- t = list_entry(t->list.next, struct sas_task, list);
+ if (n > 1)
+ t = list_entry(t->list.next, struct sas_task, list);
} while (--n);
- return 0;
+ rc = 0;
+ goto out_done;
err_out_tag:
mvs_tag_free(mvi, tag);
if (n_elem)
pci_unmap_sg(mvi->pdev, t->scatter, n_elem,
t->data_dir);
-exec_exit:
+out_done:
if (pass)
mw32(TX_PROD_IDX, (mvi->tx_prod - 1) & (MVS_CHIP_SLOT_SZ - 1));
spin_unlock_irqrestore(&mvi->lock, flags);
static int mvs_task_abort(struct sas_task *task)
{
- int rc = 1;
+ int rc;
unsigned long flags;
struct mvs_info *mvi = task->dev->port->ha->lldd_ha;
struct pci_dev *pdev = mvi->pdev;
+ int tag;
spin_lock_irqsave(&task->task_state_lock, flags);
if (task->task_state_flags & SAS_TASK_STATE_DONE) {
rc = TMF_RESP_FUNC_COMPLETE;
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
goto out_done;
}
spin_unlock_irqrestore(&task->task_state_lock, flags);
- /*FIXME*/
- rc = TMF_RESP_FUNC_COMPLETE;
-
switch (task->task_proto) {
case SAS_PROTOCOL_SMP:
- dev_printk(KERN_DEBUG, &pdev->dev, "SMP Abort! ");
+ dev_printk(KERN_DEBUG, &pdev->dev, "SMP Abort! \n");
break;
case SAS_PROTOCOL_SSP:
- dev_printk(KERN_DEBUG, &pdev->dev, "SSP Abort! ");
+ dev_printk(KERN_DEBUG, &pdev->dev, "SSP Abort! \n");
break;
case SAS_PROTOCOL_SATA:
case SAS_PROTOCOL_STP:
case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:{
- dev_printk(KERN_DEBUG, &pdev->dev, "STP Abort! "
- "Dump D2H FIS: \n");
+ dev_printk(KERN_DEBUG, &pdev->dev, "STP Abort! \n");
+#if _MV_DUMP
+ dev_printk(KERN_DEBUG, &pdev->dev, "Dump D2H FIS: \n");
mvs_hexdump(sizeof(struct host_to_dev_fis),
(void *)&task->ata_task.fis, 0);
dev_printk(KERN_DEBUG, &pdev->dev, "Dump ATAPI Cmd : \n");
mvs_hexdump(16, task->ata_task.atapi_packet, 0);
+#endif
+ spin_lock_irqsave(&task->task_state_lock, flags);
+ if (task->task_state_flags & SAS_TASK_NEED_DEV_RESET) {
+ /* TODO */
+ ;
+ }
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
break;
}
default:
break;
}
+
+ if (mvs_find_tag(mvi, task, &tag)) {
+ spin_lock_irqsave(&mvi->lock, flags);
+ mvs_slot_task_free(mvi, task, &mvi->slot_info[tag], tag);
+ spin_unlock_irqrestore(&mvi->lock, flags);
+ }
+ if (!mvs_task_exec(task, 1, GFP_ATOMIC))
+ rc = TMF_RESP_FUNC_COMPLETE;
+ else
+ rc = TMF_RESP_FUNC_FAILED;
out_done:
return rc;
}
mvi->rx_fis, mvi->rx_fis_dma);
if (mvi->rx)
dma_free_coherent(&mvi->pdev->dev,
- sizeof(*mvi->rx) * MVS_RX_RING_SZ,
+ sizeof(*mvi->rx) * (MVS_RX_RING_SZ + 1),
mvi->rx, mvi->rx_dma);
if (mvi->slot)
dma_free_coherent(&mvi->pdev->dev,
return NULL;
spin_lock_init(&mvi->lock);
+#ifdef MVS_USE_TASKLET
+ tasklet_init(&mvi->tasklet, mvs_tasklet, (unsigned long)mvi);
+#endif
mvi->pdev = pdev;
mvi->chip = chip;
mvs_phy_init(mvi, i);
arr_phy[i] = &mvi->phy[i].sas_phy;
arr_port[i] = &mvi->port[i].sas_port;
+ mvi->port[i].taskfileset = MVS_ID_NOT_MAPPED;
+ mvi->port[i].wide_port_phymap = 0;
+ mvi->port[i].port_attached = 0;
+ INIT_LIST_HEAD(&mvi->port[i].list);
}
SHOST_TO_SAS_HA(mvi->shost) = &mvi->sas;
mvi->sas.sas_phy = arr_phy;
mvi->sas.sas_port = arr_port;
mvi->sas.num_phys = chip->n_phy;
- mvi->sas.lldd_max_execute_num = MVS_CHIP_SLOT_SZ - 1;
+ mvi->sas.lldd_max_execute_num = 1;
mvi->sas.lldd_queue_size = MVS_QUEUE_SIZE;
- mvi->can_queue = (MVS_CHIP_SLOT_SZ >> 1) - 1;
+ mvi->shost->can_queue = MVS_CAN_QUEUE;
+ mvi->shost->cmd_per_lun = MVS_SLOTS / mvi->sas.num_phys;
mvi->sas.lldd_ha = mvi;
mvi->sas.core.shost = mvi->shost;
memset(mvi->rx_fis, 0, MVS_RX_FISL_SZ);
mvi->rx = dma_alloc_coherent(&pdev->dev,
- sizeof(*mvi->rx) * MVS_RX_RING_SZ,
+ sizeof(*mvi->rx) * (MVS_RX_RING_SZ + 1),
&mvi->rx_dma, GFP_KERNEL);
if (!mvi->rx)
goto err_out;
- memset(mvi->rx, 0, sizeof(*mvi->rx) * MVS_RX_RING_SZ);
+ memset(mvi->rx, 0, sizeof(*mvi->rx) * (MVS_RX_RING_SZ + 1));
mvi->rx[0] = cpu_to_le32(0xfff);
mvi->rx_cons = 0xfff;
mvs_cw32(regs, CMD_SAS_CTL0, tmp);
/* workaround for WDTIMEOUT , set to 550 ms */
- mvs_cw32(regs, CMD_WD_TIMER, 0xffffff);
+ mvs_cw32(regs, CMD_WD_TIMER, 0x86470);
/* not to halt for different port op during wideport link change */
mvs_cw32(regs, CMD_APP_ERR_CONFIG, 0xffefbf7d);
{
u32 tmp;
struct mvs_phy *phy = &mvi->phy[i];
- struct mvs_port *port;
+ struct mvs_port *port = phy->port;;
tmp = mvs_read_phy_ctl(mvi, i);
if ((tmp & PHY_READY_MASK) && !(phy->irq_status & PHYEV_POOF)) {
- if (!phy->port)
+ if (!port)
phy->phy_attached = 1;
return tmp;
}
- port = phy->port;
if (port) {
if (phy->phy_type & PORT_TYPE_SAS) {
port->wide_port_phymap &= ~(1U << i);
{
struct mvs_phy *phy = &mvi->phy[i];
struct pci_dev *pdev = mvi->pdev;
- u32 tmp, j;
+ u32 tmp;
u64 tmp64;
mvs_write_port_cfg_addr(mvi, i, PHYR_IDENTIFY);
sas_phy->linkrate =
(phy->phy_status & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >>
PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET;
-
- /* Updated attached_sas_addr */
- mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_ADDR_HI);
- phy->att_dev_sas_addr =
- (u64) mvs_read_port_cfg_data(mvi, i) << 32;
-
- mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_ADDR_LO);
- phy->att_dev_sas_addr |= mvs_read_port_cfg_data(mvi, i);
-
- dev_printk(KERN_DEBUG, &pdev->dev,
- "phy[%d] Get Attached Address 0x%llX ,"
- " SAS Address 0x%llX\n",
- i, phy->att_dev_sas_addr, phy->dev_sas_addr);
- dev_printk(KERN_DEBUG, &pdev->dev,
- "Rate = %x , type = %d\n",
- sas_phy->linkrate, phy->phy_type);
-
-#if 1
- /*
- * If the device is capable of supporting a wide port
- * on its phys, it may configure the phys as a wide port.
- */
- if (phy->phy_type & PORT_TYPE_SAS)
- for (j = 0; j < mvi->chip->n_phy && j != i; ++j) {
- if ((mvi->phy[j].phy_attached) &&
- (mvi->phy[j].phy_type & PORT_TYPE_SAS))
- if (phy->att_dev_sas_addr ==
- mvi->phy[j].att_dev_sas_addr - 1) {
- phy->att_dev_sas_addr =
- mvi->phy[j].att_dev_sas_addr;
- break;
- }
- }
-
-#endif
-
- tmp64 = cpu_to_be64(phy->att_dev_sas_addr);
- memcpy(sas_phy->attached_sas_addr, &tmp64, SAS_ADDR_SIZE);
+ phy->minimum_linkrate =
+ (phy->phy_status &
+ PHY_MIN_SPP_PHYS_LINK_RATE_MASK) >> 8;
+ phy->maximum_linkrate =
+ (phy->phy_status &
+ PHY_MAX_SPP_PHYS_LINK_RATE_MASK) >> 12;
if (phy->phy_type & PORT_TYPE_SAS) {
+ /* Updated attached_sas_addr */
+ mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_ADDR_HI);
+ phy->att_dev_sas_addr =
+ (u64) mvs_read_port_cfg_data(mvi, i) << 32;
+ mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_ADDR_LO);
+ phy->att_dev_sas_addr |= mvs_read_port_cfg_data(mvi, i);
mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_DEV_INFO);
phy->att_dev_info = mvs_read_port_cfg_data(mvi, i);
phy->identify.device_type =
} else if (phy->phy_type & PORT_TYPE_SATA) {
phy->identify.target_port_protocols = SAS_PROTOCOL_STP;
if (mvs_is_sig_fis_received(phy->irq_status)) {
+ phy->att_dev_sas_addr = i; /* temp */
if (phy_st & PHY_OOB_DTCTD)
sas_phy->oob_mode = SATA_OOB_MODE;
phy->frame_rcvd_size =
} else {
dev_printk(KERN_DEBUG, &pdev->dev,
"No sig fis\n");
+ phy->phy_type &= ~(PORT_TYPE_SATA);
+ goto out_done;
}
}
+ tmp64 = cpu_to_be64(phy->att_dev_sas_addr);
+ memcpy(sas_phy->attached_sas_addr, &tmp64, SAS_ADDR_SIZE);
+
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "phy[%d] Get Attached Address 0x%llX ,"
+ " SAS Address 0x%llX\n",
+ i,
+ (unsigned long long)phy->att_dev_sas_addr,
+ (unsigned long long)phy->dev_sas_addr);
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "Rate = %x , type = %d\n",
+ sas_phy->linkrate, phy->phy_type);
+
/* workaround for HW phy decoding error on 1.5g disk drive */
mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE6);
tmp = mvs_read_port_vsr_data(mvi, i);
if (((phy->phy_status & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >>
PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET) ==
SAS_LINK_RATE_1_5_GBPS)
- tmp &= ~PHY_MODE6_DTL_SPEED;
+ tmp &= ~PHY_MODE6_LATECLK;
else
- tmp |= PHY_MODE6_DTL_SPEED;
+ tmp |= PHY_MODE6_LATECLK;
mvs_write_port_vsr_data(mvi, i, tmp);
}
+out_done:
if (get_st)
mvs_write_port_irq_stat(mvi, i, phy->irq_status);
}
spin_unlock_irqrestore(&mvi->lock, flags);
}
+static int mvs_I_T_nexus_reset(struct domain_device *dev)
+{
+ return TMF_RESP_FUNC_FAILED;
+}
+
static int __devinit mvs_hw_init(struct mvs_info *mvi)
{
void __iomem *regs = mvi->regs;
/* enable CMD/CMPL_Q/RESP mode */
mw32(PCS, PCS_SATA_RETRY | PCS_FIS_RX_EN | PCS_CMD_EN);
- /* re-enable interrupts globally */
- mvs_hba_interrupt_enable(mvi);
-
/* enable completion queue interrupt */
- tmp = (CINT_PORT_MASK | CINT_DONE | CINT_MEM);
+ tmp = (CINT_PORT_MASK | CINT_DONE | CINT_MEM | CINT_SRS);
mw32(INT_MASK, tmp);
+ /* Enable SRS interrupt */
+ mw32(INT_MASK_SRS, 0xFF);
return 0;
}
mvs_print_info(mvi);
+ mvs_hba_interrupt_enable(mvi);
+
scsi_scan_host(mvi->shost);
return 0;
.lldd_execute_task = mvs_task_exec,
.lldd_control_phy = mvs_phy_control,
.lldd_abort_task = mvs_task_abort,
- .lldd_port_formed = mvs_port_formed
+ .lldd_port_formed = mvs_port_formed,
+ .lldd_I_T_nexus_reset = mvs_I_T_nexus_reset,
};
static struct pci_device_id __devinitdata mvs_pci_table[] = {
{ PCI_VDEVICE(MARVELL, 0x6320), chip_6320 },
{ PCI_VDEVICE(MARVELL, 0x6340), chip_6440 },
+ {
+ .vendor = PCI_VENDOR_ID_MARVELL,
+ .device = 0x6440,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = 0x6480,
+ .class = 0,
+ .class_mask = 0,
+ .driver_data = chip_6480,
+ },
{ PCI_VDEVICE(MARVELL, 0x6440), chip_6440 },
{ PCI_VDEVICE(MARVELL, 0x6480), chip_6480 },