diff options
Diffstat (limited to 'drivers/scsi/hisi_sas/hisi_sas_main.c')
-rw-r--r-- | drivers/scsi/hisi_sas/hisi_sas_main.c | 136 |
1 files changed, 98 insertions, 38 deletions
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 99b1950d751c..097ab4f27a6b 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -12,13 +12,12 @@ #include "hisi_sas.h" #define DRV_NAME "hisi_sas" -#define DEV_IS_EXPANDER(type) \ - ((type == SAS_EDGE_EXPANDER_DEVICE) || \ - (type == SAS_FANOUT_EXPANDER_DEVICE)) - #define DEV_IS_GONE(dev) \ ((!dev) || (dev->dev_type == SAS_PHY_UNUSED)) +static int hisi_sas_debug_issue_ssp_tmf(struct domain_device *device, + u8 *lun, struct hisi_sas_tmf_task *tmf); + static struct hisi_hba *dev_to_hisi_hba(struct domain_device *device) { return device->port->ha->lldd_ha; @@ -111,6 +110,50 @@ static int hisi_sas_task_prep_ssp(struct hisi_hba *hisi_hba, return hisi_hba->hw->prep_ssp(hisi_hba, slot, is_tmf, tmf); } +static int hisi_sas_task_prep_ata(struct hisi_hba *hisi_hba, + struct hisi_sas_slot *slot) +{ + return hisi_hba->hw->prep_stp(hisi_hba, slot); +} + +/* + * 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 + * cleanup and callbacks. + */ +static void hisi_sas_slot_abort(struct work_struct *work) +{ + struct hisi_sas_slot *abort_slot = + container_of(work, struct hisi_sas_slot, abort_slot); + struct sas_task *task = abort_slot->task; + struct hisi_hba *hisi_hba = dev_to_hisi_hba(task->dev); + struct scsi_cmnd *cmnd = task->uldd_task; + struct hisi_sas_tmf_task tmf_task; + struct domain_device *device = task->dev; + struct hisi_sas_device *sas_dev = device->lldd_dev; + struct scsi_lun lun; + struct device *dev = &hisi_hba->pdev->dev; + int tag = abort_slot->idx; + + if (!(task->task_proto & SAS_PROTOCOL_SSP)) { + dev_err(dev, "cannot abort slot for non-ssp task\n"); + goto out; + } + + int_to_scsilun(cmnd->device->lun, &lun); + tmf_task.tmf = TMF_ABORT_TASK; + tmf_task.tag_of_task_to_be_managed = cpu_to_le16(tag); + + hisi_sas_debug_issue_ssp_tmf(task->dev, lun.scsi_lun, &tmf_task); +out: + /* Do cleanup for this task */ + hisi_sas_slot_task_free(hisi_hba, task, abort_slot); + if (task->task_done) + task->task_done(task); + if (sas_dev && sas_dev->running_req) + sas_dev->running_req--; +} + static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba, int is_tmf, struct hisi_sas_tmf_task *tmf, int *pass) @@ -204,6 +247,7 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba, slot->task = task; slot->port = port; task->lldd_task = slot; + INIT_WORK(&slot->abort_slot, hisi_sas_slot_abort); slot->status_buffer = dma_pool_alloc(hisi_hba->status_buffer_pool, GFP_ATOMIC, @@ -234,6 +278,8 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba, case SAS_PROTOCOL_SATA: case SAS_PROTOCOL_STP: case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: + rc = hisi_sas_task_prep_ata(hisi_hba, slot); + break; default: dev_err(dev, "task prep: unknown/unsupported proto (0x%x)\n", task->task_proto); @@ -407,6 +453,19 @@ static int hisi_sas_dev_found(struct domain_device *device) return 0; } +static int hisi_sas_slave_configure(struct scsi_device *sdev) +{ + struct domain_device *dev = sdev_to_domain_dev(sdev); + int ret = sas_slave_configure(sdev); + + if (ret) + return ret; + if (!dev_is_sata(dev)) + sas_change_queue_depth(sdev, 64); + + return 0; +} + static void hisi_sas_scan_start(struct Scsi_Host *shost) { struct hisi_hba *hisi_hba = shost_priv(shost); @@ -657,7 +716,7 @@ static int hisi_sas_exec_internal_tmf_task(struct domain_device *device, } if (task->task_status.resp == SAS_TASK_COMPLETE && - task->task_status.stat == SAM_STAT_GOOD) { + task->task_status.stat == TMF_RESP_FUNC_COMPLETE) { res = TMF_RESP_FUNC_COMPLETE; break; } @@ -944,7 +1003,7 @@ static struct scsi_host_template hisi_sas_sht = { .name = DRV_NAME, .queuecommand = sas_queuecommand, .target_alloc = sas_target_alloc, - .slave_configure = sas_slave_configure, + .slave_configure = hisi_sas_slave_configure, .scan_finished = hisi_sas_scan_finished, .scan_start = hisi_sas_scan_start, .change_queue_depth = sas_change_queue_depth, @@ -977,9 +1036,9 @@ static struct sas_domain_function_template hisi_sas_transport_ops = { static int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost) { - int i, s; struct platform_device *pdev = hisi_hba->pdev; struct device *dev = &pdev->dev; + int i, s, max_command_entries = hisi_hba->hw->max_command_entries; spin_lock_init(&hisi_hba->lock); for (i = 0; i < hisi_hba->n_phy; i++) { @@ -1039,13 +1098,13 @@ static int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost) memset(hisi_hba->itct, 0, s); - hisi_hba->slot_info = devm_kcalloc(dev, HISI_SAS_COMMAND_ENTRIES, + hisi_hba->slot_info = devm_kcalloc(dev, max_command_entries, sizeof(struct hisi_sas_slot), GFP_KERNEL); if (!hisi_hba->slot_info) goto err_out; - s = HISI_SAS_COMMAND_ENTRIES * sizeof(struct hisi_sas_iost); + s = max_command_entries * sizeof(struct hisi_sas_iost); hisi_hba->iost = dma_alloc_coherent(dev, s, &hisi_hba->iost_dma, GFP_KERNEL); if (!hisi_hba->iost) @@ -1053,7 +1112,7 @@ static int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost) memset(hisi_hba->iost, 0, s); - s = HISI_SAS_COMMAND_ENTRIES * sizeof(struct hisi_sas_breakpoint); + s = max_command_entries * sizeof(struct hisi_sas_breakpoint); hisi_hba->breakpoint = dma_alloc_coherent(dev, s, &hisi_hba->breakpoint_dma, GFP_KERNEL); if (!hisi_hba->breakpoint) @@ -1061,7 +1120,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 = HISI_SAS_COMMAND_ENTRIES; + hisi_hba->slot_index_count = max_command_entries; s = hisi_hba->slot_index_count / sizeof(unsigned long); hisi_hba->slot_index_tags = devm_kzalloc(dev, s, GFP_KERNEL); if (!hisi_hba->slot_index_tags) @@ -1079,7 +1138,7 @@ static int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost) goto err_out; memset(hisi_hba->initial_fis, 0, s); - s = HISI_SAS_COMMAND_ENTRIES * sizeof(struct hisi_sas_breakpoint) * 2; + s = max_command_entries * sizeof(struct hisi_sas_breakpoint) * 2; hisi_hba->sata_breakpoint = dma_alloc_coherent(dev, s, &hisi_hba->sata_breakpoint_dma, GFP_KERNEL); if (!hisi_hba->sata_breakpoint) @@ -1102,7 +1161,7 @@ err_out: static void hisi_sas_free(struct hisi_hba *hisi_hba) { struct device *dev = &hisi_hba->pdev->dev; - int i, s; + int i, s, max_command_entries = hisi_hba->hw->max_command_entries; for (i = 0; i < hisi_hba->queue_count; i++) { s = sizeof(struct hisi_sas_cmd_hdr) * HISI_SAS_QUEUE_SLOTS; @@ -1127,12 +1186,12 @@ static void hisi_sas_free(struct hisi_hba *hisi_hba) dma_free_coherent(dev, s, hisi_hba->itct, hisi_hba->itct_dma); - s = HISI_SAS_COMMAND_ENTRIES * sizeof(struct hisi_sas_iost); + s = max_command_entries * sizeof(struct hisi_sas_iost); if (hisi_hba->iost) dma_free_coherent(dev, s, hisi_hba->iost, hisi_hba->iost_dma); - s = HISI_SAS_COMMAND_ENTRIES * sizeof(struct hisi_sas_breakpoint); + s = max_command_entries * sizeof(struct hisi_sas_breakpoint); if (hisi_hba->breakpoint) dma_free_coherent(dev, s, hisi_hba->breakpoint, @@ -1145,7 +1204,7 @@ static void hisi_sas_free(struct hisi_hba *hisi_hba) hisi_hba->initial_fis, hisi_hba->initial_fis_dma); - s = HISI_SAS_COMMAND_ENTRIES * sizeof(struct hisi_sas_breakpoint) * 2; + s = max_command_entries * sizeof(struct hisi_sas_breakpoint) * 2; if (hisi_hba->sata_breakpoint) dma_free_coherent(dev, s, hisi_hba->sata_breakpoint, @@ -1163,7 +1222,6 @@ static struct Scsi_Host *hisi_sas_shost_alloc(struct platform_device *pdev, struct hisi_hba *hisi_hba; struct device *dev = &pdev->dev; struct device_node *np = pdev->dev.of_node; - struct property *sas_addr_prop; shost = scsi_host_alloc(&hisi_sas_sht, sizeof(*hisi_hba)); if (!shost) @@ -1177,27 +1235,34 @@ static struct Scsi_Host *hisi_sas_shost_alloc(struct platform_device *pdev, init_timer(&hisi_hba->timer); - sas_addr_prop = of_find_property(np, "sas-addr", NULL); - if (!sas_addr_prop || (sas_addr_prop->length != SAS_ADDR_SIZE)) + if (device_property_read_u8_array(dev, "sas-addr", hisi_hba->sas_addr, + SAS_ADDR_SIZE)) goto err_out; - memcpy(hisi_hba->sas_addr, sas_addr_prop->value, SAS_ADDR_SIZE); - if (of_property_read_u32(np, "ctrl-reset-reg", - &hisi_hba->ctrl_reset_reg)) - goto err_out; + if (np) { + hisi_hba->ctrl = syscon_regmap_lookup_by_phandle(np, + "hisilicon,sas-syscon"); + if (IS_ERR(hisi_hba->ctrl)) + goto err_out; - if (of_property_read_u32(np, "ctrl-reset-sts-reg", - &hisi_hba->ctrl_reset_sts_reg)) - goto err_out; + if (device_property_read_u32(dev, "ctrl-reset-reg", + &hisi_hba->ctrl_reset_reg)) + goto err_out; - if (of_property_read_u32(np, "ctrl-clock-ena-reg", - &hisi_hba->ctrl_clock_ena_reg)) - goto err_out; + if (device_property_read_u32(dev, "ctrl-reset-sts-reg", + &hisi_hba->ctrl_reset_sts_reg)) + goto err_out; - if (of_property_read_u32(np, "phy-count", &hisi_hba->n_phy)) + if (device_property_read_u32(dev, "ctrl-clock-ena-reg", + &hisi_hba->ctrl_clock_ena_reg)) + goto err_out; + } + + if (device_property_read_u32(dev, "phy-count", &hisi_hba->n_phy)) goto err_out; - if (of_property_read_u32(np, "queue-count", &hisi_hba->queue_count)) + if (device_property_read_u32(dev, "queue-count", + &hisi_hba->queue_count)) goto err_out; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -1205,11 +1270,6 @@ static struct Scsi_Host *hisi_sas_shost_alloc(struct platform_device *pdev, if (IS_ERR(hisi_hba->regs)) goto err_out; - hisi_hba->ctrl = syscon_regmap_lookup_by_phandle( - np, "hisilicon,sas-syscon"); - if (IS_ERR(hisi_hba->ctrl)) - goto err_out; - if (hisi_sas_alloc(hisi_hba, shost)) { hisi_sas_free(hisi_hba); goto err_out; @@ -1277,8 +1337,8 @@ int hisi_sas_probe(struct platform_device *pdev, shost->max_channel = 1; shost->max_cmd_len = 16; shost->sg_tablesize = min_t(u16, SG_ALL, HISI_SAS_SGE_PAGE_CNT); - shost->can_queue = HISI_SAS_COMMAND_ENTRIES; - shost->cmd_per_lun = HISI_SAS_COMMAND_ENTRIES; + shost->can_queue = hisi_hba->hw->max_command_entries; + shost->cmd_per_lun = hisi_hba->hw->max_command_entries; sha->sas_ha_name = DRV_NAME; sha->dev = &hisi_hba->pdev->dev; |