X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=drivers%2Fscsi%2Fhisi_sas%2Fhisi_sas_v2_hw.c;h=7b39c4d23328b5d00ac55cf91fead074821d9262;hb=a2d76b6ba7f59ade274a76a54e4ec027bd12da76;hp=e7e2829bbdccb32887887c0d4c2976e84e2e7046;hpb=52ed2bbab7bcce75268eca09277b5eebcf056cfb;p=mirror_ubuntu-bionic-kernel.git diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index e7e2829bbdcc..7b39c4d23328 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -144,6 +144,7 @@ #define SAS_ECC_INTR_NCQ_MEM3_ECC_1B_OFF 19 #define SAS_ECC_INTR_MSK 0x1ec #define HGC_ERR_STAT_EN 0x238 +#define CQE_SEND_CNT 0x248 #define DLVRY_Q_0_BASE_ADDR_LO 0x260 #define DLVRY_Q_0_BASE_ADDR_HI 0x264 #define DLVRY_Q_0_DEPTH 0x268 @@ -295,6 +296,10 @@ #define CMD_HDR_RESP_REPORT_MSK (0x1 << CMD_HDR_RESP_REPORT_OFF) #define CMD_HDR_TLR_CTRL_OFF 6 #define CMD_HDR_TLR_CTRL_MSK (0x3 << CMD_HDR_TLR_CTRL_OFF) +#define CMD_HDR_PHY_ID_OFF 8 +#define CMD_HDR_PHY_ID_MSK (0x1ff << CMD_HDR_PHY_ID_OFF) +#define CMD_HDR_FORCE_PHY_OFF 17 +#define CMD_HDR_FORCE_PHY_MSK (0x1 << CMD_HDR_FORCE_PHY_OFF) #define CMD_HDR_PORT_OFF 18 #define CMD_HDR_PORT_MSK (0xf << CMD_HDR_PORT_OFF) #define CMD_HDR_PRIORITY_OFF 27 @@ -1216,7 +1221,22 @@ static void init_reg_v2_hw(struct hisi_hba *hisi_hba) } for (i = 0; i < hisi_hba->n_phy; i++) { - hisi_sas_phy_write32(hisi_hba, i, PROG_PHY_LINK_RATE, 0x855); + struct hisi_sas_phy *phy = &hisi_hba->phy[i]; + struct asd_sas_phy *sas_phy = &phy->sas_phy; + u32 prog_phy_link_rate = 0x800; + + if (!sas_phy->phy || (sas_phy->phy->maximum_linkrate < + SAS_LINK_RATE_1_5_GBPS)) { + prog_phy_link_rate = 0x855; + } else { + enum sas_linkrate max = sas_phy->phy->maximum_linkrate; + + prog_phy_link_rate = + hisi_sas_get_prog_phy_linkrate_mask(max) | + 0x800; + } + hisi_sas_phy_write32(hisi_hba, i, PROG_PHY_LINK_RATE, + prog_phy_link_rate); hisi_sas_phy_write32(hisi_hba, i, SAS_PHY_CTRL, sas_phy_ctrl); hisi_sas_phy_write32(hisi_hba, i, SL_TOUT_CFG, 0x7d7d7d7d); hisi_sas_phy_write32(hisi_hba, i, SL_CONTROL, 0x0); @@ -1585,13 +1605,10 @@ static enum sas_linkrate phy_get_max_linkrate_v2_hw(void) static void phy_set_linkrate_v2_hw(struct hisi_hba *hisi_hba, int phy_no, struct sas_phy_linkrates *r) { - u32 prog_phy_link_rate = - hisi_sas_phy_read32(hisi_hba, phy_no, PROG_PHY_LINK_RATE); struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no]; struct asd_sas_phy *sas_phy = &phy->sas_phy; - int i; enum sas_linkrate min, max; - u32 rate_mask = 0; + u32 prog_phy_link_rate = 0x800; if (r->maximum_linkrate == SAS_LINK_RATE_UNKNOWN) { max = sas_phy->phy->maximum_linkrate; @@ -1604,14 +1621,7 @@ static void phy_set_linkrate_v2_hw(struct hisi_hba *hisi_hba, int phy_no, sas_phy->phy->maximum_linkrate = max; sas_phy->phy->minimum_linkrate = min; - - max -= SAS_LINK_RATE_1_5_GBPS; - - for (i = 0; i <= max; i++) - rate_mask |= 1 << (i * 2); - - prog_phy_link_rate &= ~0xff; - prog_phy_link_rate |= rate_mask; + prog_phy_link_rate |= hisi_sas_get_prog_phy_linkrate_mask(max); disable_phy_v2_hw(hisi_hba, phy_no); msleep(100); @@ -1658,42 +1668,55 @@ get_free_slot_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_dq *dq) r = hisi_sas_read32_relaxed(hisi_hba, DLVRY_Q_0_RD_PTR + (queue * 0x14)); if (r == (w+1) % HISI_SAS_QUEUE_SLOTS) { - dev_warn(dev, "full queue=%d r=%d w=%d\n\n", + dev_warn(dev, "full queue=%d r=%d w=%d\n", queue, r, w); return -EAGAIN; } - return 0; + dq->wr_point = (dq->wr_point + 1) % HISI_SAS_QUEUE_SLOTS; + + return w; } +/* DQ lock must be taken here */ static void start_delivery_v2_hw(struct hisi_sas_dq *dq) { struct hisi_hba *hisi_hba = dq->hisi_hba; - int dlvry_queue = dq->slot_prep->dlvry_queue; - int dlvry_queue_slot = dq->slot_prep->dlvry_queue_slot; + struct hisi_sas_slot *s, *s1, *s2 = NULL; + struct list_head *dq_list; + int dlvry_queue = dq->id; + int wp; + + dq_list = &dq->list; + list_for_each_entry_safe(s, s1, &dq->list, delivery) { + if (!s->ready) + break; + s2 = s; + list_del(&s->delivery); + } - 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); + if (!s2) + return; + + /* + * Ensure that memories for slots built on other CPUs is observed. + */ + smp_rmb(); + wp = (s2->dlvry_queue_slot + 1) % HISI_SAS_QUEUE_SLOTS; + + hisi_sas_write32(hisi_hba, DLVRY_Q_0_WR_PTR + (dlvry_queue * 0x14), wp); } -static int prep_prd_sge_v2_hw(struct hisi_hba *hisi_hba, +static void prep_prd_sge_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot, struct hisi_sas_cmd_hdr *hdr, struct scatterlist *scatter, int n_elem) { struct hisi_sas_sge_page *sge_page = hisi_sas_sge_addr_mem(slot); - struct device *dev = hisi_hba->dev; struct scatterlist *sg; int i; - if (n_elem > HISI_SAS_SGE_PAGE_CNT) { - dev_err(dev, "prd err: n_elem(%d) > HISI_SAS_SGE_PAGE_CNT", - n_elem); - return -EINVAL; - } - for_each_sg(scatter, sg, n_elem, i) { struct hisi_sas_sge *entry = &sge_page->sge[i]; @@ -1706,47 +1729,24 @@ static int prep_prd_sge_v2_hw(struct hisi_hba *hisi_hba, hdr->prd_table_addr = cpu_to_le64(hisi_sas_sge_addr_dma(slot)); hdr->sg_len = cpu_to_le32(n_elem << CMD_HDR_DATA_SGL_LEN_OFF); - - return 0; } -static int prep_smp_v2_hw(struct hisi_hba *hisi_hba, +static void prep_smp_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot) { struct sas_task *task = slot->task; struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr; struct domain_device *device = task->dev; - struct device *dev = hisi_hba->dev; struct hisi_sas_port *port = slot->port; - struct scatterlist *sg_req, *sg_resp; + struct scatterlist *sg_req; struct hisi_sas_device *sas_dev = device->lldd_dev; dma_addr_t req_dma_addr; - unsigned int req_len, resp_len; - int elem, rc; + unsigned int req_len; - /* - * DMA-map SMP request, response buffers - */ /* req */ sg_req = &task->smp_task.smp_req; - elem = dma_map_sg(dev, sg_req, 1, DMA_TO_DEVICE); - if (!elem) - return -ENOMEM; - req_len = sg_dma_len(sg_req); req_dma_addr = sg_dma_address(sg_req); - - /* resp */ - sg_resp = &task->smp_task.smp_resp; - elem = dma_map_sg(dev, sg_resp, 1, DMA_FROM_DEVICE); - if (!elem) { - rc = -ENOMEM; - goto err_out_req; - } - resp_len = sg_dma_len(sg_resp); - if ((req_len & 0x3) || (resp_len & 0x3)) { - rc = -EINVAL; - goto err_out_resp; - } + req_len = sg_dma_len(&task->smp_task.smp_req); /* create header */ /* dw0 */ @@ -1768,21 +1768,10 @@ static int prep_smp_v2_hw(struct hisi_hba *hisi_hba, hdr->cmd_table_addr = cpu_to_le64(req_dma_addr); hdr->sts_buffer_addr = cpu_to_le64(hisi_sas_status_buf_addr_dma(slot)); - - return 0; - -err_out_resp: - dma_unmap_sg(dev, &slot->task->smp_task.smp_resp, 1, - DMA_FROM_DEVICE); -err_out_req: - dma_unmap_sg(dev, &slot->task->smp_task.smp_req, 1, - DMA_TO_DEVICE); - return rc; } -static int prep_ssp_v2_hw(struct hisi_hba *hisi_hba, - struct hisi_sas_slot *slot, int is_tmf, - struct hisi_sas_tmf_task *tmf) +static void prep_ssp_v2_hw(struct hisi_hba *hisi_hba, + struct hisi_sas_slot *slot) { struct sas_task *task = slot->task; struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr; @@ -1791,7 +1780,8 @@ static int prep_ssp_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_port *port = slot->port; struct sas_ssp_task *ssp_task = &task->ssp_task; struct scsi_cmnd *scsi_cmnd = ssp_task->cmd; - int has_data = 0, rc, priority = is_tmf; + struct hisi_sas_tmf_task *tmf = slot->tmf; + int has_data = 0, priority = !!tmf; u8 *buf_cmd; u32 dw1 = 0, dw2 = 0; @@ -1802,7 +1792,7 @@ static int prep_ssp_v2_hw(struct hisi_hba *hisi_hba, (1 << CMD_HDR_CMD_OFF)); /* ssp */ dw1 = 1 << CMD_HDR_VDTL_OFF; - if (is_tmf) { + if (tmf) { dw1 |= 2 << CMD_HDR_FRAME_TYPE_OFF; dw1 |= DIR_NO_DATA << CMD_HDR_DIR_OFF; } else { @@ -1833,12 +1823,9 @@ static int prep_ssp_v2_hw(struct hisi_hba *hisi_hba, hdr->transfer_tags = cpu_to_le32(slot->idx); - if (has_data) { - rc = prep_prd_sge_v2_hw(hisi_hba, slot, hdr, task->scatter, + if (has_data) + prep_prd_sge_v2_hw(hisi_hba, slot, hdr, task->scatter, slot->n_elem); - if (rc) - return rc; - } hdr->data_transfer_len = cpu_to_le32(task->total_xfer_len); hdr->cmd_table_addr = cpu_to_le64(hisi_sas_cmd_hdr_addr_dma(slot)); @@ -1848,7 +1835,7 @@ static int prep_ssp_v2_hw(struct hisi_hba *hisi_hba, sizeof(struct ssp_frame_hdr); memcpy(buf_cmd, &task->ssp_task.LUN, 8); - if (!is_tmf) { + if (!tmf) { buf_cmd[9] = task->ssp_task.task_attr | (task->ssp_task.task_prio << 3); memcpy(buf_cmd + 12, task->ssp_task.cmd->cmnd, @@ -1867,8 +1854,6 @@ static int prep_ssp_v2_hw(struct hisi_hba *hisi_hba, break; } } - - return 0; } #define TRANS_TX_ERR 0 @@ -2380,18 +2365,21 @@ slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot) struct device *dev = hisi_hba->dev; struct task_status_struct *ts; struct domain_device *device; + struct sas_ha_struct *ha; enum exec_status sts; struct hisi_sas_complete_v2_hdr *complete_queue = hisi_hba->complete_hdr[slot->cmplt_queue]; struct hisi_sas_complete_v2_hdr *complete_hdr = &complete_queue[slot->cmplt_queue_slot]; unsigned long flags; + bool is_internal = slot->is_internal; if (unlikely(!task || !task->lldd_task || !task->dev)) return -EINVAL; ts = &task->task_status; device = task->dev; + ha = device->port->ha; sas_dev = device->lldd_dev; spin_lock_irqsave(&task->task_state_lock, flags); @@ -2523,13 +2511,24 @@ out: task->task_state_flags |= SAS_TASK_STATE_DONE; spin_unlock_irqrestore(&task->task_state_lock, flags); + if (!is_internal && (task->task_proto != SAS_PROTOCOL_SMP)) { + spin_lock_irqsave(&device->done_lock, flags); + if (test_bit(SAS_HA_FROZEN, &ha->state)) { + spin_unlock_irqrestore(&device->done_lock, flags); + dev_info(dev, "slot complete: task(%p) ignored\n ", + task); + return sts; + } + spin_unlock_irqrestore(&device->done_lock, flags); + } + if (task->task_done) task->task_done(task); return sts; } -static int prep_ata_v2_hw(struct hisi_hba *hisi_hba, +static void prep_ata_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot) { struct sas_task *task = slot->task; @@ -2539,8 +2538,9 @@ static int prep_ata_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr; struct asd_sas_port *sas_port = device->port; struct hisi_sas_port *port = to_hisi_sas_port(sas_port); + struct hisi_sas_tmf_task *tmf = slot->tmf; u8 *buf_cmd; - int has_data = 0, rc = 0, hdr_tag = 0; + int has_data = 0, hdr_tag = 0; u32 dw1 = 0, dw2 = 0; /* create header */ @@ -2551,6 +2551,12 @@ static int prep_ata_v2_hw(struct hisi_hba *hisi_hba, else hdr->dw0 |= cpu_to_le32(4 << CMD_HDR_CMD_OFF); + if (tmf && tmf->force_phy) { + hdr->dw0 |= CMD_HDR_FORCE_PHY_MSK; + hdr->dw0 |= cpu_to_le32((1 << tmf->phy_id) + << CMD_HDR_PHY_ID_OFF); + } + /* dw1 */ switch (task->data_dir) { case DMA_TO_DEVICE: @@ -2588,12 +2594,9 @@ static int prep_ata_v2_hw(struct hisi_hba *hisi_hba, /* dw3 */ hdr->transfer_tags = cpu_to_le32(slot->idx); - if (has_data) { - rc = prep_prd_sge_v2_hw(hisi_hba, slot, hdr, task->scatter, + if (has_data) + prep_prd_sge_v2_hw(hisi_hba, slot, hdr, task->scatter, slot->n_elem); - if (rc) - return rc; - } hdr->data_transfer_len = cpu_to_le32(task->total_xfer_len); hdr->cmd_table_addr = cpu_to_le64(hisi_sas_cmd_hdr_addr_dma(slot)); @@ -2605,8 +2608,6 @@ static int prep_ata_v2_hw(struct hisi_hba *hisi_hba, task->ata_task.fis.flags |= 0x80; /* C=1: update ATA cmd reg */ /* fill in command FIS */ memcpy(buf_cmd, &task->ata_task.fis, sizeof(struct host_to_dev_fis)); - - return 0; } static void hisi_sas_internal_abort_quirk_timeout(struct timer_list *t) @@ -2643,7 +2644,7 @@ static void hisi_sas_internal_abort_quirk_timeout(struct timer_list *t) } } -static int prep_abort_v2_hw(struct hisi_hba *hisi_hba, +static void prep_abort_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot, int device_id, int abort_flag, int tag_to_abort) { @@ -2671,8 +2672,6 @@ static int prep_abort_v2_hw(struct hisi_hba *hisi_hba, /* 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) @@ -2684,6 +2683,7 @@ static int phy_up_v2_hw(int phy_no, struct hisi_hba *hisi_hba) struct device *dev = hisi_hba->dev; u32 *frame_rcvd = (u32 *)sas_phy->frame_rcvd; struct sas_identify_frame *id = (struct sas_identify_frame *)frame_rcvd; + unsigned long flags; hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_PHY_ENA_MSK, 1); @@ -2736,6 +2736,12 @@ static int phy_up_v2_hw(int phy_no, struct hisi_hba *hisi_hba) set_link_timer_quirk(hisi_hba); } hisi_sas_notify_phy_event(phy, HISI_PHYE_PHY_UP); + spin_lock_irqsave(&phy->lock, flags); + if (phy->reset_completion) { + phy->in_reset = 0; + complete(phy->reset_completion); + } + spin_unlock_irqrestore(&phy->lock, flags); end: hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0, @@ -2856,7 +2862,8 @@ static void phy_bcast_v2_hw(int phy_no, struct hisi_hba *hisi_hba) hisi_sas_phy_write32(hisi_hba, phy_no, SL_RX_BCAST_CHK_MSK, 1); bcast_status = hisi_sas_phy_read32(hisi_hba, phy_no, RX_PRIMS_STATUS); - if (bcast_status & RX_BCAST_CHG_MSK) + if ((bcast_status & RX_BCAST_CHG_MSK) && + !test_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags)) sas_ha->notify_port_event(sas_phy, PORTE_BROADCAST_RCVD); hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0, CHL_INT0_SL_RX_BCST_ACK_MSK); @@ -3224,6 +3231,7 @@ static irqreturn_t sata_int_v2_hw(int irq_no, void *p) u32 ent_tmp, ent_msk, ent_int, port_id, link_rate, hard_phy_linkrate; irqreturn_t res = IRQ_HANDLED; u8 attached_sas_addr[SAS_ADDR_SIZE] = {0}; + unsigned long flags; int phy_no, offset; phy_no = sas_phy->id; @@ -3249,8 +3257,7 @@ static irqreturn_t sata_int_v2_hw(int irq_no, void *p) if (fis->status & ATA_ERR) { dev_warn(dev, "sata int: phy%d FIS status: 0x%x\n", phy_no, fis->status); - disable_phy_v2_hw(hisi_hba, phy_no); - enable_phy_v2_hw(hisi_hba, phy_no); + hisi_sas_notify_phy_event(phy, HISI_PHYE_LINK_RESET); res = IRQ_NONE; goto end; } @@ -3284,6 +3291,7 @@ static irqreturn_t sata_int_v2_hw(int irq_no, void *p) sas_phy->oob_mode = SATA_OOB_MODE; /* Make up some unique SAS address */ attached_sas_addr[0] = 0x50; + attached_sas_addr[6] = hisi_hba->shost->host_no; attached_sas_addr[7] = phy_no; memcpy(sas_phy->attached_sas_addr, attached_sas_addr, SAS_ADDR_SIZE); memcpy(sas_phy->frame_rcvd, fis, sizeof(struct dev_to_host_fis)); @@ -3297,6 +3305,12 @@ static irqreturn_t sata_int_v2_hw(int irq_no, void *p) phy->identify.target_port_protocols = SAS_PROTOCOL_SATA; hisi_sas_notify_phy_event(phy, HISI_PHYE_PHY_UP); + spin_lock_irqsave(&phy->lock, flags); + if (phy->reset_completion) { + phy->in_reset = 0; + complete(phy->reset_completion); + } + spin_unlock_irqrestore(&phy->lock, flags); end: hisi_sas_write32(hisi_hba, ENT_INT_SRC1 + offset, ent_tmp); hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK1 + offset, ent_msk); @@ -3535,6 +3549,46 @@ static int write_gpio_v2_hw(struct hisi_hba *hisi_hba, u8 reg_type, return 0; } +static void wait_cmds_complete_timeout_v2_hw(struct hisi_hba *hisi_hba, + int delay_ms, int timeout_ms) +{ + struct device *dev = hisi_hba->dev; + int entries, entries_old = 0, time; + + for (time = 0; time < timeout_ms; time += delay_ms) { + entries = hisi_sas_read32(hisi_hba, CQE_SEND_CNT); + if (entries == entries_old) + break; + + entries_old = entries; + msleep(delay_ms); + } + + dev_dbg(dev, "wait commands complete %dms\n", time); +} + +static struct scsi_host_template sht_v2_hw = { + .name = DRV_NAME, + .module = THIS_MODULE, + .queuecommand = sas_queuecommand, + .target_alloc = sas_target_alloc, + .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, + .bios_param = sas_bios_param, + .can_queue = 1, + .this_id = -1, + .sg_tablesize = SG_ALL, + .max_sectors = SCSI_DEFAULT_MAX_SECTORS, + .use_clustering = ENABLE_CLUSTERING, + .eh_device_reset_handler = sas_eh_device_reset_handler, + .eh_target_reset_handler = sas_eh_target_reset_handler, + .target_destroy = sas_target_destroy, + .ioctl = sas_ioctl, + .shost_attrs = host_attrs, +}; + static const struct hisi_sas_hw hisi_sas_v2_hw = { .hw_init = hisi_sas_v2_init, .setup_itct = setup_itct_v2_hw, @@ -3563,6 +3617,8 @@ static const struct hisi_sas_hw hisi_sas_v2_hw = { .soft_reset = soft_reset_v2_hw, .get_phys_state = get_phys_state_v2_hw, .write_gpio = write_gpio_v2_hw, + .wait_cmds_complete_timeout = wait_cmds_complete_timeout_v2_hw, + .sht = &sht_v2_hw, }; static int hisi_sas_v2_probe(struct platform_device *pdev)