From 22c70d1a9c639b432ffdf083bea44752ad9fc8f3 Mon Sep 17 00:00:00 2001 From: Elena Reshetova Date: Thu, 9 Mar 2017 09:44:02 +0200 Subject: scsi: libfc: convert fc_fcp_pkt.ref_cnt from atomic_t to refcount_t refcount_t type and corresponding API should be used instead of atomic_t when the variable is used as a reference counter. This allows to avoid accidental refcounter overflows that might lead to use-after-free situations. Signed-off-by: Elena Reshetova Signed-off-by: Hans Liljestrand Signed-off-by: Kees Cook Signed-off-by: David Windsor Acked-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/libfc/fc_fcp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c index 0e67621477a8..a808e8ef1d08 100644 --- a/drivers/scsi/libfc/fc_fcp.c +++ b/drivers/scsi/libfc/fc_fcp.c @@ -154,7 +154,7 @@ static struct fc_fcp_pkt *fc_fcp_pkt_alloc(struct fc_lport *lport, gfp_t gfp) memset(fsp, 0, sizeof(*fsp)); fsp->lp = lport; fsp->xfer_ddp = FC_XID_UNKNOWN; - atomic_set(&fsp->ref_cnt, 1); + refcount_set(&fsp->ref_cnt, 1); init_timer(&fsp->timer); fsp->timer.data = (unsigned long)fsp; INIT_LIST_HEAD(&fsp->list); @@ -175,7 +175,7 @@ static struct fc_fcp_pkt *fc_fcp_pkt_alloc(struct fc_lport *lport, gfp_t gfp) */ static void fc_fcp_pkt_release(struct fc_fcp_pkt *fsp) { - if (atomic_dec_and_test(&fsp->ref_cnt)) { + if (refcount_dec_and_test(&fsp->ref_cnt)) { struct fc_fcp_internal *si = fc_get_scsi_internal(fsp->lp); mempool_free(fsp, si->scsi_pkt_pool); @@ -188,7 +188,7 @@ static void fc_fcp_pkt_release(struct fc_fcp_pkt *fsp) */ static void fc_fcp_pkt_hold(struct fc_fcp_pkt *fsp) { - atomic_inc(&fsp->ref_cnt); + refcount_inc(&fsp->ref_cnt); } /** -- cgit v1.2.3 From 6dc618cdd6b896791313926becb1f86ede0e046a Mon Sep 17 00:00:00 2001 From: Elena Reshetova Date: Thu, 9 Mar 2017 13:46:58 +0200 Subject: scsi: libiscsi: qedi: convert iscsi_task.refcount from atomic_t to refcount_t refcount_t type and corresponding API should be used instead of atomic_t when the variable is used as a reference counter. This allows to avoid accidental refcounter overflows that might lead to use-after-free situations. Signed-off-by: Elena Reshetova Signed-off-by: Hans Liljestrand Signed-off-by: Kees Cook Signed-off-by: David Windsor Acked-by: Chris Leech Signed-off-by: Martin K. Petersen --- drivers/scsi/libiscsi.c | 8 ++++---- drivers/scsi/qedi/qedi_iscsi.c | 2 +- include/scsi/libiscsi.h | 3 ++- 3 files changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 07c08ce68d70..ec38a18c7fab 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -517,13 +517,13 @@ static void iscsi_free_task(struct iscsi_task *task) void __iscsi_get_task(struct iscsi_task *task) { - atomic_inc(&task->refcount); + refcount_inc(&task->refcount); } EXPORT_SYMBOL_GPL(__iscsi_get_task); void __iscsi_put_task(struct iscsi_task *task) { - if (atomic_dec_and_test(&task->refcount)) + if (refcount_dec_and_test(&task->refcount)) iscsi_free_task(task); } EXPORT_SYMBOL_GPL(__iscsi_put_task); @@ -745,7 +745,7 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, * released by the lld when it has transmitted the task for * pdus we do not expect a response for. */ - atomic_set(&task->refcount, 1); + refcount_set(&task->refcount, 1); task->conn = conn; task->sc = NULL; INIT_LIST_HEAD(&task->running); @@ -1617,7 +1617,7 @@ static inline struct iscsi_task *iscsi_alloc_task(struct iscsi_conn *conn, sc->SCp.phase = conn->session->age; sc->SCp.ptr = (char *) task; - atomic_set(&task->refcount, 1); + refcount_set(&task->refcount, 1); task->state = ISCSI_TASK_PENDING; task->conn = conn; task->sc = sc; diff --git a/drivers/scsi/qedi/qedi_iscsi.c b/drivers/scsi/qedi/qedi_iscsi.c index b9f79d36142d..3895bd555746 100644 --- a/drivers/scsi/qedi/qedi_iscsi.c +++ b/drivers/scsi/qedi/qedi_iscsi.c @@ -1372,7 +1372,7 @@ static void qedi_cleanup_task(struct iscsi_task *task) { if (!task->sc || task->state == ISCSI_TASK_PENDING) { QEDI_INFO(NULL, QEDI_LOG_IO, "Returning ref_cnt=%d\n", - atomic_read(&task->refcount)); + refcount_read(&task->refcount)); return; } diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h index b0e275de6dec..24d74b5bcb24 100644 --- a/include/scsi/libiscsi.h +++ b/include/scsi/libiscsi.h @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -139,7 +140,7 @@ struct iscsi_task { /* state set/tested under session->lock */ int state; - atomic_t refcount; + refcount_t refcount; struct list_head running; /* running cmd list */ void *dd_data; /* driver/transport data */ }; -- cgit v1.2.3 From d65702272c8d35afc8d7e85fa8100a914f0b787f Mon Sep 17 00:00:00 2001 From: Charles Date: Fri, 17 Feb 2017 10:51:34 +0800 Subject: scsi: stex: Support Pegasus 3 product Pegasus series is a RAID support product using Thunderbolt technology. The newest product, Pegasus 3(P3) supports Thunderbolt 3 technology with a different chip. 1. Change driver version. 2. Add P3 VID, DID and define it's device address. 3. P3 use msi interrupt, so stex_request_irq P3 type enable msi. 4. For hibernation, use msi_lock in stex_ss_handshake to prevent msi register write again when handshaking. 5. P3 doesn't need read() as flush. 6. In stex_ss_intr & stex_abort, P3 only clear interrupt register when getting vendor defined interrupt. Signed-off-by: Charles.Chiou Signed-off-by: Paul.Lyu Signed-off-by: Martin K. Petersen --- drivers/scsi/stex.c | 262 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 195 insertions(+), 67 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c index 5b23175a584c..e177dfe08939 100644 --- a/drivers/scsi/stex.c +++ b/drivers/scsi/stex.c @@ -38,9 +38,9 @@ #include #define DRV_NAME "stex" -#define ST_DRIVER_VERSION "5.00.0000.01" -#define ST_VER_MAJOR 5 -#define ST_VER_MINOR 00 +#define ST_DRIVER_VERSION "6.02.0000.01" +#define ST_VER_MAJOR 6 +#define ST_VER_MINOR 02 #define ST_OEM 0000 #define ST_BUILD_VER 01 @@ -64,6 +64,13 @@ enum { YI2H_INT_C = 0xa0, YH2I_REQ = 0xc0, YH2I_REQ_HI = 0xc4, + PSCRATCH0 = 0xb0, + PSCRATCH1 = 0xb4, + PSCRATCH2 = 0xb8, + PSCRATCH3 = 0xbc, + PSCRATCH4 = 0xc8, + MAILBOX_BASE = 0x1000, + MAILBOX_HNDSHK_STS = 0x0, /* MU register value */ MU_INBOUND_DOORBELL_HANDSHAKE = (1 << 0), @@ -87,7 +94,7 @@ enum { MU_STATE_STOP = 5, MU_STATE_NOCONNECT = 6, - MU_MAX_DELAY = 120, + MU_MAX_DELAY = 50, MU_HANDSHAKE_SIGNATURE = 0x55aaaa55, MU_HANDSHAKE_SIGNATURE_HALF = 0x5a5a0000, MU_HARD_RESET_WAIT = 30000, @@ -135,6 +142,7 @@ enum { st_yosemite = 2, st_seq = 3, st_yel = 4, + st_P3 = 5, PASSTHRU_REQ_TYPE = 0x00000001, PASSTHRU_REQ_NO_WAKEUP = 0x00000100, @@ -339,6 +347,7 @@ struct st_hba { u16 rq_size; u16 sts_count; u8 supports_pm; + int msi_lock; }; struct st_card_info { @@ -540,11 +549,15 @@ stex_ss_send_cmd(struct st_hba *hba, struct req_msg *req, u16 tag) ++hba->req_head; hba->req_head %= hba->rq_count+1; - - writel((addr >> 16) >> 16, hba->mmio_base + YH2I_REQ_HI); - readl(hba->mmio_base + YH2I_REQ_HI); /* flush */ - writel(addr, hba->mmio_base + YH2I_REQ); - readl(hba->mmio_base + YH2I_REQ); /* flush */ + if (hba->cardtype == st_P3) { + writel((addr >> 16) >> 16, hba->mmio_base + YH2I_REQ_HI); + writel(addr, hba->mmio_base + YH2I_REQ); + } else { + writel((addr >> 16) >> 16, hba->mmio_base + YH2I_REQ_HI); + readl(hba->mmio_base + YH2I_REQ_HI); /* flush */ + writel(addr, hba->mmio_base + YH2I_REQ); + readl(hba->mmio_base + YH2I_REQ); /* flush */ + } } static void return_abnormal_state(struct st_hba *hba, int status) @@ -974,15 +987,31 @@ static irqreturn_t stex_ss_intr(int irq, void *__hba) spin_lock_irqsave(hba->host->host_lock, flags); - data = readl(base + YI2H_INT); - if (data && data != 0xffffffff) { - /* clear the interrupt */ - writel(data, base + YI2H_INT_C); - stex_ss_mu_intr(hba); - spin_unlock_irqrestore(hba->host->host_lock, flags); - if (unlikely(data & SS_I2H_REQUEST_RESET)) - queue_work(hba->work_q, &hba->reset_work); - return IRQ_HANDLED; + if (hba->cardtype == st_yel) { + data = readl(base + YI2H_INT); + if (data && data != 0xffffffff) { + /* clear the interrupt */ + writel(data, base + YI2H_INT_C); + stex_ss_mu_intr(hba); + spin_unlock_irqrestore(hba->host->host_lock, flags); + if (unlikely(data & SS_I2H_REQUEST_RESET)) + queue_work(hba->work_q, &hba->reset_work); + return IRQ_HANDLED; + } + } else { + data = readl(base + PSCRATCH4); + if (data != 0xffffffff) { + if (data != 0) { + /* clear the interrupt */ + writel(data, base + PSCRATCH1); + writel((1 << 22), base + YH2I_INT); + } + stex_ss_mu_intr(hba); + spin_unlock_irqrestore(hba->host->host_lock, flags); + if (unlikely(data & SS_I2H_REQUEST_RESET)) + queue_work(hba->work_q, &hba->reset_work); + return IRQ_HANDLED; + } } spin_unlock_irqrestore(hba->host->host_lock, flags); @@ -1080,19 +1109,36 @@ static int stex_ss_handshake(struct st_hba *hba) struct st_msg_header *msg_h; struct handshake_frame *h; __le32 *scratch; - u32 data, scratch_size; + u32 data, scratch_size, mailboxdata, operationaldata; unsigned long before; int ret = 0; before = jiffies; - while ((readl(base + YIOA_STATUS) & SS_MU_OPERATIONAL) == 0) { - if (time_after(jiffies, before + MU_MAX_DELAY * HZ)) { - printk(KERN_ERR DRV_NAME - "(%s): firmware not operational\n", - pci_name(hba->pdev)); - return -1; + + if (hba->cardtype == st_yel) { + operationaldata = readl(base + YIOA_STATUS); + while (operationaldata != SS_MU_OPERATIONAL) { + if (time_after(jiffies, before + MU_MAX_DELAY * HZ)) { + printk(KERN_ERR DRV_NAME + "(%s): firmware not operational\n", + pci_name(hba->pdev)); + return -1; + } + msleep(1); + operationaldata = readl(base + YIOA_STATUS); + } + } else { + operationaldata = readl(base + PSCRATCH3); + while (operationaldata != SS_MU_OPERATIONAL) { + if (time_after(jiffies, before + MU_MAX_DELAY * HZ)) { + printk(KERN_ERR DRV_NAME + "(%s): firmware not operational\n", + pci_name(hba->pdev)); + return -1; + } + msleep(1); + operationaldata = readl(base + PSCRATCH3); } - msleep(1); } msg_h = (struct st_msg_header *)hba->dma_mem; @@ -1111,30 +1157,60 @@ static int stex_ss_handshake(struct st_hba *hba) scratch_size = (hba->sts_count+1)*sizeof(u32); h->scratch_size = cpu_to_le32(scratch_size); - data = readl(base + YINT_EN); - data &= ~4; - writel(data, base + YINT_EN); - writel((hba->dma_handle >> 16) >> 16, base + YH2I_REQ_HI); - readl(base + YH2I_REQ_HI); - writel(hba->dma_handle, base + YH2I_REQ); - readl(base + YH2I_REQ); /* flush */ + if (hba->cardtype == st_yel) { + data = readl(base + YINT_EN); + data &= ~4; + writel(data, base + YINT_EN); + writel((hba->dma_handle >> 16) >> 16, base + YH2I_REQ_HI); + readl(base + YH2I_REQ_HI); + writel(hba->dma_handle, base + YH2I_REQ); + readl(base + YH2I_REQ); /* flush */ + } else { + data = readl(base + YINT_EN); + data &= ~(1 << 0); + data &= ~(1 << 2); + writel(data, base + YINT_EN); + if (hba->msi_lock == 0) { + /* P3 MSI Register cannot access twice */ + writel((1 << 6), base + YH2I_INT); + hba->msi_lock = 1; + } + writel((hba->dma_handle >> 16) >> 16, base + YH2I_REQ_HI); + writel(hba->dma_handle, base + YH2I_REQ); + } - scratch = hba->scratch; before = jiffies; - while (!(le32_to_cpu(*scratch) & SS_STS_HANDSHAKE)) { - if (time_after(jiffies, before + MU_MAX_DELAY * HZ)) { - printk(KERN_ERR DRV_NAME - "(%s): no signature after handshake frame\n", - pci_name(hba->pdev)); - ret = -1; - break; + scratch = hba->scratch; + if (hba->cardtype == st_yel) { + while (!(le32_to_cpu(*scratch) & SS_STS_HANDSHAKE)) { + if (time_after(jiffies, before + MU_MAX_DELAY * HZ)) { + printk(KERN_ERR DRV_NAME + "(%s): no signature after handshake frame\n", + pci_name(hba->pdev)); + ret = -1; + break; + } + rmb(); + msleep(1); + } + } else { + mailboxdata = readl(base + MAILBOX_BASE + MAILBOX_HNDSHK_STS); + while (mailboxdata != SS_STS_HANDSHAKE) { + if (time_after(jiffies, before + MU_MAX_DELAY * HZ)) { + printk(KERN_ERR DRV_NAME + "(%s): no signature after handshake frame\n", + pci_name(hba->pdev)); + ret = -1; + break; + } + rmb(); + msleep(1); + mailboxdata = readl(base + MAILBOX_BASE + MAILBOX_HNDSHK_STS); } - rmb(); - msleep(1); } - memset(scratch, 0, scratch_size); msg_h->flag = 0; + return ret; } @@ -1144,8 +1220,10 @@ static int stex_handshake(struct st_hba *hba) unsigned long flags; unsigned int mu_status; - err = (hba->cardtype == st_yel) ? - stex_ss_handshake(hba) : stex_common_handshake(hba); + if (hba->cardtype == st_yel || hba->cardtype == st_P3) + err = stex_ss_handshake(hba); + else + err = stex_common_handshake(hba); spin_lock_irqsave(hba->host->host_lock, flags); mu_status = hba->mu_status; if (err == 0) { @@ -1190,6 +1268,15 @@ static int stex_abort(struct scsi_cmnd *cmd) writel(data, base + YI2H_INT_C); stex_ss_mu_intr(hba); + } else if (hba->cardtype == st_P3) { + data = readl(base + PSCRATCH4); + if (data == 0xffffffff) + goto fail_out; + if (data != 0) { + writel(data, base + PSCRATCH1); + writel((1 << 22), base + YH2I_INT); + } + stex_ss_mu_intr(hba); } else { data = readl(base + ODBL); if (data == 0 || data == 0xffffffff) @@ -1197,7 +1284,6 @@ static int stex_abort(struct scsi_cmnd *cmd) writel(data, base + ODBL); readl(base + ODBL); /* flush */ - stex_mu_intr(hba, data); } if (hba->wait_ccb == NULL) { @@ -1293,6 +1379,12 @@ static void stex_ss_reset(struct st_hba *hba) ssleep(5); } +static void stex_p3_reset(struct st_hba *hba) +{ + writel(SS_H2I_INT_RESET, hba->mmio_base + YH2I_INT); + ssleep(5); +} + static int stex_do_reset(struct st_hba *hba) { unsigned long flags; @@ -1329,7 +1421,8 @@ static int stex_do_reset(struct st_hba *hba) stex_hard_reset(hba); else if (hba->cardtype == st_yel) stex_ss_reset(hba); - + else if (hba->cardtype == st_P3) + stex_p3_reset(hba); return_abnormal_state(hba, DID_RESET); @@ -1414,6 +1507,26 @@ static struct pci_device_id stex_pci_tbl[] = { /* st_yel */ { 0x105a, 0x8650, 0x1033, PCI_ANY_ID, 0, 0, st_yel }, { 0x105a, 0x8760, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_yel }, + + /* st_P3, pluto */ + { PCI_VENDOR_ID_PROMISE, 0x8870, PCI_VENDOR_ID_PROMISE, + 0x8870, 0, 0, st_P3 }, + /* st_P3, p3 */ + { PCI_VENDOR_ID_PROMISE, 0x8870, PCI_VENDOR_ID_PROMISE, + 0x4300, 0, 0, st_P3 }, + + /* st_P3, SymplyStor4E */ + { PCI_VENDOR_ID_PROMISE, 0x8871, PCI_VENDOR_ID_PROMISE, + 0x4311, 0, 0, st_P3 }, + /* st_P3, SymplyStor8E */ + { PCI_VENDOR_ID_PROMISE, 0x8871, PCI_VENDOR_ID_PROMISE, + 0x4312, 0, 0, st_P3 }, + /* st_P3, SymplyStor4 */ + { PCI_VENDOR_ID_PROMISE, 0x8871, PCI_VENDOR_ID_PROMISE, + 0x4321, 0, 0, st_P3 }, + /* st_P3, SymplyStor8 */ + { PCI_VENDOR_ID_PROMISE, 0x8871, PCI_VENDOR_ID_PROMISE, + 0x4322, 0, 0, st_P3 }, { } /* terminate list */ }; @@ -1482,6 +1595,19 @@ static struct st_card_info stex_card_info[] = { .map_sg = stex_ss_map_sg, .send = stex_ss_send_cmd, }, + + /* st_P3 */ + { + .max_id = 129, + .max_lun = 256, + .max_channel = 0, + .rq_count = 801, + .rq_size = 512, + .sts_count = 801, + .alloc_rq = stex_ss_alloc_req, + .map_sg = stex_ss_map_sg, + .send = stex_ss_send_cmd, + }, }; static int stex_set_dma_mask(struct pci_dev * pdev) @@ -1502,7 +1628,7 @@ static int stex_request_irq(struct st_hba *hba) struct pci_dev *pdev = hba->pdev; int status; - if (msi) { + if (msi || hba->cardtype == st_P3) { status = pci_enable_msi(pdev); if (status != 0) printk(KERN_ERR DRV_NAME @@ -1513,7 +1639,8 @@ static int stex_request_irq(struct st_hba *hba) } else hba->msi_enabled = 0; - status = request_irq(pdev->irq, hba->cardtype == st_yel ? + status = request_irq(pdev->irq, + (hba->cardtype == st_yel || hba->cardtype == st_P3) ? stex_ss_intr : stex_intr, IRQF_SHARED, DRV_NAME, hba); if (status != 0) { @@ -1597,12 +1724,12 @@ static int stex_probe(struct pci_dev *pdev, const struct pci_device_id *id) case 0x4265: break; default: - if (hba->cardtype == st_yel) + if (hba->cardtype == st_yel || hba->cardtype == st_P3) hba->supports_pm = 1; } sts_offset = scratch_offset = (ci->rq_count+1) * ci->rq_size; - if (hba->cardtype == st_yel) + if (hba->cardtype == st_yel || hba->cardtype == st_P3) sts_offset += (ci->sts_count+1) * sizeof(u32); cp_offset = sts_offset + (ci->sts_count+1) * sizeof(struct status_msg); hba->dma_size = cp_offset + sizeof(struct st_frame); @@ -1642,7 +1769,7 @@ static int stex_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto out_pci_free; } - if (hba->cardtype == st_yel) + if (hba->cardtype == st_yel || hba->cardtype == st_P3) hba->scratch = (__le32 *)(hba->dma_mem + scratch_offset); hba->status_buffer = (struct status_msg *)(hba->dma_mem + sts_offset); hba->copy_buffer = hba->dma_mem + cp_offset; @@ -1653,8 +1780,9 @@ static int stex_probe(struct pci_dev *pdev, const struct pci_device_id *id) hba->map_sg = ci->map_sg; hba->send = ci->send; hba->mu_status = MU_STATE_STARTING; + hba->msi_lock = 0; - if (hba->cardtype == st_yel) + if (hba->cardtype == st_yel || hba->cardtype == st_P3) host->sg_tablesize = 38; else host->sg_tablesize = 32; @@ -1736,28 +1864,29 @@ static void stex_hba_stop(struct st_hba *hba, int st_sleep_mic) spin_lock_irqsave(hba->host->host_lock, flags); - if (hba->cardtype == st_yel && hba->supports_pm == 1) - { - if(st_sleep_mic == ST_NOTHANDLED) - { + if ((hba->cardtype == st_yel || hba->cardtype == st_P3) && + hba->supports_pm == 1) { + if (st_sleep_mic == ST_NOTHANDLED) { spin_unlock_irqrestore(hba->host->host_lock, flags); return; } } req = hba->alloc_rq(hba); - if (hba->cardtype == st_yel) { + if (hba->cardtype == st_yel || hba->cardtype == st_P3) { msg_h = (struct st_msg_header *)req - 1; memset(msg_h, 0, hba->rq_size); } else memset(req, 0, hba->rq_size); - if ((hba->cardtype == st_yosemite || hba->cardtype == st_yel) + if ((hba->cardtype == st_yosemite || hba->cardtype == st_yel + || hba->cardtype == st_P3) && st_sleep_mic == ST_IGNORED) { req->cdb[0] = MGT_CMD; req->cdb[1] = MGT_CMD_SIGNATURE; req->cdb[2] = CTLR_CONFIG_CMD; req->cdb[3] = CTLR_SHUTDOWN; - } else if (hba->cardtype == st_yel && st_sleep_mic != ST_IGNORED) { + } else if ((hba->cardtype == st_yel || hba->cardtype == st_P3) + && st_sleep_mic != ST_IGNORED) { req->cdb[0] = MGT_CMD; req->cdb[1] = MGT_CMD_SIGNATURE; req->cdb[2] = CTLR_CONFIG_CMD; @@ -1768,16 +1897,13 @@ static void stex_hba_stop(struct st_hba *hba, int st_sleep_mic) req->cdb[1] = CTLR_POWER_STATE_CHANGE; req->cdb[2] = CTLR_POWER_SAVING; } - hba->ccb[tag].cmd = NULL; hba->ccb[tag].sg_count = 0; hba->ccb[tag].sense_bufflen = 0; hba->ccb[tag].sense_buffer = NULL; hba->ccb[tag].req_type = PASSTHRU_REQ_TYPE; - hba->send(hba, req, tag); spin_unlock_irqrestore(hba->host->host_lock, flags); - before = jiffies; while (hba->ccb[tag].req_type & PASSTHRU_REQ_TYPE) { if (time_after(jiffies, before + ST_INTERNAL_TIMEOUT * HZ)) { @@ -1833,12 +1959,13 @@ static void stex_shutdown(struct pci_dev *pdev) stex_hba_stop(hba, ST_S5); } -static int stex_choice_sleep_mic(pm_message_t state) +static int stex_choice_sleep_mic(struct st_hba *hba, pm_message_t state) { switch (state.event) { case PM_EVENT_SUSPEND: return ST_S3; case PM_EVENT_HIBERNATE: + hba->msi_lock = 0; return ST_S4; default: return ST_NOTHANDLED; @@ -1849,8 +1976,9 @@ static int stex_suspend(struct pci_dev *pdev, pm_message_t state) { struct st_hba *hba = pci_get_drvdata(pdev); - if (hba->cardtype == st_yel && hba->supports_pm == 1) - stex_hba_stop(hba, stex_choice_sleep_mic(state)); + if ((hba->cardtype == st_yel || hba->cardtype == st_P3) + && hba->supports_pm == 1) + stex_hba_stop(hba, stex_choice_sleep_mic(hba, state)); else stex_hba_stop(hba, ST_IGNORED); return 0; -- cgit v1.2.3 From 61b745fa63dbac366104c3585c0866562a8292be Mon Sep 17 00:00:00 2001 From: Charles Date: Fri, 17 Feb 2017 10:52:38 +0800 Subject: scsi: stex: Add S6 support 1. Add reboot notifier and register it in stex_probe for all supported device. 2. For all supported device in restart flow, we get a callback from notifier and set S6flag for stex_shutdown & stex_hba_stop to send restart command to FW. Signed-off-by: Charles.Chiou Signed-off-by: Paul.Lyu Signed-off-by: Martin K. Petersen --- drivers/scsi/stex.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c index e177dfe08939..0751561b59da 100644 --- a/drivers/scsi/stex.c +++ b/drivers/scsi/stex.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -362,6 +363,12 @@ struct st_card_info { u16 sts_count; }; +int S6flag; +static int stex_halt(struct notifier_block *nb, ulong event, void *buf); +static struct notifier_block stex_notifier = { + stex_halt, NULL, 0 +}; + static int msi; module_param(msi, int, 0); MODULE_PARM_DESC(msi, "Enable Message Signaled Interrupts(0=off, 1=on)"); @@ -1673,6 +1680,9 @@ static int stex_probe(struct pci_dev *pdev, const struct pci_device_id *id) pci_set_master(pdev); + S6flag = 0; + register_reboot_notifier(&stex_notifier); + host = scsi_host_alloc(&driver_template, sizeof(struct st_hba)); if (!host) { @@ -1947,15 +1957,20 @@ static void stex_remove(struct pci_dev *pdev) scsi_host_put(hba->host); pci_disable_device(pdev); + + unregister_reboot_notifier(&stex_notifier); } static void stex_shutdown(struct pci_dev *pdev) { struct st_hba *hba = pci_get_drvdata(pdev); - if (hba->supports_pm == 0) + if (hba->supports_pm == 0) { stex_hba_stop(hba, ST_IGNORED); - else + } else if (hba->supports_pm == 1 && S6flag) { + unregister_reboot_notifier(&stex_notifier); + stex_hba_stop(hba, ST_S6); + } else stex_hba_stop(hba, ST_S5); } @@ -1992,6 +2007,12 @@ static int stex_resume(struct pci_dev *pdev) stex_handshake(hba); return 0; } + +static int stex_halt(struct notifier_block *nb, unsigned long event, void *buf) +{ + S6flag = 1; + return NOTIFY_OK; +} MODULE_DEVICE_TABLE(pci, stex_pci_tbl); static struct pci_driver stex_pci_driver = { -- cgit v1.2.3 From ba21222d00a450ce3bfced0e047f52470372634d Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 1 Mar 2017 17:38:38 -0800 Subject: scsi: remove incorrect __exit markups Even if bus is not hot-pluggable, devices can be unbound from the driver via sysfs, so we should not be using __exit annotations on remove() methods. The only exception is drivers registered with platform_driver_probe() which specifically disables sysfs bind/unbind attributes. Signed-off-by: Dmitry Torokhov Signed-off-by: Martin K. Petersen --- drivers/scsi/sgiwd93.c | 2 +- drivers/scsi/sni_53c710.c | 2 +- drivers/scsi/zalon.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/sgiwd93.c b/drivers/scsi/sgiwd93.c index 6d215e2fb46d..71b4b91d2215 100644 --- a/drivers/scsi/sgiwd93.c +++ b/drivers/scsi/sgiwd93.c @@ -297,7 +297,7 @@ out: return err; } -static int __exit sgiwd93_remove(struct platform_device *pdev) +static int sgiwd93_remove(struct platform_device *pdev) { struct Scsi_Host *host = platform_get_drvdata(pdev); struct ip22_hostdata *hdata = (struct ip22_hostdata *) host->hostdata; diff --git a/drivers/scsi/sni_53c710.c b/drivers/scsi/sni_53c710.c index 76278072147e..1f9a087daf69 100644 --- a/drivers/scsi/sni_53c710.c +++ b/drivers/scsi/sni_53c710.c @@ -117,7 +117,7 @@ static int snirm710_probe(struct platform_device *dev) return -ENODEV; } -static int __exit snirm710_driver_remove(struct platform_device *dev) +static int snirm710_driver_remove(struct platform_device *dev) { struct Scsi_Host *host = dev_get_drvdata(&dev->dev); struct NCR_700_Host_Parameters *hostdata = diff --git a/drivers/scsi/zalon.c b/drivers/scsi/zalon.c index 97ccb0383539..b2cf1faa819d 100644 --- a/drivers/scsi/zalon.c +++ b/drivers/scsi/zalon.c @@ -167,7 +167,7 @@ static struct parisc_device_id zalon_tbl[] = { MODULE_DEVICE_TABLE(parisc, zalon_tbl); -static int __exit zalon_remove(struct parisc_device *dev) +static int zalon_remove(struct parisc_device *dev) { struct Scsi_Host *host = dev_get_drvdata(&dev->dev); -- cgit v1.2.3 From 33bd712be7d2e3bd60262957052abc19c71c4765 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 15 Mar 2017 16:46:24 +0000 Subject: scsi: esas2r: Remove redundant NULL check on buffer Buffer is a pointer to the static char array event_buffer and therefore can never be null, so the check is redundant. Remove it. Detected by CoverityScan, CID#1077556 ("Logically Dead Code") Signed-off-by: Colin Ian King Acked-by: Bradley Grove Signed-off-by: Martin K. Petersen --- drivers/scsi/esas2r/esas2r_log.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/esas2r/esas2r_log.c b/drivers/scsi/esas2r/esas2r_log.c index a82030aa8577..65fdf22b0ba9 100644 --- a/drivers/scsi/esas2r/esas2r_log.c +++ b/drivers/scsi/esas2r/esas2r_log.c @@ -130,11 +130,6 @@ static int esas2r_log_master(const long level, spin_lock_irqsave(&event_buffer_lock, flags); - if (buffer == NULL) { - spin_unlock_irqrestore(&event_buffer_lock, flags); - return -1; - } - memset(buffer, 0, buflen); /* -- cgit v1.2.3 From cca678dfbad4954d53e58ca6b132b306c56f4423 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 1 Feb 2017 15:02:53 +0100 Subject: scsi: fnic: switch to pci_alloc_irq_vectors Not a full cleanup for the IRQ code, for that we'd need to know if the max number of the various CQ types is going to stay 1 forever. Signed-off-by: Christoph Hellwig Acked-by: Satish Kharat Signed-off-by: Martin K. Petersen --- drivers/scsi/fnic/fnic.h | 1 - drivers/scsi/fnic/fnic_isr.c | 41 +++++++++++++---------------------------- 2 files changed, 13 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/fnic/fnic.h b/drivers/scsi/fnic/fnic.h index 9e4b7709043e..7d5739e437d2 100644 --- a/drivers/scsi/fnic/fnic.h +++ b/drivers/scsi/fnic/fnic.h @@ -217,7 +217,6 @@ struct fnic { struct fcoe_ctlr ctlr; /* FIP FCoE controller structure */ struct vnic_dev_bar bar0; - struct msix_entry msix_entry[FNIC_MSIX_INTR_MAX]; struct fnic_msix_entry msix[FNIC_MSIX_INTR_MAX]; struct vnic_stats *stats; diff --git a/drivers/scsi/fnic/fnic_isr.c b/drivers/scsi/fnic/fnic_isr.c index a0dd1b67a467..4e3a50202e8c 100644 --- a/drivers/scsi/fnic/fnic_isr.c +++ b/drivers/scsi/fnic/fnic_isr.c @@ -154,13 +154,13 @@ void fnic_free_intr(struct fnic *fnic) switch (vnic_dev_get_intr_mode(fnic->vdev)) { case VNIC_DEV_INTR_MODE_INTX: case VNIC_DEV_INTR_MODE_MSI: - free_irq(fnic->pdev->irq, fnic); + free_irq(pci_irq_vector(fnic->pdev, 0), fnic); break; case VNIC_DEV_INTR_MODE_MSIX: for (i = 0; i < ARRAY_SIZE(fnic->msix); i++) if (fnic->msix[i].requested) - free_irq(fnic->msix_entry[i].vector, + free_irq(pci_irq_vector(fnic->pdev, i), fnic->msix[i].devid); break; @@ -177,12 +177,12 @@ int fnic_request_intr(struct fnic *fnic) switch (vnic_dev_get_intr_mode(fnic->vdev)) { case VNIC_DEV_INTR_MODE_INTX: - err = request_irq(fnic->pdev->irq, &fnic_isr_legacy, - IRQF_SHARED, DRV_NAME, fnic); + err = request_irq(pci_irq_vector(fnic->pdev, 0), + &fnic_isr_legacy, IRQF_SHARED, DRV_NAME, fnic); break; case VNIC_DEV_INTR_MODE_MSI: - err = request_irq(fnic->pdev->irq, &fnic_isr_msi, + err = request_irq(pci_irq_vector(fnic->pdev, 0), &fnic_isr_msi, 0, fnic->name, fnic); break; @@ -210,7 +210,7 @@ int fnic_request_intr(struct fnic *fnic) fnic->msix[FNIC_MSIX_ERR_NOTIFY].devid = fnic; for (i = 0; i < ARRAY_SIZE(fnic->msix); i++) { - err = request_irq(fnic->msix_entry[i].vector, + err = request_irq(pci_irq_vector(fnic->pdev, i), fnic->msix[i].isr, 0, fnic->msix[i].devname, fnic->msix[i].devid); @@ -237,7 +237,6 @@ int fnic_set_intr_mode(struct fnic *fnic) unsigned int n = ARRAY_SIZE(fnic->rq); unsigned int m = ARRAY_SIZE(fnic->wq); unsigned int o = ARRAY_SIZE(fnic->wq_copy); - unsigned int i; /* * Set interrupt mode (INTx, MSI, MSI-X) depending @@ -248,23 +247,20 @@ int fnic_set_intr_mode(struct fnic *fnic) * We need n RQs, m WQs, o Copy WQs, n+m+o CQs, and n+m+o+1 INTRs * (last INTR is used for WQ/RQ errors and notification area) */ - - BUG_ON(ARRAY_SIZE(fnic->msix_entry) < n + m + o + 1); - for (i = 0; i < n + m + o + 1; i++) - fnic->msix_entry[i].entry = i; - if (fnic->rq_count >= n && fnic->raw_wq_count >= m && fnic->wq_copy_count >= o && fnic->cq_count >= n + m + o) { - if (!pci_enable_msix_exact(fnic->pdev, fnic->msix_entry, - n + m + o + 1)) { + int vecs = n + m + o + 1; + + if (pci_alloc_irq_vectors(fnic->pdev, vecs, vecs, + PCI_IRQ_MSIX) < 0) { fnic->rq_count = n; fnic->raw_wq_count = m; fnic->wq_copy_count = o; fnic->wq_count = m + o; fnic->cq_count = n + m + o; - fnic->intr_count = n + m + o + 1; + fnic->intr_count = vecs; fnic->err_intr_offset = FNIC_MSIX_ERR_NOTIFY; FNIC_ISR_DBG(KERN_DEBUG, fnic->lport->host, @@ -284,8 +280,7 @@ int fnic_set_intr_mode(struct fnic *fnic) fnic->wq_copy_count >= 1 && fnic->cq_count >= 3 && fnic->intr_count >= 1 && - !pci_enable_msi(fnic->pdev)) { - + pci_alloc_irq_vectors(fnic->pdev, 1, 1, PCI_IRQ_MSI) < 0) { fnic->rq_count = 1; fnic->raw_wq_count = 1; fnic->wq_copy_count = 1; @@ -334,17 +329,7 @@ int fnic_set_intr_mode(struct fnic *fnic) void fnic_clear_intr_mode(struct fnic *fnic) { - switch (vnic_dev_get_intr_mode(fnic->vdev)) { - case VNIC_DEV_INTR_MODE_MSIX: - pci_disable_msix(fnic->pdev); - break; - case VNIC_DEV_INTR_MODE_MSI: - pci_disable_msi(fnic->pdev); - break; - default: - break; - } - + pci_free_irq_vectors(fnic->pdev); vnic_dev_set_intr_mode(fnic->vdev, VNIC_DEV_INTR_MODE_INTX); } -- cgit v1.2.3 From b43abcbbd5b10d5f057c8388cc4eff9ff1fe2fd6 Mon Sep 17 00:00:00 2001 From: Satish Kharat Date: Tue, 28 Feb 2017 16:11:57 -0800 Subject: scsi: fnic: Ratelimit printks to avoid flooding when vlan is not set by the switch.i This is to avoid the log from being filled with vlan discovery messages when there is no vlan configured on the switch. Signed-off-by: Satish Kharat Signed-off-by: Sesidhar Baddela Signed-off-by: Martin K. Petersen --- drivers/scsi/fnic/fnic_fcs.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/fnic/fnic_fcs.c b/drivers/scsi/fnic/fnic_fcs.c index 3b7da66e2771..8d2d86e0bc72 100644 --- a/drivers/scsi/fnic/fnic_fcs.c +++ b/drivers/scsi/fnic/fnic_fcs.c @@ -342,8 +342,11 @@ static void fnic_fcoe_send_vlan_req(struct fnic *fnic) fnic_fcoe_reset_vlans(fnic); fnic->set_vlan(fnic, 0); - FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, - "Sending VLAN request...\n"); + + if (printk_ratelimit()) + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, + "Sending VLAN request...\n"); + skb = dev_alloc_skb(sizeof(struct fip_vlan)); if (!skb) return; @@ -1313,10 +1316,11 @@ void fnic_handle_fip_timer(struct fnic *fnic) spin_lock_irqsave(&fnic->vlans_lock, flags); if (list_empty(&fnic->vlans)) { - /* no vlans available, try again */ - FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, - "Start VLAN Discovery\n"); spin_unlock_irqrestore(&fnic->vlans_lock, flags); + /* no vlans available, try again */ + if (printk_ratelimit()) + FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, + "Start VLAN Discovery\n"); fnic_event_enq(fnic, FNIC_EVT_START_VLAN_DISC); return; } @@ -1332,10 +1336,11 @@ void fnic_handle_fip_timer(struct fnic *fnic) spin_unlock_irqrestore(&fnic->vlans_lock, flags); break; case FIP_VLAN_FAILED: - /* if all vlans are in failed state, restart vlan disc */ - FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, - "Start VLAN Discovery\n"); spin_unlock_irqrestore(&fnic->vlans_lock, flags); + /* if all vlans are in failed state, restart vlan disc */ + if (printk_ratelimit()) + FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, + "Start VLAN Discovery\n"); fnic_event_enq(fnic, FNIC_EVT_START_VLAN_DISC); break; case FIP_VLAN_SENT: -- cgit v1.2.3 From ccc6d704602b01f6ce48abdea53736db88c5470c Mon Sep 17 00:00:00 2001 From: Satish Kharat Date: Tue, 28 Feb 2017 16:14:33 -0800 Subject: scsi: fnic: minor cleanup in fnic_fcpio_itmf_cmpl_handler, removing else case Getting rid of else case to make the flow look bit simpler. Signed-off-by: Satish Kharat Signed-off-by: Sesidhar Baddela Signed-off-by: Martin K. Petersen --- drivers/scsi/fnic/fnic_scsi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/fnic/fnic_scsi.c b/drivers/scsi/fnic/fnic_scsi.c index adb3d5871e74..5e694a591c9d 100644 --- a/drivers/scsi/fnic/fnic_scsi.c +++ b/drivers/scsi/fnic/fnic_scsi.c @@ -1128,12 +1128,11 @@ static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic, } CMD_FLAGS(sc) |= FNIC_IO_ABT_TERM_DONE; + CMD_ABTS_STATUS(sc) = hdr_status; /* If the status is IO not found consider it as success */ if (hdr_status == FCPIO_IO_NOT_FOUND) CMD_ABTS_STATUS(sc) = FCPIO_SUCCESS; - else - CMD_ABTS_STATUS(sc) = hdr_status; atomic64_dec(&fnic_stats->io_stats.active_ios); if (atomic64_read(&fnic->io_cmpl_skip)) -- cgit v1.2.3 From 7ef539c88d7d394410d547c9f082d477093a2a22 Mon Sep 17 00:00:00 2001 From: Satish Kharat Date: Tue, 28 Feb 2017 16:14:56 -0800 Subject: scsi: fnic: Fix for "Number of Active IOs" in fnicstats becoming negative Fixing the IO stats update (Active IOs and IO completion) to prevent "Number of Active IOs" from becoming negative in the fnistats output. Signed-off-by: Satish Kharat Signed-off-by: Sesidhar Baddela Signed-off-by: Martin K. Petersen --- drivers/scsi/fnic/fnic_scsi.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/fnic/fnic_scsi.c b/drivers/scsi/fnic/fnic_scsi.c index 5e694a591c9d..0650911929fd 100644 --- a/drivers/scsi/fnic/fnic_scsi.c +++ b/drivers/scsi/fnic/fnic_scsi.c @@ -1134,12 +1134,6 @@ static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic, if (hdr_status == FCPIO_IO_NOT_FOUND) CMD_ABTS_STATUS(sc) = FCPIO_SUCCESS; - atomic64_dec(&fnic_stats->io_stats.active_ios); - if (atomic64_read(&fnic->io_cmpl_skip)) - atomic64_dec(&fnic->io_cmpl_skip); - else - atomic64_inc(&fnic_stats->io_stats.io_completions); - if (!(CMD_FLAGS(sc) & (FNIC_IO_ABORTED | FNIC_IO_DONE))) atomic64_inc(&misc_stats->no_icmnd_itmf_cmpls); @@ -1180,6 +1174,11 @@ static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic, (((u64)CMD_FLAGS(sc) << 32) | CMD_STATE(sc))); sc->scsi_done(sc); + atomic64_dec(&fnic_stats->io_stats.active_ios); + if (atomic64_read(&fnic->io_cmpl_skip)) + atomic64_dec(&fnic->io_cmpl_skip); + else + atomic64_inc(&fnic_stats->io_stats.io_completions); } } @@ -1969,6 +1968,11 @@ int fnic_abort_cmd(struct scsi_cmnd *sc) /* Call SCSI completion function to complete the IO */ sc->result = (DID_ABORT << 16); sc->scsi_done(sc); + atomic64_dec(&fnic_stats->io_stats.active_ios); + if (atomic64_read(&fnic->io_cmpl_skip)) + atomic64_dec(&fnic->io_cmpl_skip); + else + atomic64_inc(&fnic_stats->io_stats.io_completions); } fnic_abort_cmd_end: -- cgit v1.2.3 From b9202b4ae8171e9eaa21504d5a8c1c2e9d6ecd90 Mon Sep 17 00:00:00 2001 From: Satish Kharat Date: Tue, 28 Feb 2017 16:15:12 -0800 Subject: scsi: fnic: Avoid false out-of-order detection for aborted command If SCSI-ML has already issued abort on a command i.e FNIC_IOREQ_ABTS_PENDING is set and we get a IO completion, avoid this being flagged as out-of-order completion by setting the FNIC_IO_DONE flag in fnic_fcpio_icmnd_cmpl_handler Signed-off-by: Satish Kharat Signed-off-by: Sesidhar Baddela Signed-off-by: Martin K. Petersen --- drivers/scsi/fnic/fnic_scsi.c | 40 ++++++++++++++++++---------------------- 1 file changed, 18 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/fnic/fnic_scsi.c b/drivers/scsi/fnic/fnic_scsi.c index 0650911929fd..ce5de2aa39c7 100644 --- a/drivers/scsi/fnic/fnic_scsi.c +++ b/drivers/scsi/fnic/fnic_scsi.c @@ -876,32 +876,28 @@ static void fnic_fcpio_icmnd_cmpl_handler(struct fnic *fnic, /* * if SCSI-ML has already issued abort on this command, - * ignore completion of the IO. The abts path will clean it up + * set completion of the IO. The abts path will clean it up */ if (CMD_STATE(sc) == FNIC_IOREQ_ABTS_PENDING) { - spin_unlock_irqrestore(io_lock, flags); + + /* + * set the FNIC_IO_DONE so that this doesn't get + * flagged as 'out of order' if it was not aborted + */ + CMD_FLAGS(sc) |= FNIC_IO_DONE; CMD_FLAGS(sc) |= FNIC_IO_ABTS_PENDING; - switch (hdr_status) { - case FCPIO_SUCCESS: - CMD_FLAGS(sc) |= FNIC_IO_DONE; - FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host, - "icmnd_cmpl ABTS pending hdr status = %s " - "sc 0x%p scsi_status %x residual %d\n", - fnic_fcpio_status_to_str(hdr_status), sc, - icmnd_cmpl->scsi_status, - icmnd_cmpl->residual); - break; - case FCPIO_ABORTED: + spin_unlock_irqrestore(io_lock, flags); + if(FCPIO_ABORTED == hdr_status) CMD_FLAGS(sc) |= FNIC_IO_ABORTED; - break; - default: - FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host, - "icmnd_cmpl abts pending " - "hdr status = %s tag = 0x%x sc = 0x%p\n", - fnic_fcpio_status_to_str(hdr_status), - id, sc); - break; - } + + FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host, + "icmnd_cmpl abts pending " + "hdr status = %s tag = 0x%x sc = 0x%p" + "scsi_status = %x residual = %d\n", + fnic_fcpio_status_to_str(hdr_status), + id, sc, + icmnd_cmpl->scsi_status, + icmnd_cmpl->residual); return; } -- cgit v1.2.3 From 39fcbbc01b89550ca527ea8d640e3af7bfde41d7 Mon Sep 17 00:00:00 2001 From: Satish Kharat Date: Tue, 28 Feb 2017 16:15:44 -0800 Subject: scsi: fnic: Adding Check Condition counter to misc fnicstats Just a simple counter of number of check conditions encountered on that host. Signed-off-by: Satish Kharat Signed-off-by: Sesidhar Baddela Signed-off-by: Martin K. Petersen --- drivers/scsi/fnic/fnic_scsi.c | 3 +++ drivers/scsi/fnic/fnic_stats.h | 1 + drivers/scsi/fnic/fnic_trace.c | 2 ++ 3 files changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/fnic/fnic_scsi.c b/drivers/scsi/fnic/fnic_scsi.c index ce5de2aa39c7..190c0663aaf4 100644 --- a/drivers/scsi/fnic/fnic_scsi.c +++ b/drivers/scsi/fnic/fnic_scsi.c @@ -915,6 +915,9 @@ static void fnic_fcpio_icmnd_cmpl_handler(struct fnic *fnic, if (icmnd_cmpl->flags & FCPIO_ICMND_CMPL_RESID_UNDER) xfer_len -= icmnd_cmpl->residual; + if (icmnd_cmpl->scsi_status == SAM_STAT_CHECK_CONDITION) + atomic64_inc(&fnic_stats->misc_stats.check_condition); + if (icmnd_cmpl->scsi_status == SAM_STAT_TASK_SET_FULL) atomic64_inc(&fnic_stats->misc_stats.queue_fulls); break; diff --git a/drivers/scsi/fnic/fnic_stats.h b/drivers/scsi/fnic/fnic_stats.h index 540cceb843cd..69acdac7fe53 100644 --- a/drivers/scsi/fnic/fnic_stats.h +++ b/drivers/scsi/fnic/fnic_stats.h @@ -88,6 +88,7 @@ struct misc_stats { atomic64_t devrst_cpwq_alloc_failures; atomic64_t io_cpwq_alloc_failures; atomic64_t no_icmnd_itmf_cmpls; + atomic64_t check_condition; atomic64_t queue_fulls; atomic64_t rport_not_ready; atomic64_t frame_errors; diff --git a/drivers/scsi/fnic/fnic_trace.c b/drivers/scsi/fnic/fnic_trace.c index 5a5fa01576b7..ec20b3e57844 100644 --- a/drivers/scsi/fnic/fnic_trace.c +++ b/drivers/scsi/fnic/fnic_trace.c @@ -357,6 +357,7 @@ int fnic_get_stats_data(struct stats_debug_info *debug, "Number of Copy WQ Alloc Failures for Device Reset: %lld\n" "Number of Copy WQ Alloc Failures for IOs: %lld\n" "Number of no icmnd itmf Completions: %lld\n" + "Number of Check Conditions encountered: %lld\n" "Number of QUEUE Fulls: %lld\n" "Number of rport not ready: %lld\n" "Number of receive frame errors: %lld\n", @@ -377,6 +378,7 @@ int fnic_get_stats_data(struct stats_debug_info *debug, &stats->misc_stats.devrst_cpwq_alloc_failures), (u64)atomic64_read(&stats->misc_stats.io_cpwq_alloc_failures), (u64)atomic64_read(&stats->misc_stats.no_icmnd_itmf_cmpls), + (u64)atomic64_read(&stats->misc_stats.check_condition), (u64)atomic64_read(&stats->misc_stats.queue_fulls), (u64)atomic64_read(&stats->misc_stats.rport_not_ready), (u64)atomic64_read(&stats->misc_stats.frame_errors)); -- cgit v1.2.3 From 445d2960862eb3c972012bbbb9cf4ee338334b0a Mon Sep 17 00:00:00 2001 From: Satish Kharat Date: Tue, 28 Feb 2017 16:15:59 -0800 Subject: scsi: fnic: Adding debug IO and Abort latency counter to fnic stats The IO and Abort latency counter counts the time taken to complete the IO and abort command into broad buckets. This is not intended for performance measurement, just a debug statistic. current_max_io_time tries to keep track of the maximum time an IO has taken to complete if it is > 30sec. Signed-off-by: Satish Kharat Signed-off-by: Sesidhar Baddela Signed-off-by: Martin K. Petersen --- drivers/scsi/fnic/fnic.h | 2 +- drivers/scsi/fnic/fnic_scsi.c | 43 ++++++++++++++++++++++++++++++++++++++ drivers/scsi/fnic/fnic_stats.h | 15 ++++++++++++++ drivers/scsi/fnic/fnic_trace.c | 47 ++++++++++++++++++++++++++++++++++++++---- 4 files changed, 102 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/fnic/fnic.h b/drivers/scsi/fnic/fnic.h index 7d5739e437d2..67aab965c0f4 100644 --- a/drivers/scsi/fnic/fnic.h +++ b/drivers/scsi/fnic/fnic.h @@ -39,7 +39,7 @@ #define DRV_NAME "fnic" #define DRV_DESCRIPTION "Cisco FCoE HBA Driver" -#define DRV_VERSION "1.6.0.21" +#define DRV_VERSION "1.6.0.34" #define PFX DRV_NAME ": " #define DFX DRV_NAME "%d: " diff --git a/drivers/scsi/fnic/fnic_scsi.c b/drivers/scsi/fnic/fnic_scsi.c index 190c0663aaf4..d048f3b5006f 100644 --- a/drivers/scsi/fnic/fnic_scsi.c +++ b/drivers/scsi/fnic/fnic_scsi.c @@ -823,6 +823,7 @@ static void fnic_fcpio_icmnd_cmpl_handler(struct fnic *fnic, spinlock_t *io_lock; u64 cmd_trace; unsigned long start_time; + unsigned long io_duration_time; /* Decode the cmpl description to get the io_req id */ fcpio_header_dec(&desc->hdr, &type, &hdr_status, &tag); @@ -1016,6 +1017,28 @@ static void fnic_fcpio_icmnd_cmpl_handler(struct fnic *fnic, else atomic64_inc(&fnic_stats->io_stats.io_completions); + + io_duration_time = jiffies_to_msecs(jiffies) - jiffies_to_msecs(io_req->start_time); + + if(io_duration_time <= 10) + atomic64_inc(&fnic_stats->io_stats.io_btw_0_to_10_msec); + else if(io_duration_time <= 100) + atomic64_inc(&fnic_stats->io_stats.io_btw_10_to_100_msec); + else if(io_duration_time <= 500) + atomic64_inc(&fnic_stats->io_stats.io_btw_100_to_500_msec); + else if(io_duration_time <= 5000) + atomic64_inc(&fnic_stats->io_stats.io_btw_500_to_5000_msec); + else if(io_duration_time <= 10000) + atomic64_inc(&fnic_stats->io_stats.io_btw_5000_to_10000_msec); + else if(io_duration_time <= 30000) + atomic64_inc(&fnic_stats->io_stats.io_btw_10000_to_30000_msec); + else { + atomic64_inc(&fnic_stats->io_stats.io_greater_than_30000_msec); + + if(io_duration_time > atomic64_read(&fnic_stats->io_stats.current_max_io_time)) + atomic64_set(&fnic_stats->io_stats.current_max_io_time, io_duration_time); + } + /* Call SCSI completion function to complete the IO */ if (sc->scsi_done) sc->scsi_done(sc); @@ -1790,6 +1813,7 @@ int fnic_abort_cmd(struct scsi_cmnd *sc) struct terminate_stats *term_stats; enum fnic_ioreq_state old_ioreq_state; int tag; + unsigned long abt_issued_time; DECLARE_COMPLETION_ONSTACK(tm_done); /* Wait for rport to unblock */ @@ -1843,6 +1867,25 @@ int fnic_abort_cmd(struct scsi_cmnd *sc) spin_unlock_irqrestore(io_lock, flags); goto wait_pending; } + + abt_issued_time = jiffies_to_msecs(jiffies) - jiffies_to_msecs(io_req->start_time); + if (abt_issued_time <= 6000) + atomic64_inc(&abts_stats->abort_issued_btw_0_to_6_sec); + else if (abt_issued_time > 6000 && abt_issued_time <= 20000) + atomic64_inc(&abts_stats->abort_issued_btw_6_to_20_sec); + else if (abt_issued_time > 20000 && abt_issued_time <= 30000) + atomic64_inc(&abts_stats->abort_issued_btw_20_to_30_sec); + else if (abt_issued_time > 30000 && abt_issued_time <= 40000) + atomic64_inc(&abts_stats->abort_issued_btw_30_to_40_sec); + else if (abt_issued_time > 40000 && abt_issued_time <= 50000) + atomic64_inc(&abts_stats->abort_issued_btw_40_to_50_sec); + else if (abt_issued_time > 50000 && abt_issued_time <= 60000) + atomic64_inc(&abts_stats->abort_issued_btw_50_to_60_sec); + else + atomic64_inc(&abts_stats->abort_issued_greater_than_60_sec); + + FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host, + "CBD Opcode: %02x Abort issued time: %lu msec\n", sc->cmnd[0], abt_issued_time); /* * Command is still pending, need to abort it * If the firmware completes the command after this point, diff --git a/drivers/scsi/fnic/fnic_stats.h b/drivers/scsi/fnic/fnic_stats.h index 69acdac7fe53..88c73cccb015 100644 --- a/drivers/scsi/fnic/fnic_stats.h +++ b/drivers/scsi/fnic/fnic_stats.h @@ -26,6 +26,14 @@ struct io_path_stats { atomic64_t sc_null; atomic64_t io_not_found; atomic64_t num_ios; + atomic64_t io_btw_0_to_10_msec; + atomic64_t io_btw_10_to_100_msec; + atomic64_t io_btw_100_to_500_msec; + atomic64_t io_btw_500_to_5000_msec; + atomic64_t io_btw_5000_to_10000_msec; + atomic64_t io_btw_10000_to_30000_msec; + atomic64_t io_greater_than_30000_msec; + atomic64_t current_max_io_time; }; struct abort_stats { @@ -34,6 +42,13 @@ struct abort_stats { atomic64_t abort_drv_timeouts; atomic64_t abort_fw_timeouts; atomic64_t abort_io_not_found; + atomic64_t abort_issued_btw_0_to_6_sec; + atomic64_t abort_issued_btw_6_to_20_sec; + atomic64_t abort_issued_btw_20_to_30_sec; + atomic64_t abort_issued_btw_30_to_40_sec; + atomic64_t abort_issued_btw_40_to_50_sec; + atomic64_t abort_issued_btw_50_to_60_sec; + atomic64_t abort_issued_greater_than_60_sec; }; struct terminate_stats { diff --git a/drivers/scsi/fnic/fnic_trace.c b/drivers/scsi/fnic/fnic_trace.c index ec20b3e57844..b5ac5381a0d7 100644 --- a/drivers/scsi/fnic/fnic_trace.c +++ b/drivers/scsi/fnic/fnic_trace.c @@ -229,7 +229,16 @@ int fnic_get_stats_data(struct stats_debug_info *debug, "Number of IO Failures: %lld\nNumber of IO NOT Found: %lld\n" "Number of Memory alloc Failures: %lld\n" "Number of IOREQ Null: %lld\n" - "Number of SCSI cmd pointer Null: %lld\n", + "Number of SCSI cmd pointer Null: %lld\n" + + "\nIO completion times: \n" + " < 10 ms : %lld\n" + " 10 ms - 100 ms : %lld\n" + " 100 ms - 500 ms : %lld\n" + " 500 ms - 5 sec: %lld\n" + " 5 sec - 10 sec: %lld\n" + " 10 sec - 30 sec: %lld\n" + " > 30 sec: %lld\n", (u64)atomic64_read(&stats->io_stats.active_ios), (u64)atomic64_read(&stats->io_stats.max_active_ios), (u64)atomic64_read(&stats->io_stats.num_ios), @@ -238,28 +247,58 @@ int fnic_get_stats_data(struct stats_debug_info *debug, (u64)atomic64_read(&stats->io_stats.io_not_found), (u64)atomic64_read(&stats->io_stats.alloc_failures), (u64)atomic64_read(&stats->io_stats.ioreq_null), - (u64)atomic64_read(&stats->io_stats.sc_null)); + (u64)atomic64_read(&stats->io_stats.sc_null), + (u64)atomic64_read(&stats->io_stats.io_btw_0_to_10_msec), + (u64)atomic64_read(&stats->io_stats.io_btw_10_to_100_msec), + (u64)atomic64_read(&stats->io_stats.io_btw_100_to_500_msec), + (u64)atomic64_read(&stats->io_stats.io_btw_500_to_5000_msec), + (u64)atomic64_read(&stats->io_stats.io_btw_5000_to_10000_msec), + (u64)atomic64_read(&stats->io_stats.io_btw_10000_to_30000_msec), + (u64)atomic64_read(&stats->io_stats.io_greater_than_30000_msec)); + + len += snprintf(debug->debug_buffer + len, buf_size - len, + "\nCurrent Max IO time : %lld\n", + (u64)atomic64_read(&stats->io_stats.current_max_io_time)); len += snprintf(debug->debug_buffer + len, buf_size - len, "\n------------------------------------------\n" "\t\tAbort Statistics\n" "------------------------------------------\n"); + len += snprintf(debug->debug_buffer + len, buf_size - len, "Number of Aborts: %lld\n" "Number of Abort Failures: %lld\n" "Number of Abort Driver Timeouts: %lld\n" "Number of Abort FW Timeouts: %lld\n" - "Number of Abort IO NOT Found: %lld\n", + "Number of Abort IO NOT Found: %lld\n" + + "Abord issued times: \n" + " < 6 sec : %lld\n" + " 6 sec - 20 sec : %lld\n" + " 20 sec - 30 sec : %lld\n" + " 30 sec - 40 sec : %lld\n" + " 40 sec - 50 sec : %lld\n" + " 50 sec - 60 sec : %lld\n" + " > 60 sec: %lld\n", + (u64)atomic64_read(&stats->abts_stats.aborts), (u64)atomic64_read(&stats->abts_stats.abort_failures), (u64)atomic64_read(&stats->abts_stats.abort_drv_timeouts), (u64)atomic64_read(&stats->abts_stats.abort_fw_timeouts), - (u64)atomic64_read(&stats->abts_stats.abort_io_not_found)); + (u64)atomic64_read(&stats->abts_stats.abort_io_not_found), + (u64)atomic64_read(&stats->abts_stats.abort_issued_btw_0_to_6_sec), + (u64)atomic64_read(&stats->abts_stats.abort_issued_btw_6_to_20_sec), + (u64)atomic64_read(&stats->abts_stats.abort_issued_btw_20_to_30_sec), + (u64)atomic64_read(&stats->abts_stats.abort_issued_btw_30_to_40_sec), + (u64)atomic64_read(&stats->abts_stats.abort_issued_btw_40_to_50_sec), + (u64)atomic64_read(&stats->abts_stats.abort_issued_btw_50_to_60_sec), + (u64)atomic64_read(&stats->abts_stats.abort_issued_greater_than_60_sec)); len += snprintf(debug->debug_buffer + len, buf_size - len, "\n------------------------------------------\n" "\t\tTerminate Statistics\n" "------------------------------------------\n"); + len += snprintf(debug->debug_buffer + len, buf_size - len, "Number of Terminates: %lld\n" "Maximum Terminates: %lld\n" -- cgit v1.2.3 From b8e1aa3c72f461a12b350def015cf4bc87960711 Mon Sep 17 00:00:00 2001 From: Satish Kharat Date: Wed, 22 Mar 2017 16:55:01 -0700 Subject: scsi: fnic: bug fix for fip.fip_subcode in fnic_fcoe_send_vlan_req This is a bug introduced when they moved the fip subcodes to central place. Was sending FIP_SC_VL_NOTE in fip.fip_subcode for VLAN request in fnic_fcoe_send_vlan_req. Change is to use FIP_SC_VL_REQ instead. Signed-off-by: Satish Kharat Signed-off-by: Sesidhar Baddela Signed-off-by: Martin K. Petersen --- drivers/scsi/fnic/fnic_fcs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/fnic/fnic_fcs.c b/drivers/scsi/fnic/fnic_fcs.c index 8d2d86e0bc72..245dcd95e11f 100644 --- a/drivers/scsi/fnic/fnic_fcs.c +++ b/drivers/scsi/fnic/fnic_fcs.c @@ -362,7 +362,7 @@ static void fnic_fcoe_send_vlan_req(struct fnic *fnic) vlan->fip.fip_ver = FIP_VER_ENCAPS(FIP_VER); vlan->fip.fip_op = htons(FIP_OP_VLAN); - vlan->fip.fip_subcode = FIP_SC_VL_NOTE; + vlan->fip.fip_subcode = FIP_SC_VL_REQ; vlan->fip.fip_dl_len = htons(sizeof(vlan->desc) / FIP_BPW); vlan->desc.mac.fd_desc.fip_dtype = FIP_DT_MAC; -- cgit v1.2.3 From 2e244f0f5bcaa95e8b9006282d7c1ad07605d4fe Mon Sep 17 00:00:00 2001 From: John Garry Date: Thu, 23 Mar 2017 01:25:17 +0800 Subject: scsi: hisi_sas: add to_hisi_sas_port() Introduce function to get hisi_sas_port from asd_sas_port. Signed-off-by: John Garry Signed-off-by: Xiang Chen Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas.h | 2 ++ drivers/scsi/hisi_sas/hisi_sas_main.c | 17 +++++++++++++---- drivers/scsi/hisi_sas/hisi_sas_v1_hw.c | 4 +++- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 6 ++++-- 4 files changed, 22 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index 9216deaa3ff5..a018a8afa894 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -346,6 +346,8 @@ union hisi_sas_command_table { struct hisi_sas_command_table_smp smp; struct hisi_sas_command_table_stp stp; }; + +extern struct hisi_sas_port *to_hisi_sas_port(struct asd_sas_port *sas_port); extern int hisi_sas_probe(struct platform_device *pdev, const struct hisi_sas_hw *ops); extern int hisi_sas_remove(struct platform_device *pdev); diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 53637a941b94..11f32d2c436a 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -27,6 +27,12 @@ static struct hisi_hba *dev_to_hisi_hba(struct domain_device *device) return device->port->ha->lldd_ha; } +struct hisi_sas_port *to_hisi_sas_port(struct asd_sas_port *sas_port) +{ + return container_of(sas_port, struct hisi_sas_port, sas_port); +} +EXPORT_SYMBOL_GPL(to_hisi_sas_port); + static void hisi_sas_slot_index_clear(struct hisi_hba *hisi_hba, int slot_idx) { void *bitmap = hisi_hba->slot_index_tags; @@ -178,10 +184,11 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba, struct hisi_sas_port *port; struct hisi_sas_slot *slot; struct hisi_sas_cmd_hdr *cmd_hdr_base; + struct asd_sas_port *sas_port = device->port; struct device *dev = &hisi_hba->pdev->dev; int dlvry_queue_slot, dlvry_queue, n_elem = 0, rc, slot_idx; - if (!device->port) { + if (!sas_port) { struct task_status_struct *ts = &task->task_status; ts->resp = SAS_TASK_UNDELIVERED; @@ -206,7 +213,8 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba, rc = SAS_PHY_DOWN; return rc; } - port = device->port->lldd_port; + + port = to_hisi_sas_port(sas_port); if (port && !port->port_attached) { dev_info(dev, "task prep: %s port%d not attach device\n", (sas_protocol_ata(task->task_proto)) ? @@ -545,7 +553,7 @@ static void hisi_sas_port_notify_formed(struct asd_sas_phy *sas_phy) struct hisi_hba *hisi_hba = sas_ha->lldd_ha; struct hisi_sas_phy *phy = sas_phy->lldd_phy; struct asd_sas_port *sas_port = sas_phy->port; - struct hisi_sas_port *port = &hisi_hba->port[phy->port_id]; + struct hisi_sas_port *port = to_hisi_sas_port(sas_port); unsigned long flags; if (!sas_port) @@ -990,13 +998,14 @@ hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, u64 device_id, struct device *dev = &hisi_hba->pdev->dev; struct hisi_sas_port *port; struct hisi_sas_slot *slot; + struct asd_sas_port *sas_port = device->port; 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; + port = to_hisi_sas_port(sas_port); /* simply get a slot and send abort command */ rc = hisi_sas_slot_index_alloc(hisi_hba, &slot_idx); diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c index 854fbeaade3e..022ad10e102c 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c @@ -508,6 +508,8 @@ static void setup_itct_v1_hw(struct hisi_hba *hisi_hba, struct device *dev = &hisi_hba->pdev->dev; u64 qw0, device_id = sas_dev->device_id; struct hisi_sas_itct *itct = &hisi_hba->itct[device_id]; + struct asd_sas_port *sas_port = device->port; + struct hisi_sas_port *port = to_hisi_sas_port(sas_port); memset(itct, 0, sizeof(*itct)); @@ -528,7 +530,7 @@ static void setup_itct_v1_hw(struct hisi_hba *hisi_hba, (1 << ITCT_HDR_AWT_CONTROL_OFF) | (device->max_linkrate << ITCT_HDR_MAX_CONN_RATE_OFF) | (1 << ITCT_HDR_VALID_LINK_NUM_OFF) | - (device->port->id << ITCT_HDR_PORT_ID_OFF)); + (port->id << ITCT_HDR_PORT_ID_OFF)); itct->qw0 = cpu_to_le64(qw0); /* qw1 */ diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 1b214450dcb5..1590e2f6ac66 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -676,7 +676,8 @@ static void setup_itct_v2_hw(struct hisi_hba *hisi_hba, u64 qw0, device_id = sas_dev->device_id; struct hisi_sas_itct *itct = &hisi_hba->itct[device_id]; struct domain_device *parent_dev = device->parent; - struct hisi_sas_port *port = device->port->lldd_port; + struct asd_sas_port *sas_port = device->port; + struct hisi_sas_port *port = to_hisi_sas_port(sas_port); memset(itct, 0, sizeof(*itct)); @@ -1920,7 +1921,8 @@ static int prep_ata_v2_hw(struct hisi_hba *hisi_hba, struct domain_device *parent_dev = device->parent; struct hisi_sas_device *sas_dev = device->lldd_dev; struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr; - struct hisi_sas_port *port = device->port->lldd_port; + struct asd_sas_port *sas_port = device->port; + struct hisi_sas_port *port = to_hisi_sas_port(sas_port); u8 *buf_cmd; int has_data = 0, rc = 0, hdr_tag = 0; u32 dw1 = 0, dw2 = 0; -- cgit v1.2.3 From 06ec0fb97c028102c95d52422fd6dc5ac701039f Mon Sep 17 00:00:00 2001 From: Xiang Chen Date: Thu, 23 Mar 2017 01:25:18 +0800 Subject: scsi: hisi_sas: add controller reset There are some scenarios that we need to warm-reset to reset registers of SAS controller. During reset we disable interrupts/DQs/PHYs, and after reset we re-init the hardware and rescan the topology to see if anything changed. Signed-off-by: Xiang Chen Signed-off-by: Xiaofei Tan Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas.h | 7 ++ drivers/scsi/hisi_sas/hisi_sas_main.c | 134 +++++++++++++++++++++++++++++++-- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 94 +++++++++++++++++++++++ 3 files changed, 227 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index a018a8afa894..fd76a02873a5 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -31,6 +31,7 @@ #define HISI_SAS_QUEUE_SLOTS 512 #define HISI_SAS_MAX_ITCT_ENTRIES 2048 #define HISI_SAS_MAX_DEVICES HISI_SAS_MAX_ITCT_ENTRIES +#define HISI_SAS_RESET_BIT 0 #define HISI_SAS_STATUS_BUF_SZ \ (sizeof(struct hisi_sas_err_record) + 1024) @@ -175,6 +176,7 @@ struct hisi_sas_hw { void (*free_device)(struct hisi_hba *hisi_hba, struct hisi_sas_device *dev); int (*get_wideport_bitmap)(struct hisi_hba *hisi_hba, int port_id); + int (*soft_reset)(struct hisi_hba *hisi_hba); int max_command_entries; int complete_hdr_size; }; @@ -233,7 +235,9 @@ struct hisi_hba { struct hisi_sas_breakpoint *sata_breakpoint; dma_addr_t sata_breakpoint_dma; struct hisi_sas_slot *slot_info; + unsigned long flags; const struct hisi_sas_hw *hw; /* Low level hw interface */ + struct work_struct rst_work; }; /* Generic HW DMA host memory structures */ @@ -356,4 +360,7 @@ extern void hisi_sas_phy_down(struct hisi_hba *hisi_hba, int phy_no, int rdy); extern void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task, struct hisi_sas_slot *slot); +extern void hisi_sas_init_mem(struct hisi_hba *hisi_hba); +extern void hisi_sas_rescan_topology(struct hisi_hba *hisi_hba, u32 old_state, + u32 state); #endif diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 11f32d2c436a..cbaef90e584d 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -351,6 +351,9 @@ static int hisi_sas_task_exec(struct sas_task *task, gfp_t gfp_flags, struct hisi_hba *hisi_hba = dev_to_hisi_hba(task->dev); struct device *dev = &hisi_hba->pdev->dev; + if (unlikely(test_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags))) + return -EINVAL; + /* protect task_prep and start_delivery sequence */ spin_lock_irqsave(&hisi_hba->lock, flags); rc = hisi_sas_task_prep(task, hisi_hba, is_tmf, tmf, &pass); @@ -613,6 +616,20 @@ static void hisi_sas_release_task(struct hisi_hba *hisi_hba, hisi_sas_do_release_task(hisi_hba, sas_phy->id, device); } +static void hisi_sas_release_tasks(struct hisi_hba *hisi_hba) +{ + int i; + + for (i = 0; i < HISI_SAS_MAX_PHYS; i++) { + struct hisi_sas_phy *phy = &hisi_hba->phy[i]; + struct asd_sas_phy *sas_phy = &phy->sas_phy; + + if (!sas_phy->port) + continue; + hisi_sas_port_notify_deformed(sas_phy); + } +} + static void hisi_sas_dev_gone(struct domain_device *device) { struct hisi_sas_device *sas_dev = device->lldd_dev; @@ -803,6 +820,40 @@ static int hisi_sas_debug_issue_ssp_tmf(struct domain_device *device, sizeof(ssp_task), tmf); } +static int hisi_sas_controller_reset(struct hisi_hba *hisi_hba) +{ + int rc; + + if (!hisi_hba->hw->soft_reset) + return -1; + + if (!test_and_set_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags)) { + struct device *dev = &hisi_hba->pdev->dev; + struct sas_ha_struct *sas_ha = &hisi_hba->sha; + unsigned long flags; + + dev_dbg(dev, "controller reset begins!\n"); + scsi_block_requests(hisi_hba->shost); + rc = hisi_hba->hw->soft_reset(hisi_hba); + if (rc) { + dev_warn(dev, "controller reset failed (%d)\n", rc); + goto out; + } + spin_lock_irqsave(&hisi_hba->lock, flags); + hisi_sas_release_tasks(hisi_hba); + spin_unlock_irqrestore(&hisi_hba->lock, flags); + + sas_ha->notify_ha_event(sas_ha, HAE_RESET); + dev_dbg(dev, "controller reset successful!\n"); + } else + return -1; + +out: + scsi_unblock_requests(hisi_hba->shost); + clear_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags); + return rc; +} + static int hisi_sas_abort_task(struct sas_task *task) { struct scsi_lun lun; @@ -1002,6 +1053,9 @@ hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, u64 device_id, struct hisi_sas_cmd_hdr *cmd_hdr_base; int dlvry_queue_slot, dlvry_queue, n_elem = 0, rc, slot_idx; + if (unlikely(test_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags))) + return -EINVAL; + if (!device->port) return -1; @@ -1190,6 +1244,37 @@ void hisi_sas_phy_down(struct hisi_hba *hisi_hba, int phy_no, int rdy) } EXPORT_SYMBOL_GPL(hisi_sas_phy_down); +void hisi_sas_rescan_topology(struct hisi_hba *hisi_hba, u32 old_state, + u32 state) +{ + struct sas_ha_struct *sas_ha = &hisi_hba->sha; + int phy_no; + + for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++) { + struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no]; + struct asd_sas_phy *sas_phy = &phy->sas_phy; + struct asd_sas_port *sas_port = sas_phy->port; + struct domain_device *dev; + + if (sas_phy->enabled) { + /* Report PHY state change to libsas */ + if (state & (1 << phy_no)) + continue; + + if (old_state & (1 << phy_no)) + /* PHY down but was up before */ + hisi_sas_phy_down(hisi_hba, phy_no, 0); + } + if (!sas_port) + continue; + dev = sas_port->port_dev; + + if (DEV_IS_EXPANDER(dev->dev_type)) + sas_ha->notify_phy_event(sas_phy, PORTE_BROADCAST_RCVD); + } +} +EXPORT_SYMBOL_GPL(hisi_sas_rescan_topology); + static struct scsi_transport_template *hisi_sas_stt; static struct scsi_host_template hisi_sas_sht = { @@ -1228,6 +1313,37 @@ static struct sas_domain_function_template hisi_sas_transport_ops = { .lldd_port_deformed = hisi_sas_port_deformed, }; +void hisi_sas_init_mem(struct hisi_hba *hisi_hba) +{ + int i, s, max_command_entries = hisi_hba->hw->max_command_entries; + + 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]; + + s = sizeof(struct hisi_sas_cmd_hdr) * HISI_SAS_QUEUE_SLOTS; + memset(hisi_hba->cmd_hdr[i], 0, s); + dq->wr_point = 0; + + s = hisi_hba->hw->complete_hdr_size * HISI_SAS_QUEUE_SLOTS; + memset(hisi_hba->complete_hdr[i], 0, s); + cq->rd_point = 0; + } + + s = sizeof(struct hisi_sas_initial_fis) * hisi_hba->n_phy; + memset(hisi_hba->initial_fis, 0, s); + + s = max_command_entries * sizeof(struct hisi_sas_iost); + memset(hisi_hba->iost, 0, s); + + s = max_command_entries * sizeof(struct hisi_sas_breakpoint); + memset(hisi_hba->breakpoint, 0, s); + + s = max_command_entries * sizeof(struct hisi_sas_breakpoint) * 2; + memset(hisi_hba->sata_breakpoint, 0, s); +} +EXPORT_SYMBOL_GPL(hisi_sas_init_mem); + static int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost) { struct platform_device *pdev = hisi_hba->pdev; @@ -1266,7 +1382,6 @@ static int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost) &hisi_hba->cmd_hdr_dma[i], GFP_KERNEL); if (!hisi_hba->cmd_hdr[i]) goto err_out; - memset(hisi_hba->cmd_hdr[i], 0, s); /* Completion queue */ s = hisi_hba->hw->complete_hdr_size * HISI_SAS_QUEUE_SLOTS; @@ -1274,7 +1389,6 @@ static int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost) &hisi_hba->complete_hdr_dma[i], GFP_KERNEL); if (!hisi_hba->complete_hdr[i]) goto err_out; - memset(hisi_hba->complete_hdr[i], 0, s); } s = HISI_SAS_STATUS_BUF_SZ; @@ -1309,16 +1423,12 @@ static int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost) if (!hisi_hba->iost) goto err_out; - memset(hisi_hba->iost, 0, s); - 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) goto err_out; - memset(hisi_hba->breakpoint, 0, s); - hisi_hba->slot_index_count = max_command_entries; s = hisi_hba->slot_index_count / BITS_PER_BYTE; hisi_hba->slot_index_tags = devm_kzalloc(dev, s, GFP_KERNEL); @@ -1335,14 +1445,13 @@ static int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost) &hisi_hba->initial_fis_dma, GFP_KERNEL); if (!hisi_hba->initial_fis) goto err_out; - memset(hisi_hba->initial_fis, 0, s); 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) goto err_out; - memset(hisi_hba->sata_breakpoint, 0, s); + hisi_sas_init_mem(hisi_hba); hisi_sas_slot_index_init(hisi_hba); @@ -1413,6 +1522,14 @@ static void hisi_sas_free(struct hisi_hba *hisi_hba) destroy_workqueue(hisi_hba->wq); } +static void hisi_sas_rst_work_handler(struct work_struct *work) +{ + struct hisi_hba *hisi_hba = + container_of(work, struct hisi_hba, rst_work); + + hisi_sas_controller_reset(hisi_hba); +} + static struct Scsi_Host *hisi_sas_shost_alloc(struct platform_device *pdev, const struct hisi_sas_hw *hw) { @@ -1430,6 +1547,7 @@ static struct Scsi_Host *hisi_sas_shost_alloc(struct platform_device *pdev, } hisi_hba = shost_priv(shost); + INIT_WORK(&hisi_hba->rst_work, hisi_sas_rst_work_handler); hisi_hba->hw = hw; hisi_hba->pdev = pdev; hisi_hba->shost = shost; diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 1590e2f6ac66..53651cfd9da1 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -257,6 +257,10 @@ #define AM_CFG_MAX_TRANS (0x5010) #define AM_CFG_SINGLE_PORT_MAX_TRANS (0x5014) +#define AXI_MASTER_CFG_BASE (0x5000) +#define AM_CTRL_GLOBAL (0x0) +#define AM_CURR_TRANS_RETURN (0x150) + /* HW dma structures */ /* Delivery queue header */ /* dw0 */ @@ -1079,6 +1083,14 @@ static void stop_phy_v2_hw(struct hisi_hba *hisi_hba, int phy_no) disable_phy_v2_hw(hisi_hba, phy_no); } +static void stop_phys_v2_hw(struct hisi_hba *hisi_hba) +{ + int i; + + for (i = 0; i < hisi_hba->n_phy; i++) + stop_phy_v2_hw(hisi_hba, i); +} + static void phy_hard_reset_v2_hw(struct hisi_hba *hisi_hba, int phy_no) { struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no]; @@ -2857,6 +2869,87 @@ static int hisi_sas_v2_init(struct hisi_hba *hisi_hba) return 0; } +static void interrupt_disable_v2_hw(struct hisi_hba *hisi_hba) +{ + struct platform_device *pdev = hisi_hba->pdev; + int i; + + for (i = 0; i < hisi_hba->queue_count; i++) + hisi_sas_write32(hisi_hba, OQ0_INT_SRC_MSK + 0x4 * i, 0x1); + + hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK1, 0xffffffff); + hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK2, 0xffffffff); + hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, 0xffffffff); + hisi_sas_write32(hisi_hba, SAS_ECC_INTR_MSK, 0xffffffff); + + for (i = 0; i < hisi_hba->n_phy; i++) { + hisi_sas_phy_write32(hisi_hba, i, CHL_INT1_MSK, 0xffffffff); + hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0xffffffff); + } + + for (i = 0; i < 128; i++) + synchronize_irq(platform_get_irq(pdev, i)); +} + +static int soft_reset_v2_hw(struct hisi_hba *hisi_hba) +{ + struct device *dev = &hisi_hba->pdev->dev; + u32 old_state, state; + int rc, cnt; + int phy_no; + + old_state = hisi_sas_read32(hisi_hba, PHY_STATE); + + interrupt_disable_v2_hw(hisi_hba); + hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE, 0x0); + + stop_phys_v2_hw(hisi_hba); + + mdelay(10); + + hisi_sas_write32(hisi_hba, AXI_MASTER_CFG_BASE + AM_CTRL_GLOBAL, 0x1); + + /* wait until bus idle */ + cnt = 0; + while (1) { + u32 status = hisi_sas_read32_relaxed(hisi_hba, + AXI_MASTER_CFG_BASE + AM_CURR_TRANS_RETURN); + + if (status == 0x3) + break; + + udelay(10); + if (cnt++ > 10) { + dev_info(dev, "wait axi bus state to idle timeout!\n"); + return -1; + } + } + + hisi_sas_init_mem(hisi_hba); + + rc = hw_init_v2_hw(hisi_hba); + if (rc) + return rc; + + /* Re-enable the PHYs */ + for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++) { + struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no]; + struct asd_sas_phy *sas_phy = &phy->sas_phy; + + if (sas_phy->enabled) + start_phy_v2_hw(hisi_hba, phy_no); + } + + /* Wait for the PHYs to come up and read the PHY state */ + msleep(1000); + + state = hisi_sas_read32(hisi_hba, PHY_STATE); + + hisi_sas_rescan_topology(hisi_hba, old_state, state); + + return 0; +} + static const struct hisi_sas_hw hisi_sas_v2_hw = { .hw_init = hisi_sas_v2_init, .setup_itct = setup_itct_v2_hw, @@ -2879,6 +2972,7 @@ static const struct hisi_sas_hw hisi_sas_v2_hw = { .phy_get_max_linkrate = phy_get_max_linkrate_v2_hw, .max_command_entries = HISI_SAS_COMMAND_ENTRIES_V2_HW, .complete_hdr_size = sizeof(struct hisi_sas_complete_v2_hdr), + .soft_reset = soft_reset_v2_hw, }; static int hisi_sas_v2_probe(struct platform_device *pdev) -- cgit v1.2.3 From 396b80448feed4636cb2b5a5bf7d26eaf6e000a7 Mon Sep 17 00:00:00 2001 From: John Garry Date: Thu, 23 Mar 2017 01:25:19 +0800 Subject: scsi: hisi_sas: move PHY init to hisi_sas_scan_start() Relocate the PHY init code from LLDD hw init path to hisi_sas_scan_start(). Signed-off-by: John Garry Signed-off-by: Xiang Chen Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas.h | 2 +- drivers/scsi/hisi_sas/hisi_sas_main.c | 9 +++------ drivers/scsi/hisi_sas/hisi_sas_v1_hw.c | 3 +-- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 3 +-- 4 files changed, 6 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index fd76a02873a5..2135de9a654b 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -167,6 +167,7 @@ struct hisi_sas_hw { 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 (*phys_init)(struct hisi_hba *hisi_hba); void (*phy_enable)(struct hisi_hba *hisi_hba, int phy_no); void (*phy_disable)(struct hisi_hba *hisi_hba, int phy_no); void (*phy_hard_reset)(struct hisi_hba *hisi_hba, int phy_no); @@ -195,7 +196,6 @@ struct hisi_hba { u8 sas_addr[SAS_ADDR_SIZE]; int n_phy; - int scan_finished; spinlock_t lock; struct timer_list timer; diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index cbaef90e584d..b86a22878609 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -493,12 +493,8 @@ static int hisi_sas_slave_configure(struct scsi_device *sdev) static void hisi_sas_scan_start(struct Scsi_Host *shost) { struct hisi_hba *hisi_hba = shost_priv(shost); - int i; - - for (i = 0; i < hisi_hba->n_phy; ++i) - hisi_sas_bytes_dmaed(hisi_hba, i); - hisi_hba->scan_finished = 1; + hisi_hba->hw->phys_init(hisi_hba); } static int hisi_sas_scan_finished(struct Scsi_Host *shost, unsigned long time) @@ -506,7 +502,8 @@ static int hisi_sas_scan_finished(struct Scsi_Host *shost, unsigned long time) struct hisi_hba *hisi_hba = shost_priv(shost); struct sas_ha_struct *sha = &hisi_hba->sha; - if (hisi_hba->scan_finished == 0) + /* Wait for PHY up interrupt to occur */ + if (time < HZ) return 0; sas_drain_work(sha); diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c index 022ad10e102c..43988eb04028 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c @@ -1847,8 +1847,6 @@ static int hisi_sas_v1_init(struct hisi_hba *hisi_hba) if (rc) return rc; - phys_init_v1_hw(hisi_hba); - return 0; } @@ -1862,6 +1860,7 @@ static const struct hisi_sas_hw hisi_sas_v1_hw = { .get_free_slot = get_free_slot_v1_hw, .start_delivery = start_delivery_v1_hw, .slot_complete = slot_complete_v1_hw, + .phys_init = phys_init_v1_hw, .phy_enable = enable_phy_v1_hw, .phy_disable = disable_phy_v1_hw, .phy_hard_reset = phy_hard_reset_v1_hw, diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 53651cfd9da1..73e4f660ebf9 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -2864,8 +2864,6 @@ static int hisi_sas_v2_init(struct hisi_hba *hisi_hba) if (rc) return rc; - phys_init_v2_hw(hisi_hba); - return 0; } @@ -2965,6 +2963,7 @@ static const struct hisi_sas_hw hisi_sas_v2_hw = { .get_free_slot = get_free_slot_v2_hw, .start_delivery = start_delivery_v2_hw, .slot_complete = slot_complete_v2_hw, + .phys_init = phys_init_v2_hw, .phy_enable = enable_phy_v2_hw, .phy_disable = disable_phy_v2_hw, .phy_hard_reset = phy_hard_reset_v2_hw, -- cgit v1.2.3 From 7c594f0407de5d3c76e281aaedfcb441b5a5c776 Mon Sep 17 00:00:00 2001 From: Xiang Chen Date: Thu, 23 Mar 2017 01:25:20 +0800 Subject: scsi: hisi_sas: add softreset function for SATA disk Add softreset to clear IO after internal abort device for SATA disk. The SATA error handling for the controller is based on device internal abort and softreset function. The controller does not support internal abort for single IO, so we need to execute internal abort for device. Signed-off-by: Xiang Chen Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/Kconfig | 2 +- drivers/scsi/hisi_sas/hisi_sas_main.c | 70 ++++++++++++++++++++++++++++++++-- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 3 +- 3 files changed, 69 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/hisi_sas/Kconfig b/drivers/scsi/hisi_sas/Kconfig index d1dd1616f983..ded2c201071d 100644 --- a/drivers/scsi/hisi_sas/Kconfig +++ b/drivers/scsi/hisi_sas/Kconfig @@ -2,7 +2,7 @@ config SCSI_HISI_SAS tristate "HiSilicon SAS" depends on HAS_DMA && HAS_IOMEM depends on ARM64 || COMPILE_TEST - select SCSI_SAS_LIBSAS + depends on SCSI_SAS_ATA select BLK_DEV_INTEGRITY help This driver supports HiSilicon's SAS HBA diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index b86a22878609..9d9f305e3604 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -21,6 +21,7 @@ static int hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba, struct domain_device *device, int abort_flag, int tag); +static int hisi_sas_softreset_ata_disk(struct domain_device *device); static struct hisi_hba *dev_to_hisi_hba(struct domain_device *device) { @@ -720,7 +721,12 @@ static int hisi_sas_exec_internal_tmf_task(struct domain_device *device, task->dev = device; task->task_proto = device->tproto; - memcpy(&task->ssp_task, parameter, para_len); + if (dev_is_sata(device)) { + task->ata_task.device_control_reg_update = 1; + memcpy(&task->ata_task.fis, parameter, para_len); + } else { + memcpy(&task->ssp_task, parameter, para_len); + } task->task_done = hisi_sas_task_done; task->slow_task->timer.data = (unsigned long) task; @@ -742,8 +748,7 @@ static int hisi_sas_exec_internal_tmf_task(struct domain_device *device, /* Even 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, "abort tmf: TMF task[%d] timeout\n", - tmf->tag_of_task_to_be_managed); + dev_err(dev, "abort tmf: TMF task timeout\n"); if (task->lldd_task) { struct hisi_sas_slot *slot = task->lldd_task; @@ -803,6 +808,63 @@ ex_err: return res; } +static void hisi_sas_fill_ata_reset_cmd(struct ata_device *dev, + bool reset, int pmp, u8 *fis) +{ + struct ata_taskfile tf; + + ata_tf_init(dev, &tf); + if (reset) + tf.ctl |= ATA_SRST; + else + tf.ctl &= ~ATA_SRST; + tf.command = ATA_CMD_DEV_RESET; + ata_tf_to_fis(&tf, pmp, 0, fis); +} + +static int hisi_sas_softreset_ata_disk(struct domain_device *device) +{ + u8 fis[20] = {0}; + struct ata_port *ap = device->sata_dev.ap; + struct ata_link *link; + int rc = TMF_RESP_FUNC_FAILED; + struct hisi_hba *hisi_hba = dev_to_hisi_hba(device); + struct device *dev = &hisi_hba->pdev->dev; + int s = sizeof(struct host_to_dev_fis); + unsigned long flags; + + ata_for_each_link(link, ap, EDGE) { + int pmp = sata_srst_pmp(link); + + hisi_sas_fill_ata_reset_cmd(link->device, 1, pmp, fis); + rc = hisi_sas_exec_internal_tmf_task(device, fis, s, NULL); + if (rc != TMF_RESP_FUNC_COMPLETE) + break; + } + + if (rc == TMF_RESP_FUNC_COMPLETE) { + ata_for_each_link(link, ap, EDGE) { + int pmp = sata_srst_pmp(link); + + hisi_sas_fill_ata_reset_cmd(link->device, 0, pmp, fis); + rc = hisi_sas_exec_internal_tmf_task(device, fis, + s, NULL); + if (rc != TMF_RESP_FUNC_COMPLETE) + dev_err(dev, "ata disk de-reset failed\n"); + } + } else { + dev_err(dev, "ata disk reset failed\n"); + } + + if (rc == TMF_RESP_FUNC_COMPLETE) { + spin_lock_irqsave(&hisi_hba->lock, flags); + hisi_sas_release_task(hisi_hba, device); + spin_unlock_irqrestore(&hisi_hba->lock, flags); + } + + return rc; +} + static int hisi_sas_debug_issue_ssp_tmf(struct domain_device *device, u8 *lun, struct hisi_sas_tmf_task *tmf) { @@ -908,7 +970,7 @@ static int hisi_sas_abort_task(struct sas_task *task) if (task->dev->dev_type == SAS_SATA_DEV) { hisi_sas_internal_task_abort(hisi_hba, device, HISI_SAS_INT_ABT_DEV, 0); - rc = TMF_RESP_FUNC_COMPLETE; + rc = hisi_sas_softreset_ata_disk(device); } } else if (task->task_proto & SAS_PROTOCOL_SMP) { /* SMP */ diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 73e4f660ebf9..401e5c664aa2 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -1961,7 +1961,8 @@ static int prep_ata_v2_hw(struct hisi_hba *hisi_hba, dw1 &= ~CMD_HDR_DIR_MSK; } - if (0 == task->ata_task.fis.command) + if ((task->ata_task.fis.command == ATA_CMD_DEV_RESET) && + (task->ata_task.fis.control & ATA_SRST)) dw1 |= 1 << CMD_HDR_RESET_OFF; dw1 |= (get_ata_protocol(task->ata_task.fis.command, task->data_dir)) -- cgit v1.2.3 From 405314df566c6168715413db682adeba297fd684 Mon Sep 17 00:00:00 2001 From: John Garry Date: Thu, 23 Mar 2017 01:25:21 +0800 Subject: scsi: hisi_sas: remove hisi_sas_port_deformed() Currently when a root PHY is deformed from a asd_sas_port we try to release the slots in the LLDD, and fail. Regardless, it is not right to release this early. This patch removes the deformed function. As it was before, port deformation is still done in hisi_sas_phy_down(). It would be nice to actually remove the hisi_sas_port_{de}formed() pair, however we cannot as we need to know the asd_sas_port index libsas has associated with an asd_sas_phy. The hw does actually generate a port id for a PHY, but this seems to a random number, so ignored for this purpose. This patch also changes the code to link slots to the hisi_sas_device, and not hisi_sas_port. Signed-off-by: John Garry Signed-off-by: Xiang Chen Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas.h | 4 +- drivers/scsi/hisi_sas/hisi_sas_main.c | 85 ++++++++++++++-------------------- drivers/scsi/hisi_sas/hisi_sas_v1_hw.c | 9 ++-- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 13 +++--- 4 files changed, 46 insertions(+), 65 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index 2135de9a654b..6aa0b62fea86 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -91,7 +91,6 @@ struct hisi_sas_port { struct asd_sas_port sas_port; u8 port_attached; u8 id; /* from hw */ - struct list_head list; }; struct hisi_sas_cq { @@ -114,6 +113,7 @@ struct hisi_sas_device { u64 attached_phy; u64 device_id; atomic64_t running_req; + struct list_head list; u8 dev_status; }; @@ -166,7 +166,7 @@ struct hisi_sas_hw { 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); + struct hisi_sas_slot *slot); void (*phys_init)(struct hisi_hba *hisi_hba); void (*phy_enable)(struct hisi_hba *hisi_hba, int phy_no); void (*phy_disable)(struct hisi_hba *hisi_hba, int phy_no); diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 9d9f305e3604..f64c1b6a4a76 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -308,7 +308,7 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba, goto err_out_command_table; } - list_add_tail(&slot->entry, &port->list); + list_add_tail(&slot->entry, &sas_dev->list); spin_lock(&task->task_state_lock); task->task_state_flags |= SAS_TASK_AT_INITIATOR; spin_unlock(&task->task_state_lock); @@ -424,6 +424,7 @@ static struct hisi_sas_device *hisi_sas_alloc_dev(struct domain_device *device) sas_dev->dev_type = device->dev_type; sas_dev->hisi_hba = hisi_hba; sas_dev->sas_device = device; + INIT_LIST_HEAD(&hisi_hba->devices[i].list); break; } } @@ -568,63 +569,55 @@ static void hisi_sas_port_notify_formed(struct asd_sas_phy *sas_phy) spin_unlock_irqrestore(&hisi_hba->lock, flags); } -static void hisi_sas_do_release_task(struct hisi_hba *hisi_hba, int phy_no, - struct domain_device *device) +static void hisi_sas_do_release_task(struct hisi_hba *hisi_hba, + struct sas_task *task, + struct hisi_sas_slot *slot) { - struct hisi_sas_phy *phy; - struct hisi_sas_port *port; - struct hisi_sas_slot *slot, *slot2; - struct device *dev = &hisi_hba->pdev->dev; + struct task_status_struct *ts; + unsigned long flags; - phy = &hisi_hba->phy[phy_no]; - port = phy->port; - if (!port) + if (!task) return; - list_for_each_entry_safe(slot, slot2, &port->list, entry) { - struct sas_task *task; - - task = slot->task; - if (device && task->dev != device) - continue; - - dev_info(dev, "Release slot [%d:%d], task [%p]:\n", - slot->dlvry_queue, slot->dlvry_queue_slot, task); - hisi_hba->hw->slot_complete(hisi_hba, slot, 1); - } -} + ts = &task->task_status; -static void hisi_sas_port_notify_deformed(struct asd_sas_phy *sas_phy) -{ - struct domain_device *device; - struct hisi_sas_phy *phy = sas_phy->lldd_phy; - struct asd_sas_port *sas_port = sas_phy->port; + ts->resp = SAS_TASK_COMPLETE; + ts->stat = SAS_ABORTED_TASK; + spin_lock_irqsave(&task->task_state_lock, flags); + task->task_state_flags &= + ~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR); + task->task_state_flags |= SAS_TASK_STATE_DONE; + spin_unlock_irqrestore(&task->task_state_lock, flags); - list_for_each_entry(device, &sas_port->dev_list, dev_list_node) - hisi_sas_do_release_task(phy->hisi_hba, sas_phy->id, device); + hisi_sas_slot_task_free(hisi_hba, task, slot); } +/* hisi_hba.lock should be locked */ static void hisi_sas_release_task(struct hisi_hba *hisi_hba, struct domain_device *device) { - struct asd_sas_port *port = device->port; - struct asd_sas_phy *sas_phy; + struct hisi_sas_slot *slot, *slot2; + struct hisi_sas_device *sas_dev = device->lldd_dev; - list_for_each_entry(sas_phy, &port->phy_list, port_phy_el) - hisi_sas_do_release_task(hisi_hba, sas_phy->id, device); + list_for_each_entry_safe(slot, slot2, &sas_dev->list, entry) + hisi_sas_do_release_task(hisi_hba, slot->task, slot); } static void hisi_sas_release_tasks(struct hisi_hba *hisi_hba) { + struct hisi_sas_device *sas_dev; + struct domain_device *device; int i; - for (i = 0; i < HISI_SAS_MAX_PHYS; i++) { - struct hisi_sas_phy *phy = &hisi_hba->phy[i]; - struct asd_sas_phy *sas_phy = &phy->sas_phy; + for (i = 0; i < HISI_SAS_MAX_DEVICES; i++) { + sas_dev = &hisi_hba->devices[i]; + device = sas_dev->sas_device; - if (!sas_phy->port) + if ((sas_dev->dev_type == SAS_PHY_UNUSED) || + !device) continue; - hisi_sas_port_notify_deformed(sas_phy); + + hisi_sas_release_task(hisi_hba, device); } } @@ -958,7 +951,7 @@ static int hisi_sas_abort_task(struct sas_task *task) slot = &hisi_hba->slot_info [tmf_task.tag_of_task_to_be_managed]; spin_lock_irqsave(&hisi_hba->lock, flags); - hisi_hba->hw->slot_complete(hisi_hba, slot, 1); + hisi_hba->hw->slot_complete(hisi_hba, slot); spin_unlock_irqrestore(&hisi_hba->lock, flags); } } @@ -1149,11 +1142,8 @@ hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, u64 device_id, 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); + + list_add_tail(&slot->entry, &sas_dev->list); spin_lock(&task->task_state_lock); task->task_state_flags |= SAS_TASK_AT_INITIATOR; spin_unlock(&task->task_state_lock); @@ -1259,11 +1249,6 @@ static void hisi_sas_port_formed(struct asd_sas_phy *sas_phy) hisi_sas_port_notify_formed(sas_phy); } -static void hisi_sas_port_deformed(struct asd_sas_phy *sas_phy) -{ - hisi_sas_port_notify_deformed(sas_phy); -} - static void hisi_sas_phy_disconnected(struct hisi_sas_phy *phy) { phy->phy_attached = 0; @@ -1369,7 +1354,6 @@ static struct sas_domain_function_template hisi_sas_transport_ops = { .lldd_lu_reset = hisi_sas_lu_reset, .lldd_query_task = hisi_sas_query_task, .lldd_port_formed = hisi_sas_port_formed, - .lldd_port_deformed = hisi_sas_port_deformed, }; void hisi_sas_init_mem(struct hisi_hba *hisi_hba) @@ -1414,7 +1398,6 @@ static int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost) hisi_sas_phy_init(hisi_hba, i); hisi_hba->port[i].port_attached = 0; hisi_hba->port[i].id = -1; - INIT_LIST_HEAD(&hisi_hba->port[i].list); } for (i = 0; i < HISI_SAS_MAX_DEVICES; i++) { diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c index 43988eb04028..2f3e87709ac5 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c @@ -1277,7 +1277,7 @@ static void slot_err_v1_hw(struct hisi_hba *hisi_hba, } static int slot_complete_v1_hw(struct hisi_hba *hisi_hba, - struct hisi_sas_slot *slot, int abort) + struct hisi_sas_slot *slot) { struct sas_task *task = slot->task; struct hisi_sas_device *sas_dev; @@ -1307,9 +1307,8 @@ static int slot_complete_v1_hw(struct hisi_hba *hisi_hba, memset(ts, 0, sizeof(*ts)); ts->resp = SAS_TASK_COMPLETE; - if (unlikely(!sas_dev || abort)) { - if (!sas_dev) - dev_dbg(dev, "slot complete: port has not device\n"); + if (unlikely(!sas_dev)) { + dev_dbg(dev, "slot complete: port has no device\n"); ts->stat = SAS_PHY_DOWN; goto out; } @@ -1622,7 +1621,7 @@ static irqreturn_t cq_interrupt_v1_hw(int irq, void *p) */ slot->cmplt_queue_slot = rd_point; slot->cmplt_queue = queue; - slot_complete_v1_hw(hisi_hba, slot, 0); + slot_complete_v1_hw(hisi_hba, slot); if (++rd_point >= HISI_SAS_QUEUE_SLOTS) rd_point = 0; diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 401e5c664aa2..b9d51324e406 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -625,6 +625,7 @@ hisi_sas_device *alloc_dev_quirk_v2_hw(struct domain_device *device) sas_dev->dev_type = device->dev_type; sas_dev->hisi_hba = hisi_hba; sas_dev->sas_device = device; + INIT_LIST_HEAD(&hisi_hba->devices[i].list); break; } } @@ -1724,8 +1725,7 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba, } static int -slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot, - int abort) +slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot) { struct sas_task *task = slot->task; struct hisi_sas_device *sas_dev; @@ -1752,9 +1752,8 @@ slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot, memset(ts, 0, sizeof(*ts)); ts->resp = SAS_TASK_COMPLETE; - if (unlikely(!sas_dev || abort)) { - if (!sas_dev) - dev_dbg(dev, "slot complete: port has not device\n"); + if (unlikely(!sas_dev)) { + dev_dbg(dev, "slot complete: port has no device\n"); ts->stat = SAS_PHY_DOWN; goto out; } @@ -2615,7 +2614,7 @@ static void cq_tasklet_v2_hw(unsigned long val) slot = &hisi_hba->slot_info[iptt]; slot->cmplt_queue_slot = rd_point; slot->cmplt_queue = queue; - slot_complete_v2_hw(hisi_hba, slot, 0); + slot_complete_v2_hw(hisi_hba, slot); act_tmp &= ~(1 << ncq_tag_count); ncq_tag_count = ffs(act_tmp); @@ -2625,7 +2624,7 @@ static void cq_tasklet_v2_hw(unsigned long val) slot = &hisi_hba->slot_info[iptt]; slot->cmplt_queue_slot = rd_point; slot->cmplt_queue = queue; - slot_complete_v2_hw(hisi_hba, slot, 0); + slot_complete_v2_hw(hisi_hba, slot); } if (++rd_point >= HISI_SAS_QUEUE_SLOTS) -- cgit v1.2.3 From ddabca216c7fb1af8e4edde9fc981992e26e50fc Mon Sep 17 00:00:00 2001 From: John Garry Date: Thu, 23 Mar 2017 01:25:22 +0800 Subject: scsi: hisi_sas: error hisi_sas_task_prep() when port down When sas_port is NULL, then return SAS_PHY_DOWN. In addition, when the sas_dev is gone then explicitly return SAS_PHY_DOWN. Signed-off-by: John Garry Signed-off-by: Xiang Chen Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index f64c1b6a4a76..7c1fb75d11e6 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -200,7 +200,7 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba, */ if (device->dev_type != SAS_SATA_DEV) task->task_done(task); - return 0; + return SAS_PHY_DOWN; } if (DEV_IS_GONE(sas_dev)) { @@ -211,8 +211,7 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba, dev_info(dev, "task prep: device %016llx not ready\n", SAS_ADDR(device->sas_addr)); - rc = SAS_PHY_DOWN; - return rc; + return SAS_PHY_DOWN; } port = to_hisi_sas_port(sas_port); -- cgit v1.2.3 From b4c67a6ca790ca3b8caa1e6582d61ccd5bd174e5 Mon Sep 17 00:00:00 2001 From: John Garry Date: Thu, 23 Mar 2017 01:25:23 +0800 Subject: scsi: hisi_sas: only reset link for PHY_FUNC_LINK_RESET We currently do a hard reset for a link reset. Change this to do a link reset only. Signed-off-by: John Garry Signed-off-by: Xiang Chen Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 7c1fb75d11e6..00068d25ba48 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -659,8 +659,9 @@ static int hisi_sas_control_phy(struct asd_sas_phy *sas_phy, enum phy_func func, break; case PHY_FUNC_LINK_RESET: + hisi_hba->hw->phy_disable(hisi_hba, phy_no); + msleep(100); hisi_hba->hw->phy_enable(hisi_hba, phy_no); - hisi_hba->hw->phy_hard_reset(hisi_hba, phy_no); break; case PHY_FUNC_DISABLE: -- cgit v1.2.3 From fc8669514426b21b7aaa73e40a22fb1e1eb39259 Mon Sep 17 00:00:00 2001 From: Xiang Chen Date: Thu, 23 Mar 2017 01:25:24 +0800 Subject: scsi: hisi_sas: modify error handling for v2 hw For error codes which need abort-and-retry, simulate IO timeout and let SCSI+ATA layers process those errors. Previously for SSP, we should try to abort the IO in the LLDD and then pass back to upper layer, but sometimes this would also error. So Instead of adding special error handling for this scenario in the LLDD, allow the upper layer to handle completely. No performance hit is seen by taking this approach. Signed-off-by: Xiang Chen Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index b9d51324e406..a35f8811edcb 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -1747,7 +1747,6 @@ slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot) task->task_state_flags &= ~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR); - task->task_state_flags |= SAS_TASK_STATE_DONE; memset(ts, 0, sizeof(*ts)); ts->resp = SAS_TASK_COMPLETE; @@ -1786,11 +1785,9 @@ slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot) (!(complete_hdr->dw0 & CMPLT_HDR_RSPNS_XFRD_MSK))) { slot_err_v2_hw(hisi_hba, task, slot); - if (unlikely(slot->abort)) { - queue_work(hisi_hba->wq, &slot->abort_slot); - /* immediately return and do not complete */ + + if (unlikely(slot->abort)) return ts->stat; - } goto out; } @@ -1842,7 +1839,7 @@ slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot) } out: - + task->task_state_flags |= SAS_TASK_STATE_DONE; hisi_sas_slot_task_free(hisi_hba, task, slot); sts = ts->stat; -- cgit v1.2.3 From c35279f2f1eef8f7f91b2b529fc22f01b25a244f Mon Sep 17 00:00:00 2001 From: John Garry Date: Thu, 23 Mar 2017 01:25:25 +0800 Subject: scsi: hisi_sas: modify hisi_sas_abort_task() for SSP Currently an internal abort is executed regardless of the result of the TMF. We should also check the result of the internal abort to see if we should free the slot. So change the status code STAT_IO_COMPLETE to TMF_RESP_FUNC_SUCC, meaning the slot has been successfully aborted. Signed-off-by: John Garry Signed-off-by: Xiang Chen Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 28 ++++++++++++++++++---------- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 2 +- 2 files changed, 19 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 00068d25ba48..36d4e5a6d2c9 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -935,6 +935,7 @@ static int hisi_sas_abort_task(struct sas_task *task) struct scsi_cmnd *cmnd = task->uldd_task; struct hisi_sas_slot *slot = task->lldd_task; u32 tag = slot->idx; + int rc2; int_to_scsilun(cmnd->device->lun, &lun); tmf_task.tmf = TMF_ABORT_TASK; @@ -943,21 +944,22 @@ static int hisi_sas_abort_task(struct sas_task *task) rc = hisi_sas_debug_issue_ssp_tmf(task->dev, lun.scsi_lun, &tmf_task); - /* if successful, clear the task and callback forwards.*/ - if (rc == TMF_RESP_FUNC_COMPLETE) { + rc2 = hisi_sas_internal_task_abort(hisi_hba, device, + HISI_SAS_INT_ABT_CMD, tag); + /* + * If the TMF finds that the IO is not in the device and also + * the internal abort does not succeed, then it is safe to + * free the slot. + * Note: if the internal abort succeeds then the slot + * will have already been completed + */ + if (rc == TMF_RESP_FUNC_COMPLETE && rc2 != TMF_RESP_FUNC_SUCC) { if (task->lldd_task) { - struct hisi_sas_slot *slot; - - slot = &hisi_hba->slot_info - [tmf_task.tag_of_task_to_be_managed]; spin_lock_irqsave(&hisi_hba->lock, flags); - hisi_hba->hw->slot_complete(hisi_hba, slot); + hisi_sas_do_release_task(hisi_hba, task, slot); spin_unlock_irqrestore(&hisi_hba->lock, flags); } } - - 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) { @@ -1220,6 +1222,12 @@ hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba, goto exit; } + if (task->task_status.resp == SAS_TASK_COMPLETE && + task->task_status.stat == TMF_RESP_FUNC_SUCC) { + res = TMF_RESP_FUNC_SUCC; + 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)) { diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index a35f8811edcb..ad5a7e697043 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -1766,7 +1766,7 @@ slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot) goto out; case STAT_IO_COMPLETE: /* internal abort command complete */ - ts->stat = TMF_RESP_FUNC_COMPLETE; + ts->stat = TMF_RESP_FUNC_SUCC; goto out; case STAT_IO_NO_DEVICE: ts->stat = TMF_RESP_FUNC_COMPLETE; -- cgit v1.2.3 From 055945df4c10eeb6057cf380906c9b88334dd63d Mon Sep 17 00:00:00 2001 From: John Garry Date: Thu, 23 Mar 2017 01:25:26 +0800 Subject: scsi: hisi_sas: hardreset for SATA disk in LU reset When issuing an LU reset for a SATA target, issue an internal abort and a hard reset. Signed-off-by: John Garry Signed-off-by: Xiang Chen Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 38 ++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 36d4e5a6d2c9..19f28927e768 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -1037,23 +1037,43 @@ static int hisi_sas_I_T_nexus_reset(struct domain_device *device) static int hisi_sas_lu_reset(struct domain_device *device, u8 *lun) { - struct hisi_sas_tmf_task tmf_task; struct hisi_sas_device *sas_dev = device->lldd_dev; struct hisi_hba *hisi_hba = dev_to_hisi_hba(device); struct device *dev = &hisi_hba->pdev->dev; unsigned long flags; int rc = TMF_RESP_FUNC_FAILED; - tmf_task.tmf = TMF_LU_RESET; sas_dev->dev_status = HISI_SAS_DEV_EH; - rc = hisi_sas_debug_issue_ssp_tmf(device, lun, &tmf_task); - if (rc == TMF_RESP_FUNC_COMPLETE) { - spin_lock_irqsave(&hisi_hba->lock, flags); - hisi_sas_release_task(hisi_hba, device); - spin_unlock_irqrestore(&hisi_hba->lock, flags); - } + if (dev_is_sata(device)) { + struct sas_phy *phy; + + /* Clear internal IO and then hardreset */ + rc = hisi_sas_internal_task_abort(hisi_hba, device, + HISI_SAS_INT_ABT_DEV, 0); + if (rc == TMF_RESP_FUNC_FAILED) + goto out; - /* If failed, fall-through I_T_Nexus reset */ + phy = sas_get_local_phy(device); + + rc = sas_phy_reset(phy, 1); + + if (rc == 0) { + spin_lock_irqsave(&hisi_hba->lock, flags); + hisi_sas_release_task(hisi_hba, device); + spin_unlock_irqrestore(&hisi_hba->lock, flags); + } + sas_put_local_phy(phy); + } else { + struct hisi_sas_tmf_task tmf_task = { .tmf = TMF_LU_RESET }; + + rc = hisi_sas_debug_issue_ssp_tmf(device, lun, &tmf_task); + if (rc == TMF_RESP_FUNC_COMPLETE) { + spin_lock_irqsave(&hisi_hba->lock, flags); + hisi_sas_release_task(hisi_hba, device); + spin_unlock_irqrestore(&hisi_hba->lock, flags); + } + } +out: dev_err(dev, "lu_reset: for device[%llx]:rc= %d\n", sas_dev->device_id, rc); return rc; -- cgit v1.2.3 From a305f33775c0b7202fe77cbd4cc3d7f2048efc52 Mon Sep 17 00:00:00 2001 From: John Garry Date: Thu, 23 Mar 2017 01:25:27 +0800 Subject: scsi: hisi_sas: check for SAS_TASK_STATE_ABORTED in slot complete Check in slot_complete_v2_hw() for whether a task has already been completed by upper layer. Signed-off-by: John Garry Reviewed-by: Xiang Chen Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index ad5a7e697043..f4d8200ae7e2 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -1737,6 +1737,7 @@ slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot) hisi_hba->complete_hdr[slot->cmplt_queue]; struct hisi_sas_complete_v2_hdr *complete_hdr = &complete_queue[slot->cmplt_queue_slot]; + int aborted; if (unlikely(!task || !task->lldd_task || !task->dev)) return -EINVAL; @@ -1745,12 +1746,21 @@ slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot) device = task->dev; sas_dev = device->lldd_dev; + spin_lock(&task->task_state_lock); + aborted = task->task_state_flags & SAS_TASK_STATE_ABORTED; task->task_state_flags &= ~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR); + spin_unlock(&task->task_state_lock); memset(ts, 0, sizeof(*ts)); ts->resp = SAS_TASK_COMPLETE; + if (unlikely(aborted)) { + ts->stat = SAS_ABORTED_TASK; + hisi_sas_slot_task_free(hisi_hba, task, slot); + return -1; + } + if (unlikely(!sas_dev)) { dev_dbg(dev, "slot complete: port has no device\n"); ts->stat = SAS_PHY_DOWN; -- cgit v1.2.3 From 6131243acd2c3aafa041935dcef44eb8255eeb46 Mon Sep 17 00:00:00 2001 From: Xiang Chen Date: Thu, 23 Mar 2017 01:25:28 +0800 Subject: scsi: hisi_sas: free slots after hardreset After hardreset, we clear up IOs of remote disks, so we need to free those slots in LLDD. Signed-off-by: Xiang Chen Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 19f28927e768..49cac22a83bd 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -1028,11 +1028,12 @@ static int hisi_sas_I_T_nexus_reset(struct domain_device *device) rc = hisi_sas_debug_I_T_nexus_reset(device); - spin_lock_irqsave(&hisi_hba->lock, flags); - hisi_sas_release_task(hisi_hba, device); - spin_unlock_irqrestore(&hisi_hba->lock, flags); - - return 0; + if (rc == TMF_RESP_FUNC_COMPLETE) { + spin_lock_irqsave(&hisi_hba->lock, flags); + hisi_sas_release_task(hisi_hba, device); + spin_unlock_irqrestore(&hisi_hba->lock, flags); + } + return rc; } static int hisi_sas_lu_reset(struct domain_device *device, u8 *lun) -- cgit v1.2.3 From 54c9dd2d26d0951891516a956893428feb9aea17 Mon Sep 17 00:00:00 2001 From: John Garry Date: Thu, 23 Mar 2017 01:25:29 +0800 Subject: scsi: hisi_sas: fix some sas_task.task_state_lock locking Some more locking needs to be added/modified for when read-modify-writing sas_task.task_state_flags. Note: since we can attempt to grab this lock in interrupt context we should use irq variant of spin_lock. Signed-off-by: John Garry Signed-off-by: Xiang Chen Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 13 ++++++------- drivers/scsi/hisi_sas/hisi_sas_v1_hw.c | 3 +++ drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 7 +++++-- 3 files changed, 14 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 49cac22a83bd..f9ea5ccd1e84 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -188,6 +188,7 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba, struct asd_sas_port *sas_port = device->port; struct device *dev = &hisi_hba->pdev->dev; int dlvry_queue_slot, dlvry_queue, n_elem = 0, rc, slot_idx; + unsigned long flags; if (!sas_port) { struct task_status_struct *ts = &task->task_status; @@ -308,9 +309,9 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba, } list_add_tail(&slot->entry, &sas_dev->list); - spin_lock(&task->task_state_lock); + spin_lock_irqsave(&task->task_state_lock, flags); task->task_state_flags |= SAS_TASK_AT_INITIATOR; - spin_unlock(&task->task_state_lock); + spin_unlock_irqrestore(&task->task_state_lock, flags); hisi_hba->slot_prep = slot; @@ -922,14 +923,11 @@ static int hisi_sas_abort_task(struct sas_task *task) return TMF_RESP_FUNC_FAILED; } - spin_lock_irqsave(&task->task_state_lock, flags); if (task->task_state_flags & SAS_TASK_STATE_DONE) { - spin_unlock_irqrestore(&task->task_state_lock, flags); rc = TMF_RESP_FUNC_COMPLETE; goto out; } - spin_unlock_irqrestore(&task->task_state_lock, flags); sas_dev->dev_status = HISI_SAS_DEV_EH; if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SSP) { struct scsi_cmnd *cmnd = task->uldd_task; @@ -1127,6 +1125,7 @@ hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, u64 device_id, struct asd_sas_port *sas_port = device->port; struct hisi_sas_cmd_hdr *cmd_hdr_base; int dlvry_queue_slot, dlvry_queue, n_elem = 0, rc, slot_idx; + unsigned long flags; if (unlikely(test_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags))) return -EINVAL; @@ -1167,9 +1166,9 @@ hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, u64 device_id, list_add_tail(&slot->entry, &sas_dev->list); - spin_lock(&task->task_state_lock); + spin_lock_irqsave(&task->task_state_lock, flags); task->task_state_flags |= SAS_TASK_AT_INITIATOR; - spin_unlock(&task->task_state_lock); + spin_unlock_irqrestore(&task->task_state_lock, flags); hisi_hba->slot_prep = slot; diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c index 2f3e87709ac5..fc1c1b2c1a19 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c @@ -1288,6 +1288,7 @@ static int slot_complete_v1_hw(struct hisi_hba *hisi_hba, struct hisi_sas_complete_v1_hdr *complete_queue = hisi_hba->complete_hdr[slot->cmplt_queue]; struct hisi_sas_complete_v1_hdr *complete_hdr; + unsigned long flags; u32 cmplt_hdr_data; complete_hdr = &complete_queue[slot->cmplt_queue_slot]; @@ -1300,9 +1301,11 @@ static int slot_complete_v1_hw(struct hisi_hba *hisi_hba, device = task->dev; sas_dev = device->lldd_dev; + spin_lock_irqsave(&task->task_state_lock, flags); task->task_state_flags &= ~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR); task->task_state_flags |= SAS_TASK_STATE_DONE; + spin_unlock_irqrestore(&task->task_state_lock, flags); memset(ts, 0, sizeof(*ts)); ts->resp = SAS_TASK_COMPLETE; diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index f4d8200ae7e2..2b6e64c953b2 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -1737,6 +1737,7 @@ slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot) hisi_hba->complete_hdr[slot->cmplt_queue]; struct hisi_sas_complete_v2_hdr *complete_hdr = &complete_queue[slot->cmplt_queue_slot]; + unsigned long flags; int aborted; if (unlikely(!task || !task->lldd_task || !task->dev)) @@ -1746,11 +1747,11 @@ slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot) device = task->dev; sas_dev = device->lldd_dev; - spin_lock(&task->task_state_lock); + spin_lock_irqsave(&task->task_state_lock, flags); aborted = task->task_state_flags & SAS_TASK_STATE_ABORTED; task->task_state_flags &= ~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR); - spin_unlock(&task->task_state_lock); + spin_unlock_irqrestore(&task->task_state_lock, flags); memset(ts, 0, sizeof(*ts)); ts->resp = SAS_TASK_COMPLETE; @@ -1849,7 +1850,9 @@ slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot) } out: + spin_lock_irqsave(&task->task_state_lock, flags); task->task_state_flags |= SAS_TASK_STATE_DONE; + spin_unlock_irqrestore(&task->task_state_lock, flags); hisi_sas_slot_task_free(hisi_hba, task, slot); sts = ts->stat; -- cgit v1.2.3 From 6fcdda805114f9ff588c08cefe6758b62bfcb9fc Mon Sep 17 00:00:00 2001 From: John Garry Date: Thu, 23 Mar 2017 01:25:30 +0800 Subject: scsi: hisi_sas: remove task free'ing for timeouts When a TMF or internal abort times-out, do not free slot. We expect this to be done upon later escalated error handling. Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index f9ea5ccd1e84..3d63a24fea54 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -743,14 +743,6 @@ static int hisi_sas_exec_internal_tmf_task(struct domain_device *device, if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) { if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) { dev_err(dev, "abort tmf: TMF task timeout\n"); - if (task->lldd_task) { - struct hisi_sas_slot *slot = - task->lldd_task; - - hisi_sas_slot_task_free(hisi_hba, - task, slot); - } - goto ex_err; } } @@ -1248,15 +1240,10 @@ hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba, goto exit; } - /* TMF timed out, return direct. */ + /* Internal abort timed out */ 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); - } } } -- cgit v1.2.3 From 634a9585f49c7c92d6416128a18ea134eb9ac381 Mon Sep 17 00:00:00 2001 From: Xiang Chen Date: Thu, 23 Mar 2017 01:25:31 +0800 Subject: scsi: hisi_sas: process error codes according to their priority There are some rules to decide which error code has the high priority when errors happen together: (1) Error phase of CQ decides the error happens on RX or TX; (2) For TX error, when DMA/TRANS TX error happen simultaneously, the priority of DMA TX error is higher than TRANS TX error, so for the priority of TX error: DW2 (DMA TX part) > DW0; (3) For RX error, when TRANS/DMA/SIPC RX error happen simultaneously, the priority of TRANS RX error is higher than DMA and SIPC RX error, and we should also keep the rules (the priority of DW3 > DW2), so for the priority of RX error: DW1 > DW3 > DW2(SIPC RX part); (4) There are also a priority we should keep in the same error type. So, modify slot error code to handle this. In addition to this, some some error codes are modified according to recommendation from SoC designer. Signed-off-by: Xiang Chen Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 553 ++++++++++++++++++++++++--------- 1 file changed, 398 insertions(+), 155 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 2b6e64c953b2..66a458b83dac 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -313,6 +313,8 @@ /* Completion header */ /* dw0 */ +#define CMPLT_HDR_ERR_PHASE_OFF 2 +#define CMPLT_HDR_ERR_PHASE_MSK (0xff << CMPLT_HDR_ERR_PHASE_OFF) #define CMPLT_HDR_RSPNS_XFRD_OFF 10 #define CMPLT_HDR_RSPNS_XFRD_MSK (0x1 << CMPLT_HDR_RSPNS_XFRD_OFF) #define CMPLT_HDR_ERX_OFF 12 @@ -389,10 +391,10 @@ enum { enum { TRANS_TX_FAIL_BASE = 0x0, /* dw0 */ - TRANS_RX_FAIL_BASE = 0x100, /* dw1 */ - DMA_TX_ERR_BASE = 0x200, /* dw2 bit 15-0 */ - SIPC_RX_ERR_BASE = 0x300, /* dw2 bit 31-16*/ - DMA_RX_ERR_BASE = 0x400, /* dw3 */ + TRANS_RX_FAIL_BASE = 0x20, /* dw1 */ + DMA_TX_ERR_BASE = 0x40, /* dw2 bit 15-0 */ + SIPC_RX_ERR_BASE = 0x50, /* dw2 bit 31-16*/ + DMA_RX_ERR_BASE = 0x60, /* dw3 */ /* trans tx*/ TRANS_TX_OPEN_FAIL_WITH_IT_NEXUS_LOSS = TRANS_TX_FAIL_BASE, /* 0x0 */ @@ -432,97 +434,100 @@ enum { TRANS_TX_ERR_WITH_WAIT_RECV_TIMEOUT, /* 0x1f for sata/stp */ /* trans rx */ - TRANS_RX_ERR_WITH_RXFRAME_CRC_ERR = TRANS_RX_FAIL_BASE, /* 0x100 */ - TRANS_RX_ERR_WITH_RXFIS_8B10B_DISP_ERR, /* 0x101 for sata/stp */ - TRANS_RX_ERR_WITH_RXFRAME_HAVE_ERRPRM, /* 0x102 for ssp/smp */ - /*IO_ERR_WITH_RXFIS_8B10B_CODE_ERR, [> 0x102 <] for sata/stp */ - TRANS_RX_ERR_WITH_RXFIS_DECODE_ERROR, /* 0x103 for sata/stp */ - TRANS_RX_ERR_WITH_RXFIS_CRC_ERR, /* 0x104 for sata/stp */ - TRANS_RX_ERR_WITH_RXFRAME_LENGTH_OVERRUN, /* 0x105 for smp */ - /*IO_ERR_WITH_RXFIS_TX SYNCP, [> 0x105 <] for sata/stp */ - TRANS_RX_ERR_WITH_RXFIS_RX_SYNCP, /* 0x106 for sata/stp*/ - TRANS_RX_ERR_WITH_LINK_BUF_OVERRUN, /* 0x107 */ - TRANS_RX_ERR_WITH_BREAK_TIMEOUT, /* 0x108 */ - TRANS_RX_ERR_WITH_BREAK_REQUEST, /* 0x109 */ - TRANS_RX_ERR_WITH_BREAK_RECEVIED, /* 0x10a */ - RESERVED1, /* 0x10b */ - TRANS_RX_ERR_WITH_CLOSE_NORMAL, /* 0x10c */ - TRANS_RX_ERR_WITH_CLOSE_PHY_DISABLE, /* 0x10d */ - TRANS_RX_ERR_WITH_CLOSE_DWS_TIMEOUT, /* 0x10e */ - TRANS_RX_ERR_WITH_CLOSE_COMINIT, /* 0x10f */ - TRANS_RX_ERR_WITH_DATA_LEN0, /* 0x110 for ssp/smp */ - TRANS_RX_ERR_WITH_BAD_HASH, /* 0x111 for ssp */ - /*IO_RX_ERR_WITH_FIS_TOO_SHORT, [> 0x111 <] for sata/stp */ - TRANS_RX_XRDY_WLEN_ZERO_ERR, /* 0x112 for ssp*/ - /*IO_RX_ERR_WITH_FIS_TOO_LONG, [> 0x112 <] for sata/stp */ - TRANS_RX_SSP_FRM_LEN_ERR, /* 0x113 for ssp */ - /*IO_RX_ERR_WITH_SATA_DEVICE_LOST, [> 0x113 <] for sata */ - RESERVED2, /* 0x114 */ - RESERVED3, /* 0x115 */ - RESERVED4, /* 0x116 */ - RESERVED5, /* 0x117 */ - TRANS_RX_ERR_WITH_BAD_FRM_TYPE, /* 0x118 */ - TRANS_RX_SMP_FRM_LEN_ERR, /* 0x119 */ - TRANS_RX_SMP_RESP_TIMEOUT_ERR, /* 0x11a */ - RESERVED6, /* 0x11b */ - RESERVED7, /* 0x11c */ - RESERVED8, /* 0x11d */ - RESERVED9, /* 0x11e */ - TRANS_RX_R_ERR, /* 0x11f */ + TRANS_RX_ERR_WITH_RXFRAME_CRC_ERR = TRANS_RX_FAIL_BASE, /* 0x20 */ + TRANS_RX_ERR_WITH_RXFIS_8B10B_DISP_ERR, /* 0x21 for sata/stp */ + TRANS_RX_ERR_WITH_RXFRAME_HAVE_ERRPRM, /* 0x22 for ssp/smp */ + /*IO_ERR_WITH_RXFIS_8B10B_CODE_ERR, [> 0x22 <] for sata/stp */ + TRANS_RX_ERR_WITH_RXFIS_DECODE_ERROR, /* 0x23 for sata/stp */ + TRANS_RX_ERR_WITH_RXFIS_CRC_ERR, /* 0x24 for sata/stp */ + TRANS_RX_ERR_WITH_RXFRAME_LENGTH_OVERRUN, /* 0x25 for smp */ + /*IO_ERR_WITH_RXFIS_TX SYNCP, [> 0x25 <] for sata/stp */ + TRANS_RX_ERR_WITH_RXFIS_RX_SYNCP, /* 0x26 for sata/stp*/ + TRANS_RX_ERR_WITH_LINK_BUF_OVERRUN, /* 0x27 */ + TRANS_RX_ERR_WITH_BREAK_TIMEOUT, /* 0x28 */ + TRANS_RX_ERR_WITH_BREAK_REQUEST, /* 0x29 */ + TRANS_RX_ERR_WITH_BREAK_RECEVIED, /* 0x2a */ + RESERVED1, /* 0x2b */ + TRANS_RX_ERR_WITH_CLOSE_NORMAL, /* 0x2c */ + TRANS_RX_ERR_WITH_CLOSE_PHY_DISABLE, /* 0x2d */ + TRANS_RX_ERR_WITH_CLOSE_DWS_TIMEOUT, /* 0x2e */ + TRANS_RX_ERR_WITH_CLOSE_COMINIT, /* 0x2f */ + TRANS_RX_ERR_WITH_DATA_LEN0, /* 0x30 for ssp/smp */ + TRANS_RX_ERR_WITH_BAD_HASH, /* 0x31 for ssp */ + /*IO_RX_ERR_WITH_FIS_TOO_SHORT, [> 0x31 <] for sata/stp */ + TRANS_RX_XRDY_WLEN_ZERO_ERR, /* 0x32 for ssp*/ + /*IO_RX_ERR_WITH_FIS_TOO_LONG, [> 0x32 <] for sata/stp */ + TRANS_RX_SSP_FRM_LEN_ERR, /* 0x33 for ssp */ + /*IO_RX_ERR_WITH_SATA_DEVICE_LOST, [> 0x33 <] for sata */ + RESERVED2, /* 0x34 */ + RESERVED3, /* 0x35 */ + RESERVED4, /* 0x36 */ + RESERVED5, /* 0x37 */ + TRANS_RX_ERR_WITH_BAD_FRM_TYPE, /* 0x38 */ + TRANS_RX_SMP_FRM_LEN_ERR, /* 0x39 */ + TRANS_RX_SMP_RESP_TIMEOUT_ERR, /* 0x3a */ + RESERVED6, /* 0x3b */ + RESERVED7, /* 0x3c */ + RESERVED8, /* 0x3d */ + RESERVED9, /* 0x3e */ + TRANS_RX_R_ERR, /* 0x3f */ /* dma tx */ - DMA_TX_DIF_CRC_ERR = DMA_TX_ERR_BASE, /* 0x200 */ - DMA_TX_DIF_APP_ERR, /* 0x201 */ - DMA_TX_DIF_RPP_ERR, /* 0x202 */ - DMA_TX_DATA_SGL_OVERFLOW, /* 0x203 */ - DMA_TX_DIF_SGL_OVERFLOW, /* 0x204 */ - DMA_TX_UNEXP_XFER_ERR, /* 0x205 */ - DMA_TX_UNEXP_RETRANS_ERR, /* 0x206 */ - DMA_TX_XFER_LEN_OVERFLOW, /* 0x207 */ - DMA_TX_XFER_OFFSET_ERR, /* 0x208 */ - DMA_TX_RAM_ECC_ERR, /* 0x209 */ - DMA_TX_DIF_LEN_ALIGN_ERR, /* 0x20a */ + DMA_TX_DIF_CRC_ERR = DMA_TX_ERR_BASE, /* 0x40 */ + DMA_TX_DIF_APP_ERR, /* 0x41 */ + DMA_TX_DIF_RPP_ERR, /* 0x42 */ + DMA_TX_DATA_SGL_OVERFLOW, /* 0x43 */ + DMA_TX_DIF_SGL_OVERFLOW, /* 0x44 */ + DMA_TX_UNEXP_XFER_ERR, /* 0x45 */ + DMA_TX_UNEXP_RETRANS_ERR, /* 0x46 */ + DMA_TX_XFER_LEN_OVERFLOW, /* 0x47 */ + DMA_TX_XFER_OFFSET_ERR, /* 0x48 */ + DMA_TX_RAM_ECC_ERR, /* 0x49 */ + DMA_TX_DIF_LEN_ALIGN_ERR, /* 0x4a */ + DMA_TX_MAX_ERR_CODE, /* sipc rx */ - SIPC_RX_FIS_STATUS_ERR_BIT_VLD = SIPC_RX_ERR_BASE, /* 0x300 */ - SIPC_RX_PIO_WRSETUP_STATUS_DRQ_ERR, /* 0x301 */ - SIPC_RX_FIS_STATUS_BSY_BIT_ERR, /* 0x302 */ - SIPC_RX_WRSETUP_LEN_ODD_ERR, /* 0x303 */ - SIPC_RX_WRSETUP_LEN_ZERO_ERR, /* 0x304 */ - SIPC_RX_WRDATA_LEN_NOT_MATCH_ERR, /* 0x305 */ - SIPC_RX_NCQ_WRSETUP_OFFSET_ERR, /* 0x306 */ - SIPC_RX_NCQ_WRSETUP_AUTO_ACTIVE_ERR, /* 0x307 */ - SIPC_RX_SATA_UNEXP_FIS_ERR, /* 0x308 */ - SIPC_RX_WRSETUP_ESTATUS_ERR, /* 0x309 */ - SIPC_RX_DATA_UNDERFLOW_ERR, /* 0x30a */ + SIPC_RX_FIS_STATUS_ERR_BIT_VLD = SIPC_RX_ERR_BASE, /* 0x50 */ + SIPC_RX_PIO_WRSETUP_STATUS_DRQ_ERR, /* 0x51 */ + SIPC_RX_FIS_STATUS_BSY_BIT_ERR, /* 0x52 */ + SIPC_RX_WRSETUP_LEN_ODD_ERR, /* 0x53 */ + SIPC_RX_WRSETUP_LEN_ZERO_ERR, /* 0x54 */ + SIPC_RX_WRDATA_LEN_NOT_MATCH_ERR, /* 0x55 */ + SIPC_RX_NCQ_WRSETUP_OFFSET_ERR, /* 0x56 */ + SIPC_RX_NCQ_WRSETUP_AUTO_ACTIVE_ERR, /* 0x57 */ + SIPC_RX_SATA_UNEXP_FIS_ERR, /* 0x58 */ + SIPC_RX_WRSETUP_ESTATUS_ERR, /* 0x59 */ + SIPC_RX_DATA_UNDERFLOW_ERR, /* 0x5a */ + SIPC_RX_MAX_ERR_CODE, /* dma rx */ - DMA_RX_DIF_CRC_ERR = DMA_RX_ERR_BASE, /* 0x400 */ - DMA_RX_DIF_APP_ERR, /* 0x401 */ - DMA_RX_DIF_RPP_ERR, /* 0x402 */ - DMA_RX_DATA_SGL_OVERFLOW, /* 0x403 */ - DMA_RX_DIF_SGL_OVERFLOW, /* 0x404 */ - DMA_RX_DATA_LEN_OVERFLOW, /* 0x405 */ - DMA_RX_DATA_LEN_UNDERFLOW, /* 0x406 */ - DMA_RX_DATA_OFFSET_ERR, /* 0x407 */ - RESERVED10, /* 0x408 */ - DMA_RX_SATA_FRAME_TYPE_ERR, /* 0x409 */ - DMA_RX_RESP_BUF_OVERFLOW, /* 0x40a */ - DMA_RX_UNEXP_RETRANS_RESP_ERR, /* 0x40b */ - DMA_RX_UNEXP_NORM_RESP_ERR, /* 0x40c */ - DMA_RX_UNEXP_RDFRAME_ERR, /* 0x40d */ - DMA_RX_PIO_DATA_LEN_ERR, /* 0x40e */ - DMA_RX_RDSETUP_STATUS_ERR, /* 0x40f */ - DMA_RX_RDSETUP_STATUS_DRQ_ERR, /* 0x410 */ - DMA_RX_RDSETUP_STATUS_BSY_ERR, /* 0x411 */ - DMA_RX_RDSETUP_LEN_ODD_ERR, /* 0x412 */ - DMA_RX_RDSETUP_LEN_ZERO_ERR, /* 0x413 */ - DMA_RX_RDSETUP_LEN_OVER_ERR, /* 0x414 */ - DMA_RX_RDSETUP_OFFSET_ERR, /* 0x415 */ - DMA_RX_RDSETUP_ACTIVE_ERR, /* 0x416 */ - DMA_RX_RDSETUP_ESTATUS_ERR, /* 0x417 */ - DMA_RX_RAM_ECC_ERR, /* 0x418 */ - DMA_RX_UNKNOWN_FRM_ERR, /* 0x419 */ + DMA_RX_DIF_CRC_ERR = DMA_RX_ERR_BASE, /* 0x60 */ + DMA_RX_DIF_APP_ERR, /* 0x61 */ + DMA_RX_DIF_RPP_ERR, /* 0x62 */ + DMA_RX_DATA_SGL_OVERFLOW, /* 0x63 */ + DMA_RX_DIF_SGL_OVERFLOW, /* 0x64 */ + DMA_RX_DATA_LEN_OVERFLOW, /* 0x65 */ + DMA_RX_DATA_LEN_UNDERFLOW, /* 0x66 */ + DMA_RX_DATA_OFFSET_ERR, /* 0x67 */ + RESERVED10, /* 0x68 */ + DMA_RX_SATA_FRAME_TYPE_ERR, /* 0x69 */ + DMA_RX_RESP_BUF_OVERFLOW, /* 0x6a */ + DMA_RX_UNEXP_RETRANS_RESP_ERR, /* 0x6b */ + DMA_RX_UNEXP_NORM_RESP_ERR, /* 0x6c */ + DMA_RX_UNEXP_RDFRAME_ERR, /* 0x6d */ + DMA_RX_PIO_DATA_LEN_ERR, /* 0x6e */ + DMA_RX_RDSETUP_STATUS_ERR, /* 0x6f */ + DMA_RX_RDSETUP_STATUS_DRQ_ERR, /* 0x70 */ + DMA_RX_RDSETUP_STATUS_BSY_ERR, /* 0x71 */ + DMA_RX_RDSETUP_LEN_ODD_ERR, /* 0x72 */ + DMA_RX_RDSETUP_LEN_ZERO_ERR, /* 0x73 */ + DMA_RX_RDSETUP_LEN_OVER_ERR, /* 0x74 */ + DMA_RX_RDSETUP_OFFSET_ERR, /* 0x75 */ + DMA_RX_RDSETUP_ACTIVE_ERR, /* 0x76 */ + DMA_RX_RDSETUP_ESTATUS_ERR, /* 0x77 */ + DMA_RX_RAM_ECC_ERR, /* 0x78 */ + DMA_RX_UNKNOWN_FRM_ERR, /* 0x79 */ + DMA_RX_MAX_ERR_CODE, }; #define HISI_SAS_COMMAND_ENTRIES_V2_HW 4096 @@ -538,6 +543,12 @@ enum { #define SATA_PROTOCOL_FPDMA 0x8 #define SATA_PROTOCOL_ATAPI 0x10 +#define ERR_ON_TX_PHASE(err_phase) (err_phase == 0x2 || \ + err_phase == 0x4 || err_phase == 0x8 ||\ + err_phase == 0x6 || err_phase == 0xa) +#define ERR_ON_RX_PHASE(err_phase) (err_phase == 0x10 || \ + err_phase == 0x20 || err_phase == 0x40) + static void hisi_sas_link_timeout_disable_link(unsigned long data); static u32 hisi_sas_read32(struct hisi_hba *hisi_hba, u32 off) @@ -1451,10 +1462,205 @@ static void sata_done_v2_hw(struct hisi_hba *hisi_hba, struct sas_task *task, ts->buf_valid_size = sizeof(*resp); } +#define TRANS_TX_ERR 0 +#define TRANS_RX_ERR 1 +#define DMA_TX_ERR 2 +#define SIPC_RX_ERR 3 +#define DMA_RX_ERR 4 + +#define DMA_TX_ERR_OFF 0 +#define DMA_TX_ERR_MSK (0xffff << DMA_TX_ERR_OFF) +#define SIPC_RX_ERR_OFF 16 +#define SIPC_RX_ERR_MSK (0xffff << SIPC_RX_ERR_OFF) + +static int parse_trans_tx_err_code_v2_hw(u32 err_msk) +{ + const u8 trans_tx_err_code_prio[] = { + TRANS_TX_OPEN_FAIL_WITH_IT_NEXUS_LOSS, + TRANS_TX_ERR_PHY_NOT_ENABLE, + TRANS_TX_OPEN_CNX_ERR_WRONG_DESTINATION, + TRANS_TX_OPEN_CNX_ERR_ZONE_VIOLATION, + TRANS_TX_OPEN_CNX_ERR_BY_OTHER, + RESERVED0, + TRANS_TX_OPEN_CNX_ERR_AIP_TIMEOUT, + TRANS_TX_OPEN_CNX_ERR_STP_RESOURCES_BUSY, + TRANS_TX_OPEN_CNX_ERR_PROTOCOL_NOT_SUPPORTED, + TRANS_TX_OPEN_CNX_ERR_CONNECTION_RATE_NOT_SUPPORTED, + TRANS_TX_OPEN_CNX_ERR_BAD_DESTINATION, + TRANS_TX_OPEN_CNX_ERR_BREAK_RCVD, + TRANS_TX_OPEN_CNX_ERR_LOW_PHY_POWER, + TRANS_TX_OPEN_CNX_ERR_PATHWAY_BLOCKED, + TRANS_TX_OPEN_CNX_ERR_OPEN_TIMEOUT, + TRANS_TX_OPEN_CNX_ERR_NO_DESTINATION, + TRANS_TX_OPEN_RETRY_ERR_THRESHOLD_REACHED, + TRANS_TX_ERR_WITH_CLOSE_PHYDISALE, + TRANS_TX_ERR_WITH_CLOSE_DWS_TIMEOUT, + TRANS_TX_ERR_WITH_CLOSE_COMINIT, + TRANS_TX_ERR_WITH_BREAK_TIMEOUT, + TRANS_TX_ERR_WITH_BREAK_REQUEST, + TRANS_TX_ERR_WITH_BREAK_RECEVIED, + TRANS_TX_ERR_WITH_CLOSE_TIMEOUT, + TRANS_TX_ERR_WITH_CLOSE_NORMAL, + TRANS_TX_ERR_WITH_NAK_RECEVIED, + TRANS_TX_ERR_WITH_ACK_NAK_TIMEOUT, + TRANS_TX_ERR_WITH_CREDIT_TIMEOUT, + TRANS_TX_ERR_WITH_IPTT_CONFLICT, + TRANS_TX_ERR_WITH_OPEN_BY_DES_OR_OTHERS, + TRANS_TX_ERR_WITH_WAIT_RECV_TIMEOUT, + }; + int index, i; + + for (i = 0; i < ARRAY_SIZE(trans_tx_err_code_prio); i++) { + index = trans_tx_err_code_prio[i] - TRANS_TX_FAIL_BASE; + if (err_msk & (1 << index)) + return trans_tx_err_code_prio[i]; + } + return -1; +} + +static int parse_trans_rx_err_code_v2_hw(u32 err_msk) +{ + const u8 trans_rx_err_code_prio[] = { + TRANS_RX_ERR_WITH_RXFRAME_CRC_ERR, + TRANS_RX_ERR_WITH_RXFIS_8B10B_DISP_ERR, + TRANS_RX_ERR_WITH_RXFRAME_HAVE_ERRPRM, + TRANS_RX_ERR_WITH_RXFIS_DECODE_ERROR, + TRANS_RX_ERR_WITH_RXFIS_CRC_ERR, + TRANS_RX_ERR_WITH_RXFRAME_LENGTH_OVERRUN, + TRANS_RX_ERR_WITH_RXFIS_RX_SYNCP, + TRANS_RX_ERR_WITH_LINK_BUF_OVERRUN, + TRANS_RX_ERR_WITH_CLOSE_PHY_DISABLE, + TRANS_RX_ERR_WITH_CLOSE_DWS_TIMEOUT, + TRANS_RX_ERR_WITH_CLOSE_COMINIT, + TRANS_RX_ERR_WITH_BREAK_TIMEOUT, + TRANS_RX_ERR_WITH_BREAK_REQUEST, + TRANS_RX_ERR_WITH_BREAK_RECEVIED, + RESERVED1, + TRANS_RX_ERR_WITH_CLOSE_NORMAL, + TRANS_RX_ERR_WITH_DATA_LEN0, + TRANS_RX_ERR_WITH_BAD_HASH, + TRANS_RX_XRDY_WLEN_ZERO_ERR, + TRANS_RX_SSP_FRM_LEN_ERR, + RESERVED2, + RESERVED3, + RESERVED4, + RESERVED5, + TRANS_RX_ERR_WITH_BAD_FRM_TYPE, + TRANS_RX_SMP_FRM_LEN_ERR, + TRANS_RX_SMP_RESP_TIMEOUT_ERR, + RESERVED6, + RESERVED7, + RESERVED8, + RESERVED9, + TRANS_RX_R_ERR, + }; + int index, i; + + for (i = 0; i < ARRAY_SIZE(trans_rx_err_code_prio); i++) { + index = trans_rx_err_code_prio[i] - TRANS_RX_FAIL_BASE; + if (err_msk & (1 << index)) + return trans_rx_err_code_prio[i]; + } + return -1; +} + +static int parse_dma_tx_err_code_v2_hw(u32 err_msk) +{ + const u8 dma_tx_err_code_prio[] = { + DMA_TX_UNEXP_XFER_ERR, + DMA_TX_UNEXP_RETRANS_ERR, + DMA_TX_XFER_LEN_OVERFLOW, + DMA_TX_XFER_OFFSET_ERR, + DMA_TX_RAM_ECC_ERR, + DMA_TX_DIF_LEN_ALIGN_ERR, + DMA_TX_DIF_CRC_ERR, + DMA_TX_DIF_APP_ERR, + DMA_TX_DIF_RPP_ERR, + DMA_TX_DATA_SGL_OVERFLOW, + DMA_TX_DIF_SGL_OVERFLOW, + }; + int index, i; + + for (i = 0; i < ARRAY_SIZE(dma_tx_err_code_prio); i++) { + index = dma_tx_err_code_prio[i] - DMA_TX_ERR_BASE; + err_msk = err_msk & DMA_TX_ERR_MSK; + if (err_msk & (1 << index)) + return dma_tx_err_code_prio[i]; + } + return -1; +} + +static int parse_sipc_rx_err_code_v2_hw(u32 err_msk) +{ + const u8 sipc_rx_err_code_prio[] = { + SIPC_RX_FIS_STATUS_ERR_BIT_VLD, + SIPC_RX_PIO_WRSETUP_STATUS_DRQ_ERR, + SIPC_RX_FIS_STATUS_BSY_BIT_ERR, + SIPC_RX_WRSETUP_LEN_ODD_ERR, + SIPC_RX_WRSETUP_LEN_ZERO_ERR, + SIPC_RX_WRDATA_LEN_NOT_MATCH_ERR, + SIPC_RX_NCQ_WRSETUP_OFFSET_ERR, + SIPC_RX_NCQ_WRSETUP_AUTO_ACTIVE_ERR, + SIPC_RX_SATA_UNEXP_FIS_ERR, + SIPC_RX_WRSETUP_ESTATUS_ERR, + SIPC_RX_DATA_UNDERFLOW_ERR, + }; + int index, i; + + for (i = 0; i < ARRAY_SIZE(sipc_rx_err_code_prio); i++) { + index = sipc_rx_err_code_prio[i] - SIPC_RX_ERR_BASE; + err_msk = err_msk & SIPC_RX_ERR_MSK; + if (err_msk & (1 << (index + 0x10))) + return sipc_rx_err_code_prio[i]; + } + return -1; +} + +static int parse_dma_rx_err_code_v2_hw(u32 err_msk) +{ + const u8 dma_rx_err_code_prio[] = { + DMA_RX_UNKNOWN_FRM_ERR, + DMA_RX_DATA_LEN_OVERFLOW, + DMA_RX_DATA_LEN_UNDERFLOW, + DMA_RX_DATA_OFFSET_ERR, + RESERVED10, + DMA_RX_SATA_FRAME_TYPE_ERR, + DMA_RX_RESP_BUF_OVERFLOW, + DMA_RX_UNEXP_RETRANS_RESP_ERR, + DMA_RX_UNEXP_NORM_RESP_ERR, + DMA_RX_UNEXP_RDFRAME_ERR, + DMA_RX_PIO_DATA_LEN_ERR, + DMA_RX_RDSETUP_STATUS_ERR, + DMA_RX_RDSETUP_STATUS_DRQ_ERR, + DMA_RX_RDSETUP_STATUS_BSY_ERR, + DMA_RX_RDSETUP_LEN_ODD_ERR, + DMA_RX_RDSETUP_LEN_ZERO_ERR, + DMA_RX_RDSETUP_LEN_OVER_ERR, + DMA_RX_RDSETUP_OFFSET_ERR, + DMA_RX_RDSETUP_ACTIVE_ERR, + DMA_RX_RDSETUP_ESTATUS_ERR, + DMA_RX_RAM_ECC_ERR, + DMA_RX_DIF_CRC_ERR, + DMA_RX_DIF_APP_ERR, + DMA_RX_DIF_RPP_ERR, + DMA_RX_DATA_SGL_OVERFLOW, + DMA_RX_DIF_SGL_OVERFLOW, + }; + int index, i; + + for (i = 0; i < ARRAY_SIZE(dma_rx_err_code_prio); i++) { + index = dma_rx_err_code_prio[i] - DMA_RX_ERR_BASE; + if (err_msk & (1 << index)) + return dma_rx_err_code_prio[i]; + } + return -1; +} + /* by default, task resp is complete */ static void slot_err_v2_hw(struct hisi_hba *hisi_hba, struct sas_task *task, - struct hisi_sas_slot *slot) + struct hisi_sas_slot *slot, + int err_phase) { struct task_status_struct *ts = &task->task_status; struct hisi_sas_err_record_v2 *err_record = slot->status_buffer; @@ -1465,21 +1671,23 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba, u32 dma_rx_err_type = cpu_to_le32(err_record->dma_rx_err_type); int error = -1; - if (dma_rx_err_type) { - error = ffs(dma_rx_err_type) - - 1 + DMA_RX_ERR_BASE; - } else if (sipc_rx_err_type) { - error = ffs(sipc_rx_err_type) - - 1 + SIPC_RX_ERR_BASE; - } else if (dma_tx_err_type) { - error = ffs(dma_tx_err_type) - - 1 + DMA_TX_ERR_BASE; - } else if (trans_rx_fail_type) { - error = ffs(trans_rx_fail_type) - - 1 + TRANS_RX_FAIL_BASE; - } else if (trans_tx_fail_type) { - error = ffs(trans_tx_fail_type) - - 1 + TRANS_TX_FAIL_BASE; + if (err_phase == 1) { + /* error in TX phase, the priority of error is: DW2 > DW0 */ + error = parse_dma_tx_err_code_v2_hw(dma_tx_err_type); + if (error == -1) + error = parse_trans_tx_err_code_v2_hw( + trans_tx_fail_type); + } else if (err_phase == 2) { + /* error in RX phase, the priority is: DW1 > DW3 > DW2 */ + error = parse_trans_rx_err_code_v2_hw( + trans_rx_fail_type); + if (error == -1) { + error = parse_dma_rx_err_code_v2_hw( + dma_rx_err_type); + if (error == -1) + error = parse_sipc_rx_err_code_v2_hw( + sipc_rx_err_type); + } } switch (task->task_proto) { @@ -1490,13 +1698,6 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba, { ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_NO_DEST; - break; - } - case TRANS_TX_OPEN_CNX_ERR_PATHWAY_BLOCKED: - { - ts->stat = SAS_OPEN_REJECT; - ts->open_rej_reason = SAS_OREJ_PATH_BLOCKED; - break; } case TRANS_TX_OPEN_CNX_ERR_PROTOCOL_NOT_SUPPORTED: { @@ -1516,19 +1717,15 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba, ts->open_rej_reason = SAS_OREJ_BAD_DEST; break; } - case TRANS_TX_OPEN_CNX_ERR_BREAK_RCVD: - { - ts->stat = SAS_OPEN_REJECT; - ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; - break; - } case TRANS_TX_OPEN_CNX_ERR_WRONG_DESTINATION: { ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_WRONG_DEST; break; } + case DMA_RX_UNEXP_NORM_RESP_ERR: case TRANS_TX_OPEN_CNX_ERR_ZONE_VIOLATION: + case DMA_RX_RESP_BUF_OVERFLOW: { ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_UNKNOWN; @@ -1540,16 +1737,6 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba, ts->stat = SAS_DEV_NO_RESPONSE; break; } - case TRANS_RX_ERR_WITH_CLOSE_PHY_DISABLE: - { - ts->stat = SAS_PHY_DOWN; - break; - } - case TRANS_TX_OPEN_CNX_ERR_OPEN_TIMEOUT: - { - ts->stat = SAS_OPEN_TO; - break; - } case DMA_RX_DATA_LEN_OVERFLOW: { ts->stat = SAS_DATA_OVERRUN; @@ -1557,60 +1744,65 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba, break; } case DMA_RX_DATA_LEN_UNDERFLOW: - case SIPC_RX_DATA_UNDERFLOW_ERR: { - ts->residual = trans_tx_fail_type; + ts->residual = dma_rx_err_type; ts->stat = SAS_DATA_UNDERRUN; break; } - case TRANS_TX_ERR_FRAME_TXED: - { - /* This will request a retry */ - ts->stat = SAS_QUEUE_FULL; - slot->abort = 1; - break; - } case TRANS_TX_OPEN_FAIL_WITH_IT_NEXUS_LOSS: case TRANS_TX_ERR_PHY_NOT_ENABLE: case TRANS_TX_OPEN_CNX_ERR_BY_OTHER: case TRANS_TX_OPEN_CNX_ERR_AIP_TIMEOUT: + case TRANS_TX_OPEN_CNX_ERR_BREAK_RCVD: + case TRANS_TX_OPEN_CNX_ERR_PATHWAY_BLOCKED: + case TRANS_TX_OPEN_CNX_ERR_OPEN_TIMEOUT: case TRANS_TX_OPEN_RETRY_ERR_THRESHOLD_REACHED: case TRANS_TX_ERR_WITH_BREAK_TIMEOUT: case TRANS_TX_ERR_WITH_BREAK_REQUEST: case TRANS_TX_ERR_WITH_BREAK_RECEVIED: case TRANS_TX_ERR_WITH_CLOSE_TIMEOUT: case TRANS_TX_ERR_WITH_CLOSE_NORMAL: + case TRANS_TX_ERR_WITH_CLOSE_PHYDISALE: case TRANS_TX_ERR_WITH_CLOSE_DWS_TIMEOUT: case TRANS_TX_ERR_WITH_CLOSE_COMINIT: case TRANS_TX_ERR_WITH_NAK_RECEVIED: case TRANS_TX_ERR_WITH_ACK_NAK_TIMEOUT: - case TRANS_TX_ERR_WITH_IPTT_CONFLICT: case TRANS_TX_ERR_WITH_CREDIT_TIMEOUT: + case TRANS_TX_ERR_WITH_IPTT_CONFLICT: case TRANS_RX_ERR_WITH_RXFRAME_CRC_ERR: case TRANS_RX_ERR_WITH_RXFIS_8B10B_DISP_ERR: case TRANS_RX_ERR_WITH_RXFRAME_HAVE_ERRPRM: + case TRANS_RX_ERR_WITH_LINK_BUF_OVERRUN: case TRANS_RX_ERR_WITH_BREAK_TIMEOUT: case TRANS_RX_ERR_WITH_BREAK_REQUEST: case TRANS_RX_ERR_WITH_BREAK_RECEVIED: case TRANS_RX_ERR_WITH_CLOSE_NORMAL: case TRANS_RX_ERR_WITH_CLOSE_DWS_TIMEOUT: case TRANS_RX_ERR_WITH_CLOSE_COMINIT: + case TRANS_TX_ERR_FRAME_TXED: + case TRANS_RX_ERR_WITH_CLOSE_PHY_DISABLE: case TRANS_RX_ERR_WITH_DATA_LEN0: case TRANS_RX_ERR_WITH_BAD_HASH: case TRANS_RX_XRDY_WLEN_ZERO_ERR: case TRANS_RX_SSP_FRM_LEN_ERR: case TRANS_RX_ERR_WITH_BAD_FRM_TYPE: + case DMA_TX_DATA_SGL_OVERFLOW: case DMA_TX_UNEXP_XFER_ERR: case DMA_TX_UNEXP_RETRANS_ERR: case DMA_TX_XFER_LEN_OVERFLOW: case DMA_TX_XFER_OFFSET_ERR: + case SIPC_RX_DATA_UNDERFLOW_ERR: + case DMA_RX_DATA_SGL_OVERFLOW: case DMA_RX_DATA_OFFSET_ERR: - case DMA_RX_UNEXP_NORM_RESP_ERR: - case DMA_RX_UNEXP_RDFRAME_ERR: + case DMA_RX_RDSETUP_LEN_ODD_ERR: + case DMA_RX_RDSETUP_LEN_ZERO_ERR: + case DMA_RX_RDSETUP_LEN_OVER_ERR: + case DMA_RX_SATA_FRAME_TYPE_ERR: case DMA_RX_UNKNOWN_FRM_ERR: { - ts->stat = SAS_OPEN_REJECT; - ts->open_rej_reason = SAS_OREJ_UNKNOWN; + /* This will request a retry */ + ts->stat = SAS_QUEUE_FULL; + slot->abort = 1; break; } default: @@ -1627,57 +1819,92 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba, case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: { switch (error) { - case TRANS_TX_OPEN_CNX_ERR_LOW_PHY_POWER: - case TRANS_TX_OPEN_CNX_ERR_PATHWAY_BLOCKED: case TRANS_TX_OPEN_CNX_ERR_NO_DESTINATION: + { + ts->stat = SAS_OPEN_REJECT; + ts->open_rej_reason = SAS_OREJ_NO_DEST; + break; + } + case TRANS_TX_OPEN_CNX_ERR_LOW_PHY_POWER: { ts->resp = SAS_TASK_UNDELIVERED; ts->stat = SAS_DEV_NO_RESPONSE; break; } case TRANS_TX_OPEN_CNX_ERR_PROTOCOL_NOT_SUPPORTED: + { + ts->stat = SAS_OPEN_REJECT; + ts->open_rej_reason = SAS_OREJ_EPROTO; + break; + } case TRANS_TX_OPEN_CNX_ERR_CONNECTION_RATE_NOT_SUPPORTED: + { + ts->stat = SAS_OPEN_REJECT; + ts->open_rej_reason = SAS_OREJ_CONN_RATE; + break; + } case TRANS_TX_OPEN_CNX_ERR_BAD_DESTINATION: - case TRANS_TX_OPEN_CNX_ERR_BREAK_RCVD: + { + ts->stat = SAS_OPEN_REJECT; + ts->open_rej_reason = SAS_OREJ_CONN_RATE; + break; + } case TRANS_TX_OPEN_CNX_ERR_WRONG_DESTINATION: - case TRANS_TX_OPEN_CNX_ERR_ZONE_VIOLATION: - case TRANS_TX_OPEN_CNX_ERR_STP_RESOURCES_BUSY: { ts->stat = SAS_OPEN_REJECT; + ts->open_rej_reason = SAS_OREJ_WRONG_DEST; break; } - case TRANS_TX_OPEN_CNX_ERR_OPEN_TIMEOUT: + case DMA_RX_RESP_BUF_OVERFLOW: + case DMA_RX_UNEXP_NORM_RESP_ERR: + case TRANS_TX_OPEN_CNX_ERR_ZONE_VIOLATION: { - ts->stat = SAS_OPEN_TO; + ts->stat = SAS_OPEN_REJECT; + ts->open_rej_reason = SAS_OREJ_UNKNOWN; break; } case DMA_RX_DATA_LEN_OVERFLOW: { ts->stat = SAS_DATA_OVERRUN; + ts->residual = 0; + break; + } + case DMA_RX_DATA_LEN_UNDERFLOW: + { + ts->residual = dma_rx_err_type; + ts->stat = SAS_DATA_UNDERRUN; break; } case TRANS_TX_OPEN_FAIL_WITH_IT_NEXUS_LOSS: case TRANS_TX_ERR_PHY_NOT_ENABLE: case TRANS_TX_OPEN_CNX_ERR_BY_OTHER: case TRANS_TX_OPEN_CNX_ERR_AIP_TIMEOUT: + case TRANS_TX_OPEN_CNX_ERR_BREAK_RCVD: + case TRANS_TX_OPEN_CNX_ERR_PATHWAY_BLOCKED: + case TRANS_TX_OPEN_CNX_ERR_OPEN_TIMEOUT: case TRANS_TX_OPEN_RETRY_ERR_THRESHOLD_REACHED: case TRANS_TX_ERR_WITH_BREAK_TIMEOUT: case TRANS_TX_ERR_WITH_BREAK_REQUEST: case TRANS_TX_ERR_WITH_BREAK_RECEVIED: case TRANS_TX_ERR_WITH_CLOSE_TIMEOUT: case TRANS_TX_ERR_WITH_CLOSE_NORMAL: + case TRANS_TX_ERR_WITH_CLOSE_PHYDISALE: case TRANS_TX_ERR_WITH_CLOSE_DWS_TIMEOUT: case TRANS_TX_ERR_WITH_CLOSE_COMINIT: - case TRANS_TX_ERR_WITH_NAK_RECEVIED: case TRANS_TX_ERR_WITH_ACK_NAK_TIMEOUT: case TRANS_TX_ERR_WITH_CREDIT_TIMEOUT: + case TRANS_TX_ERR_WITH_OPEN_BY_DES_OR_OTHERS: case TRANS_TX_ERR_WITH_WAIT_RECV_TIMEOUT: - case TRANS_RX_ERR_WITH_RXFIS_8B10B_DISP_ERR: case TRANS_RX_ERR_WITH_RXFRAME_HAVE_ERRPRM: + case TRANS_RX_ERR_WITH_RXFIS_8B10B_DISP_ERR: case TRANS_RX_ERR_WITH_RXFIS_DECODE_ERROR: case TRANS_RX_ERR_WITH_RXFIS_CRC_ERR: case TRANS_RX_ERR_WITH_RXFRAME_LENGTH_OVERRUN: case TRANS_RX_ERR_WITH_RXFIS_RX_SYNCP: + case TRANS_RX_ERR_WITH_LINK_BUF_OVERRUN: + case TRANS_RX_ERR_WITH_BREAK_TIMEOUT: + case TRANS_RX_ERR_WITH_BREAK_REQUEST: + case TRANS_RX_ERR_WITH_BREAK_RECEVIED: case TRANS_RX_ERR_WITH_CLOSE_NORMAL: case TRANS_RX_ERR_WITH_CLOSE_PHY_DISABLE: case TRANS_RX_ERR_WITH_CLOSE_DWS_TIMEOUT: @@ -1685,7 +1912,12 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba, case TRANS_RX_ERR_WITH_DATA_LEN0: case TRANS_RX_ERR_WITH_BAD_HASH: case TRANS_RX_XRDY_WLEN_ZERO_ERR: - case TRANS_RX_SSP_FRM_LEN_ERR: + case TRANS_RX_ERR_WITH_BAD_FRM_TYPE: + case DMA_TX_DATA_SGL_OVERFLOW: + case DMA_TX_UNEXP_XFER_ERR: + case DMA_TX_UNEXP_RETRANS_ERR: + case DMA_TX_XFER_LEN_OVERFLOW: + case DMA_TX_XFER_OFFSET_ERR: case SIPC_RX_FIS_STATUS_ERR_BIT_VLD: case SIPC_RX_PIO_WRSETUP_STATUS_DRQ_ERR: case SIPC_RX_FIS_STATUS_BSY_BIT_ERR: @@ -1693,6 +1925,8 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba, case SIPC_RX_WRSETUP_LEN_ZERO_ERR: case SIPC_RX_WRDATA_LEN_NOT_MATCH_ERR: case SIPC_RX_SATA_UNEXP_FIS_ERR: + case DMA_RX_DATA_SGL_OVERFLOW: + case DMA_RX_DATA_OFFSET_ERR: case DMA_RX_SATA_FRAME_TYPE_ERR: case DMA_RX_UNEXP_RDFRAME_ERR: case DMA_RX_PIO_DATA_LEN_ERR: @@ -1706,8 +1940,11 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba, case DMA_RX_RDSETUP_ACTIVE_ERR: case DMA_RX_RDSETUP_ESTATUS_ERR: case DMA_RX_UNKNOWN_FRM_ERR: + case TRANS_RX_SSP_FRM_LEN_ERR: + case TRANS_TX_OPEN_CNX_ERR_STP_RESOURCES_BUSY: { - ts->stat = SAS_OPEN_REJECT; + slot->abort = 1; + ts->stat = SAS_PHY_DOWN; break; } default: @@ -1794,8 +2031,14 @@ slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot) if ((complete_hdr->dw0 & CMPLT_HDR_ERX_MSK) && (!(complete_hdr->dw0 & CMPLT_HDR_RSPNS_XFRD_MSK))) { - - slot_err_v2_hw(hisi_hba, task, slot); + u32 err_phase = (complete_hdr->dw0 & CMPLT_HDR_ERR_PHASE_MSK) + >> CMPLT_HDR_ERR_PHASE_OFF; + + /* Analyse error happens on which phase TX or RX */ + if (ERR_ON_TX_PHASE(err_phase)) + slot_err_v2_hw(hisi_hba, task, slot, 1); + else if (ERR_ON_RX_PHASE(err_phase)) + slot_err_v2_hw(hisi_hba, task, slot, 2); if (unlikely(slot->abort)) return ts->stat; -- cgit v1.2.3 From f1dc751876e115a65e49e7fd016e52136572e6d5 Mon Sep 17 00:00:00 2001 From: John Garry Date: Thu, 23 Mar 2017 01:25:32 +0800 Subject: scsi: hisi_sas: some modifications to v2 hw reg init values This patch includes: (1) Disable transport layer retry (2) Support CQ time and count interrupt coal (3) fix link FIFO full issue Signed-off-by: Xiang Chen Signed-off-by: Zhao Nenglong Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 66a458b83dac..8e869d9ad3bb 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -893,7 +893,7 @@ static void init_reg_v2_hw(struct hisi_hba *hisi_hba) (u32)((1ULL << hisi_hba->queue_count) - 1)); hisi_sas_write32(hisi_hba, AXI_USER1, 0xc0000000); hisi_sas_write32(hisi_hba, AXI_USER2, 0x10000); - hisi_sas_write32(hisi_hba, HGC_SAS_TXFAIL_RETRY_CTRL, 0x108); + hisi_sas_write32(hisi_hba, HGC_SAS_TXFAIL_RETRY_CTRL, 0x0); hisi_sas_write32(hisi_hba, HGC_SAS_TX_OPEN_FAIL_RETRY_CTRL, 0x7FF); hisi_sas_write32(hisi_hba, OPENA_WT_CONTI_TIME, 0x1); hisi_sas_write32(hisi_hba, I_T_NEXUS_LOSS_TIME, 0x1F4); @@ -902,9 +902,9 @@ static void init_reg_v2_hw(struct hisi_hba *hisi_hba) hisi_sas_write32(hisi_hba, CFG_AGING_TIME, 0x1); hisi_sas_write32(hisi_hba, HGC_ERR_STAT_EN, 0x1); hisi_sas_write32(hisi_hba, HGC_GET_ITV_TIME, 0x1); - hisi_sas_write32(hisi_hba, INT_COAL_EN, 0x1); - hisi_sas_write32(hisi_hba, OQ_INT_COAL_TIME, 0x1); - hisi_sas_write32(hisi_hba, OQ_INT_COAL_CNT, 0x1); + hisi_sas_write32(hisi_hba, INT_COAL_EN, 0xc); + hisi_sas_write32(hisi_hba, OQ_INT_COAL_TIME, 0x60); + hisi_sas_write32(hisi_hba, OQ_INT_COAL_CNT, 0x3); hisi_sas_write32(hisi_hba, ENT_INT_COAL_TIME, 0x1); hisi_sas_write32(hisi_hba, ENT_INT_COAL_CNT, 0x1); hisi_sas_write32(hisi_hba, OQ_INT_SRC, 0x0); @@ -927,14 +927,14 @@ static void init_reg_v2_hw(struct hisi_hba *hisi_hba) 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, DONE_RECEIVED_TIME, 0x8); hisi_sas_phy_write32(hisi_hba, i, CHL_INT0, 0xffffffff); hisi_sas_phy_write32(hisi_hba, i, CHL_INT1, 0xffffffff); hisi_sas_phy_write32(hisi_hba, i, CHL_INT2, 0xfff87fff); hisi_sas_phy_write32(hisi_hba, i, RXOP_CHECK_CFG_H, 0x1000); hisi_sas_phy_write32(hisi_hba, i, CHL_INT1_MSK, 0xffffffff); hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0x8ffffbff); - hisi_sas_phy_write32(hisi_hba, i, SL_CFG, 0x23f801fc); + hisi_sas_phy_write32(hisi_hba, i, SL_CFG, 0x13f801fc); hisi_sas_phy_write32(hisi_hba, i, PHY_CTRL_RDY_MSK, 0x0); hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_NOT_RDY_MSK, 0x0); hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_DWS_RESET_MSK, 0x0); -- cgit v1.2.3 From 981843c6c4ecfa9f6bc2589e66849cde11ef820e Mon Sep 17 00:00:00 2001 From: Xiaofei Tan Date: Thu, 23 Mar 2017 01:25:33 +0800 Subject: scsi: hisi_sas: handle PHY UP+DOWN simultaneous irq Handle the situation that PHY UP and DOWN irq happen simultaneously. There is no mechanism of SoC HW to ensure this situation will never happen. So, we add this handle just in case. Signed-off-by: Xiaofei Tan Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 56 +++++++++++++++++++++++----------- 1 file changed, 39 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 8e869d9ad3bb..45bd69da5151 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -2285,7 +2285,7 @@ static int prep_abort_v2_hw(struct hisi_hba *hisi_hba, static int phy_up_v2_hw(int phy_no, struct hisi_hba *hisi_hba) { - int i, res = 0; + int i, res = IRQ_HANDLED; u32 context, port_id, link_rate, hard_phy_linkrate; struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no]; struct asd_sas_phy *sas_phy = &phy->sas_phy; @@ -2373,7 +2373,6 @@ static bool check_any_wideports_v2_hw(struct hisi_hba *hisi_hba) static int phy_down_v2_hw(int phy_no, struct hisi_hba *hisi_hba) { - int res = 0; u32 phy_state, sl_ctrl, txid_auto; struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no]; struct hisi_sas_port *port = phy->port; @@ -2398,7 +2397,7 @@ static int phy_down_v2_hw(int phy_no, struct hisi_hba *hisi_hba) 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); - return res; + return IRQ_HANDLED; } static irqreturn_t int_phy_updown_v2_hw(int irq_no, void *p) @@ -2406,35 +2405,58 @@ static irqreturn_t int_phy_updown_v2_hw(int irq_no, void *p) struct hisi_hba *hisi_hba = p; u32 irq_msk; int phy_no = 0; - irqreturn_t res = IRQ_HANDLED; irq_msk = (hisi_sas_read32(hisi_hba, HGC_INVLD_DQE_INFO) >> HGC_INVLD_DQE_INFO_FB_CH0_OFF) & 0x1ff; while (irq_msk) { if (irq_msk & 1) { - u32 irq_value = hisi_sas_phy_read32(hisi_hba, phy_no, - CHL_INT0); + u32 reg_value = hisi_sas_phy_read32(hisi_hba, phy_no, + CHL_INT0); + + switch (reg_value & (CHL_INT0_NOT_RDY_MSK | + CHL_INT0_SL_PHY_ENABLE_MSK)) { - if (irq_value & CHL_INT0_SL_PHY_ENABLE_MSK) + case CHL_INT0_SL_PHY_ENABLE_MSK: /* phy up */ - if (phy_up_v2_hw(phy_no, hisi_hba)) { - res = IRQ_NONE; - goto end; - } + if (phy_up_v2_hw(phy_no, hisi_hba) == + IRQ_NONE) + return IRQ_NONE; + break; - if (irq_value & CHL_INT0_NOT_RDY_MSK) + case CHL_INT0_NOT_RDY_MSK: /* phy down */ - if (phy_down_v2_hw(phy_no, hisi_hba)) { - res = IRQ_NONE; - goto end; + if (phy_down_v2_hw(phy_no, hisi_hba) == + IRQ_NONE) + return IRQ_NONE; + break; + + case (CHL_INT0_NOT_RDY_MSK | + CHL_INT0_SL_PHY_ENABLE_MSK): + reg_value = hisi_sas_read32(hisi_hba, + PHY_STATE); + if (reg_value & BIT(phy_no)) { + /* phy up */ + if (phy_up_v2_hw(phy_no, hisi_hba) == + IRQ_NONE) + return IRQ_NONE; + } else { + /* phy down */ + if (phy_down_v2_hw(phy_no, hisi_hba) == + IRQ_NONE) + return IRQ_NONE; } + break; + + default: + break; + } + } irq_msk >>= 1; phy_no++; } -end: - return res; + return IRQ_HANDLED; } static void phy_bcast_v2_hw(int phy_no, struct hisi_hba *hisi_hba) -- cgit v1.2.3 From 4df642db5ba7f7362f72f033e359083b3fa873a3 Mon Sep 17 00:00:00 2001 From: John Garry Date: Thu, 23 Mar 2017 01:25:34 +0800 Subject: scsi: hisi_sas: rename hisi_sas_link_timeout_{enable, disable}_link For consistency, remove the "hisi_sas_" prefix. Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 45bd69da5151..e9c718829f3c 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -549,7 +549,7 @@ enum { #define ERR_ON_RX_PHASE(err_phase) (err_phase == 0x10 || \ err_phase == 0x20 || err_phase == 0x40) -static void hisi_sas_link_timeout_disable_link(unsigned long data); +static void link_timeout_disable_link(unsigned long data); static u32 hisi_sas_read32(struct hisi_hba *hisi_hba, u32 off) { @@ -1006,7 +1006,7 @@ static void init_reg_v2_hw(struct hisi_hba *hisi_hba) upper_32_bits(hisi_hba->initial_fis_dma)); } -static void hisi_sas_link_timeout_enable_link(unsigned long data) +static void link_timeout_enable_link(unsigned long data) { struct hisi_hba *hisi_hba = (struct hisi_hba *)data; int i, reg_val; @@ -1020,11 +1020,11 @@ static void hisi_sas_link_timeout_enable_link(unsigned long data) } } - hisi_hba->timer.function = hisi_sas_link_timeout_disable_link; + hisi_hba->timer.function = link_timeout_disable_link; mod_timer(&hisi_hba->timer, jiffies + msecs_to_jiffies(900)); } -static void hisi_sas_link_timeout_disable_link(unsigned long data) +static void link_timeout_disable_link(unsigned long data) { struct hisi_hba *hisi_hba = (struct hisi_hba *)data; int i, reg_val; @@ -1038,14 +1038,14 @@ static void hisi_sas_link_timeout_disable_link(unsigned long data) } } - hisi_hba->timer.function = hisi_sas_link_timeout_enable_link; + hisi_hba->timer.function = link_timeout_enable_link; mod_timer(&hisi_hba->timer, jiffies + msecs_to_jiffies(100)); } static void set_link_timer_quirk(struct hisi_hba *hisi_hba) { hisi_hba->timer.data = (unsigned long)hisi_hba; - hisi_hba->timer.function = hisi_sas_link_timeout_disable_link; + hisi_hba->timer.function = link_timeout_disable_link; hisi_hba->timer.expires = jiffies + msecs_to_jiffies(1000); add_timer(&hisi_hba->timer); } -- cgit v1.2.3 From 8b05ad6a9dbc4306c8eaf0f5269206647ed1ad7e Mon Sep 17 00:00:00 2001 From: John Garry Date: Thu, 23 Mar 2017 01:25:35 +0800 Subject: scsi: hisi_sas: add hisi_sas_clear_nexus_ha() Add function for upper-layer to reset controller when all else fails. Signed-off-by: John Garry Signed-off-by: Xiang Chen Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 3d63a24fea54..f86263b3bf1c 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -1070,6 +1070,13 @@ out: return rc; } +static int hisi_sas_clear_nexus_ha(struct sas_ha_struct *sas_ha) +{ + struct hisi_hba *hisi_hba = sas_ha->lldd_ha; + + return hisi_sas_controller_reset(hisi_hba); +} + static int hisi_sas_query_task(struct sas_task *task) { struct scsi_lun lun; @@ -1368,6 +1375,7 @@ static struct sas_domain_function_template hisi_sas_transport_ops = { .lldd_I_T_nexus_reset = hisi_sas_I_T_nexus_reset, .lldd_lu_reset = hisi_sas_lu_reset, .lldd_query_task = hisi_sas_query_task, + .lldd_clear_nexus_ha = hisi_sas_clear_nexus_ha, .lldd_port_formed = hisi_sas_port_formed, }; -- cgit v1.2.3 From ccbfe5a05a5be7670d1b91ad07d8b1f3b9dbd45e Mon Sep 17 00:00:00 2001 From: Xiang Chen Date: Thu, 23 Mar 2017 01:25:36 +0800 Subject: scsi: hisi_sas: release SMP slot in lldd_abort_task When an SMP task timeouts, it will call lldd_abort_task to release the associated slot, and then will release the sas_task. Currently in lldd_abort_task, if we fail to internally abort IO, then the slot of SMP IO is not released, but sas_task will still be later released, so the slot's sas_task is NULL, which will cause NULL pointer when hisi_sas_slot_task_free happens later. To resolve, check the return value of internal abort, and release the slot if it failed. Signed-off-by: Xiang Chen Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index f86263b3bf1c..1391f2dd8102 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -962,8 +962,13 @@ static int hisi_sas_abort_task(struct sas_task *task) 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); + rc = hisi_sas_internal_task_abort(hisi_hba, device, + HISI_SAS_INT_ABT_CMD, tag); + if (rc == TMF_RESP_FUNC_FAILED) { + spin_lock_irqsave(&hisi_hba->lock, flags); + hisi_sas_do_release_task(hisi_hba, task, slot); + spin_unlock_irqrestore(&hisi_hba->lock, flags); + } } out: -- cgit v1.2.3 From 14d3f397f6496e04a6b9876a44469fbfaea287f8 Mon Sep 17 00:00:00 2001 From: John Garry Date: Thu, 23 Mar 2017 01:25:37 +0800 Subject: scsi: hisi_sas: check hisi_sas_lu_reset() error message Unless we actually get some sort of failure in hisi_sas_lu_reset(), don't print a message. Signed-off-by: John Garry Signed-off-by: Xiang Chen Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 1391f2dd8102..dcceff9043b0 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -1070,8 +1070,9 @@ static int hisi_sas_lu_reset(struct domain_device *device, u8 *lun) } } out: - dev_err(dev, "lu_reset: for device[%llx]:rc= %d\n", - sas_dev->device_id, rc); + if (rc != TMF_RESP_FUNC_COMPLETE) + dev_err(dev, "lu_reset: for device[%llx]:rc= %d\n", + sas_dev->device_id, rc); return rc; } -- cgit v1.2.3 From 6073b7719a63b42f0272917b4b2b552f5002f53d Mon Sep 17 00:00:00 2001 From: Xiang Chen Date: Thu, 23 Mar 2017 01:25:38 +0800 Subject: scsi: hisi_sas: use dev_is_sata to identify SATA or SAS disk When SMP IO is sent, sas_protocol_ata couldn't judge whether the disk is SATA or SAS disk. So use dev_is_sata to identify SATA or SAS disk. Signed-off-by: Xiang Chen Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index dcceff9043b0..9890dfdd4111 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -218,7 +218,7 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba, port = to_hisi_sas_port(sas_port); if (port && !port->port_attached) { dev_info(dev, "task prep: %s port%d not attach device\n", - (sas_protocol_ata(task->task_proto)) ? + (dev_is_sata(device)) ? "SATA/STP" : "SAS", device->port->id); -- cgit v1.2.3 From 4935933e07daaf829692fa54abe0c2ad9ac94ed9 Mon Sep 17 00:00:00 2001 From: Xiaofei Tan Date: Thu, 23 Mar 2017 01:25:39 +0800 Subject: scsi: hisi_sas: add is_sata_phy_v2_hw() Add helper function is_sata_phy_v2_hw() to judge whether the attached device is SATA disk for a root PHY. Signed-off-by: Xiaofei Tan Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index e9c718829f3c..a3af380dde9e 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -1075,6 +1075,17 @@ static void enable_phy_v2_hw(struct hisi_hba *hisi_hba, int phy_no) hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CFG, cfg); } +static bool is_sata_phy_v2_hw(struct hisi_hba *hisi_hba, int phy_no) +{ + u32 context; + + context = hisi_sas_read32(hisi_hba, PHY_CONTEXT); + if (context & (1 << phy_no)) + return true; + + return false; +} + static void disable_phy_v2_hw(struct hisi_hba *hisi_hba, int phy_no) { u32 cfg = hisi_sas_phy_read32(hisi_hba, phy_no, PHY_CFG); @@ -2286,7 +2297,7 @@ static int prep_abort_v2_hw(struct hisi_hba *hisi_hba, static int phy_up_v2_hw(int phy_no, struct hisi_hba *hisi_hba) { int i, res = IRQ_HANDLED; - u32 context, port_id, link_rate, hard_phy_linkrate; + u32 port_id, link_rate, hard_phy_linkrate; struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no]; struct asd_sas_phy *sas_phy = &phy->sas_phy; struct device *dev = &hisi_hba->pdev->dev; @@ -2295,9 +2306,7 @@ static int phy_up_v2_hw(int phy_no, struct hisi_hba *hisi_hba) hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_PHY_ENA_MSK, 1); - /* Check for SATA dev */ - context = hisi_sas_read32(hisi_hba, PHY_CONTEXT); - if (context & (1 << phy_no)) + if (is_sata_phy_v2_hw(hisi_hba, phy_no)) goto end; if (phy_no == 8) { -- cgit v1.2.3 From 66a0d59cdd12546ddf01d229de28b07ccf6d637f Mon Sep 17 00:00:00 2001 From: Brian King Date: Wed, 15 Mar 2017 16:58:36 -0500 Subject: scsi: ipr: Fix missed EH wakeup Following a command abort or device reset, ipr's EH handlers wait for the commands getting aborted to get sent back from the adapter prior to returning from the EH handler. This fixes up some cases where the completion handler was not getting called, which would have resulted in the EH thread waiting until it timed out, greatly extending EH time. Signed-off-by: Brian King Reviewed-by: Wendy Xiong Tested-by: Wendy Xiong Signed-off-by: Martin K. Petersen --- drivers/scsi/ipr.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index b29afafc2885..0688e0aa76a5 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -836,8 +836,10 @@ static void ipr_sata_eh_done(struct ipr_cmnd *ipr_cmd) qc->err_mask |= AC_ERR_OTHER; sata_port->ioasa.status |= ATA_BUSY; - list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q); ata_qc_complete(qc); + if (ipr_cmd->eh_comp) + complete(ipr_cmd->eh_comp); + list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q); } /** @@ -5947,8 +5949,10 @@ static void ipr_erp_done(struct ipr_cmnd *ipr_cmd) res->in_erp = 0; } scsi_dma_unmap(ipr_cmd->scsi_cmd); - list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q); scsi_cmd->scsi_done(scsi_cmd); + if (ipr_cmd->eh_comp) + complete(ipr_cmd->eh_comp); + list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q); } /** @@ -6338,8 +6342,10 @@ static void ipr_erp_start(struct ipr_ioa_cfg *ioa_cfg, } scsi_dma_unmap(ipr_cmd->scsi_cmd); - list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q); scsi_cmd->scsi_done(scsi_cmd); + if (ipr_cmd->eh_comp) + complete(ipr_cmd->eh_comp); + list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q); } /** @@ -6365,8 +6371,10 @@ static void ipr_scsi_done(struct ipr_cmnd *ipr_cmd) scsi_dma_unmap(scsi_cmd); spin_lock_irqsave(ipr_cmd->hrrq->lock, lock_flags); - list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q); scsi_cmd->scsi_done(scsi_cmd); + if (ipr_cmd->eh_comp) + complete(ipr_cmd->eh_comp); + list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q); spin_unlock_irqrestore(ipr_cmd->hrrq->lock, lock_flags); } else { spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); -- cgit v1.2.3 From 960e96480ee2bff4f09472c64e25f1850bf06470 Mon Sep 17 00:00:00 2001 From: Brian King Date: Wed, 15 Mar 2017 16:58:37 -0500 Subject: scsi: ipr: Remove redundant initialization Removes some code in __ipr_eh_dev_reset which was modifying the ipr_cmd done function. This should have already been setup at command allocation time and if its since been changed, it means we are in the ipr_erp* functions and need to wait for them to complete and don't want to override that here. Signed-off-by: Brian King Reviewed-by: Wendy Xiong Tested-by: Wendy Xiong Signed-off-by: Martin K. Petersen --- drivers/scsi/ipr.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 0688e0aa76a5..0d780c9bb09b 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -5243,12 +5243,11 @@ static int __ipr_eh_dev_reset(struct scsi_cmnd *scsi_cmd) spin_lock(&hrrq->_lock); list_for_each_entry(ipr_cmd, &hrrq->hrrq_pending_q, queue) { if (ipr_cmd->ioarcb.res_handle == res->res_handle) { - if (ipr_cmd->scsi_cmd) - ipr_cmd->done = ipr_scsi_eh_done; - if (ipr_cmd->qc) - ipr_cmd->done = ipr_sata_eh_done; - if (ipr_cmd->qc && - !(ipr_cmd->qc->flags & ATA_QCFLAG_FAILED)) { + if (!ipr_cmd->qc) + continue; + + ipr_cmd->done = ipr_sata_eh_done; + if (!(ipr_cmd->qc->flags & ATA_QCFLAG_FAILED)) { ipr_cmd->qc->err_mask |= AC_ERR_TIMEOUT; ipr_cmd->qc->flags |= ATA_QCFLAG_FAILED; } -- cgit v1.2.3 From 439ae285b9d9da12343e3d51a0dff1b473a6a6ac Mon Sep 17 00:00:00 2001 From: Brian King Date: Wed, 15 Mar 2017 16:58:39 -0500 Subject: scsi: ipr: Fix abort path race condition This fixes a race condition in the error handlomg paths of ipr. While a command is outstanding to the adapter, it is placed on a pending queue for the hrrq it is associated with, while holding the HRRQ lock. When a command is completed, it is removed from the pending queue, under HRRQ lock, and placed on a local list. This list is then iterated through without any locks and each command's done function is invoked, inside of which, the command gets returned to the free list while grabbing the HRRQ lock. This fixes two race conditions when commands have been removed from the pending list but have not yet been added to the free list. Both of these changes fix race conditions that could result in returning success from eh_abort_handler and then later calling scsi_done for the same request. The first race condition is in ipr_cancel_op. It looks through each pending queue to see if the command to be aborted is still outstanding or not. Rather than looking on the pending queue, reverse the logic to check to look for commands that are NOT on the free queue. The second race condition can occur when in ipr_wait_for_ops where we are waiting for responses for commands we've aborted. Signed-off-by: Brian King Reviewed-by: Wendy Xiong Tested-by: Wendy Xiong Signed-off-by: Martin K. Petersen --- drivers/scsi/ipr.c | 64 +++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 47 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 0d780c9bb09b..19162d7943cb 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -5007,6 +5007,25 @@ static int ipr_match_lun(struct ipr_cmnd *ipr_cmd, void *device) return 0; } +/** + * ipr_cmnd_is_free - Check if a command is free or not + * @ipr_cmd ipr command struct + * + * Returns: + * true / false + **/ +static bool ipr_cmnd_is_free(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_cmnd *loop_cmd; + + list_for_each_entry(loop_cmd, &ipr_cmd->hrrq->hrrq_free_q, queue) { + if (loop_cmd == ipr_cmd) + return true; + } + + return false; +} + /** * ipr_wait_for_ops - Wait for matching commands to complete * @ipr_cmd: ipr command struct @@ -5020,7 +5039,7 @@ static int ipr_wait_for_ops(struct ipr_ioa_cfg *ioa_cfg, void *device, int (*match)(struct ipr_cmnd *, void *)) { struct ipr_cmnd *ipr_cmd; - int wait; + int wait, i; unsigned long flags; struct ipr_hrr_queue *hrrq; signed long timeout = IPR_ABORT_TASK_TIMEOUT; @@ -5032,10 +5051,13 @@ static int ipr_wait_for_ops(struct ipr_ioa_cfg *ioa_cfg, void *device, for_each_hrrq(hrrq, ioa_cfg) { spin_lock_irqsave(hrrq->lock, flags); - list_for_each_entry(ipr_cmd, &hrrq->hrrq_pending_q, queue) { - if (match(ipr_cmd, device)) { - ipr_cmd->eh_comp = ∁ - wait++; + for (i = hrrq->min_cmd_id; i <= hrrq->max_cmd_id; i++) { + ipr_cmd = ioa_cfg->ipr_cmnd_list[i]; + if (!ipr_cmnd_is_free(ipr_cmd)) { + if (match(ipr_cmd, device)) { + ipr_cmd->eh_comp = ∁ + wait++; + } } } spin_unlock_irqrestore(hrrq->lock, flags); @@ -5049,10 +5071,13 @@ static int ipr_wait_for_ops(struct ipr_ioa_cfg *ioa_cfg, void *device, for_each_hrrq(hrrq, ioa_cfg) { spin_lock_irqsave(hrrq->lock, flags); - list_for_each_entry(ipr_cmd, &hrrq->hrrq_pending_q, queue) { - if (match(ipr_cmd, device)) { - ipr_cmd->eh_comp = NULL; - wait++; + for (i = hrrq->min_cmd_id; i <= hrrq->max_cmd_id; i++) { + ipr_cmd = ioa_cfg->ipr_cmnd_list[i]; + if (!ipr_cmnd_is_free(ipr_cmd)) { + if (match(ipr_cmd, device)) { + ipr_cmd->eh_comp = NULL; + wait++; + } } } spin_unlock_irqrestore(hrrq->lock, flags); @@ -5219,7 +5244,7 @@ static int __ipr_eh_dev_reset(struct scsi_cmnd *scsi_cmd) struct ipr_ioa_cfg *ioa_cfg; struct ipr_resource_entry *res; struct ata_port *ap; - int rc = 0; + int rc = 0, i; struct ipr_hrr_queue *hrrq; ENTER; @@ -5241,10 +5266,14 @@ static int __ipr_eh_dev_reset(struct scsi_cmnd *scsi_cmd) for_each_hrrq(hrrq, ioa_cfg) { spin_lock(&hrrq->_lock); - list_for_each_entry(ipr_cmd, &hrrq->hrrq_pending_q, queue) { + for (i = hrrq->min_cmd_id; i <= hrrq->max_cmd_id; i++) { + ipr_cmd = ioa_cfg->ipr_cmnd_list[i]; + if (ipr_cmd->ioarcb.res_handle == res->res_handle) { if (!ipr_cmd->qc) continue; + if (ipr_cmnd_is_free(ipr_cmd)) + continue; ipr_cmd->done = ipr_sata_eh_done; if (!(ipr_cmd->qc->flags & ATA_QCFLAG_FAILED)) { @@ -5394,7 +5423,7 @@ static int ipr_cancel_op(struct scsi_cmnd *scsi_cmd) struct ipr_resource_entry *res; struct ipr_cmd_pkt *cmd_pkt; u32 ioasc, int_reg; - int op_found = 0; + int i, op_found = 0; struct ipr_hrr_queue *hrrq; ENTER; @@ -5423,11 +5452,12 @@ static int ipr_cancel_op(struct scsi_cmnd *scsi_cmd) for_each_hrrq(hrrq, ioa_cfg) { spin_lock(&hrrq->_lock); - list_for_each_entry(ipr_cmd, &hrrq->hrrq_pending_q, queue) { - if (ipr_cmd->scsi_cmd == scsi_cmd) { - ipr_cmd->done = ipr_scsi_eh_done; - op_found = 1; - break; + for (i = hrrq->min_cmd_id; i <= hrrq->max_cmd_id; i++) { + if (ioa_cfg->ipr_cmnd_list[i]->scsi_cmd == scsi_cmd) { + if (!ipr_cmnd_is_free(ioa_cfg->ipr_cmnd_list[i])) { + op_found = 1; + break; + } } } spin_unlock(&hrrq->_lock); -- cgit v1.2.3 From f646f325a829d73abc708088d2b67cd11b775fdf Mon Sep 17 00:00:00 2001 From: Brian King Date: Wed, 15 Mar 2017 16:58:39 -0500 Subject: scsi: ipr: Error path locking fixes This patch closes up some potential race conditions observed in the error handling paths in ipr while debugging an issue resulting in a hang with SATA error handling. These patches ensure we are holding the correct lock when adding and removing commands from the free and pending queues in some error scenarios. Signed-off-by: Brian King Reviewed-by: Wendy Xiong Tested-by: Wendy Xiong Signed-off-by: Martin K. Petersen --- drivers/scsi/ipr.c | 106 ++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 93 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 19162d7943cb..95f1e6457664 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -820,7 +820,7 @@ static int ipr_set_pcix_cmd_reg(struct ipr_ioa_cfg *ioa_cfg) } /** - * ipr_sata_eh_done - done function for aborted SATA commands + * __ipr_sata_eh_done - done function for aborted SATA commands * @ipr_cmd: ipr command struct * * This function is invoked for ops generated to SATA @@ -829,7 +829,7 @@ static int ipr_set_pcix_cmd_reg(struct ipr_ioa_cfg *ioa_cfg) * Return value: * none **/ -static void ipr_sata_eh_done(struct ipr_cmnd *ipr_cmd) +static void __ipr_sata_eh_done(struct ipr_cmnd *ipr_cmd) { struct ata_queued_cmd *qc = ipr_cmd->qc; struct ipr_sata_port *sata_port = qc->ap->private_data; @@ -843,7 +843,27 @@ static void ipr_sata_eh_done(struct ipr_cmnd *ipr_cmd) } /** - * ipr_scsi_eh_done - mid-layer done function for aborted ops + * ipr_sata_eh_done - done function for aborted SATA commands + * @ipr_cmd: ipr command struct + * + * This function is invoked for ops generated to SATA + * devices which are being aborted. + * + * Return value: + * none + **/ +static void ipr_sata_eh_done(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_hrr_queue *hrrq = ipr_cmd->hrrq; + unsigned long hrrq_flags; + + spin_lock_irqsave(&hrrq->_lock, hrrq_flags); + __ipr_sata_eh_done(ipr_cmd); + spin_unlock_irqrestore(&hrrq->_lock, hrrq_flags); +} + +/** + * __ipr_scsi_eh_done - mid-layer done function for aborted ops * @ipr_cmd: ipr command struct * * This function is invoked by the interrupt handler for @@ -852,7 +872,7 @@ static void ipr_sata_eh_done(struct ipr_cmnd *ipr_cmd) * Return value: * none **/ -static void ipr_scsi_eh_done(struct ipr_cmnd *ipr_cmd) +static void __ipr_scsi_eh_done(struct ipr_cmnd *ipr_cmd) { struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd; @@ -865,6 +885,26 @@ static void ipr_scsi_eh_done(struct ipr_cmnd *ipr_cmd) list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q); } +/** + * ipr_scsi_eh_done - mid-layer done function for aborted ops + * @ipr_cmd: ipr command struct + * + * This function is invoked by the interrupt handler for + * ops generated by the SCSI mid-layer which are being aborted. + * + * Return value: + * none + **/ +static void ipr_scsi_eh_done(struct ipr_cmnd *ipr_cmd) +{ + unsigned long hrrq_flags; + struct ipr_hrr_queue *hrrq = ipr_cmd->hrrq; + + spin_lock_irqsave(&hrrq->_lock, hrrq_flags); + __ipr_scsi_eh_done(ipr_cmd); + spin_unlock_irqrestore(&hrrq->_lock, hrrq_flags); +} + /** * ipr_fail_all_ops - Fails all outstanding ops. * @ioa_cfg: ioa config struct @@ -892,9 +932,9 @@ static void ipr_fail_all_ops(struct ipr_ioa_cfg *ioa_cfg) cpu_to_be32(IPR_DRIVER_ILID); if (ipr_cmd->scsi_cmd) - ipr_cmd->done = ipr_scsi_eh_done; + ipr_cmd->done = __ipr_scsi_eh_done; else if (ipr_cmd->qc) - ipr_cmd->done = ipr_sata_eh_done; + ipr_cmd->done = __ipr_sata_eh_done; ipr_trc_hook(ipr_cmd, IPR_TRACE_FINISH, IPR_IOASC_IOA_WAS_RESET); @@ -5948,7 +5988,7 @@ static int ipr_build_ioadl(struct ipr_ioa_cfg *ioa_cfg, } /** - * ipr_erp_done - Process completion of ERP for a device + * __ipr_erp_done - Process completion of ERP for a device * @ipr_cmd: ipr command struct * * This function copies the sense buffer into the scsi_cmd @@ -5957,7 +5997,7 @@ static int ipr_build_ioadl(struct ipr_ioa_cfg *ioa_cfg, * Return value: * nothing **/ -static void ipr_erp_done(struct ipr_cmnd *ipr_cmd) +static void __ipr_erp_done(struct ipr_cmnd *ipr_cmd) { struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd; struct ipr_resource_entry *res = scsi_cmd->device->hostdata; @@ -5984,6 +6024,26 @@ static void ipr_erp_done(struct ipr_cmnd *ipr_cmd) list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q); } +/** + * ipr_erp_done - Process completion of ERP for a device + * @ipr_cmd: ipr command struct + * + * This function copies the sense buffer into the scsi_cmd + * struct and pushes the scsi_done function. + * + * Return value: + * nothing + **/ +static void ipr_erp_done(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_hrr_queue *hrrq = ipr_cmd->hrrq; + unsigned long hrrq_flags; + + spin_lock_irqsave(&hrrq->_lock, hrrq_flags); + __ipr_erp_done(ipr_cmd); + spin_unlock_irqrestore(&hrrq->_lock, hrrq_flags); +} + /** * ipr_reinit_ipr_cmnd_for_erp - Re-initialize a cmnd block to be used for ERP * @ipr_cmd: ipr command struct @@ -6016,7 +6076,7 @@ static void ipr_reinit_ipr_cmnd_for_erp(struct ipr_cmnd *ipr_cmd) } /** - * ipr_erp_request_sense - Send request sense to a device + * __ipr_erp_request_sense - Send request sense to a device * @ipr_cmd: ipr command struct * * This function sends a request sense to a device as a result @@ -6025,13 +6085,13 @@ static void ipr_reinit_ipr_cmnd_for_erp(struct ipr_cmnd *ipr_cmd) * Return value: * nothing **/ -static void ipr_erp_request_sense(struct ipr_cmnd *ipr_cmd) +static void __ipr_erp_request_sense(struct ipr_cmnd *ipr_cmd) { struct ipr_cmd_pkt *cmd_pkt = &ipr_cmd->ioarcb.cmd_pkt; u32 ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc); if (IPR_IOASC_SENSE_KEY(ioasc) > 0) { - ipr_erp_done(ipr_cmd); + __ipr_erp_done(ipr_cmd); return; } @@ -6051,6 +6111,26 @@ static void ipr_erp_request_sense(struct ipr_cmnd *ipr_cmd) IPR_REQUEST_SENSE_TIMEOUT * 2); } +/** + * ipr_erp_request_sense - Send request sense to a device + * @ipr_cmd: ipr command struct + * + * This function sends a request sense to a device as a result + * of a check condition. + * + * Return value: + * nothing + **/ +static void ipr_erp_request_sense(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_hrr_queue *hrrq = ipr_cmd->hrrq; + unsigned long hrrq_flags; + + spin_lock_irqsave(&hrrq->_lock, hrrq_flags); + __ipr_erp_request_sense(ipr_cmd); + spin_unlock_irqrestore(&hrrq->_lock, hrrq_flags); +} + /** * ipr_erp_cancel_all - Send cancel all to a device * @ipr_cmd: ipr command struct @@ -6074,7 +6154,7 @@ static void ipr_erp_cancel_all(struct ipr_cmnd *ipr_cmd) ipr_reinit_ipr_cmnd_for_erp(ipr_cmd); if (!scsi_cmd->device->simple_tags) { - ipr_erp_request_sense(ipr_cmd); + __ipr_erp_request_sense(ipr_cmd); return; } @@ -6294,7 +6374,7 @@ static void ipr_erp_start(struct ipr_ioa_cfg *ioa_cfg, u32 masked_ioasc = ioasc & IPR_IOASC_IOASC_MASK; if (!res) { - ipr_scsi_eh_done(ipr_cmd); + __ipr_scsi_eh_done(ipr_cmd); return; } -- cgit v1.2.3 From ef97d8ae12eb20d81bea5d16a0c1e33dcbe44492 Mon Sep 17 00:00:00 2001 From: Brian King Date: Wed, 15 Mar 2017 16:58:41 -0500 Subject: scsi: ipr: Fix SATA EH hang This patch fixes a hang that can occur in ATA EH with ipr. With ipr's usage of libata, commands should never end up on ap->eh_done_q. The timeout function we use for ipr, even for SATA devices, is scsi_times_out, so ATA_QCFLAG_EH_SCHEDULED never gets set for ipr and EH is driven completely by ipr and SCSI. The SCSI EH thread ends up calling ipr's eh_device_reset_handler, which then calls ata_std_error_handler. This ends up calling ipr_sata_reset, which issues a reset to the device. This should result in all pending commands getting failed back and having ata_qc_complete called for them, which should end up clearing ATA_QCFLAG_FAILED as qc->flags gets zeroed in ata_qc_free. This ensures that when we end up in ata_eh_finish, we don't do anything more with the command. On adapters that only support a single interrupt and when running with two MSI-X vectors or less, the adapter firmware guarantees that responses to all outstanding commands are sent back prior to sending the response to the SATA reset command. On newer adapters supporting multiple HRRQs, however, this can no longer be guaranteed, since the command responses and reset response may be processed on different HRRQs. If ipr returns from ipr_sata_reset before the outstanding command was returned, this sends us down the path of __ata_eh_qc_complete which then moves the associated scsi_cmd from the work_q in scsi_eh_bus_device_reset to ap->eh_done_q, which then will sit there forever and we will be wedged. This patch fixes this up by ensuring that any outstanding commands are flushed before returning from eh_device_reset_handler for a SATA device. Reported-by: David Jeffery Signed-off-by: Brian King Reviewed-by: Wendy Xiong Tested-by: Wendy Xiong Signed-off-by: Martin K. Petersen --- drivers/scsi/ipr.c | 62 ++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 41 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 95f1e6457664..b3d1e4426ecc 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -5066,6 +5066,23 @@ static bool ipr_cmnd_is_free(struct ipr_cmnd *ipr_cmd) return false; } +/** + * ipr_match_res - Match function for specified resource entry + * @ipr_cmd: ipr command struct + * @resource: resource entry to match + * + * Returns: + * 1 if command matches sdev / 0 if command does not match sdev + **/ +static int ipr_match_res(struct ipr_cmnd *ipr_cmd, void *resource) +{ + struct ipr_resource_entry *res = resource; + + if (res && ipr_cmd->ioarcb.res_handle == res->res_handle) + return 1; + return 0; +} + /** * ipr_wait_for_ops - Wait for matching commands to complete * @ipr_cmd: ipr command struct @@ -5246,7 +5263,7 @@ static int ipr_sata_reset(struct ata_link *link, unsigned int *classes, struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg; struct ipr_resource_entry *res; unsigned long lock_flags = 0; - int rc = -ENXIO; + int rc = -ENXIO, ret; ENTER; spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); @@ -5260,9 +5277,19 @@ static int ipr_sata_reset(struct ata_link *link, unsigned int *classes, if (res) { rc = ipr_device_reset(ioa_cfg, res); *classes = res->ata_class; - } + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + + ret = ipr_wait_for_ops(ioa_cfg, res, ipr_match_res); + if (ret != SUCCESS) { + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_ABBREV); + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + + wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); + } + } else + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); LEAVE; return rc; } @@ -5291,9 +5318,6 @@ static int __ipr_eh_dev_reset(struct scsi_cmnd *scsi_cmd) ioa_cfg = (struct ipr_ioa_cfg *) scsi_cmd->device->host->hostdata; res = scsi_cmd->device->hostdata; - if (!res) - return FAILED; - /* * If we are currently going through reset/reload, return failed. This will force the * mid-layer to call ipr_eh_host_reset, which will then go to sleep and wait for the @@ -5332,19 +5356,6 @@ static int __ipr_eh_dev_reset(struct scsi_cmnd *scsi_cmd) spin_unlock_irq(scsi_cmd->device->host->host_lock); ata_std_error_handler(ap); spin_lock_irq(scsi_cmd->device->host->host_lock); - - for_each_hrrq(hrrq, ioa_cfg) { - spin_lock(&hrrq->_lock); - list_for_each_entry(ipr_cmd, - &hrrq->hrrq_pending_q, queue) { - if (ipr_cmd->ioarcb.res_handle == - res->res_handle) { - rc = -EIO; - break; - } - } - spin_unlock(&hrrq->_lock); - } } else rc = ipr_device_reset(ioa_cfg, res); res->resetting_device = 0; @@ -5358,15 +5369,24 @@ static int ipr_eh_dev_reset(struct scsi_cmnd *cmd) { int rc; struct ipr_ioa_cfg *ioa_cfg; + struct ipr_resource_entry *res; ioa_cfg = (struct ipr_ioa_cfg *) cmd->device->host->hostdata; + res = cmd->device->hostdata; + + if (!res) + return FAILED; spin_lock_irq(cmd->device->host->host_lock); rc = __ipr_eh_dev_reset(cmd); spin_unlock_irq(cmd->device->host->host_lock); - if (rc == SUCCESS) - rc = ipr_wait_for_ops(ioa_cfg, cmd->device, ipr_match_lun); + if (rc == SUCCESS) { + if (ipr_is_gata(res) && res->sata_port) + rc = ipr_wait_for_ops(ioa_cfg, res, ipr_match_res); + else + rc = ipr_wait_for_ops(ioa_cfg, cmd->device, ipr_match_lun); + } return rc; } -- cgit v1.2.3 From 16a20b52d1b0c900ea2e7363cf6e10267a445002 Mon Sep 17 00:00:00 2001 From: Brian King Date: Wed, 15 Mar 2017 16:58:42 -0500 Subject: scsi: ipr: Driver version 2.6.4 Bump driver version Signed-off-by: Brian King Reviewed-by: Wendy Xiong Tested-by: Wendy Xiong Signed-off-by: Martin K. Petersen --- drivers/scsi/ipr.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h index b7d2e98eb45b..e98a87a65335 100644 --- a/drivers/scsi/ipr.h +++ b/drivers/scsi/ipr.h @@ -39,8 +39,8 @@ /* * Literals */ -#define IPR_DRIVER_VERSION "2.6.3" -#define IPR_DRIVER_DATE "(October 17, 2015)" +#define IPR_DRIVER_VERSION "2.6.4" +#define IPR_DRIVER_DATE "(March 14, 2017)" /* * IPR_MAX_CMD_PER_LUN: This defines the maximum number of outstanding -- cgit v1.2.3 From 03b1a06203a1f283ad8a20dce78f0f5f17eaeb88 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 23 Mar 2017 13:41:42 +0300 Subject: scsi: osd_uld: remove an unneeded NULL check We don't call the remove() function unless probe() succeeds so "oud" can't be NULL here. Plus, if it were NULL, we dereference it on the next line so it would crash anyway. [mkp: applied by hand] Signed-off-by: Dan Carpenter Acked-by: Boaz Harrosh Signed-off-by: Martin K. Petersen --- drivers/scsi/osd/osd_uld.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/osd/osd_uld.c b/drivers/scsi/osd/osd_uld.c index e0ce5d2fd14d..c3563a9512b7 100644 --- a/drivers/scsi/osd/osd_uld.c +++ b/drivers/scsi/osd/osd_uld.c @@ -524,10 +524,9 @@ static int osd_remove(struct device *dev) struct scsi_device *scsi_device = to_scsi_device(dev); struct osd_uld_device *oud = dev_get_drvdata(dev); - if (!oud || (oud->od.scsi_device != scsi_device)) { - OSD_ERR("Half cooked osd-device %p,%p || %p!=%p", - dev, oud, oud ? oud->od.scsi_device : NULL, - scsi_device); + if (oud->od.scsi_device != scsi_device) { + OSD_ERR("Half cooked osd-device %p, || %p!=%p", + dev, oud->od.scsi_device, scsi_device); } device_unregister(&oud->class_dev); -- cgit v1.2.3 From 031d1e0f2dc41be0859e6933fcf8b088098f7913 Mon Sep 17 00:00:00 2001 From: Tomohiro Kusumi Date: Thu, 23 Mar 2017 12:49:04 +0200 Subject: scsi: ufs: fix wrong/ambiguous fall through comments These aren't really falling through to anywhere meaningful. Signed-off-by: Tomohiro Kusumi Reviewed-by: Subhash Jadavani Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index dc6efbd1be8e..b7e5128f5fb6 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -553,15 +553,14 @@ static inline u32 ufshcd_get_intr_mask(struct ufs_hba *hba) case UFSHCI_VERSION_10: intr_mask = INTERRUPT_MASK_ALL_VER_10; break; - /* allow fall through */ case UFSHCI_VERSION_11: case UFSHCI_VERSION_20: intr_mask = INTERRUPT_MASK_ALL_VER_11; break; - /* allow fall through */ case UFSHCI_VERSION_21: default: intr_mask = INTERRUPT_MASK_ALL_VER_21; + break; } return intr_mask; -- cgit v1.2.3 From eb419229be58dc6d4a3a814116a265908e088c39 Mon Sep 17 00:00:00 2001 From: Jitendra Bhivare Date: Fri, 24 Mar 2017 14:11:40 +0530 Subject: scsi: be2iscsi: Check tag in beiscsi_mccq_compl_wait scsi host12: BS_1377 : mgmt_invalidate_connection Failed for cid=256 BUG: unable to handle kernel NULL pointer dereference at 0000000000000008 IP: [] __list_add+0xf/0xc0 PGD 0 Oops: 0000 [#1] SMP Modules linked in: ... CPU: 9 PID: 1542 Comm: iscsid Tainted: G ------------ T 3.10.0-514.el7.x86_64 #1 Hardware name: HP ProLiant DL360 Gen9/ProLiant DL360 Gen9, BIOS P89 09/12/2016 task: ffff88076f310fb0 ti: ffff88076bba8000 task.ti: ffff88076bba8000 RIP: 0010:[] [] __list_add+0xf/0xc0 RSP: 0018:ffff88076bbab8e8 EFLAGS: 00010046 RAX: 0000000000000246 RBX: ffff88076bbab990 RCX: 0000000000000000 RDX: 0000000000000000 RSI: ffff880468badf58 RDI: ffff88076bbab990 RBP: ffff88076bbab900 R08: 0000000000000246 R09: 00000000000020de R10: 0000000000000000 R11: ffff88076bbab5be R12: 0000000000000000 R13: ffff880468badf58 R14: 000000000001adb0 R15: ffff88076f310fb0 FS: 00007f377124a880(0000) GS:ffff88046fa40000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000008 CR3: 0000000771318000 CR4: 00000000001407e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Stack: ffff88076bbab990 ffff880468badf50 0000000000000001 ffff88076bbab938 ffffffff810b128b 0000000000000246 00000000cf9b7040 ffff880468bac7a0 0000000000000000 ffff880468bac7a0 ffff88076bbab9d0 ffffffffa05a6ea3 Call Trace: [] prepare_to_wait+0x7b/0x90 [] beiscsi_mccq_compl_wait+0x153/0x330 [be2iscsi] [] ? wake_up_atomic_t+0x30/0x30 [] beiscsi_ep_disconnect+0x91/0x2d0 [be2iscsi] [] iscsi_if_ep_disconnect.isra.14+0x5a/0x70 [scsi_transport_iscsi] [] iscsi_if_recv_msg+0x113b/0x14a0 [scsi_transport_iscsi] [] ? __kmalloc_node_track_caller+0x58/0x290 [] iscsi_if_rx+0x8e/0x1f0 [scsi_transport_iscsi] [] netlink_unicast+0xed/0x1b0 [] netlink_sendmsg+0x31e/0x690 [] ? netlink_rcv_wake+0x44/0x60 [] ? netlink_recvmsg+0x1e3/0x450 beiscsi_mccq_compl_wait gets called even when MCC tag allocation failed for mgmt_invalidate_connection. mcc_wait is not initialized for tag 0 so causes crash in prepare_to_wait. Signed-off-by: Jitendra Bhivare Reviewed-by: Tomas Henzl Reviewed-by: Chris Leech Signed-off-by: Martin K. Petersen --- drivers/scsi/be2iscsi/be_cmds.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/be2iscsi/be_cmds.c b/drivers/scsi/be2iscsi/be_cmds.c index 5d59e2630ce6..d14ddb276255 100644 --- a/drivers/scsi/be2iscsi/be_cmds.c +++ b/drivers/scsi/be2iscsi/be_cmds.c @@ -246,6 +246,12 @@ int beiscsi_mccq_compl_wait(struct beiscsi_hba *phba, { int rc = 0; + if (!tag || tag > MAX_MCC_CMD) { + __beiscsi_log(phba, KERN_ERR, + "BC_%d : invalid tag %u\n", tag); + return -EINVAL; + } + if (beiscsi_hba_in_error(phba)) { clear_bit(MCC_TAG_STATE_RUNNING, &phba->ctrl.ptag_state[tag].tag_state); -- cgit v1.2.3 From 49fc5152f5904aeab75aaef631ea61dff7ee76d8 Mon Sep 17 00:00:00 2001 From: Jitendra Bhivare Date: Fri, 24 Mar 2017 14:11:41 +0530 Subject: scsi: be2iscsi: Fix closing of connection CID needs to be freed even when invalidate or upload connection fails. Attempt to close connection 3 times before freeing CID. Set cleanup_type to INVALIDATE instead of force TCP_RST. This unnecessarily is terminating connection with reset instead of gracefully closing it. Set save_cfg to 0 - session not to be saved on flash. Add delay and process CQ before uploading connection. Signed-off-by: Jitendra Bhivare Reviewed-by: Tomas Henzl Reviewed-by: Chris Leech Signed-off-by: Martin K. Petersen --- drivers/scsi/be2iscsi/be.h | 1 - drivers/scsi/be2iscsi/be_cmds.h | 63 +++++++++---------- drivers/scsi/be2iscsi/be_iscsi.c | 98 +++++++++++++++++------------- drivers/scsi/be2iscsi/be_mgmt.c | 127 ++++++++++++++++++++------------------- drivers/scsi/be2iscsi/be_mgmt.h | 30 ++------- 5 files changed, 159 insertions(+), 160 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/be2iscsi/be.h b/drivers/scsi/be2iscsi/be.h index ca9440fb2325..4dd8de4a7a3e 100644 --- a/drivers/scsi/be2iscsi/be.h +++ b/drivers/scsi/be2iscsi/be.h @@ -154,7 +154,6 @@ struct be_ctrl_info { #define PAGE_SHIFT_4K 12 #define PAGE_SIZE_4K (1 << PAGE_SHIFT_4K) #define mcc_timeout 120000 /* 12s timeout */ -#define BEISCSI_LOGOUT_SYNC_DELAY 250 /* Returns number of pages spanned by the data starting at the given addr */ #define PAGES_4K_SPANNED(_address, size) \ diff --git a/drivers/scsi/be2iscsi/be_cmds.h b/drivers/scsi/be2iscsi/be_cmds.h index 1d40e83b0790..88fe731a3950 100644 --- a/drivers/scsi/be2iscsi/be_cmds.h +++ b/drivers/scsi/be2iscsi/be_cmds.h @@ -1145,24 +1145,49 @@ struct tcp_connect_and_offload_out { #define DB_DEF_PDU_EVENT_SHIFT 15 #define DB_DEF_PDU_CQPROC_SHIFT 16 -struct dmsg_cqe { - u32 dw[4]; +struct be_invalidate_connection_params_in { + struct be_cmd_req_hdr hdr; + u32 session_handle; + u16 cid; + u16 unused; +#define BE_CLEANUP_TYPE_INVALIDATE 0x8001 +#define BE_CLEANUP_TYPE_ISSUE_TCP_RST 0x8002 + u16 cleanup_type; + u16 save_cfg; +} __packed; + +struct be_invalidate_connection_params_out { + u32 session_handle; + u16 cid; + u16 unused; } __packed; -struct tcp_upload_params_in { +union be_invalidate_connection_params { + struct be_invalidate_connection_params_in req; + struct be_invalidate_connection_params_out resp; +} __packed; + +struct be_tcp_upload_params_in { struct be_cmd_req_hdr hdr; u16 id; +#define BE_UPLOAD_TYPE_GRACEFUL 1 +/* abortive upload with reset */ +#define BE_UPLOAD_TYPE_ABORT_RESET 2 +/* abortive upload without reset */ +#define BE_UPLOAD_TYPE_ABORT 3 +/* abortive upload with reset, sequence number by driver */ +#define BE_UPLOAD_TYPE_ABORT_WITH_SEQ 4 u16 upload_type; u32 reset_seq; } __packed; -struct tcp_upload_params_out { +struct be_tcp_upload_params_out { u32 dw[32]; } __packed; -union tcp_upload_params { - struct tcp_upload_params_in request; - struct tcp_upload_params_out response; +union be_tcp_upload_params { + struct be_tcp_upload_params_in request; + struct be_tcp_upload_params_out response; } __packed; struct be_ulp_fw_cfg { @@ -1243,10 +1268,7 @@ struct be_cmd_get_port_name { #define OPCODE_COMMON_WRITE_FLASH 96 #define OPCODE_COMMON_READ_FLASH 97 -/* --- CMD_ISCSI_INVALIDATE_CONNECTION_TYPE --- */ #define CMD_ISCSI_COMMAND_INVALIDATE 1 -#define CMD_ISCSI_CONNECTION_INVALIDATE 0x8001 -#define CMD_ISCSI_CONNECTION_ISSUE_TCP_RST 0x8002 #define INI_WR_CMD 1 /* Initiator write command */ #define INI_TMF_CMD 2 /* Initiator TMF command */ @@ -1269,27 +1291,6 @@ struct be_cmd_get_port_name { * preparedby * driver should not be touched */ -/* --- CMD_CHUTE_TYPE --- */ -#define CMD_CONNECTION_CHUTE_0 1 -#define CMD_CONNECTION_CHUTE_1 2 -#define CMD_CONNECTION_CHUTE_2 3 - -#define EQ_MAJOR_CODE_COMPLETION 0 - -#define CMD_ISCSI_SESSION_DEL_CFG_FROM_FLASH 0 -#define CMD_ISCSI_SESSION_SAVE_CFG_ON_FLASH 1 - -/* --- CONNECTION_UPLOAD_PARAMS --- */ -/* These parameters are used to define the type of upload desired. */ -#define CONNECTION_UPLOAD_GRACEFUL 1 /* Graceful upload */ -#define CONNECTION_UPLOAD_ABORT_RESET 2 /* Abortive upload with - * reset - */ -#define CONNECTION_UPLOAD_ABORT 3 /* Abortive upload without - * reset - */ -#define CONNECTION_UPLOAD_ABORT_WITH_SEQ 4 /* Abortive upload with reset, - * sequence number by driver */ /* Returns the number of items in the field array. */ #define BE_NUMBER_OF_FIELD(_type_, _field_) \ diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c index a4844578e357..bad6b5eee37e 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.c +++ b/drivers/scsi/be2iscsi/be_iscsi.c @@ -1263,31 +1263,58 @@ static void beiscsi_flush_cq(struct beiscsi_hba *phba) } /** - * beiscsi_close_conn - Upload the connection + * beiscsi_conn_close - Invalidate and upload connection * @ep: The iscsi endpoint - * @flag: The type of connection closure + * + * Returns 0 on success, -1 on failure. */ -static int beiscsi_close_conn(struct beiscsi_endpoint *beiscsi_ep, int flag) +static int beiscsi_conn_close(struct beiscsi_endpoint *beiscsi_ep) { - int ret = 0; - unsigned int tag; struct beiscsi_hba *phba = beiscsi_ep->phba; + unsigned int tag, attempts; + int ret; - tag = mgmt_upload_connection(phba, beiscsi_ep->ep_cid, flag); - if (!tag) { - beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG, - "BS_%d : upload failed for cid 0x%x\n", - beiscsi_ep->ep_cid); - - ret = -EAGAIN; + /** + * Without successfully invalidating and uploading connection + * driver can't reuse the CID so attempt more than once. + */ + attempts = 0; + while (attempts++ < 3) { + tag = beiscsi_invalidate_cxn(phba, beiscsi_ep); + if (tag) { + ret = beiscsi_mccq_compl_wait(phba, tag, NULL, NULL); + if (!ret) + break; + beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG, + "BS_%d : invalidate conn failed cid %d\n", + beiscsi_ep->ep_cid); + } } - ret = beiscsi_mccq_compl_wait(phba, tag, NULL, NULL); - - /* Flush the CQ entries */ + /* wait for all completions to arrive, then process them */ + msleep(250); + /* flush CQ entries */ beiscsi_flush_cq(phba); - return ret; + if (attempts > 3) + return -1; + + attempts = 0; + while (attempts++ < 3) { + tag = beiscsi_upload_cxn(phba, beiscsi_ep); + if (tag) { + ret = beiscsi_mccq_compl_wait(phba, tag, NULL, NULL); + if (!ret) + break; + beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG, + "BS_%d : upload conn failed cid %d\n", + beiscsi_ep->ep_cid); + } + } + if (attempts > 3) + return -1; + + return 0; } /** @@ -1298,12 +1325,9 @@ static int beiscsi_close_conn(struct beiscsi_endpoint *beiscsi_ep, int flag) */ void beiscsi_ep_disconnect(struct iscsi_endpoint *ep) { - struct beiscsi_conn *beiscsi_conn; struct beiscsi_endpoint *beiscsi_ep; + struct beiscsi_conn *beiscsi_conn; struct beiscsi_hba *phba; - unsigned int tag; - uint8_t mgmt_invalidate_flag, tcp_upload_flag; - unsigned short savecfg_flag = CMD_ISCSI_SESSION_SAVE_CFG_ON_FLASH; uint16_t cri_index; beiscsi_ep = ep->dd_data; @@ -1324,39 +1348,27 @@ void beiscsi_ep_disconnect(struct iscsi_endpoint *ep) if (beiscsi_ep->conn) { beiscsi_conn = beiscsi_ep->conn; iscsi_suspend_queue(beiscsi_conn->conn); - mgmt_invalidate_flag = ~BEISCSI_NO_RST_ISSUE; - tcp_upload_flag = CONNECTION_UPLOAD_GRACEFUL; - } else { - mgmt_invalidate_flag = BEISCSI_NO_RST_ISSUE; - tcp_upload_flag = CONNECTION_UPLOAD_ABORT; } if (!beiscsi_hba_is_online(phba)) { beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG, "BS_%d : HBA in error 0x%lx\n", phba->state); - goto free_ep; - } - - tag = mgmt_invalidate_connection(phba, beiscsi_ep, - beiscsi_ep->ep_cid, - mgmt_invalidate_flag, - savecfg_flag); - if (!tag) { - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, - "BS_%d : mgmt_invalidate_connection Failed for cid=%d\n", - beiscsi_ep->ep_cid); + } else { + /** + * Make CID available even if close fails. + * If not freed, FW might fail open using the CID. + */ + if (beiscsi_conn_close(beiscsi_ep) < 0) + __beiscsi_log(phba, KERN_ERR, + "BS_%d : close conn failed cid %d\n", + beiscsi_ep->ep_cid); } - beiscsi_mccq_compl_wait(phba, tag, NULL, NULL); - beiscsi_close_conn(beiscsi_ep, tcp_upload_flag); -free_ep: - msleep(BEISCSI_LOGOUT_SYNC_DELAY); beiscsi_free_ep(beiscsi_ep); if (!phba->conn_table[cri_index]) __beiscsi_log(phba, KERN_ERR, - "BS_%d : conn_table empty at %u: cid %u\n", - cri_index, - beiscsi_ep->ep_cid); + "BS_%d : conn_table empty at %u: cid %u\n", + cri_index, beiscsi_ep->ep_cid); phba->conn_table[cri_index] = NULL; iscsi_destroy_endpoint(beiscsi_ep->openiscsi_ep); } diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c index 2f6d5c2ac329..3198c8441284 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.c +++ b/drivers/scsi/be2iscsi/be_mgmt.c @@ -126,67 +126,6 @@ unsigned int mgmt_vendor_specific_fw_cmd(struct be_ctrl_info *ctrl, return tag; } -unsigned int mgmt_invalidate_connection(struct beiscsi_hba *phba, - struct beiscsi_endpoint *beiscsi_ep, - unsigned short cid, - unsigned short issue_reset, - unsigned short savecfg_flag) -{ - struct be_ctrl_info *ctrl = &phba->ctrl; - struct be_mcc_wrb *wrb; - struct iscsi_invalidate_connection_params_in *req; - unsigned int tag = 0; - - mutex_lock(&ctrl->mbox_lock); - wrb = alloc_mcc_wrb(phba, &tag); - if (!wrb) { - mutex_unlock(&ctrl->mbox_lock); - return 0; - } - - req = embedded_payload(wrb); - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); - be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI, - OPCODE_ISCSI_INI_DRIVER_INVALIDATE_CONNECTION, - sizeof(*req)); - req->session_handle = beiscsi_ep->fw_handle; - req->cid = cid; - if (issue_reset) - req->cleanup_type = CMD_ISCSI_CONNECTION_ISSUE_TCP_RST; - else - req->cleanup_type = CMD_ISCSI_CONNECTION_INVALIDATE; - req->save_cfg = savecfg_flag; - be_mcc_notify(phba, tag); - mutex_unlock(&ctrl->mbox_lock); - return tag; -} - -unsigned int mgmt_upload_connection(struct beiscsi_hba *phba, - unsigned short cid, unsigned int upload_flag) -{ - struct be_ctrl_info *ctrl = &phba->ctrl; - struct be_mcc_wrb *wrb; - struct tcp_upload_params_in *req; - unsigned int tag; - - mutex_lock(&ctrl->mbox_lock); - wrb = alloc_mcc_wrb(phba, &tag); - if (!wrb) { - mutex_unlock(&ctrl->mbox_lock); - return 0; - } - - req = embedded_payload(wrb); - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); - be_cmd_hdr_prepare(&req->hdr, CMD_COMMON_TCP_UPLOAD, - OPCODE_COMMON_TCP_UPLOAD, sizeof(*req)); - req->id = (unsigned short)cid; - req->upload_type = (unsigned char)upload_flag; - be_mcc_notify(phba, tag); - mutex_unlock(&ctrl->mbox_lock); - return tag; -} - /** * mgmt_open_connection()- Establish a TCP CXN * @dst_addr: Destination Address @@ -1449,6 +1388,72 @@ void beiscsi_offload_cxn_v2(struct beiscsi_offload_params *params, exp_statsn) / 32] + 1)); } +unsigned int beiscsi_invalidate_cxn(struct beiscsi_hba *phba, + struct beiscsi_endpoint *beiscsi_ep) +{ + struct be_invalidate_connection_params_in *req; + struct be_ctrl_info *ctrl = &phba->ctrl; + struct be_mcc_wrb *wrb; + unsigned int tag = 0; + + mutex_lock(&ctrl->mbox_lock); + wrb = alloc_mcc_wrb(phba, &tag); + if (!wrb) { + mutex_unlock(&ctrl->mbox_lock); + return 0; + } + + req = embedded_payload(wrb); + be_wrb_hdr_prepare(wrb, sizeof(union be_invalidate_connection_params), + true, 0); + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI, + OPCODE_ISCSI_INI_DRIVER_INVALIDATE_CONNECTION, + sizeof(*req)); + req->session_handle = beiscsi_ep->fw_handle; + req->cid = beiscsi_ep->ep_cid; + if (beiscsi_ep->conn) + req->cleanup_type = BE_CLEANUP_TYPE_INVALIDATE; + else + req->cleanup_type = BE_CLEANUP_TYPE_ISSUE_TCP_RST; + /** + * 0 - non-persistent targets + * 1 - save session info on flash + */ + req->save_cfg = 0; + be_mcc_notify(phba, tag); + mutex_unlock(&ctrl->mbox_lock); + return tag; +} + +unsigned int beiscsi_upload_cxn(struct beiscsi_hba *phba, + struct beiscsi_endpoint *beiscsi_ep) +{ + struct be_ctrl_info *ctrl = &phba->ctrl; + struct be_mcc_wrb *wrb; + struct be_tcp_upload_params_in *req; + unsigned int tag; + + mutex_lock(&ctrl->mbox_lock); + wrb = alloc_mcc_wrb(phba, &tag); + if (!wrb) { + mutex_unlock(&ctrl->mbox_lock); + return 0; + } + + req = embedded_payload(wrb); + be_wrb_hdr_prepare(wrb, sizeof(union be_tcp_upload_params), true, 0); + be_cmd_hdr_prepare(&req->hdr, CMD_COMMON_TCP_UPLOAD, + OPCODE_COMMON_TCP_UPLOAD, sizeof(*req)); + req->id = beiscsi_ep->ep_cid; + if (beiscsi_ep->conn) + req->upload_type = BE_UPLOAD_TYPE_GRACEFUL; + else + req->upload_type = BE_UPLOAD_TYPE_ABORT; + be_mcc_notify(phba, tag); + mutex_unlock(&ctrl->mbox_lock); + return tag; +} + int beiscsi_mgmt_invalidate_icds(struct beiscsi_hba *phba, struct invldt_cmd_tbl *inv_tbl, unsigned int nents) diff --git a/drivers/scsi/be2iscsi/be_mgmt.h b/drivers/scsi/be2iscsi/be_mgmt.h index 308f1472f98a..1ad6c401a5f6 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.h +++ b/drivers/scsi/be2iscsi/be_mgmt.h @@ -41,35 +41,11 @@ int mgmt_open_connection(struct beiscsi_hba *phba, struct beiscsi_endpoint *beiscsi_ep, struct be_dma_mem *nonemb_cmd); -unsigned int mgmt_upload_connection(struct beiscsi_hba *phba, - unsigned short cid, - unsigned int upload_flag); unsigned int mgmt_vendor_specific_fw_cmd(struct be_ctrl_info *ctrl, struct beiscsi_hba *phba, struct bsg_job *job, struct be_dma_mem *nonemb_cmd); -#define BEISCSI_NO_RST_ISSUE 0 -struct iscsi_invalidate_connection_params_in { - struct be_cmd_req_hdr hdr; - unsigned int session_handle; - unsigned short cid; - unsigned short unused; - unsigned short cleanup_type; - unsigned short save_cfg; -} __packed; - -struct iscsi_invalidate_connection_params_out { - unsigned int session_handle; - unsigned short cid; - unsigned short unused; -} __packed; - -union iscsi_invalidate_connection_params { - struct iscsi_invalidate_connection_params_in request; - struct iscsi_invalidate_connection_params_out response; -} __packed; - #define BE_INVLDT_CMD_TBL_SZ 128 struct invldt_cmd_tbl { unsigned short icd; @@ -265,6 +241,12 @@ void beiscsi_offload_cxn_v2(struct beiscsi_offload_params *params, struct wrb_handle *pwrb_handle, struct hwi_wrb_context *pwrb_context); +unsigned int beiscsi_invalidate_cxn(struct beiscsi_hba *phba, + struct beiscsi_endpoint *beiscsi_ep); + +unsigned int beiscsi_upload_cxn(struct beiscsi_hba *phba, + struct beiscsi_endpoint *beiscsi_ep); + int be_cmd_modify_eq_delay(struct beiscsi_hba *phba, struct be_set_eqd *, int num); -- cgit v1.2.3 From d1e1d63b32b79a6b3d93ce7a6dd0d48b8cf472fd Mon Sep 17 00:00:00 2001 From: Jitendra Bhivare Date: Fri, 24 Mar 2017 14:11:42 +0530 Subject: scsi: be2iscsi: Replace spin_unlock_bh with spin_lock spin_unlock_bh back_lock is used in beiscsi_eh_device_reset instead of spin_lock. Signed-off-by: Jitendra Bhivare Reviewed-by: Tomas Henzl Reviewed-by: Chris Leech Signed-off-by: Martin K. Petersen --- drivers/scsi/be2iscsi/be_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 32b2713cec93..ff4857383998 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -337,7 +337,7 @@ static int beiscsi_eh_device_reset(struct scsi_cmnd *sc) inv_tbl->task[nents] = task; nents++; } - spin_unlock_bh(&session->back_lock); + spin_unlock(&session->back_lock); spin_unlock_bh(&session->frwd_lock); rc = SUCCESS; -- cgit v1.2.3 From 90e96313a9d38c21d4b9f81a824d0fbebb5d307c Mon Sep 17 00:00:00 2001 From: Jitendra Bhivare Date: Fri, 24 Mar 2017 14:11:43 +0530 Subject: scsi: scsi_transport_iscsi: Use flush_work in iscsi_remove_session scsi_flush_work flushes workqueue for the Scsi_Host. In iSCSI offload enabled host, this would wait for all other sessions under the host. Use flush_work for the session being removed instead. Signed-off-by: Jitendra Bhivare Reviewed-by: Tomas Henzl Reviewed-by: Chris Leech Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_transport_iscsi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 568c9f26a561..a424eaeafeb0 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -2158,7 +2158,6 @@ static int iscsi_iter_destroy_conn_fn(struct device *dev, void *data) void iscsi_remove_session(struct iscsi_cls_session *session) { - struct Scsi_Host *shost = iscsi_session_to_shost(session); unsigned long flags; int err; @@ -2185,7 +2184,7 @@ void iscsi_remove_session(struct iscsi_cls_session *session) scsi_target_unblock(&session->dev, SDEV_TRANSPORT_OFFLINE); /* flush running scans then delete devices */ - scsi_flush_work(shost); + flush_work(&session->scan_work); __iscsi_unbind_session(&session->unbind_work); /* hw iscsi may not have removed all connections from session */ -- cgit v1.2.3 From fecc3824696c18dbaf95abe8f3d2480b6aee76f0 Mon Sep 17 00:00:00 2001 From: Jitendra Bhivare Date: Fri, 24 Mar 2017 14:11:44 +0530 Subject: scsi: be2iscsi: Increase HDQ default queue size Currently, ASYNC PDU default queue size is set to max connections. This leaves only one buffer per connection for any ASYNC PDUs from targets. Double the size of the default queue. Signed-off-by: Jitendra Bhivare Reviewed-by: Tomas Henzl Reviewed-by: Chris Leech Signed-off-by: Martin K. Petersen --- drivers/scsi/be2iscsi/be_main.c | 29 ++++++++++++++--------------- drivers/scsi/be2iscsi/be_main.h | 4 +++- 2 files changed, 17 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index ff4857383998..b76fd267a765 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -636,7 +636,6 @@ static void beiscsi_get_params(struct beiscsi_hba *phba) (total_cid_count + BE2_TMFS + BE2_NOPOUT_REQ)); phba->params.cxns_per_ctrl = total_cid_count; - phba->params.asyncpdus_per_ctrl = total_cid_count; phba->params.icds_per_ctrl = total_icd_count; phba->params.num_sge_per_io = BE2_SGE; phba->params.defpdu_hdr_sz = BE2_DEFPDU_HDR_SZ; @@ -2407,22 +2406,22 @@ static void beiscsi_find_mem_req(struct beiscsi_hba *phba) if (test_bit(ulp_num, &phba->fw_config.ulp_supported)) { num_async_pdu_buf_sgl_pages = - PAGES_REQUIRED(BEISCSI_GET_CID_COUNT( + PAGES_REQUIRED(BEISCSI_ASYNC_HDQ_SIZE( phba, ulp_num) * sizeof(struct phys_addr)); num_async_pdu_buf_pages = - PAGES_REQUIRED(BEISCSI_GET_CID_COUNT( + PAGES_REQUIRED(BEISCSI_ASYNC_HDQ_SIZE( phba, ulp_num) * phba->params.defpdu_hdr_sz); num_async_pdu_data_pages = - PAGES_REQUIRED(BEISCSI_GET_CID_COUNT( + PAGES_REQUIRED(BEISCSI_ASYNC_HDQ_SIZE( phba, ulp_num) * phba->params.defpdu_data_sz); num_async_pdu_data_sgl_pages = - PAGES_REQUIRED(BEISCSI_GET_CID_COUNT( + PAGES_REQUIRED(BEISCSI_ASYNC_HDQ_SIZE( phba, ulp_num) * sizeof(struct phys_addr)); @@ -2459,21 +2458,21 @@ static void beiscsi_find_mem_req(struct beiscsi_hba *phba) mem_descr_index = (HWI_MEM_ASYNC_HEADER_HANDLE_ULP0 + (ulp_num * MEM_DESCR_OFFSET)); phba->mem_req[mem_descr_index] = - BEISCSI_GET_CID_COUNT(phba, ulp_num) * - sizeof(struct hd_async_handle); + BEISCSI_ASYNC_HDQ_SIZE(phba, ulp_num) * + sizeof(struct hd_async_handle); mem_descr_index = (HWI_MEM_ASYNC_DATA_HANDLE_ULP0 + (ulp_num * MEM_DESCR_OFFSET)); phba->mem_req[mem_descr_index] = - BEISCSI_GET_CID_COUNT(phba, ulp_num) * - sizeof(struct hd_async_handle); + BEISCSI_ASYNC_HDQ_SIZE(phba, ulp_num) * + sizeof(struct hd_async_handle); mem_descr_index = (HWI_MEM_ASYNC_PDU_CONTEXT_ULP0 + (ulp_num * MEM_DESCR_OFFSET)); phba->mem_req[mem_descr_index] = - sizeof(struct hd_async_context) + - (BEISCSI_GET_CID_COUNT(phba, ulp_num) * - sizeof(struct hd_async_entry)); + sizeof(struct hd_async_context) + + (BEISCSI_ASYNC_HDQ_SIZE(phba, ulp_num) * + sizeof(struct hd_async_entry)); } } } @@ -2757,7 +2756,7 @@ static int hwi_init_async_pdu_ctx(struct beiscsi_hba *phba) ((long unsigned int)pasync_ctx + sizeof(struct hd_async_context)); - pasync_ctx->num_entries = BEISCSI_GET_CID_COUNT(phba, + pasync_ctx->num_entries = BEISCSI_ASYNC_HDQ_SIZE(phba, ulp_num); /* setup header buffers */ mem_descr = (struct be_mem_descriptor *)phba->init_mem; @@ -2895,7 +2894,7 @@ static int hwi_init_async_pdu_ctx(struct beiscsi_hba *phba) phba->params.defpdu_data_sz); num_per_mem = 0; - for (index = 0; index < BEISCSI_GET_CID_COUNT + for (index = 0; index < BEISCSI_ASYNC_HDQ_SIZE (phba, ulp_num); index++) { pasync_header_h->cri = -1; pasync_header_h->is_header = 1; @@ -3772,7 +3771,7 @@ static int hwi_init_port(struct beiscsi_hba *phba) for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) { if (test_bit(ulp_num, &phba->fw_config.ulp_supported)) { def_pdu_ring_sz = - BEISCSI_GET_CID_COUNT(phba, ulp_num) * + BEISCSI_ASYNC_HDQ_SIZE(phba, ulp_num) * sizeof(struct phys_addr); status = beiscsi_create_def_hdr(phba, phwi_context, diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h index 218857926566..216f9b4b7c7b 100644 --- a/drivers/scsi/be2iscsi/be_main.h +++ b/drivers/scsi/be2iscsi/be_main.h @@ -235,7 +235,6 @@ struct sgl_handle { struct hba_parameters { unsigned int ios_per_ctrl; unsigned int cxns_per_ctrl; - unsigned int asyncpdus_per_ctrl; unsigned int icds_per_ctrl; unsigned int num_sge_per_io; unsigned int defpdu_hdr_sz; @@ -599,6 +598,9 @@ struct hd_async_handle { u8 is_final; }; +#define BEISCSI_ASYNC_HDQ_SIZE(phba, ulp) \ + (BEISCSI_GET_CID_COUNT((phba), (ulp)) * 2) + /** * This has list of async PDUs that are waiting to be processed. * Buffers live in this list for a brief duration before they get -- cgit v1.2.3 From 1e2931f134d44e413281dfc458b537d170e98596 Mon Sep 17 00:00:00 2001 From: Jitendra Bhivare Date: Fri, 24 Mar 2017 14:11:45 +0530 Subject: scsi: be2iscsi: Use num_cons field in Rx CQE FW runs out of buffer if buffers are not posted back soon. ASYNC Rx CQE indicates that FW has consumed 8 RQEs. Use it to post back buffers instead of waiting for buffers to be processed and freed by driver. Signed-off-by: Jitendra Bhivare Reviewed-by: Tomas Henzl Reviewed-by: Chris Leech Signed-off-by: Martin K. Petersen --- drivers/scsi/be2iscsi/be_main.c | 124 ++++++++++++++++------------------------ drivers/scsi/be2iscsi/be_main.h | 1 + 2 files changed, 51 insertions(+), 74 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index b76fd267a765..1cd9c2d53d34 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -1467,7 +1467,8 @@ beiscsi_hdl_put_handle(struct hd_async_context *pasync_ctx, static struct hd_async_handle * beiscsi_hdl_get_handle(struct beiscsi_conn *beiscsi_conn, struct hd_async_context *pasync_ctx, - struct i_t_dpdu_cqe *pdpdu_cqe) + struct i_t_dpdu_cqe *pdpdu_cqe, + u8 *header) { struct beiscsi_hba *phba = beiscsi_conn->phba; struct hd_async_handle *pasync_handle; @@ -1515,6 +1516,7 @@ beiscsi_hdl_get_handle(struct beiscsi_conn *beiscsi_conn, switch (code) { case UNSOL_HDR_NOTIFY: pasync_handle = pasync_ctx->async_entry[ci].header; + *header = 1; break; case UNSOL_DATA_DIGEST_ERROR_NOTIFY: error = 1; @@ -1547,6 +1549,7 @@ beiscsi_hdl_get_handle(struct beiscsi_conn *beiscsi_conn, /* FW has stale address - attempt continuing by dropping */ } + list_del_init(&pasync_handle->link); /** * Each CID is associated with unique CRI. * ASYNC_CRI_FROM_CID mapping and CRI_FROM_CID are totaly different. @@ -1554,11 +1557,6 @@ beiscsi_hdl_get_handle(struct beiscsi_conn *beiscsi_conn, pasync_handle->cri = BE_GET_ASYNC_CRI_FROM_CID(cid); pasync_handle->is_final = final; pasync_handle->buffer_len = dpl; - /* empty the slot */ - if (pasync_handle->is_header) - pasync_ctx->async_entry[ci].header = NULL; - else - pasync_ctx->async_entry[ci].data = NULL; /** * DEF PDU header and data buffers with errors should be simply @@ -1708,85 +1706,53 @@ drop_pdu: static void beiscsi_hdq_post_handles(struct beiscsi_hba *phba, - u8 header, u8 ulp_num) + u8 header, u8 ulp_num, u16 nbuf) { - struct hd_async_handle *pasync_handle, *tmp, **slot; + struct hd_async_handle *pasync_handle; struct hd_async_context *pasync_ctx; struct hwi_controller *phwi_ctrlr; - struct list_head *hfree_list; struct phys_addr *pasync_sge; u32 ring_id, doorbell = 0; u32 doorbell_offset; - u16 prod = 0, cons; - u16 index; + u16 prod, pi; phwi_ctrlr = phba->phwi_ctrlr; pasync_ctx = HWI_GET_ASYNC_PDU_CTX(phwi_ctrlr, ulp_num); if (header) { - cons = pasync_ctx->async_header.free_entries; - hfree_list = &pasync_ctx->async_header.free_list; + pasync_sge = pasync_ctx->async_header.ring_base; + pi = pasync_ctx->async_header.pi; ring_id = phwi_ctrlr->default_pdu_hdr[ulp_num].id; doorbell_offset = phwi_ctrlr->default_pdu_hdr[ulp_num]. doorbell_offset; } else { - cons = pasync_ctx->async_data.free_entries; - hfree_list = &pasync_ctx->async_data.free_list; + pasync_sge = pasync_ctx->async_data.ring_base; + pi = pasync_ctx->async_data.pi; ring_id = phwi_ctrlr->default_pdu_data[ulp_num].id; doorbell_offset = phwi_ctrlr->default_pdu_data[ulp_num]. doorbell_offset; } - /* number of entries posted must be in multiples of 8 */ - if (cons % 8) - return; - list_for_each_entry_safe(pasync_handle, tmp, hfree_list, link) { - list_del_init(&pasync_handle->link); - pasync_handle->is_final = 0; - pasync_handle->buffer_len = 0; - - /* handles can be consumed out of order, use index in handle */ - index = pasync_handle->index; - WARN_ON(pasync_handle->is_header != header); + for (prod = 0; prod < nbuf; prod++) { if (header) - slot = &pasync_ctx->async_entry[index].header; + pasync_handle = pasync_ctx->async_entry[pi].header; else - slot = &pasync_ctx->async_entry[index].data; - /** - * The slot just tracks handle's hold and release, so - * overwriting at the same index won't do any harm but - * needs to be caught. - */ - if (*slot != NULL) { - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_ISCSI, - "BM_%d : async PDU %s slot at %u not empty\n", - header ? "header" : "data", index); + pasync_handle = pasync_ctx->async_entry[pi].data; + WARN_ON(pasync_handle->is_header != header); + WARN_ON(pasync_handle->index != pi); + /* setup the ring only once */ + if (nbuf == pasync_ctx->num_entries) { + /* note hi is lo */ + pasync_sge[pi].hi = pasync_handle->pa.u.a32.address_lo; + pasync_sge[pi].lo = pasync_handle->pa.u.a32.address_hi; } - /** - * We use same freed index as in completion to post so this - * operation is not required for refills. Its required only - * for ring creation. - */ - if (header) - pasync_sge = pasync_ctx->async_header.ring_base; - else - pasync_sge = pasync_ctx->async_data.ring_base; - pasync_sge += index; - /* if its a refill then address is same; hi is lo */ - WARN_ON(pasync_sge->hi && - pasync_sge->hi != pasync_handle->pa.u.a32.address_lo); - WARN_ON(pasync_sge->lo && - pasync_sge->lo != pasync_handle->pa.u.a32.address_hi); - pasync_sge->hi = pasync_handle->pa.u.a32.address_lo; - pasync_sge->lo = pasync_handle->pa.u.a32.address_hi; - - *slot = pasync_handle; - if (++prod == cons) - break; + if (++pi == pasync_ctx->num_entries) + pi = 0; } + if (header) - pasync_ctx->async_header.free_entries -= prod; + pasync_ctx->async_header.pi = pi; else - pasync_ctx->async_data.free_entries -= prod; + pasync_ctx->async_data.pi = pi; doorbell |= ring_id & DB_DEF_PDU_RING_ID_MASK; doorbell |= 1 << DB_DEF_PDU_REARM_SHIFT; @@ -1803,20 +1769,26 @@ beiscsi_hdq_process_compl(struct beiscsi_conn *beiscsi_conn, struct hd_async_handle *pasync_handle = NULL; struct hd_async_context *pasync_ctx; struct hwi_controller *phwi_ctrlr; + u8 ulp_num, consumed, header = 0; u16 cid_cri; - u8 ulp_num; phwi_ctrlr = phba->phwi_ctrlr; cid_cri = BE_GET_CRI_FROM_CID(beiscsi_conn->beiscsi_conn_cid); ulp_num = BEISCSI_GET_ULP_FROM_CRI(phwi_ctrlr, cid_cri); pasync_ctx = HWI_GET_ASYNC_PDU_CTX(phwi_ctrlr, ulp_num); pasync_handle = beiscsi_hdl_get_handle(beiscsi_conn, pasync_ctx, - pdpdu_cqe); - if (!pasync_handle) - return; - - beiscsi_hdl_gather_pdu(beiscsi_conn, pasync_ctx, pasync_handle); - beiscsi_hdq_post_handles(phba, pasync_handle->is_header, ulp_num); + pdpdu_cqe, &header); + if (is_chip_be2_be3r(phba)) + consumed = AMAP_GET_BITS(struct amap_i_t_dpdu_cqe, + num_cons, pdpdu_cqe); + else + consumed = AMAP_GET_BITS(struct amap_i_t_dpdu_cqe_v2, + num_cons, pdpdu_cqe); + if (pasync_handle) + beiscsi_hdl_gather_pdu(beiscsi_conn, pasync_ctx, pasync_handle); + /* num_cons indicates number of 8 RQEs consumed */ + if (consumed) + beiscsi_hdq_post_handles(phba, header, ulp_num, 8 * consumed); } void beiscsi_process_mcc_cq(struct beiscsi_hba *phba) @@ -2775,6 +2747,7 @@ static int hwi_init_async_pdu_ctx(struct beiscsi_hba *phba) "BM_%d : No Virtual address for ULP : %d\n", ulp_num); + pasync_ctx->async_header.pi = 0; pasync_ctx->async_header.buffer_size = p->defpdu_hdr_sz; pasync_ctx->async_header.va_base = mem_descr->mem_array[0].virtual_address; @@ -2883,6 +2856,7 @@ static int hwi_init_async_pdu_ctx(struct beiscsi_hba *phba) ulp_num); idx = 0; + pasync_ctx->async_data.pi = 0; pasync_ctx->async_data.buffer_size = p->defpdu_data_sz; pasync_ctx->async_data.va_base = mem_descr->mem_array[idx].virtual_address; @@ -2913,11 +2887,12 @@ static int hwi_init_async_pdu_ctx(struct beiscsi_hba *phba) list_add_tail(&pasync_header_h->link, &pasync_ctx->async_header. free_list); + pasync_ctx->async_entry[index].header = + pasync_header_h; pasync_header_h++; pasync_ctx->async_header.free_entries++; INIT_LIST_HEAD(&pasync_ctx->async_entry[index]. wq.list); - pasync_ctx->async_entry[index].header = NULL; pasync_data_h->cri = -1; pasync_data_h->is_header = 0; @@ -2954,9 +2929,10 @@ static int hwi_init_async_pdu_ctx(struct beiscsi_hba *phba) list_add_tail(&pasync_data_h->link, &pasync_ctx->async_data. free_list); + pasync_ctx->async_entry[index].data = + pasync_data_h; pasync_data_h++; pasync_ctx->async_data.free_entries++; - pasync_ctx->async_entry[index].data = NULL; } } } @@ -3734,6 +3710,7 @@ static int hwi_init_port(struct beiscsi_hba *phba) unsigned int def_pdu_ring_sz; struct be_ctrl_info *ctrl = &phba->ctrl; int status, ulp_num; + u16 nbufs; phwi_ctrlr = phba->phwi_ctrlr; phwi_context = phwi_ctrlr->phwi_ctxt; @@ -3770,9 +3747,8 @@ static int hwi_init_port(struct beiscsi_hba *phba) for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) { if (test_bit(ulp_num, &phba->fw_config.ulp_supported)) { - def_pdu_ring_sz = - BEISCSI_ASYNC_HDQ_SIZE(phba, ulp_num) * - sizeof(struct phys_addr); + nbufs = phwi_context->pasync_ctx[ulp_num]->num_entries; + def_pdu_ring_sz = nbufs * sizeof(struct phys_addr); status = beiscsi_create_def_hdr(phba, phwi_context, phwi_ctrlr, @@ -3800,9 +3776,9 @@ static int hwi_init_port(struct beiscsi_hba *phba) * let EP know about it. */ beiscsi_hdq_post_handles(phba, BEISCSI_DEFQ_HDR, - ulp_num); + ulp_num, nbufs); beiscsi_hdq_post_handles(phba, BEISCSI_DEFQ_DATA, - ulp_num); + ulp_num, nbufs); } } diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h index 216f9b4b7c7b..cebacac0a07f 100644 --- a/drivers/scsi/be2iscsi/be_main.h +++ b/drivers/scsi/be2iscsi/be_main.h @@ -634,6 +634,7 @@ struct hd_async_buf_context { * They are posted back to FW in groups of 8. */ struct list_head free_list; + u16 pi; }; /** -- cgit v1.2.3 From ba6983a745fa292c36a93cac18abaf3f316f70d1 Mon Sep 17 00:00:00 2001 From: Jitendra Bhivare Date: Fri, 24 Mar 2017 14:11:46 +0530 Subject: scsi: be2iscsi: Remove free_list for ASYNC handles With previous patch adding ASYNC Rx buffers to free_list is not required. Remove all free_list related operations. Add in_use to track if buffer posted is being processed by driver and purge all buffers received for connection if found so. Signed-off-by: Jitendra Bhivare Reviewed-by: Tomas Henzl Reviewed-by: Chris Leech Signed-off-by: Martin K. Petersen --- drivers/scsi/be2iscsi/be_main.c | 99 +++++++++++++++++------------------------ drivers/scsi/be2iscsi/be_main.h | 8 +--- 2 files changed, 43 insertions(+), 64 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 1cd9c2d53d34..ee1f1c4e910e 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -1453,15 +1453,28 @@ static inline void beiscsi_hdl_put_handle(struct hd_async_context *pasync_ctx, struct hd_async_handle *pasync_handle) { - if (pasync_handle->is_header) { - list_add_tail(&pasync_handle->link, - &pasync_ctx->async_header.free_list); - pasync_ctx->async_header.free_entries++; - } else { - list_add_tail(&pasync_handle->link, - &pasync_ctx->async_data.free_list); - pasync_ctx->async_data.free_entries++; - } + pasync_handle->is_final = 0; + pasync_handle->buffer_len = 0; + pasync_handle->in_use = 0; + list_del_init(&pasync_handle->link); +} + +static void +beiscsi_hdl_purge_handles(struct beiscsi_hba *phba, + struct hd_async_context *pasync_ctx, + u16 cri) +{ + struct hd_async_handle *pasync_handle, *tmp_handle; + struct list_head *plist; + + plist = &pasync_ctx->async_entry[cri].wq.list; + list_for_each_entry_safe(pasync_handle, tmp_handle, plist, link) + beiscsi_hdl_put_handle(pasync_ctx, pasync_handle); + + INIT_LIST_HEAD(&pasync_ctx->async_entry[cri].wq.list); + pasync_ctx->async_entry[cri].wq.hdr_len = 0; + pasync_ctx->async_entry[cri].wq.bytes_received = 0; + pasync_ctx->async_entry[cri].wq.bytes_needed = 0; } static struct hd_async_handle * @@ -1473,11 +1486,12 @@ beiscsi_hdl_get_handle(struct beiscsi_conn *beiscsi_conn, struct beiscsi_hba *phba = beiscsi_conn->phba; struct hd_async_handle *pasync_handle; struct be_bus_address phys_addr; + u16 cid, code, ci, cri; u8 final, error = 0; - u16 cid, code, ci; u32 dpl; cid = beiscsi_conn->beiscsi_conn_cid; + cri = BE_GET_ASYNC_CRI_FROM_CID(cid); /** * This function is invoked to get the right async_handle structure * from a given DEF PDU CQ entry. @@ -1525,15 +1539,7 @@ beiscsi_hdl_get_handle(struct beiscsi_conn *beiscsi_conn, break; /* called only for above codes */ default: - pasync_handle = NULL; - break; - } - - if (!pasync_handle) { - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_ISCSI, - "BM_%d : cid %d async PDU handle not found - code %d ci %d addr %llx\n", - cid, code, ci, phys_addr.u.a64.address); - return pasync_handle; + return NULL; } if (pasync_handle->pa.u.a64.address != phys_addr.u.a64.address || @@ -1549,44 +1555,33 @@ beiscsi_hdl_get_handle(struct beiscsi_conn *beiscsi_conn, /* FW has stale address - attempt continuing by dropping */ } - list_del_init(&pasync_handle->link); - /** - * Each CID is associated with unique CRI. - * ASYNC_CRI_FROM_CID mapping and CRI_FROM_CID are totaly different. - **/ - pasync_handle->cri = BE_GET_ASYNC_CRI_FROM_CID(cid); - pasync_handle->is_final = final; - pasync_handle->buffer_len = dpl; - /** * DEF PDU header and data buffers with errors should be simply * dropped as there are no consumers for it. */ if (error) { beiscsi_hdl_put_handle(pasync_ctx, pasync_handle); - pasync_handle = NULL; + return NULL; } - return pasync_handle; -} - -static void -beiscsi_hdl_purge_handles(struct beiscsi_hba *phba, - struct hd_async_context *pasync_ctx, - u16 cri) -{ - struct hd_async_handle *pasync_handle, *tmp_handle; - struct list_head *plist; - plist = &pasync_ctx->async_entry[cri].wq.list; - list_for_each_entry_safe(pasync_handle, tmp_handle, plist, link) { - list_del(&pasync_handle->link); - beiscsi_hdl_put_handle(pasync_ctx, pasync_handle); + if (pasync_handle->in_use || !list_empty(&pasync_handle->link)) { + beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_ISCSI, + "BM_%d : cid %d async PDU handle in use - code %d ci %d addr %llx\n", + cid, code, ci, phys_addr.u.a64.address); + beiscsi_hdl_purge_handles(phba, pasync_ctx, cri); } - INIT_LIST_HEAD(&pasync_ctx->async_entry[cri].wq.list); - pasync_ctx->async_entry[cri].wq.hdr_len = 0; - pasync_ctx->async_entry[cri].wq.bytes_received = 0; - pasync_ctx->async_entry[cri].wq.bytes_needed = 0; + list_del_init(&pasync_handle->link); + /** + * Each CID is associated with unique CRI. + * ASYNC_CRI_FROM_CID mapping and CRI_FROM_CID are totaly different. + **/ + pasync_handle->cri = cri; + pasync_handle->is_final = final; + pasync_handle->buffer_len = dpl; + pasync_handle->in_use = 1; + + return pasync_handle; } static unsigned int @@ -2795,7 +2790,6 @@ static int hwi_init_async_pdu_ctx(struct beiscsi_hba *phba) pasync_ctx->async_header.handle_base = mem_descr->mem_array[0].virtual_address; - INIT_LIST_HEAD(&pasync_ctx->async_header.free_list); /* setup data buffer sgls */ mem_descr = (struct be_mem_descriptor *)phba->init_mem; @@ -2829,7 +2823,6 @@ static int hwi_init_async_pdu_ctx(struct beiscsi_hba *phba) pasync_ctx->async_data.handle_base = mem_descr->mem_array[0].virtual_address; - INIT_LIST_HEAD(&pasync_ctx->async_data.free_list); pasync_header_h = (struct hd_async_handle *) @@ -2884,13 +2877,9 @@ static int hwi_init_async_pdu_ctx(struct beiscsi_hba *phba) pasync_ctx->async_header.pa_base.u.a64. address + (p->defpdu_hdr_sz * index); - list_add_tail(&pasync_header_h->link, - &pasync_ctx->async_header. - free_list); pasync_ctx->async_entry[index].header = pasync_header_h; pasync_header_h++; - pasync_ctx->async_header.free_entries++; INIT_LIST_HEAD(&pasync_ctx->async_entry[index]. wq.list); @@ -2926,13 +2915,9 @@ static int hwi_init_async_pdu_ctx(struct beiscsi_hba *phba) num_per_mem++; num_async_data--; - list_add_tail(&pasync_data_h->link, - &pasync_ctx->async_data. - free_list); pasync_ctx->async_entry[index].data = pasync_data_h; pasync_data_h++; - pasync_ctx->async_data.free_entries++; } } } diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h index cebacac0a07f..9883a8540070 100644 --- a/drivers/scsi/be2iscsi/be_main.h +++ b/drivers/scsi/be2iscsi/be_main.h @@ -596,6 +596,7 @@ struct hd_async_handle { u16 cri; u8 is_header; u8 is_final; + u8 in_use; }; #define BEISCSI_ASYNC_HDQ_SIZE(phba, ulp) \ @@ -626,14 +627,7 @@ struct hd_async_buf_context { void *va_base; void *ring_base; struct hd_async_handle *handle_base; - u16 free_entries; u32 buffer_size; - /** - * Once iSCSI layer finishes processing an async PDU, the - * handles used for the PDU are added to this list. - * They are posted back to FW in groups of 8. - */ - struct list_head free_list; u16 pi; }; -- cgit v1.2.3 From 0ddee50e3f22964864b1a5f3cc632dd306ed1060 Mon Sep 17 00:00:00 2001 From: Jitendra Bhivare Date: Fri, 24 Mar 2017 14:11:47 +0530 Subject: scsi: be2iscsi: Check size before copying ASYNC handle Data in buffers are gathered into a single buffer before giving to iSCSI layer. Though less likely to have payload more than 8K in ASYNC PDU, the data length is provide by FW and check is missing for overrun. Signed-off-by: Jitendra Bhivare Reviewed-by: Tomas Henzl Reviewed-by: Chris Leech Signed-off-by: Martin K. Petersen --- drivers/scsi/be2iscsi/be_main.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index ee1f1c4e910e..4b668c4418d1 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -1611,6 +1611,10 @@ beiscsi_hdl_fwd_pdu(struct beiscsi_conn *beiscsi_conn, dlen = pasync_handle->buffer_len; continue; } + if (!pasync_handle->buffer_len || + (dlen + pasync_handle->buffer_len) > + pasync_ctx->async_data.buffer_size) + break; memcpy(pdata + dlen, pasync_handle->pbuffer, pasync_handle->buffer_len); dlen += pasync_handle->buffer_len; @@ -1619,8 +1623,9 @@ beiscsi_hdl_fwd_pdu(struct beiscsi_conn *beiscsi_conn, if (!plast_handle->is_final) { /* last handle should have final PDU notification from FW */ beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_ISCSI, - "BM_%d : cid %u %p fwd async PDU with last handle missing - HL%u:DN%u:DR%u\n", + "BM_%d : cid %u %p fwd async PDU opcode %x with last handle missing - HL%u:DN%u:DR%u\n", beiscsi_conn->beiscsi_conn_cid, plast_handle, + AMAP_GET_BITS(struct amap_pdu_base, opcode, phdr), pasync_ctx->async_entry[cri].wq.hdr_len, pasync_ctx->async_entry[cri].wq.bytes_needed, pasync_ctx->async_entry[cri].wq.bytes_received); -- cgit v1.2.3 From 942b76542ea042a1cb7d51ce493865f892f0fe00 Mon Sep 17 00:00:00 2001 From: Jitendra Bhivare Date: Fri, 24 Mar 2017 14:11:48 +0530 Subject: scsi: be2iscsi: Update Copyright Update Broadcom Copyright markings in all files. Signed-off-by: Jitendra Bhivare Signed-off-by: Martin K. Petersen --- drivers/scsi/be2iscsi/be.h | 11 ++++------- drivers/scsi/be2iscsi/be_cmds.c | 11 ++++------- drivers/scsi/be2iscsi/be_cmds.h | 11 ++++------- drivers/scsi/be2iscsi/be_iscsi.c | 13 ++++--------- drivers/scsi/be2iscsi/be_iscsi.h | 13 ++++--------- drivers/scsi/be2iscsi/be_main.c | 13 ++++--------- drivers/scsi/be2iscsi/be_main.h | 13 ++++--------- drivers/scsi/be2iscsi/be_mgmt.c | 13 ++++--------- drivers/scsi/be2iscsi/be_mgmt.h | 13 ++++--------- 9 files changed, 36 insertions(+), 75 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/be2iscsi/be.h b/drivers/scsi/be2iscsi/be.h index 4dd8de4a7a3e..55e3f8b40eb3 100644 --- a/drivers/scsi/be2iscsi/be.h +++ b/drivers/scsi/be2iscsi/be.h @@ -1,18 +1,15 @@ -/** - * Copyright (C) 2005 - 2016 Broadcom - * All rights reserved. +/* + * Copyright 2017 Broadcom. All Rights Reserved. + * The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. The full GNU General + * as published by the Free Software Foundation. The full GNU General * Public License is included in this distribution in the file called COPYING. * * Contact Information: * linux-drivers@broadcom.com * - * Emulex - * 3333 Susan Street - * Costa Mesa, CA 92626 */ #ifndef BEISCSI_H diff --git a/drivers/scsi/be2iscsi/be_cmds.c b/drivers/scsi/be2iscsi/be_cmds.c index d14ddb276255..a79a5e72c777 100644 --- a/drivers/scsi/be2iscsi/be_cmds.c +++ b/drivers/scsi/be2iscsi/be_cmds.c @@ -1,18 +1,15 @@ -/** - * Copyright (C) 2005 - 2016 Broadcom - * All rights reserved. +/* + * Copyright 2017 Broadcom. All Rights Reserved. + * The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. The full GNU General + * as published by the Free Software Foundation. The full GNU General * Public License is included in this distribution in the file called COPYING. * * Contact Information: * linux-drivers@broadcom.com * - * Emulex - * 3333 Susan Street - * Costa Mesa, CA 92626 */ #include diff --git a/drivers/scsi/be2iscsi/be_cmds.h b/drivers/scsi/be2iscsi/be_cmds.h index 88fe731a3950..d9b6773facdb 100644 --- a/drivers/scsi/be2iscsi/be_cmds.h +++ b/drivers/scsi/be2iscsi/be_cmds.h @@ -1,18 +1,15 @@ -/** - * Copyright (C) 2005 - 2016 Broadcom - * All rights reserved. +/* + * Copyright 2017 Broadcom. All Rights Reserved. + * The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. The full GNU General + * as published by the Free Software Foundation. The full GNU General * Public License is included in this distribution in the file called COPYING. * * Contact Information: * linux-drivers@broadcom.com * - * Emulex - * 3333 Susan Street - * Costa Mesa, CA 92626 */ #ifndef BEISCSI_CMDS_H diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c index bad6b5eee37e..97dca4681784 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.c +++ b/drivers/scsi/be2iscsi/be_iscsi.c @@ -1,20 +1,15 @@ -/** - * Copyright (C) 2005 - 2016 Broadcom - * All rights reserved. +/* + * Copyright 2017 Broadcom. All Rights Reserved. + * The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. The full GNU General + * as published by the Free Software Foundation. The full GNU General * Public License is included in this distribution in the file called COPYING. * - * Written by: Jayamohan Kallickal (jayamohan.kallickal@broadcom.com) - * * Contact Information: * linux-drivers@broadcom.com * - * Emulex - * 3333 Susan Street - * Costa Mesa, CA 92626 */ #include diff --git a/drivers/scsi/be2iscsi/be_iscsi.h b/drivers/scsi/be2iscsi/be_iscsi.h index e4d67dfea4cb..b9d459a21f25 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.h +++ b/drivers/scsi/be2iscsi/be_iscsi.h @@ -1,20 +1,15 @@ -/** - * Copyright (C) 2005 - 2016 Broadcom - * All rights reserved. +/* + * Copyright 2017 Broadcom. All Rights Reserved. + * The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. The full GNU General + * as published by the Free Software Foundation. The full GNU General * Public License is included in this distribution in the file called COPYING. * - * Written by: Jayamohan Kallickal (jayamohan.kallickal@broadcom.com) - * * Contact Information: * linux-drivers@broadcom.com * - * Avago Technologies - * 3333 Susan Street - * Costa Mesa, CA 92626 */ #ifndef _BE_ISCSI_ diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 4b668c4418d1..61b7f5bf6bc6 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -1,20 +1,15 @@ -/** - * Copyright (C) 2005 - 2016 Broadcom - * All rights reserved. +/* + * Copyright 2017 Broadcom. All Rights Reserved. + * The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. The full GNU General + * as published by the Free Software Foundation. The full GNU General * Public License is included in this distribution in the file called COPYING. * - * Written by: Jayamohan Kallickal (jayamohan.kallickal@broadcom.com) - * * Contact Information: * linux-drivers@broadcom.com * - * Emulex - * 3333 Susan Street - * Costa Mesa, CA 92626 */ #include diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h index 9883a8540070..c6b95dcd7b67 100644 --- a/drivers/scsi/be2iscsi/be_main.h +++ b/drivers/scsi/be2iscsi/be_main.h @@ -1,20 +1,15 @@ -/** - * Copyright (C) 2005 - 2016 Broadcom - * All rights reserved. +/* + * Copyright 2017 Broadcom. All Rights Reserved. + * The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. The full GNU General + * as published by the Free Software Foundation. The full GNU General * Public License is included in this distribution in the file called COPYING. * - * Written by: Jayamohan Kallickal (jayamohan.kallickal@broadcom.com) - * * Contact Information: * linux-drivers@broadcom.com * - * Emulex - * 3333 Susan Street - * Costa Mesa, CA 92626 */ #ifndef _BEISCSI_MAIN_ diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c index 3198c8441284..c73775368d09 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.c +++ b/drivers/scsi/be2iscsi/be_mgmt.c @@ -1,20 +1,15 @@ -/** - * Copyright (C) 2005 - 2016 Broadcom - * All rights reserved. +/* + * Copyright 2017 Broadcom. All Rights Reserved. + * The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. The full GNU General + * as published by the Free Software Foundation. The full GNU General * Public License is included in this distribution in the file called COPYING. * - * Written by: Jayamohan Kallickal (jayamohan.kallickal@broadcom.com) - * * Contact Information: * linux-drivers@broadcom.com * - * Emulex - * 3333 Susan Street - * Costa Mesa, CA 92626 */ #include diff --git a/drivers/scsi/be2iscsi/be_mgmt.h b/drivers/scsi/be2iscsi/be_mgmt.h index 1ad6c401a5f6..06ddc5ad6874 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.h +++ b/drivers/scsi/be2iscsi/be_mgmt.h @@ -1,20 +1,15 @@ -/** - * Copyright (C) 2005 - 2016 Broadcom - * All rights reserved. +/* + * Copyright 2017 Broadcom. All Rights Reserved. + * The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. The full GNU General + * as published by the Free Software Foundation. The full GNU General * Public License is included in this distribution in the file called COPYING. * - * Written by: Jayamohan Kallickal (jayamohan.kallickal@broadcom.com) - * * Contact Information: * linux-drivers@broadcom.com * - * Emulex - * 3333 Susan Street - * Costa Mesa, CA 92626 */ #ifndef _BEISCSI_MGMT_ -- cgit v1.2.3 From cbe9fc8594e503ff071b8d2e0ce503457029b0fb Mon Sep 17 00:00:00 2001 From: Jitendra Bhivare Date: Fri, 24 Mar 2017 14:11:49 +0530 Subject: scsi: be2iscsi: Update driver version Version 11.4.0.0 Signed-off-by: Jitendra Bhivare Reviewed-by: Tomas Henzl Reviewed-by: Chris Leech Signed-off-by: Martin K. Petersen --- drivers/scsi/be2iscsi/be_main.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h index c6b95dcd7b67..ee18a954a1a8 100644 --- a/drivers/scsi/be2iscsi/be_main.h +++ b/drivers/scsi/be2iscsi/be_main.h @@ -31,7 +31,7 @@ #include #define DRV_NAME "be2iscsi" -#define BUILD_STR "11.2.1.0" +#define BUILD_STR "11.4.0.0" #define BE_NAME "Emulex OneConnect" \ "Open-iSCSI Driver version" BUILD_STR #define DRV_DESC BE_NAME " " "Driver" -- cgit v1.2.3 From a28b259b43914b04746184cec318c67bded7234c Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 28 Mar 2017 12:12:22 +0100 Subject: scsi: hisi_sas: add missing break in switch statement It appears that a break in the TRANS_TX_OPEN_CNX_ERR_NO_DESTINATION case got accidentally removed in an earlier commit, as it stands, the ts->stat and ts->open_rej_reason are being updated twice for this case which looks incorrect. Fix this by adding in the missing break statement. Detected by CoverityScan, CID#1422110 ("Missing break in switch") Fixes: 634a9585f49c7 ("scsi: hisi_sas: process error codes according to their priority") Signed-off-by: Colin Ian King Acked-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index a3af380dde9e..66c2de8b7b64 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -1709,6 +1709,7 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba, { ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_NO_DEST; + break; } case TRANS_TX_OPEN_CNX_ERR_PROTOCOL_NOT_SUPPORTED: { -- cgit v1.2.3 From c9e6010b4ef532db719c10464cf62fe2785aeeab Mon Sep 17 00:00:00 2001 From: Tomohiro Kusumi Date: Tue, 28 Mar 2017 16:49:24 +0300 Subject: scsi: ufs: make ufshcd_is_{device_present, hba_active}() return bool ufshcd driver generally uses bool for is_xxx type things instead of int, so conform to its style. Signed-off-by: Tomohiro Kusumi Reviewed-by: Subhash Jadavani Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index b7e5128f5fb6..b006f1e51aae 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -585,12 +585,12 @@ static inline u32 ufshcd_get_ufs_version(struct ufs_hba *hba) * the host controller * @hba: pointer to adapter instance * - * Returns 1 if device present, 0 if no device detected + * Returns true if device present, false if no device detected */ -static inline int ufshcd_is_device_present(struct ufs_hba *hba) +static inline bool ufshcd_is_device_present(struct ufs_hba *hba) { return (ufshcd_readl(hba, REG_CONTROLLER_STATUS) & - DEVICE_PRESENT) ? 1 : 0; + DEVICE_PRESENT) ? true : false; } /** @@ -832,11 +832,11 @@ static inline void ufshcd_hba_start(struct ufs_hba *hba) * ufshcd_is_hba_active - Get controller state * @hba: per adapter instance * - * Returns zero if controller is active, 1 otherwise + * Returns false if controller is active, true otherwise */ -static inline int ufshcd_is_hba_active(struct ufs_hba *hba) +static inline bool ufshcd_is_hba_active(struct ufs_hba *hba) { - return (ufshcd_readl(hba, REG_CONTROLLER_ENABLE) & 0x1) ? 0 : 1; + return (ufshcd_readl(hba, REG_CONTROLLER_ENABLE) & 0x1) ? false : true; } static const char *ufschd_uic_link_state_to_string( -- cgit v1.2.3 From 4a8eec2bac8454043d12be1ca7489ce3632d1137 Mon Sep 17 00:00:00 2001 From: Tomohiro Kusumi Date: Tue, 28 Mar 2017 16:49:25 +0300 Subject: scsi: ufs: use existing macro CONTROLLER_ENABLE to test register bit Signed-off-by: Tomohiro Kusumi Reviewed-by: Subhash Jadavani Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index b006f1e51aae..dd4625919f22 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -836,7 +836,8 @@ static inline void ufshcd_hba_start(struct ufs_hba *hba) */ static inline bool ufshcd_is_hba_active(struct ufs_hba *hba) { - return (ufshcd_readl(hba, REG_CONTROLLER_ENABLE) & 0x1) ? false : true; + return (ufshcd_readl(hba, REG_CONTROLLER_ENABLE) & CONTROLLER_ENABLE) + ? false : true; } static const char *ufschd_uic_link_state_to_string( -- cgit v1.2.3 From 9c490d2dd36896a1179165808a8034956e9605f6 Mon Sep 17 00:00:00 2001 From: Tomohiro Kusumi Date: Tue, 28 Mar 2017 16:49:26 +0300 Subject: scsi: ufs: non functional macro fix Not having () isn't likely to do any harm in this case, but all the other macros below do have it. Also add "are" in a comment. Signed-off-by: Tomohiro Kusumi Reviewed-by: Subhash Jadavani Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index dd4625919f22..089b76f43ad9 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -151,11 +151,11 @@ enum { }; #define ufshcd_set_eh_in_progress(h) \ - (h->eh_flags |= UFSHCD_EH_IN_PROGRESS) + ((h)->eh_flags |= UFSHCD_EH_IN_PROGRESS) #define ufshcd_eh_in_progress(h) \ - (h->eh_flags & UFSHCD_EH_IN_PROGRESS) + ((h)->eh_flags & UFSHCD_EH_IN_PROGRESS) #define ufshcd_clear_eh_in_progress(h) \ - (h->eh_flags &= ~UFSHCD_EH_IN_PROGRESS) + ((h)->eh_flags &= ~UFSHCD_EH_IN_PROGRESS) #define ufshcd_set_ufs_dev_active(h) \ ((h)->curr_dev_pwr_mode = UFS_ACTIVE_PWR_MODE) @@ -1491,7 +1491,7 @@ start: break; } /* - * If we here, it means gating work is either done or + * If we are here, it means gating work is either done or * currently running. Hence, fall through to cancel gating * work and to enable clocks. */ -- cgit v1.2.3 From f6b254513cffedbd380b31ed7963cb639df319ee Mon Sep 17 00:00:00 2001 From: Tomohiro Kusumi Date: Tue, 28 Mar 2017 16:49:27 +0300 Subject: scsi: ufs: add missing macros for register bits from UFSHCI spec Add macros for register bits that can be found in JESD223C (v2.1). Not all registers are defined in ufshci.h (i.e. some are unused whether macros are defined or undefined), but all the bits for those registers that are already defined should appear here. Signed-off-by: Tomohiro Kusumi Reviewed-by: Subhash Jadavani Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshci.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h index d14e9b965d1e..88acfd3e21af 100644 --- a/drivers/scsi/ufs/ufshci.h +++ b/drivers/scsi/ufs/ufshci.h @@ -48,6 +48,7 @@ enum { REG_UFS_VERSION = 0x08, REG_CONTROLLER_DEV_ID = 0x10, REG_CONTROLLER_PROD_ID = 0x14, + REG_AUTO_HIBERNATE_IDLE_TIMER = 0x18, REG_INTERRUPT_STATUS = 0x20, REG_INTERRUPT_ENABLE = 0x24, REG_CONTROLLER_STATUS = 0x30, @@ -171,6 +172,7 @@ enum { /* HCE - Host Controller Enable 34h */ #define CONTROLLER_ENABLE UFS_BIT(0) #define CONTROLLER_DISABLE 0x0 +#define CRYPTO_GENERAL_ENABLE UFS_BIT(1) /* UECPA - Host UIC Error Code PHY Adapter Layer 38h */ #define UIC_PHY_ADAPTER_LAYER_ERROR UFS_BIT(31) -- cgit v1.2.3 From 0b9961be101419def7f7249f8e2f9b28d28b8526 Mon Sep 17 00:00:00 2001 From: Tomohiro Kusumi Date: Tue, 28 Mar 2017 16:49:28 +0300 Subject: scsi: ufs: remove deprecated enum for hw interrupt These flags are no longer needed after 2fbd009b in 2013. Signed-off-by: Tomohiro Kusumi Reviewed-by: Subhash Jadavani Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 089b76f43ad9..109a7623b561 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -143,13 +143,6 @@ enum { UFSHCD_UIC_DME_ERROR = (1 << 5), /* DME error */ }; -/* Interrupt configuration options */ -enum { - UFSHCD_INT_DISABLE, - UFSHCD_INT_ENABLE, - UFSHCD_INT_CLEAR, -}; - #define ufshcd_set_eh_in_progress(h) \ ((h)->eh_flags |= UFSHCD_EH_IN_PROGRESS) #define ufshcd_eh_in_progress(h) \ -- cgit v1.2.3 From d985c6eaa896c7f93846f97f1f7ab47aa57903ef Mon Sep 17 00:00:00 2001 From: Tomohiro Kusumi Date: Tue, 28 Mar 2017 16:49:29 +0300 Subject: scsi: ufs: just use sizeof() for snprintf() Not much reason to use ARRAY_SIZE() when we know it's for a C string. Signed-off-by: Tomohiro Kusumi Reviewed-by: Subhash Jadavani Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 109a7623b561..790c19c2162b 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -7880,7 +7880,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) INIT_WORK(&hba->clk_scaling.resume_work, ufshcd_clk_scaling_resume_work); - snprintf(wq_name, ARRAY_SIZE(wq_name), "ufs_clkscaling_%d", + snprintf(wq_name, sizeof(wq_name), "ufs_clkscaling_%d", host->host_no); hba->clk_scaling.workq = create_singlethread_workqueue(wq_name); -- cgit v1.2.3 From 8bb74d36613322ac473ff6e3d8559c66ca531533 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 28 Mar 2017 16:22:03 +0200 Subject: scsi: hisi_sas: fix SATA dependency Removing the 'select SCSI_SAS_LIBSAS' statement in Kconfig resulted in a link failure in configurations that have hisi_sas built-in but libsas as a loadable module: drivers/scsi/built-in.o: In function `hisi_sas_scan_finished': hisi_sas_main.c:(.text+0x37ce9): undefined reference to `sas_drain_work' drivers/scsi/built-in.o: In function `hisi_sas_slave_configure': hisi_sas_main.c:(.text+0x37d17): undefined reference to `sas_slave_configure' hisi_sas_main.c:(.text+0x37d40): undefined reference to `sas_change_queue_depth' drivers/scsi/built-in.o: In function `hisi_sas_remove': All other libsas users have the 'select' statement, so we should do the same here for consistency. For all I can tell, the patch that added the sata softreset does not actually introduce a dependency on SCSI_SAS_ATA but instead adds calls into libata itself, so we can express that with a more specific dependency. We cannot have 'select SCSI_SAS_LIBSAS; depends on SCSI_SAS_ATA' as that would cause a dependency loop. Fixes: 7c594f0407de ("scsi: hisi_sas: add softreset function for SATA disk") Signed-off-by: Arnd Bergmann Acked-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/hisi_sas/Kconfig b/drivers/scsi/hisi_sas/Kconfig index ded2c201071d..374a329b91fc 100644 --- a/drivers/scsi/hisi_sas/Kconfig +++ b/drivers/scsi/hisi_sas/Kconfig @@ -2,7 +2,8 @@ config SCSI_HISI_SAS tristate "HiSilicon SAS" depends on HAS_DMA && HAS_IOMEM depends on ARM64 || COMPILE_TEST - depends on SCSI_SAS_ATA + select SCSI_SAS_LIBSAS select BLK_DEV_INTEGRITY + depends on ATA help This driver supports HiSilicon's SAS HBA -- cgit v1.2.3 From 7f1974a76d4d752bb3e781b132c1663b59ca46e7 Mon Sep 17 00:00:00 2001 From: Don Brace Date: Tue, 28 Mar 2017 16:40:13 -0500 Subject: scsi: hpsa: update pci ids Reviewed-by: Gerry Morong Reviewed-by: Scott Teel Signed-off-by: Don Brace Signed-off-by: Martin K. Petersen --- drivers/scsi/hpsa.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 524a0c755ed7..6b9a37f6517e 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -108,10 +108,12 @@ static const struct pci_device_id hpsa_pci_device_id[] = { {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x3354}, {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x3355}, {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x3356}, + {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSH, 0x103c, 0x1920}, {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSH, 0x103C, 0x1921}, {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSH, 0x103C, 0x1922}, {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSH, 0x103C, 0x1923}, {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSH, 0x103C, 0x1924}, + {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSH, 0x103c, 0x1925}, {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSH, 0x103C, 0x1926}, {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSH, 0x103C, 0x1928}, {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSH, 0x103C, 0x1929}, @@ -171,10 +173,12 @@ static struct board_type products[] = { {0x3354103C, "Smart Array P420i", &SA5_access}, {0x3355103C, "Smart Array P220i", &SA5_access}, {0x3356103C, "Smart Array P721m", &SA5_access}, + {0x1920103C, "Smart Array P430i", &SA5_access}, {0x1921103C, "Smart Array P830i", &SA5_access}, {0x1922103C, "Smart Array P430", &SA5_access}, {0x1923103C, "Smart Array P431", &SA5_access}, {0x1924103C, "Smart Array P830", &SA5_access}, + {0x1925103C, "Smart Array P831", &SA5_access}, {0x1926103C, "Smart Array P731m", &SA5_access}, {0x1928103C, "Smart Array P230i", &SA5_access}, {0x1929103C, "Smart Array P530", &SA5_access}, -- cgit v1.2.3 From 5765d180fd23dc7d76109a0cbb082df6e5cfa67a Mon Sep 17 00:00:00 2001 From: Don Brace Date: Tue, 28 Mar 2017 16:40:20 -0500 Subject: scsi: hpsa: change driver version Reviewed-by: Gerry Morong Reviewed-by: Scott Teel Signed-off-by: Don Brace Signed-off-by: Martin K. Petersen --- drivers/scsi/hpsa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 6b9a37f6517e..206b45e4b465 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -60,7 +60,7 @@ * HPSA_DRIVER_VERSION must be 3 byte values (0-255) separated by '.' * with an optional trailing '-' followed by a byte value (0-255). */ -#define HPSA_DRIVER_VERSION "3.4.16-0" +#define HPSA_DRIVER_VERSION "3.4.18-0" #define DRIVER_NAME "HP HPSA Driver (v " HPSA_DRIVER_VERSION ")" #define HPSA "hpsa" -- cgit v1.2.3 From dbd34a61c343f73f835539592fba4bdba8832e05 Mon Sep 17 00:00:00 2001 From: Szymon Mielczarek Date: Wed, 29 Mar 2017 08:19:21 +0200 Subject: Revert "scsi: ufs: add queries retry mechanism" This reverts commit 61e073590b82a539654626ecae91b8fab11db3f3. The patch introduced redundant query retries as we already had such mechanism provided with _retry functions. Both ufshcd_read_desc and ufshcd_read_unit_desc_param functions call ufshcd_query_descriptor_retry wrapper. Signed-off-by: Szymon Mielczarek Reviewed-by: Subhash Jadavani Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 54 ++++++++--------------------------------------- 1 file changed, 9 insertions(+), 45 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 790c19c2162b..7dad1c0b775d 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -3032,18 +3032,7 @@ static inline int ufshcd_read_power_desc(struct ufs_hba *hba, u8 *buf, u32 size) { - int err = 0; - int retries; - - for (retries = QUERY_REQ_RETRIES; retries > 0; retries--) { - /* Read descriptor*/ - err = ufshcd_read_desc(hba, QUERY_DESC_IDN_POWER, 0, buf, size); - if (!err) - break; - dev_dbg(hba->dev, "%s: error %d retrying\n", __func__, err); - } - - return err; + return ufshcd_read_desc(hba, QUERY_DESC_IDN_POWER, 0, buf, size); } static int ufshcd_read_device_desc(struct ufs_hba *hba, u8 *buf, u32 size) @@ -4201,24 +4190,16 @@ static void ufshcd_set_queue_depth(struct scsi_device *sdev) { int ret = 0; u8 lun_qdepth; - int retries; struct ufs_hba *hba; hba = shost_priv(sdev->host); lun_qdepth = hba->nutrs; - for (retries = QUERY_REQ_RETRIES; retries > 0; retries--) { - /* Read descriptor*/ - ret = ufshcd_read_unit_desc_param(hba, - ufshcd_scsi_to_upiu_lun(sdev->lun), - UNIT_DESC_PARAM_LU_Q_DEPTH, - &lun_qdepth, - sizeof(lun_qdepth)); - if (!ret || ret == -ENOTSUPP) - break; - - dev_dbg(hba->dev, "%s: error %d retrying\n", __func__, ret); - } + ret = ufshcd_read_unit_desc_param(hba, + ufshcd_scsi_to_upiu_lun(sdev->lun), + UNIT_DESC_PARAM_LU_Q_DEPTH, + &lun_qdepth, + sizeof(lun_qdepth)); /* Some WLUN doesn't support unit descriptor */ if (ret == -EOPNOTSUPP) @@ -5891,24 +5872,6 @@ out: return icc_level; } -static int ufshcd_set_icc_levels_attr(struct ufs_hba *hba, u32 icc_level) -{ - int ret = 0; - int retries; - - for (retries = QUERY_REQ_RETRIES; retries > 0; retries--) { - /* write attribute */ - ret = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_WRITE_ATTR, - QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, &icc_level); - if (!ret) - break; - - dev_dbg(hba->dev, "%s: failed with error %d\n", __func__, ret); - } - - return ret; -} - static void ufshcd_init_icc_levels(struct ufs_hba *hba) { int ret; @@ -5929,8 +5892,9 @@ static void ufshcd_init_icc_levels(struct ufs_hba *hba) dev_dbg(hba->dev, "%s: setting icc_level 0x%x", __func__, hba->init_prefetch_data.icc_level); - ret = ufshcd_set_icc_levels_attr(hba, - hba->init_prefetch_data.icc_level); + ret = ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_WRITE_ATTR, + QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, + &hba->init_prefetch_data.icc_level); if (ret) dev_err(hba->dev, -- cgit v1.2.3 From 831488669a334ea10f60361bb90f473ce7f655ff Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 13 Jan 2017 17:29:48 +0100 Subject: scsi: be2iscsi: switch to pci_alloc_irq_vectors And get automatic MSI-X affinity for free. Signed-off-by: Christoph Hellwig Acked-by: Jitendra Bhivare Signed-off-by: Martin K. Petersen --- drivers/scsi/be2iscsi/be_main.c | 127 +++++++++++++--------------------------- drivers/scsi/be2iscsi/be_main.h | 2 - 2 files changed, 42 insertions(+), 87 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 61b7f5bf6bc6..f862332261f8 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -796,12 +796,12 @@ static int beiscsi_init_irqs(struct beiscsi_hba *phba) struct pci_dev *pcidev = phba->pcidev; struct hwi_controller *phwi_ctrlr; struct hwi_context_memory *phwi_context; - int ret, msix_vec, i, j; + int ret, i, j; phwi_ctrlr = phba->phwi_ctrlr; phwi_context = phwi_ctrlr->phwi_ctxt; - if (phba->msix_enabled) { + if (pcidev->msix_enabled) { for (i = 0; i < phba->num_cpus; i++) { phba->msi_name[i] = kzalloc(BEISCSI_MSI_NAME, GFP_KERNEL); @@ -812,9 +812,8 @@ static int beiscsi_init_irqs(struct beiscsi_hba *phba) sprintf(phba->msi_name[i], "beiscsi_%02x_%02x", phba->shost->host_no, i); - msix_vec = phba->msix_entries[i].vector; - ret = request_irq(msix_vec, be_isr_msix, 0, - phba->msi_name[i], + ret = request_irq(pci_irq_vector(pcidev, i), + be_isr_msix, 0, phba->msi_name[i], &phwi_context->be_eq[i]); if (ret) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, @@ -832,9 +831,8 @@ static int beiscsi_init_irqs(struct beiscsi_hba *phba) } sprintf(phba->msi_name[i], "beiscsi_mcc_%02x", phba->shost->host_no); - msix_vec = phba->msix_entries[i].vector; - ret = request_irq(msix_vec, be_isr_mcc, 0, phba->msi_name[i], - &phwi_context->be_eq[i]); + ret = request_irq(pci_irq_vector(pcidev, i), be_isr_mcc, 0, + phba->msi_name[i], &phwi_context->be_eq[i]); if (ret) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT , "BM_%d : beiscsi_init_irqs-" @@ -856,9 +854,8 @@ static int beiscsi_init_irqs(struct beiscsi_hba *phba) return 0; free_msix_irqs: for (j = i - 1; j >= 0; j--) { + free_irq(pci_irq_vector(pcidev, i), &phwi_context->be_eq[j]); kfree(phba->msi_name[j]); - msix_vec = phba->msix_entries[j].vector; - free_irq(msix_vec, &phwi_context->be_eq[j]); } return ret; } @@ -3000,7 +2997,7 @@ static int beiscsi_create_eqs(struct beiscsi_hba *phba, num_eq_pages = PAGES_REQUIRED(phba->params.num_eq_entries * \ sizeof(struct be_eq_entry)); - if (phba->msix_enabled) + if (phba->pcidev->msix_enabled) eq_for_mcc = 1; else eq_for_mcc = 0; @@ -3510,7 +3507,7 @@ static int be_mcc_queues_create(struct beiscsi_hba *phba, sizeof(struct be_mcc_compl))) goto err; /* Ask BE to create MCC compl queue; */ - if (phba->msix_enabled) { + if (phba->pcidev->msix_enabled) { if (beiscsi_cmd_cq_create(ctrl, cq, &phwi_context->be_eq [phba->num_cpus].q, false, true, 0)) goto mcc_cq_free; @@ -3541,42 +3538,35 @@ err: return -ENOMEM; } -/** - * find_num_cpus()- Get the CPU online count - * @phba: ptr to priv structure - * - * CPU count is used for creating EQ. - **/ -static void find_num_cpus(struct beiscsi_hba *phba) +static void be2iscsi_enable_msix(struct beiscsi_hba *phba) { - int num_cpus = 0; - - num_cpus = num_online_cpus(); + int nvec = 1; switch (phba->generation) { case BE_GEN2: case BE_GEN3: - phba->num_cpus = (num_cpus > BEISCSI_MAX_NUM_CPUS) ? - BEISCSI_MAX_NUM_CPUS : num_cpus; + nvec = BEISCSI_MAX_NUM_CPUS + 1; break; case BE_GEN4: - /* - * If eqid_count == 1 fall back to - * INTX mechanism - **/ - if (phba->fw_config.eqid_count == 1) { - enable_msix = 0; - phba->num_cpus = 1; - return; - } - - phba->num_cpus = - (num_cpus > (phba->fw_config.eqid_count - 1)) ? - (phba->fw_config.eqid_count - 1) : num_cpus; + nvec = phba->fw_config.eqid_count; break; default: - phba->num_cpus = 1; + nvec = 2; + break; + } + + /* if eqid_count == 1 fall back to INTX */ + if (enable_msix && nvec > 1) { + const struct irq_affinity desc = { .post_vectors = 1 }; + + if (pci_alloc_irq_vectors_affinity(phba->pcidev, 2, nvec, + PCI_IRQ_MSIX | PCI_IRQ_AFFINITY, &desc) < 0) { + phba->num_cpus = nvec - 1; + return; + } } + + phba->num_cpus = 1; } static void hwi_purge_eq(struct beiscsi_hba *phba) @@ -3593,7 +3583,7 @@ static void hwi_purge_eq(struct beiscsi_hba *phba) phwi_ctrlr = phba->phwi_ctrlr; phwi_context = phwi_ctrlr->phwi_ctxt; - if (phba->msix_enabled) + if (phba->pcidev->msix_enabled) eq_msix = 1; else eq_msix = 0; @@ -3671,7 +3661,7 @@ static void hwi_cleanup_port(struct beiscsi_hba *phba) } be_mcc_queues_destroy(phba); - if (phba->msix_enabled) + if (phba->pcidev->msix_enabled) eq_for_mcc = 1; else eq_for_mcc = 0; @@ -4117,7 +4107,7 @@ static void hwi_enable_intr(struct beiscsi_hba *phba) iowrite32(reg, addr); } - if (!phba->msix_enabled) { + if (!phba->pcidev->msix_enabled) { eq = &phwi_context->be_eq[0].q; beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT, "BM_%d : eq->id=%d\n", eq->id); @@ -5240,19 +5230,6 @@ static void beiscsi_eqd_update_work(struct work_struct *work) msecs_to_jiffies(BEISCSI_EQD_UPDATE_INTERVAL)); } -static void beiscsi_msix_enable(struct beiscsi_hba *phba) -{ - int i, status; - - for (i = 0; i <= phba->num_cpus; i++) - phba->msix_entries[i].entry = i; - - status = pci_enable_msix_range(phba->pcidev, phba->msix_entries, - phba->num_cpus + 1, phba->num_cpus + 1); - if (status > 0) - phba->msix_enabled = true; -} - static void beiscsi_hw_tpe_check(unsigned long ptr) { struct beiscsi_hba *phba; @@ -5320,15 +5297,7 @@ static int beiscsi_enable_port(struct beiscsi_hba *phba) if (ret) return ret; - if (enable_msix) - find_num_cpus(phba); - else - phba->num_cpus = 1; - if (enable_msix) { - beiscsi_msix_enable(phba); - if (!phba->msix_enabled) - phba->num_cpus = 1; - } + be2iscsi_enable_msix(phba); beiscsi_get_params(phba); /* Re-enable UER. If different TPE occurs then it is recoverable. */ @@ -5357,7 +5326,7 @@ static int beiscsi_enable_port(struct beiscsi_hba *phba) irq_poll_init(&pbe_eq->iopoll, be_iopoll_budget, be_iopoll); } - i = (phba->msix_enabled) ? i : 0; + i = (phba->pcidev->msix_enabled) ? i : 0; /* Work item for MCC handling */ pbe_eq = &phwi_context->be_eq[i]; INIT_WORK(&pbe_eq->mcc_work, beiscsi_mcc_work); @@ -5395,9 +5364,7 @@ cleanup_port: hwi_cleanup_port(phba); disable_msix: - if (phba->msix_enabled) - pci_disable_msix(phba->pcidev); - + pci_free_irq_vectors(phba->pcidev); return ret; } @@ -5414,7 +5381,7 @@ static void beiscsi_disable_port(struct beiscsi_hba *phba, int unload) struct hwi_context_memory *phwi_context; struct hwi_controller *phwi_ctrlr; struct be_eq_obj *pbe_eq; - unsigned int i, msix_vec; + unsigned int i; if (!test_and_clear_bit(BEISCSI_HBA_ONLINE, &phba->state)) return; @@ -5422,16 +5389,16 @@ static void beiscsi_disable_port(struct beiscsi_hba *phba, int unload) phwi_ctrlr = phba->phwi_ctrlr; phwi_context = phwi_ctrlr->phwi_ctxt; hwi_disable_intr(phba); - if (phba->msix_enabled) { + if (phba->pcidev->msix_enabled) { for (i = 0; i <= phba->num_cpus; i++) { - msix_vec = phba->msix_entries[i].vector; - free_irq(msix_vec, &phwi_context->be_eq[i]); + free_irq(pci_irq_vector(phba->pcidev, i), + &phwi_context->be_eq[i]); kfree(phba->msi_name[i]); } } else if (phba->pcidev->irq) free_irq(phba->pcidev->irq, phba); - pci_disable_msix(phba->pcidev); + pci_free_irq_vectors(phba->pcidev); for (i = 0; i < phba->num_cpus; i++) { pbe_eq = &phwi_context->be_eq[i]; @@ -5641,21 +5608,12 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev, beiscsi_get_params(phba); beiscsi_set_uer_feature(phba); - if (enable_msix) - find_num_cpus(phba); - else - phba->num_cpus = 1; + be2iscsi_enable_msix(phba); beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT, "BM_%d : num_cpus = %d\n", phba->num_cpus); - if (enable_msix) { - beiscsi_msix_enable(phba); - if (!phba->msix_enabled) - phba->num_cpus = 1; - } - phba->shost->max_id = phba->params.cxns_per_ctrl; phba->shost->can_queue = phba->params.ios_per_ctrl; ret = beiscsi_get_memory(phba); @@ -5705,7 +5663,7 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev, irq_poll_init(&pbe_eq->iopoll, be_iopoll_budget, be_iopoll); } - i = (phba->msix_enabled) ? i : 0; + i = (phba->pcidev->msix_enabled) ? i : 0; /* Work item for MCC handling */ pbe_eq = &phwi_context->be_eq[i]; INIT_WORK(&pbe_eq->mcc_work, beiscsi_mcc_work); @@ -5776,8 +5734,7 @@ free_port: phba->ctrl.mbox_mem_alloced.dma); beiscsi_unmap_pci_function(phba); hba_free: - if (phba->msix_enabled) - pci_disable_msix(phba->pcidev); + pci_disable_msix(phba->pcidev); pci_dev_put(phba->pcidev); iscsi_host_free(phba->shost); pci_set_drvdata(pcidev, NULL); diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h index ee18a954a1a8..338dbe0800c1 100644 --- a/drivers/scsi/be2iscsi/be_main.h +++ b/drivers/scsi/be2iscsi/be_main.h @@ -317,9 +317,7 @@ struct beiscsi_hba { struct pci_dev *pcidev; unsigned int num_cpus; unsigned int nxt_cqid; - struct msix_entry msix_entries[MAX_CPUS]; char *msi_name[MAX_CPUS]; - bool msix_enabled; struct be_mem_descriptor *init_mem; unsigned short io_sgl_alloc_index; -- cgit v1.2.3 From 44a5b977128c0ffff0654392b40f4c2ce72a619b Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 23 Mar 2017 16:02:18 +0100 Subject: scsi: advansys: fix uninitialized data access gcc-7.0.1 now warns about a previously unnoticed access of uninitialized struct members: drivers/scsi/advansys.c: In function 'AscMsgOutSDTR': drivers/scsi/advansys.c:3860:26: error: '*((void *)&sdtr_buf+5)' may be used uninitialized in this function [-Werror=maybe-uninitialized] ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]); ^ drivers/scsi/advansys.c:3860:26: error: '*((void *)&sdtr_buf+7)' may be used uninitialized in this function [-Werror=maybe-uninitialized] drivers/scsi/advansys.c:3860:26: error: '*((void *)&sdtr_buf+5)' may be used uninitialized in this function [-Werror=maybe-uninitialized] drivers/scsi/advansys.c:3860:26: error: '*((void *)&sdtr_buf+7)' may be used uninitialized in this function [-Werror=maybe-uninitialized] The code has existed in this exact form at least since v2.6.12, and the warning seems correct. This uses named initializers to ensure we initialize all members of the structure. Signed-off-by: Arnd Bergmann Signed-off-by: Martin K. Petersen --- drivers/scsi/advansys.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index 81dd0927246b..24e57e770432 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c @@ -6291,18 +6291,17 @@ static uchar AscGetSynPeriodIndex(ASC_DVC_VAR *asc_dvc, uchar syn_time) static uchar AscMsgOutSDTR(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar sdtr_offset) { - EXT_MSG sdtr_buf; - uchar sdtr_period_index; - PortAddr iop_base; - - iop_base = asc_dvc->iop_base; - sdtr_buf.msg_type = EXTENDED_MESSAGE; - sdtr_buf.msg_len = MS_SDTR_LEN; - sdtr_buf.msg_req = EXTENDED_SDTR; - sdtr_buf.xfer_period = sdtr_period; + PortAddr iop_base = asc_dvc->iop_base; + uchar sdtr_period_index = AscGetSynPeriodIndex(asc_dvc, sdtr_period); + EXT_MSG sdtr_buf = { + .msg_type = EXTENDED_MESSAGE, + .msg_len = MS_SDTR_LEN, + .msg_req = EXTENDED_SDTR, + .xfer_period = sdtr_period, + .req_ack_offset = sdtr_offset, + }; sdtr_offset &= ASC_SYN_MAX_OFFSET; - sdtr_buf.req_ack_offset = sdtr_offset; - sdtr_period_index = AscGetSynPeriodIndex(asc_dvc, sdtr_period); + if (sdtr_period_index <= asc_dvc->max_sdtr_index) { AscMemWordCopyPtrToLram(iop_base, ASCV_MSGOUT_BEG, (uchar *)&sdtr_buf, -- cgit v1.2.3 From 5a68a1c29fd65669bbe1e4c3f8b7aefa3db7f208 Mon Sep 17 00:00:00 2001 From: Milan P Gandhi Date: Fri, 31 Mar 2017 14:37:04 -0700 Subject: scsi: qla2xxx: Fix typo in driver Signed-off-by: Milan P Gandhi Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_attr.c | 2 +- drivers/scsi/qla2xxx/qla_bsg.c | 2 +- drivers/scsi/qla2xxx/qla_gs.c | 2 +- drivers/scsi/qla2xxx/qla_init.c | 2 +- drivers/scsi/qla2xxx/qla_isr.c | 6 +++--- 5 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index f610103994af..4000ba3df1c0 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -695,7 +695,7 @@ qla2x00_sysfs_write_reset(struct file *filp, struct kobject *kobj, case 0x2025e: if (!IS_P3P_TYPE(ha) || vha != base_vha) { ql_log(ql_log_info, vha, 0x7071, - "FCoE ctx reset no supported.\n"); + "FCoE ctx reset not supported.\n"); return -EPERM; } diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c index 84c9098cc089..069104fed267 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.c +++ b/drivers/scsi/qla2xxx/qla_bsg.c @@ -1822,7 +1822,7 @@ qla24xx_process_bidir_cmd(struct bsg_job *bsg_job) /* Check if operating mode is P2P */ if (ha->operating_mode != P2P) { ql_log(ql_log_warn, vha, 0x70a4, - "Host is operating mode is not P2p\n"); + "Host operating mode is not P2p\n"); rval = EXT_STATUS_INVALID_CFG; goto done; } diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index ab0f873fd6a1..9bc9aa9e164a 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -144,7 +144,7 @@ qla2x00_chk_ms_status(scsi_qla_host_t *vha, ms_iocb_entry_t *ms_pkt, if (ct_rsp->header.response != cpu_to_be16(CT_ACCEPT_RESPONSE)) { ql_dbg(ql_dbg_disc + ql_dbg_buffer, vha, 0x2077, - "%s failed rejected request on port_id: %02x%02x%02x Compeltion status 0x%x, response 0x%x\n", + "%s failed rejected request on port_id: %02x%02x%02x Completion status 0x%x, response 0x%x\n", routine, vha->d_id.b.domain, vha->d_id.b.area, vha->d_id.b.al_pa, comp_status, ct_rsp->header.response); diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 32fb9007f137..26b201e17ee5 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -2323,7 +2323,7 @@ qla2x00_chip_diag(scsi_qla_host_t *vha) goto chip_diag_failed; /* Check product ID of chip */ - ql_dbg(ql_dbg_init, vha, 0x007d, "Checking product Id of chip.\n"); + ql_dbg(ql_dbg_init, vha, 0x007d, "Checking product ID of chip.\n"); mb[1] = RD_MAILBOX_REG(ha, reg, 1); mb[2] = RD_MAILBOX_REG(ha, reg, 2); diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 3c66ea29de27..8d72a2d86229 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -2075,14 +2075,14 @@ qla25xx_process_bidir_status_iocb(scsi_qla_host_t *vha, void *pkt, case CS_DATA_OVERRUN: ql_dbg(ql_dbg_user, vha, 0x70b1, - "Command completed with date overrun thread_id=%d\n", + "Command completed with data overrun thread_id=%d\n", thread_id); rval = EXT_STATUS_DATA_OVERRUN; break; case CS_DATA_UNDERRUN: ql_dbg(ql_dbg_user, vha, 0x70b2, - "Command completed with date underrun thread_id=%d\n", + "Command completed with data underrun thread_id=%d\n", thread_id); rval = EXT_STATUS_DATA_UNDERRUN; break; @@ -2109,7 +2109,7 @@ qla25xx_process_bidir_status_iocb(scsi_qla_host_t *vha, void *pkt, case CS_BIDIR_RD_UNDERRUN: ql_dbg(ql_dbg_user, vha, 0x70b6, - "Command completed with read data data underrun " + "Command completed with read data underrun " "thread_id=%d\n", thread_id); rval = EXT_STATUS_DATA_UNDERRUN; break; -- cgit v1.2.3 From 8690218a4c98af41f4abd3dba97bcf468c537629 Mon Sep 17 00:00:00 2001 From: Johannes Thumshirn Date: Mon, 3 Apr 2017 16:32:50 +0200 Subject: scsi: sas: remove sas_domain_release_transport sas_domain_release_transport is unused since at least v3.13, remove it. Signed-off-by: Johannes Thumshirn Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/libsas/sas_init.c | 7 ------- include/scsi/libsas.h | 1 - 2 files changed, 8 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c index 15ef8e2e685c..64e9cdda1c3c 100644 --- a/drivers/scsi/libsas/sas_init.c +++ b/drivers/scsi/libsas/sas_init.c @@ -566,13 +566,6 @@ sas_domain_attach_transport(struct sas_domain_function_template *dft) } EXPORT_SYMBOL_GPL(sas_domain_attach_transport); - -void sas_domain_release_transport(struct scsi_transport_template *stt) -{ - sas_release_transport(stt); -} -EXPORT_SYMBOL_GPL(sas_domain_release_transport); - /* ---------- SAS Class register/unregister ---------- */ static int __init sas_class_init(void) diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h index dae99d7d2bc0..dd0f72c95abe 100644 --- a/include/scsi/libsas.h +++ b/include/scsi/libsas.h @@ -693,7 +693,6 @@ extern int sas_bios_param(struct scsi_device *, sector_t capacity, int *hsc); extern struct scsi_transport_template * sas_domain_attach_transport(struct sas_domain_function_template *); -extern void sas_domain_release_transport(struct scsi_transport_template *); int sas_discover_root_expander(struct domain_device *); -- cgit v1.2.3 From c02465fa13b6232db664c5dcfe9c429b4fe31c99 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 30 Mar 2017 17:17:17 +0000 Subject: scsi: osd_uld: Check scsi_device_get() return value scsi_device_get() can fail. Hence check its return value. Signed-off-by: Bart Van Assche Cc: Boaz Harrosh Acked-by: Boaz Harrosh Signed-off-by: Martin K. Petersen --- drivers/scsi/osd/osd_uld.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/osd/osd_uld.c b/drivers/scsi/osd/osd_uld.c index c3563a9512b7..ed948025112c 100644 --- a/drivers/scsi/osd/osd_uld.c +++ b/drivers/scsi/osd/osd_uld.c @@ -464,14 +464,15 @@ static int osd_probe(struct device *dev) /* hold one more reference to the scsi_device that will get released * in __release, in case a logout is happening while fs is mounted */ - scsi_device_get(scsi_device); + if (scsi_device_get(scsi_device)) + goto err_put_disk; osd_dev_init(&oud->od, scsi_device); /* Detect the OSD Version */ error = __detect_osd(oud); if (error) { OSD_ERR("osd detection failed, non-compatible OSD device\n"); - goto err_put_disk; + goto err_put_sdev; } /* init the char-device for communication with user-mode */ @@ -508,8 +509,9 @@ static int osd_probe(struct device *dev) err_put_cdev: cdev_del(&oud->cdev); -err_put_disk: +err_put_sdev: scsi_device_put(scsi_device); +err_put_disk: put_disk(disk); err_free_osd: dev_set_drvdata(dev, NULL); -- cgit v1.2.3 From 75106523f39751390b5789b36ee1d213b3af1945 Mon Sep 17 00:00:00 2001 From: Mauricio Faria de Oliveira Date: Wed, 5 Apr 2017 12:18:19 -0300 Subject: scsi: ses: don't get power status of SES device slot on probe The commit 08024885a2a3 ("ses: Add power_status to SES device slot") introduced the 'power_status' attribute to enclosure components and the associated callbacks. There are 2 callbacks available to get the power status of a device: 1) ses_get_power_status() for 'struct enclosure_component_callbacks' 2) get_component_power_status() for the sysfs device attribute (these are available for kernel-space and user-space, respectively.) However, despite both methods being available to get power status on demand, that commit also introduced a call to get power status in ses_enclosure_data_process(). This dramatically increased the total probe time for SCSI devices on larger configurations, because ses_enclosure_data_process() is called several times during the SCSI devices probe and loops over the component devices (but that is another problem, another patch). That results in a tremendous continuous hammering of SCSI Receive Diagnostics commands to the enclosure-services device, which does delay the total probe time for the SCSI devices __significantly__: Originally, ~34 minutes on a system attached to ~170 disks: [ 9214.490703] mpt3sas version 13.100.00.00 loaded ... [11256.580231] scsi 17:0:177:0: qdepth(16), tagged(1), simple(0), ordered(0), scsi_level(6), cmd_que(1) With this patch, it decreased to ~2.5 minutes -- a 13.6x faster [ 1002.992533] mpt3sas version 13.100.00.00 loaded ... [ 1151.978831] scsi 11:0:177:0: qdepth(16), tagged(1), simple(0), ordered(0), scsi_level(6), cmd_que(1) Back to the commit discussion.. on the ses_get_power_status() call introduced in ses_enclosure_data_process(): impact of removing it. That may possibly be in place to initialize the power status value on device probe. However, those 2 functions available to retrieve that value _do_ automatically refresh/update it. So the potential benefit would be a direct access of the 'power_status' field which does not use the callbacks... But the only reader of 'struct enclosure_component::power_status' is the get_component_power_status() callback for sysfs attribute, and it _does_ check for and call the .get_power_status callback, (which indeed is defined and implemented by that commit), so the power status value is, again, automatically updated. So, the remaining potential for a direct/non-callback access to the power_status attribute would be out-of-tree modules -- well, for those, if they are for whatever reason interested in values that are set during device probe and not up-to-date by the time they need it.. well, that would be curious. Well, to handle that more properly, set the initial power state value to '-1' (i.e., uninitialized) instead of '1' (power 'on'), and check for it in that callback which may do an direct access to the field value _if_ a callback function is not defined. Signed-off-by: Mauricio Faria de Oliveira Fixes: 08024885a2a3 ("ses: Add power_status to SES device slot") Reviewed-by: Dan Williams Reviewed-by: Song Liu Signed-off-by: Martin K. Petersen --- drivers/misc/enclosure.c | 7 ++++++- drivers/scsi/ses.c | 1 - 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/enclosure.c b/drivers/misc/enclosure.c index 65fed7146e9b..d3fe3ea902d4 100644 --- a/drivers/misc/enclosure.c +++ b/drivers/misc/enclosure.c @@ -148,7 +148,7 @@ enclosure_register(struct device *dev, const char *name, int components, for (i = 0; i < components; i++) { edev->component[i].number = -1; edev->component[i].slot = -1; - edev->component[i].power_status = 1; + edev->component[i].power_status = -1; } mutex_lock(&container_list_lock); @@ -594,6 +594,11 @@ static ssize_t get_component_power_status(struct device *cdev, if (edev->cb->get_power_status) edev->cb->get_power_status(edev, ecomp); + + /* If still uninitialized, the callback failed or does not exist. */ + if (ecomp->power_status == -1) + return (edev->cb->get_power_status) ? -EIO : -ENOTTY; + return snprintf(buf, 40, "%s\n", ecomp->power_status ? "on" : "off"); } diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c index 50adabbb5808..f1cdf32d7514 100644 --- a/drivers/scsi/ses.c +++ b/drivers/scsi/ses.c @@ -548,7 +548,6 @@ static void ses_enclosure_data_process(struct enclosure_device *edev, ecomp = &edev->component[components++]; if (!IS_ERR(ecomp)) { - ses_get_power_status(edev, ecomp); if (addl_desc_ptr) ses_process_descriptor( ecomp, -- cgit v1.2.3 From 104d9c7f94aa835b9d7bde38b13b611ddb8adbb6 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 12 Jan 2017 11:17:29 +0100 Subject: scsi: csiostor: switch to pci_alloc_irq_vectors And get automatic MSI-X affinity for free. Signed-off-by: Christoph Hellwig Acked-by: Varun Prakash Signed-off-by: Martin K. Petersen --- drivers/scsi/csiostor/csio_hw.h | 1 - drivers/scsi/csiostor/csio_isr.c | 128 ++++++++++++++------------------------- 2 files changed, 47 insertions(+), 82 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/csiostor/csio_hw.h b/drivers/scsi/csiostor/csio_hw.h index 029bef82c057..62758e830d3b 100644 --- a/drivers/scsi/csiostor/csio_hw.h +++ b/drivers/scsi/csiostor/csio_hw.h @@ -95,7 +95,6 @@ enum { }; struct csio_msix_entries { - unsigned short vector; /* Assigned MSI-X vector */ void *dev_id; /* Priv object associated w/ this msix*/ char desc[24]; /* Description of this vector */ }; diff --git a/drivers/scsi/csiostor/csio_isr.c b/drivers/scsi/csiostor/csio_isr.c index 2fb71c6c3b37..7c8814715711 100644 --- a/drivers/scsi/csiostor/csio_isr.c +++ b/drivers/scsi/csiostor/csio_isr.c @@ -383,17 +383,15 @@ csio_request_irqs(struct csio_hw *hw) int rv, i, j, k = 0; struct csio_msix_entries *entryp = &hw->msix_entries[0]; struct csio_scsi_cpu_info *info; + struct pci_dev *pdev = hw->pdev; if (hw->intr_mode != CSIO_IM_MSIX) { - rv = request_irq(hw->pdev->irq, csio_fcoe_isr, - (hw->intr_mode == CSIO_IM_MSI) ? - 0 : IRQF_SHARED, - KBUILD_MODNAME, hw); + rv = request_irq(pci_irq_vector(pdev, 0), csio_fcoe_isr, + hw->intr_mode == CSIO_IM_MSI ? 0 : IRQF_SHARED, + KBUILD_MODNAME, hw); if (rv) { - if (hw->intr_mode == CSIO_IM_MSI) - pci_disable_msi(hw->pdev); csio_err(hw, "Failed to allocate interrupt line.\n"); - return -EINVAL; + goto out_free_irqs; } goto out; @@ -402,22 +400,22 @@ csio_request_irqs(struct csio_hw *hw) /* Add the MSIX vector descriptions */ csio_add_msix_desc(hw); - rv = request_irq(entryp[k].vector, csio_nondata_isr, 0, + rv = request_irq(pci_irq_vector(pdev, k), csio_nondata_isr, 0, entryp[k].desc, hw); if (rv) { csio_err(hw, "IRQ request failed for vec %d err:%d\n", - entryp[k].vector, rv); - goto err; + pci_irq_vector(pdev, k), rv); + goto out_free_irqs; } - entryp[k++].dev_id = (void *)hw; + entryp[k++].dev_id = hw; - rv = request_irq(entryp[k].vector, csio_fwevt_isr, 0, + rv = request_irq(pci_irq_vector(pdev, k), csio_fwevt_isr, 0, entryp[k].desc, hw); if (rv) { csio_err(hw, "IRQ request failed for vec %d err:%d\n", - entryp[k].vector, rv); - goto err; + pci_irq_vector(pdev, k), rv); + goto out_free_irqs; } entryp[k++].dev_id = (void *)hw; @@ -429,51 +427,31 @@ csio_request_irqs(struct csio_hw *hw) struct csio_scsi_qset *sqset = &hw->sqset[i][j]; struct csio_q *q = hw->wrm.q_arr[sqset->iq_idx]; - rv = request_irq(entryp[k].vector, csio_scsi_isr, 0, + rv = request_irq(pci_irq_vector(pdev, k), csio_scsi_isr, 0, entryp[k].desc, q); if (rv) { csio_err(hw, "IRQ request failed for vec %d err:%d\n", - entryp[k].vector, rv); - goto err; + pci_irq_vector(pdev, k), rv); + goto out_free_irqs; } - entryp[k].dev_id = (void *)q; + entryp[k].dev_id = q; } /* for all scsi cpus */ } /* for all ports */ out: hw->flags |= CSIO_HWF_HOST_INTR_ENABLED; - return 0; -err: - for (i = 0; i < k; i++) { - entryp = &hw->msix_entries[i]; - free_irq(entryp->vector, entryp->dev_id); - } - pci_disable_msix(hw->pdev); - +out_free_irqs: + for (i = 0; i < k; i++) + free_irq(pci_irq_vector(pdev, i), hw->msix_entries[i].dev_id); + pci_free_irq_vectors(hw->pdev); return -EINVAL; } -static void -csio_disable_msix(struct csio_hw *hw, bool free) -{ - int i; - struct csio_msix_entries *entryp; - int cnt = hw->num_sqsets + CSIO_EXTRA_VECS; - - if (free) { - for (i = 0; i < cnt; i++) { - entryp = &hw->msix_entries[i]; - free_irq(entryp->vector, entryp->dev_id); - } - } - pci_disable_msix(hw->pdev); -} - /* Reduce per-port max possible CPUs */ static void csio_reduce_sqsets(struct csio_hw *hw, int cnt) @@ -500,10 +478,9 @@ static int csio_enable_msix(struct csio_hw *hw) { int i, j, k, n, min, cnt; - struct csio_msix_entries *entryp; - struct msix_entry *entries; int extra = CSIO_EXTRA_VECS; struct csio_scsi_cpu_info *info; + struct irq_affinity desc = { .pre_vectors = 2 }; min = hw->num_pports + extra; cnt = hw->num_sqsets + extra; @@ -512,50 +489,35 @@ csio_enable_msix(struct csio_hw *hw) if (hw->flags & CSIO_HWF_USING_SOFT_PARAMS || !csio_is_hw_master(hw)) cnt = min_t(uint8_t, hw->cfg_niq, cnt); - entries = kzalloc(sizeof(struct msix_entry) * cnt, GFP_KERNEL); - if (!entries) - return -ENOMEM; - - for (i = 0; i < cnt; i++) - entries[i].entry = (uint16_t)i; - csio_dbg(hw, "FW supp #niq:%d, trying %d msix's\n", hw->cfg_niq, cnt); - cnt = pci_enable_msix_range(hw->pdev, entries, min, cnt); - if (cnt < 0) { - kfree(entries); + cnt = pci_alloc_irq_vectors_affinity(hw->pdev, min, cnt, + PCI_IRQ_MSIX | PCI_IRQ_AFFINITY, &desc); + if (cnt < 0) return cnt; - } if (cnt < (hw->num_sqsets + extra)) { csio_dbg(hw, "Reducing sqsets to %d\n", cnt - extra); csio_reduce_sqsets(hw, cnt - extra); } - /* Save off vectors */ - for (i = 0; i < cnt; i++) { - entryp = &hw->msix_entries[i]; - entryp->vector = entries[i].vector; - } - /* Distribute vectors */ k = 0; - csio_set_nondata_intr_idx(hw, entries[k].entry); - csio_set_mb_intr_idx(csio_hw_to_mbm(hw), entries[k++].entry); - csio_set_fwevt_intr_idx(hw, entries[k++].entry); + csio_set_nondata_intr_idx(hw, k); + csio_set_mb_intr_idx(csio_hw_to_mbm(hw), k++); + csio_set_fwevt_intr_idx(hw, k++); for (i = 0; i < hw->num_pports; i++) { info = &hw->scsi_cpu_info[i]; for (j = 0; j < hw->num_scsi_msix_cpus; j++) { n = (j % info->max_cpus) + k; - hw->sqset[i][j].intr_idx = entries[n].entry; + hw->sqset[i][j].intr_idx = n; } k += info->max_cpus; } - kfree(entries); return 0; } @@ -597,22 +559,26 @@ csio_intr_disable(struct csio_hw *hw, bool free) { csio_hw_intr_disable(hw); - switch (hw->intr_mode) { - case CSIO_IM_MSIX: - csio_disable_msix(hw, free); - break; - case CSIO_IM_MSI: - if (free) - free_irq(hw->pdev->irq, hw); - pci_disable_msi(hw->pdev); - break; - case CSIO_IM_INTX: - if (free) - free_irq(hw->pdev->irq, hw); - break; - default: - break; + if (free) { + int i; + + switch (hw->intr_mode) { + case CSIO_IM_MSIX: + for (i = 0; i < hw->num_sqsets + CSIO_EXTRA_VECS; i++) { + free_irq(pci_irq_vector(hw->pdev, i), + hw->msix_entries[i].dev_id); + } + break; + case CSIO_IM_MSI: + case CSIO_IM_INTX: + free_irq(pci_irq_vector(hw->pdev, 0), hw); + break; + default: + break; + } } + + pci_free_irq_vectors(hw->pdev); hw->intr_mode = CSIO_IM_NONE; hw->flags &= ~CSIO_HWF_HOST_INTR_ENABLED; } -- cgit v1.2.3 From 7a38dc0bfb4cc39ed57e120e2224673f3d4d200f Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Thu, 6 Apr 2017 15:36:29 +0200 Subject: scsi: scsi_error: count medium access timeout only once per EH run The current medium access timeout counter will be increased for each command, so if there are enough failed commands we'll hit the medium access timeout for even a single device failure and the following kernel message is displayed: sd H:C:T:L: [sdXY] Medium access timeout failure. Offlining disk! Fix this by making the timeout per EH run, ie the counter will only be increased once per device and EH run. Fixes: 18a4d0a ("[SCSI] Handle disk devices which can not process medium access commands") Cc: Ewan Milne Cc: Lawrence Obermann Cc: Benjamin Block Cc: Steffen Maier Signed-off-by: Hannes Reinecke Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_error.c | 18 ++++++++++++++++++ drivers/scsi/sd.c | 27 ++++++++++++++++++++++++++- drivers/scsi/sd.h | 1 + include/scsi/scsi_driver.h | 1 + 4 files changed, 46 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index f2cafae150bc..370f6c045b60 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -220,6 +220,23 @@ scsi_abort_command(struct scsi_cmnd *scmd) return SUCCESS; } +/** + * scsi_eh_reset - call into ->eh_action to reset internal counters + * @scmd: scmd to run eh on. + * + * The scsi driver might be carrying internal state about the + * devices, so we need to call into the driver to reset the + * internal state once the error handler is started. + */ +static void scsi_eh_reset(struct scsi_cmnd *scmd) +{ + if (!blk_rq_is_passthrough(scmd->request)) { + struct scsi_driver *sdrv = scsi_cmd_to_driver(scmd); + if (sdrv->eh_reset) + sdrv->eh_reset(scmd); + } +} + /** * scsi_eh_scmd_add - add scsi cmd to error handling. * @scmd: scmd to run eh on. @@ -249,6 +266,7 @@ int scsi_eh_scmd_add(struct scsi_cmnd *scmd, int eh_flag) if (scmd->eh_eflags & SCSI_EH_ABORT_SCHEDULED) eh_flag &= ~SCSI_EH_CANCEL_CMD; scmd->eh_eflags |= eh_flag; + scsi_eh_reset(scmd); list_add_tail(&scmd->eh_entry, &shost->eh_cmd_q); shost->host_failed++; scsi_eh_wakeup(shost); diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index d277e8620e3e..bd2a38ef46f5 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -115,6 +115,7 @@ static void sd_rescan(struct device *); static int sd_init_command(struct scsi_cmnd *SCpnt); static void sd_uninit_command(struct scsi_cmnd *SCpnt); static int sd_done(struct scsi_cmnd *); +static void sd_eh_reset(struct scsi_cmnd *); static int sd_eh_action(struct scsi_cmnd *, int); static void sd_read_capacity(struct scsi_disk *sdkp, unsigned char *buffer); static void scsi_disk_release(struct device *cdev); @@ -532,6 +533,7 @@ static struct scsi_driver sd_template = { .uninit_command = sd_uninit_command, .done = sd_done, .eh_action = sd_eh_action, + .eh_reset = sd_eh_reset, }; /* @@ -1685,6 +1687,26 @@ static const struct block_device_operations sd_fops = { .pr_ops = &sd_pr_ops, }; +/** + * sd_eh_reset - reset error handling callback + * @scmd: sd-issued command that has failed + * + * This function is called by the SCSI midlayer before starting + * SCSI EH. When counting medium access failures we have to be + * careful to register it only only once per device and SCSI EH run; + * there might be several timed out commands which will cause the + * 'max_medium_access_timeouts' counter to trigger after the first + * SCSI EH run already and set the device to offline. + * So this function resets the internal counter before starting SCSI EH. + **/ +static void sd_eh_reset(struct scsi_cmnd *scmd) +{ + struct scsi_disk *sdkp = scsi_disk(scmd->request->rq_disk); + + /* New SCSI EH run, reset gate variable */ + sdkp->ignore_medium_access_errors = false; +} + /** * sd_eh_action - error handling callback * @scmd: sd-issued command that has failed @@ -1714,7 +1736,10 @@ static int sd_eh_action(struct scsi_cmnd *scmd, int eh_disp) * process of recovering or has it suffered an internal failure * that prevents access to the storage medium. */ - sdkp->medium_access_timed_out++; + if (!sdkp->ignore_medium_access_errors) { + sdkp->medium_access_timed_out++; + sdkp->ignore_medium_access_errors = true; + } /* * If the device keeps failing read/write commands but TEST UNIT diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h index 4dac35e96a75..0cf9680cb469 100644 --- a/drivers/scsi/sd.h +++ b/drivers/scsi/sd.h @@ -106,6 +106,7 @@ struct scsi_disk { unsigned rc_basis: 2; unsigned zoned: 2; unsigned urswrz : 1; + unsigned ignore_medium_access_errors : 1; }; #define to_scsi_disk(obj) container_of(obj,struct scsi_disk,dev) diff --git a/include/scsi/scsi_driver.h b/include/scsi/scsi_driver.h index 891a658aa867..a5534ccad859 100644 --- a/include/scsi/scsi_driver.h +++ b/include/scsi/scsi_driver.h @@ -16,6 +16,7 @@ struct scsi_driver { void (*uninit_command)(struct scsi_cmnd *); int (*done)(struct scsi_cmnd *); int (*eh_action)(struct scsi_cmnd *, int); + void (*eh_reset)(struct scsi_cmnd *); }; #define to_scsi_driver(drv) \ container_of((drv), struct scsi_driver, gendrv) -- cgit v1.2.3 From e8f8d50e07b0bd92f758a4f6d9ab0abf33f52881 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Thu, 6 Apr 2017 15:36:30 +0200 Subject: scsi: sd: Return SUCCESS in sd_eh_action() after device offline If sd_eh_action() decides to take the device offline there is no point in returning FAILED, as taking the device offline is the ultimate step in SCSI EH anyway. So further escalation via SCSI EH is not likely to make a difference and we can as well return SUCCESS. Cc: Benjamin Block Signed-off-by: Hannes Reinecke Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/sd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index bd2a38ef46f5..00b168b6a5fc 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1751,7 +1751,7 @@ static int sd_eh_action(struct scsi_cmnd *scmd, int eh_disp) "Medium access timeout failure. Offlining disk!\n"); scsi_device_set_state(scmd->device, SDEV_OFFLINE); - return FAILED; + return SUCCESS; } return eh_disp; -- cgit v1.2.3 From 1bcb93047e1b22b68cb8a30b48f999884fa827a8 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Thu, 6 Apr 2017 15:36:31 +0200 Subject: scsi: always send command aborts When a command has timed out we always should be sending an abort; with the previous code a failed abort might signal SCSI EH to start, and all other timed out commands will never be aborted, even though they might belong to a different ITL nexus. Cc: Benjamin Block Signed-off-by: Hannes Reinecke Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_error.c | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 370f6c045b60..cff7d9de79f2 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -196,19 +196,7 @@ scsi_abort_command(struct scsi_cmnd *scmd) return FAILED; } - /* - * Do not try a command abort if - * SCSI EH has already started. - */ spin_lock_irqsave(shost->host_lock, flags); - if (scsi_host_in_recovery(shost)) { - spin_unlock_irqrestore(shost->host_lock, flags); - SCSI_LOG_ERROR_RECOVERY(3, - scmd_printk(KERN_INFO, scmd, - "not aborting, host in recovery\n")); - return FAILED; - } - if (shost->eh_deadline != -1 && !shost->last_reset) shost->last_reset = jiffies; spin_unlock_irqrestore(shost->host_lock, flags); -- cgit v1.2.3 From 909657615d9b3ce709be4fd95b9a9e8c8c7c2be6 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 6 Apr 2017 15:36:32 +0200 Subject: scsi: libsas: allow async aborts We now first try to call ->eh_abort_handler from a work queue, but libsas was always failing that for no good reason. Allow async aborts. Reviewed-by: Johannes Thumshirn Reviewed-by: Hannes Reinecke Signed-off-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/libsas/sas_scsi_host.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index 9bd55bce83af..ee6b39a1db69 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c @@ -491,9 +491,6 @@ int sas_eh_abort_handler(struct scsi_cmnd *cmd) struct Scsi_Host *host = cmd->device->host; struct sas_internal *i = to_sas_internal(host->transportt); - if (current != host->ehandler) - return FAILED; - if (!i->dft->lldd_abort_task) return FAILED; -- cgit v1.2.3 From 8e8c9d01c5ea33e0d21f13264a9caeed255526d1 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Thu, 6 Apr 2017 15:36:33 +0200 Subject: scsi: make eh_eflags persistent If a failed command is retried and fails again we need to enter SCSI EH, otherwise we will never be able to recover the command. To detect this situation we must not clear scmd->eh_eflags when EH finishes but rather make it persistent throughout the lifetime of the command. Signed-off-by: Hannes Reinecke Reviewed-by: Benjamin Block Reviewed-by: Bart Van Assche Reviewed-by: Johannes Thumshirn Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- Documentation/scsi/scsi_eh.txt | 14 +++++++------- drivers/scsi/libsas/sas_scsi_host.c | 2 -- drivers/scsi/scsi_error.c | 4 ++-- include/scsi/scsi_eh.h | 1 + 4 files changed, 10 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/Documentation/scsi/scsi_eh.txt b/Documentation/scsi/scsi_eh.txt index 37eca00796ee..4edb9c1cbef5 100644 --- a/Documentation/scsi/scsi_eh.txt +++ b/Documentation/scsi/scsi_eh.txt @@ -105,11 +105,14 @@ function 2. If the host supports asynchronous completion (as indicated by the no_async_abort setting in the host template) scsi_abort_command() - is invoked to schedule an asynchrous abort. If that fails - Step #3 is taken. + is invoked to schedule an asynchrous abort. + Asynchronous abort are not invoked for commands which the + SCSI_EH_ABORT_SCHEDULED flag is set (this indicates that the command + already had been aborted once, and this is a retry which failed), + or when the EH deadline is expired. In these case Step #3 is taken. - 2. scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD) is invoked for the - command. See [1-3] for more information. + 3. scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD) is invoked for the + command. See [1-4] for more information. [1-3] Asynchronous command aborts @@ -263,7 +266,6 @@ scmd->allowed. 3. scmd recovered ACTION: scsi_eh_finish_cmd() is invoked to EH-finish scmd - - clear scmd->eh_eflags - scsi_setup_cmd_retry() - move from local eh_work_q to local eh_done_q LOCKING: none @@ -456,8 +458,6 @@ except for #1 must be implemented by eh_strategy_handler(). - shost->host_failed is zero. - - Each scmd's eh_eflags field is cleared. - - Each scmd is in such a state that scsi_setup_cmd_retry() on the scmd doesn't make any difference. diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index ee6b39a1db69..87e5079d816b 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c @@ -613,8 +613,6 @@ static void sas_eh_handle_sas_errors(struct Scsi_Host *shost, struct list_head * SAS_DPRINTK("trying to find task 0x%p\n", task); res = sas_scsi_find_task(task); - cmd->eh_eflags = 0; - switch (res) { case TASK_IS_DONE: SAS_DPRINTK("%s: task 0x%p is done\n", __func__, diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index cff7d9de79f2..4d26ff215c74 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -188,7 +188,6 @@ scsi_abort_command(struct scsi_cmnd *scmd) /* * Retry after abort failed, escalate to next level. */ - scmd->eh_eflags &= ~SCSI_EH_ABORT_SCHEDULED; SCSI_LOG_ERROR_RECOVERY(3, scmd_printk(KERN_INFO, scmd, "previous abort failed\n")); @@ -937,6 +936,7 @@ void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, struct scsi_eh_save *ses, ses->result = scmd->result; ses->underflow = scmd->underflow; ses->prot_op = scmd->prot_op; + ses->eh_eflags = scmd->eh_eflags; scmd->prot_op = SCSI_PROT_NORMAL; scmd->eh_eflags = 0; @@ -1000,6 +1000,7 @@ void scsi_eh_restore_cmnd(struct scsi_cmnd* scmd, struct scsi_eh_save *ses) scmd->result = ses->result; scmd->underflow = ses->underflow; scmd->prot_op = ses->prot_op; + scmd->eh_eflags = ses->eh_eflags; } EXPORT_SYMBOL(scsi_eh_restore_cmnd); @@ -1132,7 +1133,6 @@ static int scsi_eh_action(struct scsi_cmnd *scmd, int rtn) */ void scsi_eh_finish_cmd(struct scsi_cmnd *scmd, struct list_head *done_q) { - scmd->eh_eflags = 0; list_move_tail(&scmd->eh_entry, done_q); } EXPORT_SYMBOL(scsi_eh_finish_cmd); diff --git a/include/scsi/scsi_eh.h b/include/scsi/scsi_eh.h index 98d366b55770..a25b3285dd6f 100644 --- a/include/scsi/scsi_eh.h +++ b/include/scsi/scsi_eh.h @@ -31,6 +31,7 @@ extern int scsi_ioctl_reset(struct scsi_device *, int __user *); struct scsi_eh_save { /* saved state */ int result; + int eh_eflags; enum dma_data_direction data_direction; unsigned underflow; unsigned char cmd_len; -- cgit v1.2.3 From 2171b6d08bf8c2b826922b94e24ba36b00cb78b3 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Thu, 6 Apr 2017 15:36:34 +0200 Subject: scsi: make scsi_eh_scmd_add() always succeed scsi_eh_scmd_add() currently only will fail if no error handler thread is started (which will never be the case) or if the state machine encounters an illegal transition. But if we're encountering an invalid state transition chances is we cannot fixup things with the error handler. So better add a WARN_ON for illegal host states and make scsi_dh_scmd_add() a void function. Signed-off-by: Hannes Reinecke Reviewed-by: Johannes Thumshirn Reviewed-by: Bart Van Assche Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_error.c | 41 +++++++++++++---------------------------- drivers/scsi/scsi_lib.c | 4 ++-- drivers/scsi/scsi_priv.h | 2 +- 3 files changed, 16 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 4d26ff215c74..bbc431897606 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -162,13 +162,7 @@ scmd_eh_abort_handler(struct work_struct *work) } } - if (!scsi_eh_scmd_add(scmd, 0)) { - SCSI_LOG_ERROR_RECOVERY(3, - scmd_printk(KERN_WARNING, scmd, - "terminate aborted command\n")); - set_host_byte(scmd, DID_TIME_OUT); - scsi_finish_command(scmd); - } + scsi_eh_scmd_add(scmd, 0); } /** @@ -228,28 +222,23 @@ static void scsi_eh_reset(struct scsi_cmnd *scmd) * scsi_eh_scmd_add - add scsi cmd to error handling. * @scmd: scmd to run eh on. * @eh_flag: optional SCSI_EH flag. - * - * Return value: - * 0 on failure. */ -int scsi_eh_scmd_add(struct scsi_cmnd *scmd, int eh_flag) +void scsi_eh_scmd_add(struct scsi_cmnd *scmd, int eh_flag) { struct Scsi_Host *shost = scmd->device->host; unsigned long flags; - int ret = 0; + int ret; - if (!shost->ehandler) - return 0; + WARN_ON_ONCE(!shost->ehandler); spin_lock_irqsave(shost->host_lock, flags); - if (scsi_host_set_state(shost, SHOST_RECOVERY)) - if (scsi_host_set_state(shost, SHOST_CANCEL_RECOVERY)) - goto out_unlock; - + if (scsi_host_set_state(shost, SHOST_RECOVERY)) { + ret = scsi_host_set_state(shost, SHOST_CANCEL_RECOVERY); + WARN_ON_ONCE(ret); + } if (shost->eh_deadline != -1 && !shost->last_reset) shost->last_reset = jiffies; - ret = 1; if (scmd->eh_eflags & SCSI_EH_ABORT_SCHEDULED) eh_flag &= ~SCSI_EH_CANCEL_CMD; scmd->eh_eflags |= eh_flag; @@ -257,9 +246,7 @@ int scsi_eh_scmd_add(struct scsi_cmnd *scmd, int eh_flag) list_add_tail(&scmd->eh_entry, &shost->eh_cmd_q); shost->host_failed++; scsi_eh_wakeup(shost); - out_unlock: spin_unlock_irqrestore(shost->host_lock, flags); - return ret; } /** @@ -288,13 +275,11 @@ enum blk_eh_timer_return scsi_times_out(struct request *req) rtn = host->hostt->eh_timed_out(scmd); if (rtn == BLK_EH_NOT_HANDLED) { - if (!host->hostt->no_async_abort && - scsi_abort_command(scmd) == SUCCESS) - return BLK_EH_NOT_HANDLED; - - set_host_byte(scmd, DID_TIME_OUT); - if (!scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD)) - rtn = BLK_EH_HANDLED; + if (host->hostt->no_async_abort || + scsi_abort_command(scmd) != SUCCESS) { + set_host_byte(scmd, DID_TIME_OUT); + scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD); + } } return rtn; diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index ba2286652ff6..ba8da904e774 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -1593,8 +1593,8 @@ static void scsi_softirq_done(struct request *rq) scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY); break; default: - if (!scsi_eh_scmd_add(cmd, 0)) - scsi_finish_command(cmd); + scsi_eh_scmd_add(cmd, 0); + break; } } diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index 99bfc985e190..5be6cbf69df6 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h @@ -72,7 +72,7 @@ extern enum blk_eh_timer_return scsi_times_out(struct request *req); extern int scsi_error_handler(void *host); extern int scsi_decide_disposition(struct scsi_cmnd *cmd); extern void scsi_eh_wakeup(struct Scsi_Host *shost); -extern int scsi_eh_scmd_add(struct scsi_cmnd *, int); +extern void scsi_eh_scmd_add(struct scsi_cmnd *, int); void scsi_eh_ready_devs(struct Scsi_Host *shost, struct list_head *work_q, struct list_head *done_q); -- cgit v1.2.3 From a06586325f371c0f0f6095454b5beca0602eaab4 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Thu, 6 Apr 2017 15:36:35 +0200 Subject: scsi: make asynchronous aborts mandatory There hasn't been any reports for HBAs where asynchronous abort would not work, so we should make it mandatory and remove the fallback. Signed-off-by: Hannes Reinecke Reviewed-by: Johannes Thumshirn Reviewed-by: Bart Van Assche Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- Documentation/scsi/scsi_eh.txt | 18 ++++------ drivers/scsi/scsi_error.c | 81 ++++-------------------------------------- drivers/scsi/scsi_lib.c | 2 +- drivers/scsi/scsi_priv.h | 3 +- include/scsi/scsi_host.h | 5 --- 5 files changed, 15 insertions(+), 94 deletions(-) (limited to 'drivers') diff --git a/Documentation/scsi/scsi_eh.txt b/Documentation/scsi/scsi_eh.txt index 4edb9c1cbef5..11e447bdb3a5 100644 --- a/Documentation/scsi/scsi_eh.txt +++ b/Documentation/scsi/scsi_eh.txt @@ -70,7 +70,7 @@ with the command. scmd is requeued to blk queue. - otherwise - scsi_eh_scmd_add(scmd, 0) is invoked for the command. See + scsi_eh_scmd_add(scmd) is invoked for the command. See [1-3] for details of this function. @@ -103,9 +103,7 @@ function eh_timed_out() callback did not handle the command. Step #2 is taken. - 2. If the host supports asynchronous completion (as indicated by the - no_async_abort setting in the host template) scsi_abort_command() - is invoked to schedule an asynchrous abort. + 2. scsi_abort_command() is invoked to schedule an asynchrous abort. Asynchronous abort are not invoked for commands which the SCSI_EH_ABORT_SCHEDULED flag is set (this indicates that the command already had been aborted once, and this is a retry which failed), @@ -127,16 +125,13 @@ function scmds enter EH via scsi_eh_scmd_add(), which does the following. - 1. Turns on scmd->eh_eflags as requested. It's 0 for error - completions and SCSI_EH_CANCEL_CMD for timeouts. + 1. Links scmd->eh_entry to shost->eh_cmd_q - 2. Links scmd->eh_entry to shost->eh_cmd_q + 2. Sets SHOST_RECOVERY bit in shost->shost_state - 3. Sets SHOST_RECOVERY bit in shost->shost_state + 3. Increments shost->host_failed - 4. Increments shost->host_failed - - 5. Wakes up SCSI EH thread if shost->host_busy == shost->host_failed + 4. Wakes up SCSI EH thread if shost->host_busy == shost->host_failed As can be seen above, once any scmd is added to shost->eh_cmd_q, SHOST_RECOVERY shost_state bit is turned on. This prevents any new @@ -252,7 +247,6 @@ scmd->allowed. 1. Error completion / time out ACTION: scsi_eh_scmd_add() is invoked for scmd - - set scmd->eh_eflags - add scmd to shost->eh_cmd_q - set SHOST_RECOVERY - shost->host_failed++ diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index bbc431897606..53e334356f31 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -162,7 +162,7 @@ scmd_eh_abort_handler(struct work_struct *work) } } - scsi_eh_scmd_add(scmd, 0); + scsi_eh_scmd_add(scmd); } /** @@ -221,9 +221,8 @@ static void scsi_eh_reset(struct scsi_cmnd *scmd) /** * scsi_eh_scmd_add - add scsi cmd to error handling. * @scmd: scmd to run eh on. - * @eh_flag: optional SCSI_EH flag. */ -void scsi_eh_scmd_add(struct scsi_cmnd *scmd, int eh_flag) +void scsi_eh_scmd_add(struct scsi_cmnd *scmd) { struct Scsi_Host *shost = scmd->device->host; unsigned long flags; @@ -239,9 +238,6 @@ void scsi_eh_scmd_add(struct scsi_cmnd *scmd, int eh_flag) if (shost->eh_deadline != -1 && !shost->last_reset) shost->last_reset = jiffies; - if (scmd->eh_eflags & SCSI_EH_ABORT_SCHEDULED) - eh_flag &= ~SCSI_EH_CANCEL_CMD; - scmd->eh_eflags |= eh_flag; scsi_eh_reset(scmd); list_add_tail(&scmd->eh_entry, &shost->eh_cmd_q); shost->host_failed++; @@ -275,10 +271,9 @@ enum blk_eh_timer_return scsi_times_out(struct request *req) rtn = host->hostt->eh_timed_out(scmd); if (rtn == BLK_EH_NOT_HANDLED) { - if (host->hostt->no_async_abort || - scsi_abort_command(scmd) != SUCCESS) { + if (scsi_abort_command(scmd) != SUCCESS) { set_host_byte(scmd, DID_TIME_OUT); - scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD); + scsi_eh_scmd_add(scmd); } } @@ -331,7 +326,7 @@ static inline void scsi_eh_prt_fail_stats(struct Scsi_Host *shost, list_for_each_entry(scmd, work_q, eh_entry) { if (scmd->device == sdev) { ++total_failures; - if (scmd->eh_eflags & SCSI_EH_CANCEL_CMD) + if (scmd->eh_eflags & SCSI_EH_ABORT_SCHEDULED) ++cmd_cancel; else ++cmd_failed; @@ -1154,8 +1149,7 @@ int scsi_eh_get_sense(struct list_head *work_q, * should not get sense. */ list_for_each_entry_safe(scmd, next, work_q, eh_entry) { - if ((scmd->eh_eflags & SCSI_EH_CANCEL_CMD) || - (scmd->eh_eflags & SCSI_EH_ABORT_SCHEDULED) || + if ((scmd->eh_eflags & SCSI_EH_ABORT_SCHEDULED) || SCSI_SENSE_VALID(scmd)) continue; @@ -1295,61 +1289,6 @@ static int scsi_eh_test_devices(struct list_head *cmd_list, return list_empty(work_q); } - -/** - * scsi_eh_abort_cmds - abort pending commands. - * @work_q: &list_head for pending commands. - * @done_q: &list_head for processed commands. - * - * Decription: - * Try and see whether or not it makes sense to try and abort the - * running command. This only works out to be the case if we have one - * command that has timed out. If the command simply failed, it makes - * no sense to try and abort the command, since as far as the shost - * adapter is concerned, it isn't running. - */ -static int scsi_eh_abort_cmds(struct list_head *work_q, - struct list_head *done_q) -{ - struct scsi_cmnd *scmd, *next; - LIST_HEAD(check_list); - int rtn; - struct Scsi_Host *shost; - - list_for_each_entry_safe(scmd, next, work_q, eh_entry) { - if (!(scmd->eh_eflags & SCSI_EH_CANCEL_CMD)) - continue; - shost = scmd->device->host; - if (scsi_host_eh_past_deadline(shost)) { - list_splice_init(&check_list, work_q); - SCSI_LOG_ERROR_RECOVERY(3, - scmd_printk(KERN_INFO, scmd, - "%s: skip aborting cmd, past eh deadline\n", - current->comm)); - return list_empty(work_q); - } - SCSI_LOG_ERROR_RECOVERY(3, - scmd_printk(KERN_INFO, scmd, - "%s: aborting cmd\n", current->comm)); - rtn = scsi_try_to_abort_cmd(shost->hostt, scmd); - if (rtn == FAILED) { - SCSI_LOG_ERROR_RECOVERY(3, - scmd_printk(KERN_INFO, scmd, - "%s: aborting cmd failed\n", - current->comm)); - list_splice_init(&check_list, work_q); - return list_empty(work_q); - } - scmd->eh_eflags &= ~SCSI_EH_CANCEL_CMD; - if (rtn == FAST_IO_FAIL) - scsi_eh_finish_cmd(scmd, done_q); - else - list_move_tail(&scmd->eh_entry, &check_list); - } - - return scsi_eh_test_devices(&check_list, work_q, done_q, 0); -} - /** * scsi_eh_try_stu - Send START_UNIT to device. * @scmd: &scsi_cmnd to send START_UNIT @@ -1692,11 +1631,6 @@ static void scsi_eh_offline_sdevs(struct list_head *work_q, sdev_printk(KERN_INFO, scmd->device, "Device offlined - " "not ready after error recovery\n"); scsi_device_set_state(scmd->device, SDEV_OFFLINE); - if (scmd->eh_eflags & SCSI_EH_CANCEL_CMD) { - /* - * FIXME: Handle lost cmds. - */ - } scsi_eh_finish_cmd(scmd, done_q); } return; @@ -2140,8 +2074,7 @@ static void scsi_unjam_host(struct Scsi_Host *shost) SCSI_LOG_ERROR_RECOVERY(1, scsi_eh_prt_fail_stats(shost, &eh_work_q)); if (!scsi_eh_get_sense(&eh_work_q, &eh_done_q)) - if (!scsi_eh_abort_cmds(&eh_work_q, &eh_done_q)) - scsi_eh_ready_devs(shost, &eh_work_q, &eh_done_q); + scsi_eh_ready_devs(shost, &eh_work_q, &eh_done_q); spin_lock_irqsave(shost->host_lock, flags); if (shost->eh_deadline != -1) diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index ba8da904e774..9822fdeed0ce 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -1593,7 +1593,7 @@ static void scsi_softirq_done(struct request *rq) scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY); break; default: - scsi_eh_scmd_add(cmd, 0); + scsi_eh_scmd_add(cmd); break; } } diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index 5be6cbf69df6..e20ab10623fb 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h @@ -18,7 +18,6 @@ struct scsi_nl_hdr; /* * Scsi Error Handler Flags */ -#define SCSI_EH_CANCEL_CMD 0x0001 /* Cancel this cmd */ #define SCSI_EH_ABORT_SCHEDULED 0x0002 /* Abort has been scheduled */ #define SCSI_SENSE_VALID(scmd) \ @@ -72,7 +71,7 @@ extern enum blk_eh_timer_return scsi_times_out(struct request *req); extern int scsi_error_handler(void *host); extern int scsi_decide_disposition(struct scsi_cmnd *cmd); extern void scsi_eh_wakeup(struct Scsi_Host *shost); -extern void scsi_eh_scmd_add(struct scsi_cmnd *, int); +extern void scsi_eh_scmd_add(struct scsi_cmnd *); void scsi_eh_ready_devs(struct Scsi_Host *shost, struct list_head *work_q, struct list_head *done_q); diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index 3cd8c3bec638..afb04811b7b9 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -451,11 +451,6 @@ struct scsi_host_template { /* True if the controller does not support WRITE SAME */ unsigned no_write_same:1; - /* - * True if asynchronous aborts are not supported - */ - unsigned no_async_abort:1; - /* * Countdown for host blocking with no commands outstanding. */ -- cgit v1.2.3 From bf5ea6fba78b62a4d4b70151143077131ccf32a8 Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Wed, 22 Mar 2017 11:44:22 +0100 Subject: scsi: qla4xxx: drop redundant init_completion The redundant init_completion() here seems to be a cut&past error as struct scsi_qla_host only has 4 completion elements to initialize, thus the duplicate init_completion(disable_acb_comp) is simply removed. Signed-off-by: Nicholas Mc Guire Signed-off-by: Martin K. Petersen --- drivers/scsi/qla4xxx/ql4_os.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index ac52150d1569..64c6fa563fdb 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -8664,7 +8664,6 @@ static int qla4xxx_probe_adapter(struct pci_dev *pdev, init_completion(&ha->disable_acb_comp); init_completion(&ha->idc_comp); init_completion(&ha->link_up_comp); - init_completion(&ha->disable_acb_comp); spin_lock_init(&ha->hardware_lock); spin_lock_init(&ha->work_lock); -- cgit v1.2.3 From 1fdcd2d1da7f5293a210af52407d5024036975c2 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 6 Apr 2017 12:19:57 +0100 Subject: scsi: qla2xxx: remove some redundant pointer assignments There are several local or function parameter pointers that are being assigned NULL after a kfree where and these have no effect and hence can be removed. Fixes various cppcheck warnings: "Assignment of function parameter has no effect outside the function. Did you forget dereferencing it" Signed-off-by: Colin Ian King Acked-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_os.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 1fed235a1b4a..9bddbcff6d8a 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -423,7 +423,6 @@ static void qla2x00_free_req_que(struct qla_hw_data *ha, struct req_que *req) kfree(req->outstanding_cmds); kfree(req); - req = NULL; } static void qla2x00_free_rsp_que(struct qla_hw_data *ha, struct rsp_que *rsp) @@ -439,7 +438,6 @@ static void qla2x00_free_rsp_que(struct qla_hw_data *ha, struct rsp_que *rsp) rsp->ring, rsp->dma); } kfree(rsp); - rsp = NULL; } static void qla2x00_free_queues(struct qla_hw_data *ha) @@ -653,7 +651,6 @@ qla2x00_sp_free_dma(void *ptr) ha->gbl_dsd_inuse -= ctx1->dsd_use_cnt; ha->gbl_dsd_avail += ctx1->dsd_use_cnt; mempool_free(ctx1, ha->ctx_mempool); - ctx1 = NULL; } CMD_SP(cmd) = NULL; @@ -3235,7 +3232,6 @@ iospace_config_failed: } pci_release_selected_regions(ha->pdev, ha->bars); kfree(ha); - ha = NULL; probe_out: pci_disable_device(pdev); @@ -3482,7 +3478,6 @@ qla2x00_remove_one(struct pci_dev *pdev) pci_release_selected_regions(ha->pdev, ha->bars); kfree(ha); - ha = NULL; pci_disable_pcie_error_reporting(pdev); @@ -3546,7 +3541,6 @@ void qla2x00_free_fcports(struct scsi_qla_host *vha) list_del(&fcport->list); qla2x00_clear_loop_id(fcport); kfree(fcport); - fcport = NULL; } } -- cgit v1.2.3 From 745dfa0d8ec26b24f3304459ff6e9eacc5c8351b Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Fri, 7 Apr 2017 09:34:12 +0200 Subject: scsi: sg: disable SET_FORCE_LOW_DMA The ioctl SET_FORCE_LOW_DMA has never worked since the initial git check-in, and the respective setting is nowadays handled correctly. So disable it entirely. Signed-off-by: Hannes Reinecke Reviewed-by: Johannes Thumshirn Tested-by: Johannes Thumshirn Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/sg.c | 30 +++++++++--------------------- include/scsi/sg.h | 1 - 2 files changed, 9 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 29b86505f796..11ca00d8b54c 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -149,7 +149,6 @@ typedef struct sg_fd { /* holds the state of a file descriptor */ Sg_request *headrp; /* head of request slist, NULL->empty */ struct fasync_struct *async_qp; /* used by asynchronous notification */ Sg_request req_arr[SG_MAX_QUEUE]; /* used as singly-linked list */ - char low_dma; /* as in parent but possibly overridden to 1 */ char force_packid; /* 1 -> pack_id input to read(), 0 -> ignored */ char cmd_q; /* 1 -> allow command queuing, 0 -> don't */ unsigned char next_cmd_len; /* 0: automatic, >0: use on next write() */ @@ -885,24 +884,14 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg) /* strange ..., for backward compatibility */ return sfp->timeout_user; case SG_SET_FORCE_LOW_DMA: - result = get_user(val, ip); - if (result) - return result; - if (val) { - sfp->low_dma = 1; - if ((0 == sfp->low_dma) && (0 == sg_res_in_use(sfp))) { - val = (int) sfp->reserve.bufflen; - sg_remove_scat(sfp, &sfp->reserve); - sg_build_reserve(sfp, val); - } - } else { - if (atomic_read(&sdp->detaching)) - return -ENODEV; - sfp->low_dma = sdp->device->host->unchecked_isa_dma; - } + /* + * N.B. This ioctl never worked properly, but failed to + * return an error value. So returning '0' to keep compability + * with legacy applications. + */ return 0; case SG_GET_LOW_DMA: - return put_user((int) sfp->low_dma, ip); + return put_user((int) sdp->device->host->unchecked_isa_dma, ip); case SG_GET_SCSI_ID: if (!access_ok(VERIFY_WRITE, p, sizeof (sg_scsi_id_t))) return -EFAULT; @@ -1829,6 +1818,7 @@ sg_build_indirect(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size) int sg_tablesize = sfp->parentdp->sg_tablesize; int blk_size = buff_size, order; gfp_t gfp_mask = GFP_ATOMIC | __GFP_COMP | __GFP_NOWARN; + struct sg_device *sdp = sfp->parentdp; if (blk_size < 0) return -EFAULT; @@ -1854,7 +1844,7 @@ sg_build_indirect(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size) scatter_elem_sz_prev = num; } - if (sfp->low_dma) + if (sdp->device->host->unchecked_isa_dma) gfp_mask |= GFP_DMA; if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) @@ -2140,8 +2130,6 @@ sg_add_sfp(Sg_device * sdp) sfp->timeout = SG_DEFAULT_TIMEOUT; sfp->timeout_user = SG_DEFAULT_TIMEOUT_USER; sfp->force_packid = SG_DEF_FORCE_PACK_ID; - sfp->low_dma = (SG_DEF_FORCE_LOW_DMA == 0) ? - sdp->device->host->unchecked_isa_dma : 1; sfp->cmd_q = SG_DEF_COMMAND_Q; sfp->keep_orphan = SG_DEF_KEEP_ORPHAN; sfp->parentdp = sdp; @@ -2611,7 +2599,7 @@ static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp) jiffies_to_msecs(fp->timeout), fp->reserve.bufflen, (int) fp->reserve.k_use_sg, - (int) fp->low_dma); + (int) sdp->device->host->unchecked_isa_dma); seq_printf(s, " cmd_q=%d f_packid=%d k_orphan=%d closed=0\n", (int) fp->cmd_q, (int) fp->force_packid, (int) fp->keep_orphan); diff --git a/include/scsi/sg.h b/include/scsi/sg.h index 3afec7032448..20bc71c3e0b8 100644 --- a/include/scsi/sg.h +++ b/include/scsi/sg.h @@ -197,7 +197,6 @@ typedef struct sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */ #define SG_DEFAULT_RETRIES 0 /* Defaults, commented if they differ from original sg driver */ -#define SG_DEF_FORCE_LOW_DMA 0 /* was 1 -> memory below 16MB on i386 */ #define SG_DEF_FORCE_PACK_ID 0 #define SG_DEF_KEEP_ORPHAN 0 #define SG_DEF_RESERVED_SIZE SG_SCATTER_SZ /* load time option */ -- cgit v1.2.3 From 136e57bf43dc4babbfb8783abbf707d483cacbe3 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Fri, 7 Apr 2017 09:34:13 +0200 Subject: scsi: sg: remove 'save_scat_len' Unused. Signed-off-by: Hannes Reinecke Reviewed-by: Johannes Thumshirn Tested-by: Johannes Thumshirn Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/sg.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 11ca00d8b54c..92cc658d8bc6 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -145,7 +145,6 @@ typedef struct sg_fd { /* holds the state of a file descriptor */ int timeout; /* defaults to SG_DEFAULT_TIMEOUT */ int timeout_user; /* defaults to SG_DEFAULT_TIMEOUT_USER */ Sg_scatter_hold reserve; /* buffer held for this file descriptor */ - unsigned save_scat_len; /* original length of trunc. scat. element */ Sg_request *headrp; /* head of request slist, NULL->empty */ struct fasync_struct *async_qp; /* used by asynchronous notification */ Sg_request req_arr[SG_MAX_QUEUE]; /* used as singly-linked list */ @@ -2014,7 +2013,6 @@ sg_unlink_reserve(Sg_fd * sfp, Sg_request * srp) req_schp->pages = NULL; req_schp->page_order = 0; req_schp->sglist_len = 0; - sfp->save_scat_len = 0; srp->res_used = 0; } -- cgit v1.2.3 From 1bc0eb0446158cc76562176b80623aa119afee5b Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Fri, 7 Apr 2017 09:34:14 +0200 Subject: scsi: sg: protect accesses to 'reserved' page array The 'reserved' page array is used as a short-cut for mapping data, saving us to allocate pages per request. However, the 'reserved' array is only capable of holding one request, so this patch introduces a mutex for protect 'sg_fd' against concurrent accesses. Signed-off-by: Hannes Reinecke Reviewed-by: Johannes Thumshirn Tested-by: Johannes Thumshirn Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/sg.c | 45 +++++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 92cc658d8bc6..ddc18082cf6a 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -142,6 +142,7 @@ typedef struct sg_fd { /* holds the state of a file descriptor */ struct sg_device *parentdp; /* owning device */ wait_queue_head_t read_wait; /* queue read until command done */ rwlock_t rq_list_lock; /* protect access to list in req_arr */ + struct mutex f_mutex; /* protect against changes in this fd */ int timeout; /* defaults to SG_DEFAULT_TIMEOUT */ int timeout_user; /* defaults to SG_DEFAULT_TIMEOUT_USER */ Sg_scatter_hold reserve; /* buffer held for this file descriptor */ @@ -153,6 +154,7 @@ typedef struct sg_fd { /* holds the state of a file descriptor */ unsigned char next_cmd_len; /* 0: automatic, >0: use on next write() */ char keep_orphan; /* 0 -> drop orphan (def), 1 -> keep for read() */ char mmap_called; /* 0 -> mmap() never called on this fd */ + char res_in_use; /* 1 -> 'reserve' array in use */ struct kref f_ref; struct execute_work ew; } Sg_fd; @@ -196,7 +198,6 @@ static void sg_remove_sfp(struct kref *); static Sg_request *sg_get_rq_mark(Sg_fd * sfp, int pack_id); static Sg_request *sg_add_request(Sg_fd * sfp); static int sg_remove_request(Sg_fd * sfp, Sg_request * srp); -static int sg_res_in_use(Sg_fd * sfp); static Sg_device *sg_get_dev(int dev); static void sg_device_destroy(struct kref *kref); @@ -612,6 +613,7 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos) } buf += SZ_SG_HEADER; __get_user(opcode, buf); + mutex_lock(&sfp->f_mutex); if (sfp->next_cmd_len > 0) { cmd_size = sfp->next_cmd_len; sfp->next_cmd_len = 0; /* reset so only this write() effected */ @@ -620,6 +622,7 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos) if ((opcode >= 0xc0) && old_hdr.twelve_byte) cmd_size = 12; } + mutex_unlock(&sfp->f_mutex); SCSI_LOG_TIMEOUT(4, sg_printk(KERN_INFO, sdp, "sg_write: scsi opcode=0x%02x, cmd_size=%d\n", (int) opcode, cmd_size)); /* Determine buffer size. */ @@ -719,7 +722,7 @@ sg_new_write(Sg_fd *sfp, struct file *file, const char __user *buf, sg_remove_request(sfp, srp); return -EINVAL; /* either MMAP_IO or DIRECT_IO (not both) */ } - if (sg_res_in_use(sfp)) { + if (sfp->res_in_use) { sg_remove_request(sfp, srp); return -EBUSY; /* reserve buffer already being used */ } @@ -953,12 +956,18 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg) return -EINVAL; val = min_t(int, val, max_sectors_bytes(sdp->device->request_queue)); + mutex_lock(&sfp->f_mutex); if (val != sfp->reserve.bufflen) { - if (sg_res_in_use(sfp) || sfp->mmap_called) + if (sfp->mmap_called || + sfp->res_in_use) { + mutex_unlock(&sfp->f_mutex); return -EBUSY; + } + sg_remove_scat(sfp, &sfp->reserve); sg_build_reserve(sfp, val); } + mutex_unlock(&sfp->f_mutex); return 0; case SG_GET_RESERVED_SIZE: val = min_t(int, sfp->reserve.bufflen, @@ -1718,13 +1727,22 @@ sg_start_req(Sg_request *srp, unsigned char *cmd) md = &map_data; if (md) { - if (!sg_res_in_use(sfp) && dxfer_len <= rsv_schp->bufflen) + mutex_lock(&sfp->f_mutex); + if (dxfer_len <= rsv_schp->bufflen && + !sfp->res_in_use) { + sfp->res_in_use = 1; sg_link_reserve(sfp, srp, dxfer_len); - else { + } else if ((hp->flags & SG_FLAG_MMAP_IO) && sfp->res_in_use) { + mutex_unlock(&sfp->f_mutex); + return -EBUSY; + } else { res = sg_build_indirect(req_schp, sfp, dxfer_len); - if (res) + if (res) { + mutex_unlock(&sfp->f_mutex); return res; + } } + mutex_unlock(&sfp->f_mutex); md->pages = req_schp->pages; md->page_order = req_schp->page_order; @@ -2125,6 +2143,7 @@ sg_add_sfp(Sg_device * sdp) rwlock_init(&sfp->rq_list_lock); kref_init(&sfp->f_ref); + mutex_init(&sfp->f_mutex); sfp->timeout = SG_DEFAULT_TIMEOUT; sfp->timeout_user = SG_DEFAULT_TIMEOUT_USER; sfp->force_packid = SG_DEF_FORCE_PACK_ID; @@ -2198,20 +2217,6 @@ sg_remove_sfp(struct kref *kref) schedule_work(&sfp->ew.work); } -static int -sg_res_in_use(Sg_fd * sfp) -{ - const Sg_request *srp; - unsigned long iflags; - - read_lock_irqsave(&sfp->rq_list_lock, iflags); - for (srp = sfp->headrp; srp; srp = srp->nextrp) - if (srp->res_used) - break; - read_unlock_irqrestore(&sfp->rq_list_lock, iflags); - return srp ? 1 : 0; -} - #ifdef CONFIG_SCSI_PROC_FS static int sg_idr_max_id(int id, void *p, void *data) -- cgit v1.2.3 From 28676d869bbb5257b5f14c0c95ad3af3a7019dd5 Mon Sep 17 00:00:00 2001 From: Johannes Thumshirn Date: Fri, 7 Apr 2017 09:34:15 +0200 Subject: scsi: sg: check for valid direction before starting the request Check for a valid direction before starting the request, otherwise we risk running into an assertion in the scsi midlayer checking for valid requests. [mkp: fixed typo] Signed-off-by: Johannes Thumshirn Link: http://www.spinics.net/lists/linux-scsi/msg104400.html Reported-by: Dmitry Vyukov Signed-off-by: Hannes Reinecke Tested-by: Johannes Thumshirn Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/sg.c | 46 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index ddc18082cf6a..5f12273f9026 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -663,18 +663,14 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos) * is a non-zero input_size, so emit a warning. */ if (hp->dxfer_direction == SG_DXFER_TO_FROM_DEV) { - static char cmd[TASK_COMM_LEN]; - if (strcmp(current->comm, cmd)) { - printk_ratelimited(KERN_WARNING - "sg_write: data in/out %d/%d bytes " - "for SCSI command 0x%x-- guessing " - "data in;\n program %s not setting " - "count and/or reply_len properly\n", - old_hdr.reply_len - (int)SZ_SG_HEADER, - input_size, (unsigned int) cmnd[0], - current->comm); - strcpy(cmd, current->comm); - } + printk_ratelimited(KERN_WARNING + "sg_write: data in/out %d/%d bytes " + "for SCSI command 0x%x-- guessing " + "data in;\n program %s not setting " + "count and/or reply_len properly\n", + old_hdr.reply_len - (int)SZ_SG_HEADER, + input_size, (unsigned int) cmnd[0], + current->comm); } k = sg_common_write(sfp, srp, cmnd, sfp->timeout, blocking); return (k < 0) ? k : count; @@ -753,6 +749,29 @@ sg_new_write(Sg_fd *sfp, struct file *file, const char __user *buf, return count; } +static bool sg_is_valid_dxfer(sg_io_hdr_t *hp) +{ + switch (hp->dxfer_direction) { + case SG_DXFER_NONE: + if (hp->dxferp || hp->dxfer_len > 0) + return false; + return true; + case SG_DXFER_TO_DEV: + case SG_DXFER_FROM_DEV: + case SG_DXFER_TO_FROM_DEV: + if (!hp->dxferp || hp->dxfer_len == 0) + return false; + return true; + case SG_DXFER_UNKNOWN: + if ((!hp->dxferp && hp->dxfer_len) || + (hp->dxferp && hp->dxfer_len == 0)) + return false; + return true; + default: + return false; + } +} + static int sg_common_write(Sg_fd * sfp, Sg_request * srp, unsigned char *cmnd, int timeout, int blocking) @@ -773,6 +792,9 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp, "sg_common_write: scsi opcode=0x%02x, cmd_size=%d\n", (int) cmnd[0], (int) hp->cmd_len)); + if (!sg_is_valid_dxfer(hp)) + return -EINVAL; + k = sg_start_req(srp, cmnd); if (k) { SCSI_LOG_TIMEOUT(1, sg_printk(KERN_INFO, sfp->parentdp, -- cgit v1.2.3 From 109bade9c625c89bb5ea753aaa1a0a97e6fbb548 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Fri, 7 Apr 2017 09:34:16 +0200 Subject: scsi: sg: use standard lists for sg_requests 'Sg_request' is using a private list implementation; convert it to standard lists. Signed-off-by: Hannes Reinecke Reviewed-by: Johannes Thumshirn Tested-by: Johannes Thumshirn Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/sg.c | 147 ++++++++++++++++++++++-------------------------------- 1 file changed, 61 insertions(+), 86 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 5f12273f9026..5c9f1b9f69e9 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -122,7 +122,7 @@ struct sg_device; /* forward declarations */ struct sg_fd; typedef struct sg_request { /* SG_MAX_QUEUE requests outstanding per file */ - struct sg_request *nextrp; /* NULL -> tail request (slist) */ + struct list_head entry; /* list entry */ struct sg_fd *parentfp; /* NULL -> not in use */ Sg_scatter_hold data; /* hold buffer, perhaps scatter list */ sg_io_hdr_t header; /* scsi command+info, see */ @@ -146,7 +146,7 @@ typedef struct sg_fd { /* holds the state of a file descriptor */ int timeout; /* defaults to SG_DEFAULT_TIMEOUT */ int timeout_user; /* defaults to SG_DEFAULT_TIMEOUT_USER */ Sg_scatter_hold reserve; /* buffer held for this file descriptor */ - Sg_request *headrp; /* head of request slist, NULL->empty */ + struct list_head rq_list; /* head of request list */ struct fasync_struct *async_qp; /* used by asynchronous notification */ Sg_request req_arr[SG_MAX_QUEUE]; /* used as singly-linked list */ char force_packid; /* 1 -> pack_id input to read(), 0 -> ignored */ @@ -949,7 +949,7 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg) if (!access_ok(VERIFY_WRITE, ip, sizeof (int))) return -EFAULT; read_lock_irqsave(&sfp->rq_list_lock, iflags); - for (srp = sfp->headrp; srp; srp = srp->nextrp) { + list_for_each_entry(srp, &sfp->rq_list, entry) { if ((1 == srp->done) && (!srp->sg_io_owned)) { read_unlock_irqrestore(&sfp->rq_list_lock, iflags); @@ -962,7 +962,8 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg) return 0; case SG_GET_NUM_WAITING: read_lock_irqsave(&sfp->rq_list_lock, iflags); - for (val = 0, srp = sfp->headrp; srp; srp = srp->nextrp) { + val = 0; + list_for_each_entry(srp, &sfp->rq_list, entry) { if ((1 == srp->done) && (!srp->sg_io_owned)) ++val; } @@ -1035,35 +1036,33 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg) if (!rinfo) return -ENOMEM; read_lock_irqsave(&sfp->rq_list_lock, iflags); - for (srp = sfp->headrp, val = 0; val < SG_MAX_QUEUE; - ++val, srp = srp ? srp->nextrp : srp) { + val = 0; + list_for_each_entry(srp, &sfp->rq_list, entry) { + if (val > SG_MAX_QUEUE) + break; memset(&rinfo[val], 0, SZ_SG_REQ_INFO); - if (srp) { - rinfo[val].req_state = srp->done + 1; - rinfo[val].problem = - srp->header.masked_status & - srp->header.host_status & - srp->header.driver_status; - if (srp->done) - rinfo[val].duration = - srp->header.duration; - else { - ms = jiffies_to_msecs(jiffies); - rinfo[val].duration = - (ms > srp->header.duration) ? - (ms - srp->header.duration) : 0; - } - rinfo[val].orphan = srp->orphan; - rinfo[val].sg_io_owned = - srp->sg_io_owned; - rinfo[val].pack_id = - srp->header.pack_id; - rinfo[val].usr_ptr = - srp->header.usr_ptr; + rinfo[val].req_state = srp->done + 1; + rinfo[val].problem = + srp->header.masked_status & + srp->header.host_status & + srp->header.driver_status; + if (srp->done) + rinfo[val].duration = + srp->header.duration; + else { + ms = jiffies_to_msecs(jiffies); + rinfo[val].duration = + (ms > srp->header.duration) ? + (ms - srp->header.duration) : 0; } + rinfo[val].orphan = srp->orphan; + rinfo[val].sg_io_owned = srp->sg_io_owned; + rinfo[val].pack_id = srp->header.pack_id; + rinfo[val].usr_ptr = srp->header.usr_ptr; + val++; } read_unlock_irqrestore(&sfp->rq_list_lock, iflags); - result = __copy_to_user(p, rinfo, + result = __copy_to_user(p, rinfo, SZ_SG_REQ_INFO * SG_MAX_QUEUE); result = result ? -EFAULT : 0; kfree(rinfo); @@ -1169,7 +1168,7 @@ sg_poll(struct file *filp, poll_table * wait) return POLLERR; poll_wait(filp, &sfp->read_wait, wait); read_lock_irqsave(&sfp->rq_list_lock, iflags); - for (srp = sfp->headrp; srp; srp = srp->nextrp) { + list_for_each_entry(srp, &sfp->rq_list, entry) { /* if any read waiting, flag it */ if ((0 == res) && (1 == srp->done) && (!srp->sg_io_owned)) res = POLLIN | POLLRDNORM; @@ -2063,7 +2062,7 @@ sg_get_rq_mark(Sg_fd * sfp, int pack_id) unsigned long iflags; write_lock_irqsave(&sfp->rq_list_lock, iflags); - for (resp = sfp->headrp; resp; resp = resp->nextrp) { + list_for_each_entry(resp, &sfp->rq_list, entry) { /* look for requests that are ready + not SG_IO owned */ if ((1 == resp->done) && (!resp->sg_io_owned) && ((-1 == pack_id) || (resp->header.pack_id == pack_id))) { @@ -2081,70 +2080,45 @@ sg_add_request(Sg_fd * sfp) { int k; unsigned long iflags; - Sg_request *resp; Sg_request *rp = sfp->req_arr; write_lock_irqsave(&sfp->rq_list_lock, iflags); - resp = sfp->headrp; - if (!resp) { - memset(rp, 0, sizeof (Sg_request)); - rp->parentfp = sfp; - resp = rp; - sfp->headrp = resp; - } else { - if (0 == sfp->cmd_q) - resp = NULL; /* command queuing disallowed */ - else { - for (k = 0; k < SG_MAX_QUEUE; ++k, ++rp) { - if (!rp->parentfp) - break; - } - if (k < SG_MAX_QUEUE) { - memset(rp, 0, sizeof (Sg_request)); - rp->parentfp = sfp; - while (resp->nextrp) - resp = resp->nextrp; - resp->nextrp = rp; - resp = rp; - } else - resp = NULL; + if (!list_empty(&sfp->rq_list)) { + if (!sfp->cmd_q) + goto out_unlock; + + for (k = 0; k < SG_MAX_QUEUE; ++k, ++rp) { + if (!rp->parentfp) + break; } + if (k >= SG_MAX_QUEUE) + goto out_unlock; } - if (resp) { - resp->nextrp = NULL; - resp->header.duration = jiffies_to_msecs(jiffies); - } + memset(rp, 0, sizeof (Sg_request)); + rp->parentfp = sfp; + rp->header.duration = jiffies_to_msecs(jiffies); + list_add_tail(&rp->entry, &sfp->rq_list); write_unlock_irqrestore(&sfp->rq_list_lock, iflags); - return resp; + return rp; +out_unlock: + write_unlock_irqrestore(&sfp->rq_list_lock, iflags); + return NULL; } /* Return of 1 for found; 0 for not found */ static int sg_remove_request(Sg_fd * sfp, Sg_request * srp) { - Sg_request *prev_rp; - Sg_request *rp; unsigned long iflags; int res = 0; - if ((!sfp) || (!srp) || (!sfp->headrp)) + if (!sfp || !srp || list_empty(&sfp->rq_list)) return res; write_lock_irqsave(&sfp->rq_list_lock, iflags); - prev_rp = sfp->headrp; - if (srp == prev_rp) { - sfp->headrp = prev_rp->nextrp; - prev_rp->parentfp = NULL; + if (!list_empty(&srp->entry)) { + list_del(&srp->entry); + srp->parentfp = NULL; res = 1; - } else { - while ((rp = prev_rp->nextrp)) { - if (srp == rp) { - prev_rp->nextrp = rp->nextrp; - rp->parentfp = NULL; - res = 1; - break; - } - prev_rp = rp; - } } write_unlock_irqrestore(&sfp->rq_list_lock, iflags); return res; @@ -2163,7 +2137,7 @@ sg_add_sfp(Sg_device * sdp) init_waitqueue_head(&sfp->read_wait); rwlock_init(&sfp->rq_list_lock); - + INIT_LIST_HEAD(&sfp->rq_list); kref_init(&sfp->f_ref); mutex_init(&sfp->f_mutex); sfp->timeout = SG_DEFAULT_TIMEOUT; @@ -2202,10 +2176,13 @@ sg_remove_sfp_usercontext(struct work_struct *work) { struct sg_fd *sfp = container_of(work, struct sg_fd, ew.work); struct sg_device *sdp = sfp->parentdp; + Sg_request *srp; /* Cleanup any responses which were never read(). */ - while (sfp->headrp) - sg_finish_rem_req(sfp->headrp); + while (!list_empty(&sfp->rq_list)) { + srp = list_first_entry(&sfp->rq_list, Sg_request, entry); + sg_finish_rem_req(srp); + } if (sfp->reserve.bufflen > 0) { SCSI_LOG_TIMEOUT(6, sg_printk(KERN_INFO, sdp, @@ -2608,7 +2585,7 @@ static int sg_proc_seq_show_devstrs(struct seq_file *s, void *v) /* must be called while holding sg_index_lock */ static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp) { - int k, m, new_interface, blen, usg; + int k, new_interface, blen, usg; Sg_request *srp; Sg_fd *fp; const sg_io_hdr_t *hp; @@ -2628,13 +2605,11 @@ static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp) seq_printf(s, " cmd_q=%d f_packid=%d k_orphan=%d closed=0\n", (int) fp->cmd_q, (int) fp->force_packid, (int) fp->keep_orphan); - for (m = 0, srp = fp->headrp; - srp != NULL; - ++m, srp = srp->nextrp) { + list_for_each_entry(srp, &fp->rq_list, entry) { hp = &srp->header; new_interface = (hp->interface_id == '\0') ? 0 : 1; if (srp->res_used) { - if (new_interface && + if (new_interface && (SG_FLAG_MMAP_IO & hp->flags)) cp = " mmap>> "; else @@ -2665,7 +2640,7 @@ static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp) seq_printf(s, "ms sgat=%d op=0x%02x\n", usg, (int) srp->data.cmd_opcode); } - if (0 == m) + if (list_empty(&fp->rq_list)) seq_puts(s, " No requests active\n"); read_unlock(&fp->rq_list_lock); } -- cgit v1.2.3 From 97d27b0dd015e980ade63fda111fd1353276e28b Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Fri, 7 Apr 2017 09:34:17 +0200 Subject: scsi: sg: close race condition in sg_remove_sfp_usercontext() sg_remove_sfp_usercontext() is clearing any sg requests, but needs to take 'rq_list_lock' when modifying the list. Reported-by: Christoph Hellwig Signed-off-by: Hannes Reinecke Reviewed-by: Johannes Thumshirn Tested-by: Johannes Thumshirn Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/sg.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 5c9f1b9f69e9..8147147df2f4 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -524,6 +524,7 @@ sg_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos) } else count = (old_hdr->result == 0) ? 0 : -EIO; sg_finish_rem_req(srp); + sg_remove_request(sfp, srp); retval = count; free_old_hdr: kfree(old_hdr); @@ -564,6 +565,7 @@ sg_new_read(Sg_fd * sfp, char __user *buf, size_t count, Sg_request * srp) } err_out: err2 = sg_finish_rem_req(srp); + sg_remove_request(sfp, srp); return err ? : err2 ? : count; } @@ -800,6 +802,7 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp, SCSI_LOG_TIMEOUT(1, sg_printk(KERN_INFO, sfp->parentdp, "sg_common_write: start_req err=%d\n", k)); sg_finish_rem_req(srp); + sg_remove_request(sfp, srp); return k; /* probably out of space --> ENOMEM */ } if (atomic_read(&sdp->detaching)) { @@ -810,6 +813,7 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp, } sg_finish_rem_req(srp); + sg_remove_request(sfp, srp); return -ENODEV; } @@ -1285,6 +1289,7 @@ sg_rq_end_io_usercontext(struct work_struct *work) struct sg_fd *sfp = srp->parentfp; sg_finish_rem_req(srp); + sg_remove_request(sfp, srp); kref_put(&sfp->f_ref, sg_remove_sfp); } @@ -1831,8 +1836,6 @@ sg_finish_rem_req(Sg_request *srp) else sg_remove_scat(sfp, req_schp); - sg_remove_request(sfp, srp); - return ret; } @@ -2177,12 +2180,17 @@ sg_remove_sfp_usercontext(struct work_struct *work) struct sg_fd *sfp = container_of(work, struct sg_fd, ew.work); struct sg_device *sdp = sfp->parentdp; Sg_request *srp; + unsigned long iflags; /* Cleanup any responses which were never read(). */ + write_lock_irqsave(&sfp->rq_list_lock, iflags); while (!list_empty(&sfp->rq_list)) { srp = list_first_entry(&sfp->rq_list, Sg_request, entry); sg_finish_rem_req(srp); + list_del(&srp->entry); + srp->parentfp = NULL; } + write_unlock_irqrestore(&sfp->rq_list_lock, iflags); if (sfp->reserve.bufflen > 0) { SCSI_LOG_TIMEOUT(6, sg_printk(KERN_INFO, sdp, -- cgit v1.2.3 From fcabb09e59a71ee7878ca3681828eed6e2c15cd2 Mon Sep 17 00:00:00 2001 From: Johannes Thumshirn Date: Fri, 7 Apr 2017 15:42:24 +0200 Subject: scsi: libfc: directly call ELS request handlers Directly call ELS request handler functions in fc_lport_recv_els_req instead of saving the pointer to the handler's receive function and then later dereferencing this pointer. This makes the code a bit more obvious. Signed-off-by: Johannes Thumshirn Reviewed-by: Chad Dupuis Signed-off-by: Martin K. Petersen --- drivers/scsi/libfc/fc_lport.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index aa76f36abe03..2fd0ec651170 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -887,8 +887,6 @@ out: static void fc_lport_recv_els_req(struct fc_lport *lport, struct fc_frame *fp) { - void (*recv)(struct fc_lport *, struct fc_frame *); - mutex_lock(&lport->lp_mutex); /* @@ -902,31 +900,31 @@ static void fc_lport_recv_els_req(struct fc_lport *lport, /* * Check opcode. */ - recv = fc_rport_recv_req; switch (fc_frame_payload_op(fp)) { case ELS_FLOGI: if (!lport->point_to_multipoint) - recv = fc_lport_recv_flogi_req; + fc_lport_recv_flogi_req(lport, fp); break; case ELS_LOGO: if (fc_frame_sid(fp) == FC_FID_FLOGI) - recv = fc_lport_recv_logo_req; + fc_lport_recv_logo_req(lport, fp); break; case ELS_RSCN: - recv = lport->tt.disc_recv_req; + lport->tt.disc_recv_req(lport, fp); break; case ELS_ECHO: - recv = fc_lport_recv_echo_req; + fc_lport_recv_echo_req(lport, fp); break; case ELS_RLIR: - recv = fc_lport_recv_rlir_req; + fc_lport_recv_rlir_req(lport, fp); break; case ELS_RNID: - recv = fc_lport_recv_rnid_req; + fc_lport_recv_rnid_req(lport, fp); + break; + default: + fc_rport_recv_req(lport, fp); break; } - - recv(lport, fp); } mutex_unlock(&lport->lp_mutex); } -- cgit v1.2.3 From c7b9d369e4073399f97e6e090570f7df80f050dc Mon Sep 17 00:00:00 2001 From: Xiaofei Tan Date: Mon, 10 Apr 2017 21:21:56 +0800 Subject: scsi: hisi_sas: workaround STP link SoC bug After resetting the controller, the process of scanning SATA disks attached to an expander may fail occasionally. The issue is that the controller can't close the STP link created by target if the max link time is 0. To workaround this issue, we reject STP link after resetting the controller, and change the corresponding PHY to accept STP link only after receiving data. We do this check in cq interrupt handler. In order not to reduce efficiency, we use an variable to control whether we should check and change PHY to accept STP link. The function phys_reject_stp_links_v2_hw() should be called after resetting the controller. The solution of another SoC bug "SATA IO timeout", that also uses the same register to control STP link, is not effective before the PHY accepts STP link. Signed-off-by: Xiaofei Tan Signed-off-by: John Garry Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas.h | 1 + drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 60 +++++++++++++++++++++++++++++++++- 2 files changed, 60 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index 6aa0b62fea86..72347b6fc47f 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -203,6 +203,7 @@ struct hisi_hba { int slot_index_count; unsigned long *slot_index_tags; + unsigned long reject_stp_links_msk; /* SCSI/SAS glue */ struct sas_ha_struct sha; diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 66c2de8b7b64..c550cc427207 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -218,6 +218,9 @@ #define RX_IDAF_DWORD6 (PORT_BASE + 0xdc) #define RXOP_CHECK_CFG_H (PORT_BASE + 0xfc) #define CON_CONTROL (PORT_BASE + 0x118) +#define CON_CONTROL_CFG_OPEN_ACC_STP_OFF 0 +#define CON_CONTROL_CFG_OPEN_ACC_STP_MSK \ + (0x01 << CON_CONTROL_CFG_OPEN_ACC_STP_OFF) #define DONE_RECEIVED_TIME (PORT_BASE + 0x11c) #define CHL_INT0 (PORT_BASE + 0x1b4) #define CHL_INT0_HOTPLUG_TOUT_OFF 0 @@ -240,6 +243,9 @@ #define CHL_INT1_MSK (PORT_BASE + 0x1c4) #define CHL_INT2_MSK (PORT_BASE + 0x1c8) #define CHL_INT_COAL_EN (PORT_BASE + 0x1d0) +#define DMA_TX_DFX1 (PORT_BASE + 0x204) +#define DMA_TX_DFX1_IPTT_OFF 0 +#define DMA_TX_DFX1_IPTT_MSK (0xffff << DMA_TX_DFX1_IPTT_OFF) #define PHY_CTRL_RDY_MSK (PORT_BASE + 0x2b0) #define PHYCTRL_NOT_RDY_MSK (PORT_BASE + 0x2b4) #define PHYCTRL_DWS_RESET_MSK (PORT_BASE + 0x2b8) @@ -593,7 +599,8 @@ static int slot_index_alloc_quirk_v2_hw(struct hisi_hba *hisi_hba, int *slot_idx, struct domain_device *device) { - unsigned int index = 0; + /* STP link chip bug workaround:index start from 1 */ + unsigned int index = 1; void *bitmap = hisi_hba->slot_index_tags; int sata_dev = dev_is_sata(device); @@ -875,6 +882,46 @@ static int reset_hw_v2_hw(struct hisi_hba *hisi_hba) return 0; } +/* This function needs to be called after resetting SAS controller. */ +static void phys_reject_stp_links_v2_hw(struct hisi_hba *hisi_hba) +{ + u32 cfg; + int phy_no; + + hisi_hba->reject_stp_links_msk = (1 << hisi_hba->n_phy) - 1; + for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++) { + cfg = hisi_sas_phy_read32(hisi_hba, phy_no, CON_CONTROL); + if (!(cfg & CON_CONTROL_CFG_OPEN_ACC_STP_MSK)) + continue; + + cfg &= ~CON_CONTROL_CFG_OPEN_ACC_STP_MSK; + hisi_sas_phy_write32(hisi_hba, phy_no, CON_CONTROL, cfg); + } +} + +static void phys_try_accept_stp_links_v2_hw(struct hisi_hba *hisi_hba) +{ + int phy_no; + u32 dma_tx_dfx1; + + for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++) { + if (!(hisi_hba->reject_stp_links_msk & BIT(phy_no))) + continue; + + dma_tx_dfx1 = hisi_sas_phy_read32(hisi_hba, phy_no, + DMA_TX_DFX1); + if (dma_tx_dfx1 & DMA_TX_DFX1_IPTT_MSK) { + u32 cfg = hisi_sas_phy_read32(hisi_hba, + phy_no, CON_CONTROL); + + cfg |= CON_CONTROL_CFG_OPEN_ACC_STP_MSK; + hisi_sas_phy_write32(hisi_hba, phy_no, + CON_CONTROL, cfg); + clear_bit(phy_no, &hisi_hba->reject_stp_links_msk); + } + } +} + static void init_reg_v2_hw(struct hisi_hba *hisi_hba) { struct device *dev = &hisi_hba->pdev->dev; @@ -1012,6 +1059,9 @@ static void link_timeout_enable_link(unsigned long data) int i, reg_val; for (i = 0; i < hisi_hba->n_phy; i++) { + if (hisi_hba->reject_stp_links_msk & BIT(i)) + continue; + reg_val = hisi_sas_phy_read32(hisi_hba, i, CON_CONTROL); if (!(reg_val & BIT(0))) { hisi_sas_phy_write32(hisi_hba, i, @@ -1031,6 +1081,9 @@ static void link_timeout_disable_link(unsigned long data) reg_val = hisi_sas_read32(hisi_hba, PHY_STATE); for (i = 0; i < hisi_hba->n_phy && reg_val; i++) { + if (hisi_hba->reject_stp_links_msk & BIT(i)) + continue; + if (reg_val & BIT(i)) { hisi_sas_phy_write32(hisi_hba, i, CON_CONTROL, 0x6); @@ -2867,6 +2920,9 @@ static void cq_tasklet_v2_hw(unsigned long val) u32 rd_point = cq->rd_point, wr_point, dev_id; int queue = cq->id; + if (unlikely(hisi_hba->reject_stp_links_msk)) + phys_try_accept_stp_links_v2_hw(hisi_hba); + complete_queue = hisi_hba->complete_hdr[queue]; spin_lock(&hisi_hba->lock); @@ -3214,6 +3270,8 @@ static int soft_reset_v2_hw(struct hisi_hba *hisi_hba) if (rc) return rc; + phys_reject_stp_links_v2_hw(hisi_hba); + /* Re-enable the PHYs */ for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++) { struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no]; -- cgit v1.2.3 From 32ccba52f128dbaee87c0bc5b45403f484c7e013 Mon Sep 17 00:00:00 2001 From: Xiaofei Tan Date: Mon, 10 Apr 2017 21:21:57 +0800 Subject: scsi: hisi_sas: workaround a SoC SATA IO processing bug This patch provides a workaround a SoC bug where SATA IPTTs for different devices may conflict. The workaround solution requests the following: 1. SATA device id must be even and not equal to SAS IPTT. 2. SATA device can not share the same IPTT with other SAS or SATA device. Besides we shall consider IPTT value 0 is reserved for another SoC bug (STP device open link at firstly after SAS controller reset). To sum up, the solution is: Each SATA device uses independent and continuous 32 even IPTT from 64 to 4094, then v2 hw can only support 63 SATA devices. All SAS device(SSP/SMP devices) share odd IPTT value from 1 to 4095. Signed-off-by: Xiaofei Tan Signed-off-by: John Garry Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas.h | 2 + drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 83 ++++++++++++++++++++++++++++------ 2 files changed, 72 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index 72347b6fc47f..c80ca831e474 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -115,6 +115,7 @@ struct hisi_sas_device { atomic64_t running_req; struct list_head list; u8 dev_status; + int sata_idx; }; struct hisi_sas_slot { @@ -238,6 +239,7 @@ struct hisi_hba { struct hisi_sas_slot *slot_info; unsigned long flags; const struct hisi_sas_hw *hw; /* Low level hw interface */ + unsigned long sata_dev_bitmap[BITS_TO_LONGS(HISI_SAS_MAX_DEVICES)]; struct work_struct rst_work; }; diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index c550cc427207..fc8d82964150 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -537,6 +537,7 @@ enum { }; #define HISI_SAS_COMMAND_ENTRIES_V2_HW 4096 +#define HISI_MAX_SATA_SUPPORT_V2_HW (HISI_SAS_COMMAND_ENTRIES_V2_HW/64 - 1) #define DIR_NO_DATA 0 #define DIR_TO_INI 1 @@ -597,39 +598,86 @@ static u32 hisi_sas_phy_read32(struct hisi_hba *hisi_hba, /* This function needs to be protected from pre-emption. */ static int slot_index_alloc_quirk_v2_hw(struct hisi_hba *hisi_hba, int *slot_idx, - struct domain_device *device) + struct domain_device *device) { - /* STP link chip bug workaround:index start from 1 */ - unsigned int index = 1; - void *bitmap = hisi_hba->slot_index_tags; int sata_dev = dev_is_sata(device); + void *bitmap = hisi_hba->slot_index_tags; + struct hisi_sas_device *sas_dev = device->lldd_dev; + int sata_idx = sas_dev->sata_idx; + int start, end; + + if (!sata_dev) { + /* + * STP link SoC bug workaround: index starts from 1. + * additionally, we can only allocate odd IPTT(1~4095) + * for SAS/SMP device. + */ + start = 1; + end = hisi_hba->slot_index_count; + } else { + if (sata_idx >= HISI_MAX_SATA_SUPPORT_V2_HW) + return -EINVAL; + + /* + * For SATA device: allocate even IPTT in this interval + * [64*(sata_idx+1), 64*(sata_idx+2)], then each SATA device + * own 32 IPTTs. IPTT 0 shall not be used duing to STP link + * SoC bug workaround. So we ignore the first 32 even IPTTs. + */ + start = 64 * (sata_idx + 1); + end = 64 * (sata_idx + 2); + } while (1) { - index = find_next_zero_bit(bitmap, hisi_hba->slot_index_count, - index); - if (index >= hisi_hba->slot_index_count) + start = find_next_zero_bit(bitmap, + hisi_hba->slot_index_count, start); + if (start >= end) return -SAS_QUEUE_FULL; /* - * SAS IPTT bit0 should be 1 - */ - if (sata_dev || (index & 1)) + * SAS IPTT bit0 should be 1, and SATA IPTT bit0 should be 0. + */ + if (sata_dev ^ (start & 1)) break; - index++; + start++; } - set_bit(index, bitmap); - *slot_idx = index; + set_bit(start, bitmap); + *slot_idx = start; return 0; } +static bool sata_index_alloc_v2_hw(struct hisi_hba *hisi_hba, int *idx) +{ + unsigned int index; + struct device *dev = &hisi_hba->pdev->dev; + void *bitmap = hisi_hba->sata_dev_bitmap; + + index = find_first_zero_bit(bitmap, HISI_MAX_SATA_SUPPORT_V2_HW); + if (index >= HISI_MAX_SATA_SUPPORT_V2_HW) { + dev_warn(dev, "alloc sata index failed, index=%d\n", index); + return false; + } + + set_bit(index, bitmap); + *idx = index; + return true; +} + + static struct hisi_sas_device *alloc_dev_quirk_v2_hw(struct domain_device *device) { struct hisi_hba *hisi_hba = device->port->ha->lldd_ha; struct hisi_sas_device *sas_dev = NULL; int i, sata_dev = dev_is_sata(device); + int sata_idx = -1; spin_lock(&hisi_hba->lock); + + if (sata_dev) + if (!sata_index_alloc_v2_hw(hisi_hba, &sata_idx)) + goto out; + for (i = 0; i < HISI_SAS_MAX_DEVICES; i++) { /* * SATA device id bit0 should be 0 @@ -643,10 +691,13 @@ hisi_sas_device *alloc_dev_quirk_v2_hw(struct domain_device *device) sas_dev->dev_type = device->dev_type; sas_dev->hisi_hba = hisi_hba; sas_dev->sas_device = device; + sas_dev->sata_idx = sata_idx; INIT_LIST_HEAD(&hisi_hba->devices[i].list); break; } } + +out: spin_unlock(&hisi_hba->lock); return sas_dev; @@ -753,6 +804,10 @@ static void free_device_v2_hw(struct hisi_hba *hisi_hba, u32 reg_val = hisi_sas_read32(hisi_hba, ENT_INT_SRC3); int i; + /* SoC bug workaround */ + if (dev_is_sata(sas_dev->sas_device)) + clear_bit(sas_dev->sata_idx, hisi_hba->sata_dev_bitmap); + /* clear the itct interrupt state */ if (ENT_INT_SRC3_ITC_INT_MSK & reg_val) hisi_sas_write32(hisi_hba, ENT_INT_SRC3, @@ -3197,6 +3252,8 @@ static int hisi_sas_v2_init(struct hisi_hba *hisi_hba) { int rc; + memset(hisi_hba->sata_dev_bitmap, 0, sizeof(hisi_hba->sata_dev_bitmap)); + rc = hw_init_v2_hw(hisi_hba); if (rc) return rc; -- cgit v1.2.3 From 819cbf189553b183dd1257ea44c4e47949481116 Mon Sep 17 00:00:00 2001 From: Xiaofei Tan Date: Mon, 10 Apr 2017 21:21:58 +0800 Subject: scsi: hisi_sas: workaround SoC about abort timeout bug This patch adds a workaround solution for a SoC bug which may cause SoC logic fatal error when disabling a PHY. Then we find internal abort IO timeout may occur, and the controller IO breakpoint may be corrupted. We work around this SoC bug by optimizing the flow of disabling a PHY. Signed-off-by: Xiaofei Tan Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 127 ++++++++++++++++++++++++++++++++- 1 file changed, 126 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index fc8d82964150..9b80b2ab6985 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -207,6 +207,8 @@ #define TXID_AUTO (PORT_BASE + 0xb8) #define TXID_AUTO_CT3_OFF 1 #define TXID_AUTO_CT3_MSK (0x1 << TXID_AUTO_CT3_OFF) +#define TXID_AUTO_CTB_OFF 11 +#define TXID_AUTO_CTB_MSK (0x1 << TXID_AUTO_CTB_OFF) #define TX_HARDRST_OFF 2 #define TX_HARDRST_MSK (0x1 << TX_HARDRST_OFF) #define RX_IDAF_DWORD0 (PORT_BASE + 0xc4) @@ -243,9 +245,17 @@ #define CHL_INT1_MSK (PORT_BASE + 0x1c4) #define CHL_INT2_MSK (PORT_BASE + 0x1c8) #define CHL_INT_COAL_EN (PORT_BASE + 0x1d0) +#define DMA_TX_DFX0 (PORT_BASE + 0x200) #define DMA_TX_DFX1 (PORT_BASE + 0x204) #define DMA_TX_DFX1_IPTT_OFF 0 #define DMA_TX_DFX1_IPTT_MSK (0xffff << DMA_TX_DFX1_IPTT_OFF) +#define DMA_TX_FIFO_DFX0 (PORT_BASE + 0x240) +#define PORT_DFX0 (PORT_BASE + 0x258) +#define LINK_DFX2 (PORT_BASE + 0X264) +#define LINK_DFX2_RCVR_HOLD_STS_OFF 9 +#define LINK_DFX2_RCVR_HOLD_STS_MSK (0x1 << LINK_DFX2_RCVR_HOLD_STS_OFF) +#define LINK_DFX2_SEND_HOLD_STS_OFF 10 +#define LINK_DFX2_SEND_HOLD_STS_MSK (0x1 << LINK_DFX2_SEND_HOLD_STS_OFF) #define PHY_CTRL_RDY_MSK (PORT_BASE + 0x2b0) #define PHYCTRL_NOT_RDY_MSK (PORT_BASE + 0x2b4) #define PHYCTRL_DWS_RESET_MSK (PORT_BASE + 0x2b8) @@ -1194,12 +1204,127 @@ static bool is_sata_phy_v2_hw(struct hisi_hba *hisi_hba, int phy_no) return false; } +static bool tx_fifo_is_empty_v2_hw(struct hisi_hba *hisi_hba, int phy_no) +{ + u32 dfx_val; + + dfx_val = hisi_sas_phy_read32(hisi_hba, phy_no, DMA_TX_DFX1); + + if (dfx_val & BIT(16)) + return false; + + return true; +} + +static bool axi_bus_is_idle_v2_hw(struct hisi_hba *hisi_hba, int phy_no) +{ + int i, max_loop = 1000; + struct device *dev = &hisi_hba->pdev->dev; + u32 status, axi_status, dfx_val, dfx_tx_val; + + for (i = 0; i < max_loop; i++) { + status = hisi_sas_read32_relaxed(hisi_hba, + AXI_MASTER_CFG_BASE + AM_CURR_TRANS_RETURN); + + axi_status = hisi_sas_read32(hisi_hba, AXI_CFG); + dfx_val = hisi_sas_phy_read32(hisi_hba, phy_no, DMA_TX_DFX1); + dfx_tx_val = hisi_sas_phy_read32(hisi_hba, + phy_no, DMA_TX_FIFO_DFX0); + + if ((status == 0x3) && (axi_status == 0x0) && + (dfx_val & BIT(20)) && (dfx_tx_val & BIT(10))) + return true; + udelay(10); + } + dev_err(dev, "bus is not idle phy%d, axi150:0x%x axi100:0x%x port204:0x%x port240:0x%x\n", + phy_no, status, axi_status, + dfx_val, dfx_tx_val); + return false; +} + +static bool wait_io_done_v2_hw(struct hisi_hba *hisi_hba, int phy_no) +{ + int i, max_loop = 1000; + struct device *dev = &hisi_hba->pdev->dev; + u32 status, tx_dfx0; + + for (i = 0; i < max_loop; i++) { + status = hisi_sas_phy_read32(hisi_hba, phy_no, LINK_DFX2); + status = (status & 0x3fc0) >> 6; + + if (status != 0x1) + return true; + + tx_dfx0 = hisi_sas_phy_read32(hisi_hba, phy_no, DMA_TX_DFX0); + if ((tx_dfx0 & 0x1ff) == 0x2) + return true; + udelay(10); + } + dev_err(dev, "IO not done phy%d, port264:0x%x port200:0x%x\n", + phy_no, status, tx_dfx0); + return false; +} + +static bool allowed_disable_phy_v2_hw(struct hisi_hba *hisi_hba, int phy_no) +{ + if (tx_fifo_is_empty_v2_hw(hisi_hba, phy_no)) + return true; + + if (!axi_bus_is_idle_v2_hw(hisi_hba, phy_no)) + return false; + + if (!wait_io_done_v2_hw(hisi_hba, phy_no)) + return false; + + return true; +} + + static void disable_phy_v2_hw(struct hisi_hba *hisi_hba, int phy_no) { - u32 cfg = hisi_sas_phy_read32(hisi_hba, phy_no, PHY_CFG); + u32 cfg, axi_val, dfx0_val, txid_auto; + struct device *dev = &hisi_hba->pdev->dev; + + /* Close axi bus. */ + axi_val = hisi_sas_read32(hisi_hba, AXI_MASTER_CFG_BASE + + AM_CTRL_GLOBAL); + axi_val |= 0x1; + hisi_sas_write32(hisi_hba, AXI_MASTER_CFG_BASE + + AM_CTRL_GLOBAL, axi_val); + + if (is_sata_phy_v2_hw(hisi_hba, phy_no)) { + if (allowed_disable_phy_v2_hw(hisi_hba, phy_no)) + goto do_disable; + + /* Reset host controller. */ + queue_work(hisi_hba->wq, &hisi_hba->rst_work); + return; + } + + dfx0_val = hisi_sas_phy_read32(hisi_hba, phy_no, PORT_DFX0); + dfx0_val = (dfx0_val & 0x1fc0) >> 6; + if (dfx0_val != 0x4) + goto do_disable; + + if (!tx_fifo_is_empty_v2_hw(hisi_hba, phy_no)) { + dev_warn(dev, "phy%d, wait tx fifo need send break\n", + phy_no); + txid_auto = hisi_sas_phy_read32(hisi_hba, phy_no, + TXID_AUTO); + txid_auto |= TXID_AUTO_CTB_MSK; + hisi_sas_phy_write32(hisi_hba, phy_no, TXID_AUTO, + txid_auto); + } +do_disable: + cfg = hisi_sas_phy_read32(hisi_hba, phy_no, PHY_CFG); cfg &= ~PHY_CFG_ENA_MSK; hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CFG, cfg); + + /* Open axi bus. */ + axi_val &= ~0x1; + hisi_sas_write32(hisi_hba, AXI_MASTER_CFG_BASE + + AM_CTRL_GLOBAL, axi_val); } static void start_phy_v2_hw(struct hisi_hba *hisi_hba, int phy_no) -- cgit v1.2.3 From 0844a3ff00e30cf7e8edbce40eab83593c051c78 Mon Sep 17 00:00:00 2001 From: John Garry Date: Mon, 10 Apr 2017 21:21:59 +0800 Subject: scsi: hisi_sas: add v2 hw internal abort timeout workaround This patch is a workaround for a SoC bug where an internal abort command may timeout. In v2 hw, the channel should become idle in order to finish abort process. If the target side has been sending HOLD, host side channel failed to complete the frame to send, and can not enter the idle state. Then internal abort command will timeout. As this issue is only in v2 hw, we deal with it in the hw layer. Our workaround solution is: If abort is not finished within a certain period of time, we will check HOLD status. If HOLD has been sending, we will send break command. Signed-off-by: John Garry Signed-off-by: Xiaofei Tan Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas.h | 1 + drivers/scsi/hisi_sas/hisi_sas_main.c | 2 +- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 62 +++++++++++++++++++++++++++++----- 3 files changed, 55 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index c80ca831e474..4e28f32e90b0 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -138,6 +138,7 @@ struct hisi_sas_slot { struct hisi_sas_sge_page *sge_page; dma_addr_t sge_page_dma; struct work_struct abort_slot; + struct timer_list internal_abort_timer; }; struct hisi_sas_tmf_task { diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 9890dfdd4111..a5c6d060f0ca 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -1224,7 +1224,7 @@ hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba, 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; + task->slow_task->timer.expires = jiffies + msecs_to_jiffies(110); add_timer(&task->slow_task->timer); /* Lock as we are alloc'ing a slot, which cannot be interrupted */ diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 9b80b2ab6985..af19613d791e 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -194,9 +194,9 @@ #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 RX_PRIMS_STATUS (PORT_BASE + 0x98) -#define RX_BCAST_CHG_OFF 1 -#define RX_BCAST_CHG_MSK (0x1 << RX_BCAST_CHG_OFF) +#define RX_PRIMS_STATUS (PORT_BASE + 0x98) +#define RX_BCAST_CHG_OFF 1 +#define RX_BCAST_CHG_MSK (0x1 << RX_BCAST_CHG_OFF) #define TX_ID_DWORD0 (PORT_BASE + 0x9c) #define TX_ID_DWORD1 (PORT_BASE + 0xa0) #define TX_ID_DWORD2 (PORT_BASE + 0xa4) @@ -209,8 +209,8 @@ #define TXID_AUTO_CT3_MSK (0x1 << TXID_AUTO_CT3_OFF) #define TXID_AUTO_CTB_OFF 11 #define TXID_AUTO_CTB_MSK (0x1 << TXID_AUTO_CTB_OFF) -#define TX_HARDRST_OFF 2 -#define TX_HARDRST_MSK (0x1 << TX_HARDRST_OFF) +#define TX_HARDRST_OFF 2 +#define TX_HARDRST_MSK (0x1 << TX_HARDRST_OFF) #define RX_IDAF_DWORD0 (PORT_BASE + 0xc4) #define RX_IDAF_DWORD1 (PORT_BASE + 0xc8) #define RX_IDAF_DWORD2 (PORT_BASE + 0xcc) @@ -245,13 +245,13 @@ #define CHL_INT1_MSK (PORT_BASE + 0x1c4) #define CHL_INT2_MSK (PORT_BASE + 0x1c8) #define CHL_INT_COAL_EN (PORT_BASE + 0x1d0) -#define DMA_TX_DFX0 (PORT_BASE + 0x200) -#define DMA_TX_DFX1 (PORT_BASE + 0x204) +#define DMA_TX_DFX0 (PORT_BASE + 0x200) +#define DMA_TX_DFX1 (PORT_BASE + 0x204) #define DMA_TX_DFX1_IPTT_OFF 0 #define DMA_TX_DFX1_IPTT_MSK (0xffff << DMA_TX_DFX1_IPTT_OFF) #define DMA_TX_FIFO_DFX0 (PORT_BASE + 0x240) -#define PORT_DFX0 (PORT_BASE + 0x258) -#define LINK_DFX2 (PORT_BASE + 0X264) +#define PORT_DFX0 (PORT_BASE + 0x258) +#define LINK_DFX2 (PORT_BASE + 0X264) #define LINK_DFX2_RCVR_HOLD_STS_OFF 9 #define LINK_DFX2_RCVR_HOLD_STS_MSK (0x1 << LINK_DFX2_RCVR_HOLD_STS_OFF) #define LINK_DFX2_SEND_HOLD_STS_OFF 10 @@ -2260,15 +2260,18 @@ slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot) case STAT_IO_COMPLETE: /* internal abort command complete */ ts->stat = TMF_RESP_FUNC_SUCC; + del_timer(&slot->internal_abort_timer); goto out; case STAT_IO_NO_DEVICE: ts->stat = TMF_RESP_FUNC_COMPLETE; + del_timer(&slot->internal_abort_timer); 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; + del_timer(&slot->internal_abort_timer); goto out; default: break; @@ -2502,6 +2505,40 @@ static int prep_ata_v2_hw(struct hisi_hba *hisi_hba, return 0; } +static void hisi_sas_internal_abort_quirk_timeout(unsigned long data) +{ + struct hisi_sas_slot *slot = (struct hisi_sas_slot *)data; + struct hisi_sas_port *port = slot->port; + struct asd_sas_port *asd_sas_port; + struct asd_sas_phy *sas_phy; + + if (!port) + return; + + asd_sas_port = &port->sas_port; + + /* Kick the hardware - send break command */ + list_for_each_entry(sas_phy, &asd_sas_port->phy_list, port_phy_el) { + struct hisi_sas_phy *phy = sas_phy->lldd_phy; + struct hisi_hba *hisi_hba = phy->hisi_hba; + int phy_no = sas_phy->id; + u32 link_dfx2; + + link_dfx2 = hisi_sas_phy_read32(hisi_hba, phy_no, LINK_DFX2); + if ((link_dfx2 == LINK_DFX2_RCVR_HOLD_STS_MSK) || + (link_dfx2 & LINK_DFX2_SEND_HOLD_STS_MSK)) { + u32 txid_auto; + + txid_auto = hisi_sas_phy_read32(hisi_hba, phy_no, + TXID_AUTO); + txid_auto |= TXID_AUTO_CTB_MSK; + hisi_sas_phy_write32(hisi_hba, phy_no, TXID_AUTO, + txid_auto); + return; + } + } +} + 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) @@ -2510,6 +2547,13 @@ static int prep_abort_v2_hw(struct hisi_hba *hisi_hba, struct domain_device *dev = task->dev; struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr; struct hisi_sas_port *port = slot->port; + struct timer_list *timer = &slot->internal_abort_timer; + + /* setup the quirk timer */ + setup_timer(timer, hisi_sas_internal_abort_quirk_timeout, + (unsigned long)slot); + /* Set the timeout to 10ms less than internal abort timeout */ + mod_timer(timer, jiffies + msecs_to_jiffies(100)); /* dw0 */ hdr->dw0 = cpu_to_le32((5 << CMD_HDR_CMD_OFF) | /*abort*/ -- cgit v1.2.3 From d3c4dd4e3dc52a7a8ae4cfd91fedffdeeb6e003b Mon Sep 17 00:00:00 2001 From: John Garry Date: Mon, 10 Apr 2017 21:22:00 +0800 Subject: scsi: hisi_sas: fix NULL deference when TMF timeouts If a TMF timeouts (maybe due to unlikely scenario of an expander being unplugged when TMF for remote device is active), when we eventually try to free the slot, we crash as we dereference the slot's task, which has already been released. As a fix, add checks in the slot release code for a NULL task. Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 60 +++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index a5c6d060f0ca..7e6e8823a5c7 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -77,17 +77,22 @@ static void hisi_sas_slot_index_init(struct hisi_hba *hisi_hba) void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task, struct hisi_sas_slot *slot) { - struct device *dev = &hisi_hba->pdev->dev; - struct domain_device *device = task->dev; - struct hisi_sas_device *sas_dev = device->lldd_dev; - if (!slot->task) - return; + if (task) { + struct device *dev = &hisi_hba->pdev->dev; + struct domain_device *device = task->dev; + struct hisi_sas_device *sas_dev = device->lldd_dev; - if (!sas_protocol_ata(task->task_proto)) - if (slot->n_elem) - dma_unmap_sg(dev, task->scatter, slot->n_elem, - task->data_dir); + if (!sas_protocol_ata(task->task_proto)) + if (slot->n_elem) + dma_unmap_sg(dev, task->scatter, slot->n_elem, + task->data_dir); + + task->lldd_task = NULL; + + if (sas_dev) + atomic64_dec(&sas_dev->running_req); + } if (slot->command_table) dma_pool_free(hisi_hba->command_table_pool, @@ -102,12 +107,10 @@ void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task, slot->sge_page_dma); list_del_init(&slot->entry); - task->lldd_task = NULL; slot->task = NULL; slot->port = NULL; hisi_sas_slot_index_free(hisi_hba, slot->idx); - if (sas_dev) - atomic64_dec(&sas_dev->running_req); + /* slot memory is fully zeroed when it is reused */ } EXPORT_SYMBOL_GPL(hisi_sas_slot_task_free); @@ -569,25 +572,23 @@ static void hisi_sas_port_notify_formed(struct asd_sas_phy *sas_phy) spin_unlock_irqrestore(&hisi_hba->lock, flags); } -static void hisi_sas_do_release_task(struct hisi_hba *hisi_hba, - struct sas_task *task, +static void hisi_sas_do_release_task(struct hisi_hba *hisi_hba, struct sas_task *task, struct hisi_sas_slot *slot) { - struct task_status_struct *ts; - unsigned long flags; - - if (!task) - return; + if (task) { + unsigned long flags; + struct task_status_struct *ts; - ts = &task->task_status; + ts = &task->task_status; - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_ABORTED_TASK; - spin_lock_irqsave(&task->task_state_lock, flags); - task->task_state_flags &= - ~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR); - task->task_state_flags |= SAS_TASK_STATE_DONE; - spin_unlock_irqrestore(&task->task_state_lock, flags); + ts->resp = SAS_TASK_COMPLETE; + ts->stat = SAS_ABORTED_TASK; + spin_lock_irqsave(&task->task_state_lock, flags); + task->task_state_flags &= + ~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR); + task->task_state_flags |= SAS_TASK_STATE_DONE; + spin_unlock_irqrestore(&task->task_state_lock, flags); + } hisi_sas_slot_task_free(hisi_hba, task, slot); } @@ -742,7 +743,12 @@ static int hisi_sas_exec_internal_tmf_task(struct domain_device *device, /* Even TMF timed out, return direct. */ if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) { if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) { + struct hisi_sas_slot *slot = task->lldd_task; + dev_err(dev, "abort tmf: TMF task timeout\n"); + if (slot) + slot->task = NULL; + goto ex_err; } } -- cgit v1.2.3 From e281f42f41db2820b079543fffb64c50b903215b Mon Sep 17 00:00:00 2001 From: Xiang Chen Date: Mon, 10 Apr 2017 21:22:01 +0800 Subject: scsi: hisi_sas: controller reset for multi-bits ECC and AXI fatal errors For 1 bit ECC errors, those errors can be recovered by hw. But for multi-bits ECC and AXI errors, there are something wrong with whole module or system, so try reset the controller to recover those errors instead of calling panic(). Signed-off-by: Xiang Chen Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 93 ++++++++++++++++++++-------------- 1 file changed, 56 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index af19613d791e..e241921bee10 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -2918,94 +2918,105 @@ static void multi_bit_ecc_error_process_v2_hw(struct hisi_hba *hisi_hba, if (irq_value & BIT(SAS_ECC_INTR_DQE_ECC_MB_OFF)) { reg_val = hisi_sas_read32(hisi_hba, HGC_DQE_ECC_ADDR); - panic("%s: hgc_dqe_accbad_intr (0x%x) found: \ + dev_warn(dev, "hgc_dqe_accbad_intr (0x%x) found: \ Ram address is 0x%08X\n", - dev_name(dev), irq_value, + irq_value, (reg_val & HGC_DQE_ECC_MB_ADDR_MSK) >> HGC_DQE_ECC_MB_ADDR_OFF); + queue_work(hisi_hba->wq, &hisi_hba->rst_work); } if (irq_value & BIT(SAS_ECC_INTR_IOST_ECC_MB_OFF)) { reg_val = hisi_sas_read32(hisi_hba, HGC_IOST_ECC_ADDR); - panic("%s: hgc_iost_accbad_intr (0x%x) found: \ + dev_warn(dev, "hgc_iost_accbad_intr (0x%x) found: \ Ram address is 0x%08X\n", - dev_name(dev), irq_value, + irq_value, (reg_val & HGC_IOST_ECC_MB_ADDR_MSK) >> HGC_IOST_ECC_MB_ADDR_OFF); + queue_work(hisi_hba->wq, &hisi_hba->rst_work); } if (irq_value & BIT(SAS_ECC_INTR_ITCT_ECC_MB_OFF)) { reg_val = hisi_sas_read32(hisi_hba, HGC_ITCT_ECC_ADDR); - panic("%s: hgc_itct_accbad_intr (0x%x) found: \ + dev_warn(dev,"hgc_itct_accbad_intr (0x%x) found: \ Ram address is 0x%08X\n", - dev_name(dev), irq_value, + irq_value, (reg_val & HGC_ITCT_ECC_MB_ADDR_MSK) >> HGC_ITCT_ECC_MB_ADDR_OFF); + queue_work(hisi_hba->wq, &hisi_hba->rst_work); } if (irq_value & BIT(SAS_ECC_INTR_IOSTLIST_ECC_MB_OFF)) { reg_val = hisi_sas_read32(hisi_hba, HGC_LM_DFX_STATUS2); - panic("%s: hgc_iostl_accbad_intr (0x%x) found: \ + dev_warn(dev, "hgc_iostl_accbad_intr (0x%x) found: \ memory address is 0x%08X\n", - dev_name(dev), irq_value, + irq_value, (reg_val & HGC_LM_DFX_STATUS2_IOSTLIST_MSK) >> HGC_LM_DFX_STATUS2_IOSTLIST_OFF); + queue_work(hisi_hba->wq, &hisi_hba->rst_work); } if (irq_value & BIT(SAS_ECC_INTR_ITCTLIST_ECC_MB_OFF)) { reg_val = hisi_sas_read32(hisi_hba, HGC_LM_DFX_STATUS2); - panic("%s: hgc_itctl_accbad_intr (0x%x) found: \ + dev_warn(dev, "hgc_itctl_accbad_intr (0x%x) found: \ memory address is 0x%08X\n", - dev_name(dev), irq_value, + irq_value, (reg_val & HGC_LM_DFX_STATUS2_ITCTLIST_MSK) >> HGC_LM_DFX_STATUS2_ITCTLIST_OFF); + queue_work(hisi_hba->wq, &hisi_hba->rst_work); } if (irq_value & BIT(SAS_ECC_INTR_CQE_ECC_MB_OFF)) { reg_val = hisi_sas_read32(hisi_hba, HGC_CQE_ECC_ADDR); - panic("%s: hgc_cqe_accbad_intr (0x%x) found: \ + dev_warn(dev, "hgc_cqe_accbad_intr (0x%x) found: \ Ram address is 0x%08X\n", - dev_name(dev), irq_value, + irq_value, (reg_val & HGC_CQE_ECC_MB_ADDR_MSK) >> HGC_CQE_ECC_MB_ADDR_OFF); + queue_work(hisi_hba->wq, &hisi_hba->rst_work); } if (irq_value & BIT(SAS_ECC_INTR_NCQ_MEM0_ECC_MB_OFF)) { reg_val = hisi_sas_read32(hisi_hba, HGC_RXM_DFX_STATUS14); - panic("%s: rxm_mem0_accbad_intr (0x%x) found: \ + dev_warn(dev, "rxm_mem0_accbad_intr (0x%x) found: \ memory address is 0x%08X\n", - dev_name(dev), irq_value, + irq_value, (reg_val & HGC_RXM_DFX_STATUS14_MEM0_MSK) >> HGC_RXM_DFX_STATUS14_MEM0_OFF); + queue_work(hisi_hba->wq, &hisi_hba->rst_work); } if (irq_value & BIT(SAS_ECC_INTR_NCQ_MEM1_ECC_MB_OFF)) { reg_val = hisi_sas_read32(hisi_hba, HGC_RXM_DFX_STATUS14); - panic("%s: rxm_mem1_accbad_intr (0x%x) found: \ + dev_warn(dev, "rxm_mem1_accbad_intr (0x%x) found: \ memory address is 0x%08X\n", - dev_name(dev), irq_value, + irq_value, (reg_val & HGC_RXM_DFX_STATUS14_MEM1_MSK) >> HGC_RXM_DFX_STATUS14_MEM1_OFF); + queue_work(hisi_hba->wq, &hisi_hba->rst_work); } if (irq_value & BIT(SAS_ECC_INTR_NCQ_MEM2_ECC_MB_OFF)) { reg_val = hisi_sas_read32(hisi_hba, HGC_RXM_DFX_STATUS14); - panic("%s: rxm_mem2_accbad_intr (0x%x) found: \ + dev_warn(dev, "rxm_mem2_accbad_intr (0x%x) found: \ memory address is 0x%08X\n", - dev_name(dev), irq_value, + irq_value, (reg_val & HGC_RXM_DFX_STATUS14_MEM2_MSK) >> HGC_RXM_DFX_STATUS14_MEM2_OFF); + queue_work(hisi_hba->wq, &hisi_hba->rst_work); } if (irq_value & BIT(SAS_ECC_INTR_NCQ_MEM3_ECC_MB_OFF)) { reg_val = hisi_sas_read32(hisi_hba, HGC_RXM_DFX_STATUS15); - panic("%s: rxm_mem3_accbad_intr (0x%x) found: \ + dev_warn(dev, "rxm_mem3_accbad_intr (0x%x) found: \ memory address is 0x%08X\n", - dev_name(dev), irq_value, + irq_value, (reg_val & HGC_RXM_DFX_STATUS15_MEM3_MSK) >> HGC_RXM_DFX_STATUS15_MEM3_OFF); + queue_work(hisi_hba->wq, &hisi_hba->rst_work); } + return; } static irqreturn_t fatal_ecc_int_v2_hw(int irq_no, void *p) @@ -3063,23 +3074,27 @@ static irqreturn_t fatal_axi_int_v2_hw(int irq_no, void *p) if (irq_value & BIT(ENT_INT_SRC3_WP_DEPTH_OFF)) { hisi_sas_write32(hisi_hba, ENT_INT_SRC3, 1 << ENT_INT_SRC3_WP_DEPTH_OFF); - panic("%s: write pointer and depth error (0x%x) \ + dev_warn(dev, "write pointer and depth error (0x%x) \ found!\n", - dev_name(dev), irq_value); + irq_value); + queue_work(hisi_hba->wq, &hisi_hba->rst_work); } if (irq_value & BIT(ENT_INT_SRC3_IPTT_SLOT_NOMATCH_OFF)) { hisi_sas_write32(hisi_hba, ENT_INT_SRC3, 1 << ENT_INT_SRC3_IPTT_SLOT_NOMATCH_OFF); - panic("%s: iptt no match slot error (0x%x) found!\n", - dev_name(dev), irq_value); + dev_warn(dev, "iptt no match slot error (0x%x) found!\n", + irq_value); + queue_work(hisi_hba->wq, &hisi_hba->rst_work); } - if (irq_value & BIT(ENT_INT_SRC3_RP_DEPTH_OFF)) - panic("%s: read pointer and depth error (0x%x) \ + if (irq_value & BIT(ENT_INT_SRC3_RP_DEPTH_OFF)) { + dev_warn(dev, "read pointer and depth error (0x%x) \ found!\n", - dev_name(dev), irq_value); + irq_value); + queue_work(hisi_hba->wq, &hisi_hba->rst_work); + } if (irq_value & BIT(ENT_INT_SRC3_AXI_OFF)) { int i; @@ -3090,10 +3105,11 @@ static irqreturn_t fatal_axi_int_v2_hw(int irq_no, void *p) HGC_AXI_FIFO_ERR_INFO); for (i = 0; i < AXI_ERR_NR; i++) { - if (err_value & BIT(i)) - panic("%s: %s (0x%x) found!\n", - dev_name(dev), + if (err_value & BIT(i)) { + dev_warn(dev, "%s (0x%x) found!\n", axi_err_info[i], irq_value); + queue_work(hisi_hba->wq, &hisi_hba->rst_work); + } } } @@ -3106,10 +3122,11 @@ static irqreturn_t fatal_axi_int_v2_hw(int irq_no, void *p) HGC_AXI_FIFO_ERR_INFO); for (i = 0; i < FIFO_ERR_NR; i++) { - if (err_value & BIT(AXI_ERR_NR + i)) - panic("%s: %s (0x%x) found!\n", - dev_name(dev), + if (err_value & BIT(AXI_ERR_NR + i)) { + dev_warn(dev, "%s (0x%x) found!\n", fifo_err_info[i], irq_value); + queue_work(hisi_hba->wq, &hisi_hba->rst_work); + } } } @@ -3117,15 +3134,17 @@ static irqreturn_t fatal_axi_int_v2_hw(int irq_no, void *p) if (irq_value & BIT(ENT_INT_SRC3_LM_OFF)) { hisi_sas_write32(hisi_hba, ENT_INT_SRC3, 1 << ENT_INT_SRC3_LM_OFF); - panic("%s: LM add/fetch list error (0x%x) found!\n", - dev_name(dev), irq_value); + dev_warn(dev, "LM add/fetch list error (0x%x) found!\n", + irq_value); + queue_work(hisi_hba->wq, &hisi_hba->rst_work); } if (irq_value & BIT(ENT_INT_SRC3_ABT_OFF)) { hisi_sas_write32(hisi_hba, ENT_INT_SRC3, 1 << ENT_INT_SRC3_ABT_OFF); - panic("%s: SAS_HGC_ABT fetch LM list error (0x%x) found!\n", - dev_name(dev), irq_value); + dev_warn(dev, "SAS_HGC_ABT fetch LM list error (0x%x) found!\n", + irq_value); + queue_work(hisi_hba->wq, &hisi_hba->rst_work); } } -- cgit v1.2.3 From 0d4bd8fea472e6bd2c7ff031cd8952f85d7b0bb0 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 12 Apr 2017 15:12:35 +0100 Subject: scsi: snic: fix spelling mistake: "Cann't" -> "Cannot" Trivial fix to spelling mistake in SNIC_ERR error message text, one cannot have "Cann't". Signed-off-by: Colin Ian King Signed-off-by: Martin K. Petersen --- drivers/scsi/snic/snic_debugfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/snic/snic_debugfs.c b/drivers/scsi/snic/snic_debugfs.c index d30280326bde..269ddf791a73 100644 --- a/drivers/scsi/snic/snic_debugfs.c +++ b/drivers/scsi/snic/snic_debugfs.c @@ -548,7 +548,7 @@ snic_trc_debugfs_init(void) &snic_trc_fops); if (!de) { - SNIC_ERR("Cann't create trace file.\n"); + SNIC_ERR("Cannot create trace file.\n"); return ret; } -- cgit v1.2.3 From 76a6ebbeef26b004c36a0c8ee0496bae5428fc31 Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 12 Apr 2017 14:11:44 -0500 Subject: scsi: cxlflash: Separate RRQ processing from the RRQ interrupt handler In order to support processing the HRRQ by other means (e.g. polling), the processing portion of the current RRQ interrupt handler needs to be broken out into a separate routine. This will allow RRQ processing from places other than the RRQ hardware interrupt handler. Signed-off-by: Matthew R. Ochs Signed-off-by: Uma Krishnan Signed-off-by: Martin K. Petersen --- drivers/scsi/cxlflash/main.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index 3061d8045382..30c09593c122 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -1155,19 +1155,18 @@ cxlflash_sync_err_irq_exit: } /** - * cxlflash_rrq_irq() - interrupt handler for read-response queue (normal path) - * @irq: Interrupt number. - * @data: Private data provided at interrupt registration, the AFU. + * process_hrrq() - process the read-response queue + * @afu: AFU associated with the host. * - * Return: Always return IRQ_HANDLED. + * Return: The number of entries processed. */ -static irqreturn_t cxlflash_rrq_irq(int irq, void *data) +static int process_hrrq(struct afu *afu) { - struct afu *afu = (struct afu *)data; struct afu_cmd *cmd; struct sisl_ioasa *ioasa; struct sisl_ioarcb *ioarcb; bool toggle = afu->toggle; + int num_hrrq = 0; u64 entry, *hrrq_start = afu->hrrq_start, *hrrq_end = afu->hrrq_end, @@ -1201,11 +1200,27 @@ static irqreturn_t cxlflash_rrq_irq(int irq, void *data) } atomic_inc(&afu->hsq_credits); + num_hrrq++; } afu->hrrq_curr = hrrq_curr; afu->toggle = toggle; + return num_hrrq; +} + +/** + * cxlflash_rrq_irq() - interrupt handler for read-response queue (normal path) + * @irq: Interrupt number. + * @data: Private data provided at interrupt registration, the AFU. + * + * Return: Always return IRQ_HANDLED. + */ +static irqreturn_t cxlflash_rrq_irq(int irq, void *data) +{ + struct afu *afu = (struct afu *)data; + + process_hrrq(afu); return IRQ_HANDLED; } -- cgit v1.2.3 From f918b4a8e6f8bb59c44045f85d10fd9cc7e5a4c0 Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 12 Apr 2017 14:12:55 -0500 Subject: scsi: cxlflash: Serialize RRQ access and support offlevel processing As further staging to support processing the HRRQ by other means, access to the HRRQ needs to be serialized by a disabled lock. This will allow safe access in other non-hardware interrupt contexts. In an effort to minimize the period where interrupts are disabled, support is added to queue up commands harvested from the RRQ such that they can be processed with hardware interrupts enabled. While this doesn't offer any improvement with processing on a hardware interrupt it will help when IRQ polling is supported and the command completions can execute on softirq context. Signed-off-by: Matthew R. Ochs Signed-off-by: Uma Krishnan Signed-off-by: Martin K. Petersen --- drivers/scsi/cxlflash/common.h | 2 ++ drivers/scsi/cxlflash/main.c | 42 +++++++++++++++++++++++++++++++++++------- 2 files changed, 37 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/cxlflash/common.h b/drivers/scsi/cxlflash/common.h index d11dcc59ff46..9d56b8c797c4 100644 --- a/drivers/scsi/cxlflash/common.h +++ b/drivers/scsi/cxlflash/common.h @@ -134,6 +134,7 @@ struct afu_cmd { struct afu *parent; struct scsi_cmnd *scp; struct completion cevent; + struct list_head queue; u8 cmd_tmf:1; @@ -181,6 +182,7 @@ struct afu { struct sisl_ioarcb *hsq_start; struct sisl_ioarcb *hsq_end; struct sisl_ioarcb *hsq_curr; + spinlock_t hrrq_slock; u64 *hrrq_start; u64 *hrrq_end; u64 *hrrq_curr; diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index 30c09593c122..8c207ba8474b 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -1157,10 +1157,13 @@ cxlflash_sync_err_irq_exit: /** * process_hrrq() - process the read-response queue * @afu: AFU associated with the host. + * @doneq: Queue of commands harvested from the RRQ. + * + * This routine must be called holding the disabled RRQ spin lock. * * Return: The number of entries processed. */ -static int process_hrrq(struct afu *afu) +static int process_hrrq(struct afu *afu, struct list_head *doneq) { struct afu_cmd *cmd; struct sisl_ioasa *ioasa; @@ -1189,7 +1192,7 @@ static int process_hrrq(struct afu *afu) cmd = container_of(ioarcb, struct afu_cmd, rcb); } - cmd_complete(cmd); + list_add_tail(&cmd->queue, doneq); /* Advance to next entry or wrap and flip the toggle bit */ if (hrrq_curr < hrrq_end) @@ -1209,18 +1212,44 @@ static int process_hrrq(struct afu *afu) return num_hrrq; } +/** + * process_cmd_doneq() - process a queue of harvested RRQ commands + * @doneq: Queue of completed commands. + * + * Note that upon return the queue can no longer be trusted. + */ +static void process_cmd_doneq(struct list_head *doneq) +{ + struct afu_cmd *cmd, *tmp; + + WARN_ON(list_empty(doneq)); + + list_for_each_entry_safe(cmd, tmp, doneq, queue) + cmd_complete(cmd); +} + /** * cxlflash_rrq_irq() - interrupt handler for read-response queue (normal path) * @irq: Interrupt number. * @data: Private data provided at interrupt registration, the AFU. * - * Return: Always return IRQ_HANDLED. + * Return: IRQ_HANDLED or IRQ_NONE when no ready entries found. */ static irqreturn_t cxlflash_rrq_irq(int irq, void *data) { struct afu *afu = (struct afu *)data; + unsigned long hrrq_flags; + LIST_HEAD(doneq); + int num_entries = 0; - process_hrrq(afu); + spin_lock_irqsave(&afu->hrrq_slock, hrrq_flags); + num_entries = process_hrrq(afu, &doneq); + spin_unlock_irqrestore(&afu->hrrq_slock, hrrq_flags); + + if (num_entries == 0) + return IRQ_NONE; + + process_cmd_doneq(&doneq); return IRQ_HANDLED; } @@ -1540,14 +1569,13 @@ static int start_afu(struct cxlflash_cfg *cfg) init_pcr(cfg); - /* After an AFU reset, RRQ entries are stale, clear them */ + /* Initialize RRQ */ memset(&afu->rrq_entry, 0, sizeof(afu->rrq_entry)); - - /* Initialize RRQ pointers */ afu->hrrq_start = &afu->rrq_entry[0]; afu->hrrq_end = &afu->rrq_entry[NUM_RRQ_ENTRY - 1]; afu->hrrq_curr = afu->hrrq_start; afu->toggle = 1; + spin_lock_init(&afu->hrrq_slock); /* Initialize SQ */ if (afu_is_sq_cmd_mode(afu)) { -- cgit v1.2.3 From cba06e6de4038cd44a3e93a92ad982c372b8a14e Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 12 Apr 2017 14:13:20 -0500 Subject: scsi: cxlflash: Implement IRQ polling for RRQ processing Currently, RRQ processing takes place on hardware interrupt context. This can be a heavy burden in some environments due to the overhead encountered while completing RRQ entries. In an effort to improve system performance, use the IRQ polling API to schedule this processing on softirq context. This function will be disabled by default until starting values can be established for the hardware supported by this driver. Signed-off-by: Matthew R. Ochs Signed-off-by: Uma Krishnan Signed-off-by: Martin K. Petersen --- drivers/scsi/cxlflash/common.h | 8 +++ drivers/scsi/cxlflash/main.c | 123 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 127 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/cxlflash/common.h b/drivers/scsi/cxlflash/common.h index 9d56b8c797c4..3ff05f15b417 100644 --- a/drivers/scsi/cxlflash/common.h +++ b/drivers/scsi/cxlflash/common.h @@ -15,6 +15,7 @@ #ifndef _CXLFLASH_COMMON_H #define _CXLFLASH_COMMON_H +#include #include #include #include @@ -196,10 +197,17 @@ struct afu { char version[16]; u64 interface_version; + u32 irqpoll_weight; + struct irq_poll irqpoll; struct cxlflash_cfg *parent; /* Pointer back to parent cxlflash_cfg */ }; +static inline bool afu_is_irqpoll_enabled(struct afu *afu) +{ + return !!afu->irqpoll_weight; +} + static inline bool afu_is_cmd_mode(struct afu *afu, u64 cmd_mode) { u64 afu_cap = afu->interface_version >> SISL_INTVER_CAP_SHIFT; diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index 8c207ba8474b..30d68af87d1d 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -554,7 +554,7 @@ static void free_mem(struct cxlflash_cfg *cfg) * Safe to call with AFU in a partially allocated/initialized state. * * Cancels scheduled worker threads, waits for any active internal AFU - * commands to timeout and then unmaps the MMIO space. + * commands to timeout, disables IRQ polling and then unmaps the MMIO space. */ static void stop_afu(struct cxlflash_cfg *cfg) { @@ -565,6 +565,8 @@ static void stop_afu(struct cxlflash_cfg *cfg) if (likely(afu)) { while (atomic_read(&afu->cmds_active)) ssleep(1); + if (afu_is_irqpoll_enabled(afu)) + irq_poll_disable(&afu->irqpoll); if (likely(afu->afu_map)) { cxl_psa_unmap((void __iomem *)afu->afu_map); afu->afu_map = NULL; @@ -1158,12 +1160,13 @@ cxlflash_sync_err_irq_exit: * process_hrrq() - process the read-response queue * @afu: AFU associated with the host. * @doneq: Queue of commands harvested from the RRQ. + * @budget: Threshold of RRQ entries to process. * * This routine must be called holding the disabled RRQ spin lock. * * Return: The number of entries processed. */ -static int process_hrrq(struct afu *afu, struct list_head *doneq) +static int process_hrrq(struct afu *afu, struct list_head *doneq, int budget) { struct afu_cmd *cmd; struct sisl_ioasa *ioasa; @@ -1175,7 +1178,7 @@ static int process_hrrq(struct afu *afu, struct list_head *doneq) *hrrq_end = afu->hrrq_end, *hrrq_curr = afu->hrrq_curr; - /* Process however many RRQ entries that are ready */ + /* Process ready RRQ entries up to the specified budget (if any) */ while (true) { entry = *hrrq_curr; @@ -1204,6 +1207,9 @@ static int process_hrrq(struct afu *afu, struct list_head *doneq) atomic_inc(&afu->hsq_credits); num_hrrq++; + + if (budget > 0 && num_hrrq >= budget) + break; } afu->hrrq_curr = hrrq_curr; @@ -1228,6 +1234,32 @@ static void process_cmd_doneq(struct list_head *doneq) cmd_complete(cmd); } +/** + * cxlflash_irqpoll() - process a queue of harvested RRQ commands + * @irqpoll: IRQ poll structure associated with queue to poll. + * @budget: Threshold of RRQ entries to process per poll. + * + * Return: The number of entries processed. + */ +static int cxlflash_irqpoll(struct irq_poll *irqpoll, int budget) +{ + struct afu *afu = container_of(irqpoll, struct afu, irqpoll); + unsigned long hrrq_flags; + LIST_HEAD(doneq); + int num_entries = 0; + + spin_lock_irqsave(&afu->hrrq_slock, hrrq_flags); + + num_entries = process_hrrq(afu, &doneq, budget); + if (num_entries < budget) + irq_poll_complete(irqpoll); + + spin_unlock_irqrestore(&afu->hrrq_slock, hrrq_flags); + + process_cmd_doneq(&doneq); + return num_entries; +} + /** * cxlflash_rrq_irq() - interrupt handler for read-response queue (normal path) * @irq: Interrupt number. @@ -1243,7 +1275,14 @@ static irqreturn_t cxlflash_rrq_irq(int irq, void *data) int num_entries = 0; spin_lock_irqsave(&afu->hrrq_slock, hrrq_flags); - num_entries = process_hrrq(afu, &doneq); + + if (afu_is_irqpoll_enabled(afu)) { + irq_poll_sched(&afu->irqpoll); + spin_unlock_irqrestore(&afu->hrrq_slock, hrrq_flags); + return IRQ_HANDLED; + } + + num_entries = process_hrrq(afu, &doneq, -1); spin_unlock_irqrestore(&afu->hrrq_slock, hrrq_flags); if (num_entries == 0) @@ -1588,6 +1627,11 @@ static int start_afu(struct cxlflash_cfg *cfg) atomic_set(&afu->hsq_credits, NUM_SQ_ENTRY - 1); } + /* Initialize IRQ poll */ + if (afu_is_irqpoll_enabled(afu)) + irq_poll_init(&afu->irqpoll, afu->irqpoll_weight, + cxlflash_irqpoll); + rc = init_global(cfg); dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); @@ -2224,6 +2268,75 @@ static ssize_t port1_lun_table_show(struct device *dev, return cxlflash_show_port_lun_table(1, afu, buf); } +/** + * irqpoll_weight_show() - presents the current IRQ poll weight for the host + * @dev: Generic device associated with the host. + * @attr: Device attribute representing the IRQ poll weight. + * @buf: Buffer of length PAGE_SIZE to report back the current IRQ poll + * weight in ASCII. + * + * An IRQ poll weight of 0 indicates polling is disabled. + * + * Return: The size of the ASCII string returned in @buf. + */ +static ssize_t irqpoll_weight_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev)); + struct afu *afu = cfg->afu; + + return scnprintf(buf, PAGE_SIZE, "%u\n", afu->irqpoll_weight); +} + +/** + * irqpoll_weight_store() - sets the current IRQ poll weight for the host + * @dev: Generic device associated with the host. + * @attr: Device attribute representing the IRQ poll weight. + * @buf: Buffer of length PAGE_SIZE containing the desired IRQ poll + * weight in ASCII. + * @count: Length of data resizing in @buf. + * + * An IRQ poll weight of 0 indicates polling is disabled. + * + * Return: The size of the ASCII string returned in @buf. + */ +static ssize_t irqpoll_weight_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev)); + struct device *cfgdev = &cfg->dev->dev; + struct afu *afu = cfg->afu; + u32 weight; + int rc; + + rc = kstrtouint(buf, 10, &weight); + if (rc) + return -EINVAL; + + if (weight > 256) { + dev_info(cfgdev, + "Invalid IRQ poll weight. It must be 256 or less.\n"); + return -EINVAL; + } + + if (weight == afu->irqpoll_weight) { + dev_info(cfgdev, + "Current IRQ poll weight has the same weight.\n"); + return -EINVAL; + } + + if (afu_is_irqpoll_enabled(afu)) + irq_poll_disable(&afu->irqpoll); + + afu->irqpoll_weight = weight; + + if (weight > 0) + irq_poll_init(&afu->irqpoll, weight, cxlflash_irqpoll); + + return count; +} + /** * mode_show() - presents the current mode of the device * @dev: Generic device associated with the device. @@ -2250,6 +2363,7 @@ static DEVICE_ATTR_RW(lun_mode); static DEVICE_ATTR_RO(ioctl_version); static DEVICE_ATTR_RO(port0_lun_table); static DEVICE_ATTR_RO(port1_lun_table); +static DEVICE_ATTR_RW(irqpoll_weight); static struct device_attribute *cxlflash_host_attrs[] = { &dev_attr_port0, @@ -2258,6 +2372,7 @@ static struct device_attribute *cxlflash_host_attrs[] = { &dev_attr_ioctl_version, &dev_attr_port0_lun_table, &dev_attr_port1_lun_table, + &dev_attr_irqpoll_weight, NULL }; -- cgit v1.2.3 From 3b225cd32a05b627a6ca366f364a824beaabecc5 Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 12 Apr 2017 14:13:34 -0500 Subject: scsi: cxlflash: Update sysfs helper routines to pass config structure As staging for future function, pass the config pointer instead of the AFU pointer for port-related sysfs helper routines. Signed-off-by: Matthew R. Ochs Signed-off-by: Uma Krishnan Signed-off-by: Martin K. Petersen --- drivers/scsi/cxlflash/main.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index 30d68af87d1d..157d806c97fc 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -2058,13 +2058,16 @@ static int cxlflash_change_queue_depth(struct scsi_device *sdev, int qdepth) /** * cxlflash_show_port_status() - queries and presents the current port status * @port: Desired port for status reporting. - * @afu: AFU owning the specified port. + * @cfg: Internal structure associated with the host. * @buf: Buffer of length PAGE_SIZE to report back port status in ASCII. * * Return: The size of the ASCII string returned in @buf. */ -static ssize_t cxlflash_show_port_status(u32 port, struct afu *afu, char *buf) +static ssize_t cxlflash_show_port_status(u32 port, + struct cxlflash_cfg *cfg, + char *buf) { + struct afu *afu = cfg->afu; char *disp_status; u64 status; __be64 __iomem *fc_regs; @@ -2099,9 +2102,8 @@ static ssize_t port0_show(struct device *dev, char *buf) { struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev)); - struct afu *afu = cfg->afu; - return cxlflash_show_port_status(0, afu, buf); + return cxlflash_show_port_status(0, cfg, buf); } /** @@ -2117,9 +2119,8 @@ static ssize_t port1_show(struct device *dev, char *buf) { struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev)); - struct afu *afu = cfg->afu; - return cxlflash_show_port_status(1, afu, buf); + return cxlflash_show_port_status(1, cfg, buf); } /** @@ -2208,15 +2209,16 @@ static ssize_t ioctl_version_show(struct device *dev, /** * cxlflash_show_port_lun_table() - queries and presents the port LUN table * @port: Desired port for status reporting. - * @afu: AFU owning the specified port. + * @cfg: Internal structure associated with the host. * @buf: Buffer of length PAGE_SIZE to report back port status in ASCII. * * Return: The size of the ASCII string returned in @buf. */ static ssize_t cxlflash_show_port_lun_table(u32 port, - struct afu *afu, + struct cxlflash_cfg *cfg, char *buf) { + struct afu *afu = cfg->afu; int i; ssize_t bytes = 0; __be64 __iomem *fc_port; @@ -2245,9 +2247,8 @@ static ssize_t port0_lun_table_show(struct device *dev, char *buf) { struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev)); - struct afu *afu = cfg->afu; - return cxlflash_show_port_lun_table(0, afu, buf); + return cxlflash_show_port_lun_table(0, cfg, buf); } /** @@ -2263,9 +2264,8 @@ static ssize_t port1_lun_table_show(struct device *dev, char *buf) { struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev)); - struct afu *afu = cfg->afu; - return cxlflash_show_port_lun_table(1, afu, buf); + return cxlflash_show_port_lun_table(1, cfg, buf); } /** -- cgit v1.2.3 From 78ae028e823701148e4915759459ee79597ea8ec Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 12 Apr 2017 14:13:50 -0500 Subject: scsi: cxlflash: Support dynamic number of FC ports Transition from a static number of FC ports to a value that is derived during probe. For now, a static value is used but this will later be based on the type of card being configured. Signed-off-by: Matthew R. Ochs Signed-off-by: Uma Krishnan Signed-off-by: Martin K. Petersen --- drivers/scsi/cxlflash/common.h | 7 ++-- drivers/scsi/cxlflash/main.c | 71 ++++++++++++++++++++++++--------------- drivers/scsi/cxlflash/main.h | 2 -- drivers/scsi/cxlflash/sislite.h | 1 + drivers/scsi/cxlflash/superpipe.h | 2 +- 5 files changed, 51 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/cxlflash/common.h b/drivers/scsi/cxlflash/common.h index 3ff05f15b417..6a04867a0eec 100644 --- a/drivers/scsi/cxlflash/common.h +++ b/drivers/scsi/cxlflash/common.h @@ -25,7 +25,9 @@ extern const struct file_operations cxlflash_cxl_fops; -#define MAX_CONTEXT CXLFLASH_MAX_CONTEXT /* num contexts per afu */ +#define MAX_CONTEXT CXLFLASH_MAX_CONTEXT /* num contexts per afu */ +#define NUM_FC_PORTS CXLFLASH_NUM_FC_PORTS /* ports per AFU */ +#define MAX_FC_PORTS CXLFLASH_MAX_FC_PORTS /* ports per AFU */ #define CXLFLASH_BLOCK_SIZE 4096 /* 4K blocks */ #define CXLFLASH_MAX_XFER_SIZE 16777216 /* 16MB transfer */ @@ -98,6 +100,7 @@ struct cxlflash_cfg { struct pci_dev *dev; struct pci_device_id *dev_id; struct Scsi_Host *host; + int num_fc_ports; ulong cxlflash_regs_pci; @@ -118,7 +121,7 @@ struct cxlflash_cfg { struct file_operations cxl_fops; /* Parameters that are LUN table related */ - int last_lun_index[CXLFLASH_NUM_FC_PORTS]; + int last_lun_index[MAX_FC_PORTS]; int promote_lun_index; struct list_head lluns; /* list of llun_info structs */ diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index 157d806c97fc..3f9c8690af0d 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -689,7 +689,7 @@ static void notify_shutdown(struct cxlflash_cfg *cfg, bool wait) global = &afu->afu_map->global; /* Notify AFU */ - for (i = 0; i < NUM_FC_PORTS; i++) { + for (i = 0; i < cfg->num_fc_ports; i++) { reg = readq_be(&global->fc_regs[i][FC_CONFIG2 / 8]); reg |= SISL_FC_SHUTDOWN_NORMAL; writeq_be(reg, &global->fc_regs[i][FC_CONFIG2 / 8]); @@ -699,7 +699,7 @@ static void notify_shutdown(struct cxlflash_cfg *cfg, bool wait) return; /* Wait up to 1.5 seconds for shutdown processing to complete */ - for (i = 0; i < NUM_FC_PORTS; i++) { + for (i = 0; i < cfg->num_fc_ports; i++) { retry_cnt = 0; while (true) { status = readq_be(&global->fc_regs[i][FC_STATUS / 8]); @@ -1072,6 +1072,7 @@ static const struct asyc_intr_info *find_ainfo(u64 status) */ static void afu_err_intr_init(struct afu *afu) { + struct cxlflash_cfg *cfg = afu->parent; int i; u64 reg; @@ -1107,7 +1108,7 @@ static void afu_err_intr_init(struct afu *afu) writeq_be(reg, &afu->afu_map->global.fc_regs[0][FC_CONFIG2 / 8]); /* now clear FC errors */ - for (i = 0; i < NUM_FC_PORTS; i++) { + for (i = 0; i < cfg->num_fc_ports; i++) { writeq_be(0xFFFFFFFFU, &afu->afu_map->global.fc_regs[i][FC_ERROR / 8]); writeq_be(0, &afu->afu_map->global.fc_regs[i][FC_ERRCAP / 8]); @@ -1394,7 +1395,7 @@ static int start_context(struct cxlflash_cfg *cfg) /** * read_vpd() - obtains the WWPNs from VPD * @cfg: Internal structure associated with the host. - * @wwpn: Array of size NUM_FC_PORTS to pass back WWPNs + * @wwpn: Array of size MAX_FC_PORTS to pass back WWPNs * * Return: 0 on success, -errno on failure */ @@ -1407,7 +1408,7 @@ static int read_vpd(struct cxlflash_cfg *cfg, u64 wwpn[]) ssize_t vpd_size; char vpd_data[CXLFLASH_VPD_LEN]; char tmp_buf[WWPN_BUF_LEN] = { 0 }; - char *wwpn_vpd_tags[NUM_FC_PORTS] = { "V5", "V6" }; + char *wwpn_vpd_tags[MAX_FC_PORTS] = { "V5", "V6" }; /* Get the VPD data from the device */ vpd_size = cxl_read_adapter_vpd(pdev, vpd_data, sizeof(vpd_data)); @@ -1445,7 +1446,7 @@ static int read_vpd(struct cxlflash_cfg *cfg, u64 wwpn[]) * because the conversion service requires that the ASCII * string be terminated. */ - for (k = 0; k < NUM_FC_PORTS; k++) { + for (k = 0; k < cfg->num_fc_ports; k++) { j = ro_size; i = ro_start + PCI_VPD_LRDT_TAG_SIZE; @@ -1474,6 +1475,8 @@ static int read_vpd(struct cxlflash_cfg *cfg, u64 wwpn[]) rc = -ENODEV; goto out; } + + dev_dbg(dev, "%s: wwpn%d=%016llx\n", __func__, k, wwpn[k]); } out: @@ -1520,7 +1523,7 @@ static int init_global(struct cxlflash_cfg *cfg) { struct afu *afu = cfg->afu; struct device *dev = &cfg->dev->dev; - u64 wwpn[NUM_FC_PORTS]; /* wwpn of AFU ports */ + u64 wwpn[MAX_FC_PORTS]; /* wwpn of AFU ports */ int i = 0, num_ports = 0; int rc = 0; u64 reg; @@ -1531,9 +1534,6 @@ static int init_global(struct cxlflash_cfg *cfg) goto out; } - dev_dbg(dev, "%s: wwpn0=%016llx wwpn1=%016llx\n", - __func__, wwpn[0], wwpn[1]); - /* Set up RRQ and SQ in AFU for master issued cmds */ writeq_be((u64) afu->hrrq_start, &afu->host_map->rrq_start); writeq_be((u64) afu->hrrq_end, &afu->host_map->rrq_end); @@ -1556,10 +1556,10 @@ static int init_global(struct cxlflash_cfg *cfg) if (afu->internal_lun) { /* Only use port 0 */ writeq_be(PORT0, &afu->afu_map->global.regs.afu_port_sel); - num_ports = NUM_FC_PORTS - 1; + num_ports = 0; } else { writeq_be(BOTH_PORTS, &afu->afu_map->global.regs.afu_port_sel); - num_ports = NUM_FC_PORTS; + num_ports = cfg->num_fc_ports; } for (i = 0; i < num_ports; i++) { @@ -2061,19 +2061,25 @@ static int cxlflash_change_queue_depth(struct scsi_device *sdev, int qdepth) * @cfg: Internal structure associated with the host. * @buf: Buffer of length PAGE_SIZE to report back port status in ASCII. * - * Return: The size of the ASCII string returned in @buf. + * Return: The size of the ASCII string returned in @buf or -EINVAL. */ static ssize_t cxlflash_show_port_status(u32 port, struct cxlflash_cfg *cfg, char *buf) { + struct device *dev = &cfg->dev->dev; struct afu *afu = cfg->afu; char *disp_status; u64 status; __be64 __iomem *fc_regs; - if (port >= NUM_FC_PORTS) - return 0; + WARN_ON(port >= MAX_FC_PORTS); + + if (port >= cfg->num_fc_ports) { + dev_info(dev, "%s: Port %d not supported on this card.\n", + __func__, port); + return -EINVAL; + } fc_regs = &afu->afu_map->global.fc_regs[port][0]; status = readq_be(&fc_regs[FC_MTIP_STATUS / 8]); @@ -2178,12 +2184,13 @@ static ssize_t lun_mode_store(struct device *dev, /* * When configured for internal LUN, there is only one channel, - * channel number 0, else there will be 2 (default). + * channel number 0, else there will be one less than the number + * of fc ports for this card. */ if (afu->internal_lun) shost->max_channel = 0; else - shost->max_channel = NUM_FC_PORTS - 1; + shost->max_channel = cfg->num_fc_ports - 1; afu_reset(cfg); scsi_scan_host(cfg->host); @@ -2212,19 +2219,25 @@ static ssize_t ioctl_version_show(struct device *dev, * @cfg: Internal structure associated with the host. * @buf: Buffer of length PAGE_SIZE to report back port status in ASCII. * - * Return: The size of the ASCII string returned in @buf. + * Return: The size of the ASCII string returned in @buf or -EINVAL. */ static ssize_t cxlflash_show_port_lun_table(u32 port, struct cxlflash_cfg *cfg, char *buf) { + struct device *dev = &cfg->dev->dev; struct afu *afu = cfg->afu; int i; ssize_t bytes = 0; __be64 __iomem *fc_port; - if (port >= NUM_FC_PORTS) - return 0; + WARN_ON(port >= MAX_FC_PORTS); + + if (port >= cfg->num_fc_ports) { + dev_info(dev, "%s: Port %d not supported on this card.\n", + __func__, port); + return -EINVAL; + } fc_port = &afu->afu_map->global.fc_port[port][0]; @@ -2499,6 +2512,7 @@ static int cxlflash_probe(struct pci_dev *pdev, struct device *dev = &pdev->dev; struct dev_dependent_vals *ddv; int rc = 0; + int k; dev_dbg(&pdev->dev, "%s: Found CXLFLASH with IRQ: %d\n", __func__, pdev->irq); @@ -2531,17 +2545,20 @@ static int cxlflash_probe(struct pci_dev *pdev, cfg->init_state = INIT_STATE_NONE; cfg->dev = pdev; + cfg->num_fc_ports = NUM_FC_PORTS; cfg->cxl_fops = cxlflash_cxl_fops; /* - * The promoted LUNs move to the top of the LUN table. The rest stay - * on the bottom half. The bottom half grows from the end - * (index = 255), whereas the top half grows from the beginning - * (index = 0). + * Promoted LUNs move to the top of the LUN table. The rest stay on + * the bottom half. The bottom half grows from the end (index = 255), + * whereas the top half grows from the beginning (index = 0). + * + * Initialize the last LUN index for all possible ports. */ - cfg->promote_lun_index = 0; - cfg->last_lun_index[0] = CXLFLASH_NUM_VLUNS/2 - 1; - cfg->last_lun_index[1] = CXLFLASH_NUM_VLUNS/2 - 1; + cfg->promote_lun_index = 0; + + for (k = 0; k < MAX_FC_PORTS; k++) + cfg->last_lun_index[k] = CXLFLASH_NUM_VLUNS/2 - 1; cfg->dev_id = (struct pci_device_id *)dev_id; diff --git a/drivers/scsi/cxlflash/main.h b/drivers/scsi/cxlflash/main.h index 0be2261e6312..49657f1f409e 100644 --- a/drivers/scsi/cxlflash/main.h +++ b/drivers/scsi/cxlflash/main.h @@ -37,8 +37,6 @@ #define CXLFLASH_PCI_ERROR_RECOVERY_TIMEOUT (120 * HZ) -#define NUM_FC_PORTS CXLFLASH_NUM_FC_PORTS /* ports per AFU */ - /* FC defines */ #define FC_MTIP_CMDCONFIG 0x010 #define FC_MTIP_STATUS 0x018 diff --git a/drivers/scsi/cxlflash/sislite.h b/drivers/scsi/cxlflash/sislite.h index a6e48a893fef..0db4bc1f4e23 100644 --- a/drivers/scsi/cxlflash/sislite.h +++ b/drivers/scsi/cxlflash/sislite.h @@ -367,6 +367,7 @@ struct sisl_global_regs { #define SISL_INTVER_CAP_RESERVED_CMD_MODE_B 0x100000000000ULL }; +#define CXLFLASH_MAX_FC_PORTS 2 #define CXLFLASH_NUM_FC_PORTS 2 #define CXLFLASH_MAX_CONTEXT 512 /* how many contexts per afu */ #define CXLFLASH_NUM_VLUNS 512 diff --git a/drivers/scsi/cxlflash/superpipe.h b/drivers/scsi/cxlflash/superpipe.h index 9e62ff304e4b..690ce9c652b2 100644 --- a/drivers/scsi/cxlflash/superpipe.h +++ b/drivers/scsi/cxlflash/superpipe.h @@ -59,7 +59,7 @@ struct glun_info { /* Local (per-adapter) lun_info structure */ struct llun_info { - u64 lun_id[CXLFLASH_NUM_FC_PORTS]; /* from REPORT_LUNS */ + u64 lun_id[MAX_FC_PORTS]; /* from REPORT_LUNS */ u32 lun_index; /* Index in the LUN table */ u32 host_no; /* host_no from Scsi_host */ u32 port_sel; /* What port to use for this LUN */ -- cgit v1.2.3 From 8fa4f1770d56af6f0a5a862f1fd298a4eeea94f3 Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 12 Apr 2017 14:14:05 -0500 Subject: scsi: cxlflash: Remove port configuration assumptions At present, the cxlflash driver only supports hardware with two FC ports. The code was initially designed with this assumption and is dependent on having two FC ports - adding more ports will break logic within the driver. To mitigate this issue, remove the existing port assumptions and transition the code to support more than two ports. As a side effect, clarify the interpretation of the DK_CXLFLASH_ALL_PORTS_ACTIVE flag. Signed-off-by: Matthew R. Ochs Signed-off-by: Uma Krishnan Signed-off-by: Martin K. Petersen --- Documentation/powerpc/cxlflash.txt | 5 +++ drivers/scsi/cxlflash/common.h | 4 ++ drivers/scsi/cxlflash/lunmgt.c | 4 +- drivers/scsi/cxlflash/main.c | 13 +++--- drivers/scsi/cxlflash/sislite.h | 2 +- drivers/scsi/cxlflash/superpipe.c | 2 +- drivers/scsi/cxlflash/superpipe.h | 3 -- drivers/scsi/cxlflash/vlun.c | 89 +++++++++++++++++++++++++------------- 8 files changed, 77 insertions(+), 45 deletions(-) (limited to 'drivers') diff --git a/Documentation/powerpc/cxlflash.txt b/Documentation/powerpc/cxlflash.txt index 6d9a2ed32cad..66b4496d6619 100644 --- a/Documentation/powerpc/cxlflash.txt +++ b/Documentation/powerpc/cxlflash.txt @@ -239,6 +239,11 @@ DK_CXLFLASH_USER_VIRTUAL resource handle that is provided is already referencing provisioned storage. This is reflected by the last LBA being a non-zero value. + When a LUN is accessible from more than one port, this ioctl will + return with the DK_CXLFLASH_ALL_PORTS_ACTIVE return flag set. This + provides the user with a hint that I/O can be retried in the event + of an I/O error as the LUN can be reached over multiple paths. + DK_CXLFLASH_VLUN_RESIZE ----------------------- This ioctl is responsible for resizing a previously created virtual diff --git a/drivers/scsi/cxlflash/common.h b/drivers/scsi/cxlflash/common.h index 6a04867a0eec..ee23e81994c4 100644 --- a/drivers/scsi/cxlflash/common.h +++ b/drivers/scsi/cxlflash/common.h @@ -29,6 +29,10 @@ extern const struct file_operations cxlflash_cxl_fops; #define NUM_FC_PORTS CXLFLASH_NUM_FC_PORTS /* ports per AFU */ #define MAX_FC_PORTS CXLFLASH_MAX_FC_PORTS /* ports per AFU */ +#define CHAN2PORTMASK(_x) (1 << (_x)) /* channel to port mask */ +#define PORTMASK2CHAN(_x) (ilog2((_x))) /* port mask to channel */ +#define PORTNUM2CHAN(_x) ((_x) - 1) /* port number to channel */ + #define CXLFLASH_BLOCK_SIZE 4096 /* 4K blocks */ #define CXLFLASH_MAX_XFER_SIZE 16777216 /* 16MB transfer */ #define CXLFLASH_MAX_SECTORS (CXLFLASH_MAX_XFER_SIZE/512) /* SCSI wants diff --git a/drivers/scsi/cxlflash/lunmgt.c b/drivers/scsi/cxlflash/lunmgt.c index 0efed177cc8b..4d232e271af6 100644 --- a/drivers/scsi/cxlflash/lunmgt.c +++ b/drivers/scsi/cxlflash/lunmgt.c @@ -252,7 +252,7 @@ int cxlflash_manage_lun(struct scsi_device *sdev, * in unpacked, AFU-friendly format, and hang LUN reference in * the sdev. */ - lli->port_sel |= CHAN2PORT(chan); + lli->port_sel |= CHAN2PORTMASK(chan); lli->lun_id[chan] = lun_to_lunid(sdev->lun); sdev->hostdata = lli; } else if (flags & DK_CXLFLASH_MANAGE_LUN_DISABLE_SUPERPIPE) { @@ -264,7 +264,7 @@ int cxlflash_manage_lun(struct scsi_device *sdev, * tracking when no more references exist. */ sdev->hostdata = NULL; - lli->port_sel &= ~CHAN2PORT(chan); + lli->port_sel &= ~CHAN2PORTMASK(chan); if (lli->port_sel == 0U) lli->in_table = false; } diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index 3f9c8690af0d..04e1a8effa76 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -365,7 +365,6 @@ static int wait_resp(struct afu *afu, struct afu_cmd *cmd) */ static int send_tmf(struct afu *afu, struct scsi_cmnd *scp, u64 tmfcmd) { - u32 port_sel = scp->device->channel + 1; struct cxlflash_cfg *cfg = shost_priv(scp->device->host); struct afu_cmd *cmd = sc_to_afucz(scp); struct device *dev = &cfg->dev->dev; @@ -388,7 +387,7 @@ static int send_tmf(struct afu *afu, struct scsi_cmnd *scp, u64 tmfcmd) cmd->rcb.ctx_id = afu->ctx_hndl; cmd->rcb.msi = SISL_MSI_RRQ_UPDATED; - cmd->rcb.port_sel = port_sel; + cmd->rcb.port_sel = CHAN2PORTMASK(scp->device->channel); cmd->rcb.lun_id = lun_to_lunid(scp->device->lun); cmd->rcb.req_flags = (SISL_REQ_FLAGS_PORT_LUN_ID | SISL_REQ_FLAGS_SUP_UNDERRUN | @@ -444,7 +443,6 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp) struct device *dev = &cfg->dev->dev; struct afu_cmd *cmd = sc_to_afucz(scp); struct scatterlist *sg = scsi_sglist(scp); - u32 port_sel = scp->device->channel + 1; u16 req_flags = SISL_REQ_FLAGS_SUP_UNDERRUN; ulong lock_flags; int nseg = 0; @@ -503,7 +501,7 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp) cmd->rcb.ctx_id = afu->ctx_hndl; cmd->rcb.msi = SISL_MSI_RRQ_UPDATED; - cmd->rcb.port_sel = port_sel; + cmd->rcb.port_sel = CHAN2PORTMASK(scp->device->channel); cmd->rcb.lun_id = lun_to_lunid(scp->device->lun); if (scp->sc_data_direction == DMA_TO_DEVICE) @@ -1558,7 +1556,8 @@ static int init_global(struct cxlflash_cfg *cfg) writeq_be(PORT0, &afu->afu_map->global.regs.afu_port_sel); num_ports = 0; } else { - writeq_be(BOTH_PORTS, &afu->afu_map->global.regs.afu_port_sel); + writeq_be(PORT_MASK(cfg->num_fc_ports), + &afu->afu_map->global.regs.afu_port_sel); num_ports = cfg->num_fc_ports; } @@ -2190,7 +2189,7 @@ static ssize_t lun_mode_store(struct device *dev, if (afu->internal_lun) shost->max_channel = 0; else - shost->max_channel = cfg->num_fc_ports - 1; + shost->max_channel = PORTNUM2CHAN(cfg->num_fc_ports); afu_reset(cfg); scsi_scan_host(cfg->host); @@ -2529,7 +2528,7 @@ static int cxlflash_probe(struct pci_dev *pdev, host->max_id = CXLFLASH_MAX_NUM_TARGETS_PER_BUS; host->max_lun = CXLFLASH_MAX_NUM_LUNS_PER_TARGET; - host->max_channel = NUM_FC_PORTS - 1; + host->max_channel = PORTNUM2CHAN(NUM_FC_PORTS); host->unique_id = host->host_no; host->max_cmd_len = CXLFLASH_MAX_CDB_LEN; diff --git a/drivers/scsi/cxlflash/sislite.h b/drivers/scsi/cxlflash/sislite.h index 0db4bc1f4e23..f26f41be5efb 100644 --- a/drivers/scsi/cxlflash/sislite.h +++ b/drivers/scsi/cxlflash/sislite.h @@ -479,7 +479,7 @@ struct sisl_rht_entry_f1 { #define PORT0 0x01U #define PORT1 0x02U -#define BOTH_PORTS (PORT0 | PORT1) +#define PORT_MASK(_n) ((1 << (_n)) - 1) /* AFU Sync Mode byte */ #define AFU_LW_SYNC 0x0U diff --git a/drivers/scsi/cxlflash/superpipe.c b/drivers/scsi/cxlflash/superpipe.c index b46fd2f45628..f3997bed88f4 100644 --- a/drivers/scsi/cxlflash/superpipe.c +++ b/drivers/scsi/cxlflash/superpipe.c @@ -1933,7 +1933,7 @@ static int cxlflash_disk_direct_open(struct scsi_device *sdev, void *arg) u64 lun_size = 0; u64 last_lba = 0; u64 rsrc_handle = -1; - u32 port = CHAN2PORT(sdev->channel); + u32 port = CHAN2PORTMASK(sdev->channel); int rc = 0; diff --git a/drivers/scsi/cxlflash/superpipe.h b/drivers/scsi/cxlflash/superpipe.h index 690ce9c652b2..8269ff854bbe 100644 --- a/drivers/scsi/cxlflash/superpipe.h +++ b/drivers/scsi/cxlflash/superpipe.h @@ -33,9 +33,6 @@ extern struct cxlflash_global global; #define MAX_SECTOR_UNIT 512 /* max_sector is in 512 byte multiples */ -#define CHAN2PORT(_x) ((_x) + 1) -#define PORT2CHAN(_x) ((_x) - 1) - enum lun_mode { MODE_NONE = 0, MODE_VIRTUAL, diff --git a/drivers/scsi/cxlflash/vlun.c b/drivers/scsi/cxlflash/vlun.c index 7aa06ef229fd..067605b80fcd 100644 --- a/drivers/scsi/cxlflash/vlun.c +++ b/drivers/scsi/cxlflash/vlun.c @@ -819,8 +819,8 @@ int cxlflash_vlun_resize(struct scsi_device *sdev, void cxlflash_restore_luntable(struct cxlflash_cfg *cfg) { struct llun_info *lli, *temp; - u32 chan; u32 lind; + int k; struct afu *afu = cfg->afu; struct device *dev = &cfg->dev->dev; struct sisl_global_map __iomem *agm = &afu->afu_map->global; @@ -832,33 +832,41 @@ void cxlflash_restore_luntable(struct cxlflash_cfg *cfg) continue; lind = lli->lun_index; + dev_dbg(dev, "%s: Virtual LUNs on slot %d:\n", __func__, lind); - if (lli->port_sel == BOTH_PORTS) { - writeq_be(lli->lun_id[0], &agm->fc_port[0][lind]); - writeq_be(lli->lun_id[1], &agm->fc_port[1][lind]); - dev_dbg(dev, "%s: Virtual LUN on slot %d id0=%llx " - "id1=%llx\n", __func__, lind, - lli->lun_id[0], lli->lun_id[1]); - } else { - chan = PORT2CHAN(lli->port_sel); - writeq_be(lli->lun_id[chan], &agm->fc_port[chan][lind]); - dev_dbg(dev, "%s: Virtual LUN on slot %d chan=%d " - "id=%llx\n", __func__, lind, chan, - lli->lun_id[chan]); - } + for (k = 0; k < cfg->num_fc_ports; k++) + if (lli->port_sel & (1 << k)) { + writeq_be(lli->lun_id[k], + &agm->fc_port[k][lind]); + dev_dbg(dev, "\t%d=%llx\n", k, lli->lun_id[k]); + } } mutex_unlock(&global.mutex); } +/** + * get_num_ports() - compute number of ports from port selection mask + * @psm: Port selection mask. + * + * Return: Population count of port selection mask + */ +static inline u8 get_num_ports(u32 psm) +{ + static const u8 bits[16] = { 0, 1, 1, 2, 1, 2, 2, 3, + 1, 2, 2, 3, 2, 3, 3, 4 }; + + return bits[psm & 0xf]; +} + /** * init_luntable() - write an entry in the LUN table * @cfg: Internal structure associated with the host. * @lli: Per adapter LUN information structure. * - * On successful return, a LUN table entry is created. - * At the top for LUNs visible on both ports. - * At the bottom for LUNs visible only on one port. + * On successful return, a LUN table entry is created: + * - at the top for LUNs visible on multiple ports. + * - at the bottom for LUNs visible only on one port. * * Return: 0 on success, -errno on failure */ @@ -866,7 +874,9 @@ static int init_luntable(struct cxlflash_cfg *cfg, struct llun_info *lli) { u32 chan; u32 lind; + u32 nports; int rc = 0; + int k; struct afu *afu = cfg->afu; struct device *dev = &cfg->dev->dev; struct sisl_global_map __iomem *agm = &afu->afu_map->global; @@ -876,29 +886,46 @@ static int init_luntable(struct cxlflash_cfg *cfg, struct llun_info *lli) if (lli->in_table) goto out; - if (lli->port_sel == BOTH_PORTS) { + nports = get_num_ports(lli->port_sel); + if (nports == 0 || nports > cfg->num_fc_ports) { + WARN(1, "Unsupported port configuration nports=%u", nports); + rc = -EIO; + goto out; + } + + if (nports > 1) { /* - * If this LUN is visible from both ports, we will put + * When LUN is visible from multiple ports, we will put * it in the top half of the LUN table. */ - if ((cfg->promote_lun_index == cfg->last_lun_index[0]) || - (cfg->promote_lun_index == cfg->last_lun_index[1])) { - rc = -ENOSPC; - goto out; + for (k = 0; k < cfg->num_fc_ports; k++) { + if (!(lli->port_sel & (1 << k))) + continue; + + if (cfg->promote_lun_index == cfg->last_lun_index[k]) { + rc = -ENOSPC; + goto out; + } } lind = lli->lun_index = cfg->promote_lun_index; - writeq_be(lli->lun_id[0], &agm->fc_port[0][lind]); - writeq_be(lli->lun_id[1], &agm->fc_port[1][lind]); + dev_dbg(dev, "%s: Virtual LUNs on slot %d:\n", __func__, lind); + + for (k = 0; k < cfg->num_fc_ports; k++) { + if (!(lli->port_sel & (1 << k))) + continue; + + writeq_be(lli->lun_id[k], &agm->fc_port[k][lind]); + dev_dbg(dev, "\t%d=%llx\n", k, lli->lun_id[k]); + } + cfg->promote_lun_index++; - dev_dbg(dev, "%s: Virtual LUN on slot %d id0=%llx id1=%llx\n", - __func__, lind, lli->lun_id[0], lli->lun_id[1]); } else { /* - * If this LUN is visible only from one port, we will put + * When LUN is visible only from one port, we will put * it in the bottom half of the LUN table. */ - chan = PORT2CHAN(lli->port_sel); + chan = PORTMASK2CHAN(lli->port_sel); if (cfg->promote_lun_index == cfg->last_lun_index[chan]) { rc = -ENOSPC; goto out; @@ -907,7 +934,7 @@ static int init_luntable(struct cxlflash_cfg *cfg, struct llun_info *lli) lind = lli->lun_index = cfg->last_lun_index[chan]; writeq_be(lli->lun_id[chan], &agm->fc_port[chan][lind]); cfg->last_lun_index[chan]--; - dev_dbg(dev, "%s: Virtual LUN on slot %d chan=%d id=%llx\n", + dev_dbg(dev, "%s: Virtual LUNs on slot %d:\n\t%d=%llx\n", __func__, lind, chan, lli->lun_id[chan]); } @@ -1016,7 +1043,7 @@ int cxlflash_disk_virtual_open(struct scsi_device *sdev, void *arg) virt->last_lba = last_lba; virt->rsrc_handle = rsrc_handle; - if (lli->port_sel == BOTH_PORTS) + if (get_num_ports(lli->port_sel) > 1) virt->hdr.return_flags |= DK_CXLFLASH_ALL_PORTS_ACTIVE; out: if (likely(ctxi)) -- cgit v1.2.3 From 0aa14887c60c27e3385295ee85f5ac079ae2ffb5 Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 12 Apr 2017 14:14:17 -0500 Subject: scsi: cxlflash: Hide FC internals behind common access routine As staging to support FC-related updates to the SISlite specification, introduce helper routines to obtain references to FC resources that exist within the global map. This will allow changes to the underlying global map structure without impacting existing code paths. Signed-off-by: Matthew R. Ochs Signed-off-by: Uma Krishnan Signed-off-by: Martin K. Petersen --- drivers/scsi/cxlflash/common.h | 14 ++++++++ drivers/scsi/cxlflash/main.c | 72 +++++++++++++++++++++++------------------- drivers/scsi/cxlflash/vlun.c | 16 +++++----- 3 files changed, 61 insertions(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/cxlflash/common.h b/drivers/scsi/cxlflash/common.h index ee23e81994c4..e6a7c975c0dc 100644 --- a/drivers/scsi/cxlflash/common.h +++ b/drivers/scsi/cxlflash/common.h @@ -240,6 +240,20 @@ static inline u64 lun_to_lunid(u64 lun) return be64_to_cpu(lun_id); } +static inline __be64 __iomem *get_fc_port_regs(struct cxlflash_cfg *cfg, int i) +{ + struct afu *afu = cfg->afu; + + return &afu->afu_map->global.fc_regs[i][0]; +} + +static inline __be64 __iomem *get_fc_port_luns(struct cxlflash_cfg *cfg, int i) +{ + struct afu *afu = cfg->afu; + + return &afu->afu_map->global.fc_port[i][0]; +} + int cxlflash_afu_sync(struct afu *, ctx_hndl_t, res_hndl_t, u8); void cxlflash_list_init(void); void cxlflash_term_global_luns(void); diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index 04e1a8effa76..e198605c3ded 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -670,8 +670,8 @@ static void notify_shutdown(struct cxlflash_cfg *cfg, bool wait) { struct afu *afu = cfg->afu; struct device *dev = &cfg->dev->dev; - struct sisl_global_map __iomem *global; struct dev_dependent_vals *ddv; + __be64 __iomem *fc_port_regs; u64 reg, status; int i, retry_cnt = 0; @@ -684,13 +684,13 @@ static void notify_shutdown(struct cxlflash_cfg *cfg, bool wait) return; } - global = &afu->afu_map->global; - /* Notify AFU */ for (i = 0; i < cfg->num_fc_ports; i++) { - reg = readq_be(&global->fc_regs[i][FC_CONFIG2 / 8]); + fc_port_regs = get_fc_port_regs(cfg, i); + + reg = readq_be(&fc_port_regs[FC_CONFIG2 / 8]); reg |= SISL_FC_SHUTDOWN_NORMAL; - writeq_be(reg, &global->fc_regs[i][FC_CONFIG2 / 8]); + writeq_be(reg, &fc_port_regs[FC_CONFIG2 / 8]); } if (!wait) @@ -698,9 +698,11 @@ static void notify_shutdown(struct cxlflash_cfg *cfg, bool wait) /* Wait up to 1.5 seconds for shutdown processing to complete */ for (i = 0; i < cfg->num_fc_ports; i++) { + fc_port_regs = get_fc_port_regs(cfg, i); retry_cnt = 0; + while (true) { - status = readq_be(&global->fc_regs[i][FC_STATUS / 8]); + status = readq_be(&fc_port_regs[FC_STATUS / 8]); if (status & SISL_STATUS_SHUTDOWN_COMPLETE) break; if (++retry_cnt >= MC_RETRY_CNT) { @@ -1071,6 +1073,7 @@ static const struct asyc_intr_info *find_ainfo(u64 status) static void afu_err_intr_init(struct afu *afu) { struct cxlflash_cfg *cfg = afu->parent; + __be64 __iomem *fc_port_regs; int i; u64 reg; @@ -1099,17 +1102,19 @@ static void afu_err_intr_init(struct afu *afu) writeq_be(-1ULL, &afu->afu_map->global.regs.aintr_clear); /* Clear/Set internal lun bits */ - reg = readq_be(&afu->afu_map->global.fc_regs[0][FC_CONFIG2 / 8]); + fc_port_regs = get_fc_port_regs(cfg, 0); + reg = readq_be(&fc_port_regs[FC_CONFIG2 / 8]); reg &= SISL_FC_INTERNAL_MASK; if (afu->internal_lun) reg |= ((u64)(afu->internal_lun - 1) << SISL_FC_INTERNAL_SHIFT); - writeq_be(reg, &afu->afu_map->global.fc_regs[0][FC_CONFIG2 / 8]); + writeq_be(reg, &fc_port_regs[FC_CONFIG2 / 8]); /* now clear FC errors */ for (i = 0; i < cfg->num_fc_ports; i++) { - writeq_be(0xFFFFFFFFU, - &afu->afu_map->global.fc_regs[i][FC_ERROR / 8]); - writeq_be(0, &afu->afu_map->global.fc_regs[i][FC_ERRCAP / 8]); + fc_port_regs = get_fc_port_regs(cfg, i); + + writeq_be(0xFFFFFFFFU, &fc_port_regs[FC_ERROR / 8]); + writeq_be(0, &fc_port_regs[FC_ERRCAP / 8]); } /* sync interrupts for master's IOARRIN write */ @@ -1306,6 +1311,7 @@ static irqreturn_t cxlflash_async_err_irq(int irq, void *data) u64 reg_unmasked; const struct asyc_intr_info *info; struct sisl_global_map __iomem *global = &afu->afu_map->global; + __be64 __iomem *fc_port_regs; u64 reg; u8 port; int i; @@ -1329,10 +1335,11 @@ static irqreturn_t cxlflash_async_err_irq(int irq, void *data) continue; port = info->port; + fc_port_regs = get_fc_port_regs(cfg, port); dev_err(dev, "%s: FC Port %d -> %s, fc_status=%016llx\n", __func__, port, info->desc, - readq_be(&global->fc_regs[port][FC_STATUS / 8])); + readq_be(&fc_port_regs[FC_STATUS / 8])); /* * Do link reset first, some OTHER errors will set FC_ERROR @@ -1347,7 +1354,7 @@ static irqreturn_t cxlflash_async_err_irq(int irq, void *data) } if (info->action & CLR_FC_ERROR) { - reg = readq_be(&global->fc_regs[port][FC_ERROR / 8]); + reg = readq_be(&fc_port_regs[FC_ERROR / 8]); /* * Since all errors are unmasked, FC_ERROR and FC_ERRCAP @@ -1357,8 +1364,8 @@ static irqreturn_t cxlflash_async_err_irq(int irq, void *data) dev_err(dev, "%s: fc %d: clearing fc_error=%016llx\n", __func__, port, reg); - writeq_be(reg, &global->fc_regs[port][FC_ERROR / 8]); - writeq_be(0, &global->fc_regs[port][FC_ERRCAP / 8]); + writeq_be(reg, &fc_port_regs[FC_ERROR / 8]); + writeq_be(0, &fc_port_regs[FC_ERRCAP / 8]); } if (info->action & SCAN_HOST) { @@ -1521,6 +1528,7 @@ static int init_global(struct cxlflash_cfg *cfg) { struct afu *afu = cfg->afu; struct device *dev = &cfg->dev->dev; + __be64 __iomem *fc_port_regs; u64 wwpn[MAX_FC_PORTS]; /* wwpn of AFU ports */ int i = 0, num_ports = 0; int rc = 0; @@ -1562,19 +1570,17 @@ static int init_global(struct cxlflash_cfg *cfg) } for (i = 0; i < num_ports; i++) { + fc_port_regs = get_fc_port_regs(cfg, i); + /* Unmask all errors (but they are still masked at AFU) */ - writeq_be(0, &afu->afu_map->global.fc_regs[i][FC_ERRMSK / 8]); + writeq_be(0, &fc_port_regs[FC_ERRMSK / 8]); /* Clear CRC error cnt & set a threshold */ - (void)readq_be(&afu->afu_map->global. - fc_regs[i][FC_CNT_CRCERR / 8]); - writeq_be(MC_CRC_THRESH, &afu->afu_map->global.fc_regs[i] - [FC_CRC_THRESH / 8]); + (void)readq_be(&fc_port_regs[FC_CNT_CRCERR / 8]); + writeq_be(MC_CRC_THRESH, &fc_port_regs[FC_CRC_THRESH / 8]); /* Set WWPNs. If already programmed, wwpn[i] is 0 */ if (wwpn[i] != 0) - afu_set_wwpn(afu, i, - &afu->afu_map->global.fc_regs[i][0], - wwpn[i]); + afu_set_wwpn(afu, i, &fc_port_regs[0], wwpn[i]); /* Programming WWPN back to back causes additional * offline/online transitions and a PLOGI */ @@ -2067,10 +2073,9 @@ static ssize_t cxlflash_show_port_status(u32 port, char *buf) { struct device *dev = &cfg->dev->dev; - struct afu *afu = cfg->afu; char *disp_status; u64 status; - __be64 __iomem *fc_regs; + __be64 __iomem *fc_port_regs; WARN_ON(port >= MAX_FC_PORTS); @@ -2080,8 +2085,8 @@ static ssize_t cxlflash_show_port_status(u32 port, return -EINVAL; } - fc_regs = &afu->afu_map->global.fc_regs[port][0]; - status = readq_be(&fc_regs[FC_MTIP_STATUS / 8]); + fc_port_regs = get_fc_port_regs(cfg, port); + status = readq_be(&fc_port_regs[FC_MTIP_STATUS / 8]); status &= FC_MTIP_STATUS_MASK; if (status == FC_MTIP_STATUS_ONLINE) @@ -2225,10 +2230,9 @@ static ssize_t cxlflash_show_port_lun_table(u32 port, char *buf) { struct device *dev = &cfg->dev->dev; - struct afu *afu = cfg->afu; + __be64 __iomem *fc_port_luns; int i; ssize_t bytes = 0; - __be64 __iomem *fc_port; WARN_ON(port >= MAX_FC_PORTS); @@ -2238,11 +2242,12 @@ static ssize_t cxlflash_show_port_lun_table(u32 port, return -EINVAL; } - fc_port = &afu->afu_map->global.fc_port[port][0]; + fc_port_luns = get_fc_port_luns(cfg, port); for (i = 0; i < CXLFLASH_NUM_VLUNS; i++) bytes += scnprintf(buf + bytes, PAGE_SIZE - bytes, - "%03d: %016llx\n", i, readq_be(&fc_port[i])); + "%03d: %016llx\n", + i, readq_be(&fc_port_luns[i])); return bytes; } @@ -2462,6 +2467,7 @@ static void cxlflash_worker_thread(struct work_struct *work) work_q); struct afu *afu = cfg->afu; struct device *dev = &cfg->dev->dev; + __be64 __iomem *fc_port_regs; int port; ulong lock_flags; @@ -2482,8 +2488,8 @@ static void cxlflash_worker_thread(struct work_struct *work) lock_flags); /* The reset can block... */ - afu_link_reset(afu, port, - &afu->afu_map->global.fc_regs[port][0]); + fc_port_regs = get_fc_port_regs(cfg, port); + afu_link_reset(afu, port, fc_port_regs); spin_lock_irqsave(cfg->host->host_lock, lock_flags); } diff --git a/drivers/scsi/cxlflash/vlun.c b/drivers/scsi/cxlflash/vlun.c index 067605b80fcd..90b5c19f81f0 100644 --- a/drivers/scsi/cxlflash/vlun.c +++ b/drivers/scsi/cxlflash/vlun.c @@ -821,9 +821,8 @@ void cxlflash_restore_luntable(struct cxlflash_cfg *cfg) struct llun_info *lli, *temp; u32 lind; int k; - struct afu *afu = cfg->afu; struct device *dev = &cfg->dev->dev; - struct sisl_global_map __iomem *agm = &afu->afu_map->global; + __be64 __iomem *fc_port_luns; mutex_lock(&global.mutex); @@ -836,8 +835,8 @@ void cxlflash_restore_luntable(struct cxlflash_cfg *cfg) for (k = 0; k < cfg->num_fc_ports; k++) if (lli->port_sel & (1 << k)) { - writeq_be(lli->lun_id[k], - &agm->fc_port[k][lind]); + fc_port_luns = get_fc_port_luns(cfg, k); + writeq_be(lli->lun_id[k], &fc_port_luns[lind]); dev_dbg(dev, "\t%d=%llx\n", k, lli->lun_id[k]); } } @@ -877,9 +876,8 @@ static int init_luntable(struct cxlflash_cfg *cfg, struct llun_info *lli) u32 nports; int rc = 0; int k; - struct afu *afu = cfg->afu; struct device *dev = &cfg->dev->dev; - struct sisl_global_map __iomem *agm = &afu->afu_map->global; + __be64 __iomem *fc_port_luns; mutex_lock(&global.mutex); @@ -915,7 +913,8 @@ static int init_luntable(struct cxlflash_cfg *cfg, struct llun_info *lli) if (!(lli->port_sel & (1 << k))) continue; - writeq_be(lli->lun_id[k], &agm->fc_port[k][lind]); + fc_port_luns = get_fc_port_luns(cfg, k); + writeq_be(lli->lun_id[k], &fc_port_luns[lind]); dev_dbg(dev, "\t%d=%llx\n", k, lli->lun_id[k]); } @@ -932,7 +931,8 @@ static int init_luntable(struct cxlflash_cfg *cfg, struct llun_info *lli) } lind = lli->lun_index = cfg->last_lun_index[chan]; - writeq_be(lli->lun_id[chan], &agm->fc_port[chan][lind]); + fc_port_luns = get_fc_port_luns(cfg, chan); + writeq_be(lli->lun_id[chan], &fc_port_luns[lind]); cfg->last_lun_index[chan]--; dev_dbg(dev, "%s: Virtual LUNs on slot %d:\n\t%d=%llx\n", __func__, lind, chan, lli->lun_id[chan]); -- cgit v1.2.3 From 565180723294b06b3e60030033847277b9d6d4bb Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 12 Apr 2017 14:14:28 -0500 Subject: scsi: cxlflash: SISlite updates to support 4 ports Update the SISlite header to support 4 ports as outlined in the SISlite specification. Address fallout from structure renames and refreshed organization throughout the driver. Determine the number of ports supported by a card from the global port selection mask register reset value. Signed-off-by: Matthew R. Ochs Signed-off-by: Uma Krishnan Signed-off-by: Martin K. Petersen --- drivers/scsi/cxlflash/common.h | 25 ++++++++--- drivers/scsi/cxlflash/main.c | 77 +++++++++++++++++++++++++-------- drivers/scsi/cxlflash/sislite.h | 96 ++++++++++++++++++++++++++++------------- 3 files changed, 141 insertions(+), 57 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/cxlflash/common.h b/drivers/scsi/cxlflash/common.h index e6a7c975c0dc..28bb716e78fe 100644 --- a/drivers/scsi/cxlflash/common.h +++ b/drivers/scsi/cxlflash/common.h @@ -26,8 +26,11 @@ extern const struct file_operations cxlflash_cxl_fops; #define MAX_CONTEXT CXLFLASH_MAX_CONTEXT /* num contexts per afu */ -#define NUM_FC_PORTS CXLFLASH_NUM_FC_PORTS /* ports per AFU */ -#define MAX_FC_PORTS CXLFLASH_MAX_FC_PORTS /* ports per AFU */ +#define MAX_FC_PORTS CXLFLASH_MAX_FC_PORTS /* max ports per AFU */ +#define LEGACY_FC_PORTS 2 /* legacy ports per AFU */ + +#define CHAN2PORTBANK(_x) ((_x) >> ilog2(CXLFLASH_NUM_FC_PORTS_PER_BANK)) +#define CHAN2BANKPORT(_x) ((_x) & (CXLFLASH_NUM_FC_PORTS_PER_BANK - 1)) #define CHAN2PORTMASK(_x) (1 << (_x)) /* channel to port mask */ #define PORTMASK2CHAN(_x) (ilog2((_x))) /* port mask to channel */ @@ -67,7 +70,7 @@ extern const struct file_operations cxlflash_cxl_fops; static inline void check_sizes(void) { - BUILD_BUG_ON_NOT_POWER_OF_2(CXLFLASH_NUM_CMDS); + BUILD_BUG_ON_NOT_POWER_OF_2(CXLFLASH_NUM_FC_PORTS_PER_BANK); } /* AFU defines a fixed size of 4K for command buffers (borrow 4K page define) */ @@ -240,18 +243,26 @@ static inline u64 lun_to_lunid(u64 lun) return be64_to_cpu(lun_id); } -static inline __be64 __iomem *get_fc_port_regs(struct cxlflash_cfg *cfg, int i) +static inline struct fc_port_bank __iomem *get_fc_port_bank( + struct cxlflash_cfg *cfg, int i) { struct afu *afu = cfg->afu; - return &afu->afu_map->global.fc_regs[i][0]; + return &afu->afu_map->global.bank[CHAN2PORTBANK(i)]; +} + +static inline __be64 __iomem *get_fc_port_regs(struct cxlflash_cfg *cfg, int i) +{ + struct fc_port_bank __iomem *fcpb = get_fc_port_bank(cfg, i); + + return &fcpb->fc_port_regs[CHAN2BANKPORT(i)][0]; } static inline __be64 __iomem *get_fc_port_luns(struct cxlflash_cfg *cfg, int i) { - struct afu *afu = cfg->afu; + struct fc_port_bank __iomem *fcpb = get_fc_port_bank(cfg, i); - return &afu->afu_map->global.fc_port[i][0]; + return &fcpb->fc_port_luns[CHAN2BANKPORT(i)][0]; } int cxlflash_afu_sync(struct afu *, ctx_hndl_t, res_hndl_t, u8); diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index e198605c3ded..64ad76b6b672 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -1028,25 +1028,29 @@ static void afu_link_reset(struct afu *afu, int port, __be64 __iomem *fc_regs) /* * Asynchronous interrupt information table + * + * NOTE: The checkpatch script considers the BUILD_SISL_ASTATUS_FC_PORT macro + * as complex and complains because it is not wrapped with parentheses/braces. */ +#define ASTATUS_FC(_a, _b, _c, _d) \ + { SISL_ASTATUS_FC##_a##_##_b, _c, _a, (_d) } + +#define BUILD_SISL_ASTATUS_FC_PORT(_a) \ + ASTATUS_FC(_a, OTHER, "other error", CLR_FC_ERROR | LINK_RESET), \ + ASTATUS_FC(_a, LOGO, "target initiated LOGO", 0), \ + ASTATUS_FC(_a, CRC_T, "CRC threshold exceeded", LINK_RESET), \ + ASTATUS_FC(_a, LOGI_R, "login timed out, retrying", LINK_RESET), \ + ASTATUS_FC(_a, LOGI_F, "login failed", CLR_FC_ERROR), \ + ASTATUS_FC(_a, LOGI_S, "login succeeded", SCAN_HOST), \ + ASTATUS_FC(_a, LINK_DN, "link down", 0), \ + ASTATUS_FC(_a, LINK_UP, "link up", 0) + static const struct asyc_intr_info ainfo[] = { - {SISL_ASTATUS_FC0_OTHER, "other error", 0, CLR_FC_ERROR | LINK_RESET}, - {SISL_ASTATUS_FC0_LOGO, "target initiated LOGO", 0, 0}, - {SISL_ASTATUS_FC0_CRC_T, "CRC threshold exceeded", 0, LINK_RESET}, - {SISL_ASTATUS_FC0_LOGI_R, "login timed out, retrying", 0, LINK_RESET}, - {SISL_ASTATUS_FC0_LOGI_F, "login failed", 0, CLR_FC_ERROR}, - {SISL_ASTATUS_FC0_LOGI_S, "login succeeded", 0, SCAN_HOST}, - {SISL_ASTATUS_FC0_LINK_DN, "link down", 0, 0}, - {SISL_ASTATUS_FC0_LINK_UP, "link up", 0, 0}, - {SISL_ASTATUS_FC1_OTHER, "other error", 1, CLR_FC_ERROR | LINK_RESET}, - {SISL_ASTATUS_FC1_LOGO, "target initiated LOGO", 1, 0}, - {SISL_ASTATUS_FC1_CRC_T, "CRC threshold exceeded", 1, LINK_RESET}, - {SISL_ASTATUS_FC1_LOGI_R, "login timed out, retrying", 1, LINK_RESET}, - {SISL_ASTATUS_FC1_LOGI_F, "login failed", 1, CLR_FC_ERROR}, - {SISL_ASTATUS_FC1_LOGI_S, "login succeeded", 1, SCAN_HOST}, - {SISL_ASTATUS_FC1_LINK_DN, "link down", 1, 0}, - {SISL_ASTATUS_FC1_LINK_UP, "link up", 1, 0}, - {0x0, "", 0, 0} /* terminator */ + BUILD_SISL_ASTATUS_FC_PORT(2), + BUILD_SISL_ASTATUS_FC_PORT(3), + BUILD_SISL_ASTATUS_FC_PORT(0), + BUILD_SISL_ASTATUS_FC_PORT(1), + { 0x0, "", 0, 0 } }; /** @@ -1059,6 +1063,8 @@ static const struct asyc_intr_info *find_ainfo(u64 status) { const struct asyc_intr_info *info; + BUILD_BUG_ON(ainfo[ARRAY_SIZE(ainfo) - 1].status != 0); + for (info = &ainfo[0]; info->status; info++) if (info->status == status) return info; @@ -1746,6 +1752,39 @@ out: goto ret; } +/** + * get_num_afu_ports() - determines and configures the number of AFU ports + * @cfg: Internal structure associated with the host. + * + * This routine determines the number of AFU ports by converting the global + * port selection mask. The converted value is only valid following an AFU + * reset (explicit or power-on). This routine must be invoked shortly after + * mapping as other routines are dependent on the number of ports during the + * initialization sequence. + * + * To support legacy AFUs that might not have reflected an initial global + * port mask (value read is 0), default to the number of ports originally + * supported by the cxlflash driver (2) before hardware with other port + * offerings was introduced. + */ +static void get_num_afu_ports(struct cxlflash_cfg *cfg) +{ + struct afu *afu = cfg->afu; + struct device *dev = &cfg->dev->dev; + u64 port_mask; + int num_fc_ports = LEGACY_FC_PORTS; + + port_mask = readq_be(&afu->afu_map->global.regs.afu_port_sel); + if (port_mask != 0ULL) + num_fc_ports = min(ilog2(port_mask) + 1, MAX_FC_PORTS); + + dev_dbg(dev, "%s: port_mask=%016llx num_fc_ports=%d\n", + __func__, port_mask, num_fc_ports); + + cfg->num_fc_ports = num_fc_ports; + cfg->host->max_channel = PORTNUM2CHAN(num_fc_ports); +} + /** * init_afu() - setup as master context and start AFU * @cfg: Internal structure associated with the host. @@ -1803,6 +1842,8 @@ static int init_afu(struct cxlflash_cfg *cfg) dev_dbg(dev, "%s: afu_ver=%s interface_ver=%016llx\n", __func__, afu->version, afu->interface_version); + get_num_afu_ports(cfg); + rc = start_afu(cfg); if (rc) { dev_err(dev, "%s: start_afu failed, rc=%d\n", __func__, rc); @@ -2534,7 +2575,6 @@ static int cxlflash_probe(struct pci_dev *pdev, host->max_id = CXLFLASH_MAX_NUM_TARGETS_PER_BUS; host->max_lun = CXLFLASH_MAX_NUM_LUNS_PER_TARGET; - host->max_channel = PORTNUM2CHAN(NUM_FC_PORTS); host->unique_id = host->host_no; host->max_cmd_len = CXLFLASH_MAX_CDB_LEN; @@ -2550,7 +2590,6 @@ static int cxlflash_probe(struct pci_dev *pdev, cfg->init_state = INIT_STATE_NONE; cfg->dev = pdev; - cfg->num_fc_ports = NUM_FC_PORTS; cfg->cxl_fops = cxlflash_cxl_fops; /* diff --git a/drivers/scsi/cxlflash/sislite.h b/drivers/scsi/cxlflash/sislite.h index f26f41be5efb..42d9c9ee3bce 100644 --- a/drivers/scsi/cxlflash/sislite.h +++ b/drivers/scsi/cxlflash/sislite.h @@ -292,28 +292,54 @@ struct sisl_ctrl_map { /* single copy global regs */ struct sisl_global_regs { __be64 aintr_status; - /* In cxlflash, each FC port/link gets a byte of status */ -#define SISL_ASTATUS_FC0_OTHER 0x8000ULL /* b48, other err, - FC_ERRCAP[31:20] */ -#define SISL_ASTATUS_FC0_LOGO 0x4000ULL /* b49, target sent FLOGI/PLOGI/LOGO - while logged in */ -#define SISL_ASTATUS_FC0_CRC_T 0x2000ULL /* b50, CRC threshold exceeded */ -#define SISL_ASTATUS_FC0_LOGI_R 0x1000ULL /* b51, login state machine timed out - and retrying */ -#define SISL_ASTATUS_FC0_LOGI_F 0x0800ULL /* b52, login failed, - FC_ERROR[19:0] */ -#define SISL_ASTATUS_FC0_LOGI_S 0x0400ULL /* b53, login succeeded */ -#define SISL_ASTATUS_FC0_LINK_DN 0x0200ULL /* b54, link online to offline */ -#define SISL_ASTATUS_FC0_LINK_UP 0x0100ULL /* b55, link offline to online */ - -#define SISL_ASTATUS_FC1_OTHER 0x0080ULL /* b56 */ -#define SISL_ASTATUS_FC1_LOGO 0x0040ULL /* b57 */ -#define SISL_ASTATUS_FC1_CRC_T 0x0020ULL /* b58 */ -#define SISL_ASTATUS_FC1_LOGI_R 0x0010ULL /* b59 */ -#define SISL_ASTATUS_FC1_LOGI_F 0x0008ULL /* b60 */ -#define SISL_ASTATUS_FC1_LOGI_S 0x0004ULL /* b61 */ -#define SISL_ASTATUS_FC1_LINK_DN 0x0002ULL /* b62 */ -#define SISL_ASTATUS_FC1_LINK_UP 0x0001ULL /* b63 */ + /* + * In cxlflash, FC port/link are arranged in port pairs, each + * gets a byte of status: + * + * *_OTHER: other err, FC_ERRCAP[31:20] + * *_LOGO: target sent FLOGI/PLOGI/LOGO while logged in + * *_CRC_T: CRC threshold exceeded + * *_LOGI_R: login state machine timed out and retrying + * *_LOGI_F: login failed, FC_ERROR[19:0] + * *_LOGI_S: login succeeded + * *_LINK_DN: link online to offline + * *_LINK_UP: link offline to online + */ +#define SISL_ASTATUS_FC2_OTHER 0x80000000ULL /* b32 */ +#define SISL_ASTATUS_FC2_LOGO 0x40000000ULL /* b33 */ +#define SISL_ASTATUS_FC2_CRC_T 0x20000000ULL /* b34 */ +#define SISL_ASTATUS_FC2_LOGI_R 0x10000000ULL /* b35 */ +#define SISL_ASTATUS_FC2_LOGI_F 0x08000000ULL /* b36 */ +#define SISL_ASTATUS_FC2_LOGI_S 0x04000000ULL /* b37 */ +#define SISL_ASTATUS_FC2_LINK_DN 0x02000000ULL /* b38 */ +#define SISL_ASTATUS_FC2_LINK_UP 0x01000000ULL /* b39 */ + +#define SISL_ASTATUS_FC3_OTHER 0x00800000ULL /* b40 */ +#define SISL_ASTATUS_FC3_LOGO 0x00400000ULL /* b41 */ +#define SISL_ASTATUS_FC3_CRC_T 0x00200000ULL /* b42 */ +#define SISL_ASTATUS_FC3_LOGI_R 0x00100000ULL /* b43 */ +#define SISL_ASTATUS_FC3_LOGI_F 0x00080000ULL /* b44 */ +#define SISL_ASTATUS_FC3_LOGI_S 0x00040000ULL /* b45 */ +#define SISL_ASTATUS_FC3_LINK_DN 0x00020000ULL /* b46 */ +#define SISL_ASTATUS_FC3_LINK_UP 0x00010000ULL /* b47 */ + +#define SISL_ASTATUS_FC0_OTHER 0x00008000ULL /* b48 */ +#define SISL_ASTATUS_FC0_LOGO 0x00004000ULL /* b49 */ +#define SISL_ASTATUS_FC0_CRC_T 0x00002000ULL /* b50 */ +#define SISL_ASTATUS_FC0_LOGI_R 0x00001000ULL /* b51 */ +#define SISL_ASTATUS_FC0_LOGI_F 0x00000800ULL /* b52 */ +#define SISL_ASTATUS_FC0_LOGI_S 0x00000400ULL /* b53 */ +#define SISL_ASTATUS_FC0_LINK_DN 0x00000200ULL /* b54 */ +#define SISL_ASTATUS_FC0_LINK_UP 0x00000100ULL /* b55 */ + +#define SISL_ASTATUS_FC1_OTHER 0x00000080ULL /* b56 */ +#define SISL_ASTATUS_FC1_LOGO 0x00000040ULL /* b57 */ +#define SISL_ASTATUS_FC1_CRC_T 0x00000020ULL /* b58 */ +#define SISL_ASTATUS_FC1_LOGI_R 0x00000010ULL /* b59 */ +#define SISL_ASTATUS_FC1_LOGI_F 0x00000008ULL /* b60 */ +#define SISL_ASTATUS_FC1_LOGI_S 0x00000004ULL /* b61 */ +#define SISL_ASTATUS_FC1_LINK_DN 0x00000002ULL /* b62 */ +#define SISL_ASTATUS_FC1_LINK_UP 0x00000001ULL /* b63 */ #define SISL_FC_INTERNAL_UNMASK 0x0000000300000000ULL /* 1 means unmasked */ #define SISL_FC_INTERNAL_MASK ~(SISL_FC_INTERNAL_UNMASK) @@ -325,7 +351,7 @@ struct sisl_global_regs { #define SISL_STATUS_SHUTDOWN_ACTIVE 0x0000000000000010ULL #define SISL_STATUS_SHUTDOWN_COMPLETE 0x0000000000000020ULL -#define SISL_ASTATUS_UNMASK 0xFFFFULL /* 1 means unmasked */ +#define SISL_ASTATUS_UNMASK 0xFFFFFFFFULL /* 1 means unmasked */ #define SISL_ASTATUS_MASK ~(SISL_ASTATUS_UNMASK) /* 1 means masked */ __be64 aintr_clear; @@ -367,10 +393,18 @@ struct sisl_global_regs { #define SISL_INTVER_CAP_RESERVED_CMD_MODE_B 0x100000000000ULL }; -#define CXLFLASH_MAX_FC_PORTS 2 -#define CXLFLASH_NUM_FC_PORTS 2 -#define CXLFLASH_MAX_CONTEXT 512 /* how many contexts per afu */ -#define CXLFLASH_NUM_VLUNS 512 +#define CXLFLASH_NUM_FC_PORTS_PER_BANK 2 /* fixed # of ports per bank */ +#define CXLFLASH_MAX_FC_BANKS 1 /* max # of banks supported */ +#define CXLFLASH_MAX_FC_PORTS (CXLFLASH_NUM_FC_PORTS_PER_BANK * \ + CXLFLASH_MAX_FC_BANKS) +#define CXLFLASH_MAX_CONTEXT 512 /* number of contexts per AFU */ +#define CXLFLASH_NUM_VLUNS 512 /* number of vluns per AFU/port */ +#define CXLFLASH_NUM_REGS 512 /* number of registers per port */ + +struct fc_port_bank { + __be64 fc_port_regs[CXLFLASH_NUM_FC_PORTS_PER_BANK][CXLFLASH_NUM_REGS]; + __be64 fc_port_luns[CXLFLASH_NUM_FC_PORTS_PER_BANK][CXLFLASH_NUM_VLUNS]; +}; struct sisl_global_map { union { @@ -380,11 +414,9 @@ struct sisl_global_map { char page1[SIZE_4K]; /* page 1 */ - /* pages 2 & 3 */ - __be64 fc_regs[CXLFLASH_NUM_FC_PORTS][CXLFLASH_NUM_VLUNS]; + struct fc_port_bank bank[CXLFLASH_MAX_FC_BANKS]; /* pages 2 - 5 */ - /* pages 4 & 5 (lun tbl) */ - __be64 fc_port[CXLFLASH_NUM_FC_PORTS][CXLFLASH_NUM_VLUNS]; + /* pages 6 - 15 are reserved */ }; @@ -479,6 +511,8 @@ struct sisl_rht_entry_f1 { #define PORT0 0x01U #define PORT1 0x02U +#define PORT2 0x04U +#define PORT3 0x08U #define PORT_MASK(_n) ((1 << (_n)) - 1) /* AFU Sync Mode byte */ -- cgit v1.2.3 From 1cd7fabc82eb06c834956113ff287f8848811fb8 Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 12 Apr 2017 14:14:41 -0500 Subject: scsi: cxlflash: Support up to 4 ports Update the driver to allow for future cards with 4 ports. Signed-off-by: Matthew R. Ochs Signed-off-by: Uma Krishnan Signed-off-by: Martin K. Petersen --- drivers/scsi/cxlflash/main.c | 78 ++++++++++++++++++++++++++++++++++++++++- drivers/scsi/cxlflash/sislite.h | 6 ++-- 2 files changed, 80 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index 64ad76b6b672..568cd636607a 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -1419,7 +1419,7 @@ static int read_vpd(struct cxlflash_cfg *cfg, u64 wwpn[]) ssize_t vpd_size; char vpd_data[CXLFLASH_VPD_LEN]; char tmp_buf[WWPN_BUF_LEN] = { 0 }; - char *wwpn_vpd_tags[MAX_FC_PORTS] = { "V5", "V6" }; + char *wwpn_vpd_tags[MAX_FC_PORTS] = { "V5", "V6", "V7", "V8" }; /* Get the VPD data from the device */ vpd_size = cxl_read_adapter_vpd(pdev, vpd_data, sizeof(vpd_data)); @@ -2174,6 +2174,40 @@ static ssize_t port1_show(struct device *dev, return cxlflash_show_port_status(1, cfg, buf); } +/** + * port2_show() - queries and presents the current status of port 2 + * @dev: Generic device associated with the host owning the port. + * @attr: Device attribute representing the port. + * @buf: Buffer of length PAGE_SIZE to report back port status in ASCII. + * + * Return: The size of the ASCII string returned in @buf. + */ +static ssize_t port2_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev)); + + return cxlflash_show_port_status(2, cfg, buf); +} + +/** + * port3_show() - queries and presents the current status of port 3 + * @dev: Generic device associated with the host owning the port. + * @attr: Device attribute representing the port. + * @buf: Buffer of length PAGE_SIZE to report back port status in ASCII. + * + * Return: The size of the ASCII string returned in @buf. + */ +static ssize_t port3_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev)); + + return cxlflash_show_port_status(3, cfg, buf); +} + /** * lun_mode_show() - presents the current LUN mode of the host * @dev: Generic device associated with the host. @@ -2326,6 +2360,40 @@ static ssize_t port1_lun_table_show(struct device *dev, return cxlflash_show_port_lun_table(1, cfg, buf); } +/** + * port2_lun_table_show() - presents the current LUN table of port 2 + * @dev: Generic device associated with the host owning the port. + * @attr: Device attribute representing the port. + * @buf: Buffer of length PAGE_SIZE to report back port status in ASCII. + * + * Return: The size of the ASCII string returned in @buf. + */ +static ssize_t port2_lun_table_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev)); + + return cxlflash_show_port_lun_table(2, cfg, buf); +} + +/** + * port3_lun_table_show() - presents the current LUN table of port 3 + * @dev: Generic device associated with the host owning the port. + * @attr: Device attribute representing the port. + * @buf: Buffer of length PAGE_SIZE to report back port status in ASCII. + * + * Return: The size of the ASCII string returned in @buf. + */ +static ssize_t port3_lun_table_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev)); + + return cxlflash_show_port_lun_table(3, cfg, buf); +} + /** * irqpoll_weight_show() - presents the current IRQ poll weight for the host * @dev: Generic device associated with the host. @@ -2417,19 +2485,27 @@ static ssize_t mode_show(struct device *dev, */ static DEVICE_ATTR_RO(port0); static DEVICE_ATTR_RO(port1); +static DEVICE_ATTR_RO(port2); +static DEVICE_ATTR_RO(port3); static DEVICE_ATTR_RW(lun_mode); static DEVICE_ATTR_RO(ioctl_version); static DEVICE_ATTR_RO(port0_lun_table); static DEVICE_ATTR_RO(port1_lun_table); +static DEVICE_ATTR_RO(port2_lun_table); +static DEVICE_ATTR_RO(port3_lun_table); static DEVICE_ATTR_RW(irqpoll_weight); static struct device_attribute *cxlflash_host_attrs[] = { &dev_attr_port0, &dev_attr_port1, + &dev_attr_port2, + &dev_attr_port3, &dev_attr_lun_mode, &dev_attr_ioctl_version, &dev_attr_port0_lun_table, &dev_attr_port1_lun_table, + &dev_attr_port2_lun_table, + &dev_attr_port3_lun_table, &dev_attr_irqpoll_weight, NULL }; diff --git a/drivers/scsi/cxlflash/sislite.h b/drivers/scsi/cxlflash/sislite.h index 42d9c9ee3bce..0e52bbb6aeeb 100644 --- a/drivers/scsi/cxlflash/sislite.h +++ b/drivers/scsi/cxlflash/sislite.h @@ -394,7 +394,7 @@ struct sisl_global_regs { }; #define CXLFLASH_NUM_FC_PORTS_PER_BANK 2 /* fixed # of ports per bank */ -#define CXLFLASH_MAX_FC_BANKS 1 /* max # of banks supported */ +#define CXLFLASH_MAX_FC_BANKS 2 /* max # of banks supported */ #define CXLFLASH_MAX_FC_PORTS (CXLFLASH_NUM_FC_PORTS_PER_BANK * \ CXLFLASH_MAX_FC_BANKS) #define CXLFLASH_MAX_CONTEXT 512 /* number of contexts per AFU */ @@ -414,9 +414,9 @@ struct sisl_global_map { char page1[SIZE_4K]; /* page 1 */ - struct fc_port_bank bank[CXLFLASH_MAX_FC_BANKS]; /* pages 2 - 5 */ + struct fc_port_bank bank[CXLFLASH_MAX_FC_BANKS]; /* pages 2 - 9 */ - /* pages 6 - 15 are reserved */ + /* pages 10 - 15 are reserved */ }; -- cgit v1.2.3 From 323e33428ea23bfb1ae5010b18b4540048b2ad51 Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 12 Apr 2017 14:14:51 -0500 Subject: scsi: cxlflash: Fence EEH during probe An EEH during probe can lead to a crash as the recovery thread races with the probe thread. To avoid this issue, introduce new states to fence out EEH recovery until probe has completed. Also ensure the reset wait queue is flushed during device removal to avoid orphaned threads. Signed-off-by: Matthew R. Ochs Signed-off-by: Uma Krishnan Signed-off-by: Martin K. Petersen --- drivers/scsi/cxlflash/common.h | 2 ++ drivers/scsi/cxlflash/main.c | 25 +++++++++++++++++++++---- drivers/scsi/cxlflash/superpipe.c | 8 +++++--- 3 files changed, 28 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/cxlflash/common.h b/drivers/scsi/cxlflash/common.h index 28bb716e78fe..17aa74a83d39 100644 --- a/drivers/scsi/cxlflash/common.h +++ b/drivers/scsi/cxlflash/common.h @@ -90,6 +90,8 @@ enum cxlflash_init_state { }; enum cxlflash_state { + STATE_PROBING, /* Initial state during probe */ + STATE_PROBED, /* Temporary state, probe completed but EEH occurred */ STATE_NORMAL, /* Normal running state, everything good */ STATE_RESET, /* Reset state, trying to reset/recover */ STATE_FAILTERM /* Failed/terminating state, error out users/threads */ diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index 568cd636607a..ebba3c90a242 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -470,6 +470,8 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp) spin_unlock_irqrestore(&cfg->tmf_slock, lock_flags); switch (cfg->state) { + case STATE_PROBING: + case STATE_PROBED: case STATE_RESET: dev_dbg_ratelimited(dev, "%s: device is in reset\n", __func__); rc = SCSI_MLQUEUE_HOST_BUSY; @@ -719,7 +721,8 @@ static void notify_shutdown(struct cxlflash_cfg *cfg, bool wait) * cxlflash_remove() - PCI entry point to tear down host * @pdev: PCI device associated with the host. * - * Safe to use as a cleanup in partially allocated/initialized state. + * Safe to use as a cleanup in partially allocated/initialized state. Note that + * the reset_waitq is flushed as part of the stop/termination of user contexts. */ static void cxlflash_remove(struct pci_dev *pdev) { @@ -752,7 +755,6 @@ static void cxlflash_remove(struct pci_dev *pdev) case INIT_STATE_SCSI: cxlflash_term_local_luns(cfg); scsi_remove_host(cfg->host); - /* fall through */ case INIT_STATE_AFU: term_afu(cfg); case INIT_STATE_PCI: @@ -2624,6 +2626,15 @@ static void cxlflash_worker_thread(struct work_struct *work) * @pdev: PCI device associated with the host. * @dev_id: PCI device id associated with device. * + * The device will initially start out in a 'probing' state and + * transition to the 'normal' state at the end of a successful + * probe. Should an EEH event occur during probe, the notification + * thread (error_detected()) will wait until the probe handler + * is nearly complete. At that time, the device will be moved to + * a 'probed' state and the EEH thread woken up to drive the slot + * reset and recovery (device moves to 'normal' state). Meanwhile, + * the probe will be allowed to exit successfully. + * * Return: 0 on success, -errno on failure */ static int cxlflash_probe(struct pci_dev *pdev, @@ -2707,7 +2718,7 @@ static int cxlflash_probe(struct pci_dev *pdev, cfg->init_state = INIT_STATE_PCI; rc = init_afu(cfg); - if (rc) { + if (rc && !wq_has_sleeper(&cfg->reset_waitq)) { dev_err(dev, "%s: init_afu failed rc=%d\n", __func__, rc); goto out_remove; } @@ -2720,6 +2731,11 @@ static int cxlflash_probe(struct pci_dev *pdev, } cfg->init_state = INIT_STATE_SCSI; + if (wq_has_sleeper(&cfg->reset_waitq)) { + cfg->state = STATE_PROBED; + wake_up_all(&cfg->reset_waitq); + } else + cfg->state = STATE_NORMAL; out: dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); return rc; @@ -2750,7 +2766,8 @@ static pci_ers_result_t cxlflash_pci_error_detected(struct pci_dev *pdev, switch (state) { case pci_channel_io_frozen: - wait_event(cfg->reset_waitq, cfg->state != STATE_RESET); + wait_event(cfg->reset_waitq, cfg->state != STATE_RESET && + cfg->state != STATE_PROBING); if (cfg->state == STATE_FAILTERM) return PCI_ERS_RESULT_DISCONNECT; diff --git a/drivers/scsi/cxlflash/superpipe.c b/drivers/scsi/cxlflash/superpipe.c index f3997bed88f4..bc6b39275f68 100644 --- a/drivers/scsi/cxlflash/superpipe.c +++ b/drivers/scsi/cxlflash/superpipe.c @@ -78,17 +78,18 @@ void cxlflash_free_errpage(void) * memory freed. This is accomplished by putting the contexts in error * state which will notify the user and let them 'drive' the tear down. * Meanwhile, this routine camps until all user contexts have been removed. + * + * Note that the main loop in this routine will always execute at least once + * to flush the reset_waitq. */ void cxlflash_stop_term_user_contexts(struct cxlflash_cfg *cfg) { struct device *dev = &cfg->dev->dev; - int i, found; + int i, found = true; cxlflash_mark_contexts_error(cfg); while (true) { - found = false; - for (i = 0; i < MAX_CONTEXT; i++) if (cfg->ctx_tbl[i]) { found = true; @@ -102,6 +103,7 @@ void cxlflash_stop_term_user_contexts(struct cxlflash_cfg *cfg) __func__); wake_up_all(&cfg->reset_waitq); ssleep(1); + found = false; } } -- cgit v1.2.3 From 50b787f7235efbd074bbdf4315e0cc261d85b4d7 Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 12 Apr 2017 14:15:02 -0500 Subject: scsi: cxlflash: Remove unnecessary DMA mapping Devices supported by the cxlflash driver are fully coherent and do not require a bus address mapping. Avoid unnecessary path length by using the virtual address and length already present in the scatter-gather entry. Signed-off-by: Matthew R. Ochs Signed-off-by: Uma Krishnan Signed-off-by: Martin K. Petersen --- drivers/scsi/cxlflash/main.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index ebba3c90a242..3c4a83307e6e 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -176,7 +176,6 @@ static void cmd_complete(struct afu_cmd *cmd) dev_dbg_ratelimited(dev, "%s:scp=%p result=%08x ioasc=%08x\n", __func__, scp, scp->result, cmd->sa.ioasc); - scsi_dma_unmap(scp); scp->scsi_done(scp); if (cmd_is_tmf) { @@ -445,7 +444,6 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp) struct scatterlist *sg = scsi_sglist(scp); u16 req_flags = SISL_REQ_FLAGS_SUP_UNDERRUN; ulong lock_flags; - int nseg = 0; int rc = 0; dev_dbg_ratelimited(dev, "%s: (scp=%p) %d/%d/%d/%llu " @@ -487,15 +485,8 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp) } if (likely(sg)) { - nseg = scsi_dma_map(scp); - if (unlikely(nseg < 0)) { - dev_err(dev, "%s: Fail DMA map\n", __func__); - rc = SCSI_MLQUEUE_HOST_BUSY; - goto out; - } - - cmd->rcb.data_len = sg_dma_len(sg); - cmd->rcb.data_ea = sg_dma_address(sg); + cmd->rcb.data_len = sg->length; + cmd->rcb.data_ea = (uintptr_t)sg_virt(sg); } cmd->scp = scp; @@ -513,8 +504,6 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp) memcpy(cmd->rcb.cdb, scp->cmnd, sizeof(cmd->rcb.cdb)); rc = afu->send_cmd(afu, cmd); - if (unlikely(rc)) - scsi_dma_unmap(scp); out: return rc; } -- cgit v1.2.3 From cd41e18daf1a21fea5a195a5a74c97c6b183c15a Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 12 Apr 2017 14:15:11 -0500 Subject: scsi: cxlflash: Fix power-of-two validations Validation statements to enforce assumptions about specific defines are not being evaluated by the compiler due to the fact that they reside in a routine that is not used. To activate them, call the routine as part of module initialization. As an additional, related cleanup, remove the now-defunct CXLFLASH_NUM_CMDS. Signed-off-by: Matthew R. Ochs Signed-off-by: Uma Krishnan Signed-off-by: Martin K. Petersen --- drivers/scsi/cxlflash/common.h | 7 +------ drivers/scsi/cxlflash/main.c | 1 + 2 files changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/cxlflash/common.h b/drivers/scsi/cxlflash/common.h index 17aa74a83d39..455fd4dffac8 100644 --- a/drivers/scsi/cxlflash/common.h +++ b/drivers/scsi/cxlflash/common.h @@ -52,12 +52,6 @@ extern const struct file_operations cxlflash_cxl_fops; certain AFU errors */ /* Command management definitions */ -#define CXLFLASH_NUM_CMDS (2 * CXLFLASH_MAX_CMDS) /* Must be a pow2 for - alignment and more - efficient array - index derivation - */ - #define CXLFLASH_MAX_CMDS 256 #define CXLFLASH_MAX_CMDS_PER_LUN CXLFLASH_MAX_CMDS @@ -71,6 +65,7 @@ extern const struct file_operations cxlflash_cxl_fops; static inline void check_sizes(void) { BUILD_BUG_ON_NOT_POWER_OF_2(CXLFLASH_NUM_FC_PORTS_PER_BANK); + BUILD_BUG_ON_NOT_POWER_OF_2(CXLFLASH_MAX_CMDS); } /* AFU defines a fixed size of 4K for command buffers (borrow 4K page define) */ diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index 3c4a83307e6e..f5c952c953f7 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -2847,6 +2847,7 @@ static struct pci_driver cxlflash_driver = { */ static int __init init_cxlflash(void) { + check_sizes(); cxlflash_list_init(); return pci_register_driver(&cxlflash_driver); -- cgit v1.2.3 From fcc87e74a987dc9c0c85f53546df944ede76486a Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 12 Apr 2017 14:15:20 -0500 Subject: scsi: cxlflash: Fix warnings/errors As a general cleanup, address all reasonable checkpatch warnings and errors. These include enforcement of comment styles and including named identifiers in function prototypes. Signed-off-by: Matthew R. Ochs Signed-off-by: Uma Krishnan Signed-off-by: Martin K. Petersen --- drivers/scsi/cxlflash/common.h | 27 ++++++++++----------- drivers/scsi/cxlflash/sislite.h | 27 +++++++++++---------- drivers/scsi/cxlflash/superpipe.h | 51 ++++++++++++++++++++++----------------- drivers/scsi/cxlflash/vlun.h | 2 +- 4 files changed, 57 insertions(+), 50 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/cxlflash/common.h b/drivers/scsi/cxlflash/common.h index 455fd4dffac8..c69cdcf8664d 100644 --- a/drivers/scsi/cxlflash/common.h +++ b/drivers/scsi/cxlflash/common.h @@ -36,20 +36,19 @@ extern const struct file_operations cxlflash_cxl_fops; #define PORTMASK2CHAN(_x) (ilog2((_x))) /* port mask to channel */ #define PORTNUM2CHAN(_x) ((_x) - 1) /* port number to channel */ -#define CXLFLASH_BLOCK_SIZE 4096 /* 4K blocks */ +#define CXLFLASH_BLOCK_SIZE 4096 /* 4K blocks */ #define CXLFLASH_MAX_XFER_SIZE 16777216 /* 16MB transfer */ #define CXLFLASH_MAX_SECTORS (CXLFLASH_MAX_XFER_SIZE/512) /* SCSI wants - max_sectors - in units of - 512 byte - sectors - */ + * max_sectors + * in units of + * 512 byte + * sectors + */ #define MAX_RHT_PER_CONTEXT (PAGE_SIZE / sizeof(struct sisl_rht_entry)) /* AFU command retry limit */ -#define MC_RETRY_CNT 5 /* sufficient for SCSI check and - certain AFU errors */ +#define MC_RETRY_CNT 5 /* Sufficient for SCSI and certain AFU errors */ /* Command management definitions */ #define CXLFLASH_MAX_CMDS 256 @@ -262,14 +261,14 @@ static inline __be64 __iomem *get_fc_port_luns(struct cxlflash_cfg *cfg, int i) return &fcpb->fc_port_luns[CHAN2BANKPORT(i)][0]; } -int cxlflash_afu_sync(struct afu *, ctx_hndl_t, res_hndl_t, u8); +int cxlflash_afu_sync(struct afu *afu, ctx_hndl_t c, res_hndl_t r, u8 mode); void cxlflash_list_init(void); void cxlflash_term_global_luns(void); void cxlflash_free_errpage(void); -int cxlflash_ioctl(struct scsi_device *, int, void __user *); -void cxlflash_stop_term_user_contexts(struct cxlflash_cfg *); -int cxlflash_mark_contexts_error(struct cxlflash_cfg *); -void cxlflash_term_local_luns(struct cxlflash_cfg *); -void cxlflash_restore_luntable(struct cxlflash_cfg *); +int cxlflash_ioctl(struct scsi_device *sdev, int cmd, void __user *arg); +void cxlflash_stop_term_user_contexts(struct cxlflash_cfg *cfg); +int cxlflash_mark_contexts_error(struct cxlflash_cfg *cfg); +void cxlflash_term_local_luns(struct cxlflash_cfg *cfg); +void cxlflash_restore_luntable(struct cxlflash_cfg *cfg); #endif /* ifndef _CXLFLASH_COMMON_H */ diff --git a/drivers/scsi/cxlflash/sislite.h b/drivers/scsi/cxlflash/sislite.h index 0e52bbb6aeeb..a768360d2fa6 100644 --- a/drivers/scsi/cxlflash/sislite.h +++ b/drivers/scsi/cxlflash/sislite.h @@ -90,15 +90,15 @@ struct sisl_rc { #define SISL_AFU_RC_RHT_UNALIGNED 0x02U /* should never happen */ #define SISL_AFU_RC_RHT_OUT_OF_BOUNDS 0x03u /* user error */ #define SISL_AFU_RC_RHT_DMA_ERR 0x04u /* see afu_extra - may retry if afu_retry is off - possible on master exit + * may retry if afu_retry is off + * possible on master exit */ #define SISL_AFU_RC_RHT_RW_PERM 0x05u /* no RW perms, user error */ #define SISL_AFU_RC_LXT_UNALIGNED 0x12U /* should never happen */ #define SISL_AFU_RC_LXT_OUT_OF_BOUNDS 0x13u /* user error */ #define SISL_AFU_RC_LXT_DMA_ERR 0x14u /* see afu_extra - may retry if afu_retry is off - possible on master exit + * may retry if afu_retry is off + * possible on master exit */ #define SISL_AFU_RC_LXT_RW_PERM 0x15u /* no RW perms, user error */ @@ -111,11 +111,11 @@ struct sisl_rc { */ #define SISL_AFU_RC_NO_CHANNELS 0x20U /* see afu_extra, may retry */ #define SISL_AFU_RC_CAP_VIOLATION 0x21U /* either user error or - afu reset/master restart + * afu reset/master restart */ #define SISL_AFU_RC_OUT_OF_DATA_BUFS 0x30U /* always retry */ #define SISL_AFU_RC_DATA_DMA_ERR 0x31U /* see afu_extra - may retry if afu_retry is off + * may retry if afu_retry is off */ u8 scsi_rc; /* SCSI status byte, retry as appropriate */ @@ -149,8 +149,9 @@ struct sisl_rc { #define SISL_FC_RC_ABORTFAIL 0x59 /* pending abort completed w/fail */ #define SISL_FC_RC_RESID 0x5A /* ioasa underrun/overrun flags set */ #define SISL_FC_RC_RESIDERR 0x5B /* actual data len does not match SCSI - reported len, possibly due to dropped - frames */ + * reported len, possibly due to dropped + * frames + */ #define SISL_FC_RC_TGTABORT 0x5C /* command aborted by target */ }; @@ -227,10 +228,10 @@ struct sisl_ioasa { /* per context host transport MMIO */ struct sisl_host_map { - __be64 endian_ctrl; /* Per context Endian Control. The AFU will - * operate on whatever the context is of the - * host application. - */ + __be64 endian_ctrl; /* Per context Endian Control. The AFU will + * operate on whatever the context is of the + * host application. + */ __be64 intr_status; /* this sends LISN# programmed in ctx_ctrl. * Only recovery in a PERM_ERR is a context @@ -435,7 +436,7 @@ struct sisl_global_map { * | 64 KB Global | * | Trusted Process accessible | * +-------------------------------+ -*/ + */ struct cxlflash_afu_map { union { struct sisl_host_map host; diff --git a/drivers/scsi/cxlflash/superpipe.h b/drivers/scsi/cxlflash/superpipe.h index 8269ff854bbe..0b5976829913 100644 --- a/drivers/scsi/cxlflash/superpipe.h +++ b/drivers/scsi/cxlflash/superpipe.h @@ -24,8 +24,8 @@ extern struct cxlflash_global global; */ /* Chunk size parms: note sislite minimum chunk size is - 0x10000 LBAs corresponding to a NMASK or 16. -*/ + * 0x10000 LBAs corresponding to a NMASK or 16. + */ #define MC_CHUNK_SIZE (1 << MC_RHT_NMASK) /* in LBAs */ #define CMD_TIMEOUT 30 /* 30 secs */ @@ -89,7 +89,8 @@ enum ctx_ctrl { struct ctx_info { struct sisl_ctrl_map __iomem *ctrl_map; /* initialized at startup */ struct sisl_rht_entry *rht_start; /* 1 page (req'd for alignment), - alloc/free on attach/detach */ + * alloc/free on attach/detach + */ u32 rht_out; /* Number of checked out RHT entries */ u32 rht_perms; /* User-defined permissions for RHT entries */ struct llun_info **rht_lun; /* Mapping of RHT entries to LUNs */ @@ -117,34 +118,40 @@ struct cxlflash_global { struct page *err_page; /* One page of all 0xF for error notification */ }; -int cxlflash_vlun_resize(struct scsi_device *, struct dk_cxlflash_resize *); -int _cxlflash_vlun_resize(struct scsi_device *, struct ctx_info *, - struct dk_cxlflash_resize *); +int cxlflash_vlun_resize(struct scsi_device *sdev, + struct dk_cxlflash_resize *resize); +int _cxlflash_vlun_resize(struct scsi_device *sdev, struct ctx_info *ctxi, + struct dk_cxlflash_resize *resize); -int cxlflash_disk_release(struct scsi_device *, struct dk_cxlflash_release *); -int _cxlflash_disk_release(struct scsi_device *, struct ctx_info *, - struct dk_cxlflash_release *); +int cxlflash_disk_release(struct scsi_device *sdev, + struct dk_cxlflash_release *release); +int _cxlflash_disk_release(struct scsi_device *sdev, struct ctx_info *ctxi, + struct dk_cxlflash_release *release); -int cxlflash_disk_clone(struct scsi_device *, struct dk_cxlflash_clone *); +int cxlflash_disk_clone(struct scsi_device *sdev, + struct dk_cxlflash_clone *clone); -int cxlflash_disk_virtual_open(struct scsi_device *, void *); +int cxlflash_disk_virtual_open(struct scsi_device *sdev, void *arg); -int cxlflash_lun_attach(struct glun_info *, enum lun_mode, bool); -void cxlflash_lun_detach(struct glun_info *); +int cxlflash_lun_attach(struct glun_info *gli, enum lun_mode mode, bool locked); +void cxlflash_lun_detach(struct glun_info *gli); -struct ctx_info *get_context(struct cxlflash_cfg *, u64, void *, enum ctx_ctrl); -void put_context(struct ctx_info *); +struct ctx_info *get_context(struct cxlflash_cfg *cfg, u64 rctxit, void *arg, + enum ctx_ctrl ctrl); +void put_context(struct ctx_info *ctxi); -struct sisl_rht_entry *get_rhte(struct ctx_info *, res_hndl_t, - struct llun_info *); +struct sisl_rht_entry *get_rhte(struct ctx_info *ctxi, res_hndl_t rhndl, + struct llun_info *lli); -struct sisl_rht_entry *rhte_checkout(struct ctx_info *, struct llun_info *); -void rhte_checkin(struct ctx_info *, struct sisl_rht_entry *); +struct sisl_rht_entry *rhte_checkout(struct ctx_info *ctxi, + struct llun_info *lli); +void rhte_checkin(struct ctx_info *ctxi, struct sisl_rht_entry *rhte); -void cxlflash_ba_terminate(struct ba_lun *); +void cxlflash_ba_terminate(struct ba_lun *ba_lun); -int cxlflash_manage_lun(struct scsi_device *, struct dk_cxlflash_manage_lun *); +int cxlflash_manage_lun(struct scsi_device *sdev, + struct dk_cxlflash_manage_lun *manage); -int check_state(struct cxlflash_cfg *); +int check_state(struct cxlflash_cfg *cfg); #endif /* ifndef _CXLFLASH_SUPERPIPE_H */ diff --git a/drivers/scsi/cxlflash/vlun.h b/drivers/scsi/cxlflash/vlun.h index 8b29a74946e4..27a63a0155ce 100644 --- a/drivers/scsi/cxlflash/vlun.h +++ b/drivers/scsi/cxlflash/vlun.h @@ -47,7 +47,7 @@ * not stored anywhere. * * The LXT table is re-allocated whenever it needs to cross into another group. -*/ + */ #define LXT_GROUP_SIZE 8 #define LXT_NUM_GROUPS(lxt_cnt) (((lxt_cnt) + 7)/8) /* alloc'ed groups */ #define LXT_LUNIDX_SHIFT 8 /* LXT entry, shift for LUN index */ -- cgit v1.2.3 From e2ef33fa5958c51ebf0c6f18db19fe927e2185fa Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 12 Apr 2017 14:15:29 -0500 Subject: scsi: cxlflash: Improve asynchronous interrupt processing The method used to decode asynchronous interrupts involves unnecessary loops to match up bits that are set with corresponding entries in the asynchronous interrupt information table. This algorithm is wasteful and does not scale well as new status bits are supported. As an improvement, use the for_each_set_bit() service to iterate over the asynchronous status bits and refactor the information table such that it can be indexed by bit position. Signed-off-by: Matthew R. Ochs Signed-off-by: Uma Krishnan Signed-off-by: Martin K. Petersen --- drivers/scsi/cxlflash/main.c | 94 ++++++++++++++++++++------------------------ 1 file changed, 42 insertions(+), 52 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index f5c952c953f7..c60936fb70bb 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -1017,52 +1017,6 @@ static void afu_link_reset(struct afu *afu, int port, __be64 __iomem *fc_regs) dev_dbg(dev, "%s: returning port_sel=%016llx\n", __func__, port_sel); } -/* - * Asynchronous interrupt information table - * - * NOTE: The checkpatch script considers the BUILD_SISL_ASTATUS_FC_PORT macro - * as complex and complains because it is not wrapped with parentheses/braces. - */ -#define ASTATUS_FC(_a, _b, _c, _d) \ - { SISL_ASTATUS_FC##_a##_##_b, _c, _a, (_d) } - -#define BUILD_SISL_ASTATUS_FC_PORT(_a) \ - ASTATUS_FC(_a, OTHER, "other error", CLR_FC_ERROR | LINK_RESET), \ - ASTATUS_FC(_a, LOGO, "target initiated LOGO", 0), \ - ASTATUS_FC(_a, CRC_T, "CRC threshold exceeded", LINK_RESET), \ - ASTATUS_FC(_a, LOGI_R, "login timed out, retrying", LINK_RESET), \ - ASTATUS_FC(_a, LOGI_F, "login failed", CLR_FC_ERROR), \ - ASTATUS_FC(_a, LOGI_S, "login succeeded", SCAN_HOST), \ - ASTATUS_FC(_a, LINK_DN, "link down", 0), \ - ASTATUS_FC(_a, LINK_UP, "link up", 0) - -static const struct asyc_intr_info ainfo[] = { - BUILD_SISL_ASTATUS_FC_PORT(2), - BUILD_SISL_ASTATUS_FC_PORT(3), - BUILD_SISL_ASTATUS_FC_PORT(0), - BUILD_SISL_ASTATUS_FC_PORT(1), - { 0x0, "", 0, 0 } -}; - -/** - * find_ainfo() - locates and returns asynchronous interrupt information - * @status: Status code set by AFU on error. - * - * Return: The located information or NULL when the status code is invalid. - */ -static const struct asyc_intr_info *find_ainfo(u64 status) -{ - const struct asyc_intr_info *info; - - BUILD_BUG_ON(ainfo[ARRAY_SIZE(ainfo) - 1].status != 0); - - for (info = &ainfo[0]; info->status; info++) - if (info->status == status) - return info; - - return NULL; -} - /** * afu_err_intr_init() - clears and initializes the AFU for error interrupts * @afu: AFU associated with the host. @@ -1293,6 +1247,35 @@ static irqreturn_t cxlflash_rrq_irq(int irq, void *data) return IRQ_HANDLED; } +/* + * Asynchronous interrupt information table + * + * NOTE: + * - Order matters here as this array is indexed by bit position. + * + * - The checkpatch script considers the BUILD_SISL_ASTATUS_FC_PORT macro + * as complex and complains due to a lack of parentheses/braces. + */ +#define ASTATUS_FC(_a, _b, _c, _d) \ + { SISL_ASTATUS_FC##_a##_##_b, _c, _a, (_d) } + +#define BUILD_SISL_ASTATUS_FC_PORT(_a) \ + ASTATUS_FC(_a, LINK_UP, "link up", 0), \ + ASTATUS_FC(_a, LINK_DN, "link down", 0), \ + ASTATUS_FC(_a, LOGI_S, "login succeeded", SCAN_HOST), \ + ASTATUS_FC(_a, LOGI_F, "login failed", CLR_FC_ERROR), \ + ASTATUS_FC(_a, LOGI_R, "login timed out, retrying", LINK_RESET), \ + ASTATUS_FC(_a, CRC_T, "CRC threshold exceeded", LINK_RESET), \ + ASTATUS_FC(_a, LOGO, "target initiated LOGO", 0), \ + ASTATUS_FC(_a, OTHER, "other error", CLR_FC_ERROR | LINK_RESET) + +static const struct asyc_intr_info ainfo[] = { + BUILD_SISL_ASTATUS_FC_PORT(1), + BUILD_SISL_ASTATUS_FC_PORT(0), + BUILD_SISL_ASTATUS_FC_PORT(3), + BUILD_SISL_ASTATUS_FC_PORT(2) +}; + /** * cxlflash_async_err_irq() - interrupt handler for asynchronous errors * @irq: Interrupt number. @@ -1305,18 +1288,18 @@ static irqreturn_t cxlflash_async_err_irq(int irq, void *data) struct afu *afu = (struct afu *)data; struct cxlflash_cfg *cfg = afu->parent; struct device *dev = &cfg->dev->dev; - u64 reg_unmasked; const struct asyc_intr_info *info; struct sisl_global_map __iomem *global = &afu->afu_map->global; __be64 __iomem *fc_port_regs; + u64 reg_unmasked; u64 reg; + u64 bit; u8 port; - int i; reg = readq_be(&global->regs.aintr_status); reg_unmasked = (reg & SISL_ASTATUS_UNMASK); - if (reg_unmasked == 0) { + if (unlikely(reg_unmasked == 0)) { dev_err(dev, "%s: spurious interrupt, aintr_status=%016llx\n", __func__, reg); goto out; @@ -1326,10 +1309,17 @@ static irqreturn_t cxlflash_async_err_irq(int irq, void *data) writeq_be(reg_unmasked, &global->regs.aintr_clear); /* Check each bit that is on */ - for (i = 0; reg_unmasked; i++, reg_unmasked = (reg_unmasked >> 1)) { - info = find_ainfo(1ULL << i); - if (((reg_unmasked & 0x1) == 0) || !info) + for_each_set_bit(bit, (ulong *)®_unmasked, BITS_PER_LONG) { + if (unlikely(bit >= ARRAY_SIZE(ainfo))) { + WARN_ON_ONCE(1); continue; + } + + info = &ainfo[bit]; + if (unlikely(info->status != 1ULL << bit)) { + WARN_ON_ONCE(1); + continue; + } port = info->port; fc_port_regs = get_fc_port_regs(cfg, port); -- cgit v1.2.3 From bfc0bab172cabf3bb25c48c4c521b317ff4a909d Mon Sep 17 00:00:00 2001 From: Uma Krishnan Date: Wed, 12 Apr 2017 14:15:42 -0500 Subject: scsi: cxlflash: Support multiple hardware queues Introduce multiple hardware queues to improve legacy I/O path performance. Each hardware queue is comprised of a master context and associated I/O resources. The hardware queues are initially implemented as a static array embedded in the AFU. This will be transitioned to a dynamic allocation in a later series to improve the memory footprint of the driver. Signed-off-by: Uma Krishnan Acked-by: Matthew R. Ochs Signed-off-by: Martin K. Petersen --- drivers/scsi/cxlflash/common.h | 41 ++-- drivers/scsi/cxlflash/main.c | 426 ++++++++++++++++++++++++-------------- drivers/scsi/cxlflash/superpipe.c | 6 +- 3 files changed, 309 insertions(+), 164 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/cxlflash/common.h b/drivers/scsi/cxlflash/common.h index c69cdcf8664d..b5858ae1deae 100644 --- a/drivers/scsi/cxlflash/common.h +++ b/drivers/scsi/cxlflash/common.h @@ -60,6 +60,9 @@ extern const struct file_operations cxlflash_cxl_fops; /* SQ for master issued cmds */ #define NUM_SQ_ENTRY CXLFLASH_MAX_CMDS +#define CXLFLASH_NUM_HWQS 1 +#define PRIMARY_HWQ 0 + static inline void check_sizes(void) { @@ -98,7 +101,6 @@ enum cxlflash_state { struct cxlflash_cfg { struct afu *afu; - struct cxl_context *mcctx; struct pci_dev *dev; struct pci_device_id *dev_id; @@ -144,6 +146,7 @@ struct afu_cmd { struct list_head queue; u8 cmd_tmf:1; + u32 hwq_index; /* As per the SISLITE spec the IOARCB EA has to be 16-byte aligned. * However for performance reasons the IOARCB/IOASA should be @@ -164,7 +167,7 @@ static inline struct afu_cmd *sc_to_afucz(struct scsi_cmnd *sc) return afuc; } -struct afu { +struct hwq { /* Stuff requiring alignment go first. */ struct sisl_ioarcb sq[NUM_SQ_ENTRY]; /* 16K SQ */ u64 rrq_entry[NUM_RRQ_ENTRY]; /* 2K RRQ */ @@ -172,17 +175,13 @@ struct afu { /* Beware of alignment till here. Preferably introduce new * fields after this point */ - - int (*send_cmd)(struct afu *, struct afu_cmd *); - void (*context_reset)(struct afu_cmd *); - - /* AFU HW */ + struct afu *afu; + struct cxl_context *ctx; struct cxl_ioctl_start_work work; - struct cxlflash_afu_map __iomem *afu_map; /* entire MMIO map */ struct sisl_host_map __iomem *host_map; /* MC host map */ struct sisl_ctrl_map __iomem *ctrl_map; /* MC control map */ - ctx_hndl_t ctx_hndl; /* master's context handle */ + u32 index; /* Index of this hwq */ atomic_t hsq_credits; spinlock_t hsq_slock; @@ -194,9 +193,22 @@ struct afu { u64 *hrrq_end; u64 *hrrq_curr; bool toggle; - atomic_t cmds_active; /* Number of currently active AFU commands */ + s64 room; spinlock_t rrin_slock; /* Lock to rrin queuing and cmd_room updates */ + + struct irq_poll irqpoll; +} __aligned(cache_line_size()); + +struct afu { + struct hwq hwqs[CXLFLASH_NUM_HWQS]; + int (*send_cmd)(struct afu *, struct afu_cmd *); + void (*context_reset)(struct afu_cmd *); + + /* AFU HW */ + struct cxlflash_afu_map __iomem *afu_map; /* entire MMIO map */ + + atomic_t cmds_active; /* Number of currently active AFU commands */ u64 hb; u32 internal_lun; /* User-desired LUN mode for this AFU */ @@ -204,11 +216,16 @@ struct afu { u64 interface_version; u32 irqpoll_weight; - struct irq_poll irqpoll; struct cxlflash_cfg *parent; /* Pointer back to parent cxlflash_cfg */ - }; +static inline struct hwq *get_hwq(struct afu *afu, u32 index) +{ + WARN_ON(index >= CXLFLASH_NUM_HWQS); + + return &afu->hwqs[index]; +} + static inline bool afu_is_irqpoll_enabled(struct afu *afu) { return !!afu->irqpoll_weight; diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index c60936fb70bb..5d068696eee4 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -223,8 +223,9 @@ static void context_reset(struct afu_cmd *cmd, __be64 __iomem *reset_reg) static void context_reset_ioarrin(struct afu_cmd *cmd) { struct afu *afu = cmd->parent; + struct hwq *hwq = get_hwq(afu, cmd->hwq_index); - context_reset(cmd, &afu->host_map->ioarrin); + context_reset(cmd, &hwq->host_map->ioarrin); } /** @@ -234,8 +235,9 @@ static void context_reset_ioarrin(struct afu_cmd *cmd) static void context_reset_sq(struct afu_cmd *cmd) { struct afu *afu = cmd->parent; + struct hwq *hwq = get_hwq(afu, cmd->hwq_index); - context_reset(cmd, &afu->host_map->sq_ctx_reset); + context_reset(cmd, &hwq->host_map->sq_ctx_reset); } /** @@ -250,6 +252,7 @@ static int send_cmd_ioarrin(struct afu *afu, struct afu_cmd *cmd) { struct cxlflash_cfg *cfg = afu->parent; struct device *dev = &cfg->dev->dev; + struct hwq *hwq = get_hwq(afu, cmd->hwq_index); int rc = 0; s64 room; ulong lock_flags; @@ -258,23 +261,23 @@ static int send_cmd_ioarrin(struct afu *afu, struct afu_cmd *cmd) * To avoid the performance penalty of MMIO, spread the update of * 'room' over multiple commands. */ - spin_lock_irqsave(&afu->rrin_slock, lock_flags); - if (--afu->room < 0) { - room = readq_be(&afu->host_map->cmd_room); + spin_lock_irqsave(&hwq->rrin_slock, lock_flags); + if (--hwq->room < 0) { + room = readq_be(&hwq->host_map->cmd_room); if (room <= 0) { dev_dbg_ratelimited(dev, "%s: no cmd_room to send " "0x%02X, room=0x%016llX\n", __func__, cmd->rcb.cdb[0], room); - afu->room = 0; + hwq->room = 0; rc = SCSI_MLQUEUE_HOST_BUSY; goto out; } - afu->room = room - 1; + hwq->room = room - 1; } - writeq_be((u64)&cmd->rcb, &afu->host_map->ioarrin); + writeq_be((u64)&cmd->rcb, &hwq->host_map->ioarrin); out: - spin_unlock_irqrestore(&afu->rrin_slock, lock_flags); + spin_unlock_irqrestore(&hwq->rrin_slock, lock_flags); dev_dbg(dev, "%s: cmd=%p len=%u ea=%016llx rc=%d\n", __func__, cmd, cmd->rcb.data_len, cmd->rcb.data_ea, rc); return rc; @@ -292,11 +295,12 @@ static int send_cmd_sq(struct afu *afu, struct afu_cmd *cmd) { struct cxlflash_cfg *cfg = afu->parent; struct device *dev = &cfg->dev->dev; + struct hwq *hwq = get_hwq(afu, cmd->hwq_index); int rc = 0; int newval; ulong lock_flags; - newval = atomic_dec_if_positive(&afu->hsq_credits); + newval = atomic_dec_if_positive(&hwq->hsq_credits); if (newval <= 0) { rc = SCSI_MLQUEUE_HOST_BUSY; goto out; @@ -304,22 +308,22 @@ static int send_cmd_sq(struct afu *afu, struct afu_cmd *cmd) cmd->rcb.ioasa = &cmd->sa; - spin_lock_irqsave(&afu->hsq_slock, lock_flags); + spin_lock_irqsave(&hwq->hsq_slock, lock_flags); - *afu->hsq_curr = cmd->rcb; - if (afu->hsq_curr < afu->hsq_end) - afu->hsq_curr++; + *hwq->hsq_curr = cmd->rcb; + if (hwq->hsq_curr < hwq->hsq_end) + hwq->hsq_curr++; else - afu->hsq_curr = afu->hsq_start; - writeq_be((u64)afu->hsq_curr, &afu->host_map->sq_tail); + hwq->hsq_curr = hwq->hsq_start; + writeq_be((u64)hwq->hsq_curr, &hwq->host_map->sq_tail); - spin_unlock_irqrestore(&afu->hsq_slock, lock_flags); + spin_unlock_irqrestore(&hwq->hsq_slock, lock_flags); out: dev_dbg(dev, "%s: cmd=%p len=%u ea=%016llx ioasa=%p rc=%d curr=%p " "head=%016llx tail=%016llx\n", __func__, cmd, cmd->rcb.data_len, - cmd->rcb.data_ea, cmd->rcb.ioasa, rc, afu->hsq_curr, - readq_be(&afu->host_map->sq_head), - readq_be(&afu->host_map->sq_tail)); + cmd->rcb.data_ea, cmd->rcb.ioasa, rc, hwq->hsq_curr, + readq_be(&hwq->host_map->sq_head), + readq_be(&hwq->host_map->sq_tail)); return rc; } @@ -367,6 +371,7 @@ static int send_tmf(struct afu *afu, struct scsi_cmnd *scp, u64 tmfcmd) struct cxlflash_cfg *cfg = shost_priv(scp->device->host); struct afu_cmd *cmd = sc_to_afucz(scp); struct device *dev = &cfg->dev->dev; + struct hwq *hwq = get_hwq(afu, PRIMARY_HWQ); ulong lock_flags; int rc = 0; ulong to; @@ -383,8 +388,9 @@ static int send_tmf(struct afu *afu, struct scsi_cmnd *scp, u64 tmfcmd) cmd->scp = scp; cmd->parent = afu; cmd->cmd_tmf = true; + cmd->hwq_index = hwq->index; - cmd->rcb.ctx_id = afu->ctx_hndl; + cmd->rcb.ctx_id = hwq->ctx_hndl; cmd->rcb.msi = SISL_MSI_RRQ_UPDATED; cmd->rcb.port_sel = CHAN2PORTMASK(scp->device->channel); cmd->rcb.lun_id = lun_to_lunid(scp->device->lun); @@ -442,6 +448,7 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp) struct device *dev = &cfg->dev->dev; struct afu_cmd *cmd = sc_to_afucz(scp); struct scatterlist *sg = scsi_sglist(scp); + struct hwq *hwq = get_hwq(afu, PRIMARY_HWQ); u16 req_flags = SISL_REQ_FLAGS_SUP_UNDERRUN; ulong lock_flags; int rc = 0; @@ -491,8 +498,9 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp) cmd->scp = scp; cmd->parent = afu; + cmd->hwq_index = hwq->index; - cmd->rcb.ctx_id = afu->ctx_hndl; + cmd->rcb.ctx_id = hwq->ctx_hndl; cmd->rcb.msi = SISL_MSI_RRQ_UPDATED; cmd->rcb.port_sel = CHAN2PORTMASK(scp->device->channel); cmd->rcb.lun_id = lun_to_lunid(scp->device->lun); @@ -548,14 +556,23 @@ static void free_mem(struct cxlflash_cfg *cfg) static void stop_afu(struct cxlflash_cfg *cfg) { struct afu *afu = cfg->afu; + struct hwq *hwq; + int i; cancel_work_sync(&cfg->work_q); if (likely(afu)) { while (atomic_read(&afu->cmds_active)) ssleep(1); - if (afu_is_irqpoll_enabled(afu)) - irq_poll_disable(&afu->irqpoll); + + if (afu_is_irqpoll_enabled(afu)) { + for (i = 0; i < CXLFLASH_NUM_HWQS; i++) { + hwq = get_hwq(afu, i); + + irq_poll_disable(&hwq->irqpoll); + } + } + if (likely(afu->afu_map)) { cxl_psa_unmap((void __iomem *)afu->afu_map); afu->afu_map = NULL; @@ -567,28 +584,40 @@ static void stop_afu(struct cxlflash_cfg *cfg) * term_intr() - disables all AFU interrupts * @cfg: Internal structure associated with the host. * @level: Depth of allocation, where to begin waterfall tear down. + * @index: Index of the hardware queue. * * Safe to call with AFU/MC in partially allocated/initialized state. */ -static void term_intr(struct cxlflash_cfg *cfg, enum undo_level level) +static void term_intr(struct cxlflash_cfg *cfg, enum undo_level level, + u32 index) { struct afu *afu = cfg->afu; struct device *dev = &cfg->dev->dev; + struct hwq *hwq; - if (!afu || !cfg->mcctx) { - dev_err(dev, "%s: returning with NULL afu or MC\n", __func__); + if (!afu) { + dev_err(dev, "%s: returning with NULL afu\n", __func__); + return; + } + + hwq = get_hwq(afu, index); + + if (!hwq->ctx) { + dev_err(dev, "%s: returning with NULL MC\n", __func__); return; } switch (level) { case UNMAP_THREE: - cxl_unmap_afu_irq(cfg->mcctx, 3, afu); + /* SISL_MSI_ASYNC_ERROR is setup only for the primary HWQ */ + if (index == PRIMARY_HWQ) + cxl_unmap_afu_irq(hwq->ctx, 3, hwq); case UNMAP_TWO: - cxl_unmap_afu_irq(cfg->mcctx, 2, afu); + cxl_unmap_afu_irq(hwq->ctx, 2, hwq); case UNMAP_ONE: - cxl_unmap_afu_irq(cfg->mcctx, 1, afu); + cxl_unmap_afu_irq(hwq->ctx, 1, hwq); case FREE_IRQ: - cxl_free_afu_irqs(cfg->mcctx); + cxl_free_afu_irqs(hwq->ctx); /* fall through */ case UNDO_NOOP: /* No action required */ @@ -599,24 +628,32 @@ static void term_intr(struct cxlflash_cfg *cfg, enum undo_level level) /** * term_mc() - terminates the master context * @cfg: Internal structure associated with the host. - * @level: Depth of allocation, where to begin waterfall tear down. + * @index: Index of the hardware queue. * * Safe to call with AFU/MC in partially allocated/initialized state. */ -static void term_mc(struct cxlflash_cfg *cfg) +static void term_mc(struct cxlflash_cfg *cfg, u32 index) { - int rc = 0; struct afu *afu = cfg->afu; struct device *dev = &cfg->dev->dev; + struct hwq *hwq; - if (!afu || !cfg->mcctx) { - dev_err(dev, "%s: returning with NULL afu or MC\n", __func__); + if (!afu) { + dev_err(dev, "%s: returning with NULL afu\n", __func__); return; } - rc = cxl_stop_context(cfg->mcctx); - WARN_ON(rc); - cfg->mcctx = NULL; + hwq = get_hwq(afu, index); + + if (!hwq->ctx) { + dev_err(dev, "%s: returning with NULL MC\n", __func__); + return; + } + + WARN_ON(cxl_stop_context(hwq->ctx)); + if (index != PRIMARY_HWQ) + WARN_ON(cxl_release_context(hwq->ctx)); + hwq->ctx = NULL; } /** @@ -628,21 +665,25 @@ static void term_mc(struct cxlflash_cfg *cfg) static void term_afu(struct cxlflash_cfg *cfg) { struct device *dev = &cfg->dev->dev; + int k; /* * Tear down is carefully orchestrated to ensure * no interrupts can come in when the problem state * area is unmapped. * - * 1) Disable all AFU interrupts + * 1) Disable all AFU interrupts for each master * 2) Unmap the problem state area - * 3) Stop the master context + * 3) Stop each master context */ - term_intr(cfg, UNMAP_THREE); + for (k = CXLFLASH_NUM_HWQS - 1; k >= 0; k--) + term_intr(cfg, UNMAP_THREE, k); + if (cfg->afu) stop_afu(cfg); - term_mc(cfg); + for (k = CXLFLASH_NUM_HWQS - 1; k >= 0; k--) + term_mc(cfg, k); dev_dbg(dev, "%s: returning\n", __func__); } @@ -1026,6 +1067,7 @@ static void afu_err_intr_init(struct afu *afu) struct cxlflash_cfg *cfg = afu->parent; __be64 __iomem *fc_port_regs; int i; + struct hwq *hwq = get_hwq(afu, PRIMARY_HWQ); u64 reg; /* global async interrupts: AFU clears afu_ctrl on context exit @@ -1037,8 +1079,8 @@ static void afu_err_intr_init(struct afu *afu) /* mask all */ writeq_be(-1ULL, &afu->afu_map->global.regs.aintr_mask); - /* set LISN# to send and point to master context */ - reg = ((u64) (((afu->ctx_hndl << 8) | SISL_MSI_ASYNC_ERROR)) << 40); + /* set LISN# to send and point to primary master context */ + reg = ((u64) (((hwq->ctx_hndl << 8) | SISL_MSI_ASYNC_ERROR)) << 40); if (afu->internal_lun) reg |= 1; /* Bit 63 indicates local lun */ @@ -1074,8 +1116,12 @@ static void afu_err_intr_init(struct afu *afu) /* IOARRIN yet), so there is nothing to clear. */ /* set LISN#, it is always sent to the context that wrote IOARRIN */ - writeq_be(SISL_MSI_SYNC_ERROR, &afu->host_map->ctx_ctrl); - writeq_be(SISL_ISTATUS_MASK, &afu->host_map->intr_mask); + for (i = 0; i < CXLFLASH_NUM_HWQS; i++) { + hwq = get_hwq(afu, i); + + writeq_be(SISL_MSI_SYNC_ERROR, &hwq->host_map->ctx_ctrl); + writeq_be(SISL_ISTATUS_MASK, &hwq->host_map->intr_mask); + } } /** @@ -1087,13 +1133,13 @@ static void afu_err_intr_init(struct afu *afu) */ static irqreturn_t cxlflash_sync_err_irq(int irq, void *data) { - struct afu *afu = (struct afu *)data; - struct cxlflash_cfg *cfg = afu->parent; + struct hwq *hwq = (struct hwq *)data; + struct cxlflash_cfg *cfg = hwq->afu->parent; struct device *dev = &cfg->dev->dev; u64 reg; u64 reg_unmasked; - reg = readq_be(&afu->host_map->intr_status); + reg = readq_be(&hwq->host_map->intr_status); reg_unmasked = (reg & SISL_ISTATUS_UNMASK); if (reg_unmasked == 0UL) { @@ -1105,7 +1151,7 @@ static irqreturn_t cxlflash_sync_err_irq(int irq, void *data) dev_err(dev, "%s: unexpected interrupt, intr_status=%016llx\n", __func__, reg); - writeq_be(reg_unmasked, &afu->host_map->intr_clear); + writeq_be(reg_unmasked, &hwq->host_map->intr_clear); cxlflash_sync_err_irq_exit: return IRQ_HANDLED; @@ -1121,17 +1167,18 @@ cxlflash_sync_err_irq_exit: * * Return: The number of entries processed. */ -static int process_hrrq(struct afu *afu, struct list_head *doneq, int budget) +static int process_hrrq(struct hwq *hwq, struct list_head *doneq, int budget) { + struct afu *afu = hwq->afu; struct afu_cmd *cmd; struct sisl_ioasa *ioasa; struct sisl_ioarcb *ioarcb; - bool toggle = afu->toggle; + bool toggle = hwq->toggle; int num_hrrq = 0; u64 entry, - *hrrq_start = afu->hrrq_start, - *hrrq_end = afu->hrrq_end, - *hrrq_curr = afu->hrrq_curr; + *hrrq_start = hwq->hrrq_start, + *hrrq_end = hwq->hrrq_end, + *hrrq_curr = hwq->hrrq_curr; /* Process ready RRQ entries up to the specified budget (if any) */ while (true) { @@ -1160,15 +1207,15 @@ static int process_hrrq(struct afu *afu, struct list_head *doneq, int budget) toggle ^= SISL_RESP_HANDLE_T_BIT; } - atomic_inc(&afu->hsq_credits); + atomic_inc(&hwq->hsq_credits); num_hrrq++; if (budget > 0 && num_hrrq >= budget) break; } - afu->hrrq_curr = hrrq_curr; - afu->toggle = toggle; + hwq->hrrq_curr = hrrq_curr; + hwq->toggle = toggle; return num_hrrq; } @@ -1198,18 +1245,18 @@ static void process_cmd_doneq(struct list_head *doneq) */ static int cxlflash_irqpoll(struct irq_poll *irqpoll, int budget) { - struct afu *afu = container_of(irqpoll, struct afu, irqpoll); + struct hwq *hwq = container_of(irqpoll, struct hwq, irqpoll); unsigned long hrrq_flags; LIST_HEAD(doneq); int num_entries = 0; - spin_lock_irqsave(&afu->hrrq_slock, hrrq_flags); + spin_lock_irqsave(&hwq->hrrq_slock, hrrq_flags); - num_entries = process_hrrq(afu, &doneq, budget); + num_entries = process_hrrq(hwq, &doneq, budget); if (num_entries < budget) irq_poll_complete(irqpoll); - spin_unlock_irqrestore(&afu->hrrq_slock, hrrq_flags); + spin_unlock_irqrestore(&hwq->hrrq_slock, hrrq_flags); process_cmd_doneq(&doneq); return num_entries; @@ -1224,21 +1271,22 @@ static int cxlflash_irqpoll(struct irq_poll *irqpoll, int budget) */ static irqreturn_t cxlflash_rrq_irq(int irq, void *data) { - struct afu *afu = (struct afu *)data; + struct hwq *hwq = (struct hwq *)data; + struct afu *afu = hwq->afu; unsigned long hrrq_flags; LIST_HEAD(doneq); int num_entries = 0; - spin_lock_irqsave(&afu->hrrq_slock, hrrq_flags); + spin_lock_irqsave(&hwq->hrrq_slock, hrrq_flags); if (afu_is_irqpoll_enabled(afu)) { - irq_poll_sched(&afu->irqpoll); - spin_unlock_irqrestore(&afu->hrrq_slock, hrrq_flags); + irq_poll_sched(&hwq->irqpoll); + spin_unlock_irqrestore(&hwq->hrrq_slock, hrrq_flags); return IRQ_HANDLED; } - num_entries = process_hrrq(afu, &doneq, -1); - spin_unlock_irqrestore(&afu->hrrq_slock, hrrq_flags); + num_entries = process_hrrq(hwq, &doneq, -1); + spin_unlock_irqrestore(&hwq->hrrq_slock, hrrq_flags); if (num_entries == 0) return IRQ_NONE; @@ -1285,7 +1333,8 @@ static const struct asyc_intr_info ainfo[] = { */ static irqreturn_t cxlflash_async_err_irq(int irq, void *data) { - struct afu *afu = (struct afu *)data; + struct hwq *hwq = (struct hwq *)data; + struct afu *afu = hwq->afu; struct cxlflash_cfg *cfg = afu->parent; struct device *dev = &cfg->dev->dev; const struct asyc_intr_info *info; @@ -1368,16 +1417,18 @@ out: /** * start_context() - starts the master context * @cfg: Internal structure associated with the host. + * @index: Index of the hardware queue. * * Return: A success or failure value from CXL services. */ -static int start_context(struct cxlflash_cfg *cfg) +static int start_context(struct cxlflash_cfg *cfg, u32 index) { struct device *dev = &cfg->dev->dev; + struct hwq *hwq = get_hwq(cfg->afu, index); int rc = 0; - rc = cxl_start_context(cfg->mcctx, - cfg->afu->work.work_element_descriptor, + rc = cxl_start_context(hwq->ctx, + hwq->work.work_element_descriptor, NULL); dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); @@ -1487,6 +1538,7 @@ static void init_pcr(struct cxlflash_cfg *cfg) { struct afu *afu = cfg->afu; struct sisl_ctrl_map __iomem *ctrl_map; + struct hwq *hwq; int i; for (i = 0; i < MAX_CONTEXT; i++) { @@ -1498,13 +1550,17 @@ static void init_pcr(struct cxlflash_cfg *cfg) writeq_be(0, &ctrl_map->ctx_cap); } - /* Copy frequently used fields into afu */ - afu->ctx_hndl = (u16) cxl_process_element(cfg->mcctx); - afu->host_map = &afu->afu_map->hosts[afu->ctx_hndl].host; - afu->ctrl_map = &afu->afu_map->ctrls[afu->ctx_hndl].ctrl; + /* Copy frequently used fields into hwq */ + for (i = 0; i < CXLFLASH_NUM_HWQS; i++) { + hwq = get_hwq(afu, i); - /* Program the Endian Control for the master context */ - writeq_be(SISL_ENDIAN_CTRL, &afu->host_map->endian_ctrl); + hwq->ctx_hndl = (u16) cxl_process_element(hwq->ctx); + hwq->host_map = &afu->afu_map->hosts[hwq->ctx_hndl].host; + hwq->ctrl_map = &afu->afu_map->ctrls[hwq->ctx_hndl].ctrl; + + /* Program the Endian Control for the master context */ + writeq_be(SISL_ENDIAN_CTRL, &hwq->host_map->endian_ctrl); + } } /** @@ -1515,6 +1571,8 @@ static int init_global(struct cxlflash_cfg *cfg) { struct afu *afu = cfg->afu; struct device *dev = &cfg->dev->dev; + struct hwq *hwq; + struct sisl_host_map __iomem *hmap; __be64 __iomem *fc_port_regs; u64 wwpn[MAX_FC_PORTS]; /* wwpn of AFU ports */ int i = 0, num_ports = 0; @@ -1527,13 +1585,18 @@ static int init_global(struct cxlflash_cfg *cfg) goto out; } - /* Set up RRQ and SQ in AFU for master issued cmds */ - writeq_be((u64) afu->hrrq_start, &afu->host_map->rrq_start); - writeq_be((u64) afu->hrrq_end, &afu->host_map->rrq_end); + /* Set up RRQ and SQ in HWQ for master issued cmds */ + for (i = 0; i < CXLFLASH_NUM_HWQS; i++) { + hwq = get_hwq(afu, i); + hmap = hwq->host_map; - if (afu_is_sq_cmd_mode(afu)) { - writeq_be((u64)afu->hsq_start, &afu->host_map->sq_start); - writeq_be((u64)afu->hsq_end, &afu->host_map->sq_end); + writeq_be((u64) hwq->hrrq_start, &hmap->rrq_start); + writeq_be((u64) hwq->hrrq_end, &hmap->rrq_end); + + if (afu_is_sq_cmd_mode(afu)) { + writeq_be((u64)hwq->hsq_start, &hmap->sq_start); + writeq_be((u64)hwq->hsq_end, &hmap->sq_end); + } } /* AFU configuration */ @@ -1577,11 +1640,15 @@ static int init_global(struct cxlflash_cfg *cfg) /* Set up master's own CTX_CAP to allow real mode, host translation */ /* tables, afu cmds and read/write GSCSI cmds. */ /* First, unlock ctx_cap write by reading mbox */ - (void)readq_be(&afu->ctrl_map->mbox_r); /* unlock ctx_cap */ - writeq_be((SISL_CTX_CAP_REAL_MODE | SISL_CTX_CAP_HOST_XLATE | - SISL_CTX_CAP_READ_CMD | SISL_CTX_CAP_WRITE_CMD | - SISL_CTX_CAP_AFU_CMD | SISL_CTX_CAP_GSCSI_CMD), - &afu->ctrl_map->ctx_cap); + for (i = 0; i < CXLFLASH_NUM_HWQS; i++) { + hwq = get_hwq(afu, i); + + (void)readq_be(&hwq->ctrl_map->mbox_r); /* unlock ctx_cap */ + writeq_be((SISL_CTX_CAP_REAL_MODE | SISL_CTX_CAP_HOST_XLATE | + SISL_CTX_CAP_READ_CMD | SISL_CTX_CAP_WRITE_CMD | + SISL_CTX_CAP_AFU_CMD | SISL_CTX_CAP_GSCSI_CMD), + &hwq->ctrl_map->ctx_cap); + } /* Initialize heartbeat */ afu->hb = readq_be(&afu->afu_map->global.regs.afu_hb); out: @@ -1596,33 +1663,43 @@ static int start_afu(struct cxlflash_cfg *cfg) { struct afu *afu = cfg->afu; struct device *dev = &cfg->dev->dev; + struct hwq *hwq; int rc = 0; + int i; init_pcr(cfg); - /* Initialize RRQ */ - memset(&afu->rrq_entry, 0, sizeof(afu->rrq_entry)); - afu->hrrq_start = &afu->rrq_entry[0]; - afu->hrrq_end = &afu->rrq_entry[NUM_RRQ_ENTRY - 1]; - afu->hrrq_curr = afu->hrrq_start; - afu->toggle = 1; - spin_lock_init(&afu->hrrq_slock); + /* Initialize each HWQ */ + for (i = 0; i < CXLFLASH_NUM_HWQS; i++) { + hwq = get_hwq(afu, i); - /* Initialize SQ */ - if (afu_is_sq_cmd_mode(afu)) { - memset(&afu->sq, 0, sizeof(afu->sq)); - afu->hsq_start = &afu->sq[0]; - afu->hsq_end = &afu->sq[NUM_SQ_ENTRY - 1]; - afu->hsq_curr = afu->hsq_start; + /* After an AFU reset, RRQ entries are stale, clear them */ + memset(&hwq->rrq_entry, 0, sizeof(hwq->rrq_entry)); - spin_lock_init(&afu->hsq_slock); - atomic_set(&afu->hsq_credits, NUM_SQ_ENTRY - 1); - } + /* Initialize RRQ pointers */ + hwq->hrrq_start = &hwq->rrq_entry[0]; + hwq->hrrq_end = &hwq->rrq_entry[NUM_RRQ_ENTRY - 1]; + hwq->hrrq_curr = hwq->hrrq_start; + hwq->toggle = 1; + spin_lock_init(&hwq->hrrq_slock); + + /* Initialize SQ */ + if (afu_is_sq_cmd_mode(afu)) { + memset(&hwq->sq, 0, sizeof(hwq->sq)); + hwq->hsq_start = &hwq->sq[0]; + hwq->hsq_end = &hwq->sq[NUM_SQ_ENTRY - 1]; + hwq->hsq_curr = hwq->hsq_start; + + spin_lock_init(&hwq->hsq_slock); + atomic_set(&hwq->hsq_credits, NUM_SQ_ENTRY - 1); + } - /* Initialize IRQ poll */ - if (afu_is_irqpoll_enabled(afu)) - irq_poll_init(&afu->irqpoll, afu->irqpoll_weight, - cxlflash_irqpoll); + /* Initialize IRQ poll */ + if (afu_is_irqpoll_enabled(afu)) + irq_poll_init(&hwq->irqpoll, afu->irqpoll_weight, + cxlflash_irqpoll); + + } rc = init_global(cfg); @@ -1633,18 +1710,21 @@ static int start_afu(struct cxlflash_cfg *cfg) /** * init_intr() - setup interrupt handlers for the master context * @cfg: Internal structure associated with the host. + * @hwq: Hardware queue to initialize. * * Return: 0 on success, -errno on failure */ static enum undo_level init_intr(struct cxlflash_cfg *cfg, - struct cxl_context *ctx) + struct hwq *hwq) { - struct afu *afu = cfg->afu; struct device *dev = &cfg->dev->dev; + struct cxl_context *ctx = hwq->ctx; int rc = 0; enum undo_level level = UNDO_NOOP; + bool is_primary_hwq = (hwq->index == PRIMARY_HWQ); + int num_irqs = is_primary_hwq ? 3 : 2; - rc = cxl_allocate_afu_irqs(ctx, 3); + rc = cxl_allocate_afu_irqs(ctx, num_irqs); if (unlikely(rc)) { dev_err(dev, "%s: allocate_afu_irqs failed rc=%d\n", __func__, rc); @@ -1652,7 +1732,7 @@ static enum undo_level init_intr(struct cxlflash_cfg *cfg, goto out; } - rc = cxl_map_afu_irq(ctx, 1, cxlflash_sync_err_irq, afu, + rc = cxl_map_afu_irq(ctx, 1, cxlflash_sync_err_irq, hwq, "SISL_MSI_SYNC_ERROR"); if (unlikely(rc <= 0)) { dev_err(dev, "%s: SISL_MSI_SYNC_ERROR map failed\n", __func__); @@ -1660,7 +1740,7 @@ static enum undo_level init_intr(struct cxlflash_cfg *cfg, goto out; } - rc = cxl_map_afu_irq(ctx, 2, cxlflash_rrq_irq, afu, + rc = cxl_map_afu_irq(ctx, 2, cxlflash_rrq_irq, hwq, "SISL_MSI_RRQ_UPDATED"); if (unlikely(rc <= 0)) { dev_err(dev, "%s: SISL_MSI_RRQ_UPDATED map failed\n", __func__); @@ -1668,7 +1748,11 @@ static enum undo_level init_intr(struct cxlflash_cfg *cfg, goto out; } - rc = cxl_map_afu_irq(ctx, 3, cxlflash_async_err_irq, afu, + /* SISL_MSI_ASYNC_ERROR is setup only for the primary HWQ */ + if (!is_primary_hwq) + goto out; + + rc = cxl_map_afu_irq(ctx, 3, cxlflash_async_err_irq, hwq, "SISL_MSI_ASYNC_ERROR"); if (unlikely(rc <= 0)) { dev_err(dev, "%s: SISL_MSI_ASYNC_ERROR map failed\n", __func__); @@ -1682,55 +1766,73 @@ out: /** * init_mc() - create and register as the master context * @cfg: Internal structure associated with the host. + * index: HWQ Index of the master context. * * Return: 0 on success, -errno on failure */ -static int init_mc(struct cxlflash_cfg *cfg) +static int init_mc(struct cxlflash_cfg *cfg, u32 index) { struct cxl_context *ctx; struct device *dev = &cfg->dev->dev; + struct hwq *hwq = get_hwq(cfg->afu, index); int rc = 0; enum undo_level level; - ctx = cxl_get_context(cfg->dev); + hwq->afu = cfg->afu; + hwq->index = index; + + if (index == PRIMARY_HWQ) + ctx = cxl_get_context(cfg->dev); + else + ctx = cxl_dev_context_init(cfg->dev); if (unlikely(!ctx)) { rc = -ENOMEM; - goto ret; + goto err1; } - cfg->mcctx = ctx; + + WARN_ON(hwq->ctx); + hwq->ctx = ctx; /* Set it up as a master with the CXL */ cxl_set_master(ctx); - /* During initialization reset the AFU to start from a clean slate */ - rc = cxl_afu_reset(cfg->mcctx); - if (unlikely(rc)) { - dev_err(dev, "%s: AFU reset failed rc=%d\n", __func__, rc); - goto ret; + /* Reset AFU when initializing primary context */ + if (index == PRIMARY_HWQ) { + rc = cxl_afu_reset(ctx); + if (unlikely(rc)) { + dev_err(dev, "%s: AFU reset failed rc=%d\n", + __func__, rc); + goto err1; + } } - level = init_intr(cfg, ctx); + level = init_intr(cfg, hwq); if (unlikely(level)) { dev_err(dev, "%s: interrupt init failed rc=%d\n", __func__, rc); - goto out; + goto err2; } /* This performs the equivalent of the CXL_IOCTL_START_WORK. * The CXL_IOCTL_GET_PROCESS_ELEMENT is implicit in the process * element (pe) that is embedded in the context (ctx) */ - rc = start_context(cfg); + rc = start_context(cfg, index); if (unlikely(rc)) { dev_err(dev, "%s: start context failed rc=%d\n", __func__, rc); level = UNMAP_THREE; - goto out; + goto err2; } -ret: + +out: dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); return rc; -out: - term_intr(cfg, level); - goto ret; +err2: + term_intr(cfg, level, index); + if (index != PRIMARY_HWQ) + cxl_release_context(ctx); +err1: + hwq->ctx = NULL; + goto out; } /** @@ -1781,18 +1883,23 @@ static int init_afu(struct cxlflash_cfg *cfg) int rc = 0; struct afu *afu = cfg->afu; struct device *dev = &cfg->dev->dev; + struct hwq *hwq; + int i; cxl_perst_reloads_same_image(cfg->cxl_afu, true); - rc = init_mc(cfg); - if (rc) { - dev_err(dev, "%s: init_mc failed rc=%d\n", - __func__, rc); - goto out; + for (i = 0; i < CXLFLASH_NUM_HWQS; i++) { + rc = init_mc(cfg, i); + if (rc) { + dev_err(dev, "%s: init_mc failed rc=%d index=%d\n", + __func__, rc, i); + goto err1; + } } - /* Map the entire MMIO space of the AFU */ - afu->afu_map = cxl_psa_map(cfg->mcctx); + /* Map the entire MMIO space of the AFU using the first context */ + hwq = get_hwq(afu, PRIMARY_HWQ); + afu->afu_map = cxl_psa_map(hwq->ctx); if (!afu->afu_map) { dev_err(dev, "%s: cxl_psa_map failed\n", __func__); rc = -ENOMEM; @@ -1832,8 +1939,12 @@ static int init_afu(struct cxlflash_cfg *cfg) } afu_err_intr_init(cfg->afu); - spin_lock_init(&afu->rrin_slock); - afu->room = readq_be(&afu->host_map->cmd_room); + for (i = 0; i < CXLFLASH_NUM_HWQS; i++) { + hwq = get_hwq(afu, i); + + spin_lock_init(&hwq->rrin_slock); + hwq->room = readq_be(&hwq->host_map->cmd_room); + } /* Restore the LUN mappings */ cxlflash_restore_luntable(cfg); @@ -1842,8 +1953,10 @@ out: return rc; err1: - term_intr(cfg, UNMAP_THREE); - term_mc(cfg); + for (i = CXLFLASH_NUM_HWQS - 1; i >= 0; i--) { + term_intr(cfg, UNMAP_THREE, i); + term_mc(cfg, i); + } goto out; } @@ -1875,6 +1988,7 @@ int cxlflash_afu_sync(struct afu *afu, ctx_hndl_t ctx_hndl_u, struct cxlflash_cfg *cfg = afu->parent; struct device *dev = &cfg->dev->dev; struct afu_cmd *cmd = NULL; + struct hwq *hwq = get_hwq(afu, PRIMARY_HWQ); char *buf = NULL; int rc = 0; static DEFINE_MUTEX(sync_active); @@ -1897,11 +2011,12 @@ int cxlflash_afu_sync(struct afu *afu, ctx_hndl_t ctx_hndl_u, cmd = (struct afu_cmd *)PTR_ALIGN(buf, __alignof__(*cmd)); init_completion(&cmd->cevent); cmd->parent = afu; + cmd->hwq_index = hwq->index; dev_dbg(dev, "%s: afu=%p cmd=%p %d\n", __func__, afu, cmd, ctx_hndl_u); cmd->rcb.req_flags = SISL_REQ_FLAGS_AFU_CMD; - cmd->rcb.ctx_id = afu->ctx_hndl; + cmd->rcb.ctx_id = hwq->ctx_hndl; cmd->rcb.msi = SISL_MSI_RRQ_UPDATED; cmd->rcb.timeout = MC_AFU_SYNC_TIMEOUT; @@ -2414,8 +2529,9 @@ static ssize_t irqpoll_weight_store(struct device *dev, struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev)); struct device *cfgdev = &cfg->dev->dev; struct afu *afu = cfg->afu; + struct hwq *hwq; u32 weight; - int rc; + int rc, i; rc = kstrtouint(buf, 10, &weight); if (rc) @@ -2433,13 +2549,23 @@ static ssize_t irqpoll_weight_store(struct device *dev, return -EINVAL; } - if (afu_is_irqpoll_enabled(afu)) - irq_poll_disable(&afu->irqpoll); + if (afu_is_irqpoll_enabled(afu)) { + for (i = 0; i < CXLFLASH_NUM_HWQS; i++) { + hwq = get_hwq(afu, i); + + irq_poll_disable(&hwq->irqpoll); + } + } afu->irqpoll_weight = weight; - if (weight > 0) - irq_poll_init(&afu->irqpoll, weight, cxlflash_irqpoll); + if (weight > 0) { + for (i = 0; i < CXLFLASH_NUM_HWQS; i++) { + hwq = get_hwq(afu, i); + + irq_poll_init(&hwq->irqpoll, weight, cxlflash_irqpoll); + } + } return count; } diff --git a/drivers/scsi/cxlflash/superpipe.c b/drivers/scsi/cxlflash/superpipe.c index bc6b39275f68..fe9f17a6268b 100644 --- a/drivers/scsi/cxlflash/superpipe.c +++ b/drivers/scsi/cxlflash/superpipe.c @@ -254,6 +254,7 @@ static int afu_attach(struct cxlflash_cfg *cfg, struct ctx_info *ctxi) struct afu *afu = cfg->afu; struct sisl_ctrl_map __iomem *ctrl_map = ctxi->ctrl_map; int rc = 0; + struct hwq *hwq = get_hwq(afu, PRIMARY_HWQ); u64 val; /* Unlock cap and restrict user to read/write cmds in translated mode */ @@ -270,7 +271,7 @@ static int afu_attach(struct cxlflash_cfg *cfg, struct ctx_info *ctxi) /* Set up MMIO registers pointing to the RHT */ writeq_be((u64)ctxi->rht_start, &ctrl_map->rht_start); - val = SISL_RHT_CNT_ID((u64)MAX_RHT_PER_CONTEXT, (u64)(afu->ctx_hndl)); + val = SISL_RHT_CNT_ID((u64)MAX_RHT_PER_CONTEXT, (u64)(hwq->ctx_hndl)); writeq_be(val, &ctrl_map->rht_cnt_id); out: dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); @@ -1626,6 +1627,7 @@ static int cxlflash_afu_recover(struct scsi_device *sdev, struct afu *afu = cfg->afu; struct ctx_info *ctxi = NULL; struct mutex *mutex = &cfg->ctx_recovery_mutex; + struct hwq *hwq = get_hwq(afu, PRIMARY_HWQ); u64 flags; u64 ctxid = DECODE_CTXID(recover->context_id), rctxid = recover->context_id; @@ -1696,7 +1698,7 @@ retry_recover: } /* Test if in error state */ - reg = readq_be(&afu->ctrl_map->mbox_r); + reg = readq_be(&hwq->ctrl_map->mbox_r); if (reg == -1) { dev_dbg(dev, "%s: MMIO fail, wait for recovery.\n", __func__); -- cgit v1.2.3 From 3065267a80c88d775e8eb34196280e8eee33322f Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 12 Apr 2017 14:15:53 -0500 Subject: scsi: cxlflash: Add hardware queues attribute As staging for supporting multiple hardware queues, add an attribute to show and set the current number of hardware queues for the host. Support specifying a hard limit or a CPU affinitized value. This will allow the number of hardware queues to be tuned by a system administrator. Signed-off-by: Matthew R. Ochs Signed-off-by: Uma Krishnan Signed-off-by: Martin K. Petersen --- drivers/scsi/cxlflash/common.h | 10 ++-- drivers/scsi/cxlflash/main.c | 112 ++++++++++++++++++++++++++++++++++++----- 2 files changed, 106 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/cxlflash/common.h b/drivers/scsi/cxlflash/common.h index b5858ae1deae..8fd7a1fa235e 100644 --- a/drivers/scsi/cxlflash/common.h +++ b/drivers/scsi/cxlflash/common.h @@ -60,7 +60,9 @@ extern const struct file_operations cxlflash_cxl_fops; /* SQ for master issued cmds */ #define NUM_SQ_ENTRY CXLFLASH_MAX_CMDS -#define CXLFLASH_NUM_HWQS 1 +/* Hardware queue definitions */ +#define CXLFLASH_DEF_HWQS 1 +#define CXLFLASH_MAX_HWQS 8 #define PRIMARY_HWQ 0 @@ -201,7 +203,7 @@ struct hwq { } __aligned(cache_line_size()); struct afu { - struct hwq hwqs[CXLFLASH_NUM_HWQS]; + struct hwq hwqs[CXLFLASH_MAX_HWQS]; int (*send_cmd)(struct afu *, struct afu_cmd *); void (*context_reset)(struct afu_cmd *); @@ -211,6 +213,8 @@ struct afu { atomic_t cmds_active; /* Number of currently active AFU commands */ u64 hb; u32 internal_lun; /* User-desired LUN mode for this AFU */ + u32 num_hwqs; /* Number of hardware queues */ + u32 desired_hwqs; /* Desired h/w queues, effective on AFU reset */ char version[16]; u64 interface_version; @@ -221,7 +225,7 @@ struct afu { static inline struct hwq *get_hwq(struct afu *afu, u32 index) { - WARN_ON(index >= CXLFLASH_NUM_HWQS); + WARN_ON(index >= CXLFLASH_MAX_HWQS); return &afu->hwqs[index]; } diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index 5d068696eee4..113797aafd7e 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -566,7 +566,7 @@ static void stop_afu(struct cxlflash_cfg *cfg) ssleep(1); if (afu_is_irqpoll_enabled(afu)) { - for (i = 0; i < CXLFLASH_NUM_HWQS; i++) { + for (i = 0; i < afu->num_hwqs; i++) { hwq = get_hwq(afu, i); irq_poll_disable(&hwq->irqpoll); @@ -676,13 +676,13 @@ static void term_afu(struct cxlflash_cfg *cfg) * 2) Unmap the problem state area * 3) Stop each master context */ - for (k = CXLFLASH_NUM_HWQS - 1; k >= 0; k--) + for (k = cfg->afu->num_hwqs - 1; k >= 0; k--) term_intr(cfg, UNMAP_THREE, k); if (cfg->afu) stop_afu(cfg); - for (k = CXLFLASH_NUM_HWQS - 1; k >= 0; k--) + for (k = cfg->afu->num_hwqs - 1; k >= 0; k--) term_mc(cfg, k); dev_dbg(dev, "%s: returning\n", __func__); @@ -823,6 +823,7 @@ static int alloc_mem(struct cxlflash_cfg *cfg) goto out; } cfg->afu->parent = cfg; + cfg->afu->desired_hwqs = CXLFLASH_DEF_HWQS; cfg->afu->afu_map = NULL; out: return rc; @@ -1116,7 +1117,7 @@ static void afu_err_intr_init(struct afu *afu) /* IOARRIN yet), so there is nothing to clear. */ /* set LISN#, it is always sent to the context that wrote IOARRIN */ - for (i = 0; i < CXLFLASH_NUM_HWQS; i++) { + for (i = 0; i < afu->num_hwqs; i++) { hwq = get_hwq(afu, i); writeq_be(SISL_MSI_SYNC_ERROR, &hwq->host_map->ctx_ctrl); @@ -1551,7 +1552,7 @@ static void init_pcr(struct cxlflash_cfg *cfg) } /* Copy frequently used fields into hwq */ - for (i = 0; i < CXLFLASH_NUM_HWQS; i++) { + for (i = 0; i < afu->num_hwqs; i++) { hwq = get_hwq(afu, i); hwq->ctx_hndl = (u16) cxl_process_element(hwq->ctx); @@ -1586,7 +1587,7 @@ static int init_global(struct cxlflash_cfg *cfg) } /* Set up RRQ and SQ in HWQ for master issued cmds */ - for (i = 0; i < CXLFLASH_NUM_HWQS; i++) { + for (i = 0; i < afu->num_hwqs; i++) { hwq = get_hwq(afu, i); hmap = hwq->host_map; @@ -1640,7 +1641,7 @@ static int init_global(struct cxlflash_cfg *cfg) /* Set up master's own CTX_CAP to allow real mode, host translation */ /* tables, afu cmds and read/write GSCSI cmds. */ /* First, unlock ctx_cap write by reading mbox */ - for (i = 0; i < CXLFLASH_NUM_HWQS; i++) { + for (i = 0; i < afu->num_hwqs; i++) { hwq = get_hwq(afu, i); (void)readq_be(&hwq->ctrl_map->mbox_r); /* unlock ctx_cap */ @@ -1670,7 +1671,7 @@ static int start_afu(struct cxlflash_cfg *cfg) init_pcr(cfg); /* Initialize each HWQ */ - for (i = 0; i < CXLFLASH_NUM_HWQS; i++) { + for (i = 0; i < afu->num_hwqs; i++) { hwq = get_hwq(afu, i); /* After an AFU reset, RRQ entries are stale, clear them */ @@ -1888,7 +1889,8 @@ static int init_afu(struct cxlflash_cfg *cfg) cxl_perst_reloads_same_image(cfg->cxl_afu, true); - for (i = 0; i < CXLFLASH_NUM_HWQS; i++) { + afu->num_hwqs = afu->desired_hwqs; + for (i = 0; i < afu->num_hwqs; i++) { rc = init_mc(cfg, i); if (rc) { dev_err(dev, "%s: init_mc failed rc=%d index=%d\n", @@ -1939,7 +1941,7 @@ static int init_afu(struct cxlflash_cfg *cfg) } afu_err_intr_init(cfg->afu); - for (i = 0; i < CXLFLASH_NUM_HWQS; i++) { + for (i = 0; i < afu->num_hwqs; i++) { hwq = get_hwq(afu, i); spin_lock_init(&hwq->rrin_slock); @@ -1953,7 +1955,7 @@ out: return rc; err1: - for (i = CXLFLASH_NUM_HWQS - 1; i >= 0; i--) { + for (i = afu->num_hwqs - 1; i >= 0; i--) { term_intr(cfg, UNMAP_THREE, i); term_mc(cfg, i); } @@ -2550,7 +2552,7 @@ static ssize_t irqpoll_weight_store(struct device *dev, } if (afu_is_irqpoll_enabled(afu)) { - for (i = 0; i < CXLFLASH_NUM_HWQS; i++) { + for (i = 0; i < afu->num_hwqs; i++) { hwq = get_hwq(afu, i); irq_poll_disable(&hwq->irqpoll); @@ -2560,7 +2562,7 @@ static ssize_t irqpoll_weight_store(struct device *dev, afu->irqpoll_weight = weight; if (weight > 0) { - for (i = 0; i < CXLFLASH_NUM_HWQS; i++) { + for (i = 0; i < afu->num_hwqs; i++) { hwq = get_hwq(afu, i); irq_poll_init(&hwq->irqpoll, weight, cxlflash_irqpoll); @@ -2570,6 +2572,88 @@ static ssize_t irqpoll_weight_store(struct device *dev, return count; } +/** + * num_hwqs_show() - presents the number of hardware queues for the host + * @dev: Generic device associated with the host. + * @attr: Device attribute representing the number of hardware queues. + * @buf: Buffer of length PAGE_SIZE to report back the number of hardware + * queues in ASCII. + * + * Return: The size of the ASCII string returned in @buf. + */ +static ssize_t num_hwqs_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev)); + struct afu *afu = cfg->afu; + + return scnprintf(buf, PAGE_SIZE, "%u\n", afu->num_hwqs); +} + +/** + * num_hwqs_store() - sets the number of hardware queues for the host + * @dev: Generic device associated with the host. + * @attr: Device attribute representing the number of hardware queues. + * @buf: Buffer of length PAGE_SIZE containing the number of hardware + * queues in ASCII. + * @count: Length of data resizing in @buf. + * + * n > 0: num_hwqs = n + * n = 0: num_hwqs = num_online_cpus() + * n < 0: num_online_cpus() / abs(n) + * + * Return: The size of the ASCII string returned in @buf. + */ +static ssize_t num_hwqs_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev)); + struct afu *afu = cfg->afu; + int rc; + int nhwqs, num_hwqs; + + rc = kstrtoint(buf, 10, &nhwqs); + if (rc) + return -EINVAL; + + if (nhwqs >= 1) + num_hwqs = nhwqs; + else if (nhwqs == 0) + num_hwqs = num_online_cpus(); + else + num_hwqs = num_online_cpus() / abs(nhwqs); + + afu->desired_hwqs = min(num_hwqs, CXLFLASH_MAX_HWQS); + WARN_ON_ONCE(afu->desired_hwqs == 0); + +retry: + switch (cfg->state) { + case STATE_NORMAL: + cfg->state = STATE_RESET; + drain_ioctls(cfg); + cxlflash_mark_contexts_error(cfg); + rc = afu_reset(cfg); + if (rc) + cfg->state = STATE_FAILTERM; + else + cfg->state = STATE_NORMAL; + wake_up_all(&cfg->reset_waitq); + break; + case STATE_RESET: + wait_event(cfg->reset_waitq, cfg->state != STATE_RESET); + if (cfg->state == STATE_NORMAL) + goto retry; + default: + /* Ideally should not happen */ + dev_err(dev, "%s: Device is not ready, state=%d\n", + __func__, cfg->state); + break; + } + + return count; +} + /** * mode_show() - presents the current mode of the device * @dev: Generic device associated with the device. @@ -2601,6 +2685,7 @@ static DEVICE_ATTR_RO(port1_lun_table); static DEVICE_ATTR_RO(port2_lun_table); static DEVICE_ATTR_RO(port3_lun_table); static DEVICE_ATTR_RW(irqpoll_weight); +static DEVICE_ATTR_RW(num_hwqs); static struct device_attribute *cxlflash_host_attrs[] = { &dev_attr_port0, @@ -2614,6 +2699,7 @@ static struct device_attribute *cxlflash_host_attrs[] = { &dev_attr_port2_lun_table, &dev_attr_port3_lun_table, &dev_attr_irqpoll_weight, + &dev_attr_num_hwqs, NULL }; -- cgit v1.2.3 From 1dd0c0e4fd02dc5e5bfaf89bd4656aabe4ae3cb3 Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 12 Apr 2017 14:16:02 -0500 Subject: scsi: cxlflash: Introduce hardware queue steering As an enhancement to distribute requests to multiple hardware queues, add the infrastructure to hash a SCSI command into a particular hardware queue. Support the following scenarios when deriving which queue to use: single queue, tagging when SCSI-MQ enabled, and simple hash via CPU ID when SCSI-MQ is disabled. Rather than altering the existing send API, the derived hardware queue is stored in the AFU command where it can be used for sending a command to the chosen hardware queue. Signed-off-by: Matthew R. Ochs Signed-off-by: Uma Krishnan Signed-off-by: Martin K. Petersen --- drivers/scsi/cxlflash/common.h | 12 ++++- drivers/scsi/cxlflash/main.c | 120 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 126 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/cxlflash/common.h b/drivers/scsi/cxlflash/common.h index 8fd7a1fa235e..256af819377d 100644 --- a/drivers/scsi/cxlflash/common.h +++ b/drivers/scsi/cxlflash/common.h @@ -96,6 +96,13 @@ enum cxlflash_state { STATE_FAILTERM /* Failed/terminating state, error out users/threads */ }; +enum cxlflash_hwq_mode { + HWQ_MODE_RR, /* Roundrobin (default) */ + HWQ_MODE_TAG, /* Distribute based on block MQ tag */ + HWQ_MODE_CPU, /* CPU affinity */ + MAX_HWQ_MODE +}; + /* * Each context has its own set of resource handles that is visible * only from that context. @@ -146,9 +153,9 @@ struct afu_cmd { struct scsi_cmnd *scp; struct completion cevent; struct list_head queue; + u32 hwq_index; u8 cmd_tmf:1; - u32 hwq_index; /* As per the SISLITE spec the IOARCB EA has to be 16-byte aligned. * However for performance reasons the IOARCB/IOASA should be @@ -213,8 +220,11 @@ struct afu { atomic_t cmds_active; /* Number of currently active AFU commands */ u64 hb; u32 internal_lun; /* User-desired LUN mode for this AFU */ + u32 num_hwqs; /* Number of hardware queues */ u32 desired_hwqs; /* Desired h/w queues, effective on AFU reset */ + enum cxlflash_hwq_mode hwq_mode; /* Steering mode for h/w queues */ + u32 hwq_rr_count; /* Count to distribute traffic for roundrobin */ char version[16]; u64 interface_version; diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index 113797aafd7e..a7d57c343492 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -357,6 +357,43 @@ static int wait_resp(struct afu *afu, struct afu_cmd *cmd) return rc; } +/** + * cmd_to_target_hwq() - selects a target hardware queue for a SCSI command + * @host: SCSI host associated with device. + * @scp: SCSI command to send. + * @afu: SCSI command to send. + * + * Hashes a command based upon the hardware queue mode. + * + * Return: Trusted index of target hardware queue + */ +static u32 cmd_to_target_hwq(struct Scsi_Host *host, struct scsi_cmnd *scp, + struct afu *afu) +{ + u32 tag; + u32 hwq = 0; + + if (afu->num_hwqs == 1) + return 0; + + switch (afu->hwq_mode) { + case HWQ_MODE_RR: + hwq = afu->hwq_rr_count++ % afu->num_hwqs; + break; + case HWQ_MODE_TAG: + tag = blk_mq_unique_tag(scp->request); + hwq = blk_mq_unique_tag_to_hwq(tag); + break; + case HWQ_MODE_CPU: + hwq = smp_processor_id() % afu->num_hwqs; + break; + default: + WARN_ON_ONCE(1); + } + + return hwq; +} + /** * send_tmf() - sends a Task Management Function (TMF) * @afu: AFU to checkout from. @@ -368,10 +405,12 @@ static int wait_resp(struct afu *afu, struct afu_cmd *cmd) */ static int send_tmf(struct afu *afu, struct scsi_cmnd *scp, u64 tmfcmd) { - struct cxlflash_cfg *cfg = shost_priv(scp->device->host); + struct Scsi_Host *host = scp->device->host; + struct cxlflash_cfg *cfg = shost_priv(host); struct afu_cmd *cmd = sc_to_afucz(scp); struct device *dev = &cfg->dev->dev; - struct hwq *hwq = get_hwq(afu, PRIMARY_HWQ); + int hwq_index = cmd_to_target_hwq(host, scp, afu); + struct hwq *hwq = get_hwq(afu, hwq_index); ulong lock_flags; int rc = 0; ulong to; @@ -388,7 +427,7 @@ static int send_tmf(struct afu *afu, struct scsi_cmnd *scp, u64 tmfcmd) cmd->scp = scp; cmd->parent = afu; cmd->cmd_tmf = true; - cmd->hwq_index = hwq->index; + cmd->hwq_index = hwq_index; cmd->rcb.ctx_id = hwq->ctx_hndl; cmd->rcb.msi = SISL_MSI_RRQ_UPDATED; @@ -448,7 +487,8 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp) struct device *dev = &cfg->dev->dev; struct afu_cmd *cmd = sc_to_afucz(scp); struct scatterlist *sg = scsi_sglist(scp); - struct hwq *hwq = get_hwq(afu, PRIMARY_HWQ); + int hwq_index = cmd_to_target_hwq(host, scp, afu); + struct hwq *hwq = get_hwq(afu, hwq_index); u16 req_flags = SISL_REQ_FLAGS_SUP_UNDERRUN; ulong lock_flags; int rc = 0; @@ -498,7 +538,7 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp) cmd->scp = scp; cmd->parent = afu; - cmd->hwq_index = hwq->index; + cmd->hwq_index = hwq_index; cmd->rcb.ctx_id = hwq->ctx_hndl; cmd->rcb.msi = SISL_MSI_RRQ_UPDATED; @@ -2654,6 +2694,74 @@ retry: return count; } +static const char *hwq_mode_name[MAX_HWQ_MODE] = { "rr", "tag", "cpu" }; + +/** + * hwq_mode_show() - presents the HWQ steering mode for the host + * @dev: Generic device associated with the host. + * @attr: Device attribute representing the HWQ steering mode. + * @buf: Buffer of length PAGE_SIZE to report back the HWQ steering mode + * as a character string. + * + * Return: The size of the ASCII string returned in @buf. + */ +static ssize_t hwq_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev)); + struct afu *afu = cfg->afu; + + return scnprintf(buf, PAGE_SIZE, "%s\n", hwq_mode_name[afu->hwq_mode]); +} + +/** + * hwq_mode_store() - sets the HWQ steering mode for the host + * @dev: Generic device associated with the host. + * @attr: Device attribute representing the HWQ steering mode. + * @buf: Buffer of length PAGE_SIZE containing the HWQ steering mode + * as a character string. + * @count: Length of data resizing in @buf. + * + * rr = Round-Robin + * tag = Block MQ Tagging + * cpu = CPU Affinity + * + * Return: The size of the ASCII string returned in @buf. + */ +static ssize_t hwq_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct cxlflash_cfg *cfg = shost_priv(shost); + struct device *cfgdev = &cfg->dev->dev; + struct afu *afu = cfg->afu; + int i; + u32 mode = MAX_HWQ_MODE; + + for (i = 0; i < MAX_HWQ_MODE; i++) { + if (!strncmp(hwq_mode_name[i], buf, strlen(hwq_mode_name[i]))) { + mode = i; + break; + } + } + + if (mode >= MAX_HWQ_MODE) { + dev_info(cfgdev, "Invalid HWQ steering mode.\n"); + return -EINVAL; + } + + if ((mode == HWQ_MODE_TAG) && !shost_use_blk_mq(shost)) { + dev_info(cfgdev, "SCSI-MQ is not enabled, use a different " + "HWQ steering mode.\n"); + return -EINVAL; + } + + afu->hwq_mode = mode; + + return count; +} + /** * mode_show() - presents the current mode of the device * @dev: Generic device associated with the device. @@ -2686,6 +2794,7 @@ static DEVICE_ATTR_RO(port2_lun_table); static DEVICE_ATTR_RO(port3_lun_table); static DEVICE_ATTR_RW(irqpoll_weight); static DEVICE_ATTR_RW(num_hwqs); +static DEVICE_ATTR_RW(hwq_mode); static struct device_attribute *cxlflash_host_attrs[] = { &dev_attr_port0, @@ -2700,6 +2809,7 @@ static struct device_attribute *cxlflash_host_attrs[] = { &dev_attr_port3_lun_table, &dev_attr_irqpoll_weight, &dev_attr_num_hwqs, + &dev_attr_hwq_mode, NULL }; -- cgit v1.2.3 From e04085285b829dc922e78768a9abb390a8caed31 Mon Sep 17 00:00:00 2001 From: Miguel Bernal Marin Date: Thu, 16 Mar 2017 00:58:23 -0600 Subject: scsi: storvsc: Prefer kcalloc over kzalloc with multiply Use kcalloc for allocating an array instead of kzalloc with multiply, kcalloc is the preferred API. Found with checkpatch. Signed-off-by: Miguel Bernal Marin Reviewed-by: K. Y. Srinivasan Signed-off-by: Martin K. Petersen --- drivers/scsi/storvsc_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index 638e5f427c90..3d70d1cf49a3 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -866,7 +866,7 @@ static int storvsc_channel_init(struct hv_device *device, bool is_fc) * We will however populate all the slots to evenly distribute * the load. */ - stor_device->stor_chns = kzalloc(sizeof(void *) * num_possible_cpus(), + stor_device->stor_chns = kcalloc(num_possible_cpus(), sizeof(void *), GFP_KERNEL); if (stor_device->stor_chns == NULL) return -ENOMEM; -- cgit v1.2.3 From 8d4208c1a73ab30e05da142e0f05b2b02fc26fc9 Mon Sep 17 00:00:00 2001 From: Miguel Bernal Marin Date: Thu, 16 Mar 2017 00:59:57 -0600 Subject: scsi: storvsc: remove return at end of void function storvsc_on_channel_callback is a void function and the return statement at the end is not useful. Found with checkpatch. Signed-off-by: Miguel Bernal Marin Reviewed-by: K. Y. Srinivasan Signed-off-by: Martin K. Petersen --- drivers/scsi/storvsc_drv.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index 3d70d1cf49a3..538f3e131275 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -1191,8 +1191,6 @@ static void storvsc_on_channel_callback(void *context) break; } } while (1); - - return; } static int storvsc_connect_to_vsp(struct hv_device *device, u32 ring_size, -- cgit v1.2.3 From 5c66d9393f583778e8dc1ee6a69c5bbe9ab28eaa Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 10 Apr 2017 12:15:13 +1000 Subject: scsi: ibmvfc: don't check for failure from mempool_alloc() mempool_alloc() cannot fail when passed GFP_NOIO or any other gfp setting that is permitted to sleep. So remove this pointless code. Signed-off-by: NeilBrown Acked-by: Tyrel Datwyler Signed-off-by: Martin K. Petersen --- drivers/scsi/ibmvscsi/ibmvfc.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c index 2c92dabb55f6..26cd3c28186a 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.c +++ b/drivers/scsi/ibmvscsi/ibmvfc.c @@ -3910,12 +3910,6 @@ static int ibmvfc_alloc_target(struct ibmvfc_host *vhost, u64 scsi_id) spin_unlock_irqrestore(vhost->host->host_lock, flags); tgt = mempool_alloc(vhost->tgt_pool, GFP_NOIO); - if (!tgt) { - dev_err(vhost->dev, "Target allocation failure for scsi id %08llx\n", - scsi_id); - return -ENOMEM; - } - memset(tgt, 0, sizeof(*tgt)); tgt->scsi_id = scsi_id; tgt->new_scsi_id = scsi_id; -- cgit v1.2.3 From eea422709fd89aec27be408f451557ebedd19f11 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 14 Apr 2017 14:58:02 +0100 Subject: scsi: fc: remove redundant check of an unsigned long being less than zero The check for an unsigned long being less than zero is always false so it is a redundant check and can be removed. Detected by static analysis with by PVS-Studio Signed-off-by: Colin Ian King Reviewed-by: Tyrel Datwyler Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_transport_fc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index 2d753c93e07a..87b8f9d64d9b 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -850,7 +850,7 @@ static int fc_str_to_dev_loss(const char *buf, unsigned long *val) char *cp; *val = simple_strtoul(buf, &cp, 0); - if ((*cp && (*cp != '\n')) || (*val < 0)) + if (*cp && (*cp != '\n')) return -EINVAL; /* * Check for overflow; dev_loss_tmo is u32 -- cgit v1.2.3 From cb22bdc8cd5a7a4fdb9a02a64a29bb81a95e6738 Mon Sep 17 00:00:00 2001 From: Varun Prakash Date: Mon, 17 Apr 2017 21:32:41 +0530 Subject: scsi: cxgb4i: update module description Signed-off-by: Varun Prakash Signed-off-by: Martin K. Petersen --- drivers/scsi/cxgbi/cxgb4i/cxgb4i.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c index 3fb3f5708ff7..1076c1578322 100644 --- a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c +++ b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c @@ -36,7 +36,7 @@ static unsigned int dbg_level; #include "../libcxgbi.h" #define DRV_MODULE_NAME "cxgb4i" -#define DRV_MODULE_DESC "Chelsio T4/T5 iSCSI Driver" +#define DRV_MODULE_DESC "Chelsio T4-T6 iSCSI Driver" #define DRV_MODULE_VERSION "0.9.5-ko" #define DRV_MODULE_RELDATE "Apr. 2015" -- cgit v1.2.3 From ea98ab34c4339bc638fa394bf1bf0c6863fa88f4 Mon Sep 17 00:00:00 2001 From: Maurizio Lombardi Date: Tue, 18 Apr 2017 11:55:51 +0200 Subject: scsi: lpfc: fix potential buffer overflow. This patch fixes a potential buffer overflow in lpfc_nvme_info_show(). Signed-off-by: Maurizio Lombardi Reviewed-by: Ewan D. Milne Acked-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_attr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 5c783ef7f260..7c2801b04e18 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -181,7 +181,7 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr, wwn_to_u64(vport->fc_nodename.u.wwn), phba->targetport->port_id); - len += snprintf(buf + len, PAGE_SIZE, + len += snprintf(buf + len, PAGE_SIZE - len, "\nNVME Target: Statistics\n"); tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private; len += snprintf(buf+len, PAGE_SIZE-len, @@ -326,7 +326,7 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr, } spin_unlock_irq(shost->host_lock); - len += snprintf(buf + len, PAGE_SIZE, "\nNVME Statistics\n"); + len += snprintf(buf + len, PAGE_SIZE - len, "\nNVME Statistics\n"); len += snprintf(buf+len, PAGE_SIZE-len, "LS: Xmt %016llx Cmpl %016llx\n", phba->fc4NvmeLsRequests, -- cgit v1.2.3 From 25d1d50e23275e141e3a3fe06c25a99f4c4bf4e0 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 13 Apr 2017 12:13:00 +1000 Subject: scsi: virtio_scsi: Always try to read VPD pages Passed through SCSI targets may have transfer limits which come from the host SCSI controller or something on the host side other than the target itself. To make this work properly, the hypervisor can adjust the target's VPD information to advertise these limits. But for that to work, the guest has to look at the VPD pages, which we won't do by default if it is an SPC-2 device, even if it does actually support it. This adds a workaround to address this, forcing devices attached to a virtio-scsi controller to always check the VPD pages. This is modelled on a similar workaround for the storvsc (Hyper-V) SCSI controller, although that exists for slightly different reasons. A specific case which causes this is a volume from IBM's IPR RAID controller (which presents as an SPC-2 device, although it does support VPD) passed through with qemu's 'scsi-block' device. [mkp: fixed typo] Signed-off-by: David Gibson Acked-by: Paolo Bonzini Signed-off-by: Martin K. Petersen --- drivers/scsi/virtio_scsi.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c index 939c47df73fa..a29d068b7696 100644 --- a/drivers/scsi/virtio_scsi.c +++ b/drivers/scsi/virtio_scsi.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -705,6 +706,28 @@ static int virtscsi_device_reset(struct scsi_cmnd *sc) return virtscsi_tmf(vscsi, cmd); } +static int virtscsi_device_alloc(struct scsi_device *sdevice) +{ + /* + * Passed through SCSI targets (e.g. with qemu's 'scsi-block') + * may have transfer limits which come from the host SCSI + * controller or something on the host side other than the + * target itself. + * + * To make this work properly, the hypervisor can adjust the + * target's VPD information to advertise these limits. But + * for that to work, the guest has to look at the VPD pages, + * which we won't do by default if it is an SPC-2 device, even + * if it does actually support it. + * + * So, set the blist to always try to read the VPD pages. + */ + sdevice->sdev_bflags = BLIST_TRY_VPD_PAGES; + + return 0; +} + + /** * virtscsi_change_queue_depth() - Change a virtscsi target's queue depth * @sdev: Virtscsi target whose queue depth to change @@ -783,6 +806,7 @@ static struct scsi_host_template virtscsi_host_template_single = { .change_queue_depth = virtscsi_change_queue_depth, .eh_abort_handler = virtscsi_abort, .eh_device_reset_handler = virtscsi_device_reset, + .slave_alloc = virtscsi_device_alloc, .can_queue = 1024, .dma_boundary = UINT_MAX, -- cgit v1.2.3 From 0c3ae2664766ec892992a686e48ead94784ef54c Mon Sep 17 00:00:00 2001 From: Cathy Avery Date: Mon, 17 Apr 2017 14:37:45 -0400 Subject: scsi: scsi_transport_fc: Add dummy initiator role to rport This patch allows scsi drivers that expose virturalized fibre channel devices but that do not expose rports to successfully rescan the scsi bus via echo "- - -" > /sys/class/scsi_host/hostX/scan. Drivers can create a pseudo rport and indicate FC_PORT_ROLE_FCP_DUMMY_INITIATOR as the rport's role in fc_rport_identifiers. This insures that a valid scsi_target_id is assigned to the newly created rport and it can meet the requirements of fc_user_scan_tgt calling scsi_scan_target. Signed-off-by: Cathy Avery Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_transport_fc.c | 10 ++++++---- include/scsi/scsi_transport_fc.h | 1 + 2 files changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index 87b8f9d64d9b..d4cf32d55546 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -289,9 +289,10 @@ static const struct { u32 value; char *name; } fc_port_role_names[] = { - { FC_PORT_ROLE_FCP_TARGET, "FCP Target" }, - { FC_PORT_ROLE_FCP_INITIATOR, "FCP Initiator" }, - { FC_PORT_ROLE_IP_PORT, "IP Port" }, + { FC_PORT_ROLE_FCP_TARGET, "FCP Target" }, + { FC_PORT_ROLE_FCP_INITIATOR, "FCP Initiator" }, + { FC_PORT_ROLE_IP_PORT, "IP Port" }, + { FC_PORT_ROLE_FCP_DUMMY_INITIATOR, "FCP Dummy Initiator" }, }; fc_bitfield_name_search(port_roles, fc_port_role_names) @@ -2628,7 +2629,8 @@ fc_remote_port_create(struct Scsi_Host *shost, int channel, spin_lock_irqsave(shost->host_lock, flags); rport->number = fc_host->next_rport_number++; - if (rport->roles & FC_PORT_ROLE_FCP_TARGET) + if ((rport->roles & FC_PORT_ROLE_FCP_TARGET) || + (rport->roles & FC_PORT_ROLE_FCP_DUMMY_INITIATOR)) rport->scsi_target_id = fc_host->next_target_id++; else rport->scsi_target_id = -1; diff --git a/include/scsi/scsi_transport_fc.h b/include/scsi/scsi_transport_fc.h index b21b8aa58c4d..6e208bb32c78 100644 --- a/include/scsi/scsi_transport_fc.h +++ b/include/scsi/scsi_transport_fc.h @@ -162,6 +162,7 @@ enum fc_tgtid_binding_type { #define FC_PORT_ROLE_FCP_TARGET 0x01 #define FC_PORT_ROLE_FCP_INITIATOR 0x02 #define FC_PORT_ROLE_IP_PORT 0x04 +#define FC_PORT_ROLE_FCP_DUMMY_INITIATOR 0x08 /* The following are for compatibility */ #define FC_RPORT_ROLE_UNKNOWN FC_PORT_ROLE_UNKNOWN -- cgit v1.2.3 From daf0cd445a218314f9461d67d4f2b9c24cdd534b Mon Sep 17 00:00:00 2001 From: Cathy Avery Date: Mon, 17 Apr 2017 14:37:46 -0400 Subject: scsi: storvsc: Add support for FC rport. Included in the current storvsc driver for Hyper-V is the ability to access luns on an FC fabric via a virtualized fiber channel adapter exposed by the Hyper-V host. The driver also attaches to the FC transport to allow host and port names to be published under /sys/class/fc_host/hostX. Current customer tools running on the VM require that these names be available in the well known standard location under fc_host/hostX. This patch stubs in an rport per fc_host and sets its rport role as FC_PORT_ROLE_FCP_DUMMY_INITIATOR to indicate to the fc_transport that it is a pseudo rport in order to scan the scsi stack via echo "- - -" > /sys/class/scsi_host/hostX/scan. Signed-off-by: Cathy Avery Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/storvsc_drv.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index 538f3e131275..b2183415b9ee 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -478,6 +478,9 @@ struct storvsc_device { */ u64 node_name; u64 port_name; +#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS) + struct fc_rport *rport; +#endif }; struct hv_host_device { @@ -1814,19 +1817,27 @@ static int storvsc_probe(struct hv_device *device, target = (device->dev_instance.b[5] << 8 | device->dev_instance.b[4]); ret = scsi_add_device(host, 0, target, 0); - if (ret) { - scsi_remove_host(host); - goto err_out2; - } + if (ret) + goto err_out3; } #if IS_ENABLED(CONFIG_SCSI_FC_ATTRS) if (host->transportt == fc_transport_template) { + struct fc_rport_identifiers ids = { + .roles = FC_PORT_ROLE_FCP_DUMMY_INITIATOR, + }; + fc_host_node_name(host) = stor_device->node_name; fc_host_port_name(host) = stor_device->port_name; + stor_device->rport = fc_remote_port_add(host, 0, &ids); + if (!stor_device->rport) + goto err_out3; } #endif return 0; +err_out3: + scsi_remove_host(host); + err_out2: /* * Once we have connected with the host, we would need to @@ -1852,8 +1863,10 @@ static int storvsc_remove(struct hv_device *dev) struct Scsi_Host *host = stor_device->host; #if IS_ENABLED(CONFIG_SCSI_FC_ATTRS) - if (host->transportt == fc_transport_template) + if (host->transportt == fc_transport_template) { + fc_remote_port_delete(stor_device->rport); fc_remove_host(host); + } #endif scsi_remove_host(host); storvsc_dev_remove(dev); -- cgit v1.2.3 From efacae6d4c095a5a99a012713089def1c5ad8906 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 29 Mar 2017 13:59:23 -0700 Subject: scsi: qedi: qedf: Use designated initializers Prepare to mark sensitive kernel structures for randomization by making sure they're using designated initializers. These were identified during allyesconfig builds of x86, arm, and arm64, with most initializer fixes extracted from grsecurity. For these cases, terminate the list with { }, which will be zero-filled, instead of undesignated NULLs. Signed-off-by: Kees Cook Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/qedf/qedf_debugfs.c | 2 +- drivers/scsi/qedi/qedi_debugfs.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qedf/qedf_debugfs.c b/drivers/scsi/qedf/qedf_debugfs.c index cb08b625c594..00a1d6405ebe 100644 --- a/drivers/scsi/qedf/qedf_debugfs.c +++ b/drivers/scsi/qedf/qedf_debugfs.c @@ -449,7 +449,7 @@ const struct file_operations qedf_dbg_fops[] = { qedf_dbg_fileops(qedf, clear_stats), qedf_dbg_fileops_seq(qedf, offload_stats), /* This must be last */ - { NULL, NULL }, + { }, }; #else /* CONFIG_DEBUG_FS */ diff --git a/drivers/scsi/qedi/qedi_debugfs.c b/drivers/scsi/qedi/qedi_debugfs.c index 955936274241..b064c882411c 100644 --- a/drivers/scsi/qedi/qedi_debugfs.c +++ b/drivers/scsi/qedi/qedi_debugfs.c @@ -240,5 +240,5 @@ const struct file_operations qedi_dbg_fops[] = { qedi_dbg_fileops_seq(qedi, gbl_ctx), qedi_dbg_fileops(qedi, do_not_recover), qedi_dbg_fileops_seq(qedi, io_trace), - { NULL, NULL }, + { }, }; -- cgit v1.2.3 From c7c3524ce79e275dd3042de5045d7a10245d3888 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 13 Apr 2017 10:02:56 +0200 Subject: scsi: bfa: remove bfa_module_s madness Just call the functions directly and remove a giant pile of boilerplate code. Signed-off-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/bfa/bfa_core.c | 66 ++++++++-------- drivers/scsi/bfa/bfa_fcpim.c | 37 ++------- drivers/scsi/bfa/bfa_ioc.c | 30 ++----- drivers/scsi/bfa/bfa_modules.h | 101 +++++++++++------------- drivers/scsi/bfa/bfa_svc.c | 172 +++++------------------------------------ 5 files changed, 108 insertions(+), 298 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/bfa/bfa_core.c b/drivers/scsi/bfa/bfa_core.c index 7209afad82f7..3e1caec82554 100644 --- a/drivers/scsi/bfa/bfa_core.c +++ b/drivers/scsi/bfa/bfa_core.c @@ -22,22 +22,6 @@ BFA_TRC_FILE(HAL, CORE); -/* - * BFA module list terminated by NULL - */ -static struct bfa_module_s *hal_mods[] = { - &hal_mod_fcdiag, - &hal_mod_sgpg, - &hal_mod_fcport, - &hal_mod_fcxp, - &hal_mod_lps, - &hal_mod_uf, - &hal_mod_rport, - &hal_mod_fcp, - &hal_mod_dconf, - NULL -}; - /* * Message handlers for various modules. */ @@ -1191,8 +1175,13 @@ bfa_iocfc_start_submod(struct bfa_s *bfa) for (i = 0; i < BFI_IOC_MAX_CQS; i++) bfa_isr_rspq_ack(bfa, i, bfa_rspq_ci(bfa, i)); - for (i = 0; hal_mods[i]; i++) - hal_mods[i]->start(bfa); + bfa_fcport_start(bfa); + bfa_uf_start(bfa); + /* + * bfa_init() with flash read is complete. now invalidate the stale + * content of lun mask like unit attention, rp tag and lp tag. + */ + bfa_ioim_lm_init(BFA_FCP_MOD(bfa)->bfa); bfa->iocfc.submod_enabled = BFA_TRUE; } @@ -1203,13 +1192,16 @@ bfa_iocfc_start_submod(struct bfa_s *bfa) static void bfa_iocfc_disable_submod(struct bfa_s *bfa) { - int i; - if (bfa->iocfc.submod_enabled == BFA_FALSE) return; - for (i = 0; hal_mods[i]; i++) - hal_mods[i]->iocdisable(bfa); + bfa_fcdiag_iocdisable(bfa); + bfa_fcport_iocdisable(bfa); + bfa_fcxp_iocdisable(bfa); + bfa_lps_iocdisable(bfa); + bfa_rport_iocdisable(bfa); + bfa_fcp_iocdisable(bfa); + bfa_dconf_iocdisable(bfa); bfa->iocfc.submod_enabled = BFA_FALSE; } @@ -1773,7 +1765,6 @@ void bfa_cfg_get_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo, struct bfa_s *bfa) { - int i; struct bfa_mem_dma_s *port_dma = BFA_MEM_PORT_DMA(bfa); struct bfa_mem_dma_s *ablk_dma = BFA_MEM_ABLK_DMA(bfa); struct bfa_mem_dma_s *cee_dma = BFA_MEM_CEE_DMA(bfa); @@ -1792,9 +1783,14 @@ bfa_cfg_get_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo, INIT_LIST_HEAD(&meminfo->kva_info.qe); bfa_iocfc_meminfo(cfg, meminfo, bfa); - - for (i = 0; hal_mods[i]; i++) - hal_mods[i]->meminfo(cfg, meminfo, bfa); + bfa_sgpg_meminfo(cfg, meminfo, bfa); + bfa_fcport_meminfo(cfg, meminfo, bfa); + bfa_fcxp_meminfo(cfg, meminfo, bfa); + bfa_lps_meminfo(cfg, meminfo, bfa); + bfa_uf_meminfo(cfg, meminfo, bfa); + bfa_rport_meminfo(cfg, meminfo, bfa); + bfa_fcp_meminfo(cfg, meminfo, bfa); + bfa_dconf_meminfo(cfg, meminfo, bfa); /* dma info setup */ bfa_mem_dma_setup(meminfo, port_dma, bfa_port_meminfo()); @@ -1840,7 +1836,6 @@ void bfa_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev) { - int i; struct bfa_mem_dma_s *dma_info, *dma_elem; struct bfa_mem_kva_s *kva_info, *kva_elem; struct list_head *dm_qe, *km_qe; @@ -1869,10 +1864,15 @@ bfa_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, } bfa_iocfc_attach(bfa, bfad, cfg, pcidev); - - for (i = 0; hal_mods[i]; i++) - hal_mods[i]->attach(bfa, bfad, cfg, pcidev); - + bfa_fcdiag_attach(bfa, bfad, cfg, pcidev); + bfa_sgpg_attach(bfa, bfad, cfg, pcidev); + bfa_fcport_attach(bfa, bfad, cfg, pcidev); + bfa_fcxp_attach(bfa, bfad, cfg, pcidev); + bfa_lps_attach(bfa, bfad, cfg, pcidev); + bfa_uf_attach(bfa, bfad, cfg, pcidev); + bfa_rport_attach(bfa, bfad, cfg, pcidev); + bfa_fcp_attach(bfa, bfad, cfg, pcidev); + bfa_dconf_attach(bfa, bfad, cfg); bfa_com_port_attach(bfa); bfa_com_ablk_attach(bfa); bfa_com_cee_attach(bfa); @@ -1899,10 +1899,6 @@ bfa_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, void bfa_detach(struct bfa_s *bfa) { - int i; - - for (i = 0; hal_mods[i]; i++) - hal_mods[i]->detach(bfa); bfa_ioc_detach(&bfa->ioc); } diff --git a/drivers/scsi/bfa/bfa_fcpim.c b/drivers/scsi/bfa/bfa_fcpim.c index 20982e7cdd81..5f53b3276234 100644 --- a/drivers/scsi/bfa/bfa_fcpim.c +++ b/drivers/scsi/bfa/bfa_fcpim.c @@ -25,7 +25,6 @@ BFA_TRC_FILE(HAL, FCPIM); * BFA ITNIM Related definitions */ static void bfa_itnim_update_del_itn_stats(struct bfa_itnim_s *itnim); -static void bfa_ioim_lm_init(struct bfa_s *bfa); #define BFA_ITNIM_FROM_TAG(_fcpim, _tag) \ (((_fcpim)->itnim_arr + ((_tag) & ((_fcpim)->num_itnims - 1)))) @@ -339,7 +338,7 @@ bfa_fcpim_attach(struct bfa_fcp_mod_s *fcp, void *bfad, bfa_ioim_attach(fcpim); } -static void +void bfa_fcpim_iocdisable(struct bfa_fcp_mod_s *fcp) { struct bfa_fcpim_s *fcpim = &fcp->fcpim; @@ -2105,7 +2104,7 @@ bfa_ioim_sm_resfree(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) * is complete by driver. now invalidate the stale content of lun mask * like unit attention, rp tag and lp tag. */ -static void +void bfa_ioim_lm_init(struct bfa_s *bfa) { struct bfa_lun_mask_s *lunm_list; @@ -3634,11 +3633,7 @@ bfa_tskim_res_recfg(struct bfa_s *bfa, u16 num_tskim_fw) } } -/* BFA FCP module - parent module for fcpim */ - -BFA_MODULE(fcp); - -static void +void bfa_fcp_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *minfo, struct bfa_s *bfa) { @@ -3696,7 +3691,7 @@ bfa_fcp_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *minfo, bfa_mem_kva_setup(minfo, fcp_kva, km_len); } -static void +void bfa_fcp_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, struct bfa_pcidev_s *pcidev) { @@ -3739,29 +3734,7 @@ bfa_fcp_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, (fcp->num_itns * sizeof(struct bfa_itn_s))); } -static void -bfa_fcp_detach(struct bfa_s *bfa) -{ -} - -static void -bfa_fcp_start(struct bfa_s *bfa) -{ - struct bfa_fcp_mod_s *fcp = BFA_FCP_MOD(bfa); - - /* - * bfa_init() with flash read is complete. now invalidate the stale - * content of lun mask like unit attention, rp tag and lp tag. - */ - bfa_ioim_lm_init(fcp->bfa); -} - -static void -bfa_fcp_stop(struct bfa_s *bfa) -{ -} - -static void +void bfa_fcp_iocdisable(struct bfa_s *bfa) { struct bfa_fcp_mod_s *fcp = BFA_FCP_MOD(bfa); diff --git a/drivers/scsi/bfa/bfa_ioc.c b/drivers/scsi/bfa/bfa_ioc.c index a1ada4a31c97..256f4afaccf9 100644 --- a/drivers/scsi/bfa/bfa_ioc.c +++ b/drivers/scsi/bfa/bfa_ioc.c @@ -5821,12 +5821,6 @@ bfa_phy_intr(void *phyarg, struct bfi_mbmsg_s *msg) } } -/* - * DCONF module specific - */ - -BFA_MODULE(dconf); - /* * DCONF state machine events */ @@ -6073,7 +6067,7 @@ bfa_dconf_sm_iocdown_dirty(struct bfa_dconf_mod_s *dconf, /* * Compute and return memory needed by DRV_CFG module. */ -static void +void bfa_dconf_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo, struct bfa_s *bfa) { @@ -6087,9 +6081,8 @@ bfa_dconf_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo, sizeof(struct bfa_dconf_s)); } -static void -bfa_dconf_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, - struct bfa_pcidev_s *pcidev) +void +bfa_dconf_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg) { struct bfa_dconf_mod_s *dconf = BFA_DCONF_MOD(bfa); @@ -6134,33 +6127,20 @@ bfa_dconf_modinit(struct bfa_s *bfa) struct bfa_dconf_mod_s *dconf = BFA_DCONF_MOD(bfa); bfa_sm_send_event(dconf, BFA_DCONF_SM_INIT); } -static void -bfa_dconf_start(struct bfa_s *bfa) -{ -} - -static void -bfa_dconf_stop(struct bfa_s *bfa) -{ -} static void bfa_dconf_timer(void *cbarg) { struct bfa_dconf_mod_s *dconf = cbarg; bfa_sm_send_event(dconf, BFA_DCONF_SM_TIMEOUT); } -static void + +void bfa_dconf_iocdisable(struct bfa_s *bfa) { struct bfa_dconf_mod_s *dconf = BFA_DCONF_MOD(bfa); bfa_sm_send_event(dconf, BFA_DCONF_SM_IOCDISABLE); } -static void -bfa_dconf_detach(struct bfa_s *bfa) -{ -} - static bfa_status_t bfa_dconf_flash_write(struct bfa_dconf_mod_s *dconf) { diff --git a/drivers/scsi/bfa/bfa_modules.h b/drivers/scsi/bfa/bfa_modules.h index 53135f21fa0e..1c2ab395e616 100644 --- a/drivers/scsi/bfa/bfa_modules.h +++ b/drivers/scsi/bfa/bfa_modules.h @@ -61,54 +61,8 @@ enum { BFA_TRC_HAL_IOCFC_CB = 5, }; -/* - * Macro to define a new BFA module - */ -#define BFA_MODULE(__mod) \ - static void bfa_ ## __mod ## _meminfo( \ - struct bfa_iocfc_cfg_s *cfg, \ - struct bfa_meminfo_s *meminfo, \ - struct bfa_s *bfa); \ - static void bfa_ ## __mod ## _attach(struct bfa_s *bfa, \ - void *bfad, struct bfa_iocfc_cfg_s *cfg, \ - struct bfa_pcidev_s *pcidev); \ - static void bfa_ ## __mod ## _detach(struct bfa_s *bfa); \ - static void bfa_ ## __mod ## _start(struct bfa_s *bfa); \ - static void bfa_ ## __mod ## _stop(struct bfa_s *bfa); \ - static void bfa_ ## __mod ## _iocdisable(struct bfa_s *bfa); \ - \ - extern struct bfa_module_s hal_mod_ ## __mod; \ - struct bfa_module_s hal_mod_ ## __mod = { \ - bfa_ ## __mod ## _meminfo, \ - bfa_ ## __mod ## _attach, \ - bfa_ ## __mod ## _detach, \ - bfa_ ## __mod ## _start, \ - bfa_ ## __mod ## _stop, \ - bfa_ ## __mod ## _iocdisable, \ - } - #define BFA_CACHELINE_SZ (256) -/* - * Structure used to interact between different BFA sub modules - * - * Each sub module needs to implement only the entry points relevant to it (and - * can leave entry points as NULL) - */ -struct bfa_module_s { - void (*meminfo) (struct bfa_iocfc_cfg_s *cfg, - struct bfa_meminfo_s *meminfo, - struct bfa_s *bfa); - void (*attach) (struct bfa_s *bfa, void *bfad, - struct bfa_iocfc_cfg_s *cfg, - struct bfa_pcidev_s *pcidev); - void (*detach) (struct bfa_s *bfa); - void (*start) (struct bfa_s *bfa); - void (*stop) (struct bfa_s *bfa); - void (*iocdisable) (struct bfa_s *bfa); -}; - - struct bfa_s { void *bfad; /* BFA driver instance */ struct bfa_plog_s *plog; /* portlog buffer */ @@ -127,14 +81,51 @@ struct bfa_s { }; extern bfa_boolean_t bfa_auto_recover; -extern struct bfa_module_s hal_mod_fcdiag; -extern struct bfa_module_s hal_mod_sgpg; -extern struct bfa_module_s hal_mod_fcport; -extern struct bfa_module_s hal_mod_fcxp; -extern struct bfa_module_s hal_mod_lps; -extern struct bfa_module_s hal_mod_uf; -extern struct bfa_module_s hal_mod_rport; -extern struct bfa_module_s hal_mod_fcp; -extern struct bfa_module_s hal_mod_dconf; + +void bfa_dconf_attach(struct bfa_s *, void *, struct bfa_iocfc_cfg_s *); +void bfa_dconf_meminfo(struct bfa_iocfc_cfg_s *, struct bfa_meminfo_s *, + struct bfa_s *); +void bfa_dconf_iocdisable(struct bfa_s *); +void bfa_fcp_attach(struct bfa_s *, void *, struct bfa_iocfc_cfg_s *, + struct bfa_pcidev_s *); +void bfa_fcp_iocdisable(struct bfa_s *bfa); +void bfa_fcp_meminfo(struct bfa_iocfc_cfg_s *, struct bfa_meminfo_s *, + struct bfa_s *); +void bfa_fcpim_iocdisable(struct bfa_fcp_mod_s *); +void bfa_fcport_start(struct bfa_s *); +void bfa_fcport_iocdisable(struct bfa_s *); +void bfa_fcport_meminfo(struct bfa_iocfc_cfg_s *, struct bfa_meminfo_s *, + struct bfa_s *); +void bfa_fcport_attach(struct bfa_s *, void *, struct bfa_iocfc_cfg_s *, + struct bfa_pcidev_s *); +void bfa_fcxp_iocdisable(struct bfa_s *); +void bfa_fcxp_meminfo(struct bfa_iocfc_cfg_s *, struct bfa_meminfo_s *, + struct bfa_s *); +void bfa_fcxp_attach(struct bfa_s *, void *, struct bfa_iocfc_cfg_s *, + struct bfa_pcidev_s *); +void bfa_fcdiag_iocdisable(struct bfa_s *); +void bfa_fcdiag_attach(struct bfa_s *bfa, void *, struct bfa_iocfc_cfg_s *, + struct bfa_pcidev_s *); +void bfa_ioim_lm_init(struct bfa_s *); +void bfa_lps_iocdisable(struct bfa_s *bfa); +void bfa_lps_meminfo(struct bfa_iocfc_cfg_s *, struct bfa_meminfo_s *, + struct bfa_s *); +void bfa_lps_attach(struct bfa_s *, void *, struct bfa_iocfc_cfg_s *, + struct bfa_pcidev_s *); +void bfa_rport_iocdisable(struct bfa_s *bfa); +void bfa_rport_meminfo(struct bfa_iocfc_cfg_s *, struct bfa_meminfo_s *, + struct bfa_s *); +void bfa_rport_attach(struct bfa_s *, void *, struct bfa_iocfc_cfg_s *, + struct bfa_pcidev_s *); +void bfa_sgpg_meminfo(struct bfa_iocfc_cfg_s *, struct bfa_meminfo_s *, + struct bfa_s *); +void bfa_sgpg_attach(struct bfa_s *, void *bfad, struct bfa_iocfc_cfg_s *, + struct bfa_pcidev_s *); +void bfa_uf_iocdisable(struct bfa_s *); +void bfa_uf_meminfo(struct bfa_iocfc_cfg_s *, struct bfa_meminfo_s *, + struct bfa_s *); +void bfa_uf_attach(struct bfa_s *, void *, struct bfa_iocfc_cfg_s *, + struct bfa_pcidev_s *); +void bfa_uf_start(struct bfa_s *); #endif /* __BFA_MODULES_H__ */ diff --git a/drivers/scsi/bfa/bfa_svc.c b/drivers/scsi/bfa/bfa_svc.c index 12de292175ef..e640223bab3c 100644 --- a/drivers/scsi/bfa/bfa_svc.c +++ b/drivers/scsi/bfa/bfa_svc.c @@ -23,13 +23,6 @@ #include "bfa_modules.h" BFA_TRC_FILE(HAL, FCXP); -BFA_MODULE(fcdiag); -BFA_MODULE(fcxp); -BFA_MODULE(sgpg); -BFA_MODULE(lps); -BFA_MODULE(fcport); -BFA_MODULE(rport); -BFA_MODULE(uf); /* * LPS related definitions @@ -121,15 +114,6 @@ static void bfa_fcxp_queue(struct bfa_fcxp_s *fcxp, /* * forward declarations for LPS functions */ -static void bfa_lps_meminfo(struct bfa_iocfc_cfg_s *cfg, - struct bfa_meminfo_s *minfo, struct bfa_s *bfa); -static void bfa_lps_attach(struct bfa_s *bfa, void *bfad, - struct bfa_iocfc_cfg_s *cfg, - struct bfa_pcidev_s *pcidev); -static void bfa_lps_detach(struct bfa_s *bfa); -static void bfa_lps_start(struct bfa_s *bfa); -static void bfa_lps_stop(struct bfa_s *bfa); -static void bfa_lps_iocdisable(struct bfa_s *bfa); static void bfa_lps_login_rsp(struct bfa_s *bfa, struct bfi_lps_login_rsp_s *rsp); static void bfa_lps_no_res(struct bfa_lps_s *first_lps, u8 count); @@ -484,7 +468,7 @@ claim_fcxps_mem(struct bfa_fcxp_mod_s *mod) bfa_mem_kva_curp(mod) = (void *)fcxp; } -static void +void bfa_fcxp_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *minfo, struct bfa_s *bfa) { @@ -522,7 +506,7 @@ bfa_fcxp_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *minfo, cfg->fwcfg.num_fcxp_reqs * sizeof(struct bfa_fcxp_s)); } -static void +void bfa_fcxp_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, struct bfa_pcidev_s *pcidev) { @@ -544,22 +528,7 @@ bfa_fcxp_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, claim_fcxps_mem(mod); } -static void -bfa_fcxp_detach(struct bfa_s *bfa) -{ -} - -static void -bfa_fcxp_start(struct bfa_s *bfa) -{ -} - -static void -bfa_fcxp_stop(struct bfa_s *bfa) -{ -} - -static void +void bfa_fcxp_iocdisable(struct bfa_s *bfa) { struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa); @@ -1510,7 +1479,7 @@ bfa_lps_sm_logowait(struct bfa_lps_s *lps, enum bfa_lps_event event) /* * return memory requirement */ -static void +void bfa_lps_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *minfo, struct bfa_s *bfa) { @@ -1527,7 +1496,7 @@ bfa_lps_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *minfo, /* * bfa module attach at initialization time */ -static void +void bfa_lps_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, struct bfa_pcidev_s *pcidev) { @@ -1557,25 +1526,10 @@ bfa_lps_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, } } -static void -bfa_lps_detach(struct bfa_s *bfa) -{ -} - -static void -bfa_lps_start(struct bfa_s *bfa) -{ -} - -static void -bfa_lps_stop(struct bfa_s *bfa) -{ -} - /* * IOC in disabled state -- consider all lps offline */ -static void +void bfa_lps_iocdisable(struct bfa_s *bfa) { struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa); @@ -3055,7 +3009,7 @@ bfa_fcport_queue_cb(struct bfa_fcport_ln_s *ln, enum bfa_port_linkstate event) #define FCPORT_STATS_DMA_SZ (BFA_ROUNDUP(sizeof(union bfa_fcport_stats_u), \ BFA_CACHELINE_SZ)) -static void +void bfa_fcport_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *minfo, struct bfa_s *bfa) { @@ -3086,7 +3040,7 @@ bfa_fcport_mem_claim(struct bfa_fcport_s *fcport) /* * Memory initialization. */ -static void +void bfa_fcport_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, struct bfa_pcidev_s *pcidev) { @@ -3131,34 +3085,16 @@ bfa_fcport_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, bfa_reqq_winit(&fcport->reqq_wait, bfa_fcport_qresume, fcport); } -static void -bfa_fcport_detach(struct bfa_s *bfa) -{ -} - -/* - * Called when IOC is ready. - */ -static void +void bfa_fcport_start(struct bfa_s *bfa) { bfa_sm_send_event(BFA_FCPORT_MOD(bfa), BFA_FCPORT_SM_START); } -/* - * Called before IOC is stopped. - */ -static void -bfa_fcport_stop(struct bfa_s *bfa) -{ - bfa_sm_send_event(BFA_FCPORT_MOD(bfa), BFA_FCPORT_SM_STOP); - bfa_trunk_iocdisable(bfa); -} - /* * Called when IOC failure is detected. */ -static void +void bfa_fcport_iocdisable(struct bfa_s *bfa) { struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); @@ -4886,7 +4822,7 @@ bfa_rport_qresume(void *cbarg) bfa_sm_send_event(rp, BFA_RPORT_SM_QRESUME); } -static void +void bfa_rport_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *minfo, struct bfa_s *bfa) { @@ -4900,7 +4836,7 @@ bfa_rport_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *minfo, cfg->fwcfg.num_rports * sizeof(struct bfa_rport_s)); } -static void +void bfa_rport_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, struct bfa_pcidev_s *pcidev) { @@ -4940,22 +4876,7 @@ bfa_rport_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, bfa_mem_kva_curp(mod) = (u8 *) rp; } -static void -bfa_rport_detach(struct bfa_s *bfa) -{ -} - -static void -bfa_rport_start(struct bfa_s *bfa) -{ -} - -static void -bfa_rport_stop(struct bfa_s *bfa) -{ -} - -static void +void bfa_rport_iocdisable(struct bfa_s *bfa) { struct bfa_rport_mod_s *mod = BFA_RPORT_MOD(bfa); @@ -5246,7 +5167,7 @@ bfa_rport_unset_lunmask(struct bfa_s *bfa, struct bfa_rport_s *rp) /* * Compute and return memory needed by FCP(im) module. */ -static void +void bfa_sgpg_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *minfo, struct bfa_s *bfa) { @@ -5281,7 +5202,7 @@ bfa_sgpg_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *minfo, cfg->drvcfg.num_sgpgs * sizeof(struct bfa_sgpg_s)); } -static void +void bfa_sgpg_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, struct bfa_pcidev_s *pcidev) { @@ -5344,26 +5265,6 @@ bfa_sgpg_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, bfa_mem_kva_curp(mod) = (u8 *) hsgpg; } -static void -bfa_sgpg_detach(struct bfa_s *bfa) -{ -} - -static void -bfa_sgpg_start(struct bfa_s *bfa) -{ -} - -static void -bfa_sgpg_stop(struct bfa_s *bfa) -{ -} - -static void -bfa_sgpg_iocdisable(struct bfa_s *bfa) -{ -} - bfa_status_t bfa_sgpg_malloc(struct bfa_s *bfa, struct list_head *sgpg_q, int nsgpgs) { @@ -5547,7 +5448,7 @@ uf_mem_claim(struct bfa_uf_mod_s *ufm) claim_uf_post_msgs(ufm); } -static void +void bfa_uf_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *minfo, struct bfa_s *bfa) { @@ -5575,7 +5476,7 @@ bfa_uf_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *minfo, (sizeof(struct bfa_uf_s) + sizeof(struct bfi_uf_buf_post_s))); } -static void +void bfa_uf_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, struct bfa_pcidev_s *pcidev) { @@ -5590,11 +5491,6 @@ bfa_uf_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, uf_mem_claim(ufm); } -static void -bfa_uf_detach(struct bfa_s *bfa) -{ -} - static struct bfa_uf_s * bfa_uf_get(struct bfa_uf_mod_s *uf_mod) { @@ -5682,12 +5578,7 @@ uf_recv(struct bfa_s *bfa, struct bfi_uf_frm_rcvd_s *m) bfa_cb_queue(bfa, &uf->hcb_qe, __bfa_cb_uf_recv, uf); } -static void -bfa_uf_stop(struct bfa_s *bfa) -{ -} - -static void +void bfa_uf_iocdisable(struct bfa_s *bfa) { struct bfa_uf_mod_s *ufm = BFA_UF_MOD(bfa); @@ -5704,7 +5595,7 @@ bfa_uf_iocdisable(struct bfa_s *bfa) } } -static void +void bfa_uf_start(struct bfa_s *bfa) { bfa_uf_post_all(BFA_UF_MOD(bfa)); @@ -5845,13 +5736,7 @@ bfa_fcdiag_set_busy_status(struct bfa_fcdiag_s *fcdiag) fcport->diag_busy = BFA_FALSE; } -static void -bfa_fcdiag_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo, - struct bfa_s *bfa) -{ -} - -static void +void bfa_fcdiag_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, struct bfa_pcidev_s *pcidev) { @@ -5870,7 +5755,7 @@ bfa_fcdiag_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, memset(&dport->result, 0, sizeof(struct bfa_diag_dport_result_s)); } -static void +void bfa_fcdiag_iocdisable(struct bfa_s *bfa) { struct bfa_fcdiag_s *fcdiag = BFA_FCDIAG_MOD(bfa); @@ -5887,21 +5772,6 @@ bfa_fcdiag_iocdisable(struct bfa_s *bfa) bfa_sm_send_event(dport, BFA_DPORT_SM_HWFAIL); } -static void -bfa_fcdiag_detach(struct bfa_s *bfa) -{ -} - -static void -bfa_fcdiag_start(struct bfa_s *bfa) -{ -} - -static void -bfa_fcdiag_stop(struct bfa_s *bfa) -{ -} - static void bfa_fcdiag_queuetest_timeout(void *cbarg) { -- cgit v1.2.3 From 7ecaeaffd72ada135016564c08f5aa0b0be338f7 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sat, 8 Apr 2017 18:28:42 +0100 Subject: scsi: aic7xxx: fix order of arguments in function prototype The vendor/device and subvendor/subdevice arguments to the function prototype ahc_9005_subdevinfo_valid are in the wrong order and need to be swapped to fix this. Detected with PVS-Studio studio. Signed-off-by: Colin Ian King Signed-off-by: Martin K. Petersen --- drivers/scsi/aic7xxx/aic7xxx_pci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/aic7xxx/aic7xxx_pci.c b/drivers/scsi/aic7xxx/aic7xxx_pci.c index 22d5a949ec83..673e826d7adb 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_pci.c +++ b/drivers/scsi/aic7xxx/aic7xxx_pci.c @@ -601,8 +601,8 @@ static const u_int ahc_num_pci_devs = ARRAY_SIZE(ahc_pci_ident_table); #define STA 0x08 #define DPR 0x01 -static int ahc_9005_subdevinfo_valid(uint16_t vendor, uint16_t device, - uint16_t subvendor, uint16_t subdevice); +static int ahc_9005_subdevinfo_valid(uint16_t device, uint16_t vendor, + uint16_t subdevice, uint16_t subvendor); static int ahc_ext_scbram_present(struct ahc_softc *ahc); static void ahc_scbram_config(struct ahc_softc *ahc, int enable, int pcheck, int fast, int large); -- cgit v1.2.3 From b34b10a725e22980a331c796577e368ebb5ed895 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 20 Apr 2017 15:00:02 -0700 Subject: scsi: bfa: use designated initializers Prepare to mark sensitive kernel structures for randomization by making sure they're using designated initializers. This also initializes the array members using the enum used to look up __port_action entries. Signed-off-by: Kees Cook Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/bfa/bfa_fcs_lport.c | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/bfa/bfa_fcs_lport.c b/drivers/scsi/bfa/bfa_fcs_lport.c index 4ddda72f60e6..638c0a2857f7 100644 --- a/drivers/scsi/bfa/bfa_fcs_lport.c +++ b/drivers/scsi/bfa/bfa_fcs_lport.c @@ -89,16 +89,27 @@ static struct { void (*online) (struct bfa_fcs_lport_s *port); void (*offline) (struct bfa_fcs_lport_s *port); } __port_action[] = { - { - bfa_fcs_lport_unknown_init, bfa_fcs_lport_unknown_online, - bfa_fcs_lport_unknown_offline}, { - bfa_fcs_lport_fab_init, bfa_fcs_lport_fab_online, - bfa_fcs_lport_fab_offline}, { - bfa_fcs_lport_n2n_init, bfa_fcs_lport_n2n_online, - bfa_fcs_lport_n2n_offline}, { - bfa_fcs_lport_loop_init, bfa_fcs_lport_loop_online, - bfa_fcs_lport_loop_offline}, - }; + [BFA_FCS_FABRIC_UNKNOWN] = { + .init = bfa_fcs_lport_unknown_init, + .online = bfa_fcs_lport_unknown_online, + .offline = bfa_fcs_lport_unknown_offline + }, + [BFA_FCS_FABRIC_SWITCHED] = { + .init = bfa_fcs_lport_fab_init, + .online = bfa_fcs_lport_fab_online, + .offline = bfa_fcs_lport_fab_offline + }, + [BFA_FCS_FABRIC_N2N] = { + .init = bfa_fcs_lport_n2n_init, + .online = bfa_fcs_lport_n2n_online, + .offline = bfa_fcs_lport_n2n_offline + }, + [BFA_FCS_FABRIC_LOOP] = { + .init = bfa_fcs_lport_loop_init, + .online = bfa_fcs_lport_loop_online, + .offline = bfa_fcs_lport_loop_offline + }, +}; /* * fcs_port_sm FCS logical port state machine -- cgit v1.2.3 From 20961065a88a7ac8f7d7c8f256028304b55fa0b7 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 21 Feb 2017 16:27:11 +0000 Subject: scsi: BusLogic: fix incorrect spelling of adatper_reset_req Trivial fix to spelling mistake, adatper_reset_req should be adapter_reset_req. Also break up very long seq_printf statement into multiple lines. Signed-off-by: Colin Ian King Acked-by: Khalid Aziz Signed-off-by: Martin K. Petersen --- drivers/scsi/BusLogic.c | 14 +++++++++++--- drivers/scsi/BusLogic.h | 2 +- 2 files changed, 12 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c index c7be7bb37209..35380a58d3f0 100644 --- a/drivers/scsi/BusLogic.c +++ b/drivers/scsi/BusLogic.c @@ -3009,7 +3009,7 @@ static int blogic_hostreset(struct scsi_cmnd *SCpnt) spin_lock_irq(SCpnt->device->host->host_lock); - blogic_inc_count(&stats->adatper_reset_req); + blogic_inc_count(&stats->adapter_reset_req); rc = blogic_resetadapter(adapter, false); spin_unlock_irq(SCpnt->device->host->host_lock); @@ -3560,8 +3560,16 @@ Target Requested Completed Requested Completed Requested Completed\n\ struct blogic_tgt_flags *tgt_flags = &adapter->tgt_flags[tgt]; if (!tgt_flags->tgt_exists) continue; - seq_printf(m, "\ - %2d %5d %5d %5d %5d %5d %5d %5d %5d %5d\n", tgt, tgt_stats[tgt].aborts_request, tgt_stats[tgt].aborts_tried, tgt_stats[tgt].aborts_done, tgt_stats[tgt].bdr_request, tgt_stats[tgt].bdr_tried, tgt_stats[tgt].bdr_done, tgt_stats[tgt].adatper_reset_req, tgt_stats[tgt].adapter_reset_attempt, tgt_stats[tgt].adapter_reset_done); + seq_printf(m, " %2d %5d %5d %5d %5d %5d %5d %5d %5d %5d\n", + tgt, tgt_stats[tgt].aborts_request, + tgt_stats[tgt].aborts_tried, + tgt_stats[tgt].aborts_done, + tgt_stats[tgt].bdr_request, + tgt_stats[tgt].bdr_tried, + tgt_stats[tgt].bdr_done, + tgt_stats[tgt].adapter_reset_req, + tgt_stats[tgt].adapter_reset_attempt, + tgt_stats[tgt].adapter_reset_done); } seq_printf(m, "\nExternal Host Adapter Resets: %d\n", adapter->ext_resets); seq_printf(m, "Host Adapter Internal Errors: %d\n", adapter->adapter_intern_errors); diff --git a/drivers/scsi/BusLogic.h b/drivers/scsi/BusLogic.h index b53ec2f1e8cd..8d47e2c88d24 100644 --- a/drivers/scsi/BusLogic.h +++ b/drivers/scsi/BusLogic.h @@ -935,7 +935,7 @@ struct blogic_tgt_stats { unsigned short bdr_request; unsigned short bdr_tried; unsigned short bdr_done; - unsigned short adatper_reset_req; + unsigned short adapter_reset_req; unsigned short adapter_reset_attempt; unsigned short adapter_reset_done; }; -- cgit v1.2.3 From c5ce0abeb62845352d7428d6b82e5b52e8728f12 Mon Sep 17 00:00:00 2001 From: Johannes Thumshirn Date: Fri, 21 Apr 2017 14:11:41 +0200 Subject: scsi: sas: move scsi_remove_host call into sas_remove_host Move scsi_remove_host call into sas_remove_host and remove it from SAS HBA drivers, so we don't mess up the ordering. This solves an issue with double deleting sysfs entries that was introduced by the change of sysfs behaviour from commit bcdde7e221a8 ("sysfs: make __sysfs_remove_dir() recursive"). [mkp: addressed checkpatch complaints] Signed-off-by: Johannes Thumshirn Suggested-by: Christoph Hellwig Cc: Hannes Reinecke Cc: James Bottomley Cc: Jinpu Wang Cc: John Garry Reviewed-by: Christoph Hellwig Reviewed-by: Jinpu Wang Signed-off-by: Martin K. Petersen --- drivers/scsi/aic94xx/aic94xx_init.c | 1 - drivers/scsi/hisi_sas/hisi_sas_main.c | 1 - drivers/scsi/isci/init.c | 1 - drivers/scsi/mpt3sas/mpt3sas_scsih.c | 1 - drivers/scsi/mvsas/mv_init.c | 1 - drivers/scsi/pm8001/pm8001_init.c | 1 - drivers/scsi/scsi_transport_sas.c | 8 ++++++-- 7 files changed, 6 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c index 662b2321d1b0..a14ba7a6b81e 100644 --- a/drivers/scsi/aic94xx/aic94xx_init.c +++ b/drivers/scsi/aic94xx/aic94xx_init.c @@ -703,7 +703,6 @@ static int asd_unregister_sas_ha(struct asd_ha_struct *asd_ha) { int err; - scsi_remove_host(asd_ha->sas_ha.core.shost); err = sas_unregister_ha(&asd_ha->sas_ha); sas_remove_host(asd_ha->sas_ha.core.shost); diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 7e6e8823a5c7..d622db502ec9 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -1787,7 +1787,6 @@ int hisi_sas_remove(struct platform_device *pdev) struct hisi_hba *hisi_hba = sha->lldd_ha; struct Scsi_Host *shost = sha->core.shost; - scsi_remove_host(sha->core.shost); sas_unregister_ha(sha); sas_remove_host(sha->core.shost); diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c index 0b5b5db0d0f8..45371179ab87 100644 --- a/drivers/scsi/isci/init.c +++ b/drivers/scsi/isci/init.c @@ -272,7 +272,6 @@ static void isci_unregister(struct isci_host *isci_host) return; shost = to_shost(isci_host); - scsi_remove_host(shost); sas_unregister_ha(&isci_host->sas_ha); sas_remove_host(shost); diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index 46e866c36c8a..1a268a685815 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -8298,7 +8298,6 @@ static void scsih_remove(struct pci_dev *pdev) } sas_remove_host(shost); - scsi_remove_host(shost); mpt3sas_base_detach(ioc); spin_lock(&gioc_lock); list_del(&ioc->list); diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c index 8280046fd1f0..4e047b5001a6 100644 --- a/drivers/scsi/mvsas/mv_init.c +++ b/drivers/scsi/mvsas/mv_init.c @@ -642,7 +642,6 @@ static void mvs_pci_remove(struct pci_dev *pdev) tasklet_kill(&((struct mvs_prv_info *)sha->lldd_ha)->mv_tasklet); #endif - scsi_remove_host(mvi->shost); sas_unregister_ha(sha); sas_remove_host(mvi->shost); diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c index 417368ccb686..034b2f7d1135 100644 --- a/drivers/scsi/pm8001/pm8001_init.c +++ b/drivers/scsi/pm8001/pm8001_init.c @@ -1088,7 +1088,6 @@ static void pm8001_pci_remove(struct pci_dev *pdev) struct pm8001_hba_info *pm8001_ha; int i, j; pm8001_ha = sha->lldd_ha; - scsi_remove_host(pm8001_ha->shost); sas_unregister_ha(sha); sas_remove_host(pm8001_ha->shost); list_del(&pm8001_ha->list); diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c index cdbb293aca08..ca0e5a9a17f8 100644 --- a/drivers/scsi/scsi_transport_sas.c +++ b/drivers/scsi/scsi_transport_sas.c @@ -370,12 +370,16 @@ EXPORT_SYMBOL(sas_remove_children); * sas_remove_host - tear down a Scsi_Host's SAS data structures * @shost: Scsi Host that is torn down * - * Removes all SAS PHYs and remote PHYs for a given Scsi_Host. - * Must be called just before scsi_remove_host for SAS HBAs. + * Removes all SAS PHYs and remote PHYs for a given Scsi_Host and remove the + * Scsi_Host as well. + * + * Note: Do not call scsi_remove_host() on the Scsi_Host any more, as it is + * already removed. */ void sas_remove_host(struct Scsi_Host *shost) { sas_remove_children(&shost->shost_gendev); + scsi_remove_host(shost); } EXPORT_SYMBOL(sas_remove_host); -- cgit v1.2.3 From 91402608641823fdfd8e18042f20c1a449108514 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 23 Apr 2017 10:33:23 +0200 Subject: scsi: pmcraid: fix lock imbalance in pmcraid_reset_reload() sparse found a bug that has always been present since the driver was merged: drivers/scsi/pmcraid.c:2353:12: warning: context imbalance in 'pmcraid_reset_reload' - different lock contexts for basic block Fix this by using a common unlock goto label, and also reduce the indentation level in the function. Signed-off-by: Christoph Hellwig Reported-by: Arnd Bergmann Signed-off-by: Martin K. Petersen --- drivers/scsi/pmcraid.c | 59 ++++++++++++++++++++++++-------------------------- 1 file changed, 28 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c index 49e70a383afa..3cc858f45838 100644 --- a/drivers/scsi/pmcraid.c +++ b/drivers/scsi/pmcraid.c @@ -2373,46 +2373,43 @@ static int pmcraid_reset_reload( spin_lock_irqsave(pinstance->host->host_lock, lock_flags); if (pinstance->ioa_state == IOA_STATE_DEAD) { - spin_unlock_irqrestore(pinstance->host->host_lock, - lock_flags); pmcraid_info("reset_reload: IOA is dead\n"); - return reset; - } else if (pinstance->ioa_state == target_state) { + goto out_unlock; + } + + if (pinstance->ioa_state == target_state) { reset = 0; + goto out_unlock; } } - if (reset) { - pmcraid_info("reset_reload: proceeding with reset\n"); - scsi_block_requests(pinstance->host); - reset_cmd = pmcraid_get_free_cmd(pinstance); - - if (reset_cmd == NULL) { - pmcraid_err("no free cmnd for reset_reload\n"); - spin_unlock_irqrestore(pinstance->host->host_lock, - lock_flags); - return reset; - } + pmcraid_info("reset_reload: proceeding with reset\n"); + scsi_block_requests(pinstance->host); + reset_cmd = pmcraid_get_free_cmd(pinstance); + if (reset_cmd == NULL) { + pmcraid_err("no free cmnd for reset_reload\n"); + goto out_unlock; + } - if (shutdown_type == SHUTDOWN_NORMAL) - pinstance->ioa_bringdown = 1; + if (shutdown_type == SHUTDOWN_NORMAL) + pinstance->ioa_bringdown = 1; - pinstance->ioa_shutdown_type = shutdown_type; - pinstance->reset_cmd = reset_cmd; - pinstance->force_ioa_reset = reset; - pmcraid_info("reset_reload: initiating reset\n"); - pmcraid_ioa_reset(reset_cmd); - spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); - pmcraid_info("reset_reload: waiting for reset to complete\n"); - wait_event(pinstance->reset_wait_q, - !pinstance->ioa_reset_in_progress); + pinstance->ioa_shutdown_type = shutdown_type; + pinstance->reset_cmd = reset_cmd; + pinstance->force_ioa_reset = reset; + pmcraid_info("reset_reload: initiating reset\n"); + pmcraid_ioa_reset(reset_cmd); + spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); + pmcraid_info("reset_reload: waiting for reset to complete\n"); + wait_event(pinstance->reset_wait_q, + !pinstance->ioa_reset_in_progress); - pmcraid_info("reset_reload: reset is complete !!\n"); - scsi_unblock_requests(pinstance->host); - if (pinstance->ioa_state == target_state) - reset = 0; - } + pmcraid_info("reset_reload: reset is complete !!\n"); + scsi_unblock_requests(pinstance->host); + return pinstance->ioa_state != target_state; +out_unlock: + spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); return reset; } -- cgit v1.2.3 From 3397623b370494fd7e0bca62b7578051482d058d Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 20 Apr 2017 19:54:45 +0200 Subject: scsi: pmcraid: use __iomem pointers for ioctl argument kernelci.org reports a new compile warning for old code in the pmcraid driver: arch/mips/include/asm/uaccess.h:138:21: warning: passing argument 1 of '__access_ok' makes pointer from integer without a cast [-Wint-conversion] The warning got introduced by a cleanup to the access_ok() helper that requires the argument to be a pointer, where the old version silently accepts 'unsigned long' arguments as it still does on most other architectures. The new behavior in MIPS however seems absolutely sensible, and so far I could only find one other file with the same issue, so the best solution seems to be to clean up the pmcraid driver. This makes the driver consistently use 'void __iomem *' pointers for passing around the address of the user space ioctl arguments, which gets rid of the kernelci warning as well as several sparse warnings. Fixes: f0a955f4eeec ("mips: sanitize __access_ok()") Cc: Alexander Viro Signed-off-by: Arnd Bergmann Signed-off-by: Martin K. Petersen --- drivers/scsi/pmcraid.c | 44 ++++++++++++++++---------------------------- 1 file changed, 16 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c index 3cc858f45838..6ed1bc09f1c1 100644 --- a/drivers/scsi/pmcraid.c +++ b/drivers/scsi/pmcraid.c @@ -3322,7 +3322,7 @@ static struct pmcraid_sglist *pmcraid_alloc_sglist(int buflen) */ static int pmcraid_copy_sglist( struct pmcraid_sglist *sglist, - unsigned long buffer, + void __user *buffer, u32 len, int direction ) @@ -3343,11 +3343,9 @@ static int pmcraid_copy_sglist( kaddr = kmap(page); if (direction == DMA_TO_DEVICE) - rc = __copy_from_user(kaddr, - (void *)buffer, - bsize_elem); + rc = __copy_from_user(kaddr, buffer, bsize_elem); else - rc = __copy_to_user((void *)buffer, kaddr, bsize_elem); + rc = __copy_to_user(buffer, kaddr, bsize_elem); kunmap(page); @@ -3365,13 +3363,9 @@ static int pmcraid_copy_sglist( kaddr = kmap(page); if (direction == DMA_TO_DEVICE) - rc = __copy_from_user(kaddr, - (void *)buffer, - len % bsize_elem); + rc = __copy_from_user(kaddr, buffer, len % bsize_elem); else - rc = __copy_to_user((void *)buffer, - kaddr, - len % bsize_elem); + rc = __copy_to_user(buffer, kaddr, len % bsize_elem); kunmap(page); @@ -3649,17 +3643,17 @@ static long pmcraid_ioctl_passthrough( struct pmcraid_instance *pinstance, unsigned int ioctl_cmd, unsigned int buflen, - unsigned long arg + void __user *arg ) { struct pmcraid_passthrough_ioctl_buffer *buffer; struct pmcraid_ioarcb *ioarcb; struct pmcraid_cmd *cmd; struct pmcraid_cmd *cancel_cmd; - unsigned long request_buffer; + void __user *request_buffer; unsigned long request_offset; unsigned long lock_flags; - void *ioasa; + void __user *ioasa; u32 ioasc; int request_size; int buffer_size; @@ -3698,13 +3692,10 @@ static long pmcraid_ioctl_passthrough( request_buffer = arg + request_offset; - rc = __copy_from_user(buffer, - (struct pmcraid_passthrough_ioctl_buffer *) arg, + rc = __copy_from_user(buffer, arg, sizeof(struct pmcraid_passthrough_ioctl_buffer)); - ioasa = - (void *)(arg + - offsetof(struct pmcraid_passthrough_ioctl_buffer, ioasa)); + ioasa = arg + offsetof(struct pmcraid_passthrough_ioctl_buffer, ioasa); if (rc) { pmcraid_err("ioctl: can't copy passthrough buffer\n"); @@ -4018,6 +4009,7 @@ static long pmcraid_chr_ioctl( { struct pmcraid_instance *pinstance = NULL; struct pmcraid_ioctl_header *hdr = NULL; + void __user *argp = (void __user *)arg; int retval = -ENOTTY; hdr = kmalloc(sizeof(struct pmcraid_ioctl_header), GFP_KERNEL); @@ -4027,7 +4019,7 @@ static long pmcraid_chr_ioctl( return -ENOMEM; } - retval = pmcraid_check_ioctl_buffer(cmd, (void *)arg, hdr); + retval = pmcraid_check_ioctl_buffer(cmd, argp, hdr); if (retval) { pmcraid_info("chr_ioctl: header check failed\n"); @@ -4052,10 +4044,8 @@ static long pmcraid_chr_ioctl( if (cmd == PMCRAID_IOCTL_DOWNLOAD_MICROCODE) scsi_block_requests(pinstance->host); - retval = pmcraid_ioctl_passthrough(pinstance, - cmd, - hdr->buffer_length, - arg); + retval = pmcraid_ioctl_passthrough(pinstance, cmd, + hdr->buffer_length, argp); if (cmd == PMCRAID_IOCTL_DOWNLOAD_MICROCODE) scsi_unblock_requests(pinstance->host); @@ -4063,10 +4053,8 @@ static long pmcraid_chr_ioctl( case PMCRAID_DRIVER_IOCTL: arg += sizeof(struct pmcraid_ioctl_header); - retval = pmcraid_ioctl_driver(pinstance, - cmd, - hdr->buffer_length, - (void __user *)arg); + retval = pmcraid_ioctl_driver(pinstance, cmd, + hdr->buffer_length, argp); break; default: -- cgit v1.2.3 From 45c80be614b094459f2c699353080e4f8059f610 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 20 Apr 2017 19:54:47 +0200 Subject: scsi: pmcraid: fix endianess sparse annotations The use of le32_to_cpu() etc in this driver looks completely arbitrary. It may have made sense at some point, but it is not applied consistently, so this driver presumably won't work on big-endian kernel builds. Unfortunately it's unclear whether the type names or the calls to le32_to_cpu() are the correct ones. I'm taking educated guesses here and assume that most of the __le32 and __le16 annotations are correct, adding the conversion helpers whereever we access those fields. The exceptions are the 'fw_version' field that is always accessed as big-endian, so I'm changing the type here, and the 'hrrq' values that are accessed as little-endian, so I'm changing those the other way. None of these changes should have any effect on little-endian architectures like x86, but it addresses the sparse warnings. Signed-off-by: Arnd Bergmann Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/pmcraid.c | 95 +++++++++++++++++++++++++------------------------- drivers/scsi/pmcraid.h | 8 ++--- 2 files changed, 51 insertions(+), 52 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c index 6ed1bc09f1c1..35a2b3685208 100644 --- a/drivers/scsi/pmcraid.c +++ b/drivers/scsi/pmcraid.c @@ -175,7 +175,7 @@ static int pmcraid_slave_alloc(struct scsi_device *scsi_dev) if (fw_version <= PMCRAID_FW_VERSION_1) target = temp->cfg_entry.unique_flags1; else - target = temp->cfg_entry.array_id & 0xFF; + target = le16_to_cpu(temp->cfg_entry.array_id) & 0xFF; if (target > PMCRAID_MAX_VSET_TARGETS) continue; @@ -330,7 +330,7 @@ static void pmcraid_init_cmdblk(struct pmcraid_cmd *cmd, int index) ioarcb->request_flags0 = 0; ioarcb->request_flags1 = 0; ioarcb->cmd_timeout = 0; - ioarcb->ioarcb_bus_addr &= (~0x1FULL); + ioarcb->ioarcb_bus_addr &= cpu_to_le64(~0x1FULL); ioarcb->ioadl_bus_addr = 0; ioarcb->ioadl_length = 0; ioarcb->data_transfer_length = 0; @@ -898,8 +898,7 @@ static void _pmcraid_fire_command(struct pmcraid_cmd *cmd) /* driver writes lower 32-bit value of IOARCB address only */ mb(); - iowrite32(le32_to_cpu(cmd->ioa_cb->ioarcb.ioarcb_bus_addr), - pinstance->ioarrin); + iowrite32(le64_to_cpu(cmd->ioa_cb->ioarcb.ioarcb_bus_addr), pinstance->ioarrin); } /** @@ -1051,7 +1050,7 @@ static void pmcraid_get_fwversion(struct pmcraid_cmd *cmd) offsetof(struct pmcraid_ioarcb, add_data.u.ioadl[0])); ioarcb->ioadl_length = cpu_to_le32(sizeof(struct pmcraid_ioadl_desc)); - ioarcb->ioarcb_bus_addr &= ~(0x1FULL); + ioarcb->ioarcb_bus_addr &= cpu_to_le64(~(0x1FULL)); ioarcb->request_flags0 |= NO_LINK_DESCS; ioarcb->data_transfer_length = cpu_to_le32(data_size); @@ -1077,7 +1076,7 @@ static void pmcraid_identify_hrrq(struct pmcraid_cmd *cmd) struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; int index = cmd->hrrq_index; __be64 hrrq_addr = cpu_to_be64(pinstance->hrrq_start_bus_addr[index]); - u32 hrrq_size = cpu_to_be32(sizeof(u32) * PMCRAID_MAX_CMD); + __be32 hrrq_size = cpu_to_be32(sizeof(u32) * PMCRAID_MAX_CMD); void (*done_function)(struct pmcraid_cmd *); pmcraid_reinit_cmdblk(cmd); @@ -1202,7 +1201,7 @@ static struct pmcraid_cmd *pmcraid_init_hcam ioadl[0].flags |= IOADL_FLAGS_READ_LAST; ioadl[0].data_len = cpu_to_le32(rcb_size); - ioadl[0].address = cpu_to_le32(dma); + ioadl[0].address = cpu_to_le64(dma); cmd->cmd_done = cmd_done; return cmd; @@ -1237,7 +1236,13 @@ static void pmcraid_prepare_cancel_cmd( ) { struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; - __be64 ioarcb_addr = cmd_to_cancel->ioa_cb->ioarcb.ioarcb_bus_addr; + __be64 ioarcb_addr; + + /* IOARCB address of the command to be cancelled is given in + * cdb[2]..cdb[9] is Big-Endian format. Note that length bits in + * IOARCB address are not masked. + */ + ioarcb_addr = cpu_to_be64(le64_to_cpu(cmd_to_cancel->ioa_cb->ioarcb.ioarcb_bus_addr)); /* Get the resource handle to where the command to be aborted has been * sent. @@ -1247,11 +1252,6 @@ static void pmcraid_prepare_cancel_cmd( memset(ioarcb->cdb, 0, PMCRAID_MAX_CDB_LEN); ioarcb->cdb[0] = PMCRAID_ABORT_CMD; - /* IOARCB address of the command to be cancelled is given in - * cdb[2]..cdb[9] is Big-Endian format. Note that length bits in - * IOARCB address are not masked. - */ - ioarcb_addr = cpu_to_be64(ioarcb_addr); memcpy(&(ioarcb->cdb[2]), &ioarcb_addr, sizeof(ioarcb_addr)); } @@ -1493,7 +1493,7 @@ static int pmcraid_notify_ccn(struct pmcraid_instance *pinstance) { return pmcraid_notify_aen(pinstance, pinstance->ccn.msg, - pinstance->ccn.hcam->data_len + + le32_to_cpu(pinstance->ccn.hcam->data_len) + sizeof(struct pmcraid_hcam_hdr)); } @@ -1508,7 +1508,7 @@ static int pmcraid_notify_ldn(struct pmcraid_instance *pinstance) { return pmcraid_notify_aen(pinstance, pinstance->ldn.msg, - pinstance->ldn.hcam->data_len + + le32_to_cpu(pinstance->ldn.hcam->data_len) + sizeof(struct pmcraid_hcam_hdr)); } @@ -1556,10 +1556,10 @@ static void pmcraid_handle_config_change(struct pmcraid_instance *pinstance) pmcraid_info("CCN(%x): %x timestamp: %llx type: %x lost: %x flags: %x \ res: %x:%x:%x:%x\n", - pinstance->ccn.hcam->ilid, + le32_to_cpu(pinstance->ccn.hcam->ilid), pinstance->ccn.hcam->op_code, - ((pinstance->ccn.hcam->timestamp1) | - ((pinstance->ccn.hcam->timestamp2 & 0xffffffffLL) << 32)), + (le32_to_cpu(pinstance->ccn.hcam->timestamp1) | + ((le32_to_cpu(pinstance->ccn.hcam->timestamp2) & 0xffffffffLL) << 32)), pinstance->ccn.hcam->notification_type, pinstance->ccn.hcam->notification_lost, pinstance->ccn.hcam->flags, @@ -1570,7 +1570,7 @@ static void pmcraid_handle_config_change(struct pmcraid_instance *pinstance) RES_IS_VSET(*cfg_entry) ? (fw_version <= PMCRAID_FW_VERSION_1 ? cfg_entry->unique_flags1 : - cfg_entry->array_id & 0xFF) : + le16_to_cpu(cfg_entry->array_id) & 0xFF) : RES_TARGET(cfg_entry->resource_address), RES_LUN(cfg_entry->resource_address)); @@ -1658,7 +1658,7 @@ static void pmcraid_handle_config_change(struct pmcraid_instance *pinstance) if (fw_version <= PMCRAID_FW_VERSION_1) res->cfg_entry.unique_flags1 &= 0x7F; else - res->cfg_entry.array_id &= 0xFF; + res->cfg_entry.array_id &= cpu_to_le16(0xFF); res->change_detected = RES_CHANGE_DEL; res->cfg_entry.resource_handle = PMCRAID_INVALID_RES_HANDLE; @@ -1716,8 +1716,8 @@ static void pmcraid_ioasc_logger(u32 ioasc, struct pmcraid_cmd *cmd) /* log the error string */ pmcraid_err("cmd [%x] for resource %x failed with %x(%s)\n", cmd->ioa_cb->ioarcb.cdb[0], - cmd->ioa_cb->ioarcb.resource_handle, - le32_to_cpu(ioasc), error_info->error_string); + le32_to_cpu(cmd->ioa_cb->ioarcb.resource_handle), + ioasc, error_info->error_string); } /** @@ -2034,7 +2034,7 @@ static void pmcraid_fail_outstanding_cmds(struct pmcraid_instance *pinstance) cmd->ioa_cb->ioasa.ioasc = cpu_to_le32(PMCRAID_IOASC_IOA_WAS_RESET); cmd->ioa_cb->ioasa.ilid = - cpu_to_be32(PMCRAID_DRIVER_ILID); + cpu_to_le32(PMCRAID_DRIVER_ILID); /* In case the command timer is still running */ del_timer(&cmd->timer); @@ -2526,7 +2526,7 @@ static void pmcraid_cancel_all(struct pmcraid_cmd *cmd, u32 sense) ioarcb->ioadl_bus_addr = 0; ioarcb->ioadl_length = 0; ioarcb->data_transfer_length = 0; - ioarcb->ioarcb_bus_addr &= (~0x1FULL); + ioarcb->ioarcb_bus_addr &= cpu_to_le64((~0x1FULL)); /* writing to IOARRIN must be protected by host_lock, as mid-layer * schedule queuecommand while we are doing this @@ -2689,8 +2689,8 @@ static int pmcraid_error_handler(struct pmcraid_cmd *cmd) * mid-layer */ if (ioasa->auto_sense_length != 0) { - short sense_len = ioasa->auto_sense_length; - int data_size = min_t(u16, le16_to_cpu(sense_len), + short sense_len = le16_to_cpu(ioasa->auto_sense_length); + int data_size = min_t(u16, sense_len, SCSI_SENSE_BUFFERSIZE); memcpy(scsi_cmd->sense_buffer, @@ -2912,7 +2912,7 @@ static struct pmcraid_cmd *pmcraid_abort_cmd(struct pmcraid_cmd *cmd) pmcraid_info("aborting command CDB[0]= %x with index = %d\n", cmd->ioa_cb->ioarcb.cdb[0], - cmd->ioa_cb->ioarcb.response_handle >> 2); + le32_to_cpu(cmd->ioa_cb->ioarcb.response_handle) >> 2); init_completion(&cancel_cmd->wait_for_completion); cancel_cmd->completion_req = 1; @@ -3137,9 +3137,8 @@ pmcraid_init_ioadls(struct pmcraid_cmd *cmd, int sgcount) int ioadl_count = 0; if (ioarcb->add_cmd_param_length) - ioadl_count = DIV_ROUND_UP(ioarcb->add_cmd_param_length, 16); - ioarcb->ioadl_length = - sizeof(struct pmcraid_ioadl_desc) * sgcount; + ioadl_count = DIV_ROUND_UP(le16_to_cpu(ioarcb->add_cmd_param_length), 16); + ioarcb->ioadl_length = cpu_to_le32(sizeof(struct pmcraid_ioadl_desc) * sgcount); if ((sgcount + ioadl_count) > (ARRAY_SIZE(ioarcb->add_data.u.ioadl))) { /* external ioadls start at offset 0x80 from control_block @@ -3147,7 +3146,7 @@ pmcraid_init_ioadls(struct pmcraid_cmd *cmd, int sgcount) * It is necessary to indicate to firmware that driver is * using ioadls to be treated as external to IOARCB. */ - ioarcb->ioarcb_bus_addr &= ~(0x1FULL); + ioarcb->ioarcb_bus_addr &= cpu_to_le64(~(0x1FULL)); ioarcb->ioadl_bus_addr = cpu_to_le64((cmd->ioa_cb_bus_addr) + offsetof(struct pmcraid_ioarcb, @@ -3161,7 +3160,7 @@ pmcraid_init_ioadls(struct pmcraid_cmd *cmd, int sgcount) ioadl = &ioarcb->add_data.u.ioadl[ioadl_count]; ioarcb->ioarcb_bus_addr |= - DIV_ROUND_CLOSEST(sgcount + ioadl_count, 8); + cpu_to_le64(DIV_ROUND_CLOSEST(sgcount + ioadl_count, 8)); } return ioadl; @@ -3487,7 +3486,7 @@ static int pmcraid_queuecommand_lck( RES_IS_VSET(res->cfg_entry) ? (fw_version <= PMCRAID_FW_VERSION_1 ? res->cfg_entry.unique_flags1 : - res->cfg_entry.array_id & 0xFF) : + le16_to_cpu(res->cfg_entry.array_id) & 0xFF) : RES_TARGET(res->cfg_entry.resource_address), RES_LUN(res->cfg_entry.resource_address)); @@ -3703,7 +3702,7 @@ static long pmcraid_ioctl_passthrough( goto out_free_buffer; } - request_size = buffer->ioarcb.data_transfer_length; + request_size = le32_to_cpu(buffer->ioarcb.data_transfer_length); if (buffer->ioarcb.request_flags0 & TRANSFER_DIR_WRITE) { access = VERIFY_READ; @@ -3726,7 +3725,8 @@ static long pmcraid_ioctl_passthrough( } /* check if we have any additional command parameters */ - if (buffer->ioarcb.add_cmd_param_length > PMCRAID_ADD_CMD_PARAM_LEN) { + if (le16_to_cpu(buffer->ioarcb.add_cmd_param_length) + > PMCRAID_ADD_CMD_PARAM_LEN) { rc = -EINVAL; goto out_free_buffer; } @@ -3758,7 +3758,7 @@ static long pmcraid_ioctl_passthrough( buffer->ioarcb.add_cmd_param_offset; memcpy(ioarcb->add_data.u.add_cmd_params, buffer->ioarcb.add_data.u.add_cmd_params, - buffer->ioarcb.add_cmd_param_length); + le16_to_cpu(buffer->ioarcb.add_cmd_param_length)); } /* set hrrq number where the IOA should respond to. Note that all cmds @@ -3828,10 +3828,10 @@ static long pmcraid_ioctl_passthrough( wait_for_completion(&cmd->wait_for_completion); } else if (!wait_for_completion_timeout( &cmd->wait_for_completion, - msecs_to_jiffies(buffer->ioarcb.cmd_timeout * 1000))) { + msecs_to_jiffies(le16_to_cpu(buffer->ioarcb.cmd_timeout) * 1000))) { pmcraid_info("aborting cmd %d (CDB[0] = %x) due to timeout\n", - le32_to_cpu(cmd->ioa_cb->ioarcb.response_handle >> 2), + le32_to_cpu(cmd->ioa_cb->ioarcb.response_handle) >> 2, cmd->ioa_cb->ioarcb.cdb[0]); spin_lock_irqsave(pinstance->host->host_lock, lock_flags); @@ -3840,7 +3840,7 @@ static long pmcraid_ioctl_passthrough( if (cancel_cmd) { wait_for_completion(&cancel_cmd->wait_for_completion); - ioasc = cancel_cmd->ioa_cb->ioasa.ioasc; + ioasc = le32_to_cpu(cancel_cmd->ioa_cb->ioasa.ioasc); pmcraid_return_cmd(cancel_cmd); /* if abort task couldn't find the command i.e it got @@ -4455,7 +4455,7 @@ static void pmcraid_worker_function(struct work_struct *workp) if (fw_version <= PMCRAID_FW_VERSION_1) target = res->cfg_entry.unique_flags1; else - target = res->cfg_entry.array_id & 0xFF; + target = le16_to_cpu(res->cfg_entry.array_id) & 0xFF; lun = PMCRAID_VSET_LUN_ID; } else { bus = PMCRAID_PHYS_BUS_ID; @@ -4494,7 +4494,7 @@ static void pmcraid_tasklet_function(unsigned long instance) unsigned long host_lock_flags; spinlock_t *lockp; /* hrrq buffer lock */ int id; - __le32 resp; + u32 resp; hrrq_vector = (struct pmcraid_isr_param *)instance; pinstance = hrrq_vector->drv_inst; @@ -5534,8 +5534,7 @@ static void pmcraid_set_timestamp(struct pmcraid_cmd *cmd) struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; __be32 time_stamp_len = cpu_to_be32(PMCRAID_TIMESTAMP_LEN); struct pmcraid_ioadl_desc *ioadl = ioarcb->add_data.u.ioadl; - - __le64 timestamp; + u64 timestamp; timestamp = ktime_get_real_seconds() * 1000; @@ -5557,7 +5556,7 @@ static void pmcraid_set_timestamp(struct pmcraid_cmd *cmd) offsetof(struct pmcraid_ioarcb, add_data.u.ioadl[0])); ioarcb->ioadl_length = cpu_to_le32(sizeof(struct pmcraid_ioadl_desc)); - ioarcb->ioarcb_bus_addr &= ~(0x1FULL); + ioarcb->ioarcb_bus_addr &= cpu_to_le64(~(0x1FULL)); ioarcb->request_flags0 |= NO_LINK_DESCS; ioarcb->request_flags0 |= TRANSFER_DIR_WRITE; @@ -5616,7 +5615,7 @@ static void pmcraid_init_res_table(struct pmcraid_cmd *cmd) list_for_each_entry_safe(res, temp, &pinstance->used_res_q, queue) list_move_tail(&res->queue, &old_res); - for (i = 0; i < pinstance->cfg_table->num_entries; i++) { + for (i = 0; i < le16_to_cpu(pinstance->cfg_table->num_entries); i++) { if (be16_to_cpu(pinstance->inq_data->fw_version) <= PMCRAID_FW_VERSION_1) cfgte = &pinstance->cfg_table->entries[i]; @@ -5671,7 +5670,7 @@ static void pmcraid_init_res_table(struct pmcraid_cmd *cmd) res->cfg_entry.resource_type, (fw_version <= PMCRAID_FW_VERSION_1 ? res->cfg_entry.unique_flags1 : - res->cfg_entry.array_id & 0xFF), + le16_to_cpu(res->cfg_entry.array_id) & 0xFF), le32_to_cpu(res->cfg_entry.resource_address)); } } @@ -5709,7 +5708,7 @@ static void pmcraid_querycfg(struct pmcraid_cmd *cmd) struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; struct pmcraid_ioadl_desc *ioadl = ioarcb->add_data.u.ioadl; struct pmcraid_instance *pinstance = cmd->drv_inst; - int cfg_table_size = cpu_to_be32(sizeof(struct pmcraid_config_table)); + __be32 cfg_table_size = cpu_to_be32(sizeof(struct pmcraid_config_table)); if (be16_to_cpu(pinstance->inq_data->fw_version) <= PMCRAID_FW_VERSION_1) @@ -5734,7 +5733,7 @@ static void pmcraid_querycfg(struct pmcraid_cmd *cmd) offsetof(struct pmcraid_ioarcb, add_data.u.ioadl[0])); ioarcb->ioadl_length = cpu_to_le32(sizeof(struct pmcraid_ioadl_desc)); - ioarcb->ioarcb_bus_addr &= ~(0x1FULL); + ioarcb->ioarcb_bus_addr &= cpu_to_le64(~0x1FULL); ioarcb->request_flags0 |= NO_LINK_DESCS; ioarcb->data_transfer_length = diff --git a/drivers/scsi/pmcraid.h b/drivers/scsi/pmcraid.h index 568b18a2f47d..01eb2bc16dc1 100644 --- a/drivers/scsi/pmcraid.h +++ b/drivers/scsi/pmcraid.h @@ -554,7 +554,7 @@ struct pmcraid_inquiry_data { __u8 add_page_len; __u8 length; __u8 reserved2; - __le16 fw_version; + __be16 fw_version; __u8 reserved3[16]; }; @@ -697,13 +697,13 @@ struct pmcraid_instance { dma_addr_t hrrq_start_bus_addr[PMCRAID_NUM_MSIX_VECTORS]; /* Pointer to 1st entry of HRRQ */ - __be32 *hrrq_start[PMCRAID_NUM_MSIX_VECTORS]; + __le32 *hrrq_start[PMCRAID_NUM_MSIX_VECTORS]; /* Pointer to last entry of HRRQ */ - __be32 *hrrq_end[PMCRAID_NUM_MSIX_VECTORS]; + __le32 *hrrq_end[PMCRAID_NUM_MSIX_VECTORS]; /* Pointer to current pointer of hrrq */ - __be32 *hrrq_curr[PMCRAID_NUM_MSIX_VECTORS]; + __le32 *hrrq_curr[PMCRAID_NUM_MSIX_VECTORS]; /* Lock for HRRQ access */ spinlock_t hrrq_lock[PMCRAID_NUM_MSIX_VECTORS]; -- cgit v1.2.3 From 144b139c96200c51248b8701a1ef4a6bebd3dc8c Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 20 Apr 2017 19:54:48 +0200 Subject: scsi: pmcraid: fix minor sparse warnings pmcraid_minor is only used in this one file and should be 'static' as suggested by sparse: drivers/scsi/pmcraid.c:80:1: warning: symbol 'pmcraid_minor' was not declared. Should it be static? In Linux coding style, a literal '0' integer should not be used to represent a NULL pointer: drivers/scsi/pmcraid.c:348:29: warning: Using plain integer as NULL pointer drivers/scsi/pmcraid.c:4824:49: warning: Using plain integer as NULL pointer Signed-off-by: Arnd Bergmann Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/pmcraid.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c index 35a2b3685208..94f71aef196f 100644 --- a/drivers/scsi/pmcraid.c +++ b/drivers/scsi/pmcraid.c @@ -77,7 +77,7 @@ static atomic_t pmcraid_adapter_count = ATOMIC_INIT(0); */ static unsigned int pmcraid_major; static struct class *pmcraid_class; -DECLARE_BITMAP(pmcraid_minor, PMCRAID_MAX_ADAPTERS); +static DECLARE_BITMAP(pmcraid_minor, PMCRAID_MAX_ADAPTERS); /* * Module parameters @@ -345,7 +345,7 @@ static void pmcraid_init_cmdblk(struct pmcraid_cmd *cmd, int index) cmd->scsi_cmd = NULL; cmd->release = 0; cmd->completion_req = 0; - cmd->sense_buffer = 0; + cmd->sense_buffer = NULL; cmd->sense_buffer_dma = 0; cmd->dma_handle = 0; init_timer(&cmd->timer); @@ -4818,7 +4818,7 @@ static int pmcraid_allocate_host_rrqs(struct pmcraid_instance *pinstance) buffer_size, &(pinstance->hrrq_start_bus_addr[i])); - if (pinstance->hrrq_start[i] == 0) { + if (!pinstance->hrrq_start[i]) { pmcraid_err("pci_alloc failed for hrrq vector : %d\n", i); pmcraid_release_host_rrqs(pinstance, i); -- cgit v1.2.3 From edb88cef0570914375d461107759cf0d6d677ed5 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Sat, 22 Apr 2017 00:02:31 +0200 Subject: scsi: pmcraid: use normal copy_from_user As pointed out by Al Viro for my previous series, the driver has no need to call access_ok() and __copy_from_user()/__copy_to_user(). Changing it to regular copy_from_user()/copy_to_user() simplifies the code without any real downsides, making it less error-prone at best. This patch by itself also addresses the warning about the access_ok() macro on MIPS, but both fixes improve the code, so ideally we apply them both. Signed-off-by: Arnd Bergmann Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/pmcraid.c | 40 +++++++--------------------------------- 1 file changed, 7 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c index 94f71aef196f..a4aadf5f4dc6 100644 --- a/drivers/scsi/pmcraid.c +++ b/drivers/scsi/pmcraid.c @@ -3342,9 +3342,9 @@ static int pmcraid_copy_sglist( kaddr = kmap(page); if (direction == DMA_TO_DEVICE) - rc = __copy_from_user(kaddr, buffer, bsize_elem); + rc = copy_from_user(kaddr, buffer, bsize_elem); else - rc = __copy_to_user(buffer, kaddr, bsize_elem); + rc = copy_to_user(buffer, kaddr, bsize_elem); kunmap(page); @@ -3362,9 +3362,9 @@ static int pmcraid_copy_sglist( kaddr = kmap(page); if (direction == DMA_TO_DEVICE) - rc = __copy_from_user(kaddr, buffer, len % bsize_elem); + rc = copy_from_user(kaddr, buffer, len % bsize_elem); else - rc = __copy_to_user(buffer, kaddr, len % bsize_elem); + rc = copy_to_user(buffer, kaddr, len % bsize_elem); kunmap(page); @@ -3691,7 +3691,7 @@ static long pmcraid_ioctl_passthrough( request_buffer = arg + request_offset; - rc = __copy_from_user(buffer, arg, + rc = copy_from_user(buffer, arg, sizeof(struct pmcraid_passthrough_ioctl_buffer)); ioasa = arg + offsetof(struct pmcraid_passthrough_ioctl_buffer, ioasa); @@ -3712,14 +3712,7 @@ static long pmcraid_ioctl_passthrough( direction = DMA_FROM_DEVICE; } - if (request_size > 0) { - rc = access_ok(access, arg, request_offset + request_size); - - if (!rc) { - rc = -EFAULT; - goto out_free_buffer; - } - } else if (request_size < 0) { + if (request_size < 0) { rc = -EINVAL; goto out_free_buffer; } @@ -3929,11 +3922,6 @@ static long pmcraid_ioctl_driver( { int rc = -ENOSYS; - if (!access_ok(VERIFY_READ, user_buffer, _IOC_SIZE(cmd))) { - pmcraid_err("ioctl_driver: access fault in request buffer\n"); - return -EFAULT; - } - switch (cmd) { case PMCRAID_IOCTL_RESET_ADAPTER: pmcraid_reset_bringup(pinstance); @@ -3965,8 +3953,7 @@ static int pmcraid_check_ioctl_buffer( struct pmcraid_ioctl_header *hdr ) { - int rc = 0; - int access = VERIFY_READ; + int rc; if (copy_from_user(hdr, arg, sizeof(struct pmcraid_ioctl_header))) { pmcraid_err("couldn't copy ioctl header from user buffer\n"); @@ -3982,19 +3969,6 @@ static int pmcraid_check_ioctl_buffer( return -EINVAL; } - /* check for appropriate buffer access */ - if ((_IOC_DIR(cmd) & _IOC_READ) == _IOC_READ) - access = VERIFY_WRITE; - - rc = access_ok(access, - (arg + sizeof(struct pmcraid_ioctl_header)), - hdr->buffer_length); - if (!rc) { - pmcraid_err("access failed for user buffer of size %d\n", - hdr->buffer_length); - return -EFAULT; - } - return 0; } -- cgit v1.2.3 From 6b8accea1b03da5f03e6dcd589f7024c4f4ee445 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sat, 22 Apr 2017 14:02:02 +0100 Subject: scsi: fusion: fix spelling mistake: "Persistancy" -> "Persistency" trivial fix to spelling mistake Signed-off-by: Colin Ian King Signed-off-by: Martin K. Petersen --- drivers/message/fusion/mptbase.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index 1e73064b0fb2..62cff5afc6bd 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -7396,7 +7396,7 @@ mpt_display_event_info(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply) break; case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED: snprintf(evStr, EVENT_DESCR_STR_SZ, - "SAS Device Status Change: No Persistancy: " + "SAS Device Status Change: No Persistency: " "id=%d channel=%d", id, channel); break; case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED: -- cgit v1.2.3 From 4bd13a077172a1a509115993ebe2082f327f1609 Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Mon, 24 Apr 2017 02:01:00 +0300 Subject: scsi: mvumi: remove code handling zero scsi_sg_count(scmd) case As Christoph Hellwig noted, SCSI commands that transfer data always have a SG entry. The patch removes dead code in mvumi_make_sgl(), mvumi_complete_cmd() and mvumi_timed_out() that handle zero scsi_sg_count(scmd) case. Also the patch adds pci_unmap_sg() on failure path in mvumi_make_sgl(). Signed-off-by: Alexey Khoroshilov Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/mvumi.c | 85 ++++++++++++++++------------------------------------ 1 file changed, 26 insertions(+), 59 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/mvumi.c b/drivers/scsi/mvumi.c index 247df5e79b71..fe97401ad192 100644 --- a/drivers/scsi/mvumi.c +++ b/drivers/scsi/mvumi.c @@ -210,39 +210,27 @@ static int mvumi_make_sgl(struct mvumi_hba *mhba, struct scsi_cmnd *scmd, unsigned int sgnum = scsi_sg_count(scmd); dma_addr_t busaddr; - if (sgnum) { - sg = scsi_sglist(scmd); - *sg_count = pci_map_sg(mhba->pdev, sg, sgnum, - (int) scmd->sc_data_direction); - if (*sg_count > mhba->max_sge) { - dev_err(&mhba->pdev->dev, "sg count[0x%x] is bigger " - "than max sg[0x%x].\n", - *sg_count, mhba->max_sge); - return -1; - } - for (i = 0; i < *sg_count; i++) { - busaddr = sg_dma_address(&sg[i]); - m_sg->baseaddr_l = cpu_to_le32(lower_32_bits(busaddr)); - m_sg->baseaddr_h = cpu_to_le32(upper_32_bits(busaddr)); - m_sg->flags = 0; - sgd_setsz(mhba, m_sg, cpu_to_le32(sg_dma_len(&sg[i]))); - if ((i + 1) == *sg_count) - m_sg->flags |= 1U << mhba->eot_flag; - - sgd_inc(mhba, m_sg); - } - } else { - scmd->SCp.dma_handle = scsi_bufflen(scmd) ? - pci_map_single(mhba->pdev, scsi_sglist(scmd), - scsi_bufflen(scmd), - (int) scmd->sc_data_direction) - : 0; - busaddr = scmd->SCp.dma_handle; + sg = scsi_sglist(scmd); + *sg_count = pci_map_sg(mhba->pdev, sg, sgnum, + (int) scmd->sc_data_direction); + if (*sg_count > mhba->max_sge) { + dev_err(&mhba->pdev->dev, + "sg count[0x%x] is bigger than max sg[0x%x].\n", + *sg_count, mhba->max_sge); + pci_unmap_sg(mhba->pdev, sg, sgnum, + (int) scmd->sc_data_direction); + return -1; + } + for (i = 0; i < *sg_count; i++) { + busaddr = sg_dma_address(&sg[i]); m_sg->baseaddr_l = cpu_to_le32(lower_32_bits(busaddr)); m_sg->baseaddr_h = cpu_to_le32(upper_32_bits(busaddr)); - m_sg->flags = 1U << mhba->eot_flag; - sgd_setsz(mhba, m_sg, cpu_to_le32(scsi_bufflen(scmd))); - *sg_count = 1; + m_sg->flags = 0; + sgd_setsz(mhba, m_sg, cpu_to_le32(sg_dma_len(&sg[i]))); + if ((i + 1) == *sg_count) + m_sg->flags |= 1U << mhba->eot_flag; + + sgd_inc(mhba, m_sg); } return 0; @@ -1350,21 +1338,10 @@ static void mvumi_complete_cmd(struct mvumi_hba *mhba, struct mvumi_cmd *cmd, break; } - if (scsi_bufflen(scmd)) { - if (scsi_sg_count(scmd)) { - pci_unmap_sg(mhba->pdev, - scsi_sglist(scmd), - scsi_sg_count(scmd), - (int) scmd->sc_data_direction); - } else { - pci_unmap_single(mhba->pdev, - scmd->SCp.dma_handle, - scsi_bufflen(scmd), - (int) scmd->sc_data_direction); - - scmd->SCp.dma_handle = 0; - } - } + if (scsi_bufflen(scmd)) + pci_unmap_sg(mhba->pdev, scsi_sglist(scmd), + scsi_sg_count(scmd), + (int) scmd->sc_data_direction); cmd->scmd->scsi_done(scmd); mvumi_return_cmd(mhba, cmd); } @@ -2171,19 +2148,9 @@ static enum blk_eh_timer_return mvumi_timed_out(struct scsi_cmnd *scmd) scmd->result = (DRIVER_INVALID << 24) | (DID_ABORT << 16); scmd->SCp.ptr = NULL; if (scsi_bufflen(scmd)) { - if (scsi_sg_count(scmd)) { - pci_unmap_sg(mhba->pdev, - scsi_sglist(scmd), - scsi_sg_count(scmd), - (int)scmd->sc_data_direction); - } else { - pci_unmap_single(mhba->pdev, - scmd->SCp.dma_handle, - scsi_bufflen(scmd), - (int)scmd->sc_data_direction); - - scmd->SCp.dma_handle = 0; - } + pci_unmap_sg(mhba->pdev, scsi_sglist(scmd), + scsi_sg_count(scmd), + (int)scmd->sc_data_direction); } mvumi_return_cmd(mhba, cmd); spin_unlock_irqrestore(mhba->shost->host_lock, flags); -- cgit v1.2.3 From e791ce27c3f6a1d3c746fd6a8f8e36c9540ec6f9 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Mon, 24 Apr 2017 10:26:36 +0200 Subject: scsi: sg: reset 'res_in_use' after unlinking reserved array Once the reserved page array is unused we can reset the 'res_in_use' state; here we can do a lazy update without holding the mutex as we only need to check against concurrent access, not concurrent release. [mkp: checkpatch] Fixes: 1bc0eb044615 ("scsi: sg: protect accesses to 'reserved' page array") Signed-off-by: Hannes Reinecke Reviewed-by: Johannes Thumshirn Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/sg.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 8147147df2f4..06503c10ea27 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -2056,6 +2056,8 @@ sg_unlink_reserve(Sg_fd * sfp, Sg_request * srp) req_schp->page_order = 0; req_schp->sglist_len = 0; srp->res_used = 0; + /* Called without mutex lock to avoid deadlock */ + sfp->res_in_use = 0; } static Sg_request * -- cgit v1.2.3 From cfd2aff711aa9de301258d322a0b5a3c64010220 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Mon, 24 Apr 2017 11:22:32 +0200 Subject: scsi: mpt: Move scsi_remove_host() out of mptscsih_remove_host() Commit c5ce0abeb628 ("scsi: sas: move scsi_remove_host call...") moved the call to scsi_remove_host() into sas_remove_host(), but forgot to modify the mpt drivers. Fixes: c5ce0abeb628 ("scsi: sas: move scsi_remove_host call into sas_remove_host") Signed-off-by: Hannes Reinecke Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/message/fusion/mptfc.c | 7 ++++++- drivers/message/fusion/mptscsih.c | 2 -- drivers/message/fusion/mptspi.c | 10 +++++++++- 3 files changed, 15 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c index 98eafae78576..d065062240bc 100644 --- a/drivers/message/fusion/mptfc.c +++ b/drivers/message/fusion/mptfc.c @@ -1329,7 +1329,7 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id) WQ_MEM_RECLAIM); if (!ioc->fc_rescan_work_q) { error = -ENOMEM; - goto out_mptfc_probe; + goto out_mptfc_host; } /* @@ -1351,6 +1351,9 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id) return 0; +out_mptfc_host: + scsi_remove_host(sh); + out_mptfc_probe: mptscsih_remove(pdev); @@ -1530,6 +1533,8 @@ static void mptfc_remove(struct pci_dev *pdev) } } + scsi_remove_host(ioc->sh); + mptscsih_remove(pdev); } diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index 08a807d6a44f..6ba07c7feb92 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -1176,8 +1176,6 @@ mptscsih_remove(struct pci_dev *pdev) MPT_SCSI_HOST *hd; int sz1; - scsi_remove_host(host); - if((hd = shost_priv(host)) == NULL) return; diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c index 031e088edb5e..9a336a161d9f 100644 --- a/drivers/message/fusion/mptspi.c +++ b/drivers/message/fusion/mptspi.c @@ -1548,11 +1548,19 @@ out_mptspi_probe: return error; } +static void mptspi_remove(struct pci_dev *pdev) +{ + MPT_ADAPTER *ioc = pci_get_drvdata(pdev); + + scsi_remove_host(ioc->sh); + mptscsih_remove(pdev); +} + static struct pci_driver mptspi_driver = { .name = "mptspi", .id_table = mptspi_pci_table, .probe = mptspi_probe, - .remove = mptscsih_remove, + .remove = mptspi_remove, .shutdown = mptscsih_shutdown, #ifdef CONFIG_PM .suspend = mptscsih_suspend, -- cgit v1.2.3 From b1391a5bf83a593bbe92d1f9bddaf563be5c7c9d Mon Sep 17 00:00:00 2001 From: Sinan Kaya Date: Fri, 7 Apr 2017 15:06:18 -0400 Subject: scsi: mpt3sas: remove redundant wmb Due to relaxed ordering requirements on multiple architectures, drivers are required to use wmb/rmb/mb combinations when they need to guarantee observability between the memory and the HW. The mpt3sas driver is already using wmb() for this purpose. However, it issues a writel following wmb(). writel() function on arm/arm64 arhictectures have an embedded wmb() call inside. This results in unnecessary performance loss and code duplication. writel already guarantees ordering for both cpu and bus. we don't need additional wmb() Signed-off-by: Sinan Kaya Acked-by: Sreekanth Reddy Reviewed-by: Brian King Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_base.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index 5b7aec5d575a..18039bba26c4 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -1025,7 +1025,6 @@ _base_interrupt(int irq, void *bus_id) 0 : ioc->reply_free_host_index + 1; ioc->reply_free[ioc->reply_free_host_index] = cpu_to_le32(reply); - wmb(); writel(ioc->reply_free_host_index, &ioc->chip->ReplyFreeHostIndex); } @@ -1074,7 +1073,6 @@ _base_interrupt(int irq, void *bus_id) return IRQ_NONE; } - wmb(); if (ioc->is_warpdrive) { writel(reply_q->reply_post_host_index, ioc->reply_post_host_index[msix_index]); -- cgit v1.2.3 From 7529fbb0080d67bc45a3cdad91574cdd0f8a31cf Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Mon, 24 Apr 2017 16:51:09 +0900 Subject: scsi: sd: Fix function descriptions Fix argument names and description of function documentation comments. No functional change is introduced by this patch. [mkp: verbify] Signed-off-by: Damien Le Moal Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/sd.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 00b168b6a5fc..c385d903c253 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -705,11 +705,10 @@ static void sd_config_discard(struct scsi_disk *sdkp, unsigned int mode) /** * sd_setup_discard_cmnd - unmap blocks on thinly provisioned device - * @sdp: scsi device to operate on - * @rq: Request to prepare + * @cmd: command to prepare * - * Will issue either UNMAP or WRITE SAME(16) depending on preference - * indicated by target device. + * Will set up either UNMAP, WRITE SAME(16) or WRITE SAME(10) depending + * on the provisioning mode of the target device. **/ static int sd_setup_discard_cmnd(struct scsi_cmnd *cmd) { @@ -827,8 +826,8 @@ out: * sd_setup_write_same_cmnd - write the same data to multiple blocks * @cmd: command to prepare * - * Will issue either WRITE SAME(10) or WRITE SAME(16) depending on - * preference indicated by target device. + * Will set up either WRITE SAME(10) or WRITE SAME(16) depending on + * the preference indicated by the target device. **/ static int sd_setup_write_same_cmnd(struct scsi_cmnd *cmd) { @@ -1190,8 +1189,8 @@ static void sd_uninit_command(struct scsi_cmnd *SCpnt) /** * sd_open - open a scsi disk device - * @inode: only i_rdev member may be used - * @filp: only f_mode and f_flags may be used + * @bdev: Block device of the scsi disk to open + * @mode: FMODE_* mask * * Returns 0 if successful. Returns a negated errno value in case * of error. @@ -1267,8 +1266,8 @@ error_out: /** * sd_release - invoked when the (last) close(2) is called on this * scsi disk. - * @inode: only i_rdev member may be used - * @filp: only f_mode and f_flags may be used + * @disk: disk to release + * @mode: FMODE_* mask * * Returns 0. * @@ -1324,8 +1323,8 @@ static int sd_getgeo(struct block_device *bdev, struct hd_geometry *geo) /** * sd_ioctl - process an ioctl - * @inode: only i_rdev/i_bdev members may be used - * @filp: only f_mode and f_flags may be used + * @bdev: target block device + * @mode: FMODE_* mask * @cmd: ioctl command number * @arg: this is third argument given to ioctl(2) system call. * Often contains a pointer. @@ -2713,7 +2712,7 @@ static void sd_read_app_tag_own(struct scsi_disk *sdkp, unsigned char *buffer) /** * sd_read_block_limits - Query disk device for preferred I/O sizes. - * @disk: disk to query + * @sdkp: disk to query */ static void sd_read_block_limits(struct scsi_disk *sdkp) { @@ -2779,7 +2778,7 @@ static void sd_read_block_limits(struct scsi_disk *sdkp) /** * sd_read_block_characteristics - Query block dev. characteristics - * @disk: disk to query + * @sdkp: disk to query */ static void sd_read_block_characteristics(struct scsi_disk *sdkp) { @@ -2827,7 +2826,7 @@ static void sd_read_block_characteristics(struct scsi_disk *sdkp) /** * sd_read_block_provisioning - Query provisioning VPD page - * @disk: disk to query + * @sdkp: disk to query */ static void sd_read_block_provisioning(struct scsi_disk *sdkp) { -- cgit v1.2.3 From 6eadc61224666dcc79763dc21749b5f809d82140 Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Mon, 24 Apr 2017 16:51:10 +0900 Subject: scsi: sd: Improve sd_completed_bytes Re-shuffle the code to be more efficient by not initializing variables upfront (i.e. do it only when necessary). Also replace the do_div calls with calls to sectors_to_logical(). No functional change is introduced by this patch. [mkp: bytes_to_logical()] Signed-off-by: Damien Le Moal Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/sd.c | 51 +++++++++++++++++++++++++++------------------------ drivers/scsi/sd.h | 5 +++++ 2 files changed, 32 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index c385d903c253..1cc5dd20e2f2 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1758,41 +1758,44 @@ static int sd_eh_action(struct scsi_cmnd *scmd, int eh_disp) static unsigned int sd_completed_bytes(struct scsi_cmnd *scmd) { - u64 start_lba = blk_rq_pos(scmd->request); - u64 end_lba = blk_rq_pos(scmd->request) + (scsi_bufflen(scmd) / 512); - u64 factor = scmd->device->sector_size / 512; - u64 bad_lba; - int info_valid; + struct request *req = scmd->request; + struct scsi_device *sdev = scmd->device; + unsigned int transferred, good_bytes; + u64 start_lba, end_lba, bad_lba; + /* - * resid is optional but mostly filled in. When it's unused, - * its value is zero, so we assume the whole buffer transferred + * Some commands have a payload smaller than the device logical + * block size (e.g. INQUIRY on a 4K disk). */ - unsigned int transferred = scsi_bufflen(scmd) - scsi_get_resid(scmd); - unsigned int good_bytes; - - info_valid = scsi_get_sense_info_fld(scmd->sense_buffer, - SCSI_SENSE_BUFFERSIZE, - &bad_lba); - if (!info_valid) + if (scsi_bufflen(scmd) <= sdev->sector_size) return 0; - if (scsi_bufflen(scmd) <= scmd->device->sector_size) + /* Check if we have a 'bad_lba' information */ + if (!scsi_get_sense_info_fld(scmd->sense_buffer, + SCSI_SENSE_BUFFERSIZE, + &bad_lba)) return 0; - /* be careful ... don't want any overflows */ - do_div(start_lba, factor); - do_div(end_lba, factor); - - /* The bad lba was reported incorrectly, we have no idea where + /* + * If the bad lba was reported incorrectly, we have no idea where * the error is. */ - if (bad_lba < start_lba || bad_lba >= end_lba) + start_lba = sectors_to_logical(sdev, blk_rq_pos(req)); + end_lba = start_lba + bytes_to_logical(sdev, scsi_bufflen(scmd)); + if (bad_lba < start_lba || bad_lba >= end_lba) return 0; - /* This computation should always be done in terms of - * the resolution of the device's medium. + /* + * resid is optional but mostly filled in. When it's unused, + * its value is zero, so we assume the whole buffer transferred */ - good_bytes = (bad_lba - start_lba) * scmd->device->sector_size; + transferred = scsi_bufflen(scmd) - scsi_get_resid(scmd); + + /* This computation should always be done in terms of the + * resolution of the device's medium. + */ + good_bytes = logical_to_bytes(sdev, bad_lba - start_lba); + return min(good_bytes, transferred); } diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h index 0cf9680cb469..e6241c445878 100644 --- a/drivers/scsi/sd.h +++ b/drivers/scsi/sd.h @@ -169,6 +169,11 @@ static inline unsigned int logical_to_bytes(struct scsi_device *sdev, sector_t b return blocks * sdev->sector_size; } +static inline sector_t bytes_to_logical(struct scsi_device *sdev, unsigned int bytes) +{ + return bytes >> ilog2(sdev->sector_size); +} + static inline sector_t sectors_to_logical(struct scsi_device *sdev, sector_t sector) { return sector >> (ilog2(sdev->sector_size) - 9); -- cgit v1.2.3 From d227ec267ff4fa91ac2db9965d5392cf825be511 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 24 Apr 2017 19:05:12 -0400 Subject: scsi: sd: Cleanup sd_done sense data handling Use a switch for the sense key, and remove two pointless variables that are only used once. [mkp: Added UNMAP comment and removed good_bytes based on comment from Damien] Signed-off-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/sd.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 1cc5dd20e2f2..7aa00d95f69f 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1815,8 +1815,6 @@ static int sd_done(struct scsi_cmnd *SCpnt) struct request *req = SCpnt->request; int sense_valid = 0; int sense_deferred = 0; - unsigned char op = SCpnt->cmnd[0]; - unsigned char unmap = SCpnt->cmnd[1] & 8; switch (req_op(req)) { case REQ_OP_DISCARD: @@ -1874,26 +1872,27 @@ static int sd_done(struct scsi_cmnd *SCpnt) good_bytes = sd_completed_bytes(SCpnt); break; case ILLEGAL_REQUEST: - if (sshdr.asc == 0x10) /* DIX: Host detected corruption */ + switch (sshdr.asc) { + case 0x10: /* DIX: Host detected corruption */ good_bytes = sd_completed_bytes(SCpnt); - /* INVALID COMMAND OPCODE or INVALID FIELD IN CDB */ - if (sshdr.asc == 0x20 || sshdr.asc == 0x24) { - switch (op) { + break; + case 0x20: /* INVALID COMMAND OPCODE */ + case 0x24: /* INVALID FIELD IN CDB */ + switch (SCpnt->cmnd[0]) { case UNMAP: sd_config_discard(sdkp, SD_LBP_DISABLE); break; case WRITE_SAME_16: case WRITE_SAME: - if (unmap) + if (SCpnt->cmnd[1] & 8) { /* UNMAP */ sd_config_discard(sdkp, SD_LBP_DISABLE); - else { + } else { sdkp->device->no_write_same = 1; sd_config_write_same(sdkp); - - good_bytes = 0; req->__data_len = blk_rq_bytes(req); req->rq_flags |= RQF_QUIET; } + break; } } break; -- cgit v1.2.3 From 2908769c35fbd3de7b874b60b95ba81546e3c920 Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Mon, 24 Apr 2017 16:51:12 +0900 Subject: scsi: Improve scsi_get_sense_info_fld Use get_unaligned_be32 and get_unaligned_be64 to obtain values from the sense buffer instead of open coding the operations. Also change the function return value to a bool and fix the function signature declaration to remove spaces triggering checkpatch warnings. No functional change is introduced by this patch. Signed-off-by: Damien Le Moal Reviewed-by: Bart Van Assche Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_error.c | 38 +++++++++++++++----------------------- include/scsi/scsi_eh.h | 4 ++-- 2 files changed, 17 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 53e334356f31..d70c67cf46ef 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -46,6 +46,8 @@ #include +#include + static void scsi_eh_done(struct scsi_cmnd *scmd); /* @@ -2361,44 +2363,34 @@ EXPORT_SYMBOL(scsi_command_normalize_sense); * field will be placed if found. * * Return value: - * 1 if information field found, 0 if not found. + * true if information field found, false if not found. */ -int scsi_get_sense_info_fld(const u8 * sense_buffer, int sb_len, - u64 * info_out) +bool scsi_get_sense_info_fld(const u8 *sense_buffer, int sb_len, + u64 *info_out) { - int j; const u8 * ucp; - u64 ull; if (sb_len < 7) - return 0; + return false; switch (sense_buffer[0] & 0x7f) { case 0x70: case 0x71: if (sense_buffer[0] & 0x80) { - *info_out = (sense_buffer[3] << 24) + - (sense_buffer[4] << 16) + - (sense_buffer[5] << 8) + sense_buffer[6]; - return 1; - } else - return 0; + *info_out = get_unaligned_be32(&sense_buffer[3]); + return true; + } + return false; case 0x72: case 0x73: ucp = scsi_sense_desc_find(sense_buffer, sb_len, 0 /* info desc */); if (ucp && (0xa == ucp[1])) { - ull = 0; - for (j = 0; j < 8; ++j) { - if (j > 0) - ull <<= 8; - ull |= ucp[4 + j]; - } - *info_out = ull; - return 1; - } else - return 0; + *info_out = get_unaligned_be64(&ucp[4]); + return true; + } + return false; default: - return 0; + return false; } } EXPORT_SYMBOL(scsi_get_sense_info_fld); diff --git a/include/scsi/scsi_eh.h b/include/scsi/scsi_eh.h index a25b3285dd6f..64d30d80dadb 100644 --- a/include/scsi/scsi_eh.h +++ b/include/scsi/scsi_eh.h @@ -23,8 +23,8 @@ static inline bool scsi_sense_is_deferred(const struct scsi_sense_hdr *sshdr) return ((sshdr->response_code >= 0x70) && (sshdr->response_code & 1)); } -extern int scsi_get_sense_info_fld(const u8 * sense_buffer, int sb_len, - u64 * info_out); +extern bool scsi_get_sense_info_fld(const u8 *sense_buffer, int sb_len, + u64 *info_out); extern int scsi_ioctl_reset(struct scsi_device *, int __user *); -- cgit v1.2.3 From a90dfdc2dea1ce8ab87e3949c3c6bab3c1e36137 Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Mon, 24 Apr 2017 16:51:13 +0900 Subject: scsi: sd: sd_zbc: Rename sd_zbc_setup_write_cmnd Rename sd_zbc_setup_write_cmnd() to sd_zbc_write_lock_zone() to be clear about what the function actually does. To be consistent, also rename sd_zbc_cancel_write_cmnd() to sd_zbc_write_unlock_zone(). No functional change is introduced by this patch. Signed-off-by: Damien Le Moal Reviewed-by: Bart Van Assche Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/sd.c | 6 +++--- drivers/scsi/sd.h | 8 ++++---- drivers/scsi/sd_zbc.c | 12 ++++-------- 3 files changed, 11 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 7aa00d95f69f..4195b7c7f81e 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -846,7 +846,7 @@ static int sd_setup_write_same_cmnd(struct scsi_cmnd *cmd) BUG_ON(bio_offset(bio) || bio_iovec(bio).bv_len != sdp->sector_size); if (sd_is_zoned(sdkp)) { - ret = sd_zbc_setup_write_cmnd(cmd); + ret = sd_zbc_write_lock_zone(cmd); if (ret != BLKPREP_OK) return ret; } @@ -918,7 +918,7 @@ static int sd_setup_read_write_cmnd(struct scsi_cmnd *SCpnt) unsigned char protect; if (zoned_write) { - ret = sd_zbc_setup_write_cmnd(SCpnt); + ret = sd_zbc_write_lock_zone(SCpnt); if (ret != BLKPREP_OK) return ret; } @@ -1145,7 +1145,7 @@ static int sd_setup_read_write_cmnd(struct scsi_cmnd *SCpnt) ret = BLKPREP_OK; out: if (zoned_write && ret != BLKPREP_OK) - sd_zbc_cancel_write_cmnd(SCpnt); + sd_zbc_write_unlock_zone(SCpnt); return ret; } diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h index e6241c445878..952100232e24 100644 --- a/drivers/scsi/sd.h +++ b/drivers/scsi/sd.h @@ -272,8 +272,8 @@ static inline int sd_is_zoned(struct scsi_disk *sdkp) extern int sd_zbc_read_zones(struct scsi_disk *sdkp, unsigned char *buffer); extern void sd_zbc_remove(struct scsi_disk *sdkp); extern void sd_zbc_print_zones(struct scsi_disk *sdkp); -extern int sd_zbc_setup_write_cmnd(struct scsi_cmnd *cmd); -extern void sd_zbc_cancel_write_cmnd(struct scsi_cmnd *cmd); +extern int sd_zbc_write_lock_zone(struct scsi_cmnd *cmd); +extern void sd_zbc_write_unlock_zone(struct scsi_cmnd *cmd); extern int sd_zbc_setup_report_cmnd(struct scsi_cmnd *cmd); extern int sd_zbc_setup_reset_cmnd(struct scsi_cmnd *cmd); extern void sd_zbc_complete(struct scsi_cmnd *cmd, unsigned int good_bytes, @@ -291,13 +291,13 @@ static inline void sd_zbc_remove(struct scsi_disk *sdkp) {} static inline void sd_zbc_print_zones(struct scsi_disk *sdkp) {} -static inline int sd_zbc_setup_write_cmnd(struct scsi_cmnd *cmd) +static inline int sd_zbc_write_lock_zone(struct scsi_cmnd *cmd) { /* Let the drive fail requests */ return BLKPREP_OK; } -static inline void sd_zbc_cancel_write_cmnd(struct scsi_cmnd *cmd) {} +static inline void sd_zbc_write_unlock_zone(struct scsi_cmnd *cmd) {} static inline int sd_zbc_setup_report_cmnd(struct scsi_cmnd *cmd) { diff --git a/drivers/scsi/sd_zbc.c b/drivers/scsi/sd_zbc.c index 92620c8ea8ad..a7926825b120 100644 --- a/drivers/scsi/sd_zbc.c +++ b/drivers/scsi/sd_zbc.c @@ -269,7 +269,7 @@ int sd_zbc_setup_reset_cmnd(struct scsi_cmnd *cmd) return BLKPREP_OK; } -int sd_zbc_setup_write_cmnd(struct scsi_cmnd *cmd) +int sd_zbc_write_lock_zone(struct scsi_cmnd *cmd) { struct request *rq = cmd->request; struct scsi_disk *sdkp = scsi_disk(rq->rq_disk); @@ -303,8 +303,9 @@ int sd_zbc_setup_write_cmnd(struct scsi_cmnd *cmd) return BLKPREP_OK; } -static void sd_zbc_unlock_zone(struct request *rq) +void sd_zbc_write_unlock_zone(struct scsi_cmnd *cmd) { + struct request *rq = cmd->request; struct scsi_disk *sdkp = scsi_disk(rq->rq_disk); if (sdkp->zones_wlock) { @@ -315,11 +316,6 @@ static void sd_zbc_unlock_zone(struct request *rq) } } -void sd_zbc_cancel_write_cmnd(struct scsi_cmnd *cmd) -{ - sd_zbc_unlock_zone(cmd->request); -} - void sd_zbc_complete(struct scsi_cmnd *cmd, unsigned int good_bytes, struct scsi_sense_hdr *sshdr) @@ -333,7 +329,7 @@ void sd_zbc_complete(struct scsi_cmnd *cmd, case REQ_OP_ZONE_RESET: /* Unlock the zone */ - sd_zbc_unlock_zone(rq); + sd_zbc_write_unlock_zone(cmd); if (!result || sshdr->sense_key != ILLEGAL_REQUEST) -- cgit v1.2.3 From f70532406aa4193e484b1e3c4d7d613f39257a44 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 24 Apr 2017 16:51:14 +0900 Subject: scsi: sd_zbc: Remove superfluous assignments A value is assigned to the variable 'capacity' in sd_zbc_read_zones() but that value is never used. Hence remove the variable 'capacity'. [Damien: There is no need to initialize to 0 the variable 'ret' in sd_zbc_read_zones()] Signed-off-by: Bart Van Assche Signed-off-by: Damien Le Moal Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/sd_zbc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/sd_zbc.c b/drivers/scsi/sd_zbc.c index a7926825b120..29ba1d7e9b2e 100644 --- a/drivers/scsi/sd_zbc.c +++ b/drivers/scsi/sd_zbc.c @@ -560,8 +560,7 @@ static int sd_zbc_setup(struct scsi_disk *sdkp) int sd_zbc_read_zones(struct scsi_disk *sdkp, unsigned char *buf) { - sector_t capacity; - int ret = 0; + int ret; if (!sd_is_zoned(sdkp)) /* @@ -593,7 +592,6 @@ int sd_zbc_read_zones(struct scsi_disk *sdkp, ret = sd_zbc_check_capacity(sdkp, buf); if (ret) goto err; - capacity = logical_to_sectors(sdkp->device, sdkp->capacity); /* * Check zone size: only devices with a constant zone size (except -- cgit v1.2.3 From 868ed5a5b73f7cc18432ffe6e8d8addd395e91a1 Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Mon, 24 Apr 2017 16:51:15 +0900 Subject: scsi: sd_zbc: Do not write lock zones for reset Resetting a zone write pointer is equivalent to discarding sectors: after a reset, the zone sectors will contain zeros (or the format pattern). So there is no need for mutual exclusion between a zone reset and write. Similarly to discard, make it the responsability of the user to properly synchronize between reset and write (as is done now for discard and write). Signed-off-by: Damien Le Moal Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/sd_zbc.c | 42 ++++++++++++++++-------------------------- 1 file changed, 16 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/sd_zbc.c b/drivers/scsi/sd_zbc.c index 29ba1d7e9b2e..fcf0fad72dd9 100644 --- a/drivers/scsi/sd_zbc.c +++ b/drivers/scsi/sd_zbc.c @@ -237,7 +237,6 @@ int sd_zbc_setup_reset_cmnd(struct scsi_cmnd *cmd) struct scsi_disk *sdkp = scsi_disk(rq->rq_disk); sector_t sector = blk_rq_pos(rq); sector_t block = sectors_to_logical(sdkp->device, sector); - unsigned int zno = block >> sdkp->zone_shift; if (!sd_is_zoned(sdkp)) /* Not a zoned device */ @@ -250,11 +249,6 @@ int sd_zbc_setup_reset_cmnd(struct scsi_cmnd *cmd) /* Unaligned request */ return BLKPREP_KILL; - /* Do not allow concurrent reset and writes */ - if (sdkp->zones_wlock && - test_and_set_bit(zno, sdkp->zones_wlock)) - return BLKPREP_DEFER; - cmd->cmd_len = 16; memset(cmd->cmnd, 0, cmd->cmd_len); cmd->cmnd[0] = ZBC_OUT; @@ -324,38 +318,34 @@ void sd_zbc_complete(struct scsi_cmnd *cmd, struct request *rq = cmd->request; switch (req_op(rq)) { + case REQ_OP_ZONE_RESET: + + if (result && + sshdr->sense_key == ILLEGAL_REQUEST && + sshdr->asc == 0x24) + /* + * INVALID FIELD IN CDB error: reset of a conventional + * zone was attempted. Nothing to worry about, so be + * quiet about the error. + */ + rq->rq_flags |= RQF_QUIET; + break; + case REQ_OP_WRITE: case REQ_OP_WRITE_SAME: - case REQ_OP_ZONE_RESET: /* Unlock the zone */ sd_zbc_write_unlock_zone(cmd); - if (!result || - sshdr->sense_key != ILLEGAL_REQUEST) - break; - - switch (sshdr->asc) { - case 0x24: - /* - * INVALID FIELD IN CDB error: For a zone reset, - * this means that a reset of a conventional - * zone was attempted. Nothing to worry about in - * this case, so be quiet about the error. - */ - if (req_op(rq) == REQ_OP_ZONE_RESET) - rq->rq_flags |= RQF_QUIET; - break; - case 0x21: + if (result && + sshdr->sense_key == ILLEGAL_REQUEST && + sshdr->asc == 0x21) /* * INVALID ADDRESS FOR WRITE error: It is unlikely that * retrying write requests failed with any kind of * alignement error will result in success. So don't. */ cmd->allowed = 0; - break; - } - break; case REQ_OP_ZONE_REPORT: -- cgit v1.2.3 From 62d57f20ff6d9715c5d7605c5b6b1a2e6f4fbbd8 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 24 Apr 2017 18:04:18 +0100 Subject: scsi: fcoe: make fcoe_e_d_tov and fcoe_r_a_tov static These module parameter variables don't need global scope, make them static Signed-off-by: Colin Ian King Acked-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/fcoe/fcoe.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index ab7bc1505e0b..90939f66bc0d 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -63,11 +63,11 @@ unsigned int fcoe_debug_logging; module_param_named(debug_logging, fcoe_debug_logging, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(debug_logging, "a bit mask of logging levels"); -unsigned int fcoe_e_d_tov = 2 * 1000; +static unsigned int fcoe_e_d_tov = 2 * 1000; module_param_named(e_d_tov, fcoe_e_d_tov, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(e_d_tov, "E_D_TOV in ms, default 2000"); -unsigned int fcoe_r_a_tov = 2 * 2 * 1000; +static unsigned int fcoe_r_a_tov = 2 * 2 * 1000; module_param_named(r_a_tov, fcoe_r_a_tov, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(r_a_tov, "R_A_TOV in ms, default 4000"); -- cgit v1.2.3 From 4da2b1eb230ba4ad19b58984dc52e05b1073df5f Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Sun, 2 Apr 2017 17:08:05 +1000 Subject: scsi: mac_esp: Replace bogus memory barrier with spinlock Commit da244654c66e ("[SCSI] mac_esp: fix for quadras with two esp chips") added mac_scsi_esp_intr() to handle the IRQ lines from a pair of on-board ESP chips (a normal shared IRQ did not work). Proper mutual exclusion was missing from that patch. This patch fixes race conditions between comparison and assignment of esp_chips[] pointers. Signed-off-by: Finn Thain Reviewed-by: Michael Schmitz Signed-off-by: Martin K. Petersen --- drivers/scsi/mac_esp.c | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c index 14c0334f41e4..26c67c42985c 100644 --- a/drivers/scsi/mac_esp.c +++ b/drivers/scsi/mac_esp.c @@ -55,6 +55,7 @@ struct mac_esp_priv { int error; }; static struct esp *esp_chips[2]; +static DEFINE_SPINLOCK(esp_chips_lock); #define MAC_ESP_GET_PRIV(esp) ((struct mac_esp_priv *) \ platform_get_drvdata((struct platform_device *) \ @@ -562,15 +563,18 @@ static int esp_mac_probe(struct platform_device *dev) } host->irq = IRQ_MAC_SCSI; - esp_chips[dev->id] = esp; - mb(); - if (esp_chips[!dev->id] == NULL) { - err = request_irq(host->irq, mac_scsi_esp_intr, 0, "ESP", NULL); - if (err < 0) { - esp_chips[dev->id] = NULL; - goto fail_free_priv; - } + + /* The request_irq() call is intended to succeed for the first device + * and fail for the second device. + */ + err = request_irq(host->irq, mac_scsi_esp_intr, 0, "ESP", NULL); + spin_lock(&esp_chips_lock); + if (err < 0 && esp_chips[!dev->id] == NULL) { + spin_unlock(&esp_chips_lock); + goto fail_free_priv; } + esp_chips[dev->id] = esp; + spin_unlock(&esp_chips_lock); err = scsi_esp_register(esp, &dev->dev); if (err) @@ -579,8 +583,13 @@ static int esp_mac_probe(struct platform_device *dev) return 0; fail_free_irq: - if (esp_chips[!dev->id] == NULL) + spin_lock(&esp_chips_lock); + esp_chips[dev->id] = NULL; + if (esp_chips[!dev->id] == NULL) { + spin_unlock(&esp_chips_lock); free_irq(host->irq, esp); + } else + spin_unlock(&esp_chips_lock); fail_free_priv: kfree(mep); fail_free_command_block: @@ -599,9 +608,13 @@ static int esp_mac_remove(struct platform_device *dev) scsi_esp_unregister(esp); + spin_lock(&esp_chips_lock); esp_chips[dev->id] = NULL; - if (!(esp_chips[0] || esp_chips[1])) + if (esp_chips[!dev->id] == NULL) { + spin_unlock(&esp_chips_lock); free_irq(irq, NULL); + } else + spin_unlock(&esp_chips_lock); kfree(mep); -- cgit v1.2.3 From d7e2ddd5e502c93dc29114cf6de5fba339b28e4d Mon Sep 17 00:00:00 2001 From: Tomohiro Kusumi Date: Thu, 20 Apr 2017 15:01:44 +0300 Subject: scsi: ufs: use MASK_EE_STATUS MASK_EE_STATUS added by 66ec6d59 was unused, but it seems to have been defined to do this. Signed-off-by: Tomohiro Kusumi Reviewed-by: Subhash Jadavani Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 7dad1c0b775d..68d7d6fc9458 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -4629,7 +4629,7 @@ static int ufshcd_disable_ee(struct ufs_hba *hba, u16 mask) goto out; val = hba->ee_ctrl_mask & ~mask; - val &= 0xFFFF; /* 2 bytes */ + val &= MASK_EE_STATUS; err = ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_WRITE_ATTR, QUERY_ATTR_IDN_EE_CONTROL, 0, 0, &val); if (!err) @@ -4657,7 +4657,7 @@ static int ufshcd_enable_ee(struct ufs_hba *hba, u16 mask) goto out; val = hba->ee_ctrl_mask | mask; - val &= 0xFFFF; /* 2 bytes */ + val &= MASK_EE_STATUS; err = ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_WRITE_ATTR, QUERY_ATTR_IDN_EE_CONTROL, 0, 0, &val); if (!err) -- cgit v1.2.3 From 6cf161150d815da0ee8cff158b185bc33dca3a34 Mon Sep 17 00:00:00 2001 From: Tomohiro Kusumi Date: Wed, 26 Apr 2017 20:28:58 +0300 Subject: scsi: ufs: make ufshcd_get_lists_status() register operation obvious It could be just cmp 0xe instead of >>1 and cmp 0x7, with readable code. Signed-off-by: Tomohiro Kusumi Reviewed-by: Subhash Jadavani Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 11 +---------- drivers/scsi/ufs/ufshci.h | 4 ++++ 2 files changed, 5 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 68d7d6fc9458..5793cd7ad371 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -673,16 +673,7 @@ static inline void ufshcd_outstanding_req_clear(struct ufs_hba *hba, int tag) */ static inline int ufshcd_get_lists_status(u32 reg) { - /* - * The mask 0xFF is for the following HCS register bits - * Bit Description - * 0 Device Present - * 1 UTRLRDY - * 2 UTMRLRDY - * 3 UCRDY - * 4-7 reserved - */ - return ((reg & 0xFF) >> 1) ^ 0x07; + return !((reg & UFSHCD_STATUS_READY) == UFSHCD_STATUS_READY); } /** diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h index 88acfd3e21af..f60145d4a66e 100644 --- a/drivers/scsi/ufs/ufshci.h +++ b/drivers/scsi/ufs/ufshci.h @@ -160,6 +160,10 @@ enum { #define DEVICE_ERROR_INDICATOR UFS_BIT(5) #define UIC_POWER_MODE_CHANGE_REQ_STATUS_MASK UFS_MASK(0x7, 8) +#define UFSHCD_STATUS_READY (UTP_TRANSFER_REQ_LIST_READY |\ + UTP_TASK_REQ_LIST_READY |\ + UIC_COMMAND_READY) + enum { PWR_OK = 0x0, PWR_LOCAL = 0x01, -- cgit v1.2.3 From f481973d5efdb63b7c6ca6b0ecd2b8462556a461 Mon Sep 17 00:00:00 2001 From: Mahesh Rajashekhara Date: Wed, 5 Apr 2017 16:14:16 +0530 Subject: scsi: aacraid: pci_alloc_consistent() failures on ARM64 There were pci_alloc_consistent() failures on ARM64 platform. Use dma_alloc_coherent() with GFP_KERNEL flag DMA memory allocations. Signed-off-by: Mahesh Rajashekhara [hch: tweaked indentation, removed memsets] Signed-off-by: Christoph Hellwig Acked-by: Dave Carroll Signed-off-by: Martin K. Petersen --- drivers/scsi/aacraid/aachba.c | 13 ++++++------- drivers/scsi/aacraid/commctrl.c | 6 ++++-- drivers/scsi/aacraid/comminit.c | 3 +-- drivers/scsi/aacraid/commsup.c | 20 +++++++++++--------- drivers/scsi/aacraid/linit.c | 8 ++++---- drivers/scsi/aacraid/rx.c | 16 +++++++++------- 6 files changed, 35 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index e3e93def722b..43d88389e899 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c @@ -1678,8 +1678,8 @@ int aac_issue_bmic_identify(struct aac_dev *dev, u32 bus, u32 target) sizeof(struct sgentry) + sizeof(struct sgentry64); datasize = sizeof(struct aac_ciss_identify_pd); - identify_resp = pci_alloc_consistent(dev->pdev, datasize, &addr); - + identify_resp = dma_alloc_coherent(&dev->pdev->dev, datasize, &addr, + GFP_KERNEL); if (!identify_resp) goto fib_free_ptr; @@ -1720,7 +1720,7 @@ int aac_issue_bmic_identify(struct aac_dev *dev, u32 bus, u32 target) dev->hba_map[bus][target].qd_limit = identify_resp->current_queue_depth_limit; - pci_free_consistent(dev->pdev, datasize, (void *)identify_resp, addr); + dma_free_coherent(&dev->pdev->dev, datasize, identify_resp, addr); aac_fib_complete(fibptr); @@ -1814,9 +1814,8 @@ int aac_report_phys_luns(struct aac_dev *dev, struct fib *fibptr, int rescan) datasize = sizeof(struct aac_ciss_phys_luns_resp) + (AAC_MAX_TARGETS - 1) * sizeof(struct _ciss_lun); - phys_luns = (struct aac_ciss_phys_luns_resp *) pci_alloc_consistent( - dev->pdev, datasize, &addr); - + phys_luns = dma_alloc_coherent(&dev->pdev->dev, datasize, &addr, + GFP_KERNEL); if (phys_luns == NULL) { rcode = -ENOMEM; goto err_out; @@ -1861,7 +1860,7 @@ int aac_report_phys_luns(struct aac_dev *dev, struct fib *fibptr, int rescan) aac_update_hba_map(dev, phys_luns, rescan); } - pci_free_consistent(dev->pdev, datasize, (void *) phys_luns, addr); + dma_free_coherent(&dev->pdev->dev, datasize, phys_luns, addr); err_out: return rcode; } diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c index f6afd50579c0..d2f8d5954840 100644 --- a/drivers/scsi/aacraid/commctrl.c +++ b/drivers/scsi/aacraid/commctrl.c @@ -100,7 +100,8 @@ static int ioctl_send_fib(struct aac_dev * dev, void __user *arg) goto cleanup; } - kfib = pci_alloc_consistent(dev->pdev, size, &daddr); + kfib = dma_alloc_coherent(&dev->pdev->dev, size, &daddr, + GFP_KERNEL); if (!kfib) { retval = -ENOMEM; goto cleanup; @@ -160,7 +161,8 @@ static int ioctl_send_fib(struct aac_dev * dev, void __user *arg) retval = -EFAULT; cleanup: if (hw_fib) { - pci_free_consistent(dev->pdev, size, kfib, fibptr->hw_fib_pa); + dma_free_coherent(&dev->pdev->dev, size, kfib, + fibptr->hw_fib_pa); fibptr->hw_fib_pa = hw_fib_pa; fibptr->hw_fib_va = hw_fib; } diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c index 35607005f7e1..1151505853cf 100644 --- a/drivers/scsi/aacraid/comminit.c +++ b/drivers/scsi/aacraid/comminit.c @@ -99,8 +99,7 @@ static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long co size = fibsize + aac_init_size + commsize + commalign + printfbufsiz + host_rrq_size; - base = pci_alloc_consistent(dev->pdev, size, &phys); - + base = dma_alloc_coherent(&dev->pdev->dev, size, &phys, GFP_KERNEL); if (base == NULL) { printk(KERN_ERR "aacraid: unable to create mapping.\n"); return 0; diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c index a3ad04293487..d08920d4b92c 100644 --- a/drivers/scsi/aacraid/commsup.c +++ b/drivers/scsi/aacraid/commsup.c @@ -73,13 +73,13 @@ static int fib_map_alloc(struct aac_dev *dev) } dprintk((KERN_INFO - "allocate hardware fibs pci_alloc_consistent(%p, %d * (%d + %d), %p)\n", - dev->pdev, dev->max_cmd_size, dev->scsi_host_ptr->can_queue, + "allocate hardware fibs dma_alloc_coherent(%p, %d * (%d + %d), %p)\n", + &dev->pdev->dev, dev->max_cmd_size, dev->scsi_host_ptr->can_queue, AAC_NUM_MGT_FIB, &dev->hw_fib_pa)); - dev->hw_fib_va = pci_alloc_consistent(dev->pdev, + dev->hw_fib_va = dma_alloc_coherent(&dev->pdev->dev, (dev->max_cmd_size + sizeof(struct aac_fib_xporthdr)) * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB) + (ALIGN32 - 1), - &dev->hw_fib_pa); + &dev->hw_fib_pa, GFP_KERNEL); if (dev->hw_fib_va == NULL) return -ENOMEM; return 0; @@ -106,8 +106,8 @@ void aac_fib_map_free(struct aac_dev *dev) fib_size = dev->max_fib_size + sizeof(struct aac_fib_xporthdr); alloc_size = fib_size * num_fibs + ALIGN32 - 1; - pci_free_consistent(dev->pdev, alloc_size, dev->hw_fib_va, - dev->hw_fib_pa); + dma_free_coherent(&dev->pdev->dev, alloc_size, dev->hw_fib_va, + dev->hw_fib_pa); dev->hw_fib_va = NULL; dev->hw_fib_pa = 0; @@ -1571,7 +1571,8 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced, u8 reset_type) * case. */ aac_fib_map_free(aac); - pci_free_consistent(aac->pdev, aac->comm_size, aac->comm_addr, aac->comm_phys); + dma_free_coherent(&aac->pdev->dev, aac->comm_size, aac->comm_addr, + aac->comm_phys); aac->comm_addr = NULL; aac->comm_phys = 0; kfree(aac->queues); @@ -2320,7 +2321,8 @@ static int aac_send_wellness_command(struct aac_dev *dev, char *wellness_str, if (!fibptr) goto out; - dma_buf = pci_alloc_consistent(dev->pdev, datasize, &addr); + dma_buf = dma_alloc_coherent(&dev->pdev->dev, datasize, &addr, + GFP_KERNEL); if (!dma_buf) goto fib_free_out; @@ -2355,7 +2357,7 @@ static int aac_send_wellness_command(struct aac_dev *dev, char *wellness_str, ret = aac_fib_send(ScsiPortCommand64, fibptr, sizeof(struct aac_srb), FsaNormal, 1, 1, NULL, NULL); - pci_free_consistent(dev->pdev, datasize, (void *)dma_buf, addr); + dma_free_coherent(&dev->pdev->dev, datasize, dma_buf, addr); /* * Do not set XferState to zero unless diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index 520ada8266af..372a07533026 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -1592,8 +1592,8 @@ static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) out_unmap: aac_fib_map_free(aac); if (aac->comm_addr) - pci_free_consistent(aac->pdev, aac->comm_size, aac->comm_addr, - aac->comm_phys); + dma_free_coherent(&aac->pdev->dev, aac->comm_size, + aac->comm_addr, aac->comm_phys); kfree(aac->queues); aac_adapter_ioremap(aac, 0); kfree(aac->fibs); @@ -1729,8 +1729,8 @@ static void aac_remove_one(struct pci_dev *pdev) __aac_shutdown(aac); aac_fib_map_free(aac); - pci_free_consistent(aac->pdev, aac->comm_size, aac->comm_addr, - aac->comm_phys); + dma_free_coherent(&aac->pdev->dev, aac->comm_size, aac->comm_addr, + aac->comm_phys); kfree(aac->queues); aac_adapter_ioremap(aac, 0); diff --git a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c index 5d19c31e3bba..93ef7c37e568 100644 --- a/drivers/scsi/aacraid/rx.c +++ b/drivers/scsi/aacraid/rx.c @@ -355,14 +355,16 @@ static int aac_rx_check_health(struct aac_dev *dev) if (likely((status & 0xFF000000L) == 0xBC000000L)) return (status >> 16) & 0xFF; - buffer = pci_alloc_consistent(dev->pdev, 512, &baddr); + buffer = dma_alloc_coherent(&dev->pdev->dev, 512, &baddr, + GFP_KERNEL); ret = -2; if (unlikely(buffer == NULL)) return ret; - post = pci_alloc_consistent(dev->pdev, - sizeof(struct POSTSTATUS), &paddr); + post = dma_alloc_coherent(&dev->pdev->dev, + sizeof(struct POSTSTATUS), &paddr, + GFP_KERNEL); if (unlikely(post == NULL)) { - pci_free_consistent(dev->pdev, 512, buffer, baddr); + dma_free_coherent(&dev->pdev->dev, 512, buffer, baddr); return ret; } memset(buffer, 0, 512); @@ -371,13 +373,13 @@ static int aac_rx_check_health(struct aac_dev *dev) rx_writel(dev, MUnit.IMRx[0], paddr); rx_sync_cmd(dev, COMMAND_POST_RESULTS, baddr, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL); - pci_free_consistent(dev->pdev, sizeof(struct POSTSTATUS), - post, paddr); + dma_free_coherent(&dev->pdev->dev, sizeof(struct POSTSTATUS), + post, paddr); if (likely((buffer[0] == '0') && ((buffer[1] == 'x') || (buffer[1] == 'X')))) { ret = (hex_to_bin(buffer[2]) << 4) + hex_to_bin(buffer[3]); } - pci_free_consistent(dev->pdev, 512, buffer, baddr); + dma_free_coherent(&dev->pdev->dev, 512, buffer, baddr); return ret; } /* -- cgit v1.2.3 From c0e3a6acdebc5b98c65a379460df1b4b2fe6c0d3 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 26 Apr 2017 15:43:59 +1000 Subject: scsi: mac_esp: fix to pass correct device identity to free_irq() free_irq() expects the same device identity that was passed to corresponding request_irq(), otherwise the IRQ is not freed. Signed-off-by: Wei Yongjun Signed-off-by: Finn Thain Signed-off-by: Martin K. Petersen --- drivers/scsi/mac_esp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c index 26c67c42985c..999699d45e14 100644 --- a/drivers/scsi/mac_esp.c +++ b/drivers/scsi/mac_esp.c @@ -587,7 +587,7 @@ fail_free_irq: esp_chips[dev->id] = NULL; if (esp_chips[!dev->id] == NULL) { spin_unlock(&esp_chips_lock); - free_irq(host->irq, esp); + free_irq(host->irq, NULL); } else spin_unlock(&esp_chips_lock); fail_free_priv: -- cgit v1.2.3 From 9385c5be5ce03d023a1cd860376aed7fd1f3a5b3 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 25 Apr 2017 18:36:19 +0100 Subject: scsi: stex: make S6flag static This module specific flag can be made static as it does not need to be in global scope. Signed-off-by: Colin Ian King Acked-by: Charles Chiou Signed-off-by: Martin K. Petersen --- drivers/scsi/stex.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c index 0751561b59da..9b20643ab49d 100644 --- a/drivers/scsi/stex.c +++ b/drivers/scsi/stex.c @@ -363,7 +363,7 @@ struct st_card_info { u16 sts_count; }; -int S6flag; +static int S6flag; static int stex_halt(struct notifier_block *nb, ulong event, void *buf); static struct notifier_block stex_notifier = { stex_halt, NULL, 0 -- cgit v1.2.3 From e7731da36f107e87b0ea137265ebcc991972e14c Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 25 Apr 2017 22:37:10 +0100 Subject: scsi: qla4xxx: fix spelling mistake: "Tempalate" -> "Template" trivial fix to spelling mistake in DEBUG2 debug message Signed-off-by: Colin Ian King Acked-by: Manish Rangankar Signed-off-by: Martin K. Petersen --- drivers/scsi/qla4xxx/ql4_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c index 4180d6d9fe78..5d6d158bbfd6 100644 --- a/drivers/scsi/qla4xxx/ql4_init.c +++ b/drivers/scsi/qla4xxx/ql4_init.c @@ -389,7 +389,7 @@ void qla4xxx_alloc_fw_dump(struct scsi_qla_host *ha) goto alloc_cleanup; DEBUG2(ql4_printk(KERN_INFO, ha, - "Minidump Tempalate Size = 0x%x KB\n", + "Minidump Template Size = 0x%x KB\n", ha->fw_dump_tmplt_size)); DEBUG2(ql4_printk(KERN_INFO, ha, "Total Minidump size = 0x%x KB\n", ha->fw_dump_size)); -- cgit v1.2.3