diff options
Diffstat (limited to 'drivers/scsi/hisi_sas')
-rw-r--r-- | drivers/scsi/hisi_sas/hisi_sas.h | 18 | ||||
-rw-r--r-- | drivers/scsi/hisi_sas/hisi_sas_main.c | 238 | ||||
-rw-r--r-- | drivers/scsi/hisi_sas/hisi_sas_v1_hw.c | 36 | ||||
-rw-r--r-- | drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 130 |
4 files changed, 326 insertions, 96 deletions
diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index 4731d3241323..72c98522bd26 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -23,7 +23,7 @@ #include <scsi/sas_ata.h> #include <scsi/libsas.h> -#define DRV_VERSION "v1.5" +#define DRV_VERSION "v1.6" #define HISI_SAS_MAX_PHYS 9 #define HISI_SAS_MAX_QUEUES 32 @@ -56,6 +56,11 @@ enum dev_status { HISI_SAS_DEV_EH, }; +enum { + HISI_SAS_INT_ABT_CMD = 0, + HISI_SAS_INT_ABT_DEV = 1, +}; + enum hisi_sas_dev_type { HISI_SAS_DEV_TYPE_STP = 0, HISI_SAS_DEV_TYPE_SSP, @@ -89,6 +94,13 @@ struct hisi_sas_port { struct hisi_sas_cq { struct hisi_hba *hisi_hba; + int rd_point; + int id; +}; + +struct hisi_sas_dq { + struct hisi_hba *hisi_hba; + int wr_point; int id; }; @@ -146,6 +158,9 @@ struct hisi_sas_hw { struct hisi_sas_slot *slot); int (*prep_stp)(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot); + int (*prep_abort)(struct hisi_hba *hisi_hba, + struct hisi_sas_slot *slot, + int device_id, int abort_flag, int tag_to_abort); int (*slot_complete)(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot, int abort); void (*phy_enable)(struct hisi_hba *hisi_hba, int phy_no); @@ -185,6 +200,7 @@ struct hisi_hba { struct Scsi_Host *shost; struct hisi_sas_cq cq[HISI_SAS_MAX_QUEUES]; + struct hisi_sas_dq dq[HISI_SAS_MAX_QUEUES]; struct hisi_sas_phy phy[HISI_SAS_MAX_PHYS]; struct hisi_sas_port port[HISI_SAS_MAX_PHYS]; diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 18dd5ea2c721..2f872f784e10 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -17,6 +17,10 @@ static int hisi_sas_debug_issue_ssp_tmf(struct domain_device *device, u8 *lun, struct hisi_sas_tmf_task *tmf); +static int +hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba, + struct domain_device *device, + int abort_flag, int tag); static struct hisi_hba *dev_to_hisi_hba(struct domain_device *device) { @@ -93,7 +97,7 @@ void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task, slot->task = NULL; slot->port = NULL; hisi_sas_slot_index_free(hisi_hba, slot->idx); - memset(slot, 0, sizeof(*slot)); + /* slot memory is fully zeroed when it is reused */ } EXPORT_SYMBOL_GPL(hisi_sas_slot_task_free); @@ -116,6 +120,14 @@ static int hisi_sas_task_prep_ata(struct hisi_hba *hisi_hba, return hisi_hba->hw->prep_stp(hisi_hba, slot); } +static int hisi_sas_task_prep_abort(struct hisi_hba *hisi_hba, + struct hisi_sas_slot *slot, + int device_id, int abort_flag, int tag_to_abort) +{ + return hisi_hba->hw->prep_abort(hisi_hba, slot, + device_id, abort_flag, tag_to_abort); +} + /* * This function will issue an abort TMF regardless of whether the * task is in the sdev or not. Then it will do the task complete @@ -192,27 +204,13 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba, return rc; } port = device->port->lldd_port; - if (port && !port->port_attached && !tmf) { - if (sas_protocol_ata(task->task_proto)) { - struct task_status_struct *ts = &task->task_status; - - dev_info(dev, - "task prep: SATA/STP port%d not attach device\n", - device->port->id); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_PHY_DOWN; - task->task_done(task); - } else { - struct task_status_struct *ts = &task->task_status; - - dev_info(dev, - "task prep: SAS port%d does not attach device\n", - device->port->id); - ts->resp = SAS_TASK_UNDELIVERED; - ts->stat = SAS_PHY_DOWN; - task->task_done(task); - } - return 0; + if (port && !port->port_attached) { + dev_info(dev, "task prep: %s port%d not attach device\n", + (sas_protocol_ata(task->task_proto)) ? + "SATA/STP" : "SAS", + device->port->id); + + return SAS_PHY_DOWN; } if (!sas_protocol_ata(task->task_proto)) { @@ -609,6 +607,9 @@ static void hisi_sas_dev_gone(struct domain_device *device) dev_info(dev, "found dev[%lld:%x] is gone\n", sas_dev->device_id, sas_dev->dev_type); + hisi_sas_internal_task_abort(hisi_hba, device, + HISI_SAS_INT_ABT_DEV, 0); + hisi_hba->hw->free_device(hisi_hba, sas_dev); device->lldd_dev = NULL; memset(sas_dev, 0, sizeof(*sas_dev)); @@ -729,6 +730,12 @@ static int hisi_sas_exec_internal_tmf_task(struct domain_device *device, } if (task->task_status.resp == SAS_TASK_COMPLETE && + task->task_status.stat == TMF_RESP_FUNC_SUCC) { + res = TMF_RESP_FUNC_SUCC; + break; + } + + if (task->task_status.resp == SAS_TASK_COMPLETE && task->task_status.stat == SAS_DATA_UNDERRUN) { /* no error, but return the number of bytes of * underrun @@ -826,18 +833,22 @@ static int hisi_sas_abort_task(struct sas_task *task) } } + hisi_sas_internal_task_abort(hisi_hba, device, + HISI_SAS_INT_ABT_CMD, tag); } else if (task->task_proto & SAS_PROTOCOL_SATA || task->task_proto & SAS_PROTOCOL_STP) { if (task->dev->dev_type == SAS_SATA_DEV) { - struct hisi_slot_info *slot = task->lldd_task; - - dev_notice(dev, "abort task: hba=%p task=%p slot=%p\n", - hisi_hba, task, slot); - task->task_state_flags |= SAS_TASK_STATE_ABORTED; + hisi_sas_internal_task_abort(hisi_hba, device, + HISI_SAS_INT_ABT_DEV, 0); rc = TMF_RESP_FUNC_COMPLETE; - goto out; } + } else if (task->task_proto & SAS_PROTOCOL_SMP) { + /* SMP */ + struct hisi_sas_slot *slot = task->lldd_task; + u32 tag = slot->idx; + hisi_sas_internal_task_abort(hisi_hba, device, + HISI_SAS_INT_ABT_CMD, tag); } out: @@ -954,6 +965,157 @@ static int hisi_sas_query_task(struct sas_task *task) return rc; } +static int +hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, u64 device_id, + struct sas_task *task, int abort_flag, + int task_tag) +{ + struct domain_device *device = task->dev; + struct hisi_sas_device *sas_dev = device->lldd_dev; + struct device *dev = &hisi_hba->pdev->dev; + struct hisi_sas_port *port; + struct hisi_sas_slot *slot; + struct hisi_sas_cmd_hdr *cmd_hdr_base; + int dlvry_queue_slot, dlvry_queue, n_elem = 0, rc, slot_idx; + + if (!device->port) + return -1; + + port = device->port->lldd_port; + + /* simply get a slot and send abort command */ + rc = hisi_sas_slot_index_alloc(hisi_hba, &slot_idx); + if (rc) + goto err_out; + rc = hisi_hba->hw->get_free_slot(hisi_hba, &dlvry_queue, + &dlvry_queue_slot); + if (rc) + goto err_out_tag; + + slot = &hisi_hba->slot_info[slot_idx]; + memset(slot, 0, sizeof(struct hisi_sas_slot)); + + slot->idx = slot_idx; + slot->n_elem = n_elem; + slot->dlvry_queue = dlvry_queue; + slot->dlvry_queue_slot = dlvry_queue_slot; + cmd_hdr_base = hisi_hba->cmd_hdr[dlvry_queue]; + slot->cmd_hdr = &cmd_hdr_base[dlvry_queue_slot]; + slot->task = task; + slot->port = port; + task->lldd_task = slot; + + memset(slot->cmd_hdr, 0, sizeof(struct hisi_sas_cmd_hdr)); + + rc = hisi_sas_task_prep_abort(hisi_hba, slot, device_id, + abort_flag, task_tag); + if (rc) + goto err_out_tag; + + /* Port structure is static for the HBA, so + * even if the port is deformed it is ok + * to reference. + */ + list_add_tail(&slot->entry, &port->list); + spin_lock(&task->task_state_lock); + task->task_state_flags |= SAS_TASK_AT_INITIATOR; + spin_unlock(&task->task_state_lock); + + hisi_hba->slot_prep = slot; + + sas_dev->running_req++; + /* send abort command to our chip */ + hisi_hba->hw->start_delivery(hisi_hba); + + return 0; + +err_out_tag: + hisi_sas_slot_index_free(hisi_hba, slot_idx); +err_out: + dev_err(dev, "internal abort task prep: failed[%d]!\n", rc); + + return rc; +} + +/** + * hisi_sas_internal_task_abort -- execute an internal + * abort command for single IO command or a device + * @hisi_hba: host controller struct + * @device: domain device + * @abort_flag: mode of operation, device or single IO + * @tag: tag of IO to be aborted (only relevant to single + * IO mode) + */ +static int +hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba, + struct domain_device *device, + int abort_flag, int tag) +{ + struct sas_task *task; + struct hisi_sas_device *sas_dev = device->lldd_dev; + struct device *dev = &hisi_hba->pdev->dev; + int res; + unsigned long flags; + + if (!hisi_hba->hw->prep_abort) + return -EOPNOTSUPP; + + task = sas_alloc_slow_task(GFP_KERNEL); + if (!task) + return -ENOMEM; + + task->dev = device; + task->task_proto = device->tproto; + task->task_done = hisi_sas_task_done; + task->slow_task->timer.data = (unsigned long)task; + task->slow_task->timer.function = hisi_sas_tmf_timedout; + task->slow_task->timer.expires = jiffies + 20*HZ; + add_timer(&task->slow_task->timer); + + /* Lock as we are alloc'ing a slot, which cannot be interrupted */ + spin_lock_irqsave(&hisi_hba->lock, flags); + res = hisi_sas_internal_abort_task_exec(hisi_hba, sas_dev->device_id, + task, abort_flag, tag); + spin_unlock_irqrestore(&hisi_hba->lock, flags); + if (res) { + del_timer(&task->slow_task->timer); + dev_err(dev, "internal task abort: executing internal task failed: %d\n", + res); + goto exit; + } + wait_for_completion(&task->slow_task->completion); + res = TMF_RESP_FUNC_FAILED; + + if (task->task_status.resp == SAS_TASK_COMPLETE && + task->task_status.stat == TMF_RESP_FUNC_COMPLETE) { + res = TMF_RESP_FUNC_COMPLETE; + goto exit; + } + + /* TMF timed out, return direct. */ + if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) { + if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) { + dev_err(dev, "internal task abort: timeout.\n"); + if (task->lldd_task) { + struct hisi_sas_slot *slot = task->lldd_task; + + hisi_sas_slot_task_free(hisi_hba, task, slot); + } + } + } + +exit: + dev_info(dev, "internal task abort: task to dev %016llx task=%p " + "resp: 0x%x sts 0x%x\n", + SAS_ADDR(device->sas_addr), + task, + task->task_status.resp, /* 0 is complete, -1 is undelivered */ + task->task_status.stat); + sas_free_task(task); + + return res; +} + static void hisi_sas_port_formed(struct asd_sas_phy *sas_phy) { hisi_sas_port_notify_formed(sas_phy); @@ -1063,11 +1225,16 @@ static int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost) for (i = 0; i < hisi_hba->queue_count; i++) { struct hisi_sas_cq *cq = &hisi_hba->cq[i]; + struct hisi_sas_dq *dq = &hisi_hba->dq[i]; /* Completion queue structure */ cq->id = i; cq->hisi_hba = hisi_hba; + /* Delivery queue structure */ + dq->id = i; + dq->hisi_hba = hisi_hba; + /* Delivery queue */ s = sizeof(struct hisi_sas_cmd_hdr) * HISI_SAS_QUEUE_SLOTS; hisi_hba->cmd_hdr[i] = dma_alloc_coherent(dev, s, @@ -1128,7 +1295,7 @@ static int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost) memset(hisi_hba->breakpoint, 0, s); hisi_hba->slot_index_count = max_command_entries; - s = hisi_hba->slot_index_count / sizeof(unsigned long); + s = hisi_hba->slot_index_count / BITS_PER_BYTE; hisi_hba->slot_index_tags = devm_kzalloc(dev, s, GFP_KERNEL); if (!hisi_hba->slot_index_tags) goto err_out; @@ -1272,6 +1439,12 @@ static struct Scsi_Host *hisi_sas_shost_alloc(struct platform_device *pdev, &hisi_hba->queue_count)) goto err_out; + if (dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)) && + dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32))) { + dev_err(dev, "No usable DMA addressing method\n"); + goto err_out; + } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); hisi_hba->regs = devm_ioremap_resource(dev, res); if (IS_ERR(hisi_hba->regs)) @@ -1319,13 +1492,6 @@ int hisi_sas_probe(struct platform_device *pdev, hisi_hba = shost_priv(shost); platform_set_drvdata(pdev, sha); - if (dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)) && - dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32))) { - dev_err(dev, "No usable DMA addressing method\n"); - rc = -EIO; - goto err_out_ha; - } - phy_nr = port_nr = hisi_hba->n_phy; arr_phy = devm_kcalloc(dev, phy_nr, sizeof(void *), GFP_KERNEL); diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c index 1abbc2e162df..c0ac49d8bc8d 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c @@ -490,25 +490,17 @@ static void config_id_frame_v1_hw(struct hisi_hba *hisi_hba, int phy_no) hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD0, __swab32(identify_buffer[0])); hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD1, - identify_buffer[2]); + __swab32(identify_buffer[1])); hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD2, - identify_buffer[1]); + __swab32(identify_buffer[2])); hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD3, - identify_buffer[4]); + __swab32(identify_buffer[3])); hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD4, - identify_buffer[3]); + __swab32(identify_buffer[4])); hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD5, __swab32(identify_buffer[5])); } -static void init_id_frame_v1_hw(struct hisi_hba *hisi_hba) -{ - int i; - - for (i = 0; i < hisi_hba->n_phy; i++) - config_id_frame_v1_hw(hisi_hba, i); -} - static void setup_itct_v1_hw(struct hisi_hba *hisi_hba, struct hisi_sas_device *sas_dev) { @@ -774,8 +766,6 @@ static int hw_init_v1_hw(struct hisi_hba *hisi_hba) msleep(100); init_reg_v1_hw(hisi_hba); - init_id_frame_v1_hw(hisi_hba); - return 0; } @@ -875,12 +865,13 @@ static int get_wideport_bitmap_v1_hw(struct hisi_hba *hisi_hba, int port_id) static int get_free_slot_v1_hw(struct hisi_hba *hisi_hba, int *q, int *s) { struct device *dev = &hisi_hba->pdev->dev; + struct hisi_sas_dq *dq; u32 r, w; int queue = hisi_hba->queue; while (1) { - w = hisi_sas_read32_relaxed(hisi_hba, - DLVRY_Q_0_WR_PTR + (queue * 0x14)); + dq = &hisi_hba->dq[queue]; + w = dq->wr_point; r = hisi_sas_read32_relaxed(hisi_hba, DLVRY_Q_0_RD_PTR + (queue * 0x14)); if (r == (w+1) % HISI_SAS_QUEUE_SLOTS) { @@ -903,10 +894,11 @@ static void start_delivery_v1_hw(struct hisi_hba *hisi_hba) { int dlvry_queue = hisi_hba->slot_prep->dlvry_queue; int dlvry_queue_slot = hisi_hba->slot_prep->dlvry_queue_slot; + struct hisi_sas_dq *dq = &hisi_hba->dq[dlvry_queue]; - hisi_sas_write32(hisi_hba, - DLVRY_Q_0_WR_PTR + (dlvry_queue * 0x14), - ++dlvry_queue_slot % HISI_SAS_QUEUE_SLOTS); + dq->wr_point = ++dlvry_queue_slot % HISI_SAS_QUEUE_SLOTS; + hisi_sas_write32(hisi_hba, DLVRY_Q_0_WR_PTR + (dlvry_queue * 0x14), + dq->wr_point); } static int prep_prd_sge_v1_hw(struct hisi_hba *hisi_hba, @@ -1565,14 +1557,11 @@ static irqreturn_t cq_interrupt_v1_hw(int irq, void *p) struct hisi_sas_complete_v1_hdr *complete_queue = (struct hisi_sas_complete_v1_hdr *) hisi_hba->complete_hdr[queue]; - u32 irq_value, rd_point, wr_point; + u32 irq_value, rd_point = cq->rd_point, wr_point; irq_value = hisi_sas_read32(hisi_hba, OQ_INT_SRC); hisi_sas_write32(hisi_hba, OQ_INT_SRC, 1 << queue); - - rd_point = hisi_sas_read32(hisi_hba, - COMPL_Q_0_RD_PTR + (0x14 * queue)); wr_point = hisi_sas_read32(hisi_hba, COMPL_Q_0_WR_PTR + (0x14 * queue)); @@ -1600,6 +1589,7 @@ static irqreturn_t cq_interrupt_v1_hw(int irq, void *p) } /* update rd_point */ + cq->rd_point = rd_point; hisi_sas_write32(hisi_hba, COMPL_Q_0_RD_PTR + (0x14 * queue), rd_point); return IRQ_HANDLED; diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index f96560431cf1..9825a3f49f53 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -117,6 +117,8 @@ #define SL_CONTROL (PORT_BASE + 0x94) #define SL_CONTROL_NOTIFY_EN_OFF 0 #define SL_CONTROL_NOTIFY_EN_MSK (0x1 << SL_CONTROL_NOTIFY_EN_OFF) +#define SL_CONTROL_CTA_OFF 17 +#define SL_CONTROL_CTA_MSK (0x1 << SL_CONTROL_CTA_OFF) #define TX_ID_DWORD0 (PORT_BASE + 0x9c) #define TX_ID_DWORD1 (PORT_BASE + 0xa0) #define TX_ID_DWORD2 (PORT_BASE + 0xa4) @@ -124,6 +126,9 @@ #define TX_ID_DWORD4 (PORT_BASE + 0xaC) #define TX_ID_DWORD5 (PORT_BASE + 0xb0) #define TX_ID_DWORD6 (PORT_BASE + 0xb4) +#define TXID_AUTO (PORT_BASE + 0xb8) +#define TXID_AUTO_CT3_OFF 1 +#define TXID_AUTO_CT3_MSK (0x1 << TXID_AUTO_CT3_OFF) #define RX_IDAF_DWORD0 (PORT_BASE + 0xc4) #define RX_IDAF_DWORD1 (PORT_BASE + 0xc8) #define RX_IDAF_DWORD2 (PORT_BASE + 0xcc) @@ -174,6 +179,10 @@ /* HW dma structures */ /* Delivery queue header */ /* dw0 */ +#define CMD_HDR_ABORT_FLAG_OFF 0 +#define CMD_HDR_ABORT_FLAG_MSK (0x3 << CMD_HDR_ABORT_FLAG_OFF) +#define CMD_HDR_ABORT_DEVICE_TYPE_OFF 2 +#define CMD_HDR_ABORT_DEVICE_TYPE_MSK (0x1 << CMD_HDR_ABORT_DEVICE_TYPE_OFF) #define CMD_HDR_RESP_REPORT_OFF 5 #define CMD_HDR_RESP_REPORT_MSK (0x1 << CMD_HDR_RESP_REPORT_OFF) #define CMD_HDR_TLR_CTRL_OFF 6 @@ -214,6 +223,8 @@ #define CMD_HDR_DIF_SGL_LEN_MSK (0xffff << CMD_HDR_DIF_SGL_LEN_OFF) #define CMD_HDR_DATA_SGL_LEN_OFF 16 #define CMD_HDR_DATA_SGL_LEN_MSK (0xffff << CMD_HDR_DATA_SGL_LEN_OFF) +#define CMD_HDR_ABORT_IPTT_OFF 16 +#define CMD_HDR_ABORT_IPTT_MSK (0xffff << CMD_HDR_ABORT_IPTT_OFF) /* Completion header */ /* dw0 */ @@ -221,6 +232,13 @@ #define CMPLT_HDR_RSPNS_XFRD_MSK (0x1 << CMPLT_HDR_RSPNS_XFRD_OFF) #define CMPLT_HDR_ERX_OFF 12 #define CMPLT_HDR_ERX_MSK (0x1 << CMPLT_HDR_ERX_OFF) +#define CMPLT_HDR_ABORT_STAT_OFF 13 +#define CMPLT_HDR_ABORT_STAT_MSK (0x7 << CMPLT_HDR_ABORT_STAT_OFF) +/* abort_stat */ +#define STAT_IO_NOT_VALID 0x1 +#define STAT_IO_NO_DEVICE 0x2 +#define STAT_IO_COMPLETE 0x3 +#define STAT_IO_ABORTED 0x4 /* dw1 */ #define CMPLT_HDR_IPTT_OFF 0 #define CMPLT_HDR_IPTT_MSK (0xffff << CMPLT_HDR_IPTT_OFF) @@ -549,25 +567,17 @@ static void config_id_frame_v2_hw(struct hisi_hba *hisi_hba, int phy_no) hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD0, __swab32(identify_buffer[0])); hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD1, - identify_buffer[2]); + __swab32(identify_buffer[1])); hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD2, - identify_buffer[1]); + __swab32(identify_buffer[2])); hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD3, - identify_buffer[4]); + __swab32(identify_buffer[3])); hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD4, - identify_buffer[3]); + __swab32(identify_buffer[4])); hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD5, __swab32(identify_buffer[5])); } -static void init_id_frame_v2_hw(struct hisi_hba *hisi_hba) -{ - int i; - - for (i = 0; i < hisi_hba->n_phy; i++) - config_id_frame_v2_hw(hisi_hba, i); -} - static void setup_itct_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_device *sas_dev) { @@ -589,6 +599,7 @@ static void setup_itct_v2_hw(struct hisi_hba *hisi_hba, qw0 = HISI_SAS_DEV_TYPE_SSP << ITCT_HDR_DEV_TYPE_OFF; break; case SAS_SATA_DEV: + case SAS_SATA_PENDING: if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type)) qw0 = HISI_SAS_DEV_TYPE_STP << ITCT_HDR_DEV_TYPE_OFF; else @@ -672,9 +683,7 @@ static int reset_hw_v2_hw(struct hisi_hba *hisi_hba) else reset_val = 0x7ffff; - /* Disable all of the DQ */ - for (i = 0; i < HISI_SAS_MAX_QUEUES; i++) - hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE, 0); + hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE, 0); /* Disable all of the PHYs */ for (i = 0; i < hisi_hba->n_phy; i++) { @@ -810,6 +819,8 @@ static void init_reg_v2_hw(struct hisi_hba *hisi_hba) hisi_sas_phy_write32(hisi_hba, i, PROG_PHY_LINK_RATE, 0x855); hisi_sas_phy_write32(hisi_hba, i, SAS_PHY_CTRL, 0x30b9908); hisi_sas_phy_write32(hisi_hba, i, SL_TOUT_CFG, 0x7d7d7d7d); + hisi_sas_phy_write32(hisi_hba, i, SL_CONTROL, 0x0); + hisi_sas_phy_write32(hisi_hba, i, TXID_AUTO, 0x2); hisi_sas_phy_write32(hisi_hba, i, DONE_RECEIVED_TIME, 0x10); hisi_sas_phy_write32(hisi_hba, i, CHL_INT0, 0xffffffff); hisi_sas_phy_write32(hisi_hba, i, CHL_INT1, 0xffffffff); @@ -901,8 +912,6 @@ static int hw_init_v2_hw(struct hisi_hba *hisi_hba) msleep(100); init_reg_v2_hw(hisi_hba); - init_id_frame_v2_hw(hisi_hba); - return 0; } @@ -952,14 +961,8 @@ static void start_phys_v2_hw(unsigned long data) static void phys_init_v2_hw(struct hisi_hba *hisi_hba) { - int i; struct timer_list *timer = &hisi_hba->timer; - for (i = 0; i < hisi_hba->n_phy; i++) { - hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0x6a); - hisi_sas_phy_read32(hisi_hba, i, CHL_INT2_MSK); - } - setup_timer(timer, start_phys_v2_hw, (unsigned long)hisi_hba); mod_timer(timer, jiffies + HZ); } @@ -1010,12 +1013,13 @@ static int get_wideport_bitmap_v2_hw(struct hisi_hba *hisi_hba, int port_id) static int get_free_slot_v2_hw(struct hisi_hba *hisi_hba, int *q, int *s) { struct device *dev = &hisi_hba->pdev->dev; + struct hisi_sas_dq *dq; u32 r, w; int queue = hisi_hba->queue; while (1) { - w = hisi_sas_read32_relaxed(hisi_hba, - DLVRY_Q_0_WR_PTR + (queue * 0x14)); + dq = &hisi_hba->dq[queue]; + w = dq->wr_point; r = hisi_sas_read32_relaxed(hisi_hba, DLVRY_Q_0_RD_PTR + (queue * 0x14)); if (r == (w+1) % HISI_SAS_QUEUE_SLOTS) { @@ -1038,9 +1042,11 @@ static void start_delivery_v2_hw(struct hisi_hba *hisi_hba) { int dlvry_queue = hisi_hba->slot_prep->dlvry_queue; int dlvry_queue_slot = hisi_hba->slot_prep->dlvry_queue_slot; + struct hisi_sas_dq *dq = &hisi_hba->dq[dlvry_queue]; + dq->wr_point = ++dlvry_queue_slot % HISI_SAS_QUEUE_SLOTS; hisi_sas_write32(hisi_hba, DLVRY_Q_0_WR_PTR + (dlvry_queue * 0x14), - ++dlvry_queue_slot % HISI_SAS_QUEUE_SLOTS); + dq->wr_point); } static int prep_prd_sge_v2_hw(struct hisi_hba *hisi_hba, @@ -1563,6 +1569,30 @@ slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot, goto out; } + /* Use SAS+TMF status codes */ + switch ((complete_hdr->dw0 & CMPLT_HDR_ABORT_STAT_MSK) + >> CMPLT_HDR_ABORT_STAT_OFF) { + case STAT_IO_ABORTED: + /* this io has been aborted by abort command */ + ts->stat = SAS_ABORTED_TASK; + goto out; + case STAT_IO_COMPLETE: + /* internal abort command complete */ + ts->stat = TMF_RESP_FUNC_COMPLETE; + goto out; + case STAT_IO_NO_DEVICE: + ts->stat = TMF_RESP_FUNC_COMPLETE; + goto out; + case STAT_IO_NOT_VALID: + /* abort single io, controller don't find + * the io need to abort + */ + ts->stat = TMF_RESP_FUNC_FAILED; + goto out; + default: + break; + } + if ((complete_hdr->dw0 & CMPLT_HDR_ERX_MSK) && (!(complete_hdr->dw0 & CMPLT_HDR_RSPNS_XFRD_MSK))) { @@ -1775,6 +1805,32 @@ static int prep_ata_v2_hw(struct hisi_hba *hisi_hba, return 0; } +static int prep_abort_v2_hw(struct hisi_hba *hisi_hba, + struct hisi_sas_slot *slot, + int device_id, int abort_flag, int tag_to_abort) +{ + struct sas_task *task = slot->task; + struct domain_device *dev = task->dev; + struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr; + struct hisi_sas_port *port = slot->port; + + /* dw0 */ + hdr->dw0 = cpu_to_le32((5 << CMD_HDR_CMD_OFF) | /*abort*/ + (port->id << CMD_HDR_PORT_OFF) | + ((dev_is_sata(dev) ? 1:0) << + CMD_HDR_ABORT_DEVICE_TYPE_OFF) | + (abort_flag << CMD_HDR_ABORT_FLAG_OFF)); + + /* dw1 */ + hdr->dw1 = cpu_to_le32(device_id << CMD_HDR_DEV_ID_OFF); + + /* dw7 */ + hdr->dw7 = cpu_to_le32(tag_to_abort << CMD_HDR_ABORT_IPTT_OFF); + hdr->transfer_tags = cpu_to_le32(slot->idx); + + return 0; +} + static int phy_up_v2_hw(int phy_no, struct hisi_hba *hisi_hba) { int i, res = 0; @@ -1818,9 +1874,6 @@ static int phy_up_v2_hw(int phy_no, struct hisi_hba *hisi_hba) frame_rcvd[i] = __swab32(idaf); } - /* Get the linkrates */ - link_rate = hisi_sas_read32(hisi_hba, PHY_CONN_RATE); - link_rate = (link_rate >> (phy_no * 4)) & 0xf; sas_phy->linkrate = link_rate; hard_phy_linkrate = hisi_sas_phy_read32(hisi_hba, phy_no, HARD_PHY_LINKRATE); @@ -1855,16 +1908,21 @@ end: static int phy_down_v2_hw(int phy_no, struct hisi_hba *hisi_hba) { int res = 0; - u32 phy_cfg, phy_state; + u32 phy_state, sl_ctrl, txid_auto; hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_NOT_RDY_MSK, 1); - phy_cfg = hisi_sas_phy_read32(hisi_hba, phy_no, PHY_CFG); - phy_state = hisi_sas_read32(hisi_hba, PHY_STATE); - hisi_sas_phy_down(hisi_hba, phy_no, (phy_state & 1 << phy_no) ? 1 : 0); + sl_ctrl = hisi_sas_phy_read32(hisi_hba, phy_no, SL_CONTROL); + hisi_sas_phy_write32(hisi_hba, phy_no, SL_CONTROL, + sl_ctrl & ~SL_CONTROL_CTA_MSK); + + txid_auto = hisi_sas_phy_read32(hisi_hba, phy_no, TXID_AUTO); + hisi_sas_phy_write32(hisi_hba, phy_no, TXID_AUTO, + txid_auto | TXID_AUTO_CT3_MSK); + hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0, CHL_INT0_NOT_RDY_MSK); hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_NOT_RDY_MSK, 0); @@ -1986,7 +2044,7 @@ static irqreturn_t cq_interrupt_v2_hw(int irq_no, void *p) struct hisi_sas_slot *slot; struct hisi_sas_itct *itct; struct hisi_sas_complete_v2_hdr *complete_queue; - u32 irq_value, rd_point, wr_point, dev_id; + u32 irq_value, rd_point = cq->rd_point, wr_point, dev_id; int queue = cq->id; complete_queue = hisi_hba->complete_hdr[queue]; @@ -1994,8 +2052,6 @@ static irqreturn_t cq_interrupt_v2_hw(int irq_no, void *p) hisi_sas_write32(hisi_hba, OQ_INT_SRC, 1 << queue); - rd_point = hisi_sas_read32(hisi_hba, COMPL_Q_0_RD_PTR + - (0x14 * queue)); wr_point = hisi_sas_read32(hisi_hba, COMPL_Q_0_WR_PTR + (0x14 * queue)); @@ -2043,6 +2099,7 @@ static irqreturn_t cq_interrupt_v2_hw(int irq_no, void *p) } /* update rd_point */ + cq->rd_point = rd_point; hisi_sas_write32(hisi_hba, COMPL_Q_0_RD_PTR + (0x14 * queue), rd_point); return IRQ_HANDLED; } @@ -2239,6 +2296,7 @@ static const struct hisi_sas_hw hisi_sas_v2_hw = { .prep_smp = prep_smp_v2_hw, .prep_ssp = prep_ssp_v2_hw, .prep_stp = prep_ata_v2_hw, + .prep_abort = prep_abort_v2_hw, .get_free_slot = get_free_slot_v2_hw, .start_delivery = start_delivery_v2_hw, .slot_complete = slot_complete_v2_hw, |