diff options
Diffstat (limited to 'drivers/scsi/pm8001/pm80xx_hwi.c')
-rw-r--r-- | drivers/scsi/pm8001/pm80xx_hwi.c | 262 |
1 files changed, 250 insertions, 12 deletions
diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c index 7dee46716a58..f0dbe79b049c 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.c +++ b/drivers/scsi/pm8001/pm80xx_hwi.c | |||
@@ -270,6 +270,9 @@ static void init_default_table_values(struct pm8001_hba_info *pm8001_ha) | |||
270 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.pcs_event_log_severity = 0x01; | 270 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.pcs_event_log_severity = 0x01; |
271 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.fatal_err_interrupt = 0x01; | 271 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.fatal_err_interrupt = 0x01; |
272 | 272 | ||
273 | /* Disable end to end CRC checking */ | ||
274 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.crc_core_dump = (0x1 << 16); | ||
275 | |||
273 | for (i = 0; i < PM8001_MAX_SPCV_INB_NUM; i++) { | 276 | for (i = 0; i < PM8001_MAX_SPCV_INB_NUM; i++) { |
274 | pm8001_ha->inbnd_q_tbl[i].element_pri_size_cnt = | 277 | pm8001_ha->inbnd_q_tbl[i].element_pri_size_cnt = |
275 | PM8001_MPI_QUEUE | (64 << 16) | (0x00<<30); | 278 | PM8001_MPI_QUEUE | (64 << 16) | (0x00<<30); |
@@ -353,6 +356,8 @@ static void update_main_config_table(struct pm8001_hba_info *pm8001_ha) | |||
353 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.pcs_event_log_severity); | 356 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.pcs_event_log_severity); |
354 | pm8001_mw32(address, MAIN_FATAL_ERROR_INTERRUPT, | 357 | pm8001_mw32(address, MAIN_FATAL_ERROR_INTERRUPT, |
355 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.fatal_err_interrupt); | 358 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.fatal_err_interrupt); |
359 | pm8001_mw32(address, MAIN_EVENT_CRC_CHECK, | ||
360 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.crc_core_dump); | ||
356 | 361 | ||
357 | /* SPCv specific */ | 362 | /* SPCv specific */ |
358 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.gpio_led_mapping &= 0xCFFFFFFF; | 363 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.gpio_led_mapping &= 0xCFFFFFFF; |
@@ -1026,6 +1031,123 @@ pm80xx_chip_interrupt_disable(struct pm8001_hba_info *pm8001_ha, u8 vec) | |||
1026 | pm80xx_chip_intx_interrupt_disable(pm8001_ha); | 1031 | pm80xx_chip_intx_interrupt_disable(pm8001_ha); |
1027 | } | 1032 | } |
1028 | 1033 | ||
1034 | static void pm80xx_send_abort_all(struct pm8001_hba_info *pm8001_ha, | ||
1035 | struct pm8001_device *pm8001_ha_dev) | ||
1036 | { | ||
1037 | int res; | ||
1038 | u32 ccb_tag; | ||
1039 | struct pm8001_ccb_info *ccb; | ||
1040 | struct sas_task *task = NULL; | ||
1041 | struct task_abort_req task_abort; | ||
1042 | struct inbound_queue_table *circularQ; | ||
1043 | u32 opc = OPC_INB_SATA_ABORT; | ||
1044 | int ret; | ||
1045 | |||
1046 | if (!pm8001_ha_dev) { | ||
1047 | PM8001_FAIL_DBG(pm8001_ha, pm8001_printk("dev is null\n")); | ||
1048 | return; | ||
1049 | } | ||
1050 | |||
1051 | task = sas_alloc_slow_task(GFP_ATOMIC); | ||
1052 | |||
1053 | if (!task) { | ||
1054 | PM8001_FAIL_DBG(pm8001_ha, pm8001_printk("cannot " | ||
1055 | "allocate task\n")); | ||
1056 | return; | ||
1057 | } | ||
1058 | |||
1059 | task->task_done = pm8001_task_done; | ||
1060 | |||
1061 | res = pm8001_tag_alloc(pm8001_ha, &ccb_tag); | ||
1062 | if (res) | ||
1063 | return; | ||
1064 | |||
1065 | ccb = &pm8001_ha->ccb_info[ccb_tag]; | ||
1066 | ccb->device = pm8001_ha_dev; | ||
1067 | ccb->ccb_tag = ccb_tag; | ||
1068 | ccb->task = task; | ||
1069 | |||
1070 | circularQ = &pm8001_ha->inbnd_q_tbl[0]; | ||
1071 | |||
1072 | memset(&task_abort, 0, sizeof(task_abort)); | ||
1073 | task_abort.abort_all = cpu_to_le32(1); | ||
1074 | task_abort.device_id = cpu_to_le32(pm8001_ha_dev->device_id); | ||
1075 | task_abort.tag = cpu_to_le32(ccb_tag); | ||
1076 | |||
1077 | ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &task_abort, 0); | ||
1078 | |||
1079 | } | ||
1080 | |||
1081 | static void pm80xx_send_read_log(struct pm8001_hba_info *pm8001_ha, | ||
1082 | struct pm8001_device *pm8001_ha_dev) | ||
1083 | { | ||
1084 | struct sata_start_req sata_cmd; | ||
1085 | int res; | ||
1086 | u32 ccb_tag; | ||
1087 | struct pm8001_ccb_info *ccb; | ||
1088 | struct sas_task *task = NULL; | ||
1089 | struct host_to_dev_fis fis; | ||
1090 | struct domain_device *dev; | ||
1091 | struct inbound_queue_table *circularQ; | ||
1092 | u32 opc = OPC_INB_SATA_HOST_OPSTART; | ||
1093 | |||
1094 | task = sas_alloc_slow_task(GFP_ATOMIC); | ||
1095 | |||
1096 | if (!task) { | ||
1097 | PM8001_FAIL_DBG(pm8001_ha, | ||
1098 | pm8001_printk("cannot allocate task !!!\n")); | ||
1099 | return; | ||
1100 | } | ||
1101 | task->task_done = pm8001_task_done; | ||
1102 | |||
1103 | res = pm8001_tag_alloc(pm8001_ha, &ccb_tag); | ||
1104 | if (res) { | ||
1105 | PM8001_FAIL_DBG(pm8001_ha, | ||
1106 | pm8001_printk("cannot allocate tag !!!\n")); | ||
1107 | return; | ||
1108 | } | ||
1109 | |||
1110 | /* allocate domain device by ourselves as libsas | ||
1111 | * is not going to provide any | ||
1112 | */ | ||
1113 | dev = kzalloc(sizeof(struct domain_device), GFP_ATOMIC); | ||
1114 | if (!dev) { | ||
1115 | PM8001_FAIL_DBG(pm8001_ha, | ||
1116 | pm8001_printk("Domain device cannot be allocated\n")); | ||
1117 | sas_free_task(task); | ||
1118 | return; | ||
1119 | } else { | ||
1120 | task->dev = dev; | ||
1121 | task->dev->lldd_dev = pm8001_ha_dev; | ||
1122 | } | ||
1123 | |||
1124 | ccb = &pm8001_ha->ccb_info[ccb_tag]; | ||
1125 | ccb->device = pm8001_ha_dev; | ||
1126 | ccb->ccb_tag = ccb_tag; | ||
1127 | ccb->task = task; | ||
1128 | pm8001_ha_dev->id |= NCQ_READ_LOG_FLAG; | ||
1129 | pm8001_ha_dev->id |= NCQ_2ND_RLE_FLAG; | ||
1130 | |||
1131 | memset(&sata_cmd, 0, sizeof(sata_cmd)); | ||
1132 | circularQ = &pm8001_ha->inbnd_q_tbl[0]; | ||
1133 | |||
1134 | /* construct read log FIS */ | ||
1135 | memset(&fis, 0, sizeof(struct host_to_dev_fis)); | ||
1136 | fis.fis_type = 0x27; | ||
1137 | fis.flags = 0x80; | ||
1138 | fis.command = ATA_CMD_READ_LOG_EXT; | ||
1139 | fis.lbal = 0x10; | ||
1140 | fis.sector_count = 0x1; | ||
1141 | |||
1142 | sata_cmd.tag = cpu_to_le32(ccb_tag); | ||
1143 | sata_cmd.device_id = cpu_to_le32(pm8001_ha_dev->device_id); | ||
1144 | sata_cmd.ncqtag_atap_dir_m_dad |= ((0x1 << 7) | (0x5 << 9)); | ||
1145 | memcpy(&sata_cmd.sata_fis, &fis, sizeof(struct host_to_dev_fis)); | ||
1146 | |||
1147 | res = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &sata_cmd, 0); | ||
1148 | |||
1149 | } | ||
1150 | |||
1029 | /** | 1151 | /** |
1030 | * mpi_ssp_completion- process the event that FW response to the SSP request. | 1152 | * mpi_ssp_completion- process the event that FW response to the SSP request. |
1031 | * @pm8001_ha: our hba card information | 1153 | * @pm8001_ha: our hba card information |
@@ -1480,22 +1602,50 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) | |||
1480 | struct ata_task_resp *resp ; | 1602 | struct ata_task_resp *resp ; |
1481 | u32 *sata_resp; | 1603 | u32 *sata_resp; |
1482 | struct pm8001_device *pm8001_dev; | 1604 | struct pm8001_device *pm8001_dev; |
1483 | unsigned long flags = 0; | 1605 | unsigned long flags; |
1484 | 1606 | ||
1485 | psataPayload = (struct sata_completion_resp *)(piomb + 4); | 1607 | psataPayload = (struct sata_completion_resp *)(piomb + 4); |
1486 | status = le32_to_cpu(psataPayload->status); | 1608 | status = le32_to_cpu(psataPayload->status); |
1487 | tag = le32_to_cpu(psataPayload->tag); | 1609 | tag = le32_to_cpu(psataPayload->tag); |
1488 | 1610 | ||
1611 | if (!tag) { | ||
1612 | PM8001_FAIL_DBG(pm8001_ha, | ||
1613 | pm8001_printk("tag null\n")); | ||
1614 | return; | ||
1615 | } | ||
1489 | ccb = &pm8001_ha->ccb_info[tag]; | 1616 | ccb = &pm8001_ha->ccb_info[tag]; |
1490 | param = le32_to_cpu(psataPayload->param); | 1617 | param = le32_to_cpu(psataPayload->param); |
1491 | t = ccb->task; | 1618 | if (ccb) { |
1619 | t = ccb->task; | ||
1620 | pm8001_dev = ccb->device; | ||
1621 | } else { | ||
1622 | PM8001_FAIL_DBG(pm8001_ha, | ||
1623 | pm8001_printk("ccb null\n")); | ||
1624 | return; | ||
1625 | } | ||
1626 | |||
1627 | if (t) { | ||
1628 | if (t->dev && (t->dev->lldd_dev)) | ||
1629 | pm8001_dev = t->dev->lldd_dev; | ||
1630 | } else { | ||
1631 | PM8001_FAIL_DBG(pm8001_ha, | ||
1632 | pm8001_printk("task null\n")); | ||
1633 | return; | ||
1634 | } | ||
1635 | |||
1636 | if ((pm8001_dev && !(pm8001_dev->id & NCQ_READ_LOG_FLAG)) | ||
1637 | && unlikely(!t || !t->lldd_task || !t->dev)) { | ||
1638 | PM8001_FAIL_DBG(pm8001_ha, | ||
1639 | pm8001_printk("task or dev null\n")); | ||
1640 | return; | ||
1641 | } | ||
1642 | |||
1492 | ts = &t->task_status; | 1643 | ts = &t->task_status; |
1493 | pm8001_dev = ccb->device; | 1644 | if (!ts) { |
1494 | if (status) | ||
1495 | PM8001_FAIL_DBG(pm8001_ha, | 1645 | PM8001_FAIL_DBG(pm8001_ha, |
1496 | pm8001_printk("sata IO status 0x%x\n", status)); | 1646 | pm8001_printk("ts null\n")); |
1497 | if (unlikely(!t || !t->lldd_task || !t->dev)) | ||
1498 | return; | 1647 | return; |
1648 | } | ||
1499 | 1649 | ||
1500 | switch (status) { | 1650 | switch (status) { |
1501 | case IO_SUCCESS: | 1651 | case IO_SUCCESS: |
@@ -1503,6 +1653,19 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) | |||
1503 | if (param == 0) { | 1653 | if (param == 0) { |
1504 | ts->resp = SAS_TASK_COMPLETE; | 1654 | ts->resp = SAS_TASK_COMPLETE; |
1505 | ts->stat = SAM_STAT_GOOD; | 1655 | ts->stat = SAM_STAT_GOOD; |
1656 | /* check if response is for SEND READ LOG */ | ||
1657 | if (pm8001_dev && | ||
1658 | (pm8001_dev->id & NCQ_READ_LOG_FLAG)) { | ||
1659 | /* set new bit for abort_all */ | ||
1660 | pm8001_dev->id |= NCQ_ABORT_ALL_FLAG; | ||
1661 | /* clear bit for read log */ | ||
1662 | pm8001_dev->id = pm8001_dev->id & 0x7FFFFFFF; | ||
1663 | pm80xx_send_abort_all(pm8001_ha, pm8001_dev); | ||
1664 | /* Free the tag */ | ||
1665 | pm8001_tag_free(pm8001_ha, tag); | ||
1666 | sas_free_task(t); | ||
1667 | return; | ||
1668 | } | ||
1506 | } else { | 1669 | } else { |
1507 | u8 len; | 1670 | u8 len; |
1508 | ts->resp = SAS_TASK_COMPLETE; | 1671 | ts->resp = SAS_TASK_COMPLETE; |
@@ -1807,16 +1970,39 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb) | |||
1807 | u32 event = le32_to_cpu(psataPayload->event); | 1970 | u32 event = le32_to_cpu(psataPayload->event); |
1808 | u32 tag = le32_to_cpu(psataPayload->tag); | 1971 | u32 tag = le32_to_cpu(psataPayload->tag); |
1809 | u32 port_id = le32_to_cpu(psataPayload->port_id); | 1972 | u32 port_id = le32_to_cpu(psataPayload->port_id); |
1810 | unsigned long flags = 0; | 1973 | u32 dev_id = le32_to_cpu(psataPayload->device_id); |
1974 | unsigned long flags; | ||
1811 | 1975 | ||
1812 | ccb = &pm8001_ha->ccb_info[tag]; | 1976 | ccb = &pm8001_ha->ccb_info[tag]; |
1813 | t = ccb->task; | 1977 | |
1814 | pm8001_dev = ccb->device; | 1978 | if (ccb) { |
1979 | t = ccb->task; | ||
1980 | pm8001_dev = ccb->device; | ||
1981 | } else { | ||
1982 | PM8001_FAIL_DBG(pm8001_ha, | ||
1983 | pm8001_printk("No CCB !!!. returning\n")); | ||
1984 | return; | ||
1985 | } | ||
1815 | if (event) | 1986 | if (event) |
1816 | PM8001_FAIL_DBG(pm8001_ha, | 1987 | PM8001_FAIL_DBG(pm8001_ha, |
1817 | pm8001_printk("sata IO status 0x%x\n", event)); | 1988 | pm8001_printk("SATA EVENT 0x%x\n", event)); |
1818 | if (unlikely(!t || !t->lldd_task || !t->dev)) | 1989 | |
1990 | /* Check if this is NCQ error */ | ||
1991 | if (event == IO_XFER_ERROR_ABORTED_NCQ_MODE) { | ||
1992 | /* find device using device id */ | ||
1993 | pm8001_dev = pm8001_find_dev(pm8001_ha, dev_id); | ||
1994 | /* send read log extension */ | ||
1995 | if (pm8001_dev) | ||
1996 | pm80xx_send_read_log(pm8001_ha, pm8001_dev); | ||
1997 | return; | ||
1998 | } | ||
1999 | |||
2000 | if (unlikely(!t || !t->lldd_task || !t->dev)) { | ||
2001 | PM8001_FAIL_DBG(pm8001_ha, | ||
2002 | pm8001_printk("task or dev null\n")); | ||
1819 | return; | 2003 | return; |
2004 | } | ||
2005 | |||
1820 | ts = &t->task_status; | 2006 | ts = &t->task_status; |
1821 | PM8001_IO_DBG(pm8001_ha, | 2007 | PM8001_IO_DBG(pm8001_ha, |
1822 | pm8001_printk("port_id:0x%x, tag:0x%x, event:0x%x\n", | 2008 | pm8001_printk("port_id:0x%x, tag:0x%x, event:0x%x\n", |
@@ -3414,6 +3600,7 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha, | |||
3414 | u32 ATAP = 0x0; | 3600 | u32 ATAP = 0x0; |
3415 | u32 dir; | 3601 | u32 dir; |
3416 | struct inbound_queue_table *circularQ; | 3602 | struct inbound_queue_table *circularQ; |
3603 | unsigned long flags; | ||
3417 | u32 opc = OPC_INB_SATA_HOST_OPSTART; | 3604 | u32 opc = OPC_INB_SATA_HOST_OPSTART; |
3418 | memset(&sata_cmd, 0, sizeof(sata_cmd)); | 3605 | memset(&sata_cmd, 0, sizeof(sata_cmd)); |
3419 | circularQ = &pm8001_ha->inbnd_q_tbl[inb++]; | 3606 | circularQ = &pm8001_ha->inbnd_q_tbl[inb++]; |
@@ -3438,8 +3625,10 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha, | |||
3438 | PM8001_IO_DBG(pm8001_ha, pm8001_printk("FPDMA\n")); | 3625 | PM8001_IO_DBG(pm8001_ha, pm8001_printk("FPDMA\n")); |
3439 | } | 3626 | } |
3440 | } | 3627 | } |
3441 | if (task->ata_task.use_ncq && pm8001_get_ncq_tag(task, &hdr_tag)) | 3628 | if (task->ata_task.use_ncq && pm8001_get_ncq_tag(task, &hdr_tag)) { |
3629 | task->ata_task.fis.sector_count |= (u8) (hdr_tag << 3); | ||
3442 | ncg_tag = hdr_tag; | 3630 | ncg_tag = hdr_tag; |
3631 | } | ||
3443 | dir = data_dir_flags[task->data_dir] << 8; | 3632 | dir = data_dir_flags[task->data_dir] << 8; |
3444 | sata_cmd.tag = cpu_to_le32(tag); | 3633 | sata_cmd.tag = cpu_to_le32(tag); |
3445 | sata_cmd.device_id = cpu_to_le32(pm8001_ha_dev->device_id); | 3634 | sata_cmd.device_id = cpu_to_le32(pm8001_ha_dev->device_id); |
@@ -3547,6 +3736,55 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha, | |||
3547 | (task->ata_task.atapi_packet[14] << 16) | | 3736 | (task->ata_task.atapi_packet[14] << 16) | |
3548 | (task->ata_task.atapi_packet[15] << 24))); | 3737 | (task->ata_task.atapi_packet[15] << 24))); |
3549 | } | 3738 | } |
3739 | |||
3740 | /* Check for read log for failed drive and return */ | ||
3741 | if (sata_cmd.sata_fis.command == 0x2f) { | ||
3742 | if (pm8001_ha_dev && ((pm8001_ha_dev->id & NCQ_READ_LOG_FLAG) || | ||
3743 | (pm8001_ha_dev->id & NCQ_ABORT_ALL_FLAG) || | ||
3744 | (pm8001_ha_dev->id & NCQ_2ND_RLE_FLAG))) { | ||
3745 | struct task_status_struct *ts; | ||
3746 | |||
3747 | pm8001_ha_dev->id &= 0xDFFFFFFF; | ||
3748 | ts = &task->task_status; | ||
3749 | |||
3750 | spin_lock_irqsave(&task->task_state_lock, flags); | ||
3751 | ts->resp = SAS_TASK_COMPLETE; | ||
3752 | ts->stat = SAM_STAT_GOOD; | ||
3753 | task->task_state_flags &= ~SAS_TASK_STATE_PENDING; | ||
3754 | task->task_state_flags &= ~SAS_TASK_AT_INITIATOR; | ||
3755 | task->task_state_flags |= SAS_TASK_STATE_DONE; | ||
3756 | if (unlikely((task->task_state_flags & | ||
3757 | SAS_TASK_STATE_ABORTED))) { | ||
3758 | spin_unlock_irqrestore(&task->task_state_lock, | ||
3759 | flags); | ||
3760 | PM8001_FAIL_DBG(pm8001_ha, | ||
3761 | pm8001_printk("task 0x%p resp 0x%x " | ||
3762 | " stat 0x%x but aborted by upper layer " | ||
3763 | "\n", task, ts->resp, ts->stat)); | ||
3764 | pm8001_ccb_task_free(pm8001_ha, task, ccb, tag); | ||
3765 | return 0; | ||
3766 | } else if (task->uldd_task) { | ||
3767 | spin_unlock_irqrestore(&task->task_state_lock, | ||
3768 | flags); | ||
3769 | pm8001_ccb_task_free(pm8001_ha, task, ccb, tag); | ||
3770 | mb();/* ditto */ | ||
3771 | spin_unlock_irq(&pm8001_ha->lock); | ||
3772 | task->task_done(task); | ||
3773 | spin_lock_irq(&pm8001_ha->lock); | ||
3774 | return 0; | ||
3775 | } else if (!task->uldd_task) { | ||
3776 | spin_unlock_irqrestore(&task->task_state_lock, | ||
3777 | flags); | ||
3778 | pm8001_ccb_task_free(pm8001_ha, task, ccb, tag); | ||
3779 | mb();/*ditto*/ | ||
3780 | spin_unlock_irq(&pm8001_ha->lock); | ||
3781 | task->task_done(task); | ||
3782 | spin_lock_irq(&pm8001_ha->lock); | ||
3783 | return 0; | ||
3784 | } | ||
3785 | } | ||
3786 | } | ||
3787 | |||
3550 | ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, | 3788 | ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, |
3551 | &sata_cmd, outb++); | 3789 | &sata_cmd, outb++); |
3552 | 3790 | ||