diff options
author | Stephen Rothwell <sfr@canb.auug.org.au> | 2017-02-06 15:49:57 +1100 |
---|---|---|
committer | Stephen Rothwell <sfr@canb.auug.org.au> | 2017-02-06 16:04:10 +1100 |
commit | 392649e7477a74d53c679c0404c4ea2e3bde3cad (patch) | |
tree | 3313ea51322a9f2a6ea8f35e805bd932087c066c /drivers | |
parent | fa03c088ca9318039d9f681308a0f0ac76f20d8e (diff) | |
parent | 66043a3bcbcea5183d6aac2eb70ab77b87a4e4ee (diff) |
Merge remote-tracking branch 'scsi/for-next'
Diffstat (limited to 'drivers')
76 files changed, 4090 insertions, 1933 deletions
diff --git a/drivers/block/cciss.h b/drivers/block/cciss.h index 7fda30e4a241..428766d1ce80 100644 --- a/drivers/block/cciss.h +++ b/drivers/block/cciss.h @@ -402,27 +402,27 @@ static bool SA5_performant_intr_pending(ctlr_info_t *h) } static struct access_method SA5_access = { - SA5_submit_command, - SA5_intr_mask, - SA5_fifo_full, - SA5_intr_pending, - SA5_completed, + .submit_command = SA5_submit_command, + .set_intr_mask = SA5_intr_mask, + .fifo_full = SA5_fifo_full, + .intr_pending = SA5_intr_pending, + .command_completed = SA5_completed, }; static struct access_method SA5B_access = { - SA5_submit_command, - SA5B_intr_mask, - SA5_fifo_full, - SA5B_intr_pending, - SA5_completed, + .submit_command = SA5_submit_command, + .set_intr_mask = SA5B_intr_mask, + .fifo_full = SA5_fifo_full, + .intr_pending = SA5B_intr_pending, + .command_completed = SA5_completed, }; static struct access_method SA5_performant_access = { - SA5_submit_command, - SA5_performant_intr_mask, - SA5_fifo_full, - SA5_performant_intr_pending, - SA5_performant_completed, + .submit_command = SA5_submit_command, + .set_intr_mask = SA5_performant_intr_mask, + .fifo_full = SA5_fifo_full, + .intr_pending = SA5_performant_intr_pending, + .command_completed = SA5_performant_completed, }; struct board_type { diff --git a/drivers/message/fusion/mptlan.h b/drivers/message/fusion/mptlan.h index 8946e19dbfc8..8a24494f8c4d 100644 --- a/drivers/message/fusion/mptlan.h +++ b/drivers/message/fusion/mptlan.h @@ -65,7 +65,6 @@ #include <linux/init.h> #include <linux/kernel.h> #include <linux/slab.h> -#include <linux/miscdevice.h> #include <linux/spinlock.h> #include <linux/workqueue.h> #include <linux/delay.h> diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c index 4f5ca794bb71..acc33440bca0 100644 --- a/drivers/scsi/NCR5380.c +++ b/drivers/scsi/NCR5380.c @@ -96,17 +96,6 @@ * of chips. To use it, you write an architecture specific functions * and macros and include this file in your driver. * - * These macros control options : - * AUTOSENSE - if defined, REQUEST SENSE will be performed automatically - * for commands that return with a CHECK CONDITION status. - * - * DIFFERENTIAL - if defined, NCR53c81 chips will use external differential - * transceivers. - * - * PSEUDO_DMA - if defined, PSEUDO DMA is used during the data transfer phases. - * - * REAL_DMA - if defined, REAL DMA is used during the data transfer phases. - * * These macros MUST be defined : * * NCR5380_read(register) - read from the specified register @@ -347,7 +336,7 @@ static void NCR5380_print_phase(struct Scsi_Host *instance) #endif /** - * NCR58380_info - report driver and host information + * NCR5380_info - report driver and host information * @instance: relevant scsi host instance * * For use as the host template info() handler. @@ -360,33 +349,6 @@ static const char *NCR5380_info(struct Scsi_Host *instance) return hostdata->info; } -static void prepare_info(struct Scsi_Host *instance) -{ - struct NCR5380_hostdata *hostdata = shost_priv(instance); - - snprintf(hostdata->info, sizeof(hostdata->info), - "%s, irq %d, " - "io_port 0x%lx, base 0x%lx, " - "can_queue %d, cmd_per_lun %d, " - "sg_tablesize %d, this_id %d, " - "flags { %s%s%s}, " - "options { %s} ", - instance->hostt->name, instance->irq, - hostdata->io_port, hostdata->base, - instance->can_queue, instance->cmd_per_lun, - instance->sg_tablesize, instance->this_id, - hostdata->flags & FLAG_DMA_FIXUP ? "DMA_FIXUP " : "", - hostdata->flags & FLAG_NO_PSEUDO_DMA ? "NO_PSEUDO_DMA " : "", - hostdata->flags & FLAG_TOSHIBA_DELAY ? "TOSHIBA_DELAY " : "", -#ifdef DIFFERENTIAL - "DIFFERENTIAL " -#endif -#ifdef PARITY - "PARITY " -#endif - ""); -} - /** * NCR5380_init - initialise an NCR5380 * @instance: adapter to configure @@ -436,7 +398,14 @@ static int NCR5380_init(struct Scsi_Host *instance, int flags) if (!hostdata->work_q) return -ENOMEM; - prepare_info(instance); + snprintf(hostdata->info, sizeof(hostdata->info), + "%s, irq %d, io_port 0x%lx, base 0x%lx, can_queue %d, cmd_per_lun %d, sg_tablesize %d, this_id %d, flags { %s%s%s}", + instance->hostt->name, instance->irq, hostdata->io_port, + hostdata->base, instance->can_queue, instance->cmd_per_lun, + instance->sg_tablesize, instance->this_id, + hostdata->flags & FLAG_DMA_FIXUP ? "DMA_FIXUP " : "", + hostdata->flags & FLAG_NO_PSEUDO_DMA ? "NO_PSEUDO_DMA " : "", + hostdata->flags & FLAG_TOSHIBA_DELAY ? "TOSHIBA_DELAY " : ""); NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); NCR5380_write(MODE_REG, MR_BASE); @@ -622,8 +591,9 @@ static inline void maybe_release_dma_irq(struct Scsi_Host *instance) list_empty(&hostdata->unissued) && list_empty(&hostdata->autosense) && !hostdata->connected && - !hostdata->selecting) + !hostdata->selecting) { NCR5380_release_dma_irq(instance); + } } /** @@ -962,6 +932,7 @@ static irqreturn_t __maybe_unused NCR5380_intr(int irq, void *dev_id) static struct scsi_cmnd *NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd) + __releases(&hostdata->lock) __acquires(&hostdata->lock) { struct NCR5380_hostdata *hostdata = shost_priv(instance); unsigned char tmp[3], phase; @@ -1194,8 +1165,16 @@ static struct scsi_cmnd *NCR5380_select(struct Scsi_Host *instance, data = tmp; phase = PHASE_MSGOUT; NCR5380_transfer_pio(instance, &phase, &len, &data); + if (len) { + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + cmd->result = DID_ERROR << 16; + complete_cmd(instance, cmd); + dsprintk(NDEBUG_SELECTION, instance, "IDENTIFY message transfer failed\n"); + cmd = NULL; + goto out; + } + dsprintk(NDEBUG_SELECTION, instance, "nexus established.\n"); - /* XXX need to handle errors here */ hostdata->connected = cmd; hostdata->busy[cmd->device->id] |= 1 << cmd->device->lun; @@ -1654,6 +1633,7 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance, */ static void NCR5380_information_transfer(struct Scsi_Host *instance) + __releases(&hostdata->lock) __acquires(&hostdata->lock) { struct NCR5380_hostdata *hostdata = shost_priv(instance); unsigned char msgout = NOP; diff --git a/drivers/scsi/NCR5380.h b/drivers/scsi/NCR5380.h index 51a3567a6fb2..d78f0957d865 100644 --- a/drivers/scsi/NCR5380.h +++ b/drivers/scsi/NCR5380.h @@ -81,11 +81,7 @@ #define ICR_ASSERT_ATN 0x02 /* rw Set to assert ATN */ #define ICR_ASSERT_DATA 0x01 /* rw SCSI_DATA_REG is asserted */ -#ifdef DIFFERENTIAL -#define ICR_BASE ICR_DIFF_ENABLE -#else #define ICR_BASE 0 -#endif #define MODE_REG 2 /* @@ -102,11 +98,7 @@ #define MR_DMA_MODE 0x02 /* rw DMA / pseudo DMA mode */ #define MR_ARBITRATE 0x01 /* rw start arbitration */ -#ifdef PARITY -#define MR_BASE MR_ENABLE_PAR_CHECK -#else #define MR_BASE 0 -#endif #define TARGET_COMMAND_REG 3 #define TCR_LAST_BYTE_SENT 0x80 /* ro DMA done */ @@ -174,11 +166,7 @@ #define CSR_SCSI_BUF_RDY 0x02 /* ro SCSI buffer read */ #define CSR_GATED_53C80_IRQ 0x01 /* ro Last block xferred */ -#if 0 -#define CSR_BASE CSR_SCSI_BUFF_INTR | CSR_53C80_INTR -#else #define CSR_BASE CSR_53C80_INTR -#endif /* Note : PHASE_* macros are based on the values of the STATUS register */ #define PHASE_MASK (SR_MSG | SR_CD | SR_IO) @@ -234,11 +222,9 @@ struct NCR5380_hostdata { unsigned char id_higher_mask; /* All bits above id_mask */ unsigned char last_message; /* Last Message Out */ unsigned long region_size; /* Size of address/port range */ - char info[256]; + char info[168]; /* Host banner message */ }; -#ifdef __KERNEL__ - struct NCR5380_cmd { struct list_head list; }; @@ -331,5 +317,4 @@ static inline int NCR5380_dma_residual_none(struct NCR5380_hostdata *hostdata) return 0; } -#endif /* __KERNEL__ */ #endif /* NCR5380_H */ diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c index 105b35393ce9..f792420c533e 100644 --- a/drivers/scsi/atari_scsi.c +++ b/drivers/scsi/atari_scsi.c @@ -178,37 +178,6 @@ static int scsi_dma_is_ignored_buserr(unsigned char dma_stat) } -#if 0 -/* Dead code... wasn't called anyway :-) and causes some trouble, because at - * end-of-DMA, both SCSI ints are triggered simultaneously, so the NCR int has - * to clear the DMA int pending bit before it allows other level 6 interrupts. - */ -static void scsi_dma_buserr(int irq, void *dummy) -{ - unsigned char dma_stat = tt_scsi_dma.dma_ctrl; - - /* Don't do anything if a NCR interrupt is pending. Probably it's just - * masked... */ - if (atari_irq_pending(IRQ_TT_MFP_SCSI)) - return; - - printk("Bad SCSI DMA interrupt! dma_addr=0x%08lx dma_stat=%02x dma_cnt=%08lx\n", - SCSI_DMA_READ_P(dma_addr), dma_stat, SCSI_DMA_READ_P(dma_cnt)); - if (dma_stat & 0x80) { - if (!scsi_dma_is_ignored_buserr(dma_stat)) - printk("SCSI DMA bus error -- bad DMA programming!\n"); - } else { - /* Under normal circumstances we never should get to this point, - * since both interrupts are triggered simultaneously and the 5380 - * int has higher priority. When this irq is handled, that DMA - * interrupt is cleared. So a warning message is printed here. - */ - printk("SCSI DMA intr ?? -- this shouldn't happen!\n"); - } -} -#endif - - static irqreturn_t scsi_tt_intr(int irq, void *dev) { struct Scsi_Host *instance = dev; @@ -713,7 +682,8 @@ static int atari_scsi_bus_reset(struct scsi_cmnd *cmd) if (IS_A_TT()) { tt_scsi_dma.dma_ctrl = 0; } else { - st_dma.dma_mode_status = 0x90; + if (stdma_is_locked_by(scsi_falcon_intr)) + st_dma.dma_mode_status = 0x90; atari_dma_active = 0; atari_dma_orig_addr = NULL; } @@ -813,7 +783,7 @@ static int __init atari_scsi_probe(struct platform_device *pdev) return -ENOMEM; } atari_dma_phys_buffer = atari_stram_to_phys(atari_dma_buffer); - atari_dma_orig_addr = 0; + atari_dma_orig_addr = NULL; } instance = scsi_host_alloc(&atari_scsi_template, diff --git a/drivers/scsi/be2iscsi/be.h b/drivers/scsi/be2iscsi/be.h index b1d0fdc5d5e1..ca9440fb2325 100644 --- a/drivers/scsi/be2iscsi/be.h +++ b/drivers/scsi/be2iscsi/be.h @@ -84,7 +84,6 @@ static inline void queue_tail_inc(struct be_queue_info *q) /*ISCSI */ struct be_aic_obj { /* Adaptive interrupt coalescing (AIC) info */ - bool enable; u32 min_eqd; /* in usecs */ u32 max_eqd; /* in usecs */ u32 prev_eqd; /* in usecs */ @@ -94,8 +93,6 @@ struct be_aic_obj { /* Adaptive interrupt coalescing (AIC) info */ }; struct be_eq_obj { - bool todo_mcc_cq; - bool todo_cq; u32 cq_count; struct be_queue_info q; struct beiscsi_hba *phba; diff --git a/drivers/scsi/be2iscsi/be_cmds.c b/drivers/scsi/be2iscsi/be_cmds.c index be65da2988fb..5d59e2630ce6 100644 --- a/drivers/scsi/be2iscsi/be_cmds.c +++ b/drivers/scsi/be2iscsi/be_cmds.c @@ -676,10 +676,10 @@ void be_wrb_hdr_prepare(struct be_mcc_wrb *wrb, int payload_len, bool embedded, u8 sge_cnt) { if (embedded) - wrb->embedded |= MCC_WRB_EMBEDDED_MASK; + wrb->emb_sgecnt_special |= MCC_WRB_EMBEDDED_MASK; else - wrb->embedded |= (sge_cnt & MCC_WRB_SGE_CNT_MASK) << - MCC_WRB_SGE_CNT_SHIFT; + wrb->emb_sgecnt_special |= (sge_cnt & MCC_WRB_SGE_CNT_MASK) << + MCC_WRB_SGE_CNT_SHIFT; wrb->payload_length = payload_len; be_dws_cpu_to_le(wrb, 8); } @@ -1599,7 +1599,7 @@ int beiscsi_cmd_function_reset(struct beiscsi_hba *phba) { struct be_ctrl_info *ctrl = &phba->ctrl; struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); - struct be_post_sgl_pages_req *req = embedded_payload(wrb); + struct be_post_sgl_pages_req *req; int status; mutex_lock(&ctrl->mbox_lock); @@ -1700,31 +1700,34 @@ int beiscsi_cmd_iscsi_cleanup(struct beiscsi_hba *phba, unsigned short ulp) struct be_ctrl_info *ctrl = &phba->ctrl; struct iscsi_cleanup_req_v1 *req_v1; struct iscsi_cleanup_req *req; + u16 hdr_ring_id, data_ring_id; struct be_mcc_wrb *wrb; int status; mutex_lock(&ctrl->mbox_lock); wrb = wrb_from_mbox(&ctrl->mbox_mem); - req = embedded_payload(wrb); - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); - be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI, - OPCODE_COMMON_ISCSI_CLEANUP, sizeof(*req)); - /** - * TODO: Check with FW folks the chute value to be set. - * For now, use the ULP_MASK as the chute value. - */ + hdr_ring_id = HWI_GET_DEF_HDRQ_ID(phba, ulp); + data_ring_id = HWI_GET_DEF_BUFQ_ID(phba, ulp); if (is_chip_be2_be3r(phba)) { + req = embedded_payload(wrb); + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI, + OPCODE_COMMON_ISCSI_CLEANUP, sizeof(*req)); req->chute = (1 << ulp); - req->hdr_ring_id = HWI_GET_DEF_HDRQ_ID(phba, ulp); - req->data_ring_id = HWI_GET_DEF_BUFQ_ID(phba, ulp); + /* BE2/BE3 FW creates 8-bit ring id */ + req->hdr_ring_id = hdr_ring_id; + req->data_ring_id = data_ring_id; } else { - req_v1 = (struct iscsi_cleanup_req_v1 *)req; + req_v1 = embedded_payload(wrb); + be_wrb_hdr_prepare(wrb, sizeof(*req_v1), true, 0); + be_cmd_hdr_prepare(&req_v1->hdr, CMD_SUBSYSTEM_ISCSI, + OPCODE_COMMON_ISCSI_CLEANUP, + sizeof(*req_v1)); req_v1->hdr.version = 1; - req_v1->hdr_ring_id = cpu_to_le16(HWI_GET_DEF_HDRQ_ID(phba, - ulp)); - req_v1->data_ring_id = cpu_to_le16(HWI_GET_DEF_BUFQ_ID(phba, - ulp)); + req_v1->chute = (1 << ulp); + req_v1->hdr_ring_id = cpu_to_le16(hdr_ring_id); + req_v1->data_ring_id = cpu_to_le16(data_ring_id); } status = be_mbox_notify(ctrl); diff --git a/drivers/scsi/be2iscsi/be_cmds.h b/drivers/scsi/be2iscsi/be_cmds.h index 328fb5b973cd..1d40e83b0790 100644 --- a/drivers/scsi/be2iscsi/be_cmds.h +++ b/drivers/scsi/be2iscsi/be_cmds.h @@ -31,10 +31,16 @@ struct be_sge { __le32 len; }; -#define MCC_WRB_SGE_CNT_SHIFT 3 /* bits 3 - 7 of dword 0 */ -#define MCC_WRB_SGE_CNT_MASK 0x1F /* bits 3 - 7 of dword 0 */ struct be_mcc_wrb { - u32 embedded; /* dword 0 */ + u32 emb_sgecnt_special; /* dword 0 */ + /* bits 0 - embedded */ + /* bits 1 - 2 reserved */ + /* bits 3 - 7 sge count */ + /* bits 8 - 23 reserved */ + /* bits 24 - 31 special */ +#define MCC_WRB_EMBEDDED_MASK 1 +#define MCC_WRB_SGE_CNT_SHIFT 3 +#define MCC_WRB_SGE_CNT_MASK 0x1F u32 payload_length; /* dword 1 */ u32 tag0; /* dword 2 */ u32 tag1; /* dword 3 */ @@ -1133,11 +1139,6 @@ struct tcp_connect_and_offload_out { } __packed; -struct be_mcc_wrb_context { - struct MCC_WRB *wrb; - int *users_final_status; -} __packed; - #define DB_DEF_PDU_RING_ID_MASK 0x3FFF /* bits 0 - 13 */ #define DB_DEF_PDU_CQPROC_MASK 0x3FFF /* bits 16 - 29 */ #define DB_DEF_PDU_REARM_SHIFT 14 diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c index ba258217614e..a4844578e357 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.c +++ b/drivers/scsi/be2iscsi/be_iscsi.c @@ -166,33 +166,6 @@ beiscsi_conn_create(struct iscsi_cls_session *cls_session, u32 cid) } /** - * beiscsi_bindconn_cid - Bind the beiscsi_conn with phba connection table - * @beiscsi_conn: The pointer to beiscsi_conn structure - * @phba: The phba instance - * @cid: The cid to free - */ -static int beiscsi_bindconn_cid(struct beiscsi_hba *phba, - struct beiscsi_conn *beiscsi_conn, - unsigned int cid) -{ - uint16_t cri_index = BE_GET_CRI_FROM_CID(cid); - - if (phba->conn_table[cri_index]) { - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, - "BS_%d : Connection table already occupied. Detected clash\n"); - - return -EINVAL; - } else { - beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG, - "BS_%d : phba->conn_table[%d]=%p(beiscsi_conn)\n", - cri_index, beiscsi_conn); - - phba->conn_table[cri_index] = beiscsi_conn; - } - return 0; -} - -/** * beiscsi_conn_bind - Binds iscsi session/connection with TCP connection * @cls_session: pointer to iscsi cls session * @cls_conn: pointer to iscsi cls conn @@ -212,6 +185,7 @@ int beiscsi_conn_bind(struct iscsi_cls_session *cls_session, struct hwi_wrb_context *pwrb_context; struct beiscsi_endpoint *beiscsi_ep; struct iscsi_endpoint *ep; + uint16_t cri_index; ep = iscsi_lookup_endpoint(transport_fd); if (!ep) @@ -229,20 +203,34 @@ int beiscsi_conn_bind(struct iscsi_cls_session *cls_session, return -EEXIST; } - - pwrb_context = &phwi_ctrlr->wrb_context[BE_GET_CRI_FROM_CID( - beiscsi_ep->ep_cid)]; + cri_index = BE_GET_CRI_FROM_CID(beiscsi_ep->ep_cid); + if (phba->conn_table[cri_index]) { + if (beiscsi_conn != phba->conn_table[cri_index] || + beiscsi_ep != phba->conn_table[cri_index]->ep) { + __beiscsi_log(phba, KERN_ERR, + "BS_%d : conn_table not empty at %u: cid %u conn %p:%p\n", + cri_index, + beiscsi_ep->ep_cid, + beiscsi_conn, + phba->conn_table[cri_index]); + return -EINVAL; + } + } beiscsi_conn->beiscsi_conn_cid = beiscsi_ep->ep_cid; beiscsi_conn->ep = beiscsi_ep; beiscsi_ep->conn = beiscsi_conn; + /** + * Each connection is associated with a WRBQ kept in wrb_context. + * Store doorbell offset for transmit path. + */ + pwrb_context = &phwi_ctrlr->wrb_context[cri_index]; beiscsi_conn->doorbell_offset = pwrb_context->doorbell_offset; - beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG, - "BS_%d : beiscsi_conn=%p conn=%p ep_cid=%d\n", - beiscsi_conn, conn, beiscsi_ep->ep_cid); - - return beiscsi_bindconn_cid(phba, beiscsi_conn, beiscsi_ep->ep_cid); + "BS_%d : cid %d phba->conn_table[%u]=%p\n", + beiscsi_ep->ep_cid, cri_index, beiscsi_conn); + phba->conn_table[cri_index] = beiscsi_conn; + return 0; } static int beiscsi_iface_create_ipv4(struct beiscsi_hba *phba) @@ -973,9 +961,9 @@ int beiscsi_conn_start(struct iscsi_cls_conn *cls_conn) */ static int beiscsi_get_cid(struct beiscsi_hba *phba) { - unsigned short cid = 0xFFFF, cid_from_ulp; - struct ulp_cid_info *cid_info = NULL; uint16_t cid_avlbl_ulp0, cid_avlbl_ulp1; + unsigned short cid, cid_from_ulp; + struct ulp_cid_info *cid_info; /* Find the ULP which has more CID available */ cid_avlbl_ulp0 = (phba->cid_array_info[BEISCSI_ULP0]) ? @@ -984,20 +972,27 @@ static int beiscsi_get_cid(struct beiscsi_hba *phba) BEISCSI_ULP1_AVLBL_CID(phba) : 0; cid_from_ulp = (cid_avlbl_ulp0 > cid_avlbl_ulp1) ? BEISCSI_ULP0 : BEISCSI_ULP1; - - if (test_bit(cid_from_ulp, (void *)&phba->fw_config.ulp_supported)) { - cid_info = phba->cid_array_info[cid_from_ulp]; - if (!cid_info->avlbl_cids) - return cid; - - cid = cid_info->cid_array[cid_info->cid_alloc++]; - - if (cid_info->cid_alloc == BEISCSI_GET_CID_COUNT( - phba, cid_from_ulp)) - cid_info->cid_alloc = 0; - - cid_info->avlbl_cids--; + /** + * If iSCSI protocol is loaded only on ULP 0, and when cid_avlbl_ulp + * is ZERO for both, ULP 1 is returned. + * Check if ULP is loaded before getting new CID. + */ + if (!test_bit(cid_from_ulp, (void *)&phba->fw_config.ulp_supported)) + return BE_INVALID_CID; + + cid_info = phba->cid_array_info[cid_from_ulp]; + cid = cid_info->cid_array[cid_info->cid_alloc]; + if (!cid_info->avlbl_cids || cid == BE_INVALID_CID) { + __beiscsi_log(phba, KERN_ERR, + "BS_%d : failed to get cid: available %u:%u\n", + cid_info->avlbl_cids, cid_info->cid_free); + return BE_INVALID_CID; } + /* empty the slot */ + cid_info->cid_array[cid_info->cid_alloc++] = BE_INVALID_CID; + if (cid_info->cid_alloc == BEISCSI_GET_CID_COUNT(phba, cid_from_ulp)) + cid_info->cid_alloc = 0; + cid_info->avlbl_cids--; return cid; } @@ -1008,22 +1003,28 @@ static int beiscsi_get_cid(struct beiscsi_hba *phba) */ static void beiscsi_put_cid(struct beiscsi_hba *phba, unsigned short cid) { - uint16_t cid_post_ulp; - struct hwi_controller *phwi_ctrlr; - struct hwi_wrb_context *pwrb_context; - struct ulp_cid_info *cid_info = NULL; uint16_t cri_index = BE_GET_CRI_FROM_CID(cid); + struct hwi_wrb_context *pwrb_context; + struct hwi_controller *phwi_ctrlr; + struct ulp_cid_info *cid_info; + uint16_t cid_post_ulp; phwi_ctrlr = phba->phwi_ctrlr; pwrb_context = &phwi_ctrlr->wrb_context[cri_index]; cid_post_ulp = pwrb_context->ulp_num; cid_info = phba->cid_array_info[cid_post_ulp]; - cid_info->avlbl_cids++; - + /* fill only in empty slot */ + if (cid_info->cid_array[cid_info->cid_free] != BE_INVALID_CID) { + __beiscsi_log(phba, KERN_ERR, + "BS_%d : failed to put cid %u: available %u:%u\n", + cid, cid_info->avlbl_cids, cid_info->cid_free); + return; + } cid_info->cid_array[cid_info->cid_free++] = cid; if (cid_info->cid_free == BEISCSI_GET_CID_COUNT(phba, cid_post_ulp)) cid_info->cid_free = 0; + cid_info->avlbl_cids++; } /** @@ -1037,8 +1038,8 @@ static void beiscsi_free_ep(struct beiscsi_endpoint *beiscsi_ep) beiscsi_put_cid(phba, beiscsi_ep->ep_cid); beiscsi_ep->phba = NULL; - phba->ep_array[BE_GET_CRI_FROM_CID - (beiscsi_ep->ep_cid)] = NULL; + /* clear this to track freeing in beiscsi_ep_disconnect */ + phba->ep_array[BE_GET_CRI_FROM_CID(beiscsi_ep->ep_cid)] = NULL; /** * Check if any connection resource allocated by driver @@ -1049,6 +1050,11 @@ static void beiscsi_free_ep(struct beiscsi_endpoint *beiscsi_ep) return; beiscsi_conn = beiscsi_ep->conn; + /** + * Break ep->conn link here so that completions after + * this are ignored. + */ + beiscsi_ep->conn = NULL; if (beiscsi_conn->login_in_progress) { beiscsi_free_mgmt_task_handles(beiscsi_conn, beiscsi_conn->task); @@ -1079,7 +1085,7 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep, "BS_%d : In beiscsi_open_conn\n"); beiscsi_ep->ep_cid = beiscsi_get_cid(phba); - if (beiscsi_ep->ep_cid == 0xFFFF) { + if (beiscsi_ep->ep_cid == BE_INVALID_CID) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, "BS_%d : No free cid available\n"); return ret; @@ -1114,7 +1120,7 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep, nonemb_cmd.size = req_memsize; memset(nonemb_cmd.va, 0, nonemb_cmd.size); tag = mgmt_open_connection(phba, dst_addr, beiscsi_ep, &nonemb_cmd); - if (tag <= 0) { + if (!tag) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, "BS_%d : mgmt_open_connection Failed for cid=%d\n", beiscsi_ep->ep_cid); @@ -1285,26 +1291,6 @@ static int beiscsi_close_conn(struct beiscsi_endpoint *beiscsi_ep, int flag) } /** - * beiscsi_unbind_conn_to_cid - Unbind the beiscsi_conn from phba conn table - * @phba: The phba instance - * @cid: The cid to free - */ -static int beiscsi_unbind_conn_to_cid(struct beiscsi_hba *phba, - unsigned int cid) -{ - uint16_t cri_index = BE_GET_CRI_FROM_CID(cid); - - if (phba->conn_table[cri_index]) - phba->conn_table[cri_index] = NULL; - else { - beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG, - "BS_%d : Connection table Not occupied.\n"); - return -EINVAL; - } - return 0; -} - -/** * beiscsi_ep_disconnect - Tears down the TCP connection * @ep: endpoint to be used * @@ -1318,13 +1304,23 @@ void beiscsi_ep_disconnect(struct iscsi_endpoint *ep) 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; phba = beiscsi_ep->phba; beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG, - "BS_%d : In beiscsi_ep_disconnect for ep_cid = %d\n", + "BS_%d : In beiscsi_ep_disconnect for ep_cid = %u\n", beiscsi_ep->ep_cid); + cri_index = BE_GET_CRI_FROM_CID(beiscsi_ep->ep_cid); + if (!phba->ep_array[cri_index]) { + __beiscsi_log(phba, KERN_ERR, + "BS_%d : ep_array at %u cid %u empty\n", + cri_index, + beiscsi_ep->ep_cid); + return; + } + if (beiscsi_ep->conn) { beiscsi_conn = beiscsi_ep->conn; iscsi_suspend_queue(beiscsi_conn->conn); @@ -1356,7 +1352,12 @@ void beiscsi_ep_disconnect(struct iscsi_endpoint *ep) free_ep: msleep(BEISCSI_LOGOUT_SYNC_DELAY); beiscsi_free_ep(beiscsi_ep); - beiscsi_unbind_conn_to_cid(phba, beiscsi_ep->ep_cid); + 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); + phba->conn_table[cri_index] = NULL; iscsi_destroy_endpoint(beiscsi_ep->openiscsi_ep); } diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index b5112d6d7e73..c9b9daa91091 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -67,8 +67,6 @@ beiscsi_##_name##_disp(struct device *dev,\ { \ struct Scsi_Host *shost = class_to_shost(dev);\ struct beiscsi_hba *phba = iscsi_host_priv(shost); \ - uint32_t param_val = 0; \ - param_val = phba->attr_##_name;\ return snprintf(buf, PAGE_SIZE, "%d\n",\ phba->attr_##_name);\ } @@ -218,160 +216,156 @@ static int beiscsi_slave_configure(struct scsi_device *sdev) static int beiscsi_eh_abort(struct scsi_cmnd *sc) { + struct iscsi_task *abrt_task = (struct iscsi_task *)sc->SCp.ptr; struct iscsi_cls_session *cls_session; - struct iscsi_task *aborted_task = (struct iscsi_task *)sc->SCp.ptr; - struct beiscsi_io_task *aborted_io_task; - struct iscsi_conn *conn; + struct beiscsi_io_task *abrt_io_task; struct beiscsi_conn *beiscsi_conn; - struct beiscsi_hba *phba; struct iscsi_session *session; - struct invalidate_command_table *inv_tbl; - struct be_dma_mem nonemb_cmd; - unsigned int cid, tag, num_invalidate; + struct invldt_cmd_tbl inv_tbl; + struct beiscsi_hba *phba; + struct iscsi_conn *conn; int rc; cls_session = starget_to_session(scsi_target(sc->device)); session = cls_session->dd_data; - spin_lock_bh(&session->frwd_lock); - if (!aborted_task || !aborted_task->sc) { - /* we raced */ - spin_unlock_bh(&session->frwd_lock); - return SUCCESS; - } - - aborted_io_task = aborted_task->dd_data; - if (!aborted_io_task->scsi_cmnd) { - /* raced or invalid command */ - spin_unlock_bh(&session->frwd_lock); + /* check if we raced, task just got cleaned up under us */ + spin_lock_bh(&session->back_lock); + if (!abrt_task || !abrt_task->sc) { + spin_unlock_bh(&session->back_lock); return SUCCESS; } - spin_unlock_bh(&session->frwd_lock); - /* Invalidate WRB Posted for this Task */ - AMAP_SET_BITS(struct amap_iscsi_wrb, invld, - aborted_io_task->pwrb_handle->pwrb, - 1); - - conn = aborted_task->conn; + /* get a task ref till FW processes the req for the ICD used */ + __iscsi_get_task(abrt_task); + abrt_io_task = abrt_task->dd_data; + conn = abrt_task->conn; beiscsi_conn = conn->dd_data; phba = beiscsi_conn->phba; - - /* invalidate iocb */ - cid = beiscsi_conn->beiscsi_conn_cid; - inv_tbl = phba->inv_tbl; - memset(inv_tbl, 0x0, sizeof(*inv_tbl)); - inv_tbl->cid = cid; - inv_tbl->icd = aborted_io_task->psgl_handle->sgl_index; - num_invalidate = 1; - nonemb_cmd.va = pci_alloc_consistent(phba->ctrl.pdev, - sizeof(struct invalidate_commands_params_in), - &nonemb_cmd.dma); - if (nonemb_cmd.va == NULL) { - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_EH, - "BM_%d : Failed to allocate memory for" - "mgmt_invalidate_icds\n"); - return FAILED; + /* mark WRB invalid which have been not processed by FW yet */ + if (is_chip_be2_be3r(phba)) { + AMAP_SET_BITS(struct amap_iscsi_wrb, invld, + abrt_io_task->pwrb_handle->pwrb, 1); + } else { + AMAP_SET_BITS(struct amap_iscsi_wrb_v2, invld, + abrt_io_task->pwrb_handle->pwrb, 1); } - nonemb_cmd.size = sizeof(struct invalidate_commands_params_in); + inv_tbl.cid = beiscsi_conn->beiscsi_conn_cid; + inv_tbl.icd = abrt_io_task->psgl_handle->sgl_index; + spin_unlock_bh(&session->back_lock); - tag = mgmt_invalidate_icds(phba, inv_tbl, num_invalidate, - cid, &nonemb_cmd); - if (!tag) { + rc = beiscsi_mgmt_invalidate_icds(phba, &inv_tbl, 1); + iscsi_put_task(abrt_task); + if (rc) { beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_EH, - "BM_%d : mgmt_invalidate_icds could not be" - "submitted\n"); - pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size, - nonemb_cmd.va, nonemb_cmd.dma); - + "BM_%d : sc %p invalidation failed %d\n", + sc, rc); return FAILED; } - rc = beiscsi_mccq_compl_wait(phba, tag, NULL, &nonemb_cmd); - if (rc != -EBUSY) - pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size, - nonemb_cmd.va, nonemb_cmd.dma); - return iscsi_eh_abort(sc); } static int beiscsi_eh_device_reset(struct scsi_cmnd *sc) { - struct iscsi_task *abrt_task; - struct beiscsi_io_task *abrt_io_task; - struct iscsi_conn *conn; + struct beiscsi_invldt_cmd_tbl { + struct invldt_cmd_tbl tbl[BE_INVLDT_CMD_TBL_SZ]; + struct iscsi_task *task[BE_INVLDT_CMD_TBL_SZ]; + } *inv_tbl; + struct iscsi_cls_session *cls_session; struct beiscsi_conn *beiscsi_conn; - struct beiscsi_hba *phba; + struct beiscsi_io_task *io_task; struct iscsi_session *session; - struct iscsi_cls_session *cls_session; - struct invalidate_command_table *inv_tbl; - struct be_dma_mem nonemb_cmd; - unsigned int cid, tag, i, num_invalidate; - int rc; + struct beiscsi_hba *phba; + struct iscsi_conn *conn; + struct iscsi_task *task; + unsigned int i, nents; + int rc, more = 0; - /* invalidate iocbs */ cls_session = starget_to_session(scsi_target(sc->device)); session = cls_session->dd_data; + spin_lock_bh(&session->frwd_lock); if (!session->leadconn || session->state != ISCSI_STATE_LOGGED_IN) { spin_unlock_bh(&session->frwd_lock); return FAILED; } + conn = session->leadconn; beiscsi_conn = conn->dd_data; phba = beiscsi_conn->phba; - cid = beiscsi_conn->beiscsi_conn_cid; - inv_tbl = phba->inv_tbl; - memset(inv_tbl, 0x0, sizeof(*inv_tbl) * BE2_CMDS_PER_CXN); - num_invalidate = 0; + + inv_tbl = kzalloc(sizeof(*inv_tbl), GFP_ATOMIC); + if (!inv_tbl) { + spin_unlock_bh(&session->frwd_lock); + beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_EH, + "BM_%d : invldt_cmd_tbl alloc failed\n"); + return FAILED; + } + nents = 0; + /* take back_lock to prevent task from getting cleaned up under us */ + spin_lock(&session->back_lock); for (i = 0; i < conn->session->cmds_max; i++) { - abrt_task = conn->session->cmds[i]; - abrt_io_task = abrt_task->dd_data; - if (!abrt_task->sc || abrt_task->state == ISCSI_TASK_FREE) + task = conn->session->cmds[i]; + if (!task->sc) continue; - if (sc->device->lun != abrt_task->sc->device->lun) + if (sc->device->lun != task->sc->device->lun) continue; + /** + * Can't fit in more cmds? Normally this won't happen b'coz + * BEISCSI_CMD_PER_LUN is same as BE_INVLDT_CMD_TBL_SZ. + */ + if (nents == BE_INVLDT_CMD_TBL_SZ) { + more = 1; + break; + } - /* Invalidate WRB Posted for this Task */ - AMAP_SET_BITS(struct amap_iscsi_wrb, invld, - abrt_io_task->pwrb_handle->pwrb, - 1); + /* get a task ref till FW processes the req for the ICD used */ + __iscsi_get_task(task); + io_task = task->dd_data; + /* mark WRB invalid which have been not processed by FW yet */ + if (is_chip_be2_be3r(phba)) { + AMAP_SET_BITS(struct amap_iscsi_wrb, invld, + io_task->pwrb_handle->pwrb, 1); + } else { + AMAP_SET_BITS(struct amap_iscsi_wrb_v2, invld, + io_task->pwrb_handle->pwrb, 1); + } - inv_tbl->cid = cid; - inv_tbl->icd = abrt_io_task->psgl_handle->sgl_index; - num_invalidate++; - inv_tbl++; + inv_tbl->tbl[nents].cid = beiscsi_conn->beiscsi_conn_cid; + inv_tbl->tbl[nents].icd = io_task->psgl_handle->sgl_index; + inv_tbl->task[nents] = task; + nents++; } + spin_unlock_bh(&session->back_lock); spin_unlock_bh(&session->frwd_lock); - inv_tbl = phba->inv_tbl; - nonemb_cmd.va = pci_alloc_consistent(phba->ctrl.pdev, - sizeof(struct invalidate_commands_params_in), - &nonemb_cmd.dma); - if (nonemb_cmd.va == NULL) { + rc = SUCCESS; + if (!nents) + goto end_reset; + + if (more) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_EH, - "BM_%d : Failed to allocate memory for" - "mgmt_invalidate_icds\n"); - return FAILED; + "BM_%d : number of cmds exceeds size of invalidation table\n"); + rc = FAILED; + goto end_reset; } - nonemb_cmd.size = sizeof(struct invalidate_commands_params_in); - memset(nonemb_cmd.va, 0, nonemb_cmd.size); - tag = mgmt_invalidate_icds(phba, inv_tbl, num_invalidate, - cid, &nonemb_cmd); - if (!tag) { + + if (beiscsi_mgmt_invalidate_icds(phba, &inv_tbl->tbl[0], nents)) { beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_EH, - "BM_%d : mgmt_invalidate_icds could not be" - " submitted\n"); - pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size, - nonemb_cmd.va, nonemb_cmd.dma); - return FAILED; + "BM_%d : cid %u scmds invalidation failed\n", + beiscsi_conn->beiscsi_conn_cid); + rc = FAILED; } - rc = beiscsi_mccq_compl_wait(phba, tag, NULL, &nonemb_cmd); - if (rc != -EBUSY) - pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size, - nonemb_cmd.va, nonemb_cmd.dma); - return iscsi_eh_device_reset(sc); +end_reset: + for (i = 0; i < nents; i++) + iscsi_put_task(inv_tbl->task[i]); + kfree(inv_tbl); + + if (rc == SUCCESS) + rc = iscsi_eh_device_reset(sc); + return rc; } /*------------------- PCI Driver operations and data ----------------- */ @@ -646,7 +640,6 @@ static void beiscsi_get_params(struct beiscsi_hba *phba) phba->params.num_sge_per_io = BE2_SGE; phba->params.defpdu_hdr_sz = BE2_DEFPDU_HDR_SZ; phba->params.defpdu_data_sz = BE2_DEFPDU_DATA_SZ; - phba->params.eq_timer = 64; phba->params.num_eq_entries = 1024; phba->params.num_cq_entries = 1024; phba->params.wrbs_per_cxn = 256; @@ -964,6 +957,10 @@ beiscsi_get_wrb_handle(struct hwi_wrb_context *pwrb_context, unsigned long flags; spin_lock_irqsave(&pwrb_context->wrb_lock, flags); + if (!pwrb_context->wrb_handles_available) { + spin_unlock_irqrestore(&pwrb_context->wrb_lock, flags); + return NULL; + } pwrb_handle = pwrb_context->pwrb_handle_base[pwrb_context->alloc_index]; pwrb_context->wrb_handles_available--; if (pwrb_context->alloc_index == (wrbs_per_cxn - 1)) @@ -1014,6 +1011,7 @@ beiscsi_put_wrb_handle(struct hwi_wrb_context *pwrb_context, pwrb_context->free_index = 0; else pwrb_context->free_index++; + pwrb_handle->pio_handle = NULL; spin_unlock_irqrestore(&pwrb_context->wrb_lock, flags); } @@ -1224,6 +1222,7 @@ hwi_complete_drvr_msgs(struct beiscsi_conn *beiscsi_conn, uint16_t wrb_index, cid, cri_index; struct hwi_controller *phwi_ctrlr; struct wrb_handle *pwrb_handle; + struct iscsi_session *session; struct iscsi_task *task; phwi_ctrlr = phba->phwi_ctrlr; @@ -1242,8 +1241,12 @@ hwi_complete_drvr_msgs(struct beiscsi_conn *beiscsi_conn, cri_index = BE_GET_CRI_FROM_CID(cid); pwrb_context = &phwi_ctrlr->wrb_context[cri_index]; pwrb_handle = pwrb_context->pwrb_handle_basestd[wrb_index]; + session = beiscsi_conn->conn->session; + spin_lock_bh(&session->back_lock); task = pwrb_handle->pio_handle; - iscsi_put_task(task); + if (task) + __iscsi_put_task(task); + spin_unlock_bh(&session->back_lock); } static void @@ -1323,16 +1326,15 @@ static void adapter_get_sol_cqe(struct beiscsi_hba *phba, static void hwi_complete_cmd(struct beiscsi_conn *beiscsi_conn, struct beiscsi_hba *phba, struct sol_cqe *psol) { - struct hwi_wrb_context *pwrb_context; - struct wrb_handle *pwrb_handle; - struct iscsi_wrb *pwrb = NULL; - struct hwi_controller *phwi_ctrlr; - struct iscsi_task *task; - unsigned int type; struct iscsi_conn *conn = beiscsi_conn->conn; struct iscsi_session *session = conn->session; struct common_sol_cqe csol_cqe = {0}; + struct hwi_wrb_context *pwrb_context; + struct hwi_controller *phwi_ctrlr; + struct wrb_handle *pwrb_handle; + struct iscsi_task *task; uint16_t cri_index = 0; + uint8_t type; phwi_ctrlr = phba->phwi_ctrlr; @@ -1345,11 +1347,14 @@ static void hwi_complete_cmd(struct beiscsi_conn *beiscsi_conn, pwrb_handle = pwrb_context->pwrb_handle_basestd[ csol_cqe.wrb_index]; + spin_lock_bh(&session->back_lock); task = pwrb_handle->pio_handle; - pwrb = pwrb_handle->pwrb; + if (!task) { + spin_unlock_bh(&session->back_lock); + return; + } type = ((struct beiscsi_io_task *)task->dd_data)->wrb_type; - spin_lock_bh(&session->back_lock); switch (type) { case HWH_TYPE_IO: case HWH_TYPE_IO_RD: @@ -1711,13 +1716,12 @@ beiscsi_hdq_post_handles(struct beiscsi_hba *phba, struct list_head *hfree_list; struct phys_addr *pasync_sge; u32 ring_id, doorbell = 0; - u16 index, num_entries; u32 doorbell_offset; u16 prod = 0, cons; + u16 index; phwi_ctrlr = phba->phwi_ctrlr; pasync_ctx = HWI_GET_ASYNC_PDU_CTX(phwi_ctrlr, ulp_num); - num_entries = pasync_ctx->num_entries; if (header) { cons = pasync_ctx->async_header.free_entries; hfree_list = &pasync_ctx->async_header.free_list; @@ -2374,13 +2378,10 @@ static int hwi_write_buffer(struct iscsi_wrb *pwrb, struct iscsi_task *task) static void beiscsi_find_mem_req(struct beiscsi_hba *phba) { uint8_t mem_descr_index, ulp_num; - unsigned int num_cq_pages, num_async_pdu_buf_pages; + unsigned int num_async_pdu_buf_pages; unsigned int num_async_pdu_data_pages, wrb_sz_per_cxn; unsigned int num_async_pdu_buf_sgl_pages, num_async_pdu_data_sgl_pages; - num_cq_pages = PAGES_REQUIRED(phba->params.num_cq_entries * \ - sizeof(struct sol_cqe)); - phba->params.hwi_ws_sz = sizeof(struct hwi_controller); phba->mem_req[ISCSI_MEM_GLOBAL_HEADER] = 2 * @@ -2737,7 +2738,7 @@ static int hwi_init_async_pdu_ctx(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)) { - /* get async_ctx for each ULP */ + /* get async_ctx for each ULP */ mem_descr = (struct be_mem_descriptor *)phba->init_mem; mem_descr += (HWI_MEM_ASYNC_PDU_CONTEXT_ULP0 + (ulp_num * MEM_DESCR_OFFSET)); @@ -3367,7 +3368,7 @@ beiscsi_create_wrb_rings(struct beiscsi_hba *phba, struct hwi_context_memory *phwi_context, struct hwi_controller *phwi_ctrlr) { - unsigned int wrb_mem_index, offset, size, num_wrb_rings; + unsigned int num_wrb_rings; u64 pa_addr_lo; unsigned int idx, num, i, ulp_num; struct mem_array *pwrb_arr; @@ -3432,10 +3433,6 @@ beiscsi_create_wrb_rings(struct beiscsi_hba *phba, } for (i = 0; i < phba->params.cxns_per_ctrl; i++) { - wrb_mem_index = 0; - offset = 0; - size = 0; - if (ulp_count > 1) { ulp_base_num = (ulp_base_num + 1) % BEISCSI_ULP_COUNT; @@ -3663,7 +3660,6 @@ static void hwi_cleanup_port(struct beiscsi_hba *phba) struct be_ctrl_info *ctrl = &phba->ctrl; struct hwi_controller *phwi_ctrlr; struct hwi_context_memory *phwi_context; - struct hd_async_context *pasync_ctx; int i, eq_for_mcc, ulp_num; for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) @@ -3700,8 +3696,6 @@ static void hwi_cleanup_port(struct beiscsi_hba *phba) q = &phwi_context->be_def_dataq[ulp_num]; if (q->created) beiscsi_cmd_q_destroy(ctrl, q, QTYPE_DPDUQ); - - pasync_ctx = phwi_ctrlr->phwi_ctxt->pasync_ctx[ulp_num]; } } @@ -3804,7 +3798,6 @@ static int hwi_init_port(struct beiscsi_hba *phba) /** * Now that the default PDU rings have been created, * let EP know about it. - * Call beiscsi_cmd_iscsi_cleanup before posting? */ beiscsi_hdq_post_handles(phba, BEISCSI_DEFQ_HDR, ulp_num); @@ -3850,14 +3843,6 @@ static int hwi_init_port(struct beiscsi_hba *phba) phwi_ctrlr->wrb_context[cri].cid] = async_arr_idx++; } - /** - * Now that the default PDU rings have been created, - * let EP know about it. - */ - beiscsi_hdq_post_handles(phba, BEISCSI_DEFQ_HDR, - ulp_num); - beiscsi_hdq_post_handles(phba, BEISCSI_DEFQ_DATA, - ulp_num); } } @@ -3934,31 +3919,6 @@ static void beiscsi_free_mem(struct beiscsi_hba *phba) kfree(phba->phwi_ctrlr); } -static int beiscsi_init_controller(struct beiscsi_hba *phba) -{ - int ret = -ENOMEM; - - ret = beiscsi_get_memory(phba); - if (ret < 0) { - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, - "BM_%d : beiscsi_dev_probe -" - "Failed in beiscsi_alloc_memory\n"); - return ret; - } - - ret = hwi_init_controller(phba); - if (ret) - goto free_init; - beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT, - "BM_%d : Return success from beiscsi_init_controller"); - - return 0; - -free_init: - beiscsi_free_mem(phba); - return ret; -} - static int beiscsi_init_sgl_handle(struct beiscsi_hba *phba) { struct be_mem_descriptor *mem_descr_sglh, *mem_descr_sg; @@ -4089,9 +4049,10 @@ static int hba_setup_cid_tbls(struct beiscsi_hba *phba) } /* Allocate memory for CID array */ - ptr_cid_info->cid_array = kzalloc(sizeof(void *) * - BEISCSI_GET_CID_COUNT(phba, - ulp_num), GFP_KERNEL); + ptr_cid_info->cid_array = + kcalloc(BEISCSI_GET_CID_COUNT(phba, ulp_num), + sizeof(*ptr_cid_info->cid_array), + GFP_KERNEL); if (!ptr_cid_info->cid_array) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, "BM_%d : Failed to allocate memory" @@ -4231,33 +4192,30 @@ static int beiscsi_init_port(struct beiscsi_hba *phba) { int ret; - ret = beiscsi_init_controller(phba); + ret = hwi_init_controller(phba); if (ret < 0) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, - "BM_%d : beiscsi_dev_probe - Failed in" - "beiscsi_init_controller\n"); + "BM_%d : init controller failed\n"); return ret; } ret = beiscsi_init_sgl_handle(phba); if (ret < 0) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, - "BM_%d : beiscsi_dev_probe - Failed in" - "beiscsi_init_sgl_handle\n"); - goto do_cleanup_ctrlr; + "BM_%d : init sgl handles failed\n"); + goto cleanup_port; } ret = hba_setup_cid_tbls(phba); if (ret < 0) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, - "BM_%d : Failed in hba_setup_cid_tbls\n"); + "BM_%d : setup CID table failed\n"); kfree(phba->io_sgl_hndl_base); kfree(phba->eh_sgl_hndl_base); - goto do_cleanup_ctrlr; + goto cleanup_port; } - return ret; -do_cleanup_ctrlr: +cleanup_port: hwi_cleanup_port(phba); return ret; } @@ -5417,10 +5375,10 @@ static int beiscsi_enable_port(struct beiscsi_hba *phba) phba->shost->max_id = phba->params.cxns_per_ctrl; phba->shost->can_queue = phba->params.ios_per_ctrl; - ret = hwi_init_controller(phba); - if (ret) { + ret = beiscsi_init_port(phba); + if (ret < 0) { __beiscsi_log(phba, KERN_ERR, - "BM_%d : init controller failed %d\n", ret); + "BM_%d : init port failed\n"); goto disable_msix; } @@ -5526,6 +5484,7 @@ static void beiscsi_disable_port(struct beiscsi_hba *phba, int unload) cancel_work_sync(&pbe_eq->mcc_work); } hwi_cleanup_port(phba); + beiscsi_cleanup_port(phba); } static void beiscsi_sess_work(struct work_struct *work) @@ -5638,11 +5597,12 @@ static void beiscsi_eeh_resume(struct pci_dev *pdev) static int beiscsi_dev_probe(struct pci_dev *pcidev, const struct pci_device_id *id) { - struct beiscsi_hba *phba = NULL; - struct hwi_controller *phwi_ctrlr; struct hwi_context_memory *phwi_context; + struct hwi_controller *phwi_ctrlr; + struct beiscsi_hba *phba = NULL; struct be_eq_obj *pbe_eq; unsigned int s_handle; + char wq_name[20]; int ret, i; ret = beiscsi_enable_pci(pcidev); @@ -5680,6 +5640,8 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev, case OC_DEVICE_ID2: phba->generation = BE_GEN2; phba->iotask_fn = beiscsi_iotask; + dev_warn(&pcidev->dev, + "Obsolete/Unsupported BE2 Adapter Family\n"); break; case BE_DEVICE_ID2: case OC_DEVICE_ID3: @@ -5735,11 +5697,18 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev, phba->shost->max_id = phba->params.cxns_per_ctrl; phba->shost->can_queue = phba->params.ios_per_ctrl; + ret = beiscsi_get_memory(phba); + if (ret < 0) { + beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, + "BM_%d : alloc host mem failed\n"); + goto free_port; + } + ret = beiscsi_init_port(phba); if (ret < 0) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, - "BM_%d : beiscsi_dev_probe-" - "Failed in beiscsi_init_port\n"); + "BM_%d : init port failed\n"); + beiscsi_free_mem(phba); goto free_port; } @@ -5754,9 +5723,9 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev, phba->ctrl.mcc_alloc_index = phba->ctrl.mcc_free_index = 0; - snprintf(phba->wq_name, sizeof(phba->wq_name), "beiscsi_%02x_wq", + snprintf(wq_name, sizeof(wq_name), "beiscsi_%02x_wq", phba->shost->host_no); - phba->wq = alloc_workqueue("%s", WQ_MEM_RECLAIM, 1, phba->wq_name); + phba->wq = alloc_workqueue("%s", WQ_MEM_RECLAIM, 1, wq_name); if (!phba->wq) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, "BM_%d : beiscsi_dev_probe-" @@ -5881,7 +5850,6 @@ static void beiscsi_remove(struct pci_dev *pcidev) /* free all resources */ destroy_workqueue(phba->wq); - beiscsi_cleanup_port(phba); beiscsi_free_mem(phba); /* ctrl uninit */ diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h index 6376657e45f7..218857926566 100644 --- a/drivers/scsi/be2iscsi/be_main.h +++ b/drivers/scsi/be2iscsi/be_main.h @@ -36,7 +36,7 @@ #include <scsi/scsi_transport_iscsi.h> #define DRV_NAME "be2iscsi" -#define BUILD_STR "11.2.0.0" +#define BUILD_STR "11.2.1.0" #define BE_NAME "Emulex OneConnect" \ "Open-iSCSI Driver version" BUILD_STR #define DRV_DESC BE_NAME " " "Driver" @@ -57,7 +57,6 @@ #define BE2_IO_DEPTH 1024 #define BE2_MAX_SESSIONS 256 -#define BE2_CMDS_PER_CXN 128 #define BE2_TMFS 16 #define BE2_NOPOUT_REQ 16 #define BE2_SGE 32 @@ -72,8 +71,13 @@ #define BEISCSI_SGLIST_ELEMENTS 30 -#define BEISCSI_CMD_PER_LUN 128 /* scsi_host->cmd_per_lun */ -#define BEISCSI_MAX_SECTORS 1024 /* scsi_host->max_sectors */ +/** + * BE_INVLDT_CMD_TBL_SZ is 128 which is total number commands that can + * be invalidated at a time, consider it before changing the value of + * BEISCSI_CMD_PER_LUN. + */ +#define BEISCSI_CMD_PER_LUN 128 /* scsi_host->cmd_per_lun */ +#define BEISCSI_MAX_SECTORS 1024 /* scsi_host->max_sectors */ #define BEISCSI_TEMPLATE_HDR_PER_CXN_SIZE 128 /* Template size per cxn */ #define BEISCSI_MAX_CMD_LEN 16 /* scsi_host->max_cmd_len */ @@ -239,19 +243,7 @@ struct hba_parameters { unsigned int num_cq_entries; unsigned int num_eq_entries; unsigned int wrbs_per_cxn; - unsigned int crashmode; - unsigned int hba_num; - - unsigned int mgmt_ws_sz; unsigned int hwi_ws_sz; - - unsigned int eto; - unsigned int ldto; - - unsigned int dbg_flags; - unsigned int num_cxn; - - unsigned int eq_timer; /** * These are calculated from other params. They're here * for debug purposes @@ -272,11 +264,6 @@ struct hba_parameters { unsigned int num_sge; }; -struct invalidate_command_table { - unsigned short icd; - unsigned short cid; -} __packed; - #define BEISCSI_GET_ULP_FROM_CRI(phwi_ctrlr, cri) \ (phwi_ctrlr->wrb_context[cri].ulp_num) struct hwi_wrb_context { @@ -334,7 +321,6 @@ struct beiscsi_hba { struct be_bus_address pci_pa; /* CSR */ /* PCI representation of our HBA */ struct pci_dev *pcidev; - unsigned short asic_revision; unsigned int num_cpus; unsigned int nxt_cqid; struct msix_entry msix_entries[MAX_CPUS]; @@ -355,9 +341,9 @@ struct beiscsi_hba { spinlock_t io_sgl_lock; spinlock_t mgmt_sgl_lock; spinlock_t async_pdu_lock; - unsigned int age; struct list_head hba_queue; #define BE_MAX_SESSION 2048 +#define BE_INVALID_CID 0xffff #define BE_SET_CID_TO_CRI(cri_index, cid) \ (phba->cid_to_cri_map[cid] = cri_index) #define BE_GET_CRI_FROM_CID(cid) (phba->cid_to_cri_map[cid]) @@ -425,12 +411,10 @@ struct beiscsi_hba { u8 port_name; u8 port_speed; char fw_ver_str[BEISCSI_VER_STRLEN]; - char wq_name[20]; struct workqueue_struct *wq; /* The actuak work queue */ struct be_ctrl_info ctrl; unsigned int generation; unsigned int interface_handle; - struct invalidate_command_table inv_tbl[128]; struct be_aic_obj aic_obj[MAX_CPUS]; unsigned int attr_log_enable; @@ -525,10 +509,6 @@ struct beiscsi_io_task { struct scsi_cmnd *scsi_cmnd; int num_sg; struct hwi_wrb_context *pwrb_context; - unsigned int cmd_sn; - unsigned int flags; - unsigned short cid; - unsigned short header_len; itt_t libiscsi_itt; struct be_cmd_bhs *cmd_bhs; struct be_bus_address bhs_pa; @@ -842,7 +822,7 @@ struct amap_iscsi_wrb_v2 { u8 diff_enbl; /* DWORD 11 */ u8 u_run; /* DWORD 11 */ u8 o_run; /* DWORD 11 */ - u8 invalid; /* DWORD 11 */ + u8 invld; /* DWORD 11 */ u8 dsp; /* DWORD 11 */ u8 dmsg; /* DWORD 11 */ u8 rsvd4; /* DWORD 11 */ @@ -1042,10 +1022,8 @@ struct hwi_controller { struct list_head io_sgl_list; struct list_head eh_sgl_list; struct sgl_handle *psgl_handle_base; - unsigned int wrb_mem_index; struct hwi_wrb_context *wrb_context; - struct mcc_wrb *pmcc_wrb_base; struct be_ring default_pdu_hdr[BEISCSI_ULP_COUNT]; struct be_ring default_pdu_data[BEISCSI_ULP_COUNT]; struct hwi_context_memory *phwi_ctxt; @@ -1062,9 +1040,7 @@ enum hwh_type_enum { }; struct wrb_handle { - enum hwh_type_enum type; unsigned short wrb_index; - struct iscsi_task *pio_handle; struct iscsi_wrb *pwrb; }; diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c index ac05317bba7f..2f6d5c2ac329 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.c +++ b/drivers/scsi/be2iscsi/be_mgmt.c @@ -66,7 +66,6 @@ unsigned int mgmt_vendor_specific_fw_cmd(struct be_ctrl_info *ctrl, struct bsg_job *job, struct be_dma_mem *nonemb_cmd) { - struct be_cmd_resp_hdr *resp; struct be_mcc_wrb *wrb; struct be_sge *mcc_sge; unsigned int tag = 0; @@ -76,7 +75,6 @@ unsigned int mgmt_vendor_specific_fw_cmd(struct be_ctrl_info *ctrl, nonemb_cmd->size = job->request_payload.payload_len; memset(nonemb_cmd->va, 0, nonemb_cmd->size); - resp = nonemb_cmd->va; region = bsg_req->rqst_data.h_vendor.vendor_cmd[1]; sector_size = bsg_req->rqst_data.h_vendor.vendor_cmd[2]; sector = bsg_req->rqst_data.h_vendor.vendor_cmd[3]; @@ -128,50 +126,6 @@ unsigned int mgmt_vendor_specific_fw_cmd(struct be_ctrl_info *ctrl, return tag; } -unsigned int mgmt_invalidate_icds(struct beiscsi_hba *phba, - struct invalidate_command_table *inv_tbl, - unsigned int num_invalidate, unsigned int cid, - struct be_dma_mem *nonemb_cmd) - -{ - struct be_ctrl_info *ctrl = &phba->ctrl; - struct be_mcc_wrb *wrb; - struct be_sge *sge; - struct invalidate_commands_params_in *req; - unsigned int i, tag; - - mutex_lock(&ctrl->mbox_lock); - wrb = alloc_mcc_wrb(phba, &tag); - if (!wrb) { - mutex_unlock(&ctrl->mbox_lock); - return 0; - } - - req = nonemb_cmd->va; - memset(req, 0, sizeof(*req)); - sge = nonembedded_sgl(wrb); - - be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1); - be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI, - OPCODE_COMMON_ISCSI_ERROR_RECOVERY_INVALIDATE_COMMANDS, - sizeof(*req)); - req->ref_handle = 0; - req->cleanup_type = CMD_ISCSI_COMMAND_INVALIDATE; - for (i = 0; i < num_invalidate; i++) { - req->table[i].icd = inv_tbl->icd; - req->table[i].cid = inv_tbl->cid; - req->icd_count++; - inv_tbl++; - } - sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma)); - sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF); - sge->len = cpu_to_le32(nonemb_cmd->size); - - be_mcc_notify(phba, tag); - mutex_unlock(&ctrl->mbox_lock); - return tag; -} - unsigned int mgmt_invalidate_connection(struct beiscsi_hba *phba, struct beiscsi_endpoint *beiscsi_ep, unsigned short cid, @@ -1066,7 +1020,6 @@ unsigned int beiscsi_boot_reopen_sess(struct beiscsi_hba *phba) unsigned int beiscsi_boot_get_sinfo(struct beiscsi_hba *phba) { struct be_ctrl_info *ctrl = &phba->ctrl; - struct be_cmd_get_session_resp *resp; struct be_cmd_get_session_req *req; struct be_dma_mem *nonemb_cmd; struct be_mcc_wrb *wrb; @@ -1081,7 +1034,7 @@ unsigned int beiscsi_boot_get_sinfo(struct beiscsi_hba *phba) } nonemb_cmd = &phba->boot_struct.nonemb_cmd; - nonemb_cmd->size = sizeof(*resp); + nonemb_cmd->size = sizeof(struct be_cmd_get_session_resp); nonemb_cmd->va = pci_alloc_consistent(phba->ctrl.pdev, nonemb_cmd->size, &nonemb_cmd->dma); @@ -1096,7 +1049,7 @@ unsigned int beiscsi_boot_get_sinfo(struct beiscsi_hba *phba) be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1); be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI, OPCODE_ISCSI_INI_SESSION_GET_A_SESSION, - sizeof(*resp)); + sizeof(struct be_cmd_get_session_resp)); req->session_handle = phba->boot_struct.s_handle; sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma)); sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF); @@ -1309,7 +1262,8 @@ beiscsi_adap_family_disp(struct device *dev, struct device_attribute *attr, case BE_DEVICE_ID1: case OC_DEVICE_ID1: case OC_DEVICE_ID2: - return snprintf(buf, PAGE_SIZE, "BE2 Adapter Family\n"); + return snprintf(buf, PAGE_SIZE, + "Obsolete/Unsupported BE2 Adapter Family\n"); break; case BE_DEVICE_ID2: case OC_DEVICE_ID3: @@ -1341,7 +1295,7 @@ beiscsi_phys_port_disp(struct device *dev, struct device_attribute *attr, struct Scsi_Host *shost = class_to_shost(dev); struct beiscsi_hba *phba = iscsi_host_priv(shost); - return snprintf(buf, PAGE_SIZE, "Port Identifier : %d\n", + return snprintf(buf, PAGE_SIZE, "Port Identifier : %u\n", phba->fw_config.phys_port); } @@ -1494,3 +1448,64 @@ void beiscsi_offload_cxn_v2(struct beiscsi_offload_params *params, (params->dw[offsetof(struct amap_beiscsi_offload_params, exp_statsn) / 32] + 1)); } + +int beiscsi_mgmt_invalidate_icds(struct beiscsi_hba *phba, + struct invldt_cmd_tbl *inv_tbl, + unsigned int nents) +{ + struct be_ctrl_info *ctrl = &phba->ctrl; + struct invldt_cmds_params_in *req; + struct be_dma_mem nonemb_cmd; + struct be_mcc_wrb *wrb; + unsigned int i, tag; + struct be_sge *sge; + int rc; + + if (!nents || nents > BE_INVLDT_CMD_TBL_SZ) + return -EINVAL; + + nonemb_cmd.size = sizeof(union be_invldt_cmds_params); + nonemb_cmd.va = pci_zalloc_consistent(phba->ctrl.pdev, + nonemb_cmd.size, + &nonemb_cmd.dma); + if (!nonemb_cmd.va) { + beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_EH, + "BM_%d : invldt_cmds_params alloc failed\n"); + return -ENOMEM; + } + + mutex_lock(&ctrl->mbox_lock); + wrb = alloc_mcc_wrb(phba, &tag); + if (!wrb) { + mutex_unlock(&ctrl->mbox_lock); + pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size, + nonemb_cmd.va, nonemb_cmd.dma); + return -ENOMEM; + } + + req = nonemb_cmd.va; + be_wrb_hdr_prepare(wrb, nonemb_cmd.size, false, 1); + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI, + OPCODE_COMMON_ISCSI_ERROR_RECOVERY_INVALIDATE_COMMANDS, + sizeof(*req)); + req->ref_handle = 0; + req->cleanup_type = CMD_ISCSI_COMMAND_INVALIDATE; + for (i = 0; i < nents; i++) { + req->table[i].icd = inv_tbl[i].icd; + req->table[i].cid = inv_tbl[i].cid; + req->icd_count++; + } + sge = nonembedded_sgl(wrb); + sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd.dma)); + sge->pa_lo = cpu_to_le32(lower_32_bits(nonemb_cmd.dma)); + sge->len = cpu_to_le32(nonemb_cmd.size); + + be_mcc_notify(phba, tag); + mutex_unlock(&ctrl->mbox_lock); + + rc = beiscsi_mccq_compl_wait(phba, tag, NULL, &nonemb_cmd); + if (rc != -EBUSY) + pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size, + nonemb_cmd.va, nonemb_cmd.dma); + return rc; +} diff --git a/drivers/scsi/be2iscsi/be_mgmt.h b/drivers/scsi/be2iscsi/be_mgmt.h index b897cfd57c72..308f1472f98a 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.h +++ b/drivers/scsi/be2iscsi/be_mgmt.h @@ -36,66 +36,6 @@ #define PCICFG_UE_STATUS_MASK_LOW 0xA8 #define PCICFG_UE_STATUS_MASK_HI 0xAC -/** - * Pseudo amap definition in which each bit of the actual structure is defined - * as a byte: used to calculate offset/shift/mask of each field - */ -struct amap_mcc_sge { - u8 pa_lo[32]; /* dword 0 */ - u8 pa_hi[32]; /* dword 1 */ - u8 length[32]; /* DWORD 2 */ -} __packed; - -/** - * Pseudo amap definition in which each bit of the actual structure is defined - * as a byte: used to calculate offset/shift/mask of each field - */ -struct amap_mcc_wrb_payload { - union { - struct amap_mcc_sge sgl[19]; - u8 embedded[59 * 32]; /* DWORDS 57 to 115 */ - } u; -} __packed; - -/** - * Pseudo amap definition in which each bit of the actual structure is defined - * as a byte: used to calculate offset/shift/mask of each field - */ -struct amap_mcc_wrb { - u8 embedded; /* DWORD 0 */ - u8 rsvd0[2]; /* DWORD 0 */ - u8 sge_count[5]; /* DWORD 0 */ - u8 rsvd1[16]; /* DWORD 0 */ - u8 special[8]; /* DWORD 0 */ - u8 payload_length[32]; - u8 tag[64]; /* DWORD 2 */ - u8 rsvd2[32]; /* DWORD 4 */ - struct amap_mcc_wrb_payload payload; -}; - -struct mcc_sge { - u32 pa_lo; /* dword 0 */ - u32 pa_hi; /* dword 1 */ - u32 length; /* DWORD 2 */ -} __packed; - -struct mcc_wrb_payload { - union { - struct mcc_sge sgl[19]; - u32 embedded[59]; /* DWORDS 57 to 115 */ - } u; -} __packed; - -#define MCC_WRB_EMBEDDED_MASK 0x00000001 - -struct mcc_wrb { - u32 dw[0]; /* DWORD 0 */ - u32 payload_length; - u32 tag[2]; /* DWORD 2 */ - u32 rsvd2[1]; /* DWORD 4 */ - struct mcc_wrb_payload payload; -}; - int mgmt_open_connection(struct beiscsi_hba *phba, struct sockaddr *dst_addr, struct beiscsi_endpoint *beiscsi_ep, @@ -104,10 +44,6 @@ int mgmt_open_connection(struct beiscsi_hba *phba, unsigned int mgmt_upload_connection(struct beiscsi_hba *phba, unsigned short cid, unsigned int upload_flag); -unsigned int mgmt_invalidate_icds(struct beiscsi_hba *phba, - struct invalidate_command_table *inv_tbl, - unsigned int num_invalidate, unsigned int cid, - struct be_dma_mem *nonemb_cmd); unsigned int mgmt_vendor_specific_fw_cmd(struct be_ctrl_info *ctrl, struct beiscsi_hba *phba, struct bsg_job *job, @@ -134,24 +70,31 @@ union iscsi_invalidate_connection_params { struct iscsi_invalidate_connection_params_out response; } __packed; -struct invalidate_commands_params_in { +#define BE_INVLDT_CMD_TBL_SZ 128 +struct invldt_cmd_tbl { + unsigned short icd; + unsigned short cid; +} __packed; + +struct invldt_cmds_params_in { struct be_cmd_req_hdr hdr; unsigned int ref_handle; unsigned int icd_count; - struct invalidate_command_table table[128]; + struct invldt_cmd_tbl table[BE_INVLDT_CMD_TBL_SZ]; unsigned short cleanup_type; unsigned short unused; } __packed; -struct invalidate_commands_params_out { +struct invldt_cmds_params_out { + struct be_cmd_resp_hdr hdr; unsigned int ref_handle; unsigned int icd_count; - unsigned int icd_status[128]; + unsigned int icd_status[BE_INVLDT_CMD_TBL_SZ]; } __packed; -union invalidate_commands_params { - struct invalidate_commands_params_in request; - struct invalidate_commands_params_out response; +union be_invldt_cmds_params { + struct invldt_cmds_params_in request; + struct invldt_cmds_params_out response; } __packed; struct mgmt_hba_attributes { @@ -231,16 +174,6 @@ struct be_bsg_vendor_cmd { #define GET_MGMT_CONTROLLER_WS(phba) (phba->pmgmt_ws) -/* MGMT CMD flags */ - -#define MGMT_CMDH_FREE (1<<0) - -/* --- MGMT_ERROR_CODES --- */ -/* Error Codes returned in the status field of the CMD response header */ -#define MGMT_STATUS_SUCCESS 0 /* The CMD completed without errors */ -#define MGMT_STATUS_FAILED 1 /* Error status in the Status field of */ - /* the CMD_RESPONSE_HEADER */ - #define ISCSI_GET_PDU_TEMPLATE_ADDRESS(pc, pa) {\ pa->lo = phba->init_mem[ISCSI_MEM_GLOBAL_HEADER].mem_array[0].\ bus_address.u.a32.address_lo; \ @@ -270,6 +203,9 @@ unsigned int mgmt_invalidate_connection(struct beiscsi_hba *phba, unsigned short cid, unsigned short issue_reset, unsigned short savecfg_flag); +int beiscsi_mgmt_invalidate_icds(struct beiscsi_hba *phba, + struct invldt_cmd_tbl *inv_tbl, + unsigned int nents); int beiscsi_if_en_dhcp(struct beiscsi_hba *phba, u32 ip_type); diff --git a/drivers/scsi/bfa/bfa_fcs.c b/drivers/scsi/bfa/bfa_fcs.c index 1e7e139d71ea..4aa61e20e82d 100644 --- a/drivers/scsi/bfa/bfa_fcs.c +++ b/drivers/scsi/bfa/bfa_fcs.c @@ -28,24 +28,6 @@ BFA_TRC_FILE(FCS, FCS); /* - * FCS sub-modules - */ -struct bfa_fcs_mod_s { - void (*attach) (struct bfa_fcs_s *fcs); - void (*modinit) (struct bfa_fcs_s *fcs); - void (*modexit) (struct bfa_fcs_s *fcs); -}; - -#define BFA_FCS_MODULE(_mod) { _mod ## _modinit, _mod ## _modexit } - -static struct bfa_fcs_mod_s fcs_modules[] = { - { bfa_fcs_port_attach, NULL, NULL }, - { bfa_fcs_uf_attach, NULL, NULL }, - { bfa_fcs_fabric_attach, bfa_fcs_fabric_modinit, - bfa_fcs_fabric_modexit }, -}; - -/* * fcs_api BFA FCS API */ @@ -58,52 +40,19 @@ bfa_fcs_exit_comp(void *fcs_cbarg) complete(&bfad->comp); } - - /* - * fcs_api BFA FCS API - */ - -/* - * fcs attach -- called once to initialize data structures at driver attach time + * fcs initialization, called once after bfa initialization is complete */ void -bfa_fcs_attach(struct bfa_fcs_s *fcs, struct bfa_s *bfa, struct bfad_s *bfad, - bfa_boolean_t min_cfg) +bfa_fcs_init(struct bfa_fcs_s *fcs) { - int i; - struct bfa_fcs_mod_s *mod; - - fcs->bfa = bfa; - fcs->bfad = bfad; - fcs->min_cfg = min_cfg; - fcs->num_rport_logins = 0; - - bfa->fcs = BFA_TRUE; - fcbuild_init(); - - for (i = 0; i < ARRAY_SIZE(fcs_modules); i++) { - mod = &fcs_modules[i]; - if (mod->attach) - mod->attach(fcs); - } + bfa_sm_send_event(&fcs->fabric, BFA_FCS_FABRIC_SM_CREATE); + bfa_trc(fcs, 0); } /* - * fcs initialization, called once after bfa initialization is complete + * fcs_api BFA FCS API */ -void -bfa_fcs_init(struct bfa_fcs_s *fcs) -{ - int i; - struct bfa_fcs_mod_s *mod; - - for (i = 0; i < ARRAY_SIZE(fcs_modules); i++) { - mod = &fcs_modules[i]; - if (mod->modinit) - mod->modinit(fcs); - } -} /* * FCS update cfg - reset the pwwn/nwwn of fabric base logical port @@ -180,26 +129,14 @@ bfa_fcs_driver_info_init(struct bfa_fcs_s *fcs, void bfa_fcs_exit(struct bfa_fcs_s *fcs) { - struct bfa_fcs_mod_s *mod; - int nmods, i; - bfa_wc_init(&fcs->wc, bfa_fcs_exit_comp, fcs); - - nmods = ARRAY_SIZE(fcs_modules); - - for (i = 0; i < nmods; i++) { - - mod = &fcs_modules[i]; - if (mod->modexit) { - bfa_wc_up(&fcs->wc); - mod->modexit(fcs); - } - } - + bfa_wc_up(&fcs->wc); + bfa_trc(fcs, 0); + bfa_lps_delete(fcs->fabric.lps); + bfa_sm_send_event(&fcs->fabric, BFA_FCS_FABRIC_SM_DELETE); bfa_wc_wait(&fcs->wc); } - /* * Fabric module implementation. */ @@ -1128,62 +1065,6 @@ bfa_fcs_fabric_stop_comp(void *cbarg) */ /* - * Attach time initialization. - */ -void -bfa_fcs_fabric_attach(struct bfa_fcs_s *fcs) -{ - struct bfa_fcs_fabric_s *fabric; - - fabric = &fcs->fabric; - memset(fabric, 0, sizeof(struct bfa_fcs_fabric_s)); - - /* - * Initialize base fabric. - */ - fabric->fcs = fcs; - INIT_LIST_HEAD(&fabric->vport_q); - INIT_LIST_HEAD(&fabric->vf_q); - fabric->lps = bfa_lps_alloc(fcs->bfa); - WARN_ON(!fabric->lps); - - /* - * Initialize fabric delete completion handler. Fabric deletion is - * complete when the last vport delete is complete. - */ - bfa_wc_init(&fabric->wc, bfa_fcs_fabric_delete_comp, fabric); - bfa_wc_up(&fabric->wc); /* For the base port */ - - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_uninit); - bfa_fcs_lport_attach(&fabric->bport, fabric->fcs, FC_VF_ID_NULL, NULL); -} - -void -bfa_fcs_fabric_modinit(struct bfa_fcs_s *fcs) -{ - bfa_sm_send_event(&fcs->fabric, BFA_FCS_FABRIC_SM_CREATE); - bfa_trc(fcs, 0); -} - -/* - * Module cleanup - */ -void -bfa_fcs_fabric_modexit(struct bfa_fcs_s *fcs) -{ - struct bfa_fcs_fabric_s *fabric; - - bfa_trc(fcs, 0); - - /* - * Cleanup base fabric. - */ - fabric = &fcs->fabric; - bfa_lps_delete(fabric->lps); - bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_DELETE); -} - -/* * Fabric module stop -- stop FCS actions */ void @@ -1633,12 +1514,6 @@ bfa_fcs_port_event_handler(void *cbarg, enum bfa_port_linkstate event) } } -void -bfa_fcs_port_attach(struct bfa_fcs_s *fcs) -{ - bfa_fcport_event_register(fcs->bfa, bfa_fcs_port_event_handler, fcs); -} - /* * BFA FCS UF ( Unsolicited Frames) */ @@ -1706,8 +1581,44 @@ bfa_fcs_uf_recv(void *cbarg, struct bfa_uf_s *uf) bfa_uf_free(uf); } +/* + * fcs attach -- called once to initialize data structures at driver attach time + */ void -bfa_fcs_uf_attach(struct bfa_fcs_s *fcs) +bfa_fcs_attach(struct bfa_fcs_s *fcs, struct bfa_s *bfa, struct bfad_s *bfad, + bfa_boolean_t min_cfg) { + struct bfa_fcs_fabric_s *fabric = &fcs->fabric; + + fcs->bfa = bfa; + fcs->bfad = bfad; + fcs->min_cfg = min_cfg; + fcs->num_rport_logins = 0; + + bfa->fcs = BFA_TRUE; + fcbuild_init(); + + bfa_fcport_event_register(fcs->bfa, bfa_fcs_port_event_handler, fcs); bfa_uf_recv_register(fcs->bfa, bfa_fcs_uf_recv, fcs); + + memset(fabric, 0, sizeof(struct bfa_fcs_fabric_s)); + + /* + * Initialize base fabric. + */ + fabric->fcs = fcs; + INIT_LIST_HEAD(&fabric->vport_q); + INIT_LIST_HEAD(&fabric->vf_q); + fabric->lps = bfa_lps_alloc(fcs->bfa); + WARN_ON(!fabric->lps); + + /* + * Initialize fabric delete completion handler. Fabric deletion is + * complete when the last vport delete is complete. + */ + bfa_wc_init(&fabric->wc, bfa_fcs_fabric_delete_comp, fabric); + bfa_wc_up(&fabric->wc); /* For the base port */ + + bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_uninit); + bfa_fcs_lport_attach(&fabric->bport, fabric->fcs, FC_VF_ID_NULL, NULL); } diff --git a/drivers/scsi/bfa/bfa_fcs.h b/drivers/scsi/bfa/bfa_fcs.h index 0f797a55d504..e60f72b766ea 100644 --- a/drivers/scsi/bfa/bfa_fcs.h +++ b/drivers/scsi/bfa/bfa_fcs.h @@ -808,9 +808,7 @@ void bfa_fcs_vf_get_ports(bfa_fcs_vf_t *vf, wwn_t vpwwn[], int *nports); /* * fabric protected interface functions */ -void bfa_fcs_fabric_attach(struct bfa_fcs_s *fcs); void bfa_fcs_fabric_modinit(struct bfa_fcs_s *fcs); -void bfa_fcs_fabric_modexit(struct bfa_fcs_s *fcs); void bfa_fcs_fabric_link_up(struct bfa_fcs_fabric_s *fabric); void bfa_fcs_fabric_link_down(struct bfa_fcs_fabric_s *fabric); void bfa_fcs_fabric_addvport(struct bfa_fcs_fabric_s *fabric, @@ -827,8 +825,6 @@ void bfa_fcs_fabric_nsymb_init(struct bfa_fcs_fabric_s *fabric); void bfa_fcs_fabric_set_fabric_name(struct bfa_fcs_fabric_s *fabric, wwn_t fabric_name); u16 bfa_fcs_fabric_get_switch_oui(struct bfa_fcs_fabric_s *fabric); -void bfa_fcs_uf_attach(struct bfa_fcs_s *fcs); -void bfa_fcs_port_attach(struct bfa_fcs_s *fcs); void bfa_fcs_fabric_modstop(struct bfa_fcs_s *fcs); void bfa_fcs_fabric_sm_online(struct bfa_fcs_fabric_s *fabric, enum bfa_fcs_fabric_event event); diff --git a/drivers/scsi/cxlflash/common.h b/drivers/scsi/cxlflash/common.h index 0e9de5d62da2..d11dcc59ff46 100644 --- a/drivers/scsi/cxlflash/common.h +++ b/drivers/scsi/cxlflash/common.h @@ -54,6 +54,9 @@ extern const struct file_operations cxlflash_cxl_fops; /* RRQ for master issued cmds */ #define NUM_RRQ_ENTRY CXLFLASH_MAX_CMDS +/* SQ for master issued cmds */ +#define NUM_SQ_ENTRY CXLFLASH_MAX_CMDS + static inline void check_sizes(void) { @@ -155,8 +158,8 @@ static inline struct afu_cmd *sc_to_afucz(struct scsi_cmnd *sc) struct afu { /* Stuff requiring alignment go first. */ - - u64 rrq_entry[NUM_RRQ_ENTRY]; /* 2K RRQ */ + struct sisl_ioarcb sq[NUM_SQ_ENTRY]; /* 16K SQ */ + u64 rrq_entry[NUM_RRQ_ENTRY]; /* 2K RRQ */ /* Beware of alignment till here. Preferably introduce new * fields after this point @@ -171,9 +174,13 @@ struct afu { struct sisl_host_map __iomem *host_map; /* MC host map */ struct sisl_ctrl_map __iomem *ctrl_map; /* MC control map */ - struct kref mapcount; - ctx_hndl_t ctx_hndl; /* master's context handle */ + + atomic_t hsq_credits; + spinlock_t hsq_slock; + struct sisl_ioarcb *hsq_start; + struct sisl_ioarcb *hsq_end; + struct sisl_ioarcb *hsq_curr; u64 *hrrq_start; u64 *hrrq_end; u64 *hrrq_curr; @@ -191,6 +198,23 @@ struct afu { }; +static inline bool afu_is_cmd_mode(struct afu *afu, u64 cmd_mode) +{ + u64 afu_cap = afu->interface_version >> SISL_INTVER_CAP_SHIFT; + + return afu_cap & cmd_mode; +} + +static inline bool afu_is_sq_cmd_mode(struct afu *afu) +{ + return afu_is_cmd_mode(afu, SISL_INTVER_CAP_SQ_CMD_MODE); +} + +static inline bool afu_is_ioarrin_cmd_mode(struct afu *afu) +{ + return afu_is_cmd_mode(afu, SISL_INTVER_CAP_IOARRIN_CMD_MODE); +} + static inline u64 lun_to_lunid(u64 lun) { __be64 lun_id; diff --git a/drivers/scsi/cxlflash/lunmgt.c b/drivers/scsi/cxlflash/lunmgt.c index 6c318db90c85..0efed177cc8b 100644 --- a/drivers/scsi/cxlflash/lunmgt.c +++ b/drivers/scsi/cxlflash/lunmgt.c @@ -32,11 +32,13 @@ */ static struct llun_info *create_local(struct scsi_device *sdev, u8 *wwid) { + struct cxlflash_cfg *cfg = shost_priv(sdev->host); + struct device *dev = &cfg->dev->dev; struct llun_info *lli = NULL; lli = kzalloc(sizeof(*lli), GFP_KERNEL); if (unlikely(!lli)) { - pr_err("%s: could not allocate lli\n", __func__); + dev_err(dev, "%s: could not allocate lli\n", __func__); goto out; } @@ -58,11 +60,13 @@ out: */ static struct glun_info *create_global(struct scsi_device *sdev, u8 *wwid) { + struct cxlflash_cfg *cfg = shost_priv(sdev->host); + struct device *dev = &cfg->dev->dev; struct glun_info *gli = NULL; gli = kzalloc(sizeof(*gli), GFP_KERNEL); if (unlikely(!gli)) { - pr_err("%s: could not allocate gli\n", __func__); + dev_err(dev, "%s: could not allocate gli\n", __func__); goto out; } @@ -129,10 +133,10 @@ static struct glun_info *lookup_global(u8 *wwid) */ static struct llun_info *find_and_create_lun(struct scsi_device *sdev, u8 *wwid) { + struct cxlflash_cfg *cfg = shost_priv(sdev->host); + struct device *dev = &cfg->dev->dev; struct llun_info *lli = NULL; struct glun_info *gli = NULL; - struct Scsi_Host *shost = sdev->host; - struct cxlflash_cfg *cfg = shost_priv(shost); if (unlikely(!wwid)) goto out; @@ -165,7 +169,7 @@ static struct llun_info *find_and_create_lun(struct scsi_device *sdev, u8 *wwid) list_add(&gli->list, &global.gluns); out: - pr_debug("%s: returning %p\n", __func__, lli); + dev_dbg(dev, "%s: returning lli=%p, gli=%p\n", __func__, lli, gli); return lli; } @@ -225,17 +229,18 @@ void cxlflash_term_global_luns(void) int cxlflash_manage_lun(struct scsi_device *sdev, struct dk_cxlflash_manage_lun *manage) { - int rc = 0; + struct cxlflash_cfg *cfg = shost_priv(sdev->host); + struct device *dev = &cfg->dev->dev; struct llun_info *lli = NULL; + int rc = 0; u64 flags = manage->hdr.flags; u32 chan = sdev->channel; mutex_lock(&global.mutex); lli = find_and_create_lun(sdev, manage->wwid); - pr_debug("%s: ENTER: WWID = %016llX%016llX, flags = %016llX li = %p\n", - __func__, get_unaligned_be64(&manage->wwid[0]), - get_unaligned_be64(&manage->wwid[8]), - manage->hdr.flags, lli); + dev_dbg(dev, "%s: WWID=%016llx%016llx, flags=%016llx lli=%p\n", + __func__, get_unaligned_be64(&manage->wwid[0]), + get_unaligned_be64(&manage->wwid[8]), manage->hdr.flags, lli); if (unlikely(!lli)) { rc = -ENOMEM; goto out; @@ -265,11 +270,11 @@ int cxlflash_manage_lun(struct scsi_device *sdev, } } - pr_debug("%s: port_sel = %08X chan = %u lun_id = %016llX\n", __func__, - lli->port_sel, chan, lli->lun_id[chan]); + dev_dbg(dev, "%s: port_sel=%08x chan=%u lun_id=%016llx\n", + __func__, lli->port_sel, chan, lli->lun_id[chan]); out: mutex_unlock(&global.mutex); - pr_debug("%s: returning rc=%d\n", __func__, rc); + dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); return rc; } diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index b17ebf6d0a7e..7069639e92bc 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -43,6 +43,9 @@ MODULE_LICENSE("GPL"); */ static void process_cmd_err(struct afu_cmd *cmd, struct scsi_cmnd *scp) { + struct afu *afu = cmd->parent; + struct cxlflash_cfg *cfg = afu->parent; + struct device *dev = &cfg->dev->dev; struct sisl_ioarcb *ioarcb; struct sisl_ioasa *ioasa; u32 resid; @@ -56,21 +59,20 @@ static void process_cmd_err(struct afu_cmd *cmd, struct scsi_cmnd *scp) if (ioasa->rc.flags & SISL_RC_FLAGS_UNDERRUN) { resid = ioasa->resid; scsi_set_resid(scp, resid); - pr_debug("%s: cmd underrun cmd = %p scp = %p, resid = %d\n", - __func__, cmd, scp, resid); + dev_dbg(dev, "%s: cmd underrun cmd = %p scp = %p, resid = %d\n", + __func__, cmd, scp, resid); } if (ioasa->rc.flags & SISL_RC_FLAGS_OVERRUN) { - pr_debug("%s: cmd underrun cmd = %p scp = %p\n", - __func__, cmd, scp); + dev_dbg(dev, "%s: cmd underrun cmd = %p scp = %p\n", + __func__, cmd, scp); scp->result = (DID_ERROR << 16); } - pr_debug("%s: cmd failed afu_rc=%d scsi_rc=%d fc_rc=%d " - "afu_extra=0x%X, scsi_extra=0x%X, fc_extra=0x%X\n", - __func__, ioasa->rc.afu_rc, ioasa->rc.scsi_rc, - ioasa->rc.fc_rc, ioasa->afu_extra, ioasa->scsi_extra, - ioasa->fc_extra); + dev_dbg(dev, "%s: cmd failed afu_rc=%02x scsi_rc=%02x fc_rc=%02x " + "afu_extra=%02x scsi_extra=%02x fc_extra=%02x\n", __func__, + ioasa->rc.afu_rc, ioasa->rc.scsi_rc, ioasa->rc.fc_rc, + ioasa->afu_extra, ioasa->scsi_extra, ioasa->fc_extra); if (ioasa->rc.scsi_rc) { /* We have a SCSI status */ @@ -159,6 +161,7 @@ static void cmd_complete(struct afu_cmd *cmd) ulong lock_flags; struct afu *afu = cmd->parent; struct cxlflash_cfg *cfg = afu->parent; + struct device *dev = &cfg->dev->dev; bool cmd_is_tmf; if (cmd->scp) { @@ -170,9 +173,8 @@ static void cmd_complete(struct afu_cmd *cmd) cmd_is_tmf = cmd->cmd_tmf; - pr_debug_ratelimited("%s: calling scsi_done scp=%p result=%X " - "ioasc=%d\n", __func__, scp, scp->result, - cmd->sa.ioasc); + 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); @@ -188,10 +190,11 @@ static void cmd_complete(struct afu_cmd *cmd) } /** - * context_reset_ioarrin() - reset command owner context via IOARRIN register + * context_reset() - reset command owner context via specified register * @cmd: AFU command that timed out. + * @reset_reg: MMIO register to perform reset. */ -static void context_reset_ioarrin(struct afu_cmd *cmd) +static void context_reset(struct afu_cmd *cmd, __be64 __iomem *reset_reg) { int nretry = 0; u64 rrin = 0x1; @@ -199,22 +202,44 @@ static void context_reset_ioarrin(struct afu_cmd *cmd) struct cxlflash_cfg *cfg = afu->parent; struct device *dev = &cfg->dev->dev; - pr_debug("%s: cmd=%p\n", __func__, cmd); + dev_dbg(dev, "%s: cmd=%p\n", __func__, cmd); - writeq_be(rrin, &afu->host_map->ioarrin); + writeq_be(rrin, reset_reg); do { - rrin = readq_be(&afu->host_map->ioarrin); + rrin = readq_be(reset_reg); if (rrin != 0x1) break; /* Double delay each time */ udelay(1 << nretry); } while (nretry++ < MC_ROOM_RETRY_CNT); - dev_dbg(dev, "%s: returning rrin=0x%016llX nretry=%d\n", + dev_dbg(dev, "%s: returning rrin=%016llx nretry=%d\n", __func__, rrin, nretry); } /** + * context_reset_ioarrin() - reset command owner context via IOARRIN register + * @cmd: AFU command that timed out. + */ +static void context_reset_ioarrin(struct afu_cmd *cmd) +{ + struct afu *afu = cmd->parent; + + context_reset(cmd, &afu->host_map->ioarrin); +} + +/** + * context_reset_sq() - reset command owner context w/ SQ Context Reset register + * @cmd: AFU command that timed out. + */ +static void context_reset_sq(struct afu_cmd *cmd) +{ + struct afu *afu = cmd->parent; + + context_reset(cmd, &afu->host_map->sq_ctx_reset); +} + +/** * send_cmd_ioarrin() - sends an AFU command via IOARRIN register * @afu: AFU associated with the host. * @cmd: AFU command to send. @@ -251,8 +276,51 @@ static int send_cmd_ioarrin(struct afu *afu, struct afu_cmd *cmd) writeq_be((u64)&cmd->rcb, &afu->host_map->ioarrin); out: spin_unlock_irqrestore(&afu->rrin_slock, lock_flags); - pr_devel("%s: cmd=%p len=%d ea=%p rc=%d\n", __func__, cmd, - cmd->rcb.data_len, (void *)cmd->rcb.data_ea, rc); + 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; +} + +/** + * send_cmd_sq() - sends an AFU command via SQ ring + * @afu: AFU associated with the host. + * @cmd: AFU command to send. + * + * Return: + * 0 on success, SCSI_MLQUEUE_HOST_BUSY on failure + */ +static int send_cmd_sq(struct afu *afu, struct afu_cmd *cmd) +{ + struct cxlflash_cfg *cfg = afu->parent; + struct device *dev = &cfg->dev->dev; + int rc = 0; + int newval; + ulong lock_flags; + + newval = atomic_dec_if_positive(&afu->hsq_credits); + if (newval <= 0) { + rc = SCSI_MLQUEUE_HOST_BUSY; + goto out; + } + + cmd->rcb.ioasa = &cmd->sa; + + spin_lock_irqsave(&afu->hsq_slock, lock_flags); + + *afu->hsq_curr = cmd->rcb; + if (afu->hsq_curr < afu->hsq_end) + afu->hsq_curr++; + else + afu->hsq_curr = afu->hsq_start; + writeq_be((u64)afu->hsq_curr, &afu->host_map->sq_tail); + + spin_unlock_irqrestore(&afu->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)); return rc; } @@ -266,6 +334,8 @@ out: */ static int wait_resp(struct afu *afu, struct afu_cmd *cmd) { + struct cxlflash_cfg *cfg = afu->parent; + struct device *dev = &cfg->dev->dev; int rc = 0; ulong timeout = msecs_to_jiffies(cmd->rcb.timeout * 2 * 1000); @@ -276,10 +346,8 @@ static int wait_resp(struct afu *afu, struct afu_cmd *cmd) } if (unlikely(cmd->sa.ioasc != 0)) { - pr_err("%s: CMD 0x%X failed, IOASC: flags 0x%X, afu_rc 0x%X, " - "scsi_rc 0x%X, fc_rc 0x%X\n", __func__, cmd->rcb.cdb[0], - cmd->sa.rc.flags, cmd->sa.rc.afu_rc, cmd->sa.rc.scsi_rc, - cmd->sa.rc.fc_rc); + dev_err(dev, "%s: cmd %02x failed, ioasc=%08x\n", + __func__, cmd->rcb.cdb[0], cmd->sa.ioasc); rc = -1; } @@ -298,8 +366,7 @@ 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 Scsi_Host *host = scp->device->host; - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)host->hostdata; + struct cxlflash_cfg *cfg = shost_priv(scp->device->host); struct afu_cmd *cmd = sc_to_afucz(scp); struct device *dev = &cfg->dev->dev; ulong lock_flags; @@ -344,7 +411,7 @@ static int send_tmf(struct afu *afu, struct scsi_cmnd *scp, u64 tmfcmd) to); if (!to) { cfg->tmf_active = false; - dev_err(dev, "%s: TMF timed out!\n", __func__); + dev_err(dev, "%s: TMF timed out\n", __func__); rc = -1; } spin_unlock_irqrestore(&cfg->tmf_slock, lock_flags); @@ -352,16 +419,6 @@ out: return rc; } -static void afu_unmap(struct kref *ref) -{ - struct afu *afu = container_of(ref, struct afu, mapcount); - - if (likely(afu->afu_map)) { - cxl_psa_unmap((void __iomem *)afu->afu_map); - afu->afu_map = NULL; - } -} - /** * cxlflash_driver_info() - information handler for this host driver * @host: SCSI host associated with device. @@ -382,7 +439,7 @@ static const char *cxlflash_driver_info(struct Scsi_Host *host) */ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp) { - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)host->hostdata; + struct cxlflash_cfg *cfg = shost_priv(host); struct afu *afu = cfg->afu; struct device *dev = &cfg->dev->dev; struct afu_cmd *cmd = sc_to_afucz(scp); @@ -392,10 +449,9 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp) ulong lock_flags; int nseg = 0; int rc = 0; - int kref_got = 0; dev_dbg_ratelimited(dev, "%s: (scp=%p) %d/%d/%d/%llu " - "cdb=(%08X-%08X-%08X-%08X)\n", + "cdb=(%08x-%08x-%08x-%08x)\n", __func__, scp, host->host_no, scp->device->channel, scp->device->id, scp->device->lun, get_unaligned_be32(&((u32 *)scp->cmnd)[0]), @@ -417,11 +473,11 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp) switch (cfg->state) { case STATE_RESET: - dev_dbg_ratelimited(dev, "%s: device is in reset!\n", __func__); + dev_dbg_ratelimited(dev, "%s: device is in reset\n", __func__); rc = SCSI_MLQUEUE_HOST_BUSY; goto out; case STATE_FAILTERM: - dev_dbg_ratelimited(dev, "%s: device has failed!\n", __func__); + dev_dbg_ratelimited(dev, "%s: device has failed\n", __func__); scp->result = (DID_NO_CONNECT << 16); scp->scsi_done(scp); rc = 0; @@ -430,13 +486,10 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp) break; } - kref_get(&cfg->afu->mapcount); - kref_got = 1; - if (likely(sg)) { nseg = scsi_dma_map(scp); if (unlikely(nseg < 0)) { - dev_err(dev, "%s: Fail DMA map!\n", __func__); + dev_err(dev, "%s: Fail DMA map\n", __func__); rc = SCSI_MLQUEUE_HOST_BUSY; goto out; } @@ -463,9 +516,6 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp) if (unlikely(rc)) scsi_dma_unmap(scp); out: - if (kref_got) - kref_put(&afu->mapcount, afu_unmap); - pr_devel("%s: returning rc=%d\n", __func__, rc); return rc; } @@ -503,13 +553,15 @@ static void free_mem(struct cxlflash_cfg *cfg) * * Safe to call with AFU in a partially allocated/initialized state. * - * Waits for any active internal AFU commands to timeout and then unmaps - * the MMIO space. + * Cancels scheduled worker threads, waits for any active internal AFU + * commands to timeout and then unmaps the MMIO space. */ static void stop_afu(struct cxlflash_cfg *cfg) { struct afu *afu = cfg->afu; + cancel_work_sync(&cfg->work_q); + if (likely(afu)) { while (atomic_read(&afu->cmds_active)) ssleep(1); @@ -517,7 +569,6 @@ static void stop_afu(struct cxlflash_cfg *cfg) cxl_psa_unmap((void __iomem *)afu->afu_map); afu->afu_map = NULL; } - kref_put(&afu->mapcount, afu_unmap); } } @@ -585,6 +636,8 @@ static void term_mc(struct cxlflash_cfg *cfg) */ static void term_afu(struct cxlflash_cfg *cfg) { + struct device *dev = &cfg->dev->dev; + /* * Tear down is carefully orchestrated to ensure * no interrupts can come in when the problem state @@ -600,7 +653,7 @@ static void term_afu(struct cxlflash_cfg *cfg) term_mc(cfg); - pr_debug("%s: returning\n", __func__); + dev_dbg(dev, "%s: returning\n", __func__); } /** @@ -627,8 +680,7 @@ static void notify_shutdown(struct cxlflash_cfg *cfg, bool wait) return; if (!afu || !afu->afu_map) { - dev_dbg(dev, "%s: The problem state area is not mapped\n", - __func__); + dev_dbg(dev, "%s: Problem state area not mapped\n", __func__); return; } @@ -670,10 +722,11 @@ static void notify_shutdown(struct cxlflash_cfg *cfg, bool wait) static void cxlflash_remove(struct pci_dev *pdev) { struct cxlflash_cfg *cfg = pci_get_drvdata(pdev); + struct device *dev = &pdev->dev; ulong lock_flags; if (!pci_is_enabled(pdev)) { - pr_debug("%s: Device is disabled\n", __func__); + dev_dbg(dev, "%s: Device is disabled\n", __func__); return; } @@ -699,7 +752,6 @@ static void cxlflash_remove(struct pci_dev *pdev) scsi_remove_host(cfg->host); /* fall through */ case INIT_STATE_AFU: - cancel_work_sync(&cfg->work_q); term_afu(cfg); case INIT_STATE_PCI: pci_disable_device(pdev); @@ -709,7 +761,7 @@ static void cxlflash_remove(struct pci_dev *pdev) break; } - pr_debug("%s: returning\n", __func__); + dev_dbg(dev, "%s: returning\n", __func__); } /** @@ -727,7 +779,7 @@ static int alloc_mem(struct cxlflash_cfg *cfg) int rc = 0; struct device *dev = &cfg->dev->dev; - /* AFU is ~12k, i.e. only one 64k page or up to four 4k pages */ + /* AFU is ~28k, i.e. only one 64k page or up to seven 4k pages */ cfg->afu = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, get_order(sizeof(struct afu))); if (unlikely(!cfg->afu)) { @@ -751,6 +803,7 @@ out: static int init_pci(struct cxlflash_cfg *cfg) { struct pci_dev *pdev = cfg->dev; + struct device *dev = &cfg->dev->dev; int rc = 0; rc = pci_enable_device(pdev); @@ -761,15 +814,14 @@ static int init_pci(struct cxlflash_cfg *cfg) } if (rc) { - dev_err(&pdev->dev, "%s: Cannot enable adapter\n", - __func__); + dev_err(dev, "%s: Cannot enable adapter\n", __func__); cxlflash_wait_for_pci_err_recovery(cfg); goto out; } } out: - pr_debug("%s: returning rc=%d\n", __func__, rc); + dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); return rc; } @@ -782,19 +834,19 @@ out: static int init_scsi(struct cxlflash_cfg *cfg) { struct pci_dev *pdev = cfg->dev; + struct device *dev = &cfg->dev->dev; int rc = 0; rc = scsi_add_host(cfg->host, &pdev->dev); if (rc) { - dev_err(&pdev->dev, "%s: scsi_add_host failed (rc=%d)\n", - __func__, rc); + dev_err(dev, "%s: scsi_add_host failed rc=%d\n", __func__, rc); goto out; } scsi_scan_host(cfg->host); out: - pr_debug("%s: returning rc=%d\n", __func__, rc); + dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); return rc; } @@ -844,16 +896,12 @@ static void set_port_offline(__be64 __iomem *fc_regs) * Return: * TRUE (1) when the specified port is online * FALSE (0) when the specified port fails to come online after timeout - * -EINVAL when @delay_us is less than 1000 */ -static int wait_port_online(__be64 __iomem *fc_regs, u32 delay_us, u32 nretry) +static bool wait_port_online(__be64 __iomem *fc_regs, u32 delay_us, u32 nretry) { u64 status; - if (delay_us < 1000) { - pr_err("%s: invalid delay specified %d\n", __func__, delay_us); - return -EINVAL; - } + WARN_ON(delay_us < 1000); do { msleep(delay_us / 1000); @@ -877,16 +925,12 @@ static int wait_port_online(__be64 __iomem *fc_regs, u32 delay_us, u32 nretry) * Return: * TRUE (1) when the specified port is offline * FALSE (0) when the specified port fails to go offline after timeout - * -EINVAL when @delay_us is less than 1000 */ -static int wait_port_offline(__be64 __iomem *fc_regs, u32 delay_us, u32 nretry) +static bool wait_port_offline(__be64 __iomem *fc_regs, u32 delay_us, u32 nretry) { u64 status; - if (delay_us < 1000) { - pr_err("%s: invalid delay specified %d\n", __func__, delay_us); - return -EINVAL; - } + WARN_ON(delay_us < 1000); do { msleep(delay_us / 1000); @@ -915,11 +959,14 @@ static int wait_port_offline(__be64 __iomem *fc_regs, u32 delay_us, u32 nretry) static void afu_set_wwpn(struct afu *afu, int port, __be64 __iomem *fc_regs, u64 wwpn) { + struct cxlflash_cfg *cfg = afu->parent; + struct device *dev = &cfg->dev->dev; + set_port_offline(fc_regs); if (!wait_port_offline(fc_regs, FC_PORT_STATUS_RETRY_INTERVAL_US, FC_PORT_STATUS_RETRY_CNT)) { - pr_debug("%s: wait on port %d to go offline timed out\n", - __func__, port); + dev_dbg(dev, "%s: wait on port %d to go offline timed out\n", + __func__, port); } writeq_be(wwpn, &fc_regs[FC_PNAME / 8]); @@ -927,8 +974,8 @@ static void afu_set_wwpn(struct afu *afu, int port, __be64 __iomem *fc_regs, set_port_online(fc_regs); if (!wait_port_online(fc_regs, FC_PORT_STATUS_RETRY_INTERVAL_US, FC_PORT_STATUS_RETRY_CNT)) { - pr_debug("%s: wait on port %d to go online timed out\n", - __func__, port); + dev_dbg(dev, "%s: wait on port %d to go online timed out\n", + __func__, port); } } @@ -947,6 +994,8 @@ static void afu_set_wwpn(struct afu *afu, int port, __be64 __iomem *fc_regs, */ static void afu_link_reset(struct afu *afu, int port, __be64 __iomem *fc_regs) { + struct cxlflash_cfg *cfg = afu->parent; + struct device *dev = &cfg->dev->dev; u64 port_sel; /* first switch the AFU to the other links, if any */ @@ -958,21 +1007,21 @@ static void afu_link_reset(struct afu *afu, int port, __be64 __iomem *fc_regs) set_port_offline(fc_regs); if (!wait_port_offline(fc_regs, FC_PORT_STATUS_RETRY_INTERVAL_US, FC_PORT_STATUS_RETRY_CNT)) - pr_err("%s: wait on port %d to go offline timed out\n", - __func__, port); + dev_err(dev, "%s: wait on port %d to go offline timed out\n", + __func__, port); set_port_online(fc_regs); if (!wait_port_online(fc_regs, FC_PORT_STATUS_RETRY_INTERVAL_US, FC_PORT_STATUS_RETRY_CNT)) - pr_err("%s: wait on port %d to go online timed out\n", - __func__, port); + dev_err(dev, "%s: wait on port %d to go online timed out\n", + __func__, port); /* switch back to include this port */ port_sel |= (1ULL << port); writeq_be(port_sel, &afu->afu_map->global.regs.afu_port_sel); cxlflash_afu_sync(afu, 0, 0, AFU_GSYNC); - pr_debug("%s: returning port_sel=%lld\n", __func__, port_sel); + dev_dbg(dev, "%s: returning port_sel=%016llx\n", __func__, port_sel); } /* @@ -1082,6 +1131,8 @@ 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 device *dev = &cfg->dev->dev; u64 reg; u64 reg_unmasked; @@ -1089,18 +1140,17 @@ static irqreturn_t cxlflash_sync_err_irq(int irq, void *data) reg_unmasked = (reg & SISL_ISTATUS_UNMASK); if (reg_unmasked == 0UL) { - pr_err("%s: %llX: spurious interrupt, intr_status %016llX\n", - __func__, (u64)afu, reg); + dev_err(dev, "%s: spurious interrupt, intr_status=%016llx\n", + __func__, reg); goto cxlflash_sync_err_irq_exit; } - pr_err("%s: %llX: unexpected interrupt, intr_status %016llX\n", - __func__, (u64)afu, reg); + dev_err(dev, "%s: unexpected interrupt, intr_status=%016llx\n", + __func__, reg); writeq_be(reg_unmasked, &afu->host_map->intr_clear); cxlflash_sync_err_irq_exit: - pr_debug("%s: returning rc=%d\n", __func__, IRQ_HANDLED); return IRQ_HANDLED; } @@ -1115,6 +1165,8 @@ static irqreturn_t cxlflash_rrq_irq(int irq, void *data) { struct afu *afu = (struct afu *)data; struct afu_cmd *cmd; + struct sisl_ioasa *ioasa; + struct sisl_ioarcb *ioarcb; bool toggle = afu->toggle; u64 entry, *hrrq_start = afu->hrrq_start, @@ -1128,7 +1180,16 @@ static irqreturn_t cxlflash_rrq_irq(int irq, void *data) if ((entry & SISL_RESP_HANDLE_T_BIT) != toggle) break; - cmd = (struct afu_cmd *)(entry & ~SISL_RESP_HANDLE_T_BIT); + entry &= ~SISL_RESP_HANDLE_T_BIT; + + if (afu_is_sq_cmd_mode(afu)) { + ioasa = (struct sisl_ioasa *)entry; + cmd = container_of(ioasa, struct afu_cmd, sa); + } else { + ioarcb = (struct sisl_ioarcb *)entry; + cmd = container_of(ioarcb, struct afu_cmd, rcb); + } + cmd_complete(cmd); /* Advance to next entry or wrap and flip the toggle bit */ @@ -1138,6 +1199,8 @@ static irqreturn_t cxlflash_rrq_irq(int irq, void *data) hrrq_curr = hrrq_start; toggle ^= SISL_RESP_HANDLE_T_BIT; } + + atomic_inc(&afu->hsq_credits); } afu->hrrq_curr = hrrq_curr; @@ -1169,7 +1232,7 @@ static irqreturn_t cxlflash_async_err_irq(int irq, void *data) reg_unmasked = (reg & SISL_ASTATUS_UNMASK); if (reg_unmasked == 0) { - dev_err(dev, "%s: spurious interrupt, aintr_status 0x%016llX\n", + dev_err(dev, "%s: spurious interrupt, aintr_status=%016llx\n", __func__, reg); goto out; } @@ -1185,7 +1248,7 @@ static irqreturn_t cxlflash_async_err_irq(int irq, void *data) port = info->port; - dev_err(dev, "%s: FC Port %d -> %s, fc_status 0x%08llX\n", + 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])); @@ -1198,7 +1261,6 @@ static irqreturn_t cxlflash_async_err_irq(int irq, void *data) __func__, port); cfg->lr_state = LINK_RESET_REQUIRED; cfg->lr_port = port; - kref_get(&cfg->afu->mapcount); schedule_work(&cfg->work_q); } @@ -1210,7 +1272,7 @@ static irqreturn_t cxlflash_async_err_irq(int irq, void *data) * should be the same and tracing one is sufficient. */ - dev_err(dev, "%s: fc %d: clearing fc_error 0x%08llX\n", + dev_err(dev, "%s: fc %d: clearing fc_error=%016llx\n", __func__, port, reg); writeq_be(reg, &global->fc_regs[port][FC_ERROR / 8]); @@ -1219,13 +1281,11 @@ static irqreturn_t cxlflash_async_err_irq(int irq, void *data) if (info->action & SCAN_HOST) { atomic_inc(&cfg->scan_host_needed); - kref_get(&cfg->afu->mapcount); schedule_work(&cfg->work_q); } } out: - dev_dbg(dev, "%s: returning IRQ_HANDLED, afu=%p\n", __func__, afu); return IRQ_HANDLED; } @@ -1237,13 +1297,14 @@ out: */ static int start_context(struct cxlflash_cfg *cfg) { + struct device *dev = &cfg->dev->dev; int rc = 0; rc = cxl_start_context(cfg->mcctx, cfg->afu->work.work_element_descriptor, NULL); - pr_debug("%s: returning rc=%d\n", __func__, rc); + dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); return rc; } @@ -1256,7 +1317,8 @@ static int start_context(struct cxlflash_cfg *cfg) */ static int read_vpd(struct cxlflash_cfg *cfg, u64 wwpn[]) { - struct pci_dev *dev = cfg->dev; + struct device *dev = &cfg->dev->dev; + struct pci_dev *pdev = cfg->dev; int rc = 0; int ro_start, ro_size, i, j, k; ssize_t vpd_size; @@ -1265,10 +1327,10 @@ static int read_vpd(struct cxlflash_cfg *cfg, u64 wwpn[]) char *wwpn_vpd_tags[NUM_FC_PORTS] = { "V5", "V6" }; /* Get the VPD data from the device */ - vpd_size = cxl_read_adapter_vpd(dev, vpd_data, sizeof(vpd_data)); + vpd_size = cxl_read_adapter_vpd(pdev, vpd_data, sizeof(vpd_data)); if (unlikely(vpd_size <= 0)) { - dev_err(&dev->dev, "%s: Unable to read VPD (size = %ld)\n", - __func__, vpd_size); + dev_err(dev, "%s: Unable to read VPD (size = %ld)\n", + __func__, vpd_size); rc = -ENODEV; goto out; } @@ -1277,8 +1339,7 @@ static int read_vpd(struct cxlflash_cfg *cfg, u64 wwpn[]) ro_start = pci_vpd_find_tag(vpd_data, 0, vpd_size, PCI_VPD_LRDT_RO_DATA); if (unlikely(ro_start < 0)) { - dev_err(&dev->dev, "%s: VPD Read-only data not found\n", - __func__); + dev_err(dev, "%s: VPD Read-only data not found\n", __func__); rc = -ENODEV; goto out; } @@ -1288,8 +1349,8 @@ static int read_vpd(struct cxlflash_cfg *cfg, u64 wwpn[]) j = ro_size; i = ro_start + PCI_VPD_LRDT_TAG_SIZE; if (unlikely((i + j) > vpd_size)) { - pr_debug("%s: Might need to read more VPD (%d > %ld)\n", - __func__, (i + j), vpd_size); + dev_dbg(dev, "%s: Might need to read more VPD (%d > %ld)\n", + __func__, (i + j), vpd_size); ro_size = vpd_size - i; } @@ -1307,8 +1368,8 @@ static int read_vpd(struct cxlflash_cfg *cfg, u64 wwpn[]) i = pci_vpd_find_info_keyword(vpd_data, i, j, wwpn_vpd_tags[k]); if (unlikely(i < 0)) { - dev_err(&dev->dev, "%s: Port %d WWPN not found " - "in VPD\n", __func__, k); + dev_err(dev, "%s: Port %d WWPN not found in VPD\n", + __func__, k); rc = -ENODEV; goto out; } @@ -1316,9 +1377,8 @@ static int read_vpd(struct cxlflash_cfg *cfg, u64 wwpn[]) j = pci_vpd_info_field_size(&vpd_data[i]); i += PCI_VPD_INFO_FLD_HDR_SIZE; if (unlikely((i + j > vpd_size) || (j != WWPN_LEN))) { - dev_err(&dev->dev, "%s: Port %d WWPN incomplete or " - "VPD corrupt\n", - __func__, k); + dev_err(dev, "%s: Port %d WWPN incomplete or bad VPD\n", + __func__, k); rc = -ENODEV; goto out; } @@ -1326,15 +1386,15 @@ static int read_vpd(struct cxlflash_cfg *cfg, u64 wwpn[]) memcpy(tmp_buf, &vpd_data[i], WWPN_LEN); rc = kstrtoul(tmp_buf, WWPN_LEN, (ulong *)&wwpn[k]); if (unlikely(rc)) { - dev_err(&dev->dev, "%s: Fail to convert port %d WWPN " - "to integer\n", __func__, k); + dev_err(dev, "%s: WWPN conversion failed for port %d\n", + __func__, k); rc = -ENODEV; goto out; } } out: - pr_debug("%s: returning rc=%d\n", __func__, rc); + dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); return rc; } @@ -1388,12 +1448,18 @@ static int init_global(struct cxlflash_cfg *cfg) goto out; } - pr_debug("%s: wwpn0=0x%llX wwpn1=0x%llX\n", __func__, wwpn[0], wwpn[1]); + dev_dbg(dev, "%s: wwpn0=%016llx wwpn1=%016llx\n", + __func__, wwpn[0], wwpn[1]); - /* Set up RRQ in AFU for master issued cmds */ + /* 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); + 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); + } + /* AFU configuration */ reg = readq_be(&afu->afu_map->global.regs.afu_config); reg |= SISL_AFUCONF_AR_ALL|SISL_AFUCONF_ENDIAN; @@ -1443,7 +1509,6 @@ static int init_global(struct cxlflash_cfg *cfg) &afu->ctrl_map->ctx_cap); /* Initialize heartbeat */ afu->hb = readq_be(&afu->afu_map->global.regs.afu_hb); - out: return rc; } @@ -1455,6 +1520,7 @@ out: static int start_afu(struct cxlflash_cfg *cfg) { struct afu *afu = cfg->afu; + struct device *dev = &cfg->dev->dev; int rc = 0; init_pcr(cfg); @@ -1468,9 +1534,20 @@ static int start_afu(struct cxlflash_cfg *cfg) afu->hrrq_curr = afu->hrrq_start; afu->toggle = 1; + /* 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; + + spin_lock_init(&afu->hsq_slock); + atomic_set(&afu->hsq_credits, NUM_SQ_ENTRY - 1); + } + rc = init_global(cfg); - pr_debug("%s: returning rc=%d\n", __func__, rc); + dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); return rc; } @@ -1490,7 +1567,7 @@ static enum undo_level init_intr(struct cxlflash_cfg *cfg, rc = cxl_allocate_afu_irqs(ctx, 3); if (unlikely(rc)) { - dev_err(dev, "%s: call to allocate_afu_irqs failed rc=%d!\n", + dev_err(dev, "%s: allocate_afu_irqs failed rc=%d\n", __func__, rc); level = UNDO_NOOP; goto out; @@ -1499,8 +1576,7 @@ static enum undo_level init_intr(struct cxlflash_cfg *cfg, rc = cxl_map_afu_irq(ctx, 1, cxlflash_sync_err_irq, afu, "SISL_MSI_SYNC_ERROR"); if (unlikely(rc <= 0)) { - dev_err(dev, "%s: IRQ 1 (SISL_MSI_SYNC_ERROR) map failed!\n", - __func__); + dev_err(dev, "%s: SISL_MSI_SYNC_ERROR map failed\n", __func__); level = FREE_IRQ; goto out; } @@ -1508,8 +1584,7 @@ static enum undo_level init_intr(struct cxlflash_cfg *cfg, rc = cxl_map_afu_irq(ctx, 2, cxlflash_rrq_irq, afu, "SISL_MSI_RRQ_UPDATED"); if (unlikely(rc <= 0)) { - dev_err(dev, "%s: IRQ 2 (SISL_MSI_RRQ_UPDATED) map failed!\n", - __func__); + dev_err(dev, "%s: SISL_MSI_RRQ_UPDATED map failed\n", __func__); level = UNMAP_ONE; goto out; } @@ -1517,8 +1592,7 @@ static enum undo_level init_intr(struct cxlflash_cfg *cfg, rc = cxl_map_afu_irq(ctx, 3, cxlflash_async_err_irq, afu, "SISL_MSI_ASYNC_ERROR"); if (unlikely(rc <= 0)) { - dev_err(dev, "%s: IRQ 3 (SISL_MSI_ASYNC_ERROR) map failed!\n", - __func__); + dev_err(dev, "%s: SISL_MSI_ASYNC_ERROR map failed\n", __func__); level = UNMAP_TWO; goto out; } @@ -1552,15 +1626,13 @@ static int init_mc(struct cxlflash_cfg *cfg) /* During initialization reset the AFU to start from a clean slate */ rc = cxl_afu_reset(cfg->mcctx); if (unlikely(rc)) { - dev_err(dev, "%s: initial AFU reset failed rc=%d\n", - __func__, rc); + dev_err(dev, "%s: AFU reset failed rc=%d\n", __func__, rc); goto ret; } level = init_intr(cfg, ctx); if (unlikely(level)) { - dev_err(dev, "%s: setting up interrupts failed rc=%d\n", - __func__, rc); + dev_err(dev, "%s: interrupt init failed rc=%d\n", __func__, rc); goto out; } @@ -1575,7 +1647,7 @@ static int init_mc(struct cxlflash_cfg *cfg) goto out; } ret: - pr_debug("%s: returning rc=%d\n", __func__, rc); + dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); return rc; out: term_intr(cfg, level); @@ -1602,7 +1674,7 @@ static int init_afu(struct cxlflash_cfg *cfg) rc = init_mc(cfg); if (rc) { - dev_err(dev, "%s: call to init_mc failed, rc=%d!\n", + dev_err(dev, "%s: init_mc failed rc=%d\n", __func__, rc); goto out; } @@ -1610,11 +1682,10 @@ static int init_afu(struct cxlflash_cfg *cfg) /* Map the entire MMIO space of the AFU */ afu->afu_map = cxl_psa_map(cfg->mcctx); if (!afu->afu_map) { - dev_err(dev, "%s: call to cxl_psa_map failed!\n", __func__); + dev_err(dev, "%s: cxl_psa_map failed\n", __func__); rc = -ENOMEM; goto err1; } - kref_init(&afu->mapcount); /* No byte reverse on reading afu_version or string will be backwards */ reg = readq(&afu->afu_map->global.regs.afu_version); @@ -1622,24 +1693,28 @@ static int init_afu(struct cxlflash_cfg *cfg) afu->interface_version = readq_be(&afu->afu_map->global.regs.interface_version); if ((afu->interface_version + 1) == 0) { - pr_err("Back level AFU, please upgrade. AFU version %s " - "interface version 0x%llx\n", afu->version, + dev_err(dev, "Back level AFU, please upgrade. AFU version %s " + "interface version %016llx\n", afu->version, afu->interface_version); rc = -EINVAL; - goto err2; + goto err1; } - afu->send_cmd = send_cmd_ioarrin; - afu->context_reset = context_reset_ioarrin; + if (afu_is_sq_cmd_mode(afu)) { + afu->send_cmd = send_cmd_sq; + afu->context_reset = context_reset_sq; + } else { + afu->send_cmd = send_cmd_ioarrin; + afu->context_reset = context_reset_ioarrin; + } - pr_debug("%s: afu version %s, interface version 0x%llX\n", __func__, - afu->version, afu->interface_version); + dev_dbg(dev, "%s: afu_ver=%s interface_ver=%016llx\n", __func__, + afu->version, afu->interface_version); rc = start_afu(cfg); if (rc) { - dev_err(dev, "%s: call to start_afu failed, rc=%d!\n", - __func__, rc); - goto err2; + dev_err(dev, "%s: start_afu failed, rc=%d\n", __func__, rc); + goto err1; } afu_err_intr_init(cfg->afu); @@ -1649,11 +1724,9 @@ static int init_afu(struct cxlflash_cfg *cfg) /* Restore the LUN mappings */ cxlflash_restore_luntable(cfg); out: - pr_debug("%s: returning rc=%d\n", __func__, rc); + dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); return rc; -err2: - kref_put(&afu->mapcount, afu_unmap); err1: term_intr(cfg, UNMAP_THREE); term_mc(cfg); @@ -1693,7 +1766,8 @@ int cxlflash_afu_sync(struct afu *afu, ctx_hndl_t ctx_hndl_u, static DEFINE_MUTEX(sync_active); if (cfg->state != STATE_NORMAL) { - pr_debug("%s: Sync not required! (%u)\n", __func__, cfg->state); + dev_dbg(dev, "%s: Sync not required state=%u\n", + __func__, cfg->state); return 0; } @@ -1710,7 +1784,7 @@ int cxlflash_afu_sync(struct afu *afu, ctx_hndl_t ctx_hndl_u, init_completion(&cmd->cevent); cmd->parent = afu; - pr_debug("%s: afu=%p cmd=%p %d\n", __func__, afu, cmd, ctx_hndl_u); + 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; @@ -1735,7 +1809,7 @@ out: atomic_dec(&afu->cmds_active); mutex_unlock(&sync_active); kfree(buf); - pr_debug("%s: returning rc=%d\n", __func__, rc); + dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); return rc; } @@ -1747,16 +1821,17 @@ out: */ static int afu_reset(struct cxlflash_cfg *cfg) { + struct device *dev = &cfg->dev->dev; int rc = 0; + /* Stop the context before the reset. Since the context is * no longer available restart it after the reset is complete */ - term_afu(cfg); rc = init_afu(cfg); - pr_debug("%s: returning rc=%d\n", __func__, rc); + dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); return rc; } @@ -1785,18 +1860,18 @@ static int cxlflash_eh_device_reset_handler(struct scsi_cmnd *scp) { int rc = SUCCESS; struct Scsi_Host *host = scp->device->host; - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)host->hostdata; + struct cxlflash_cfg *cfg = shost_priv(host); + struct device *dev = &cfg->dev->dev; struct afu *afu = cfg->afu; int rcr = 0; - pr_debug("%s: (scp=%p) %d/%d/%d/%llu " - "cdb=(%08X-%08X-%08X-%08X)\n", __func__, scp, - host->host_no, scp->device->channel, - scp->device->id, scp->device->lun, - get_unaligned_be32(&((u32 *)scp->cmnd)[0]), - get_unaligned_be32(&((u32 *)scp->cmnd)[1]), - get_unaligned_be32(&((u32 *)scp->cmnd)[2]), - get_unaligned_be32(&((u32 *)scp->cmnd)[3])); + dev_dbg(dev, "%s: (scp=%p) %d/%d/%d/%llu " + "cdb=(%08x-%08x-%08x-%08x)\n", __func__, scp, host->host_no, + scp->device->channel, scp->device->id, scp->device->lun, + get_unaligned_be32(&((u32 *)scp->cmnd)[0]), + get_unaligned_be32(&((u32 *)scp->cmnd)[1]), + get_unaligned_be32(&((u32 *)scp->cmnd)[2]), + get_unaligned_be32(&((u32 *)scp->cmnd)[3])); retry: switch (cfg->state) { @@ -1813,7 +1888,7 @@ retry: break; } - pr_debug("%s: returning rc=%d\n", __func__, rc); + dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); return rc; } @@ -1835,16 +1910,16 @@ static int cxlflash_eh_host_reset_handler(struct scsi_cmnd *scp) int rc = SUCCESS; int rcr = 0; struct Scsi_Host *host = scp->device->host; - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)host->hostdata; + struct cxlflash_cfg *cfg = shost_priv(host); + struct device *dev = &cfg->dev->dev; - pr_debug("%s: (scp=%p) %d/%d/%d/%llu " - "cdb=(%08X-%08X-%08X-%08X)\n", __func__, scp, - host->host_no, scp->device->channel, - scp->device->id, scp->device->lun, - get_unaligned_be32(&((u32 *)scp->cmnd)[0]), - get_unaligned_be32(&((u32 *)scp->cmnd)[1]), - get_unaligned_be32(&((u32 *)scp->cmnd)[2]), - get_unaligned_be32(&((u32 *)scp->cmnd)[3])); + dev_dbg(dev, "%s: (scp=%p) %d/%d/%d/%llu " + "cdb=(%08x-%08x-%08x-%08x)\n", __func__, scp, host->host_no, + scp->device->channel, scp->device->id, scp->device->lun, + get_unaligned_be32(&((u32 *)scp->cmnd)[0]), + get_unaligned_be32(&((u32 *)scp->cmnd)[1]), + get_unaligned_be32(&((u32 *)scp->cmnd)[2]), + get_unaligned_be32(&((u32 *)scp->cmnd)[3])); switch (cfg->state) { case STATE_NORMAL: @@ -1870,7 +1945,7 @@ static int cxlflash_eh_host_reset_handler(struct scsi_cmnd *scp) break; } - pr_debug("%s: returning rc=%d\n", __func__, rc); + dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); return rc; } @@ -1936,8 +2011,7 @@ static ssize_t port0_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct Scsi_Host *shost = class_to_shost(dev); - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata; + struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev)); struct afu *afu = cfg->afu; return cxlflash_show_port_status(0, afu, buf); @@ -1955,8 +2029,7 @@ static ssize_t port1_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct Scsi_Host *shost = class_to_shost(dev); - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata; + struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev)); struct afu *afu = cfg->afu; return cxlflash_show_port_status(1, afu, buf); @@ -1973,8 +2046,7 @@ static ssize_t port1_show(struct device *dev, static ssize_t lun_mode_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct Scsi_Host *shost = class_to_shost(dev); - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata; + struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev)); struct afu *afu = cfg->afu; return scnprintf(buf, PAGE_SIZE, "%u\n", afu->internal_lun); @@ -2007,7 +2079,7 @@ static ssize_t lun_mode_store(struct device *dev, const char *buf, size_t count) { struct Scsi_Host *shost = class_to_shost(dev); - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata; + struct cxlflash_cfg *cfg = shost_priv(shost); struct afu *afu = cfg->afu; int rc; u32 lun_mode; @@ -2069,7 +2141,7 @@ static ssize_t cxlflash_show_port_lun_table(u32 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[i])); return bytes; } @@ -2085,8 +2157,7 @@ static ssize_t port0_lun_table_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct Scsi_Host *shost = class_to_shost(dev); - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata; + struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev)); struct afu *afu = cfg->afu; return cxlflash_show_port_lun_table(0, afu, buf); @@ -2104,8 +2175,7 @@ static ssize_t port1_lun_table_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct Scsi_Host *shost = class_to_shost(dev); - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata; + struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev)); struct afu *afu = cfg->afu; return cxlflash_show_port_lun_table(1, afu, buf); @@ -2250,7 +2320,6 @@ static void cxlflash_worker_thread(struct work_struct *work) if (atomic_dec_if_positive(&cfg->scan_host_needed) >= 0) scsi_scan_host(cfg->host); - kref_put(&afu->mapcount, afu_unmap); } /** @@ -2265,6 +2334,7 @@ static int cxlflash_probe(struct pci_dev *pdev, { struct Scsi_Host *host; struct cxlflash_cfg *cfg = NULL; + struct device *dev = &pdev->dev; struct dev_dependent_vals *ddv; int rc = 0; @@ -2276,8 +2346,7 @@ static int cxlflash_probe(struct pci_dev *pdev, host = scsi_host_alloc(&driver_template, sizeof(struct cxlflash_cfg)); if (!host) { - dev_err(&pdev->dev, "%s: call to scsi_host_alloc failed!\n", - __func__); + dev_err(dev, "%s: scsi_host_alloc failed\n", __func__); rc = -ENOMEM; goto out; } @@ -2288,12 +2357,11 @@ static int cxlflash_probe(struct pci_dev *pdev, host->unique_id = host->host_no; host->max_cmd_len = CXLFLASH_MAX_CDB_LEN; - cfg = (struct cxlflash_cfg *)host->hostdata; + cfg = shost_priv(host); cfg->host = host; rc = alloc_mem(cfg); if (rc) { - dev_err(&pdev->dev, "%s: call to alloc_mem failed!\n", - __func__); + dev_err(dev, "%s: alloc_mem failed\n", __func__); rc = -ENOMEM; scsi_host_put(cfg->host); goto out; @@ -2334,30 +2402,27 @@ static int cxlflash_probe(struct pci_dev *pdev, rc = init_pci(cfg); if (rc) { - dev_err(&pdev->dev, "%s: call to init_pci " - "failed rc=%d!\n", __func__, rc); + dev_err(dev, "%s: init_pci failed rc=%d\n", __func__, rc); goto out_remove; } cfg->init_state = INIT_STATE_PCI; rc = init_afu(cfg); if (rc) { - dev_err(&pdev->dev, "%s: call to init_afu " - "failed rc=%d!\n", __func__, rc); + dev_err(dev, "%s: init_afu failed rc=%d\n", __func__, rc); goto out_remove; } cfg->init_state = INIT_STATE_AFU; rc = init_scsi(cfg); if (rc) { - dev_err(&pdev->dev, "%s: call to init_scsi " - "failed rc=%d!\n", __func__, rc); + dev_err(dev, "%s: init_scsi failed rc=%d\n", __func__, rc); goto out_remove; } cfg->init_state = INIT_STATE_SCSI; out: - pr_debug("%s: returning rc=%d\n", __func__, rc); + dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); return rc; out_remove: @@ -2395,7 +2460,7 @@ static pci_ers_result_t cxlflash_pci_error_detected(struct pci_dev *pdev, drain_ioctls(cfg); rc = cxlflash_mark_contexts_error(cfg); if (unlikely(rc)) - dev_err(dev, "%s: Failed to mark user contexts!(%d)\n", + dev_err(dev, "%s: Failed to mark user contexts rc=%d\n", __func__, rc); term_afu(cfg); return PCI_ERS_RESULT_NEED_RESET; @@ -2429,7 +2494,7 @@ static pci_ers_result_t cxlflash_pci_slot_reset(struct pci_dev *pdev) rc = init_afu(cfg); if (unlikely(rc)) { - dev_err(dev, "%s: EEH recovery failed! (%d)\n", __func__, rc); + dev_err(dev, "%s: EEH recovery failed rc=%d\n", __func__, rc); return PCI_ERS_RESULT_DISCONNECT; } @@ -2477,8 +2542,6 @@ static struct pci_driver cxlflash_driver = { */ static int __init init_cxlflash(void) { - pr_info("%s: %s\n", __func__, CXLFLASH_ADAPTER_NAME); - cxlflash_list_init(); return pci_register_driver(&cxlflash_driver); diff --git a/drivers/scsi/cxlflash/sislite.h b/drivers/scsi/cxlflash/sislite.h index 1a2d09c148b3..a6e48a893fef 100644 --- a/drivers/scsi/cxlflash/sislite.h +++ b/drivers/scsi/cxlflash/sislite.h @@ -72,7 +72,10 @@ struct sisl_ioarcb { u16 timeout; /* in units specified by req_flags */ u32 rsvd1; u8 cdb[16]; /* must be in big endian */ - u64 reserved; /* Reserved area */ + union { + u64 reserved; /* Reserved for IOARRIN mode */ + struct sisl_ioasa *ioasa; /* IOASA EA for SQ Mode */ + }; } __packed; struct sisl_rc { @@ -260,6 +263,11 @@ struct sisl_host_map { __be64 cmd_room; __be64 ctx_ctrl; /* least significant byte or b56:63 is LISN# */ __be64 mbox_w; /* restricted use */ + __be64 sq_start; /* Submission Queue (R/W): write sequence and */ + __be64 sq_end; /* inclusion semantics are the same as RRQ */ + __be64 sq_head; /* Submission Queue Head (R): for debugging */ + __be64 sq_tail; /* Submission Queue TAIL (R/W): next IOARCB */ + __be64 sq_ctx_reset; /* Submission Queue Context Reset (R/W) */ }; /* per context provisioning & control MMIO */ @@ -348,6 +356,15 @@ struct sisl_global_regs { __be64 rsvd[0xf8]; __le64 afu_version; __be64 interface_version; +#define SISL_INTVER_CAP_SHIFT 16 +#define SISL_INTVER_MAJ_SHIFT 8 +#define SISL_INTVER_CAP_MASK 0xFFFFFFFF00000000ULL +#define SISL_INTVER_MAJ_MASK 0x00000000FFFF0000ULL +#define SISL_INTVER_MIN_MASK 0x000000000000FFFFULL +#define SISL_INTVER_CAP_IOARRIN_CMD_MODE 0x800000000000ULL +#define SISL_INTVER_CAP_SQ_CMD_MODE 0x400000000000ULL +#define SISL_INTVER_CAP_RESERVED_CMD_MODE_A 0x200000000000ULL +#define SISL_INTVER_CAP_RESERVED_CMD_MODE_B 0x100000000000ULL }; #define CXLFLASH_NUM_FC_PORTS 2 diff --git a/drivers/scsi/cxlflash/superpipe.c b/drivers/scsi/cxlflash/superpipe.c index 9636970d9611..90869cee2b20 100644 --- a/drivers/scsi/cxlflash/superpipe.c +++ b/drivers/scsi/cxlflash/superpipe.c @@ -212,7 +212,7 @@ struct ctx_info *get_context(struct cxlflash_cfg *cfg, u64 rctxid, } out: - dev_dbg(dev, "%s: rctxid=%016llX ctxinfo=%p ctxpid=%u pid=%u " + dev_dbg(dev, "%s: rctxid=%016llx ctxinfo=%p ctxpid=%u pid=%u " "ctx_ctrl=%u\n", __func__, rctxid, ctxi, ctxpid, pid, ctx_ctrl); @@ -260,7 +260,7 @@ static int afu_attach(struct cxlflash_cfg *cfg, struct ctx_info *ctxi) writeq_be(val, &ctrl_map->ctx_cap); val = readq_be(&ctrl_map->ctx_cap); if (val != (SISL_CTX_CAP_READ_CMD | SISL_CTX_CAP_WRITE_CMD)) { - dev_err(dev, "%s: ctx may be closed val=%016llX\n", + dev_err(dev, "%s: ctx may be closed val=%016llx\n", __func__, val); rc = -EAGAIN; goto out; @@ -302,7 +302,7 @@ out: */ static int read_cap16(struct scsi_device *sdev, struct llun_info *lli) { - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct cxlflash_cfg *cfg = shost_priv(sdev->host); struct device *dev = &cfg->dev->dev; struct glun_info *gli = lli->parent; u8 *cmd_buf = NULL; @@ -326,7 +326,7 @@ retry: scsi_cmd[1] = SAI_READ_CAPACITY_16; /* service action */ put_unaligned_be32(CMD_BUFSIZE, &scsi_cmd[10]); - dev_dbg(dev, "%s: %ssending cmd(0x%x)\n", __func__, + dev_dbg(dev, "%s: %ssending cmd(%02x)\n", __func__, retry_cnt ? "re" : "", scsi_cmd[0]); /* Drop the ioctl read semahpore across lengthy call */ @@ -336,7 +336,7 @@ retry: down_read(&cfg->ioctl_rwsem); rc = check_state(cfg); if (rc) { - dev_err(dev, "%s: Failed state! result=0x08%X\n", + dev_err(dev, "%s: Failed state result=%08x\n", __func__, result); rc = -ENODEV; goto out; @@ -378,7 +378,7 @@ retry: } if (result) { - dev_err(dev, "%s: command failed, result=0x%x\n", + dev_err(dev, "%s: command failed, result=%08x\n", __func__, result); rc = -EIO; goto out; @@ -415,29 +415,32 @@ out: struct sisl_rht_entry *get_rhte(struct ctx_info *ctxi, res_hndl_t rhndl, struct llun_info *lli) { + struct cxlflash_cfg *cfg = ctxi->cfg; + struct device *dev = &cfg->dev->dev; struct sisl_rht_entry *rhte = NULL; if (unlikely(!ctxi->rht_start)) { - pr_debug("%s: Context does not have allocated RHT!\n", + dev_dbg(dev, "%s: Context does not have allocated RHT\n", __func__); goto out; } if (unlikely(rhndl >= MAX_RHT_PER_CONTEXT)) { - pr_debug("%s: Bad resource handle! (%d)\n", __func__, rhndl); + dev_dbg(dev, "%s: Bad resource handle rhndl=%d\n", + __func__, rhndl); goto out; } if (unlikely(ctxi->rht_lun[rhndl] != lli)) { - pr_debug("%s: Bad resource handle LUN! (%d)\n", - __func__, rhndl); + dev_dbg(dev, "%s: Bad resource handle LUN rhndl=%d\n", + __func__, rhndl); goto out; } rhte = &ctxi->rht_start[rhndl]; if (unlikely(rhte->nmask == 0)) { - pr_debug("%s: Unopened resource handle! (%d)\n", - __func__, rhndl); + dev_dbg(dev, "%s: Unopened resource handle rhndl=%d\n", + __func__, rhndl); rhte = NULL; goto out; } @@ -456,6 +459,8 @@ out: struct sisl_rht_entry *rhte_checkout(struct ctx_info *ctxi, struct llun_info *lli) { + struct cxlflash_cfg *cfg = ctxi->cfg; + struct device *dev = &cfg->dev->dev; struct sisl_rht_entry *rhte = NULL; int i; @@ -470,7 +475,7 @@ struct sisl_rht_entry *rhte_checkout(struct ctx_info *ctxi, if (likely(rhte)) ctxi->rht_lun[i] = lli; - pr_debug("%s: returning rhte=%p (%d)\n", __func__, rhte, i); + dev_dbg(dev, "%s: returning rhte=%p index=%d\n", __func__, rhte, i); return rhte; } @@ -547,7 +552,7 @@ int cxlflash_lun_attach(struct glun_info *gli, enum lun_mode mode, bool locked) if (gli->mode == MODE_NONE) gli->mode = mode; else if (gli->mode != mode) { - pr_debug("%s: LUN operating in mode %d, requested mode %d\n", + pr_debug("%s: gli_mode=%d requested_mode=%d\n", __func__, gli->mode, mode); rc = -EINVAL; goto out; @@ -605,7 +610,7 @@ int _cxlflash_disk_release(struct scsi_device *sdev, struct ctx_info *ctxi, struct dk_cxlflash_release *release) { - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct cxlflash_cfg *cfg = shost_priv(sdev->host); struct device *dev = &cfg->dev->dev; struct llun_info *lli = sdev->hostdata; struct glun_info *gli = lli->parent; @@ -622,13 +627,13 @@ int _cxlflash_disk_release(struct scsi_device *sdev, struct sisl_rht_entry *rhte; struct sisl_rht_entry_f1 *rhte_f1; - dev_dbg(dev, "%s: ctxid=%llu rhndl=0x%llx gli->mode=%u gli->users=%u\n", + dev_dbg(dev, "%s: ctxid=%llu rhndl=%llu gli->mode=%u gli->users=%u\n", __func__, ctxid, release->rsrc_handle, gli->mode, gli->users); if (!ctxi) { ctxi = get_context(cfg, rctxid, lli, CTX_CTRL_ERR_FALLBACK); if (unlikely(!ctxi)) { - dev_dbg(dev, "%s: Bad context! (%llu)\n", + dev_dbg(dev, "%s: Bad context ctxid=%llu\n", __func__, ctxid); rc = -EINVAL; goto out; @@ -639,7 +644,7 @@ int _cxlflash_disk_release(struct scsi_device *sdev, rhte = get_rhte(ctxi, rhndl, lli); if (unlikely(!rhte)) { - dev_dbg(dev, "%s: Bad resource handle! (%d)\n", + dev_dbg(dev, "%s: Bad resource handle rhndl=%d\n", __func__, rhndl); rc = -EINVAL; goto out; @@ -758,13 +763,13 @@ static struct ctx_info *create_context(struct cxlflash_cfg *cfg) lli = kzalloc((MAX_RHT_PER_CONTEXT * sizeof(*lli)), GFP_KERNEL); ws = kzalloc((MAX_RHT_PER_CONTEXT * sizeof(*ws)), GFP_KERNEL); if (unlikely(!ctxi || !lli || !ws)) { - dev_err(dev, "%s: Unable to allocate context!\n", __func__); + dev_err(dev, "%s: Unable to allocate context\n", __func__); goto err; } rhte = (struct sisl_rht_entry *)get_zeroed_page(GFP_KERNEL); if (unlikely(!rhte)) { - dev_err(dev, "%s: Unable to allocate RHT!\n", __func__); + dev_err(dev, "%s: Unable to allocate RHT\n", __func__); goto err; } @@ -858,7 +863,7 @@ static int _cxlflash_disk_detach(struct scsi_device *sdev, struct ctx_info *ctxi, struct dk_cxlflash_detach *detach) { - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct cxlflash_cfg *cfg = shost_priv(sdev->host); struct device *dev = &cfg->dev->dev; struct llun_info *lli = sdev->hostdata; struct lun_access *lun_access, *t; @@ -875,7 +880,7 @@ static int _cxlflash_disk_detach(struct scsi_device *sdev, if (!ctxi) { ctxi = get_context(cfg, rctxid, lli, CTX_CTRL_ERR_FALLBACK); if (unlikely(!ctxi)) { - dev_dbg(dev, "%s: Bad context! (%llu)\n", + dev_dbg(dev, "%s: Bad context ctxid=%llu\n", __func__, ctxid); rc = -EINVAL; goto out; @@ -964,7 +969,7 @@ static int cxlflash_cxl_release(struct inode *inode, struct file *file) ctxid = cxl_process_element(ctx); if (unlikely(ctxid < 0)) { - dev_err(dev, "%s: Context %p was closed! (%d)\n", + dev_err(dev, "%s: Context %p was closed ctxid=%d\n", __func__, ctx, ctxid); goto out; } @@ -973,18 +978,18 @@ static int cxlflash_cxl_release(struct inode *inode, struct file *file) if (unlikely(!ctxi)) { ctxi = get_context(cfg, ctxid, file, ctrl | CTX_CTRL_CLONE); if (!ctxi) { - dev_dbg(dev, "%s: Context %d already free!\n", + dev_dbg(dev, "%s: ctxid=%d already free\n", __func__, ctxid); goto out_release; } - dev_dbg(dev, "%s: Another process owns context %d!\n", + dev_dbg(dev, "%s: Another process owns ctxid=%d\n", __func__, ctxid); put_context(ctxi); goto out; } - dev_dbg(dev, "%s: close for context %d\n", __func__, ctxid); + dev_dbg(dev, "%s: close for ctxid=%d\n", __func__, ctxid); detach.context_id = ctxi->ctxid; list_for_each_entry_safe(lun_access, t, &ctxi->luns, list) @@ -1011,17 +1016,20 @@ static void unmap_context(struct ctx_info *ctxi) /** * get_err_page() - obtains and allocates the error notification page + * @cfg: Internal structure associated with the host. * * Return: error notification page on success, NULL on failure */ -static struct page *get_err_page(void) +static struct page *get_err_page(struct cxlflash_cfg *cfg) { struct page *err_page = global.err_page; + struct device *dev = &cfg->dev->dev; if (unlikely(!err_page)) { err_page = alloc_page(GFP_KERNEL); if (unlikely(!err_page)) { - pr_err("%s: Unable to allocate err_page!\n", __func__); + dev_err(dev, "%s: Unable to allocate err_page\n", + __func__); goto out; } @@ -1039,7 +1047,7 @@ static struct page *get_err_page(void) } out: - pr_debug("%s: returning err_page=%p\n", __func__, err_page); + dev_dbg(dev, "%s: returning err_page=%p\n", __func__, err_page); return err_page; } @@ -1074,14 +1082,14 @@ static int cxlflash_mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) ctxid = cxl_process_element(ctx); if (unlikely(ctxid < 0)) { - dev_err(dev, "%s: Context %p was closed! (%d)\n", + dev_err(dev, "%s: Context %p was closed ctxid=%d\n", __func__, ctx, ctxid); goto err; } ctxi = get_context(cfg, ctxid, file, ctrl); if (unlikely(!ctxi)) { - dev_dbg(dev, "%s: Bad context! (%d)\n", __func__, ctxid); + dev_dbg(dev, "%s: Bad context ctxid=%d\n", __func__, ctxid); goto err; } @@ -1091,13 +1099,12 @@ static int cxlflash_mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); rc = ctxi->cxl_mmap_vmops->fault(vma, vmf); } else { - dev_dbg(dev, "%s: err recovery active, use err_page!\n", + dev_dbg(dev, "%s: err recovery active, use err_page\n", __func__); - err_page = get_err_page(); + err_page = get_err_page(cfg); if (unlikely(!err_page)) { - dev_err(dev, "%s: Could not obtain error page!\n", - __func__); + dev_err(dev, "%s: Could not get err_page\n", __func__); rc = VM_FAULT_RETRY; goto out; } @@ -1147,7 +1154,7 @@ static int cxlflash_cxl_mmap(struct file *file, struct vm_area_struct *vma) ctxid = cxl_process_element(ctx); if (unlikely(ctxid < 0)) { - dev_err(dev, "%s: Context %p was closed! (%d)\n", + dev_err(dev, "%s: Context %p was closed ctxid=%d\n", __func__, ctx, ctxid); rc = -EIO; goto out; @@ -1155,7 +1162,7 @@ static int cxlflash_cxl_mmap(struct file *file, struct vm_area_struct *vma) ctxi = get_context(cfg, ctxid, file, ctrl); if (unlikely(!ctxi)) { - dev_dbg(dev, "%s: Bad context! (%d)\n", __func__, ctxid); + dev_dbg(dev, "%s: Bad context ctxid=%d\n", __func__, ctxid); rc = -EIO; goto out; } @@ -1251,7 +1258,7 @@ retry: break; goto retry; case STATE_FAILTERM: - dev_dbg(dev, "%s: Failed/Terminating!\n", __func__); + dev_dbg(dev, "%s: Failed/Terminating\n", __func__); rc = -ENODEV; break; default: @@ -1276,7 +1283,7 @@ retry: static int cxlflash_disk_attach(struct scsi_device *sdev, struct dk_cxlflash_attach *attach) { - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct cxlflash_cfg *cfg = shost_priv(sdev->host); struct device *dev = &cfg->dev->dev; struct afu *afu = cfg->afu; struct llun_info *lli = sdev->hostdata; @@ -1287,6 +1294,7 @@ static int cxlflash_disk_attach(struct scsi_device *sdev, int rc = 0; u32 perms; int ctxid = -1; + u64 flags = 0UL; u64 rctxid = 0UL; struct file *file = NULL; @@ -1302,24 +1310,24 @@ static int cxlflash_disk_attach(struct scsi_device *sdev, } if (gli->max_lba == 0) { - dev_dbg(dev, "%s: No capacity info for this LUN (%016llX)\n", + dev_dbg(dev, "%s: No capacity info for LUN=%016llx\n", __func__, lli->lun_id[sdev->channel]); rc = read_cap16(sdev, lli); if (rc) { - dev_err(dev, "%s: Invalid device! (%d)\n", + dev_err(dev, "%s: Invalid device rc=%d\n", __func__, rc); rc = -ENODEV; goto out; } - dev_dbg(dev, "%s: LBA = %016llX\n", __func__, gli->max_lba); - dev_dbg(dev, "%s: BLK_LEN = %08X\n", __func__, gli->blk_len); + dev_dbg(dev, "%s: LBA = %016llx\n", __func__, gli->max_lba); + dev_dbg(dev, "%s: BLK_LEN = %08x\n", __func__, gli->blk_len); } if (attach->hdr.flags & DK_CXLFLASH_ATTACH_REUSE_CONTEXT) { rctxid = attach->context_id; ctxi = get_context(cfg, rctxid, NULL, 0); if (!ctxi) { - dev_dbg(dev, "%s: Bad context! (%016llX)\n", + dev_dbg(dev, "%s: Bad context rctxid=%016llx\n", __func__, rctxid); rc = -EINVAL; goto out; @@ -1327,7 +1335,7 @@ static int cxlflash_disk_attach(struct scsi_device *sdev, list_for_each_entry(lun_access, &ctxi->luns, list) if (lun_access->lli == lli) { - dev_dbg(dev, "%s: Already attached!\n", + dev_dbg(dev, "%s: Already attached\n", __func__); rc = -EINVAL; goto out; @@ -1336,13 +1344,13 @@ static int cxlflash_disk_attach(struct scsi_device *sdev, rc = scsi_device_get(sdev); if (unlikely(rc)) { - dev_err(dev, "%s: Unable to get sdev reference!\n", __func__); + dev_err(dev, "%s: Unable to get sdev reference\n", __func__); goto out; } lun_access = kzalloc(sizeof(*lun_access), GFP_KERNEL); if (unlikely(!lun_access)) { - dev_err(dev, "%s: Unable to allocate lun_access!\n", __func__); + dev_err(dev, "%s: Unable to allocate lun_access\n", __func__); rc = -ENOMEM; goto err; } @@ -1352,7 +1360,7 @@ static int cxlflash_disk_attach(struct scsi_device *sdev, /* Non-NULL context indicates reuse (another context reference) */ if (ctxi) { - dev_dbg(dev, "%s: Reusing context for LUN! (%016llX)\n", + dev_dbg(dev, "%s: Reusing context for LUN rctxid=%016llx\n", __func__, rctxid); kref_get(&ctxi->kref); list_add(&lun_access->list, &ctxi->luns); @@ -1361,7 +1369,7 @@ static int cxlflash_disk_attach(struct scsi_device *sdev, ctxi = create_context(cfg); if (unlikely(!ctxi)) { - dev_err(dev, "%s: Failed to create context! (%d)\n", + dev_err(dev, "%s: Failed to create context ctxid=%d\n", __func__, ctxid); goto err; } @@ -1387,7 +1395,7 @@ static int cxlflash_disk_attach(struct scsi_device *sdev, ctxid = cxl_process_element(ctx); if (unlikely((ctxid >= MAX_CONTEXT) || (ctxid < 0))) { - dev_err(dev, "%s: ctxid (%d) invalid!\n", __func__, ctxid); + dev_err(dev, "%s: ctxid=%d invalid\n", __func__, ctxid); rc = -EPERM; goto err; } @@ -1426,10 +1434,11 @@ static int cxlflash_disk_attach(struct scsi_device *sdev, out_attach: if (fd != -1) - attach->hdr.return_flags = DK_CXLFLASH_APP_CLOSE_ADAP_FD; - else - attach->hdr.return_flags = 0; + flags |= DK_CXLFLASH_APP_CLOSE_ADAP_FD; + if (afu_is_sq_cmd_mode(afu)) + flags |= DK_CXLFLASH_CONTEXT_SQ_CMD_MODE; + attach->hdr.return_flags = flags; attach->context_id = ctxi->ctxid; attach->block_size = gli->blk_len; attach->mmio_size = sizeof(afu->afu_map->hosts[0].harea); @@ -1520,7 +1529,7 @@ static int recover_context(struct cxlflash_cfg *cfg, ctxid = cxl_process_element(ctx); if (unlikely((ctxid >= MAX_CONTEXT) || (ctxid < 0))) { - dev_err(dev, "%s: ctxid (%d) invalid!\n", __func__, ctxid); + dev_err(dev, "%s: ctxid=%d invalid\n", __func__, ctxid); rc = -EPERM; goto err2; } @@ -1611,12 +1620,13 @@ err1: static int cxlflash_afu_recover(struct scsi_device *sdev, struct dk_cxlflash_recover_afu *recover) { - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct cxlflash_cfg *cfg = shost_priv(sdev->host); struct device *dev = &cfg->dev->dev; struct llun_info *lli = sdev->hostdata; struct afu *afu = cfg->afu; struct ctx_info *ctxi = NULL; struct mutex *mutex = &cfg->ctx_recovery_mutex; + u64 flags; u64 ctxid = DECODE_CTXID(recover->context_id), rctxid = recover->context_id; long reg; @@ -1632,19 +1642,19 @@ static int cxlflash_afu_recover(struct scsi_device *sdev, goto out; rc = check_state(cfg); if (rc) { - dev_err(dev, "%s: Failed state! rc=%d\n", __func__, rc); + dev_err(dev, "%s: Failed state rc=%d\n", __func__, rc); rc = -ENODEV; goto out; } - dev_dbg(dev, "%s: reason 0x%016llX rctxid=%016llX\n", + dev_dbg(dev, "%s: reason=%016llx rctxid=%016llx\n", __func__, recover->reason, rctxid); retry: /* Ensure that this process is attached to the context */ ctxi = get_context(cfg, rctxid, lli, CTX_CTRL_ERR_FALLBACK); if (unlikely(!ctxi)) { - dev_dbg(dev, "%s: Bad context! (%llu)\n", __func__, ctxid); + dev_dbg(dev, "%s: Bad context ctxid=%llu\n", __func__, ctxid); rc = -EINVAL; goto out; } @@ -1653,12 +1663,12 @@ retry: retry_recover: rc = recover_context(cfg, ctxi, &new_adap_fd); if (unlikely(rc)) { - dev_err(dev, "%s: Recovery failed for context %llu (rc=%d)\n", + dev_err(dev, "%s: Recovery failed ctxid=%llu rc=%d\n", __func__, ctxid, rc); if ((rc == -ENODEV) && ((atomic_read(&cfg->recovery_threads) > 1) || (lretry--))) { - dev_dbg(dev, "%s: Going to try again!\n", + dev_dbg(dev, "%s: Going to try again\n", __func__); mutex_unlock(mutex); msleep(100); @@ -1672,11 +1682,16 @@ retry_recover: } ctxi->err_recovery_active = false; + + flags = DK_CXLFLASH_APP_CLOSE_ADAP_FD | + DK_CXLFLASH_RECOVER_AFU_CONTEXT_RESET; + if (afu_is_sq_cmd_mode(afu)) + flags |= DK_CXLFLASH_CONTEXT_SQ_CMD_MODE; + + recover->hdr.return_flags = flags; recover->context_id = ctxi->ctxid; recover->adap_fd = new_adap_fd; recover->mmio_size = sizeof(afu->afu_map->hosts[0].harea); - recover->hdr.return_flags = DK_CXLFLASH_APP_CLOSE_ADAP_FD | - DK_CXLFLASH_RECOVER_AFU_CONTEXT_RESET; goto out; } @@ -1699,7 +1714,7 @@ retry_recover: goto retry; } - dev_dbg(dev, "%s: MMIO working, no recovery required!\n", __func__); + dev_dbg(dev, "%s: MMIO working, no recovery required\n", __func__); out: if (likely(ctxi)) put_context(ctxi); @@ -1718,7 +1733,7 @@ out: static int process_sense(struct scsi_device *sdev, struct dk_cxlflash_verify *verify) { - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct cxlflash_cfg *cfg = shost_priv(sdev->host); struct device *dev = &cfg->dev->dev; struct llun_info *lli = sdev->hostdata; struct glun_info *gli = lli->parent; @@ -1729,7 +1744,7 @@ static int process_sense(struct scsi_device *sdev, rc = scsi_normalize_sense((const u8 *)&verify->sense_data, DK_CXLFLASH_VERIFY_SENSE_LEN, &sshdr); if (!rc) { - dev_err(dev, "%s: Failed to normalize sense data!\n", __func__); + dev_err(dev, "%s: Failed to normalize sense data\n", __func__); rc = -EINVAL; goto out; } @@ -1785,7 +1800,7 @@ static int cxlflash_disk_verify(struct scsi_device *sdev, { int rc = 0; struct ctx_info *ctxi = NULL; - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct cxlflash_cfg *cfg = shost_priv(sdev->host); struct device *dev = &cfg->dev->dev; struct llun_info *lli = sdev->hostdata; struct glun_info *gli = lli->parent; @@ -1795,20 +1810,20 @@ static int cxlflash_disk_verify(struct scsi_device *sdev, rctxid = verify->context_id; u64 last_lba = 0; - dev_dbg(dev, "%s: ctxid=%llu rhndl=%016llX, hint=%016llX, " - "flags=%016llX\n", __func__, ctxid, verify->rsrc_handle, + dev_dbg(dev, "%s: ctxid=%llu rhndl=%016llx, hint=%016llx, " + "flags=%016llx\n", __func__, ctxid, verify->rsrc_handle, verify->hint, verify->hdr.flags); ctxi = get_context(cfg, rctxid, lli, 0); if (unlikely(!ctxi)) { - dev_dbg(dev, "%s: Bad context! (%llu)\n", __func__, ctxid); + dev_dbg(dev, "%s: Bad context ctxid=%llu\n", __func__, ctxid); rc = -EINVAL; goto out; } rhte = get_rhte(ctxi, rhndl, lli); if (unlikely(!rhte)) { - dev_dbg(dev, "%s: Bad resource handle! (%d)\n", + dev_dbg(dev, "%s: Bad resource handle rhndl=%d\n", __func__, rhndl); rc = -EINVAL; goto out; @@ -1855,7 +1870,7 @@ static int cxlflash_disk_verify(struct scsi_device *sdev, out: if (likely(ctxi)) put_context(ctxi); - dev_dbg(dev, "%s: returning rc=%d llba=%llX\n", + dev_dbg(dev, "%s: returning rc=%d llba=%llx\n", __func__, rc, verify->last_lba); return rc; } @@ -1907,7 +1922,7 @@ static char *decode_ioctl(int cmd) */ static int cxlflash_disk_direct_open(struct scsi_device *sdev, void *arg) { - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct cxlflash_cfg *cfg = shost_priv(sdev->host); struct device *dev = &cfg->dev->dev; struct afu *afu = cfg->afu; struct llun_info *lli = sdev->hostdata; @@ -1927,25 +1942,25 @@ static int cxlflash_disk_direct_open(struct scsi_device *sdev, void *arg) struct ctx_info *ctxi = NULL; struct sisl_rht_entry *rhte = NULL; - pr_debug("%s: ctxid=%llu ls=0x%llx\n", __func__, ctxid, lun_size); + dev_dbg(dev, "%s: ctxid=%llu ls=%llu\n", __func__, ctxid, lun_size); rc = cxlflash_lun_attach(gli, MODE_PHYSICAL, false); if (unlikely(rc)) { - dev_dbg(dev, "%s: Failed to attach to LUN! (PHYSICAL)\n", - __func__); + dev_dbg(dev, "%s: Failed attach to LUN (PHYSICAL)\n", __func__); goto out; } ctxi = get_context(cfg, rctxid, lli, 0); if (unlikely(!ctxi)) { - dev_dbg(dev, "%s: Bad context! (%llu)\n", __func__, ctxid); + dev_dbg(dev, "%s: Bad context ctxid=%llu\n", __func__, ctxid); rc = -EINVAL; goto err1; } rhte = rhte_checkout(ctxi, lli); if (unlikely(!rhte)) { - dev_dbg(dev, "%s: too many opens for this context\n", __func__); + dev_dbg(dev, "%s: Too many opens ctxid=%lld\n", + __func__, ctxid); rc = -EMFILE; /* too many opens */ goto err1; } @@ -1963,7 +1978,7 @@ static int cxlflash_disk_direct_open(struct scsi_device *sdev, void *arg) out: if (likely(ctxi)) put_context(ctxi); - dev_dbg(dev, "%s: returning handle 0x%llx rc=%d llba %lld\n", + dev_dbg(dev, "%s: returning handle=%llu rc=%d llba=%llu\n", __func__, rsrc_handle, rc, last_lba); return rc; @@ -1985,7 +2000,7 @@ err1: */ static int ioctl_common(struct scsi_device *sdev, int cmd) { - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct cxlflash_cfg *cfg = shost_priv(sdev->host); struct device *dev = &cfg->dev->dev; struct llun_info *lli = sdev->hostdata; int rc = 0; @@ -2002,7 +2017,7 @@ static int ioctl_common(struct scsi_device *sdev, int cmd) case DK_CXLFLASH_VLUN_RESIZE: case DK_CXLFLASH_RELEASE: case DK_CXLFLASH_DETACH: - dev_dbg(dev, "%s: Command override! (%d)\n", + dev_dbg(dev, "%s: Command override rc=%d\n", __func__, rc); rc = 0; break; @@ -2032,7 +2047,7 @@ int cxlflash_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) { typedef int (*sioctl) (struct scsi_device *, void *); - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct cxlflash_cfg *cfg = shost_priv(sdev->host); struct device *dev = &cfg->dev->dev; struct afu *afu = cfg->afu; struct dk_cxlflash_hdr *hdr; @@ -2111,7 +2126,7 @@ int cxlflash_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) } if (unlikely(copy_from_user(&buf, arg, size))) { - dev_err(dev, "%s: copy_from_user() fail! " + dev_err(dev, "%s: copy_from_user() fail " "size=%lu cmd=%d (%s) arg=%p\n", __func__, size, cmd, decode_ioctl(cmd), arg); rc = -EFAULT; @@ -2127,7 +2142,7 @@ int cxlflash_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) } if (hdr->rsvd[0] || hdr->rsvd[1] || hdr->rsvd[2] || hdr->return_flags) { - dev_dbg(dev, "%s: Reserved/rflags populated!\n", __func__); + dev_dbg(dev, "%s: Reserved/rflags populated\n", __func__); rc = -EINVAL; goto cxlflash_ioctl_exit; } @@ -2135,7 +2150,7 @@ int cxlflash_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) rc = do_ioctl(sdev, (void *)&buf); if (likely(!rc)) if (unlikely(copy_to_user(arg, &buf, size))) { - dev_err(dev, "%s: copy_to_user() fail! " + dev_err(dev, "%s: copy_to_user() fail " "size=%lu cmd=%d (%s) arg=%p\n", __func__, size, cmd, decode_ioctl(cmd), arg); rc = -EFAULT; diff --git a/drivers/scsi/cxlflash/vlun.c b/drivers/scsi/cxlflash/vlun.c index 90c5d7f5278e..8fcc804dbef9 100644 --- a/drivers/scsi/cxlflash/vlun.c +++ b/drivers/scsi/cxlflash/vlun.c @@ -66,8 +66,8 @@ static int ba_init(struct ba_lun *ba_lun) int last_word_underflow = 0; u64 *lam; - pr_debug("%s: Initializing LUN: lun_id = %llX, " - "ba_lun->lsize = %lX, ba_lun->au_size = %lX\n", + pr_debug("%s: Initializing LUN: lun_id=%016llx " + "ba_lun->lsize=%lx ba_lun->au_size=%lX\n", __func__, ba_lun->lun_id, ba_lun->lsize, ba_lun->au_size); /* Calculate bit map size */ @@ -80,7 +80,7 @@ static int ba_init(struct ba_lun *ba_lun) /* Allocate lun information container */ bali = kzalloc(sizeof(struct ba_lun_info), GFP_KERNEL); if (unlikely(!bali)) { - pr_err("%s: Failed to allocate lun_info for lun_id %llX\n", + pr_err("%s: Failed to allocate lun_info lun_id=%016llx\n", __func__, ba_lun->lun_id); return -ENOMEM; } @@ -96,7 +96,7 @@ static int ba_init(struct ba_lun *ba_lun) GFP_KERNEL); if (unlikely(!bali->lun_alloc_map)) { pr_err("%s: Failed to allocate lun allocation map: " - "lun_id = %llX\n", __func__, ba_lun->lun_id); + "lun_id=%016llx\n", __func__, ba_lun->lun_id); kfree(bali); return -ENOMEM; } @@ -125,7 +125,7 @@ static int ba_init(struct ba_lun *ba_lun) bali->aun_clone_map = kzalloc((bali->total_aus * sizeof(u8)), GFP_KERNEL); if (unlikely(!bali->aun_clone_map)) { - pr_err("%s: Failed to allocate clone map: lun_id = %llX\n", + pr_err("%s: Failed to allocate clone map: lun_id=%016llx\n", __func__, ba_lun->lun_id); kfree(bali->lun_alloc_map); kfree(bali); @@ -136,7 +136,7 @@ static int ba_init(struct ba_lun *ba_lun) ba_lun->ba_lun_handle = bali; pr_debug("%s: Successfully initialized the LUN: " - "lun_id = %llX, bitmap size = %X, free_aun_cnt = %llX\n", + "lun_id=%016llx bitmap size=%x, free_aun_cnt=%llx\n", __func__, ba_lun->lun_id, bali->lun_bmap_size, bali->free_aun_cnt); return 0; @@ -165,10 +165,9 @@ static int find_free_range(u32 low, num_bits = (sizeof(*lam) * BITS_PER_BYTE); bit_pos = find_first_bit(lam, num_bits); - pr_devel("%s: Found free bit %llX in LUN " - "map entry %llX at bitmap index = %X\n", - __func__, bit_pos, bali->lun_alloc_map[i], - i); + pr_devel("%s: Found free bit %llu in LUN " + "map entry %016llx at bitmap index = %d\n", + __func__, bit_pos, bali->lun_alloc_map[i], i); *bit_word = i; bali->free_aun_cnt--; @@ -194,11 +193,11 @@ static u64 ba_alloc(struct ba_lun *ba_lun) bali = ba_lun->ba_lun_handle; pr_debug("%s: Received block allocation request: " - "lun_id = %llX, free_aun_cnt = %llX\n", + "lun_id=%016llx free_aun_cnt=%llx\n", __func__, ba_lun->lun_id, bali->free_aun_cnt); if (bali->free_aun_cnt == 0) { - pr_debug("%s: No space left on LUN: lun_id = %llX\n", + pr_debug("%s: No space left on LUN: lun_id=%016llx\n", __func__, ba_lun->lun_id); return -1ULL; } @@ -212,7 +211,7 @@ static u64 ba_alloc(struct ba_lun *ba_lun) bali, &bit_word); if (bit_pos == -1) { pr_debug("%s: Could not find an allocation unit on LUN:" - " lun_id = %llX\n", __func__, ba_lun->lun_id); + " lun_id=%016llx\n", __func__, ba_lun->lun_id); return -1ULL; } } @@ -223,8 +222,8 @@ static u64 ba_alloc(struct ba_lun *ba_lun) else bali->free_curr_idx = bit_word; - pr_debug("%s: Allocating AU number %llX, on lun_id %llX, " - "free_aun_cnt = %llX\n", __func__, + pr_debug("%s: Allocating AU number=%llx lun_id=%016llx " + "free_aun_cnt=%llx\n", __func__, ((bit_word * BITS_PER_LONG) + bit_pos), ba_lun->lun_id, bali->free_aun_cnt); @@ -266,18 +265,18 @@ static int ba_free(struct ba_lun *ba_lun, u64 to_free) bali = ba_lun->ba_lun_handle; if (validate_alloc(bali, to_free)) { - pr_debug("%s: The AUN %llX is not allocated on lun_id %llX\n", + pr_debug("%s: AUN %llx is not allocated on lun_id=%016llx\n", __func__, to_free, ba_lun->lun_id); return -1; } - pr_debug("%s: Received a request to free AU %llX on lun_id %llX, " - "free_aun_cnt = %llX\n", __func__, to_free, ba_lun->lun_id, + pr_debug("%s: Received a request to free AU=%llx lun_id=%016llx " + "free_aun_cnt=%llx\n", __func__, to_free, ba_lun->lun_id, bali->free_aun_cnt); if (bali->aun_clone_map[to_free] > 0) { - pr_debug("%s: AUN %llX on lun_id %llX has been cloned. Clone " - "count = %X\n", __func__, to_free, ba_lun->lun_id, + pr_debug("%s: AUN %llx lun_id=%016llx cloned. Clone count=%x\n", + __func__, to_free, ba_lun->lun_id, bali->aun_clone_map[to_free]); bali->aun_clone_map[to_free]--; return 0; @@ -294,8 +293,8 @@ static int ba_free(struct ba_lun *ba_lun, u64 to_free) else if (idx > bali->free_high_idx) bali->free_high_idx = idx; - pr_debug("%s: Successfully freed AU at bit_pos %X, bit map index %X on " - "lun_id %llX, free_aun_cnt = %llX\n", __func__, bit_pos, idx, + pr_debug("%s: Successfully freed AU bit_pos=%x bit map index=%x " + "lun_id=%016llx free_aun_cnt=%llx\n", __func__, bit_pos, idx, ba_lun->lun_id, bali->free_aun_cnt); return 0; @@ -313,16 +312,16 @@ static int ba_clone(struct ba_lun *ba_lun, u64 to_clone) struct ba_lun_info *bali = ba_lun->ba_lun_handle; if (validate_alloc(bali, to_clone)) { - pr_debug("%s: AUN %llX is not allocated on lun_id %llX\n", + pr_debug("%s: AUN=%llx not allocated on lun_id=%016llx\n", __func__, to_clone, ba_lun->lun_id); return -1; } - pr_debug("%s: Received a request to clone AUN %llX on lun_id %llX\n", + pr_debug("%s: Received a request to clone AUN %llx on lun_id=%016llx\n", __func__, to_clone, ba_lun->lun_id); if (bali->aun_clone_map[to_clone] == MAX_AUN_CLONE_CNT) { - pr_debug("%s: AUN %llX on lun_id %llX hit max clones already\n", + pr_debug("%s: AUN %llx on lun_id=%016llx hit max clones already\n", __func__, to_clone, ba_lun->lun_id); return -1; } @@ -433,7 +432,7 @@ static int write_same16(struct scsi_device *sdev, u64 offset = lba; int left = nblks; u32 to = sdev->request_queue->rq_timeout; - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct cxlflash_cfg *cfg = shost_priv(sdev->host); struct device *dev = &cfg->dev->dev; cmd_buf = kzalloc(CMD_BUFSIZE, GFP_KERNEL); @@ -459,7 +458,7 @@ static int write_same16(struct scsi_device *sdev, down_read(&cfg->ioctl_rwsem); rc = check_state(cfg); if (rc) { - dev_err(dev, "%s: Failed state! result=0x08%X\n", + dev_err(dev, "%s: Failed state result=%08x\n", __func__, result); rc = -ENODEV; goto out; @@ -467,7 +466,7 @@ static int write_same16(struct scsi_device *sdev, if (result) { dev_err_ratelimited(dev, "%s: command failed for " - "offset %lld result=0x%x\n", + "offset=%lld result=%08x\n", __func__, offset, result); rc = -EIO; goto out; @@ -480,7 +479,7 @@ out: kfree(cmd_buf); kfree(scsi_cmd); kfree(sense_buf); - pr_debug("%s: returning rc=%d\n", __func__, rc); + dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); return rc; } @@ -508,6 +507,8 @@ static int grow_lxt(struct afu *afu, struct sisl_rht_entry *rhte, u64 *new_size) { + struct cxlflash_cfg *cfg = shost_priv(sdev->host); + struct device *dev = &cfg->dev->dev; struct sisl_lxt_entry *lxt = NULL, *lxt_old = NULL; struct llun_info *lli = sdev->hostdata; struct glun_info *gli = lli->parent; @@ -527,7 +528,8 @@ static int grow_lxt(struct afu *afu, mutex_lock(&blka->mutex); av_size = ba_space(&blka->ba_lun); if (unlikely(av_size <= 0)) { - pr_debug("%s: ba_space error: av_size %d\n", __func__, av_size); + dev_dbg(dev, "%s: ba_space error av_size=%d\n", + __func__, av_size); mutex_unlock(&blka->mutex); rc = -ENOSPC; goto out; @@ -568,8 +570,8 @@ static int grow_lxt(struct afu *afu, */ aun = ba_alloc(&blka->ba_lun); if ((aun == -1ULL) || (aun >= blka->nchunk)) - pr_debug("%s: ba_alloc error: allocated chunk# %llX, " - "max %llX\n", __func__, aun, blka->nchunk - 1); + dev_dbg(dev, "%s: ba_alloc error allocated chunk=%llu " + "max=%llu\n", __func__, aun, blka->nchunk - 1); /* select both ports, use r/w perms from RHT */ lxt[i].rlba_base = ((aun << MC_CHUNK_SHIFT) | @@ -599,7 +601,7 @@ static int grow_lxt(struct afu *afu, kfree(lxt_old); *new_size = my_new_size; out: - pr_debug("%s: returning rc=%d\n", __func__, rc); + dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); return rc; } @@ -621,6 +623,8 @@ static int shrink_lxt(struct afu *afu, struct ctx_info *ctxi, u64 *new_size) { + struct cxlflash_cfg *cfg = shost_priv(sdev->host); + struct device *dev = &cfg->dev->dev; struct sisl_lxt_entry *lxt, *lxt_old; struct llun_info *lli = sdev->hostdata; struct glun_info *gli = lli->parent; @@ -706,7 +710,7 @@ static int shrink_lxt(struct afu *afu, kfree(lxt_old); *new_size = my_new_size; out: - pr_debug("%s: returning rc=%d\n", __func__, rc); + dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); return rc; } @@ -728,7 +732,8 @@ int _cxlflash_vlun_resize(struct scsi_device *sdev, struct ctx_info *ctxi, struct dk_cxlflash_resize *resize) { - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct cxlflash_cfg *cfg = shost_priv(sdev->host); + struct device *dev = &cfg->dev->dev; struct llun_info *lli = sdev->hostdata; struct glun_info *gli = lli->parent; struct afu *afu = cfg->afu; @@ -751,13 +756,13 @@ int _cxlflash_vlun_resize(struct scsi_device *sdev, nsectors = (resize->req_size * CXLFLASH_BLOCK_SIZE) / gli->blk_len; new_size = DIV_ROUND_UP(nsectors, MC_CHUNK_SIZE); - pr_debug("%s: ctxid=%llu rhndl=0x%llx, req_size=0x%llx," - "new_size=%llx\n", __func__, ctxid, resize->rsrc_handle, - resize->req_size, new_size); + dev_dbg(dev, "%s: ctxid=%llu rhndl=%llu req_size=%llu new_size=%llu\n", + __func__, ctxid, resize->rsrc_handle, resize->req_size, + new_size); if (unlikely(gli->mode != MODE_VIRTUAL)) { - pr_debug("%s: LUN mode does not support resize! (%d)\n", - __func__, gli->mode); + dev_dbg(dev, "%s: LUN mode does not support resize mode=%d\n", + __func__, gli->mode); rc = -EINVAL; goto out; @@ -766,7 +771,8 @@ int _cxlflash_vlun_resize(struct scsi_device *sdev, if (!ctxi) { ctxi = get_context(cfg, rctxid, lli, CTX_CTRL_ERR_FALLBACK); if (unlikely(!ctxi)) { - pr_debug("%s: Bad context! (%llu)\n", __func__, ctxid); + dev_dbg(dev, "%s: Bad context ctxid=%llu\n", + __func__, ctxid); rc = -EINVAL; goto out; } @@ -776,7 +782,8 @@ int _cxlflash_vlun_resize(struct scsi_device *sdev, rhte = get_rhte(ctxi, rhndl, lli); if (unlikely(!rhte)) { - pr_debug("%s: Bad resource handle! (%u)\n", __func__, rhndl); + dev_dbg(dev, "%s: Bad resource handle rhndl=%u\n", + __func__, rhndl); rc = -EINVAL; goto out; } @@ -794,8 +801,8 @@ int _cxlflash_vlun_resize(struct scsi_device *sdev, out: if (put_ctx) put_context(ctxi); - pr_debug("%s: resized to %lld returning rc=%d\n", - __func__, resize->last_lba, rc); + dev_dbg(dev, "%s: resized to %llu returning rc=%d\n", + __func__, resize->last_lba, rc); return rc; } @@ -815,6 +822,7 @@ void cxlflash_restore_luntable(struct cxlflash_cfg *cfg) u32 chan; u32 lind; struct afu *afu = cfg->afu; + struct device *dev = &cfg->dev->dev; struct sisl_global_map __iomem *agm = &afu->afu_map->global; mutex_lock(&global.mutex); @@ -828,15 +836,15 @@ void cxlflash_restore_luntable(struct cxlflash_cfg *cfg) 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]); - pr_debug("%s: Virtual LUN on slot %d id0=%llx, " - "id1=%llx\n", __func__, lind, - lli->lun_id[0], lli->lun_id[1]); + 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]); - pr_debug("%s: Virtual LUN on slot %d chan=%d, " - "id=%llx\n", __func__, lind, chan, - lli->lun_id[chan]); + dev_dbg(dev, "%s: Virtual LUN on slot %d chan=%d " + "id=%llx\n", __func__, lind, chan, + lli->lun_id[chan]); } } @@ -860,6 +868,7 @@ static int init_luntable(struct cxlflash_cfg *cfg, struct llun_info *lli) u32 lind; int rc = 0; struct afu *afu = cfg->afu; + struct device *dev = &cfg->dev->dev; struct sisl_global_map __iomem *agm = &afu->afu_map->global; mutex_lock(&global.mutex); @@ -882,8 +891,8 @@ static int init_luntable(struct cxlflash_cfg *cfg, struct llun_info *lli) writeq_be(lli->lun_id[0], &agm->fc_port[0][lind]); writeq_be(lli->lun_id[1], &agm->fc_port[1][lind]); cfg->promote_lun_index++; - pr_debug("%s: Virtual LUN on slot %d id0=%llx, id1=%llx\n", - __func__, lind, lli->lun_id[0], lli->lun_id[1]); + 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 @@ -898,14 +907,14 @@ 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]--; - pr_debug("%s: Virtual LUN on slot %d chan=%d, id=%llx\n", - __func__, lind, chan, lli->lun_id[chan]); + dev_dbg(dev, "%s: Virtual LUN on slot %d chan=%d id=%llx\n", + __func__, lind, chan, lli->lun_id[chan]); } lli->in_table = true; out: mutex_unlock(&global.mutex); - pr_debug("%s: returning rc=%d\n", __func__, rc); + dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); return rc; } @@ -923,7 +932,7 @@ out: */ int cxlflash_disk_virtual_open(struct scsi_device *sdev, void *arg) { - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct cxlflash_cfg *cfg = shost_priv(sdev->host); struct device *dev = &cfg->dev->dev; struct llun_info *lli = sdev->hostdata; struct glun_info *gli = lli->parent; @@ -942,14 +951,14 @@ int cxlflash_disk_virtual_open(struct scsi_device *sdev, void *arg) struct ctx_info *ctxi = NULL; struct sisl_rht_entry *rhte = NULL; - pr_debug("%s: ctxid=%llu ls=0x%llx\n", __func__, ctxid, lun_size); + dev_dbg(dev, "%s: ctxid=%llu ls=%llu\n", __func__, ctxid, lun_size); /* Setup the LUNs block allocator on first call */ mutex_lock(&gli->mutex); if (gli->mode == MODE_NONE) { rc = init_vlun(lli); if (rc) { - dev_err(dev, "%s: call to init_vlun failed rc=%d!\n", + dev_err(dev, "%s: init_vlun failed rc=%d\n", __func__, rc); rc = -ENOMEM; goto err0; @@ -958,29 +967,28 @@ int cxlflash_disk_virtual_open(struct scsi_device *sdev, void *arg) rc = cxlflash_lun_attach(gli, MODE_VIRTUAL, true); if (unlikely(rc)) { - dev_err(dev, "%s: Failed to attach to LUN! (VIRTUAL)\n", - __func__); + dev_err(dev, "%s: Failed attach to LUN (VIRTUAL)\n", __func__); goto err0; } mutex_unlock(&gli->mutex); rc = init_luntable(cfg, lli); if (rc) { - dev_err(dev, "%s: call to init_luntable failed rc=%d!\n", - __func__, rc); + dev_err(dev, "%s: init_luntable failed rc=%d\n", __func__, rc); goto err1; } ctxi = get_context(cfg, rctxid, lli, 0); if (unlikely(!ctxi)) { - dev_err(dev, "%s: Bad context! (%llu)\n", __func__, ctxid); + dev_err(dev, "%s: Bad context ctxid=%llu\n", __func__, ctxid); rc = -EINVAL; goto err1; } rhte = rhte_checkout(ctxi, lli); if (unlikely(!rhte)) { - dev_err(dev, "%s: too many opens for this context\n", __func__); + dev_err(dev, "%s: too many opens ctxid=%llu\n", + __func__, ctxid); rc = -EMFILE; /* too many opens */ goto err1; } @@ -996,7 +1004,7 @@ int cxlflash_disk_virtual_open(struct scsi_device *sdev, void *arg) resize.rsrc_handle = rsrc_handle; rc = _cxlflash_vlun_resize(sdev, ctxi, &resize); if (rc) { - dev_err(dev, "%s: resize failed rc %d\n", __func__, rc); + dev_err(dev, "%s: resize failed rc=%d\n", __func__, rc); goto err2; } last_lba = resize.last_lba; @@ -1013,8 +1021,8 @@ int cxlflash_disk_virtual_open(struct scsi_device *sdev, void *arg) out: if (likely(ctxi)) put_context(ctxi); - pr_debug("%s: returning handle 0x%llx rc=%d llba %lld\n", - __func__, rsrc_handle, rc, last_lba); + dev_dbg(dev, "%s: returning handle=%llu rc=%d llba=%llu\n", + __func__, rsrc_handle, rc, last_lba); return rc; err2: @@ -1047,6 +1055,8 @@ static int clone_lxt(struct afu *afu, struct sisl_rht_entry *rhte, struct sisl_rht_entry *rhte_src) { + struct cxlflash_cfg *cfg = afu->parent; + struct device *dev = &cfg->dev->dev; struct sisl_lxt_entry *lxt; u32 ngrps; u64 aun; /* chunk# allocated by block allocator */ @@ -1101,7 +1111,7 @@ static int clone_lxt(struct afu *afu, cxlflash_afu_sync(afu, ctxid, rhndl, AFU_LW_SYNC); - pr_debug("%s: returning\n", __func__); + dev_dbg(dev, "%s: returning\n", __func__); return 0; } @@ -1120,7 +1130,8 @@ static int clone_lxt(struct afu *afu, int cxlflash_disk_clone(struct scsi_device *sdev, struct dk_cxlflash_clone *clone) { - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct cxlflash_cfg *cfg = shost_priv(sdev->host); + struct device *dev = &cfg->dev->dev; struct llun_info *lli = sdev->hostdata; struct glun_info *gli = lli->parent; struct blka *blka = &gli->blka; @@ -1140,8 +1151,8 @@ int cxlflash_disk_clone(struct scsi_device *sdev, bool found; LIST_HEAD(sidecar); - pr_debug("%s: ctxid_src=%llu ctxid_dst=%llu\n", - __func__, ctxid_src, ctxid_dst); + dev_dbg(dev, "%s: ctxid_src=%llu ctxid_dst=%llu\n", + __func__, ctxid_src, ctxid_dst); /* Do not clone yourself */ if (unlikely(rctxid_src == rctxid_dst)) { @@ -1151,16 +1162,16 @@ int cxlflash_disk_clone(struct scsi_device *sdev, if (unlikely(gli->mode != MODE_VIRTUAL)) { rc = -EINVAL; - pr_debug("%s: Clone not supported on physical LUNs! (%d)\n", - __func__, gli->mode); + dev_dbg(dev, "%s: Only supported on virtual LUNs mode=%u\n", + __func__, gli->mode); goto out; } ctxi_src = get_context(cfg, rctxid_src, lli, CTX_CTRL_CLONE); ctxi_dst = get_context(cfg, rctxid_dst, lli, 0); if (unlikely(!ctxi_src || !ctxi_dst)) { - pr_debug("%s: Bad context! (%llu,%llu)\n", __func__, - ctxid_src, ctxid_dst); + dev_dbg(dev, "%s: Bad context ctxid_src=%llu ctxid_dst=%llu\n", + __func__, ctxid_src, ctxid_dst); rc = -EINVAL; goto out; } @@ -1185,8 +1196,8 @@ int cxlflash_disk_clone(struct scsi_device *sdev, lun_access_dst = kzalloc(sizeof(*lun_access_dst), GFP_KERNEL); if (unlikely(!lun_access_dst)) { - pr_err("%s: Unable to allocate lun_access!\n", - __func__); + dev_err(dev, "%s: lun_access allocation fail\n", + __func__); rc = -ENOMEM; goto out; } @@ -1197,7 +1208,7 @@ int cxlflash_disk_clone(struct scsi_device *sdev, } if (unlikely(!ctxi_src->rht_out)) { - pr_debug("%s: Nothing to clone!\n", __func__); + dev_dbg(dev, "%s: Nothing to clone\n", __func__); goto out_success; } @@ -1256,7 +1267,7 @@ out: put_context(ctxi_src); if (ctxi_dst) put_context(ctxi_dst); - pr_debug("%s: returning rc=%d\n", __func__, rc); + dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); return rc; err: diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c index 5f75e638ec95..256dd6791fcc 100644 --- a/drivers/scsi/dpt_i2o.c +++ b/drivers/scsi/dpt_i2o.c @@ -2768,16 +2768,12 @@ static int adpt_i2o_activate_hba(adpt_hba* pHba) static int adpt_i2o_online_hba(adpt_hba* pHba) { - if (adpt_i2o_systab_send(pHba) < 0) { - adpt_i2o_delete_hba(pHba); + if (adpt_i2o_systab_send(pHba) < 0) return -1; - } /* In READY state */ - if (adpt_i2o_enable_hba(pHba) < 0) { - adpt_i2o_delete_hba(pHba); + if (adpt_i2o_enable_hba(pHba) < 0) return -1; - } /* In OPERATIONAL state */ return 0; diff --git a/drivers/scsi/esas2r/esas2r_init.c b/drivers/scsi/esas2r/esas2r_init.c index d6e53aee2295..6432a50b26d8 100644 --- a/drivers/scsi/esas2r/esas2r_init.c +++ b/drivers/scsi/esas2r/esas2r_init.c @@ -237,7 +237,7 @@ static void esas2r_claim_interrupts(struct esas2r_adapter *a) flags |= IRQF_SHARED; esas2r_log(ESAS2R_LOG_INFO, - "esas2r_claim_interrupts irq=%d (%p, %s, %x)", + "esas2r_claim_interrupts irq=%d (%p, %s, %lx)", a->pcid->irq, a, a->name, flags); if (request_irq(a->pcid->irq, diff --git a/drivers/scsi/esas2r/esas2r_ioctl.c b/drivers/scsi/esas2r/esas2r_ioctl.c index 3e8483410f61..b35ed3829421 100644 --- a/drivers/scsi/esas2r/esas2r_ioctl.c +++ b/drivers/scsi/esas2r/esas2r_ioctl.c @@ -1301,7 +1301,7 @@ int esas2r_ioctl_handler(void *hostdata, int cmd, void __user *arg) ioctl = kzalloc(sizeof(struct atto_express_ioctl), GFP_KERNEL); if (ioctl == NULL) { esas2r_log(ESAS2R_LOG_WARN, - "ioctl_handler kzalloc failed for %d bytes", + "ioctl_handler kzalloc failed for %zu bytes", sizeof(struct atto_express_ioctl)); return -ENOMEM; } diff --git a/drivers/scsi/esas2r/esas2r_log.h b/drivers/scsi/esas2r/esas2r_log.h index 7b6397bb5b94..75b9d23cd736 100644 --- a/drivers/scsi/esas2r/esas2r_log.h +++ b/drivers/scsi/esas2r/esas2r_log.h @@ -61,8 +61,8 @@ enum { #endif }; -int esas2r_log(const long level, const char *format, ...); -int esas2r_log_dev(const long level, +__printf(2, 3) int esas2r_log(const long level, const char *format, ...); +__printf(3, 4) int esas2r_log_dev(const long level, const struct device *dev, const char *format, ...); diff --git a/drivers/scsi/esas2r/esas2r_main.c b/drivers/scsi/esas2r/esas2r_main.c index 5092c821d088..f2e9d8aa979c 100644 --- a/drivers/scsi/esas2r/esas2r_main.c +++ b/drivers/scsi/esas2r/esas2r_main.c @@ -198,7 +198,7 @@ static ssize_t write_hw(struct file *file, struct kobject *kobj, GFP_KERNEL); if (a->local_atto_ioctl == NULL) { esas2r_log(ESAS2R_LOG_WARN, - "write_hw kzalloc failed for %d bytes", + "write_hw kzalloc failed for %zu bytes", sizeof(struct atto_ioctl)); return -ENOMEM; } @@ -1186,7 +1186,7 @@ retry: } else { esas2r_log(ESAS2R_LOG_CRIT, "unable to allocate a request for a " - "device reset (%d:%d)!", + "device reset (%d:%llu)!", cmd->device->id, cmd->device->lun); } diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c index 6f9665d50d84..67c8dac321ad 100644 --- a/drivers/scsi/g_NCR5380.c +++ b/drivers/scsi/g_NCR5380.c @@ -26,14 +26,55 @@ #include <linux/blkdev.h> #include <linux/module.h> #include <scsi/scsi_host.h> -#include "g_NCR5380.h" -#include "NCR5380.h" #include <linux/init.h> #include <linux/ioport.h> #include <linux/isa.h> #include <linux/pnp.h> #include <linux/interrupt.h> +/* Definitions for the core NCR5380 driver. */ + +#define NCR5380_read(reg) \ + ioread8(hostdata->io + hostdata->offset + (reg)) +#define NCR5380_write(reg, value) \ + iowrite8(value, hostdata->io + hostdata->offset + (reg)) + +#define NCR5380_implementation_fields \ + int offset; \ + int c400_ctl_status; \ + int c400_blk_cnt; \ + int c400_host_buf; \ + int io_width + +#define NCR5380_dma_xfer_len generic_NCR5380_dma_xfer_len +#define NCR5380_dma_recv_setup generic_NCR5380_pread +#define NCR5380_dma_send_setup generic_NCR5380_pwrite +#define NCR5380_dma_residual NCR5380_dma_residual_none + +#define NCR5380_intr generic_NCR5380_intr +#define NCR5380_queue_command generic_NCR5380_queue_command +#define NCR5380_abort generic_NCR5380_abort +#define NCR5380_bus_reset generic_NCR5380_bus_reset +#define NCR5380_info generic_NCR5380_info + +#define NCR5380_io_delay(x) udelay(x) + +#include "NCR5380.h" + +#define DRV_MODULE_NAME "g_NCR5380" + +#define NCR53C400_mem_base 0x3880 +#define NCR53C400_host_buffer 0x3900 +#define NCR53C400_region_size 0x3a00 + +#define BOARD_NCR5380 0 +#define BOARD_NCR53C400 1 +#define BOARD_NCR53C400A 2 +#define BOARD_DTC3181E 3 +#define BOARD_HP_C2502 4 + +#define IRQ_AUTO 254 + #define MAX_CARDS 8 /* old-style parameters for compatibility */ diff --git a/drivers/scsi/g_NCR5380.h b/drivers/scsi/g_NCR5380.h deleted file mode 100644 index 81b22d989648..000000000000 --- a/drivers/scsi/g_NCR5380.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Generic Generic NCR5380 driver defines - * - * Copyright 1993, Drew Eckhardt - * Visionary Computing - * (Unix and Linux consulting and custom programming) - * drew@colorado.edu - * +1 (303) 440-4894 - * - * NCR53C400 extensions (c) 1994,1995,1996, Kevin Lentin - * K.Lentin@cs.monash.edu.au - */ - -#ifndef GENERIC_NCR5380_H -#define GENERIC_NCR5380_H - -#define DRV_MODULE_NAME "g_NCR5380" - -#define NCR5380_read(reg) \ - ioread8(hostdata->io + hostdata->offset + (reg)) -#define NCR5380_write(reg, value) \ - iowrite8(value, hostdata->io + hostdata->offset + (reg)) - -#define NCR5380_implementation_fields \ - int offset; \ - int c400_ctl_status; \ - int c400_blk_cnt; \ - int c400_host_buf; \ - int io_width; - -#define NCR53C400_mem_base 0x3880 -#define NCR53C400_host_buffer 0x3900 -#define NCR53C400_region_size 0x3a00 - -#define NCR5380_dma_xfer_len generic_NCR5380_dma_xfer_len -#define NCR5380_dma_recv_setup generic_NCR5380_pread -#define NCR5380_dma_send_setup generic_NCR5380_pwrite -#define NCR5380_dma_residual NCR5380_dma_residual_none - -#define NCR5380_intr generic_NCR5380_intr -#define NCR5380_queue_command generic_NCR5380_queue_command -#define NCR5380_abort generic_NCR5380_abort -#define NCR5380_bus_reset generic_NCR5380_bus_reset -#define NCR5380_info generic_NCR5380_info - -#define NCR5380_io_delay(x) udelay(x) - -#define BOARD_NCR5380 0 -#define BOARD_NCR53C400 1 -#define BOARD_NCR53C400A 2 -#define BOARD_DTC3181E 3 -#define BOARD_HP_C2502 4 - -#define IRQ_AUTO 254 - -#endif /* GENERIC_NCR5380_H */ diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index c0cd505a9ef7..9216deaa3ff5 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -95,6 +95,7 @@ struct hisi_sas_port { struct hisi_sas_cq { struct hisi_hba *hisi_hba; + struct tasklet_struct tasklet; int rd_point; int id; }; diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index d50e9cfefd24..53637a941b94 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -71,6 +71,8 @@ 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; @@ -97,6 +99,8 @@ void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task, slot->task = NULL; slot->port = NULL; hisi_sas_slot_index_free(hisi_hba, slot->idx); + 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); @@ -141,11 +145,10 @@ static void hisi_sas_slot_abort(struct work_struct *work) struct hisi_hba *hisi_hba = dev_to_hisi_hba(task->dev); struct scsi_cmnd *cmnd = task->uldd_task; struct hisi_sas_tmf_task tmf_task; - struct domain_device *device = task->dev; - struct hisi_sas_device *sas_dev = device->lldd_dev; struct scsi_lun lun; struct device *dev = &hisi_hba->pdev->dev; int tag = abort_slot->idx; + unsigned long flags; if (!(task->task_proto & SAS_PROTOCOL_SSP)) { dev_err(dev, "cannot abort slot for non-ssp task\n"); @@ -159,11 +162,11 @@ static void hisi_sas_slot_abort(struct work_struct *work) hisi_sas_debug_issue_ssp_tmf(task->dev, lun.scsi_lun, &tmf_task); out: /* Do cleanup for this task */ + spin_lock_irqsave(&hisi_hba->lock, flags); hisi_sas_slot_task_free(hisi_hba, task, abort_slot); + spin_unlock_irqrestore(&hisi_hba->lock, flags); if (task->task_done) task->task_done(task); - if (sas_dev) - atomic64_dec(&sas_dev->running_req); } static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba, @@ -1118,7 +1121,7 @@ hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba, } exit: - dev_info(dev, "internal task abort: task to dev %016llx task=%p " + dev_dbg(dev, "internal task abort: task to dev %016llx task=%p " "resp: 0x%x sts 0x%x\n", SAS_ADDR(device->sas_addr), task, @@ -1450,7 +1453,7 @@ static struct Scsi_Host *hisi_sas_shost_alloc(struct platform_device *pdev, refclk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(refclk)) - dev_info(dev, "no ref clk property\n"); + dev_dbg(dev, "no ref clk property\n"); else hisi_hba->refclk_frequency_mhz = clk_get_rate(refclk) / 1000000; @@ -1549,10 +1552,6 @@ int hisi_sas_probe(struct platform_device *pdev, hisi_sas_init_add(hisi_hba); - rc = hisi_hba->hw->hw_init(hisi_hba); - if (rc) - goto err_out_ha; - rc = scsi_add_host(shost, &pdev->dev); if (rc) goto err_out_ha; @@ -1561,6 +1560,10 @@ int hisi_sas_probe(struct platform_device *pdev, if (rc) goto err_out_register_ha; + rc = hisi_hba->hw->hw_init(hisi_hba); + if (rc) + goto err_out_register_ha; + scsi_scan_host(shost); return 0; diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c index 8a1be0ba8a22..854fbeaade3e 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c @@ -1596,6 +1596,7 @@ static irqreturn_t cq_interrupt_v1_hw(int irq, void *p) hisi_hba->complete_hdr[queue]; u32 irq_value, rd_point = cq->rd_point, wr_point; + spin_lock(&hisi_hba->lock); irq_value = hisi_sas_read32(hisi_hba, OQ_INT_SRC); hisi_sas_write32(hisi_hba, OQ_INT_SRC, 1 << queue); @@ -1628,6 +1629,7 @@ static irqreturn_t cq_interrupt_v1_hw(int irq, void *p) /* update rd_point */ cq->rd_point = rd_point; hisi_sas_write32(hisi_hba, COMPL_Q_0_RD_PTR + (0x14 * queue), rd_point); + spin_unlock(&hisi_hba->lock); return IRQ_HANDLED; } diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index b934aec1eebb..1b214450dcb5 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 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) @@ -215,6 +217,7 @@ #define RX_IDAF_DWORD5 (PORT_BASE + 0xd8) #define RX_IDAF_DWORD6 (PORT_BASE + 0xdc) #define RXOP_CHECK_CFG_H (PORT_BASE + 0xfc) +#define CON_CONTROL (PORT_BASE + 0x118) #define DONE_RECEIVED_TIME (PORT_BASE + 0x11c) #define CHL_INT0 (PORT_BASE + 0x1b4) #define CHL_INT0_HOTPLUG_TOUT_OFF 0 @@ -333,6 +336,11 @@ #define ITCT_HDR_MCR_MSK (0xf << ITCT_HDR_MCR_OFF) #define ITCT_HDR_VLN_OFF 9 #define ITCT_HDR_VLN_MSK (0xf << ITCT_HDR_VLN_OFF) +#define ITCT_HDR_SMP_TIMEOUT_OFF 16 +#define ITCT_HDR_SMP_TIMEOUT_8US 1 +#define ITCT_HDR_SMP_TIMEOUT (ITCT_HDR_SMP_TIMEOUT_8US * \ + 250) /* 2ms */ +#define ITCT_HDR_AWT_CONTINUE_OFF 25 #define ITCT_HDR_PORT_ID_OFF 28 #define ITCT_HDR_PORT_ID_MSK (0xf << ITCT_HDR_PORT_ID_OFF) /* qw2 */ @@ -526,6 +534,8 @@ enum { #define SATA_PROTOCOL_FPDMA 0x8 #define SATA_PROTOCOL_ATAPI 0x10 +static void hisi_sas_link_timeout_disable_link(unsigned long data); + static u32 hisi_sas_read32(struct hisi_hba *hisi_hba, u32 off) { void __iomem *regs = hisi_hba->regs + off; @@ -693,6 +703,8 @@ static void setup_itct_v2_hw(struct hisi_hba *hisi_hba, qw0 |= ((1 << ITCT_HDR_VALID_OFF) | (device->linkrate << ITCT_HDR_MCR_OFF) | (1 << ITCT_HDR_VLN_OFF) | + (ITCT_HDR_SMP_TIMEOUT << ITCT_HDR_SMP_TIMEOUT_OFF) | + (1 << ITCT_HDR_AWT_CONTINUE_OFF) | (port->id << ITCT_HDR_PORT_ID_OFF)); itct->qw0 = cpu_to_le64(qw0); @@ -702,7 +714,7 @@ static void setup_itct_v2_hw(struct hisi_hba *hisi_hba, /* qw2 */ if (!dev_is_sata(device)) - itct->qw2 = cpu_to_le64((500ULL << ITCT_HDR_INLT_OFF) | + itct->qw2 = cpu_to_le64((5000ULL << ITCT_HDR_INLT_OFF) | (0x1ULL << ITCT_HDR_BITLT_OFF) | (0x32ULL << ITCT_HDR_MCTLT_OFF) | (0x1ULL << ITCT_HDR_RTOLT_OFF)); @@ -711,7 +723,7 @@ static void setup_itct_v2_hw(struct hisi_hba *hisi_hba, static void free_device_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_device *sas_dev) { - u64 qw0, dev_id = sas_dev->device_id; + u64 dev_id = sas_dev->device_id; struct device *dev = &hisi_hba->pdev->dev; struct hisi_sas_itct *itct = &hisi_hba->itct[dev_id]; u32 reg_val = hisi_sas_read32(hisi_hba, ENT_INT_SRC3); @@ -735,8 +747,7 @@ static void free_device_v2_hw(struct hisi_hba *hisi_hba, dev_dbg(dev, "got clear ITCT done interrupt\n"); /* invalid the itct state*/ - qw0 = cpu_to_le64(itct->qw0); - qw0 &= ~(1 << ITCT_HDR_VALID_OFF); + memset(itct, 0, sizeof(struct hisi_sas_itct)); hisi_sas_write32(hisi_hba, ENT_INT_SRC3, ENT_INT_SRC3_ITC_INT_MSK); @@ -978,6 +989,50 @@ 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) +{ + struct hisi_hba *hisi_hba = (struct hisi_hba *)data; + int i, reg_val; + + for (i = 0; i < hisi_hba->n_phy; i++) { + reg_val = hisi_sas_phy_read32(hisi_hba, i, CON_CONTROL); + if (!(reg_val & BIT(0))) { + hisi_sas_phy_write32(hisi_hba, i, + CON_CONTROL, 0x7); + break; + } + } + + hisi_hba->timer.function = hisi_sas_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) +{ + struct hisi_hba *hisi_hba = (struct hisi_hba *)data; + int i, reg_val; + + reg_val = hisi_sas_read32(hisi_hba, PHY_STATE); + for (i = 0; i < hisi_hba->n_phy && reg_val; i++) { + if (reg_val & BIT(i)) { + hisi_sas_phy_write32(hisi_hba, i, + CON_CONTROL, 0x6); + break; + } + } + + hisi_hba->timer.function = hisi_sas_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.expires = jiffies + msecs_to_jiffies(1000); + add_timer(&hisi_hba->timer); +} + static int hw_init_v2_hw(struct hisi_hba *hisi_hba) { struct device *dev = &hisi_hba->pdev->dev; @@ -1025,14 +1080,21 @@ static void stop_phy_v2_hw(struct hisi_hba *hisi_hba, int phy_no) 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]; + u32 txid_auto; + stop_phy_v2_hw(hisi_hba, phy_no); + if (phy->identify.device_type == SAS_END_DEVICE) { + txid_auto = hisi_sas_phy_read32(hisi_hba, phy_no, TXID_AUTO); + hisi_sas_phy_write32(hisi_hba, phy_no, TXID_AUTO, + txid_auto | TX_HARDRST_MSK); + } msleep(100); start_phy_v2_hw(hisi_hba, phy_no); } -static void start_phys_v2_hw(unsigned long data) +static void start_phys_v2_hw(struct hisi_hba *hisi_hba) { - struct hisi_hba *hisi_hba = (struct hisi_hba *)data; int i; for (i = 0; i < hisi_hba->n_phy; i++) @@ -1041,10 +1103,7 @@ static void start_phys_v2_hw(unsigned long data) static void phys_init_v2_hw(struct hisi_hba *hisi_hba) { - struct timer_list *timer = &hisi_hba->timer; - - setup_timer(timer, start_phys_v2_hw, (unsigned long)hisi_hba); - mod_timer(timer, jiffies + HZ); + start_phys_v2_hw(hisi_hba); } static void sl_notify_v2_hw(struct hisi_hba *hisi_hba, int phy_no) @@ -1771,8 +1830,6 @@ slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot, } out: - if (sas_dev) - atomic64_dec(&sas_dev->running_req); hisi_sas_slot_task_free(hisi_hba, task, slot); sts = ts->stat; @@ -2020,9 +2077,12 @@ static int phy_up_v2_hw(int phy_no, struct hisi_hba *hisi_hba) if (phy->identify.device_type == SAS_END_DEVICE) phy->identify.target_port_protocols = SAS_PROTOCOL_SSP; - else if (phy->identify.device_type != SAS_PHY_UNUSED) + else if (phy->identify.device_type != SAS_PHY_UNUSED) { phy->identify.target_port_protocols = SAS_PROTOCOL_SMP; + if (!timer_pending(&hisi_hba->timer)) + set_link_timer_quirk(hisi_hba); + } queue_work(hisi_hba->wq, &phy->phyup_ws); end: @@ -2033,10 +2093,23 @@ end: return res; } +static bool check_any_wideports_v2_hw(struct hisi_hba *hisi_hba) +{ + u32 port_state; + + port_state = hisi_sas_read32(hisi_hba, PORT_STATE); + if (port_state & 0x1ff) + return true; + + return false; +} + 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; hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_NOT_RDY_MSK, 1); @@ -2046,6 +2119,10 @@ static int phy_down_v2_hw(int phy_no, struct hisi_hba *hisi_hba) sl_ctrl = hisi_sas_phy_read32(hisi_hba, phy_no, SL_CONTROL); hisi_sas_phy_write32(hisi_hba, phy_no, SL_CONTROL, sl_ctrl & ~SL_CONTROL_CTA_MSK); + if (port && !get_wideport_bitmap_v2_hw(hisi_hba, port->id)) + if (!check_any_wideports_v2_hw(hisi_hba) && + timer_pending(&hisi_hba->timer)) + del_timer(&hisi_hba->timer); txid_auto = hisi_sas_phy_read32(hisi_hba, phy_no, TXID_AUTO); hisi_sas_phy_write32(hisi_hba, phy_no, TXID_AUTO, @@ -2481,21 +2558,19 @@ static irqreturn_t fatal_axi_int_v2_hw(int irq_no, void *p) return IRQ_HANDLED; } -static irqreturn_t cq_interrupt_v2_hw(int irq_no, void *p) +static void cq_tasklet_v2_hw(unsigned long val) { - struct hisi_sas_cq *cq = p; + struct hisi_sas_cq *cq = (struct hisi_sas_cq *)val; struct hisi_hba *hisi_hba = cq->hisi_hba; struct hisi_sas_slot *slot; struct hisi_sas_itct *itct; struct hisi_sas_complete_v2_hdr *complete_queue; - u32 irq_value, rd_point = cq->rd_point, wr_point, dev_id; + u32 rd_point = cq->rd_point, wr_point, dev_id; int queue = cq->id; complete_queue = hisi_hba->complete_hdr[queue]; - irq_value = hisi_sas_read32(hisi_hba, OQ_INT_SRC); - - hisi_sas_write32(hisi_hba, OQ_INT_SRC, 1 << queue); + spin_lock(&hisi_hba->lock); wr_point = hisi_sas_read32(hisi_hba, COMPL_Q_0_WR_PTR + (0x14 * queue)); @@ -2545,6 +2620,19 @@ static irqreturn_t cq_interrupt_v2_hw(int irq_no, void *p) /* update rd_point */ cq->rd_point = rd_point; hisi_sas_write32(hisi_hba, COMPL_Q_0_RD_PTR + (0x14 * queue), rd_point); + spin_unlock(&hisi_hba->lock); +} + +static irqreturn_t cq_interrupt_v2_hw(int irq_no, void *p) +{ + struct hisi_sas_cq *cq = p; + struct hisi_hba *hisi_hba = cq->hisi_hba; + int queue = cq->id; + + hisi_sas_write32(hisi_hba, OQ_INT_SRC, 1 << queue); + + tasklet_schedule(&cq->tasklet); + return IRQ_HANDLED; } @@ -2726,6 +2814,8 @@ static int interrupt_init_v2_hw(struct hisi_hba *hisi_hba) for (i = 0; i < hisi_hba->queue_count; i++) { int idx = i + 96; /* First cq interrupt is irq96 */ + struct hisi_sas_cq *cq = &hisi_hba->cq[i]; + struct tasklet_struct *t = &cq->tasklet; irq = irq_map[idx]; if (!irq) { @@ -2742,6 +2832,7 @@ static int interrupt_init_v2_hw(struct hisi_hba *hisi_hba) irq, rc); return -ENOENT; } + tasklet_init(t, cq_tasklet_v2_hw, (unsigned long)cq); } return 0; @@ -2807,6 +2898,12 @@ static int hisi_sas_v2_probe(struct platform_device *pdev) static int hisi_sas_v2_remove(struct platform_device *pdev) { + struct sas_ha_struct *sha = platform_get_drvdata(pdev); + struct hisi_hba *hisi_hba = sha->lldd_ha; + + if (timer_pending(&hisi_hba->timer)) + del_timer(&hisi_hba->timer); + return hisi_sas_remove(pdev); } diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index c611412a8de9..524a0c755ed7 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -9263,13 +9263,9 @@ static int hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support) access = SA5_ioaccel_mode1_access; writel(10, &h->cfgtable->HostWrite.CoalIntDelay); writel(4, &h->cfgtable->HostWrite.CoalIntCount); - } else { - if (trans_support & CFGTBL_Trans_io_accel2) { + } else + if (trans_support & CFGTBL_Trans_io_accel2) access = SA5_ioaccel_mode2_access; - writel(10, &h->cfgtable->HostWrite.CoalIntDelay); - writel(4, &h->cfgtable->HostWrite.CoalIntCount); - } - } writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL); if (hpsa_wait_for_mode_change_ack(h)) { dev_err(&h->pdev->dev, diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 64e98295b707..bf6cdc106654 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -578,38 +578,38 @@ static unsigned long SA5_ioaccel_mode1_completed(struct ctlr_info *h, u8 q) } static struct access_method SA5_access = { - SA5_submit_command, - SA5_intr_mask, - SA5_intr_pending, - SA5_completed, + .submit_command = SA5_submit_command, + .set_intr_mask = SA5_intr_mask, + .intr_pending = SA5_intr_pending, + .command_completed = SA5_completed, }; static struct access_method SA5_ioaccel_mode1_access = { - SA5_submit_command, - SA5_performant_intr_mask, - SA5_ioaccel_mode1_intr_pending, - SA5_ioaccel_mode1_completed, + .submit_command = SA5_submit_command, + .set_intr_mask = SA5_performant_intr_mask, + .intr_pending = SA5_ioaccel_mode1_intr_pending, + .command_completed = SA5_ioaccel_mode1_completed, }; static struct access_method SA5_ioaccel_mode2_access = { - SA5_submit_command_ioaccel2, - SA5_performant_intr_mask, - SA5_performant_intr_pending, - SA5_performant_completed, + .submit_command = SA5_submit_command_ioaccel2, + .set_intr_mask = SA5_performant_intr_mask, + .intr_pending = SA5_performant_intr_pending, + .command_completed = SA5_performant_completed, }; static struct access_method SA5_performant_access = { - SA5_submit_command, - SA5_performant_intr_mask, - SA5_performant_intr_pending, - SA5_performant_completed, + .submit_command = SA5_submit_command, + .set_intr_mask = SA5_performant_intr_mask, + .intr_pending = SA5_performant_intr_pending, + .command_completed = SA5_performant_completed, }; static struct access_method SA5_performant_access_no_read = { - SA5_submit_command_no_read, - SA5_performant_intr_mask, - SA5_performant_intr_pending, - SA5_performant_completed, + .submit_command = SA5_submit_command_no_read, + .set_intr_mask = SA5_performant_intr_mask, + .intr_pending = SA5_performant_intr_pending, + .command_completed = SA5_performant_completed, }; struct board_type { diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 8a20b4e86224..6593b073c524 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -727,7 +727,6 @@ struct lpfc_hba { uint32_t cfg_fcp_io_channel; uint32_t cfg_total_seg_cnt; uint32_t cfg_sg_seg_cnt; - uint32_t cfg_prot_sg_seg_cnt; uint32_t cfg_sg_dma_buf_size; uint64_t cfg_soft_wwnn; uint64_t cfg_soft_wwpn; diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index c84775562c65..50cf402dea29 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -2073,6 +2073,13 @@ lpfc_soft_wwn_enable_store(struct device *dev, struct device_attribute *attr, return -EINVAL; phba->soft_wwn_enable = 1; + + dev_printk(KERN_WARNING, &phba->pcidev->dev, + "lpfc%d: soft_wwpn assignment has been enabled.\n", + phba->brd_no); + dev_printk(KERN_WARNING, &phba->pcidev->dev, + " The soft_wwpn feature is not supported by Broadcom."); + return count; } static DEVICE_ATTR(lpfc_soft_wwn_enable, S_IWUSR, NULL, @@ -2143,7 +2150,7 @@ lpfc_soft_wwpn_store(struct device *dev, struct device_attribute *attr, phba->soft_wwn_enable = 0; rc = lpfc_wwn_set(buf, cnt, wwpn); - if (!rc) { + if (rc) { /* not able to set wwpn, unlock it */ phba->soft_wwn_enable = 1; return rc; @@ -2224,7 +2231,7 @@ lpfc_soft_wwnn_store(struct device *dev, struct device_attribute *attr, return -EINVAL; rc = lpfc_wwn_set(buf, cnt, wwnn); - if (!rc) { + if (rc) { /* Allow wwnn to be set many times, as long as the enable * is set. However, once the wwpn is set, everything locks. */ @@ -2435,7 +2442,8 @@ lpfc_oas_vpt_store(struct device *dev, struct device_attribute *attr, else phba->cfg_oas_flags &= ~OAS_FIND_ANY_VPORT; phba->cfg_oas_flags &= ~OAS_LUN_VALID; - phba->cfg_oas_priority = phba->cfg_XLanePriority; + if (phba->cfg_oas_priority == 0) + phba->cfg_oas_priority = phba->cfg_XLanePriority; phba->sli4_hba.oas_next_lun = FIND_FIRST_OAS_LUN; return count; } @@ -2561,7 +2569,7 @@ lpfc_oas_lun_state_set(struct lpfc_hba *phba, uint8_t vpt_wwpn[], rc = -ENOMEM; } else { lpfc_disable_oas_lun(phba, (struct lpfc_name *)vpt_wwpn, - (struct lpfc_name *)tgt_wwpn, lun); + (struct lpfc_name *)tgt_wwpn, lun, pri); } return rc; @@ -2585,7 +2593,8 @@ lpfc_oas_lun_state_set(struct lpfc_hba *phba, uint8_t vpt_wwpn[], */ static uint64_t lpfc_oas_lun_get_next(struct lpfc_hba *phba, uint8_t vpt_wwpn[], - uint8_t tgt_wwpn[], uint32_t *lun_status) + uint8_t tgt_wwpn[], uint32_t *lun_status, + uint32_t *lun_pri) { uint64_t found_lun; @@ -2598,7 +2607,7 @@ lpfc_oas_lun_get_next(struct lpfc_hba *phba, uint8_t vpt_wwpn[], &phba->sli4_hba.oas_next_lun, (struct lpfc_name *)vpt_wwpn, (struct lpfc_name *)tgt_wwpn, - &found_lun, lun_status)) + &found_lun, lun_status, lun_pri)) return found_lun; else return NOT_OAS_ENABLED_LUN; @@ -2670,7 +2679,8 @@ lpfc_oas_lun_show(struct device *dev, struct device_attribute *attr, oas_lun = lpfc_oas_lun_get_next(phba, phba->cfg_oas_vpt_wwpn, phba->cfg_oas_tgt_wwpn, - &phba->cfg_oas_lun_status); + &phba->cfg_oas_lun_status, + &phba->cfg_oas_priority); if (oas_lun != NOT_OAS_ENABLED_LUN) phba->cfg_oas_flags |= OAS_LUN_VALID; @@ -2701,6 +2711,7 @@ lpfc_oas_lun_store(struct device *dev, struct device_attribute *attr, struct Scsi_Host *shost = class_to_shost(dev); struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; uint64_t scsi_lun; + uint32_t pri; ssize_t rc; if (!phba->cfg_fof) @@ -2718,17 +2729,20 @@ lpfc_oas_lun_store(struct device *dev, struct device_attribute *attr, if (sscanf(buf, "0x%llx", &scsi_lun) != 1) return -EINVAL; + pri = phba->cfg_oas_priority; + if (pri == 0) + pri = phba->cfg_XLanePriority; + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "3372 Try to set vport 0x%llx target 0x%llx lun:0x%llx " "priority 0x%x with oas state %d\n", wwn_to_u64(phba->cfg_oas_vpt_wwpn), wwn_to_u64(phba->cfg_oas_tgt_wwpn), scsi_lun, - phba->cfg_oas_priority, phba->cfg_oas_lun_state); + pri, phba->cfg_oas_lun_state); rc = lpfc_oas_lun_state_change(phba, phba->cfg_oas_vpt_wwpn, phba->cfg_oas_tgt_wwpn, scsi_lun, - phba->cfg_oas_lun_state, - phba->cfg_oas_priority); + phba->cfg_oas_lun_state, pri); if (rc) return rc; @@ -4670,14 +4684,6 @@ LPFC_ATTR_R(sg_seg_cnt, LPFC_DEFAULT_SG_SEG_CNT, LPFC_DEFAULT_SG_SEG_CNT, LPFC_MAX_SG_SEG_CNT, "Max Scatter Gather Segment Count"); /* - * This parameter will be depricated, the driver cannot limit the - * protection data s/g list. - */ -LPFC_ATTR_R(prot_sg_seg_cnt, LPFC_DEFAULT_SG_SEG_CNT, - LPFC_DEFAULT_SG_SEG_CNT, LPFC_MAX_SG_SEG_CNT, - "Max Protection Scatter Gather Segment Count"); - -/* * lpfc_enable_mds_diags: Enable MDS Diagnostics * 0 = MDS Diagnostics disabled (default) * 1 = MDS Diagnostics enabled @@ -4766,7 +4772,6 @@ struct device_attribute *lpfc_hba_attrs[] = { &dev_attr_lpfc_sg_seg_cnt, &dev_attr_lpfc_max_scsicmpl_time, &dev_attr_lpfc_stat_data_ctrl, - &dev_attr_lpfc_prot_sg_seg_cnt, &dev_attr_lpfc_aer_support, &dev_attr_lpfc_aer_state_cleanup, &dev_attr_lpfc_sriov_nr_virtfn, @@ -5061,6 +5066,19 @@ lpfc_free_sysfs_attr(struct lpfc_vport *vport) */ /** + * lpfc_get_host_symbolic_name - Copy symbolic name into the scsi host + * @shost: kernel scsi host pointer. + **/ +static void +lpfc_get_host_symbolic_name(struct Scsi_Host *shost) +{ + struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata; + + lpfc_vport_symbolic_node_name(vport, fc_host_symbolic_name(shost), + sizeof fc_host_symbolic_name(shost)); +} + +/** * lpfc_get_host_port_id - Copy the vport DID into the scsi host port id * @shost: kernel scsi host pointer. **/ @@ -5597,6 +5615,8 @@ struct fc_function_template lpfc_transport_functions = { .show_host_supported_fc4s = 1, .show_host_supported_speeds = 1, .show_host_maxframe_size = 1, + + .get_host_symbolic_name = lpfc_get_host_symbolic_name, .show_host_symbolic_name = 1, /* dynamic attributes the driver supports */ @@ -5664,6 +5684,8 @@ struct fc_function_template lpfc_vport_transport_functions = { .show_host_supported_fc4s = 1, .show_host_supported_speeds = 1, .show_host_maxframe_size = 1, + + .get_host_symbolic_name = lpfc_get_host_symbolic_name, .show_host_symbolic_name = 1, /* dynamic attributes the driver supports */ @@ -5768,7 +5790,6 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) phba->cfg_soft_wwnn = 0L; phba->cfg_soft_wwpn = 0L; lpfc_sg_seg_cnt_init(phba, lpfc_sg_seg_cnt); - lpfc_prot_sg_seg_cnt_init(phba, lpfc_prot_sg_seg_cnt); lpfc_hba_queue_depth_init(phba, lpfc_hba_queue_depth); lpfc_hba_log_verbose_init(phba, lpfc_log_verbose); lpfc_aer_support_init(phba, lpfc_aer_support); diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 15d2bfdf582d..309643a2c55c 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -480,7 +480,7 @@ void lpfc_sli4_offline_eratt(struct lpfc_hba *); struct lpfc_device_data *lpfc_create_device_data(struct lpfc_hba *, struct lpfc_name *, struct lpfc_name *, - uint64_t, bool); + uint64_t, uint32_t, bool); void lpfc_delete_device_data(struct lpfc_hba *, struct lpfc_device_data*); struct lpfc_device_data *__lpfc_get_device_data(struct lpfc_hba *, struct list_head *list, @@ -489,9 +489,10 @@ struct lpfc_device_data *__lpfc_get_device_data(struct lpfc_hba *, bool lpfc_enable_oas_lun(struct lpfc_hba *, struct lpfc_name *, struct lpfc_name *, uint64_t, uint8_t); bool lpfc_disable_oas_lun(struct lpfc_hba *, struct lpfc_name *, - struct lpfc_name *, uint64_t); + struct lpfc_name *, uint64_t, uint8_t); bool lpfc_find_next_oas_lun(struct lpfc_hba *, struct lpfc_name *, struct lpfc_name *, uint64_t *, struct lpfc_name *, - struct lpfc_name *, uint64_t *, uint32_t *); + struct lpfc_name *, uint64_t *, + uint32_t *, uint32_t *); int lpfc_sli4_dump_page_a0(struct lpfc_hba *phba, struct lpfcMboxq *mbox); void lpfc_mbx_cmpl_rdp_page_a0(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb); diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 63bef4566548..3a1f1a2a2b55 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -1999,6 +1999,9 @@ lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry) if (sp->cmn.fcphHigh < FC_PH3) sp->cmn.fcphHigh = FC_PH3; + sp->cmn.valid_vendor_ver_level = 0; + memset(sp->vendorVersion, 0, sizeof(sp->vendorVersion)); + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, "Issue PLOGI: did:x%x", did, 0, 0); @@ -3990,6 +3993,9 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag, } else { memcpy(pcmd, &vport->fc_sparam, sizeof(struct serv_parm)); + + sp->cmn.valid_vendor_ver_level = 0; + memset(sp->vendorVersion, 0, sizeof(sp->vendorVersion)); } lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP, @@ -8851,8 +8857,7 @@ lpfc_cmpl_fabric_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, { struct ls_rjt stat; - if ((cmdiocb->iocb_flag & LPFC_IO_FABRIC) != LPFC_IO_FABRIC) - BUG(); + BUG_ON((cmdiocb->iocb_flag & LPFC_IO_FABRIC) != LPFC_IO_FABRIC); switch (rspiocb->iocb.ulpStatus) { case IOSTAT_NPORT_RJT: diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index 822654322e67..3b970d370600 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -360,6 +360,12 @@ struct csp { * Word 1 Bit 30 in PLOGI request is random offset */ #define virtual_fabric_support randomOffset /* Word 1, bit 30 */ +/* + * Word 1 Bit 29 in common service parameter is overloaded. + * Word 1 Bit 29 in FLOGI response is multiple NPort assignment + * Word 1 Bit 29 in FLOGI/PLOGI request is Valid Vendor Version Level + */ +#define valid_vendor_ver_level response_multiple_NPort /* Word 1, bit 29 */ #ifdef __BIG_ENDIAN_BITFIELD uint16_t request_multiple_Nport:1; /* FC Word 1, bit 31 */ uint16_t randomOffset:1; /* FC Word 1, bit 30 */ diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index ad350d969bdc..19d349fc889f 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -5452,7 +5452,9 @@ lpfc_slave_alloc(struct scsi_device *sdev) device_data = lpfc_create_device_data(phba, &vport->fc_portname, &target_wwpn, - sdev->lun, true); + sdev->lun, + phba->cfg_XLanePriority, + true); if (!device_data) return -ENOMEM; spin_lock_irqsave(&phba->devicelock, flags); @@ -5587,7 +5589,7 @@ lpfc_slave_destroy(struct scsi_device *sdev) struct lpfc_device_data* lpfc_create_device_data(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn, struct lpfc_name *target_wwpn, uint64_t lun, - bool atomic_create) + uint32_t pri, bool atomic_create) { struct lpfc_device_data *lun_info; @@ -5614,7 +5616,7 @@ lpfc_create_device_data(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn, sizeof(struct lpfc_name)); lun_info->device_id.lun = lun; lun_info->oas_enabled = false; - lun_info->priority = phba->cfg_XLanePriority; + lun_info->priority = pri; lun_info->available = false; return lun_info; } @@ -5716,7 +5718,8 @@ lpfc_find_next_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn, struct lpfc_name *found_vport_wwpn, struct lpfc_name *found_target_wwpn, uint64_t *found_lun, - uint32_t *found_lun_status) + uint32_t *found_lun_status, + uint32_t *found_lun_pri) { unsigned long flags; @@ -5763,6 +5766,7 @@ lpfc_find_next_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn, OAS_LUN_STATUS_EXISTS; else *found_lun_status = 0; + *found_lun_pri = lun_info->priority; if (phba->cfg_oas_flags & OAS_FIND_ANY_VPORT) memset(vport_wwpn, 0x0, sizeof(struct lpfc_name)); @@ -5824,13 +5828,14 @@ lpfc_enable_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn, if (lun_info) { if (!lun_info->oas_enabled) lun_info->oas_enabled = true; + lun_info->priority = pri; spin_unlock_irqrestore(&phba->devicelock, flags); return true; } /* Create an lun info structure and add to list of luns */ lun_info = lpfc_create_device_data(phba, vport_wwpn, target_wwpn, lun, - false); + pri, false); if (lun_info) { lun_info->oas_enabled = true; lun_info->priority = pri; @@ -5864,7 +5869,7 @@ lpfc_enable_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn, **/ bool lpfc_disable_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn, - struct lpfc_name *target_wwpn, uint64_t lun) + struct lpfc_name *target_wwpn, uint64_t lun, uint8_t pri) { struct lpfc_device_data *lun_info; @@ -5882,6 +5887,7 @@ lpfc_disable_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn, target_wwpn, lun); if (lun_info) { lun_info->oas_enabled = false; + lun_info->priority = pri; if (!lun_info->available) lpfc_delete_device_data(phba, lun_info); spin_unlock_irqrestore(&phba->devicelock, flags); diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index a78a3df68f67..d977a472f89f 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -120,6 +120,8 @@ lpfc_sli4_wq_put(struct lpfc_queue *q, union lpfc_wqe *wqe) if (q->phba->sli3_options & LPFC_SLI4_PHWQ_ENABLED) bf_set(wqe_wqid, &wqe->generic.wqe_com, q->queue_id); lpfc_sli_pcimem_bcopy(wqe, temp_wqe, q->entry_size); + /* ensure WQE bcopy flushed before doorbell write */ + wmb(); /* Update the host index before invoking device */ host_index = q->host_index; @@ -6313,7 +6315,8 @@ lpfc_set_host_data(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox) LPFC_SLI4_MBX_EMBED); mbox->u.mqe.un.set_host_data.param_id = LPFC_SET_HOST_OS_DRIVER_VERSION; - mbox->u.mqe.un.set_host_data.param_len = 8; + mbox->u.mqe.un.set_host_data.param_len = + LPFC_HOST_OS_DRIVER_VERSION_SIZE; snprintf(mbox->u.mqe.un.set_host_data.data, LPFC_HOST_OS_DRIVER_VERSION_SIZE, "Linux %s v"LPFC_DRIVER_VERSION, @@ -10035,6 +10038,7 @@ lpfc_sli_abort_iotag_issue(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, iabt->ulpCommand = CMD_CLOSE_XRI_CN; abtsiocbp->iocb_cmpl = lpfc_sli_abort_els_cmpl; + abtsiocbp->vport = vport; lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI, "0339 Abort xri x%x, original iotag x%x, " @@ -17226,7 +17230,8 @@ lpfc_drain_txq(struct lpfc_hba *phba) unsigned long iflags = 0; char *fail_msg = NULL; struct lpfc_sglq *sglq; - union lpfc_wqe wqe; + union lpfc_wqe128 wqe128; + union lpfc_wqe *wqe = (union lpfc_wqe *) &wqe128; uint32_t txq_cnt = 0; spin_lock_irqsave(&pring->ring_lock, iflags); @@ -17265,9 +17270,9 @@ lpfc_drain_txq(struct lpfc_hba *phba) piocbq->sli4_xritag = sglq->sli4_xritag; if (NO_XRI == lpfc_sli4_bpl2sgl(phba, piocbq, sglq)) fail_msg = "to convert bpl to sgl"; - else if (lpfc_sli4_iocb2wqe(phba, piocbq, &wqe)) + else if (lpfc_sli4_iocb2wqe(phba, piocbq, wqe)) fail_msg = "to convert iocb to wqe"; - else if (lpfc_sli4_wq_put(phba->sli4_hba.els_wq, &wqe)) + else if (lpfc_sli4_wq_put(phba->sli4_hba.els_wq, wqe)) fail_msg = " - Wq is full"; else lpfc_sli_ringtxcmpl_put(phba, pring, piocbq); diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index 50bfc43ebcb0..0ee0623a354c 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -18,7 +18,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "11.2.0.2" +#define LPFC_DRIVER_VERSION "11.2.0.4" #define LPFC_DRIVER_NAME "lpfc" /* Used for SLI 2/3 */ diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c index c27f4b724547..e18bbc66e83b 100644 --- a/drivers/scsi/lpfc/lpfc_vport.c +++ b/drivers/scsi/lpfc/lpfc_vport.c @@ -537,6 +537,12 @@ enable_vport(struct fc_vport *fc_vport) spin_lock_irq(shost->host_lock); vport->load_flag |= FC_LOADING; + if (vport->fc_flag & FC_VPORT_NEEDS_INIT_VPI) { + spin_unlock_irq(shost->host_lock); + lpfc_issue_init_vpi(vport); + goto out; + } + vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; spin_unlock_irq(shost->host_lock); @@ -557,6 +563,8 @@ enable_vport(struct fc_vport *fc_vport) } else { lpfc_vport_set_state(vport, FC_VPORT_FAILED); } + +out: lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT, "1827 Vport Enabled.\n"); return VPORT_OK; diff --git a/drivers/scsi/mac_scsi.c b/drivers/scsi/mac_scsi.c index ccb68d12692c..196acc79714b 100644 --- a/drivers/scsi/mac_scsi.c +++ b/drivers/scsi/mac_scsi.c @@ -154,7 +154,7 @@ __asm__ __volatile__ \ static inline int macscsi_pread(struct NCR5380_hostdata *hostdata, unsigned char *dst, int len) { - unsigned char *s = hostdata->pdma_io + (INPUT_DATA_REG << 4); + u8 __iomem *s = hostdata->pdma_io + (INPUT_DATA_REG << 4); unsigned char *d = dst; int n = len; int transferred; @@ -257,7 +257,7 @@ static inline int macscsi_pwrite(struct NCR5380_hostdata *hostdata, unsigned char *src, int len) { unsigned char *s = src; - unsigned char *d = hostdata->pdma_io + (OUTPUT_DATA_REG << 4); + u8 __iomem *d = hostdata->pdma_io + (OUTPUT_DATA_REG << 4); int n = len; int transferred; @@ -381,10 +381,10 @@ static int __init mac_scsi_probe(struct platform_device *pdev) hostdata = shost_priv(instance); hostdata->base = pio_mem->start; - hostdata->io = (void *)pio_mem->start; + hostdata->io = (u8 __iomem *)pio_mem->start; if (pdma_mem && setup_use_pdma) - hostdata->pdma_io = (void *)pdma_mem->start; + hostdata->pdma_io = (u8 __iomem *)pdma_mem->start; else host_flags |= FLAG_NO_PSEUDO_DMA; diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index fdd519c1dd57..ba9fbb71eb35 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -35,8 +35,8 @@ /* * MegaRAID SAS Driver meta data */ -#define MEGASAS_VERSION "06.812.07.00-rc1" -#define MEGASAS_RELDATE "August 22, 2016" +#define MEGASAS_VERSION "07.700.00.00-rc1" +#define MEGASAS_RELDATE "November 29, 2016" /* * Device IDs @@ -56,6 +56,11 @@ #define PCI_DEVICE_ID_LSI_INTRUDER_24 0x00cf #define PCI_DEVICE_ID_LSI_CUTLASS_52 0x0052 #define PCI_DEVICE_ID_LSI_CUTLASS_53 0x0053 +#define PCI_DEVICE_ID_LSI_VENTURA 0x0014 +#define PCI_DEVICE_ID_LSI_HARPOON 0x0016 +#define PCI_DEVICE_ID_LSI_TOMCAT 0x0017 +#define PCI_DEVICE_ID_LSI_VENTURA_4PORT 0x001B +#define PCI_DEVICE_ID_LSI_CRUSADER_4PORT 0x001C /* * Intel HBA SSDIDs @@ -100,7 +105,7 @@ */ /* - * MFI stands for MegaRAID SAS FW Interface. This is just a moniker for + * MFI stands for MegaRAID SAS FW Interface. This is just a moniker for * protocol between the software and firmware. Commands are issued using * "message frames" */ @@ -1312,7 +1317,55 @@ struct megasas_ctrl_info { #endif } adapterOperations3; - u8 pad[0x800-0x7EC]; + struct { +#if defined(__BIG_ENDIAN_BITFIELD) + u8 reserved:7; + /* Indicates whether the CPLD image is part of + * the package and stored in flash + */ + u8 cpld_in_flash:1; +#else + u8 cpld_in_flash:1; + u8 reserved:7; +#endif + u8 reserved1[3]; + /* Null terminated string. Has the version + * information if cpld_in_flash = FALSE + */ + u8 userCodeDefinition[12]; + } cpld; /* Valid only if upgradableCPLD is TRUE */ + + struct { + #if defined(__BIG_ENDIAN_BITFIELD) + u16 reserved:8; + u16 fw_swaps_bbu_vpd_info:1; + u16 support_pd_map_target_id:1; + u16 support_ses_ctrl_in_multipathcfg:1; + u16 image_upload_supported:1; + u16 support_encrypted_mfc:1; + u16 supported_enc_algo:1; + u16 support_ibutton_less:1; + u16 ctrl_info_ext_supported:1; + #else + + u16 ctrl_info_ext_supported:1; + u16 support_ibutton_less:1; + u16 supported_enc_algo:1; + u16 support_encrypted_mfc:1; + u16 image_upload_supported:1; + /* FW supports LUN based association and target port based */ + u16 support_ses_ctrl_in_multipathcfg:1; + /* association for the SES device connected in multipath mode */ + /* FW defines Jbod target Id within MR_PD_CFG_SEQ */ + u16 support_pd_map_target_id:1; + /* FW swaps relevant fields in MR_BBU_VPD_INFO_FIXED to + * provide the data in little endian order + */ + u16 fw_swaps_bbu_vpd_info:1; + u16 reserved:8; + #endif + } adapter_operations4; + u8 pad[0x800-0x7FE]; /* 0x7FE pad to 2K for expansion */ } __packed; /* @@ -1424,18 +1477,26 @@ enum FW_BOOT_CONTEXT { #define MFI_1068_FW_HANDSHAKE_OFFSET 0x64 #define MFI_1068_FW_READY 0xDDDD0000 +#define MEGASAS_RAID1_FAST_PATH_STATUS_CHECK_INTERVAL HZ + #define MR_MAX_REPLY_QUEUES_OFFSET 0X0000001F #define MR_MAX_REPLY_QUEUES_EXT_OFFSET 0X003FC000 #define MR_MAX_REPLY_QUEUES_EXT_OFFSET_SHIFT 14 #define MR_MAX_MSIX_REG_ARRAY 16 #define MR_RDPQ_MODE_OFFSET 0X00800000 + +#define MR_MAX_RAID_MAP_SIZE_OFFSET_SHIFT 16 +#define MR_MAX_RAID_MAP_SIZE_MASK 0x1FF +#define MR_MIN_MAP_SIZE 0x10000 +/* 64k */ + #define MR_CAN_HANDLE_SYNC_CACHE_OFFSET 0X01000000 /* * register set for both 1068 and 1078 controllers * structure extended for 1078 registers */ - + struct megasas_register_set { u32 doorbell; /*0000h*/ u32 fusion_seq_offset; /*0004h*/ @@ -1478,7 +1539,7 @@ struct megasas_register_set { u32 inbound_high_queue_port ; /*00C4h*/ - u32 reserved_5; /*00C8h*/ + u32 inbound_single_queue_port; /*00C8h*/ u32 res_6[11]; /*CCh*/ u32 host_diag; u32 seq_offset; @@ -1544,33 +1605,35 @@ union megasas_sgl_frame { typedef union _MFI_CAPABILITIES { struct { #if defined(__BIG_ENDIAN_BITFIELD) - u32 reserved:20; - u32 support_qd_throttling:1; - u32 support_fp_rlbypass:1; - u32 support_vfid_in_ioframe:1; - u32 support_ext_io_size:1; - u32 support_ext_queue_depth:1; - u32 security_protocol_cmds_fw:1; - u32 support_core_affinity:1; - u32 support_ndrive_r1_lb:1; - u32 support_max_255lds:1; - u32 support_fastpath_wb:1; - u32 support_additional_msix:1; - u32 support_fp_remote_lun:1; + u32 reserved:19; + u32 support_pd_map_target_id:1; + u32 support_qd_throttling:1; + u32 support_fp_rlbypass:1; + u32 support_vfid_in_ioframe:1; + u32 support_ext_io_size:1; + u32 support_ext_queue_depth:1; + u32 security_protocol_cmds_fw:1; + u32 support_core_affinity:1; + u32 support_ndrive_r1_lb:1; + u32 support_max_255lds:1; + u32 support_fastpath_wb:1; + u32 support_additional_msix:1; + u32 support_fp_remote_lun:1; #else - u32 support_fp_remote_lun:1; - u32 support_additional_msix:1; - u32 support_fastpath_wb:1; - u32 support_max_255lds:1; - u32 support_ndrive_r1_lb:1; - u32 support_core_affinity:1; - u32 security_protocol_cmds_fw:1; - u32 support_ext_queue_depth:1; - u32 support_ext_io_size:1; - u32 support_vfid_in_ioframe:1; - u32 support_fp_rlbypass:1; - u32 support_qd_throttling:1; - u32 reserved:20; + u32 support_fp_remote_lun:1; + u32 support_additional_msix:1; + u32 support_fastpath_wb:1; + u32 support_max_255lds:1; + u32 support_ndrive_r1_lb:1; + u32 support_core_affinity:1; + u32 security_protocol_cmds_fw:1; + u32 support_ext_queue_depth:1; + u32 support_ext_io_size:1; + u32 support_vfid_in_ioframe:1; + u32 support_fp_rlbypass:1; + u32 support_qd_throttling:1; + u32 support_pd_map_target_id:1; + u32 reserved:19; #endif } mfi_capabilities; __le32 reg; @@ -2039,6 +2102,7 @@ struct megasas_instance { u32 crash_dump_drv_support; u32 crash_dump_app_support; u32 secure_jbod_support; + u32 support_morethan256jbod; /* FW support for more than 256 PD/JBOD */ bool use_seqnum_jbod_fp; /* Added for PD sequence */ spinlock_t crashdump_lock; @@ -2051,6 +2115,7 @@ struct megasas_instance { u16 max_num_sge; u16 max_fw_cmds; + u16 max_mpt_cmds; u16 max_mfi_cmds; u16 max_scsi_cmds; u16 ldio_threshold; @@ -2065,6 +2130,7 @@ struct megasas_instance { /* used to sync fire the cmd to fw */ spinlock_t hba_lock; /* used to synch producer, consumer ptrs in dpc */ + spinlock_t stream_lock; spinlock_t completion_lock; struct dma_pool *frame_dma_pool; struct dma_pool *sense_dma_pool; @@ -2088,6 +2154,10 @@ struct megasas_instance { atomic_t ldio_outstanding; atomic_t fw_reset_no_pci_access; + atomic64_t bytes_wrote; /* used for raid1 fast path enable or disable */ + atomic_t r1_write_fp_capable; + + struct megasas_instance_template *instancet; struct tasklet_struct isr_tasklet; struct work_struct work_init; @@ -2129,6 +2199,7 @@ struct megasas_instance { long reset_flags; struct mutex reset_mutex; struct timer_list sriov_heartbeat_timer; + struct timer_list r1_fp_hold_timer; char skip_heartbeat_timer_del; u8 requestorId; char PlasmaFW111; @@ -2142,6 +2213,10 @@ struct megasas_instance { u8 is_rdpq; bool dev_handle; bool fw_sync_cache_support; + bool is_ventura; + bool msix_combined; + u16 max_raid_mapsize; + u64 pci_threshold_bandwidth; /* used to control the fp writes */ }; struct MR_LD_VF_MAP { u32 size; diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index d5cf15eb8c5e..70891a76ca86 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -155,6 +155,12 @@ static struct pci_device_id megasas_pci_table[] = { /* Intruder 24 port*/ {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_CUTLASS_52)}, {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_CUTLASS_53)}, + /* VENTURA */ + {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_VENTURA)}, + {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_HARPOON)}, + {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_TOMCAT)}, + {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_VENTURA_4PORT)}, + {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_CRUSADER_4PORT)}, {} }; @@ -1934,6 +1940,9 @@ void megaraid_sas_kill_hba(struct megasas_instance *instance) } /* Complete outstanding ioctls when adapter is killed */ megasas_complete_outstanding_ioctls(instance); + if (instance->is_ventura) + del_timer_sync(&instance->r1_fp_hold_timer); + } /** @@ -2432,6 +2441,24 @@ void megasas_sriov_heartbeat_handler(unsigned long instance_addr) } } +/*Handler for disabling/enabling raid 1 fast paths*/ +void megasas_change_r1_fp_status(unsigned long instance_addr) +{ + struct megasas_instance *instance = + (struct megasas_instance *)instance_addr; + if (atomic64_read(&instance->bytes_wrote) >= + instance->pci_threshold_bandwidth) { + + atomic64_set(&instance->bytes_wrote, 0); + atomic_set(&instance->r1_write_fp_capable, 0); + } else { + atomic64_set(&instance->bytes_wrote, 0); + atomic_set(&instance->r1_write_fp_capable, 1); + } + mod_timer(&instance->r1_fp_hold_timer, + jiffies + MEGASAS_RAID1_FAST_PATH_STATUS_CHECK_INTERVAL); +} + /** * megasas_wait_for_outstanding - Wait for all outstanding cmds * @instance: Adapter soft state @@ -4418,8 +4445,7 @@ megasas_ld_list_query(struct megasas_instance *instance, u8 query_type) static void megasas_update_ext_vd_details(struct megasas_instance *instance) { struct fusion_context *fusion; - u32 old_map_sz; - u32 new_map_sz; + u32 ventura_map_sz = 0; fusion = instance->ctrl_context; /* For MFI based controllers return dummy success */ @@ -4449,21 +4475,38 @@ static void megasas_update_ext_vd_details(struct megasas_instance *instance) instance->supportmax256vd ? "Extended VD(240 VD)firmware" : "Legacy(64 VD) firmware"); - old_map_sz = sizeof(struct MR_FW_RAID_MAP) + - (sizeof(struct MR_LD_SPAN_MAP) * - (instance->fw_supported_vd_count - 1)); - new_map_sz = sizeof(struct MR_FW_RAID_MAP_EXT); - fusion->drv_map_sz = sizeof(struct MR_DRV_RAID_MAP) + - (sizeof(struct MR_LD_SPAN_MAP) * - (instance->drv_supported_vd_count - 1)); - - fusion->max_map_sz = max(old_map_sz, new_map_sz); + if (instance->max_raid_mapsize) { + ventura_map_sz = instance->max_raid_mapsize * + MR_MIN_MAP_SIZE; /* 64k */ + fusion->current_map_sz = ventura_map_sz; + fusion->max_map_sz = ventura_map_sz; + } else { + fusion->old_map_sz = sizeof(struct MR_FW_RAID_MAP) + + (sizeof(struct MR_LD_SPAN_MAP) * + (instance->fw_supported_vd_count - 1)); + fusion->new_map_sz = sizeof(struct MR_FW_RAID_MAP_EXT); + fusion->max_map_sz = + max(fusion->old_map_sz, fusion->new_map_sz); - if (instance->supportmax256vd) - fusion->current_map_sz = new_map_sz; - else - fusion->current_map_sz = old_map_sz; + if (instance->supportmax256vd) + fusion->current_map_sz = fusion->new_map_sz; + else + fusion->current_map_sz = fusion->old_map_sz; + } + /* irrespective of FW raid maps, driver raid map is constant */ + fusion->drv_map_sz = sizeof(struct MR_DRV_RAID_MAP_ALL); + +#if VD_EXT_DEBUG + dev_info(&instance->pdev->dev, "instance->max_raid_mapsize 0x%x\n ", + instance->max_raid_mapsize); + dev_info(&instance->pdev->dev, "new_map_sz = 0x%x, old_map_sz = 0x%x\n", + fusion->new_map_sz, fusion->old_map_sz); + dev_info(&instance->pdev->dev, "ventura_map_sz = 0x%x, current_map_sz = 0x%x\n", + ventura_map_sz, fusion->current_map_sz); + dev_info(&instance->pdev->dev, "fusion->drv_map_sz =0x%x, size of driver raid map 0x%lx\n", + fusion->drv_map_sz, sizeof(struct MR_DRV_RAID_MAP_ALL)); +#endif } /** @@ -4533,6 +4576,7 @@ megasas_get_ctrl_info(struct megasas_instance *instance) le32_to_cpus((u32 *)&ctrl_info->properties.OnOffProperties); le32_to_cpus((u32 *)&ctrl_info->adapterOperations2); le32_to_cpus((u32 *)&ctrl_info->adapterOperations3); + le16_to_cpus((u16 *)&ctrl_info->adapter_operations4); /* Update the latest Ext VD info. * From Init path, store current firmware details. @@ -4542,6 +4586,8 @@ megasas_get_ctrl_info(struct megasas_instance *instance) megasas_update_ext_vd_details(instance); instance->use_seqnum_jbod_fp = ctrl_info->adapterOperations3.useSeqNumJbodFP; + instance->support_morethan256jbod = + ctrl_info->adapter_operations4.support_pd_map_target_id; /*Check whether controller is iMR or MR */ instance->is_imr = (ctrl_info->memory_size ? 0 : 1); @@ -4990,12 +5036,12 @@ static int megasas_init_fw(struct megasas_instance *instance) { u32 max_sectors_1; u32 max_sectors_2; - u32 tmp_sectors, msix_enable, scratch_pad_2; + u32 tmp_sectors, msix_enable, scratch_pad_2, scratch_pad_3; resource_size_t base_addr; struct megasas_register_set __iomem *reg_set; struct megasas_ctrl_info *ctrl_info = NULL; unsigned long bar_list; - int i, loop, fw_msix_count = 0; + int i, j, loop, fw_msix_count = 0; struct IOV_111 *iovPtr; struct fusion_context *fusion; @@ -5020,34 +5066,29 @@ static int megasas_init_fw(struct megasas_instance *instance) reg_set = instance->reg_set; - switch (instance->pdev->device) { - case PCI_DEVICE_ID_LSI_FUSION: - case PCI_DEVICE_ID_LSI_PLASMA: - case PCI_DEVICE_ID_LSI_INVADER: - case PCI_DEVICE_ID_LSI_FURY: - case PCI_DEVICE_ID_LSI_INTRUDER: - case PCI_DEVICE_ID_LSI_INTRUDER_24: - case PCI_DEVICE_ID_LSI_CUTLASS_52: - case PCI_DEVICE_ID_LSI_CUTLASS_53: + if (fusion) instance->instancet = &megasas_instance_template_fusion; - break; - case PCI_DEVICE_ID_LSI_SAS1078R: - case PCI_DEVICE_ID_LSI_SAS1078DE: - instance->instancet = &megasas_instance_template_ppc; - break; - case PCI_DEVICE_ID_LSI_SAS1078GEN2: - case PCI_DEVICE_ID_LSI_SAS0079GEN2: - instance->instancet = &megasas_instance_template_gen2; - break; - case PCI_DEVICE_ID_LSI_SAS0073SKINNY: - case PCI_DEVICE_ID_LSI_SAS0071SKINNY: - instance->instancet = &megasas_instance_template_skinny; - break; - case PCI_DEVICE_ID_LSI_SAS1064R: - case PCI_DEVICE_ID_DELL_PERC5: - default: - instance->instancet = &megasas_instance_template_xscale; - break; + else { + switch (instance->pdev->device) { + case PCI_DEVICE_ID_LSI_SAS1078R: + case PCI_DEVICE_ID_LSI_SAS1078DE: + instance->instancet = &megasas_instance_template_ppc; + break; + case PCI_DEVICE_ID_LSI_SAS1078GEN2: + case PCI_DEVICE_ID_LSI_SAS0079GEN2: + instance->instancet = &megasas_instance_template_gen2; + break; + case PCI_DEVICE_ID_LSI_SAS0073SKINNY: + case PCI_DEVICE_ID_LSI_SAS0071SKINNY: + instance->instancet = &megasas_instance_template_skinny; + break; + case PCI_DEVICE_ID_LSI_SAS1064R: + case PCI_DEVICE_ID_DELL_PERC5: + default: + instance->instancet = &megasas_instance_template_xscale; + instance->pd_list_not_supported = 1; + break; + } } if (megasas_transition_to_ready(instance, 0)) { @@ -5066,13 +5107,17 @@ static int megasas_init_fw(struct megasas_instance *instance) goto fail_ready_state; } - /* - * MSI-X host index 0 is common for all adapter. - * It is used for all MPT based Adapters. - */ - instance->reply_post_host_index_addr[0] = - (u32 __iomem *)((u8 __iomem *)instance->reg_set + - MPI2_REPLY_POST_HOST_INDEX_OFFSET); + if (instance->is_ventura) { + scratch_pad_3 = + readl(&instance->reg_set->outbound_scratch_pad_3); +#if VD_EXT_DEBUG + dev_info(&instance->pdev->dev, "scratch_pad3 0x%x\n", + scratch_pad_3); +#endif + instance->max_raid_mapsize = ((scratch_pad_3 >> + MR_MAX_RAID_MAP_SIZE_OFFSET_SHIFT) & + MR_MAX_RAID_MAP_SIZE_MASK); + } /* Check if MSI-X is supported while in ready state */ msix_enable = (instance->instancet->read_fw_status_reg(reg_set) & @@ -5092,6 +5137,9 @@ static int megasas_init_fw(struct megasas_instance *instance) instance->msix_vectors = ((scratch_pad_2 & MR_MAX_REPLY_QUEUES_EXT_OFFSET) >> MR_MAX_REPLY_QUEUES_EXT_OFFSET_SHIFT) + 1; + if (instance->msix_vectors > 16) + instance->msix_combined = true; + if (rdpq_enable) instance->is_rdpq = (scratch_pad_2 & MR_RDPQ_MODE_OFFSET) ? 1 : 0; @@ -5125,6 +5173,20 @@ static int megasas_init_fw(struct megasas_instance *instance) else instance->msix_vectors = 0; } + /* + * MSI-X host index 0 is common for all adapter. + * It is used for all MPT based Adapters. + */ + if (instance->msix_combined) { + instance->reply_post_host_index_addr[0] = + (u32 *)((u8 *)instance->reg_set + + MPI2_SUP_REPLY_POST_HOST_INDEX_OFFSET); + } else { + instance->reply_post_host_index_addr[0] = + (u32 *)((u8 *)instance->reg_set + + MPI2_REPLY_POST_HOST_INDEX_OFFSET); + } + i = pci_alloc_irq_vectors(instance->pdev, 1, 1, PCI_IRQ_LEGACY); if (i < 0) goto fail_setup_irqs; @@ -5177,6 +5239,36 @@ static int megasas_init_fw(struct megasas_instance *instance) } memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS); + + /* stream detection initialization */ + if (instance->is_ventura) { + fusion->stream_detect_by_ld = + kzalloc(sizeof(struct LD_STREAM_DETECT *) + * MAX_LOGICAL_DRIVES_EXT, + GFP_KERNEL); + if (!fusion->stream_detect_by_ld) { + dev_err(&instance->pdev->dev, + "unable to allocate stream detection for pool of LDs\n"); + goto fail_get_ld_pd_list; + } + for (i = 0; i < MAX_LOGICAL_DRIVES_EXT; ++i) { + fusion->stream_detect_by_ld[i] = + kmalloc(sizeof(struct LD_STREAM_DETECT), + GFP_KERNEL); + if (!fusion->stream_detect_by_ld[i]) { + dev_err(&instance->pdev->dev, + "unable to allocate stream detect by LD\n "); + for (j = 0; j < i; ++j) + kfree(fusion->stream_detect_by_ld[j]); + kfree(fusion->stream_detect_by_ld); + fusion->stream_detect_by_ld = NULL; + goto fail_get_ld_pd_list; + } + fusion->stream_detect_by_ld[i]->mru_bit_map + = MR_STREAM_BITMAP; + } + } + if (megasas_ld_list_query(instance, MR_LD_QUERY_TYPE_EXPOSED_TO_HOST)) megasas_get_ld_list(instance); @@ -5294,8 +5386,21 @@ static int megasas_init_fw(struct megasas_instance *instance) instance->skip_heartbeat_timer_del = 1; } + if (instance->is_ventura) { + atomic64_set(&instance->bytes_wrote, 0); + atomic_set(&instance->r1_write_fp_capable, 1); + megasas_start_timer(instance, + &instance->r1_fp_hold_timer, + megasas_change_r1_fp_status, + MEGASAS_RAID1_FAST_PATH_STATUS_CHECK_INTERVAL); + dev_info(&instance->pdev->dev, "starting the raid 1 fp timer with interval %d\n", + MEGASAS_RAID1_FAST_PATH_STATUS_CHECK_INTERVAL); + } + return 0; +fail_get_ld_pd_list: + instance->instancet->disable_intr(instance); fail_get_pd_list: instance->instancet->disable_intr(instance); fail_init_adapter: @@ -5714,6 +5819,12 @@ static int megasas_probe_one(struct pci_dev *pdev, instance->pdev = pdev; switch (instance->pdev->device) { + case PCI_DEVICE_ID_LSI_VENTURA: + case PCI_DEVICE_ID_LSI_HARPOON: + case PCI_DEVICE_ID_LSI_TOMCAT: + case PCI_DEVICE_ID_LSI_VENTURA_4PORT: + case PCI_DEVICE_ID_LSI_CRUSADER_4PORT: + instance->is_ventura = true; case PCI_DEVICE_ID_LSI_FUSION: case PCI_DEVICE_ID_LSI_PLASMA: case PCI_DEVICE_ID_LSI_INVADER: @@ -5738,6 +5849,8 @@ static int megasas_probe_one(struct pci_dev *pdev, if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) || (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA)) fusion->adapter_type = THUNDERBOLT_SERIES; + else if (instance->is_ventura) + fusion->adapter_type = VENTURA_SERIES; else fusion->adapter_type = INVADER_SERIES; } @@ -5823,6 +5936,7 @@ static int megasas_probe_one(struct pci_dev *pdev, spin_lock_init(&instance->mfi_pool_lock); spin_lock_init(&instance->hba_lock); + spin_lock_init(&instance->stream_lock); spin_lock_init(&instance->completion_lock); mutex_init(&instance->reset_mutex); @@ -6073,6 +6187,9 @@ megasas_suspend(struct pci_dev *pdev, pm_message_t state) if (instance->requestorId && !instance->skip_heartbeat_timer_del) del_timer_sync(&instance->sriov_heartbeat_timer); + if (instance->is_ventura) + del_timer_sync(&instance->r1_fp_hold_timer); + megasas_flush_cache(instance); megasas_shutdown_controller(instance, MR_DCMD_HIBERNATE_SHUTDOWN); @@ -6199,6 +6316,16 @@ megasas_resume(struct pci_dev *pdev) megasas_setup_jbod_map(instance); instance->unload = 0; + if (instance->is_ventura) { + atomic64_set(&instance->bytes_wrote, 0); + atomic_set(&instance->r1_write_fp_capable, 1); + megasas_start_timer(instance, + &instance->r1_fp_hold_timer, + megasas_change_r1_fp_status, + MEGASAS_RAID1_FAST_PATH_STATUS_CHECK_INTERVAL); + } + + /* * Initiate AEN (Asynchronous Event Notification) */ @@ -6287,6 +6414,9 @@ static void megasas_detach_one(struct pci_dev *pdev) if (instance->requestorId && !instance->skip_heartbeat_timer_del) del_timer_sync(&instance->sriov_heartbeat_timer); + if (instance->is_ventura) + del_timer_sync(&instance->r1_fp_hold_timer); + if (instance->fw_crash_state != UNAVAILABLE) megasas_free_host_crash_buffer(instance); scsi_remove_host(instance->host); @@ -6330,6 +6460,14 @@ skip_firing_dcmds: if (instance->msix_vectors) pci_free_irq_vectors(instance->pdev); + if (instance->is_ventura) { + for (i = 0; i < MAX_LOGICAL_DRIVES_EXT; ++i) + kfree(fusion->stream_detect_by_ld[i]); + kfree(fusion->stream_detect_by_ld); + fusion->stream_detect_by_ld = NULL; + } + + if (instance->ctrl_context) { megasas_release_fusion(instance); pd_seq_map_sz = sizeof(struct MR_PD_CFG_SEQ_NUM_SYNC) + diff --git a/drivers/scsi/megaraid/megaraid_sas_fp.c b/drivers/scsi/megaraid/megaraid_sas_fp.c index f237d0003df3..322a72b593e3 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fp.c +++ b/drivers/scsi/megaraid/megaraid_sas_fp.c @@ -179,18 +179,209 @@ void MR_PopulateDrvRaidMap(struct megasas_instance *instance) struct fusion_context *fusion = instance->ctrl_context; struct MR_FW_RAID_MAP_ALL *fw_map_old = NULL; struct MR_FW_RAID_MAP *pFwRaidMap = NULL; - int i; + int i, j; u16 ld_count; + struct MR_FW_RAID_MAP_DYNAMIC *fw_map_dyn; + struct MR_FW_RAID_MAP_EXT *fw_map_ext; + struct MR_RAID_MAP_DESC_TABLE *desc_table; struct MR_DRV_RAID_MAP_ALL *drv_map = fusion->ld_drv_map[(instance->map_id & 1)]; struct MR_DRV_RAID_MAP *pDrvRaidMap = &drv_map->raidMap; + void *raid_map_data = NULL; + + memset(drv_map, 0, fusion->drv_map_sz); + memset(pDrvRaidMap->ldTgtIdToLd, + 0xff, (sizeof(u16) * MAX_LOGICAL_DRIVES_DYN)); + + if (instance->max_raid_mapsize) { + fw_map_dyn = fusion->ld_map[(instance->map_id & 1)]; + if (fw_map_dyn->pci_threshold_bandwidth) + instance->pci_threshold_bandwidth = + le64_to_cpu(fw_map_dyn->pci_threshold_bandwidth); +#if VD_EXT_DEBUG + dev_dbg(&instance->pdev->dev, "raidMapSize 0x%x fw_map_dyn->descTableOffset 0x%x\n", + le32_to_cpu(fw_map_dyn->raid_map_size), + le32_to_cpu(fw_map_dyn->desc_table_offset)); + dev_dbg(&instance->pdev->dev, "descTableSize 0x%x descTableNumElements 0x%x\n", + le32_to_cpu(fw_map_dyn->desc_table_size), + le32_to_cpu(fw_map_dyn->desc_table_num_elements)); + dev_dbg(&instance->pdev->dev, "PCIThreasholdBandwidth %llu\n", + instance->pci_threshold_bandwidth); + dev_dbg(&instance->pdev->dev, "drv map %p ldCount %d\n", + drv_map, fw_map_dyn->ld_count); +#endif + desc_table = + (struct MR_RAID_MAP_DESC_TABLE *)((void *)fw_map_dyn + le32_to_cpu(fw_map_dyn->desc_table_offset)); + if (desc_table != fw_map_dyn->raid_map_desc_table) + dev_dbg(&instance->pdev->dev, "offsets of desc table are not matching desc %p original %p\n", + desc_table, fw_map_dyn->raid_map_desc_table); + + ld_count = (u16)le16_to_cpu(fw_map_dyn->ld_count); + pDrvRaidMap->ldCount = (__le16)cpu_to_le16(ld_count); + pDrvRaidMap->fpPdIoTimeoutSec = + fw_map_dyn->fp_pd_io_timeout_sec; + pDrvRaidMap->totalSize = sizeof(struct MR_DRV_RAID_MAP_ALL); + /* point to actual data starting point*/ + raid_map_data = (void *)fw_map_dyn + + le32_to_cpu(fw_map_dyn->desc_table_offset) + + le32_to_cpu(fw_map_dyn->desc_table_size); + + for (i = 0; i < le32_to_cpu(fw_map_dyn->desc_table_num_elements); ++i) { + +#if VD_EXT_DEBUG + dev_dbg(&instance->pdev->dev, "desc table %p\n", + desc_table); + dev_dbg(&instance->pdev->dev, "raidmap type %d, raidmapOffset 0x%x\n", + desc_table->raid_map_desc_type, + desc_table->raid_map_desc_offset); + dev_dbg(&instance->pdev->dev, "raid map number of elements 0%x, raidmapsize 0x%x\n", + desc_table->raid_map_desc_elements, + desc_table->raid_map_desc_buffer_size); +#endif + switch (le32_to_cpu(desc_table->raid_map_desc_type)) { + case RAID_MAP_DESC_TYPE_DEVHDL_INFO: + fw_map_dyn->dev_hndl_info = + (struct MR_DEV_HANDLE_INFO *)(raid_map_data + le32_to_cpu(desc_table->raid_map_desc_offset)); +#if VD_EXT_DEBUG + dev_dbg(&instance->pdev->dev, "devHndlInfo address %p\n", + fw_map_dyn->dev_hndl_info); +#endif + memcpy(pDrvRaidMap->devHndlInfo, + fw_map_dyn->dev_hndl_info, + sizeof(struct MR_DEV_HANDLE_INFO) * + le32_to_cpu(desc_table->raid_map_desc_elements)); + break; + case RAID_MAP_DESC_TYPE_TGTID_INFO: + fw_map_dyn->ld_tgt_id_to_ld = + (u16 *) (raid_map_data + + le32_to_cpu(desc_table->raid_map_desc_offset)); +#if VD_EXT_DEBUG + dev_dbg(&instance->pdev->dev, "ldTgtIdToLd address %p\n", + fw_map_dyn->ld_tgt_id_to_ld); +#endif + for (j = 0; j < le32_to_cpu(desc_table->raid_map_desc_elements); j++) { + pDrvRaidMap->ldTgtIdToLd[j] = + fw_map_dyn->ld_tgt_id_to_ld[j]; +#if VD_EXT_DEBUG + dev_dbg(&instance->pdev->dev, " %d drv ldTgtIdToLd %d\n", + j, pDrvRaidMap->ldTgtIdToLd[j]); +#endif + } + break; + case RAID_MAP_DESC_TYPE_ARRAY_INFO: + fw_map_dyn->ar_map_info = + (struct MR_ARRAY_INFO *) + (raid_map_data + le32_to_cpu(desc_table->raid_map_desc_offset)); +#if VD_EXT_DEBUG + dev_dbg(&instance->pdev->dev, "arMapInfo address %p\n", + fw_map_dyn->ar_map_info); +#endif + + memcpy(pDrvRaidMap->arMapInfo, + fw_map_dyn->ar_map_info, + sizeof(struct MR_ARRAY_INFO) * le32_to_cpu(desc_table->raid_map_desc_elements)); + break; + case RAID_MAP_DESC_TYPE_SPAN_INFO: + fw_map_dyn->ld_span_map = + (struct MR_LD_SPAN_MAP *) + (raid_map_data + le32_to_cpu(desc_table->raid_map_desc_offset)); + memcpy(pDrvRaidMap->ldSpanMap, + fw_map_dyn->ld_span_map, + sizeof(struct MR_LD_SPAN_MAP) * le32_to_cpu(desc_table->raid_map_desc_elements)); +#if VD_EXT_DEBUG + dev_dbg(&instance->pdev->dev, "ldSpanMap address %p\n", + fw_map_dyn->ld_span_map); + dev_dbg(&instance->pdev->dev, "MR_LD_SPAN_MAP size 0x%lx\n", + sizeof(struct MR_LD_SPAN_MAP)); + for (j = 0; j < ld_count; j++) { + dev_dbg(&instance->pdev->dev, "megaraid_sas(%d) : fw_map_dyn->ldSpanMap[%d].ldRaid.targetId 0x%x\n", + j, j, fw_map_dyn->ld_span_map[j].ldRaid.targetId); + dev_dbg(&instance->pdev->dev, "fw_map_dyn->ldSpanMap[%d].ldRaid.seqNum 0x%x\n", + j, fw_map_dyn->ld_span_map[j].ldRaid.seqNum); + dev_dbg(&instance->pdev->dev, "fw_map_dyn->ld_span_map[%d].ldRaid.rowSize 0x%x\n", + j, (u32)fw_map_dyn->ld_span_map[j].ldRaid.rowSize); + + dev_dbg(&instance->pdev->dev, "megaraid_sas(%d) :pDrvRaidMap->ldSpanMap[%d].ldRaid.targetId 0x%x\n", + j, j, pDrvRaidMap->ldSpanMap[j].ldRaid.targetId); + dev_dbg(&instance->pdev->dev, "DrvRaidMap->ldSpanMap[%d].ldRaid.seqNum 0x%x\n", + j, pDrvRaidMap->ldSpanMap[j].ldRaid.seqNum); + dev_dbg(&instance->pdev->dev, "pDrvRaidMap->ldSpanMap[%d].ldRaid.rowSize 0x%x\n", + j, (u32)pDrvRaidMap->ldSpanMap[j].ldRaid.rowSize); + + dev_dbg(&instance->pdev->dev, "megaraid_sas(%d) : drv raid map all %p\n", + instance->unique_id, drv_map); + dev_dbg(&instance->pdev->dev, "raid map %p LD RAID MAP %p/%p\n", + pDrvRaidMap, + &fw_map_dyn->ld_span_map[j].ldRaid, + &pDrvRaidMap->ldSpanMap[j].ldRaid); + } +#endif + break; + default: + dev_dbg(&instance->pdev->dev, "wrong number of desctableElements %d\n", + fw_map_dyn->desc_table_num_elements); + } + ++desc_table; + } + + } else if (instance->supportmax256vd) { + fw_map_ext = + (struct MR_FW_RAID_MAP_EXT *) fusion->ld_map[(instance->map_id & 1)]; + ld_count = (u16)le16_to_cpu(fw_map_ext->ldCount); + if (ld_count > MAX_LOGICAL_DRIVES_EXT) { + dev_dbg(&instance->pdev->dev, "megaraid_sas: LD count exposed in RAID map in not valid\n"); + return; + } +#if VD_EXT_DEBUG + for (i = 0; i < ld_count; i++) { + dev_dbg(&instance->pdev->dev, "megaraid_sas(%d) :Index 0x%x\n", + instance->unique_id, i); + dev_dbg(&instance->pdev->dev, "Target Id 0x%x\n", + fw_map_ext->ldSpanMap[i].ldRaid.targetId); + dev_dbg(&instance->pdev->dev, "Seq Num 0x%x Size 0/%llx\n", + fw_map_ext->ldSpanMap[i].ldRaid.seqNum, + fw_map_ext->ldSpanMap[i].ldRaid.size); + } +#endif + + pDrvRaidMap->ldCount = (__le16)cpu_to_le16(ld_count); + pDrvRaidMap->fpPdIoTimeoutSec = fw_map_ext->fpPdIoTimeoutSec; + for (i = 0; i < (MAX_LOGICAL_DRIVES_EXT); i++) + pDrvRaidMap->ldTgtIdToLd[i] = + (u16)fw_map_ext->ldTgtIdToLd[i]; + memcpy(pDrvRaidMap->ldSpanMap, fw_map_ext->ldSpanMap, + sizeof(struct MR_LD_SPAN_MAP) * ld_count); +#if VD_EXT_DEBUG + for (i = 0; i < ld_count; i++) { + dev_dbg(&instance->pdev->dev, "megaraid_sas(%d) : fw_map_ext->ldSpanMap[%d].ldRaid.targetId 0x%x\n", + i, i, fw_map_ext->ldSpanMap[i].ldRaid.targetId); + dev_dbg(&instance->pdev->dev, "fw_map_ext->ldSpanMap[%d].ldRaid.seqNum 0x%x\n", + i, fw_map_ext->ldSpanMap[i].ldRaid.seqNum); + dev_dbg(&instance->pdev->dev, "fw_map_ext->ldSpanMap[%d].ldRaid.rowSize 0x%x\n", + i, (u32)fw_map_ext->ldSpanMap[i].ldRaid.rowSize); + + dev_dbg(&instance->pdev->dev, "megaraid_sas(%d) : pDrvRaidMap->ldSpanMap[%d].ldRaid.targetId 0x%x\n", + i, i, pDrvRaidMap->ldSpanMap[i].ldRaid.targetId); + dev_dbg(&instance->pdev->dev, "pDrvRaidMap->ldSpanMap[%d].ldRaid.seqNum 0x%x\n", + i, pDrvRaidMap->ldSpanMap[i].ldRaid.seqNum); + dev_dbg(&instance->pdev->dev, "pDrvRaidMap->ldSpanMap[%d].ldRaid.rowSize 0x%x\n", + i, (u32)pDrvRaidMap->ldSpanMap[i].ldRaid.rowSize); + + dev_dbg(&instance->pdev->dev, "megaraid_sas(%d) : drv raid map all %p\n", + instance->unique_id, drv_map); + dev_dbg(&instance->pdev->dev, "raid map %p LD RAID MAP %p %p\n", + pDrvRaidMap, &fw_map_ext->ldSpanMap[i].ldRaid, + &pDrvRaidMap->ldSpanMap[i].ldRaid); + } +#endif + memcpy(pDrvRaidMap->arMapInfo, fw_map_ext->arMapInfo, + sizeof(struct MR_ARRAY_INFO) * MAX_API_ARRAYS_EXT); + memcpy(pDrvRaidMap->devHndlInfo, fw_map_ext->devHndlInfo, + sizeof(struct MR_DEV_HANDLE_INFO) * + MAX_RAIDMAP_PHYSICAL_DEVICES); - if (instance->supportmax256vd) { - memcpy(fusion->ld_drv_map[instance->map_id & 1], - fusion->ld_map[instance->map_id & 1], - fusion->current_map_sz); /* New Raid map will not set totalSize, so keep expected value * for legacy code in ValidateMapInfo */ @@ -213,16 +404,12 @@ void MR_PopulateDrvRaidMap(struct megasas_instance *instance) } #endif - memset(drv_map, 0, fusion->drv_map_sz); pDrvRaidMap->totalSize = pFwRaidMap->totalSize; pDrvRaidMap->ldCount = (__le16)cpu_to_le16(ld_count); pDrvRaidMap->fpPdIoTimeoutSec = pFwRaidMap->fpPdIoTimeoutSec; for (i = 0; i < MAX_RAIDMAP_LOGICAL_DRIVES + MAX_RAIDMAP_VIEWS; i++) pDrvRaidMap->ldTgtIdToLd[i] = (u8)pFwRaidMap->ldTgtIdToLd[i]; - for (i = (MAX_RAIDMAP_LOGICAL_DRIVES + MAX_RAIDMAP_VIEWS); - i < MAX_LOGICAL_DRIVES_EXT; i++) - pDrvRaidMap->ldTgtIdToLd[i] = 0xff; for (i = 0; i < ld_count; i++) { pDrvRaidMap->ldSpanMap[i] = pFwRaidMap->ldSpanMap[i]; #if VD_EXT_DEBUG @@ -252,6 +439,8 @@ void MR_PopulateDrvRaidMap(struct megasas_instance *instance) sizeof(struct MR_DEV_HANDLE_INFO) * MAX_RAIDMAP_PHYSICAL_DEVICES); } + if (instance->is_ventura && !instance->pci_threshold_bandwidth) + instance->pci_threshold_bandwidth = ULLONG_MAX; } /* @@ -279,7 +468,9 @@ u8 MR_ValidateMapInfo(struct megasas_instance *instance) lbInfo = fusion->load_balance_info; ldSpanInfo = fusion->log_to_span; - if (instance->supportmax256vd) + if (instance->max_raid_mapsize) + expected_size = sizeof(struct MR_DRV_RAID_MAP_ALL); + else if (instance->supportmax256vd) expected_size = sizeof(struct MR_FW_RAID_MAP_EXT); else expected_size = @@ -287,8 +478,10 @@ u8 MR_ValidateMapInfo(struct megasas_instance *instance) (sizeof(struct MR_LD_SPAN_MAP) * le16_to_cpu(pDrvRaidMap->ldCount))); if (le32_to_cpu(pDrvRaidMap->totalSize) != expected_size) { - dev_err(&instance->pdev->dev, "map info structure size 0x%x is not matching with ld count\n", - (unsigned int) expected_size); + dev_dbg(&instance->pdev->dev, "megasas: map info structure size 0x%x", + le32_to_cpu(pDrvRaidMap->totalSize)); + dev_dbg(&instance->pdev->dev, "is not matching expected size 0x%x\n", + (unsigned int) expected_size); dev_err(&instance->pdev->dev, "megasas: span map %x, pDrvRaidMap->totalSize : %x\n", (unsigned int)sizeof(struct MR_LD_SPAN_MAP), le32_to_cpu(pDrvRaidMap->totalSize)); @@ -737,7 +930,7 @@ static u8 mr_spanset_get_phy_params(struct megasas_instance *instance, u32 ld, struct MR_DRV_RAID_MAP_ALL *map) { struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map); - u32 pd, arRef; + u32 pd, arRef, r1_alt_pd; u8 physArm, span; u64 row; u8 retval = TRUE; @@ -772,15 +965,22 @@ static u8 mr_spanset_get_phy_params(struct megasas_instance *instance, u32 ld, arRef = MR_LdSpanArrayGet(ld, span, map); pd = MR_ArPdGet(arRef, physArm, map); - if (pd != MR_PD_INVALID) + if (pd != MR_PD_INVALID) { *pDevHandle = MR_PdDevHandleGet(pd, map); - else { + /* get second pd also for raid 1/10 fast path writes*/ + if (raid->level == 1) { + r1_alt_pd = MR_ArPdGet(arRef, physArm + 1, map); + if (r1_alt_pd != MR_PD_INVALID) + io_info->r1_alt_dev_handle = + MR_PdDevHandleGet(r1_alt_pd, map); + } + } else { *pDevHandle = cpu_to_le16(MR_PD_INVALID); if ((raid->level >= 5) && ((fusion->adapter_type == THUNDERBOLT_SERIES) || ((fusion->adapter_type == INVADER_SERIES) && (raid->regTypeReqOnRead != REGION_TYPE_UNUSED)))) - pRAID_Context->regLockFlags = REGION_TYPE_EXCLUSIVE; + pRAID_Context->reg_lock_flags = REGION_TYPE_EXCLUSIVE; else if (raid->level == 1) { physArm = physArm + 1; pd = MR_ArPdGet(arRef, physArm, map); @@ -790,9 +990,16 @@ static u8 mr_spanset_get_phy_params(struct megasas_instance *instance, u32 ld, } *pdBlock += stripRef + le64_to_cpu(MR_LdSpanPtrGet(ld, span, map)->startBlk); - pRAID_Context->spanArm = (span << RAID_CTX_SPANARM_SPAN_SHIFT) | - physArm; - io_info->span_arm = pRAID_Context->spanArm; + if (instance->is_ventura) { + ((struct RAID_CONTEXT_G35 *) pRAID_Context)->span_arm = + (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm; + io_info->span_arm = + (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm; + } else { + pRAID_Context->span_arm = + (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm; + io_info->span_arm = pRAID_Context->span_arm; + } return retval; } @@ -819,7 +1026,7 @@ u8 MR_GetPhyParams(struct megasas_instance *instance, u32 ld, u64 stripRow, struct MR_DRV_RAID_MAP_ALL *map) { struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map); - u32 pd, arRef; + u32 pd, arRef, r1_alt_pd; u8 physArm, span; u64 row; u8 retval = TRUE; @@ -867,17 +1074,24 @@ u8 MR_GetPhyParams(struct megasas_instance *instance, u32 ld, u64 stripRow, arRef = MR_LdSpanArrayGet(ld, span, map); pd = MR_ArPdGet(arRef, physArm, map); /* Get the pd */ - if (pd != MR_PD_INVALID) + if (pd != MR_PD_INVALID) { /* Get dev handle from Pd. */ *pDevHandle = MR_PdDevHandleGet(pd, map); - else { + /* get second pd also for raid 1/10 fast path writes*/ + if (raid->level == 1) { + r1_alt_pd = MR_ArPdGet(arRef, physArm + 1, map); + if (r1_alt_pd != MR_PD_INVALID) + io_info->r1_alt_dev_handle = + MR_PdDevHandleGet(r1_alt_pd, map); + } + } else { /* set dev handle as invalid. */ *pDevHandle = cpu_to_le16(MR_PD_INVALID); if ((raid->level >= 5) && ((fusion->adapter_type == THUNDERBOLT_SERIES) || ((fusion->adapter_type == INVADER_SERIES) && (raid->regTypeReqOnRead != REGION_TYPE_UNUSED)))) - pRAID_Context->regLockFlags = REGION_TYPE_EXCLUSIVE; + pRAID_Context->reg_lock_flags = REGION_TYPE_EXCLUSIVE; else if (raid->level == 1) { /* Get alternate Pd. */ physArm = physArm + 1; @@ -889,9 +1103,16 @@ u8 MR_GetPhyParams(struct megasas_instance *instance, u32 ld, u64 stripRow, } *pdBlock += stripRef + le64_to_cpu(MR_LdSpanPtrGet(ld, span, map)->startBlk); - pRAID_Context->spanArm = (span << RAID_CTX_SPANARM_SPAN_SHIFT) | - physArm; - io_info->span_arm = pRAID_Context->spanArm; + if (instance->is_ventura) { + ((struct RAID_CONTEXT_G35 *) pRAID_Context)->span_arm = + (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm; + io_info->span_arm = + (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm; + } else { + pRAID_Context->span_arm = + (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm; + io_info->span_arm = pRAID_Context->span_arm; + } return retval; } @@ -935,6 +1156,8 @@ MR_BuildRaidContext(struct megasas_instance *instance, ld = MR_TargetIdToLdGet(ldTgtId, map); raid = MR_LdRaidGet(ld, map); + /*check read ahead bit*/ + io_info->ra_capable = raid->capability.ra_capable; /* * if rowDataSize @RAID map and spanRowDataSize @SPAN INFO are zero @@ -1093,20 +1316,20 @@ MR_BuildRaidContext(struct megasas_instance *instance, regSize += stripSize; } - pRAID_Context->timeoutValue = + pRAID_Context->timeout_value = cpu_to_le16(raid->fpIoTimeoutForLd ? raid->fpIoTimeoutForLd : map->raidMap.fpPdIoTimeoutSec); if (fusion->adapter_type == INVADER_SERIES) - pRAID_Context->regLockFlags = (isRead) ? + pRAID_Context->reg_lock_flags = (isRead) ? raid->regTypeReqOnRead : raid->regTypeReqOnWrite; - else - pRAID_Context->regLockFlags = (isRead) ? + else if (!instance->is_ventura) + pRAID_Context->reg_lock_flags = (isRead) ? REGION_TYPE_SHARED_READ : raid->regTypeReqOnWrite; - pRAID_Context->VirtualDiskTgtId = raid->targetId; - pRAID_Context->regLockRowLBA = cpu_to_le64(regStart); - pRAID_Context->regLockLength = cpu_to_le32(regSize); - pRAID_Context->configSeqNum = raid->seqNum; + pRAID_Context->virtual_disk_tgt_id = raid->targetId; + pRAID_Context->reg_lock_row_lba = cpu_to_le64(regStart); + pRAID_Context->reg_lock_length = cpu_to_le32(regSize); + pRAID_Context->config_seq_num = raid->seqNum; /* save pointer to raid->LUN array */ *raidLUN = raid->LUN; @@ -1124,6 +1347,18 @@ MR_BuildRaidContext(struct megasas_instance *instance, /* If IO on an invalid Pd, then FP is not possible.*/ if (io_info->devHandle == cpu_to_le16(MR_PD_INVALID)) io_info->fpOkForIo = FALSE; + /* if FP possible, set the SLUD bit in + * regLockFlags for ventura + */ + else if ((instance->is_ventura) && (!isRead) && + (raid->writeMode == MR_RL_WRITE_BACK_MODE) && + (raid->capability.fp_cache_bypass_capable)) + ((struct RAID_CONTEXT_G35 *) pRAID_Context)->routing_flags.bits.sld = 1; + /* set raid 1/10 fast path write capable bit in io_info */ + if (io_info->fpOkForIo && + (io_info->r1_alt_dev_handle != MR_PD_INVALID) && + (raid->level == 1) && !isRead) + io_info->is_raid_1_fp_write = 1; return retval; } else if (isRead) { uint stripIdx; @@ -1298,6 +1533,7 @@ u8 megasas_get_best_arm_pd(struct megasas_instance *instance, struct fusion_context *fusion; struct MR_LD_RAID *raid; struct MR_DRV_RAID_MAP_ALL *drv_map; + u16 pd1_dev_handle; u16 pend0, pend1, ld; u64 diff0, diff1; u8 bestArm, pd0, pd1, span, arm; @@ -1323,23 +1559,36 @@ u8 megasas_get_best_arm_pd(struct megasas_instance *instance, pd1 = MR_ArPdGet(arRef, (arm + 1) >= span_row_size ? (arm + 1 - span_row_size) : arm + 1, drv_map); - /* get the pending cmds for the data and mirror arms */ - pend0 = atomic_read(&lbInfo->scsi_pending_cmds[pd0]); - pend1 = atomic_read(&lbInfo->scsi_pending_cmds[pd1]); + /* Get PD1 Dev Handle */ + + pd1_dev_handle = MR_PdDevHandleGet(pd1, drv_map); + + if (pd1_dev_handle == MR_PD_INVALID) { + bestArm = arm; + } else { + /* get the pending cmds for the data and mirror arms */ + pend0 = atomic_read(&lbInfo->scsi_pending_cmds[pd0]); + pend1 = atomic_read(&lbInfo->scsi_pending_cmds[pd1]); - /* Determine the disk whose head is nearer to the req. block */ - diff0 = ABS_DIFF(block, lbInfo->last_accessed_block[pd0]); - diff1 = ABS_DIFF(block, lbInfo->last_accessed_block[pd1]); - bestArm = (diff0 <= diff1 ? arm : arm ^ 1); + /* Determine the disk whose head is nearer to the req. block */ + diff0 = ABS_DIFF(block, lbInfo->last_accessed_block[pd0]); + diff1 = ABS_DIFF(block, lbInfo->last_accessed_block[pd1]); + bestArm = (diff0 <= diff1 ? arm : arm ^ 1); - if ((bestArm == arm && pend0 > pend1 + lb_pending_cmds) || + /* Make balance count from 16 to 4 to + * keep driver in sync with Firmware + */ + if ((bestArm == arm && pend0 > pend1 + lb_pending_cmds) || (bestArm != arm && pend1 > pend0 + lb_pending_cmds)) - bestArm ^= 1; + bestArm ^= 1; + + /* Update the last accessed block on the correct pd */ + io_info->span_arm = + (span << RAID_CTX_SPANARM_SPAN_SHIFT) | bestArm; + io_info->pd_after_lb = (bestArm == arm) ? pd0 : pd1; + } - /* Update the last accessed block on the correct pd */ - io_info->pd_after_lb = (bestArm == arm) ? pd0 : pd1; lbInfo->last_accessed_block[io_info->pd_after_lb] = block + count - 1; - io_info->span_arm = (span << RAID_CTX_SPANARM_SPAN_SHIFT) | bestArm; #if SPAN_DEBUG if (arm != bestArm) dev_dbg(&instance->pdev->dev, "LSI Debug R1 Load balance " diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index 24778ba4b6e8..9a9c84fb91b1 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -95,6 +95,7 @@ extern unsigned int resetwaittime; extern unsigned int dual_qdepth_disable; static void megasas_free_rdpq_fusion(struct megasas_instance *instance); static void megasas_free_reply_fusion(struct megasas_instance *instance); +void megasas_change_r1_fp_status(unsigned long instance_addr); @@ -189,15 +190,29 @@ inline void megasas_return_cmd_fusion(struct megasas_instance *instance, */ static void megasas_fire_cmd_fusion(struct megasas_instance *instance, - union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc) + union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc, bool is_32bit) { + struct megasas_register_set __iomem *regs = instance->reg_set; + unsigned long flags; + + if (is_32bit) + writel(le32_to_cpu(req_desc->u.low), + &(regs)->inbound_single_queue_port); + else if (instance->is_ventura) { + spin_lock_irqsave(&instance->hba_lock, flags); + writel(le32_to_cpu(req_desc->u.low), + &(regs)->inbound_low_queue_port); + writel(le32_to_cpu(req_desc->u.high), + &(regs)->inbound_high_queue_port); + mmiowb(); + spin_unlock_irqrestore(&instance->hba_lock, flags); + } else { #if defined(writeq) && defined(CONFIG_64BIT) u64 req_data = (((u64)le32_to_cpu(req_desc->u.high) << 32) | le32_to_cpu(req_desc->u.low)); writeq(req_data, &instance->reg_set->inbound_low_queue_port); #else - unsigned long flags; spin_lock_irqsave(&instance->hba_lock, flags); writel(le32_to_cpu(req_desc->u.low), @@ -207,6 +222,7 @@ megasas_fire_cmd_fusion(struct megasas_instance *instance, mmiowb(); spin_unlock_irqrestore(&instance->hba_lock, flags); #endif + } } /** @@ -229,7 +245,10 @@ megasas_fusion_update_can_queue(struct megasas_instance *instance, int fw_boot_c reg_set = instance->reg_set; - cur_max_fw_cmds = readl(&instance->reg_set->outbound_scratch_pad_3) & 0x00FFFF; + /* ventura FW does not fill outbound_scratch_pad_3 with queue depth */ + if (!instance->is_ventura) + cur_max_fw_cmds = + readl(&instance->reg_set->outbound_scratch_pad_3) & 0x00FFFF; if (dual_qdepth_disable || !cur_max_fw_cmds) cur_max_fw_cmds = instance->instancet->read_fw_status_reg(reg_set) & 0x00FFFF; @@ -255,7 +274,8 @@ megasas_fusion_update_can_queue(struct megasas_instance *instance, int fw_boot_c instance->ldio_threshold = ldio_threshold; if (!instance->is_rdpq) - instance->max_fw_cmds = min_t(u16, instance->max_fw_cmds, 1024); + instance->max_fw_cmds = + min_t(u16, instance->max_fw_cmds, 1024); if (reset_devices) instance->max_fw_cmds = min(instance->max_fw_cmds, @@ -271,7 +291,14 @@ megasas_fusion_update_can_queue(struct megasas_instance *instance, int fw_boot_c (MEGASAS_FUSION_INTERNAL_CMDS + MEGASAS_FUSION_IOCTL_CMDS); instance->cur_can_queue = instance->max_scsi_cmds; + instance->host->can_queue = instance->cur_can_queue; } + + if (instance->is_ventura) + instance->max_mpt_cmds = + instance->max_fw_cmds * RAID_1_10_RMW_CMDS; + else + instance->max_mpt_cmds = instance->max_fw_cmds; } /** * megasas_free_cmds_fusion - Free all the cmds in the free cmd pool @@ -285,7 +312,7 @@ megasas_free_cmds_fusion(struct megasas_instance *instance) struct megasas_cmd_fusion *cmd; /* SG, Sense */ - for (i = 0; i < instance->max_fw_cmds; i++) { + for (i = 0; i < instance->max_mpt_cmds; i++) { cmd = fusion->cmd_list[i]; if (cmd) { if (cmd->sg_frame) @@ -329,7 +356,7 @@ megasas_free_cmds_fusion(struct megasas_instance *instance) /* cmd_list */ - for (i = 0; i < instance->max_fw_cmds; i++) + for (i = 0; i < instance->max_mpt_cmds; i++) kfree(fusion->cmd_list[i]); kfree(fusion->cmd_list); @@ -381,33 +408,49 @@ static int megasas_create_sg_sense_fusion(struct megasas_instance *instance) return -ENOMEM; } } + + /* create sense buffer for the raid 1/10 fp */ + for (i = max_cmd; i < instance->max_mpt_cmds; i++) { + cmd = fusion->cmd_list[i]; + cmd->sense = pci_pool_alloc(fusion->sense_dma_pool, + GFP_KERNEL, &cmd->sense_phys_addr); + if (!cmd->sense) { + dev_err(&instance->pdev->dev, + "Failed from %s %d\n", __func__, __LINE__); + return -ENOMEM; + } + } + return 0; } int megasas_alloc_cmdlist_fusion(struct megasas_instance *instance) { - u32 max_cmd, i; + u32 max_mpt_cmd, i; struct fusion_context *fusion; fusion = instance->ctrl_context; - max_cmd = instance->max_fw_cmds; + max_mpt_cmd = instance->max_mpt_cmds; /* * fusion->cmd_list is an array of struct megasas_cmd_fusion pointers. * Allocate the dynamic array first and then allocate individual * commands. */ - fusion->cmd_list = kzalloc(sizeof(struct megasas_cmd_fusion *) * max_cmd, - GFP_KERNEL); + fusion->cmd_list = + kzalloc(sizeof(struct megasas_cmd_fusion *) * max_mpt_cmd, + GFP_KERNEL); if (!fusion->cmd_list) { dev_err(&instance->pdev->dev, "Failed from %s %d\n", __func__, __LINE__); return -ENOMEM; } - for (i = 0; i < max_cmd; i++) { + + + for (i = 0; i < max_mpt_cmd; i++) { fusion->cmd_list[i] = kzalloc(sizeof(struct megasas_cmd_fusion), GFP_KERNEL); if (!fusion->cmd_list[i]) { @@ -642,13 +685,14 @@ megasas_alloc_cmds_fusion(struct megasas_instance *instance) */ /* SMID 0 is reserved. Set SMID/index from 1 */ - for (i = 0; i < instance->max_fw_cmds; i++) { + for (i = 0; i < instance->max_mpt_cmds; i++) { cmd = fusion->cmd_list[i]; offset = MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE * i; memset(cmd, 0, sizeof(struct megasas_cmd_fusion)); cmd->index = i + 1; cmd->scmd = NULL; - cmd->sync_cmd_idx = (i >= instance->max_scsi_cmds) ? + cmd->sync_cmd_idx = + (i >= instance->max_scsi_cmds && i < instance->max_fw_cmds) ? (i - instance->max_scsi_cmds) : (u32)ULONG_MAX; /* Set to Invalid */ cmd->instance = instance; @@ -658,6 +702,7 @@ megasas_alloc_cmds_fusion(struct megasas_instance *instance) memset(cmd->io_request, 0, sizeof(struct MPI2_RAID_SCSI_IO_REQUEST)); cmd->io_request_phys_addr = io_req_base_phys + offset; + cmd->is_raid_1_fp_write = 0; } if (megasas_create_sg_sense_fusion(instance)) @@ -796,7 +841,7 @@ megasas_ioc_init_fusion(struct megasas_instance *instance) drv_ops = (MFI_CAPABILITIES *) &(init_frame->driver_operations); /* driver support Extended MSIX */ - if (fusion->adapter_type == INVADER_SERIES) + if (fusion->adapter_type >= INVADER_SERIES) drv_ops->mfi_capabilities.support_additional_msix = 1; /* driver supports HA / Remote LUN over Fast Path interface */ drv_ops->mfi_capabilities.support_fp_remote_lun = 1; @@ -813,6 +858,7 @@ megasas_ioc_init_fusion(struct megasas_instance *instance) drv_ops->mfi_capabilities.support_ext_queue_depth = 1; drv_ops->mfi_capabilities.support_qd_throttling = 1; + drv_ops->mfi_capabilities.support_pd_map_target_id = 1; /* Convert capability to LE32 */ cpu_to_le32s((u32 *)&init_frame->driver_operations.mfi_capabilities); @@ -850,7 +896,7 @@ megasas_ioc_init_fusion(struct megasas_instance *instance) break; } - megasas_fire_cmd_fusion(instance, &req_desc); + megasas_fire_cmd_fusion(instance, &req_desc, false); wait_and_poll(instance, cmd, MFI_POLL_TIMEOUT_SECS); @@ -1247,12 +1293,12 @@ megasas_init_adapter_fusion(struct megasas_instance *instance) fusion->reply_q_depth = 2 * (((max_cmd + 1 + 15)/16)*16); fusion->request_alloc_sz = - sizeof(union MEGASAS_REQUEST_DESCRIPTOR_UNION) *max_cmd; + sizeof(union MEGASAS_REQUEST_DESCRIPTOR_UNION) * instance->max_mpt_cmds; fusion->reply_alloc_sz = sizeof(union MPI2_REPLY_DESCRIPTORS_UNION) *(fusion->reply_q_depth); fusion->io_frames_alloc_sz = MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE + - (MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE * - (max_cmd + 1)); /* Extra 1 for SMID 0 */ + (MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE + * (instance->max_mpt_cmds + 1)); /* Extra 1 for SMID 0 */ scratch_pad_2 = readl(&instance->reg_set->outbound_scratch_pad_2); /* If scratch_pad_2 & MEGASAS_MAX_CHAIN_SIZE_UNITS_MASK is set, @@ -1388,42 +1434,43 @@ fail_alloc_mfi_cmds: */ void -map_cmd_status(struct megasas_cmd_fusion *cmd, u8 status, u8 ext_status) +map_cmd_status(struct fusion_context *fusion, + struct scsi_cmnd *scmd, u8 status, u8 ext_status, + u32 data_length, u8 *sense) { switch (status) { case MFI_STAT_OK: - cmd->scmd->result = DID_OK << 16; + scmd->result = DID_OK << 16; break; case MFI_STAT_SCSI_IO_FAILED: case MFI_STAT_LD_INIT_IN_PROGRESS: - cmd->scmd->result = (DID_ERROR << 16) | ext_status; + scmd->result = (DID_ERROR << 16) | ext_status; break; case MFI_STAT_SCSI_DONE_WITH_ERROR: - cmd->scmd->result = (DID_OK << 16) | ext_status; + scmd->result = (DID_OK << 16) | ext_status; if (ext_status == SAM_STAT_CHECK_CONDITION) { - memset(cmd->scmd->sense_buffer, 0, + memset(scmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); - memcpy(cmd->scmd->sense_buffer, cmd->sense, + memcpy(scmd->sense_buffer, sense, SCSI_SENSE_BUFFERSIZE); - cmd->scmd->result |= DRIVER_SENSE << 24; + scmd->result |= DRIVER_SENSE << 24; } break; case MFI_STAT_LD_OFFLINE: case MFI_STAT_DEVICE_NOT_FOUND: - cmd->scmd->result = DID_BAD_TARGET << 16; + scmd->result = DID_BAD_TARGET << 16; break; case MFI_STAT_CONFIG_SEQ_MISMATCH: - cmd->scmd->result = DID_IMM_RETRY << 16; + scmd->result = DID_IMM_RETRY << 16; break; default: - dev_printk(KERN_DEBUG, &cmd->instance->pdev->dev, "FW status %#x\n", status); - cmd->scmd->result = DID_ERROR << 16; + scmd->result = DID_ERROR << 16; break; } } @@ -1449,7 +1496,7 @@ megasas_make_sgl_fusion(struct megasas_instance *instance, fusion = instance->ctrl_context; - if (fusion->adapter_type == INVADER_SERIES) { + if (fusion->adapter_type >= INVADER_SERIES) { struct MPI25_IEEE_SGE_CHAIN64 *sgl_ptr_end = sgl_ptr; sgl_ptr_end += fusion->max_sge_in_main_msg - 1; sgl_ptr_end->Flags = 0; @@ -1466,7 +1513,7 @@ megasas_make_sgl_fusion(struct megasas_instance *instance, sgl_ptr->Length = cpu_to_le32(sg_dma_len(os_sgl)); sgl_ptr->Address = cpu_to_le64(sg_dma_address(os_sgl)); sgl_ptr->Flags = 0; - if (fusion->adapter_type == INVADER_SERIES) + if (fusion->adapter_type >= INVADER_SERIES) if (i == sge_count - 1) sgl_ptr->Flags = IEEE_SGE_FLAGS_END_OF_LIST; sgl_ptr++; @@ -1477,7 +1524,7 @@ megasas_make_sgl_fusion(struct megasas_instance *instance, (sge_count > fusion->max_sge_in_main_msg)) { struct MPI25_IEEE_SGE_CHAIN64 *sg_chain; - if (fusion->adapter_type == INVADER_SERIES) { + if (fusion->adapter_type >= INVADER_SERIES) { if ((le16_to_cpu(cmd->io_request->IoFlags) & MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH) != MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH) @@ -1493,7 +1540,7 @@ megasas_make_sgl_fusion(struct megasas_instance *instance, sg_chain = sgl_ptr; /* Prepare chain element */ sg_chain->NextChainOffset = 0; - if (fusion->adapter_type == INVADER_SERIES) + if (fusion->adapter_type >= INVADER_SERIES) sg_chain->Flags = IEEE_SGE_FLAGS_CHAIN_ELEMENT; else sg_chain->Flags = @@ -1574,6 +1621,7 @@ megasas_set_pd_lba(struct MPI2_RAID_SCSI_IO_REQUEST *io_request, u8 cdb_len, MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG | MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP | MPI2_SCSIIO_EEDPFLAGS_CHECK_APPTAG | + MPI25_SCSIIO_EEDPFLAGS_DO_NOT_DISABLE_MODE | MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD); } else { io_request->EEDPFlags = cpu_to_le16( @@ -1688,6 +1736,90 @@ megasas_set_pd_lba(struct MPI2_RAID_SCSI_IO_REQUEST *io_request, u8 cdb_len, } /** + * megasas_stream_detect - stream detection on read and and write IOs + * @instance: Adapter soft state + * @cmd: Command to be prepared + * @io_info: IO Request info + * + */ + +/** stream detection on read and and write IOs */ +static void megasas_stream_detect(struct megasas_instance *instance, + struct megasas_cmd_fusion *cmd, + struct IO_REQUEST_INFO *io_info) +{ + struct fusion_context *fusion = instance->ctrl_context; + u32 device_id = io_info->ldTgtId; + struct LD_STREAM_DETECT *current_ld_sd + = fusion->stream_detect_by_ld[device_id]; + u32 *track_stream = ¤t_ld_sd->mru_bit_map, stream_num; + u32 shifted_values, unshifted_values; + u32 index_value_mask, shifted_values_mask; + int i; + bool is_read_ahead = false; + struct STREAM_DETECT *current_sd; + /* find possible stream */ + for (i = 0; i < MAX_STREAMS_TRACKED; ++i) { + stream_num = + (*track_stream >> (i * BITS_PER_INDEX_STREAM)) & + STREAM_MASK; + current_sd = ¤t_ld_sd->stream_track[stream_num]; + /* if we found a stream, update the raid + * context and also update the mruBitMap + */ + /* boundary condition */ + if ((current_sd->next_seq_lba) && + (io_info->ldStartBlock >= current_sd->next_seq_lba) && + (io_info->ldStartBlock <= (current_sd->next_seq_lba+32)) && + (current_sd->is_read == io_info->isRead)) { + + if ((io_info->ldStartBlock != current_sd->next_seq_lba) + && ((!io_info->isRead) || (!is_read_ahead))) + /* + * Once the API availible we need to change this. + * At this point we are not allowing any gap + */ + continue; + + cmd->io_request->RaidContext.raid_context_g35.stream_detected = true; + current_sd->next_seq_lba = + io_info->ldStartBlock + io_info->numBlocks; + /* + * update the mruBitMap LRU + */ + shifted_values_mask = + (1 << i * BITS_PER_INDEX_STREAM) - 1; + shifted_values = ((*track_stream & shifted_values_mask) + << BITS_PER_INDEX_STREAM); + index_value_mask = + STREAM_MASK << i * BITS_PER_INDEX_STREAM; + unshifted_values = + *track_stream & ~(shifted_values_mask | + index_value_mask); + *track_stream = + unshifted_values | shifted_values | stream_num; + return; + + } + + } + /* + * if we did not find any stream, create a new one + * from the least recently used + */ + stream_num = + (*track_stream >> ((MAX_STREAMS_TRACKED - 1) * BITS_PER_INDEX_STREAM)) & + STREAM_MASK; + current_sd = ¤t_ld_sd->stream_track[stream_num]; + current_sd->is_read = io_info->isRead; + current_sd->next_seq_lba = io_info->ldStartBlock + io_info->numBlocks; + *track_stream = + (((*track_stream & ZERO_LAST_STREAM) << 4) | stream_num); + return; + +} + +/** * megasas_build_ldio_fusion - Prepares IOs to devices * @instance: Adapter soft state * @scp: SCSI command @@ -1702,22 +1834,26 @@ megasas_build_ldio_fusion(struct megasas_instance *instance, struct megasas_cmd_fusion *cmd) { u8 fp_possible; - u32 start_lba_lo, start_lba_hi, device_id, datalength = 0; + u32 start_lba_lo, start_lba_hi, device_id, datalength = 0, ld; struct MPI2_RAID_SCSI_IO_REQUEST *io_request; union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc; struct IO_REQUEST_INFO io_info; struct fusion_context *fusion; struct MR_DRV_RAID_MAP_ALL *local_map_ptr; u8 *raidLUN; + unsigned long spinlock_flags; + union RAID_CONTEXT_UNION *praid_context; + struct MR_LD_RAID *raid; device_id = MEGASAS_DEV_INDEX(scp); fusion = instance->ctrl_context; io_request = cmd->io_request; - io_request->RaidContext.VirtualDiskTgtId = cpu_to_le16(device_id); - io_request->RaidContext.status = 0; - io_request->RaidContext.exStatus = 0; + io_request->RaidContext.raid_context.virtual_disk_tgt_id = + cpu_to_le16(device_id); + io_request->RaidContext.raid_context.status = 0; + io_request->RaidContext.raid_context.ex_status = 0; req_desc = (union MEGASAS_REQUEST_DESCRIPTOR_UNION *)cmd->request_desc; @@ -1779,20 +1915,23 @@ megasas_build_ldio_fusion(struct megasas_instance *instance, io_info.ldStartBlock = ((u64)start_lba_hi << 32) | start_lba_lo; io_info.numBlocks = datalength; io_info.ldTgtId = device_id; + io_info.r1_alt_dev_handle = MR_PD_INVALID; io_request->DataLength = cpu_to_le32(scsi_bufflen(scp)); if (scp->sc_data_direction == PCI_DMA_FROMDEVICE) io_info.isRead = 1; local_map_ptr = fusion->ld_drv_map[(instance->map_id & 1)]; + ld = MR_TargetIdToLdGet(device_id, local_map_ptr); + raid = MR_LdRaidGet(ld, local_map_ptr); if ((MR_TargetIdToLdGet(device_id, local_map_ptr) >= instance->fw_supported_vd_count) || (!fusion->fast_path_io)) { - io_request->RaidContext.regLockFlags = 0; + io_request->RaidContext.raid_context.reg_lock_flags = 0; fp_possible = 0; } else { if (MR_BuildRaidContext(instance, &io_info, - &io_request->RaidContext, + &io_request->RaidContext.raid_context, local_map_ptr, &raidLUN)) fp_possible = io_info.fpOkForIo; } @@ -1803,6 +1942,20 @@ megasas_build_ldio_fusion(struct megasas_instance *instance, cmd->request_desc->SCSIIO.MSIxIndex = instance->msix_vectors ? raw_smp_processor_id() % instance->msix_vectors : 0; + if (instance->is_ventura) { + spin_lock_irqsave(&instance->stream_lock, spinlock_flags); + megasas_stream_detect(instance, cmd, &io_info); + spin_unlock_irqrestore(&instance->stream_lock, spinlock_flags); + /* In ventura if stream detected for a read and it is read ahead + * capable make this IO as LDIO + */ + if (io_request->RaidContext.raid_context_g35.stream_detected && + io_info.isRead && io_info.ra_capable) + fp_possible = false; + } + + praid_context = &io_request->RaidContext; + if (fp_possible) { megasas_set_pd_lba(io_request, scp->cmd_len, &io_info, scp, local_map_ptr, start_lba_lo); @@ -1811,17 +1964,25 @@ megasas_build_ldio_fusion(struct megasas_instance *instance, (MPI2_REQ_DESCRIPT_FLAGS_FP_IO << MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); if (fusion->adapter_type == INVADER_SERIES) { - if (io_request->RaidContext.regLockFlags == + if (io_request->RaidContext.raid_context.reg_lock_flags == REGION_TYPE_UNUSED) cmd->request_desc->SCSIIO.RequestFlags = (MEGASAS_REQ_DESCRIPT_FLAGS_NO_LOCK << MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); - io_request->RaidContext.Type = MPI2_TYPE_CUDA; - io_request->RaidContext.nseg = 0x1; + io_request->RaidContext.raid_context.type + = MPI2_TYPE_CUDA; + io_request->RaidContext.raid_context.nseg = 0x1; io_request->IoFlags |= cpu_to_le16(MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH); - io_request->RaidContext.regLockFlags |= + io_request->RaidContext.raid_context.reg_lock_flags |= (MR_RL_FLAGS_GRANT_DESTINATION_CUDA | MR_RL_FLAGS_SEQ_NUM_ENABLE); + } else if (instance->is_ventura) { + io_request->RaidContext.raid_context_g35.type + = MPI2_TYPE_CUDA; + io_request->RaidContext.raid_context_g35.nseg = 0x1; + io_request->RaidContext.raid_context_g35.routing_flags.bits.sqn = 1; + io_request->IoFlags |= + cpu_to_le16(MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH); } if ((fusion->load_balance_info[device_id].loadBalanceFlag) && (io_info.isRead)) { @@ -1831,9 +1992,20 @@ megasas_build_ldio_fusion(struct megasas_instance *instance, &io_info); scp->SCp.Status |= MEGASAS_LOAD_BALANCE_FLAG; cmd->pd_r1_lb = io_info.pd_after_lb; + if (instance->is_ventura) + io_request->RaidContext.raid_context_g35.span_arm + = io_info.span_arm; + else + io_request->RaidContext.raid_context.span_arm + = io_info.span_arm; + } else scp->SCp.Status &= ~MEGASAS_LOAD_BALANCE_FLAG; + cmd->is_raid_1_fp_write = io_info.is_raid_1_fp_write; + if (io_info.is_raid_1_fp_write) + cmd->r1_alt_dev_handle = io_info.r1_alt_dev_handle; + if ((raidLUN[0] == 1) && (local_map_ptr->raidMap.devHndlInfo[io_info.pd_after_lb].validHandles > 1)) { instance->dev_handle = !(instance->dev_handle); @@ -1845,26 +2017,98 @@ megasas_build_ldio_fusion(struct megasas_instance *instance, io_request->DevHandle = io_info.devHandle; /* populate the LUN field */ memcpy(io_request->LUN, raidLUN, 8); + if (instance->is_ventura) { + if (io_info.isRead) { + if ((raid->cpuAffinity.pdRead.cpu0) && + (raid->cpuAffinity.pdRead.cpu1)) + praid_context->raid_context_g35.routing_flags.bits.cpu_sel + = MR_RAID_CTX_CPUSEL_FCFS; + else if (raid->cpuAffinity.pdRead.cpu1) + praid_context->raid_context_g35.routing_flags.bits.cpu_sel + = MR_RAID_CTX_CPUSEL_1; + else + praid_context->raid_context_g35.routing_flags.bits.cpu_sel + = MR_RAID_CTX_CPUSEL_0; + } else { + if ((raid->cpuAffinity.pdWrite.cpu0) + && (raid->cpuAffinity.pdWrite.cpu1)) + praid_context->raid_context_g35.routing_flags.bits.cpu_sel + = MR_RAID_CTX_CPUSEL_FCFS; + else if (raid->cpuAffinity.pdWrite.cpu1) + praid_context->raid_context_g35.routing_flags.bits.cpu_sel + = MR_RAID_CTX_CPUSEL_1; + else + praid_context->raid_context_g35.routing_flags.bits.cpu_sel + = MR_RAID_CTX_CPUSEL_0; + if (praid_context->raid_context_g35.routing_flags.bits.sld) { + praid_context->raid_context_g35.raid_flags + = (MR_RAID_FLAGS_IO_SUB_TYPE_CACHE_BYPASS + << MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT); + } + } + } } else { - io_request->RaidContext.timeoutValue = + io_request->RaidContext.raid_context.timeout_value = cpu_to_le16(local_map_ptr->raidMap.fpPdIoTimeoutSec); cmd->request_desc->SCSIIO.RequestFlags = (MEGASAS_REQ_DESCRIPT_FLAGS_LD_IO << MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); if (fusion->adapter_type == INVADER_SERIES) { if (io_info.do_fp_rlbypass || - (io_request->RaidContext.regLockFlags == REGION_TYPE_UNUSED)) + (io_request->RaidContext.raid_context.reg_lock_flags + == REGION_TYPE_UNUSED)) cmd->request_desc->SCSIIO.RequestFlags = (MEGASAS_REQ_DESCRIPT_FLAGS_NO_LOCK << MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); - io_request->RaidContext.Type = MPI2_TYPE_CUDA; - io_request->RaidContext.regLockFlags |= + io_request->RaidContext.raid_context.type + = MPI2_TYPE_CUDA; + io_request->RaidContext.raid_context.reg_lock_flags |= (MR_RL_FLAGS_GRANT_DESTINATION_CPU0 | MR_RL_FLAGS_SEQ_NUM_ENABLE); - io_request->RaidContext.nseg = 0x1; + io_request->RaidContext.raid_context.nseg = 0x1; + } else if (instance->is_ventura) { + io_request->RaidContext.raid_context_g35.type + = MPI2_TYPE_CUDA; + io_request->RaidContext.raid_context_g35.routing_flags.bits.sqn = 1; + io_request->RaidContext.raid_context_g35.nseg = 0x1; } io_request->Function = MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST; io_request->DevHandle = cpu_to_le16(device_id); + + if (instance->is_ventura) { + if (io_info.isRead) { + if ((raid->cpuAffinity.ldRead.cpu0) + && (raid->cpuAffinity.ldRead.cpu1)) + praid_context->raid_context_g35.routing_flags.bits.cpu_sel + = MR_RAID_CTX_CPUSEL_FCFS; + else if (raid->cpuAffinity.ldRead.cpu1) + praid_context->raid_context_g35.routing_flags.bits.cpu_sel + = MR_RAID_CTX_CPUSEL_1; + else + praid_context->raid_context_g35.routing_flags.bits.cpu_sel + = MR_RAID_CTX_CPUSEL_0; + } else { + if ((raid->cpuAffinity.ldWrite.cpu0) && + (raid->cpuAffinity.ldWrite.cpu1)) + praid_context->raid_context_g35.routing_flags.bits.cpu_sel + = MR_RAID_CTX_CPUSEL_FCFS; + else if (raid->cpuAffinity.ldWrite.cpu1) + praid_context->raid_context_g35.routing_flags.bits.cpu_sel + = MR_RAID_CTX_CPUSEL_1; + else + praid_context->raid_context_g35.routing_flags.bits.cpu_sel + = MR_RAID_CTX_CPUSEL_0; + + if (io_request->RaidContext.raid_context_g35.stream_detected + && (raid->level == 5) && + (raid->writeMode == MR_RL_WRITE_THROUGH_MODE)) { + if (praid_context->raid_context_g35.routing_flags.bits.cpu_sel + == MR_RAID_CTX_CPUSEL_FCFS) + praid_context->raid_context_g35.routing_flags.bits.cpu_sel + = MR_RAID_CTX_CPUSEL_0; + } + } + } } /* Not FP */ } @@ -1897,11 +2141,11 @@ static void megasas_build_ld_nonrw_fusion(struct megasas_instance *instance, local_map_ptr = fusion->ld_drv_map[(instance->map_id & 1)]; io_request->DataLength = cpu_to_le32(scsi_bufflen(scmd)); /* get RAID_Context pointer */ - pRAID_Context = &io_request->RaidContext; + pRAID_Context = &io_request->RaidContext.raid_context; /* Check with FW team */ - pRAID_Context->VirtualDiskTgtId = cpu_to_le16(device_id); - pRAID_Context->regLockRowLBA = 0; - pRAID_Context->regLockLength = 0; + pRAID_Context->virtual_disk_tgt_id = cpu_to_le16(device_id); + pRAID_Context->reg_lock_row_lba = 0; + pRAID_Context->reg_lock_length = 0; if (fusion->fast_path_io && ( device_id < instance->fw_supported_vd_count)) { @@ -1920,7 +2164,7 @@ static void megasas_build_ld_nonrw_fusion(struct megasas_instance *instance, io_request->Function = MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST; io_request->DevHandle = cpu_to_le16(device_id); io_request->LUN[1] = scmd->device->lun; - pRAID_Context->timeoutValue = + pRAID_Context->timeout_value = cpu_to_le16 (scmd->request->timeout / HZ); cmd->request_desc->SCSIIO.RequestFlags = (MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO << @@ -1928,9 +2172,11 @@ static void megasas_build_ld_nonrw_fusion(struct megasas_instance *instance, } else { /* set RAID context values */ - pRAID_Context->configSeqNum = raid->seqNum; - pRAID_Context->regLockFlags = REGION_TYPE_SHARED_READ; - pRAID_Context->timeoutValue = cpu_to_le16(raid->fpIoTimeoutForLd); + pRAID_Context->config_seq_num = raid->seqNum; + if (!instance->is_ventura) + pRAID_Context->reg_lock_flags = REGION_TYPE_SHARED_READ; + pRAID_Context->timeout_value = + cpu_to_le16(raid->fpIoTimeoutForLd); /* get the DevHandle for the PD (since this is fpNonRWCapable, this is a single disk RAID0) */ @@ -1984,13 +2230,13 @@ megasas_build_syspd_fusion(struct megasas_instance *instance, io_request = cmd->io_request; /* get RAID_Context pointer */ - pRAID_Context = &io_request->RaidContext; - pRAID_Context->regLockFlags = 0; - pRAID_Context->regLockRowLBA = 0; - pRAID_Context->regLockLength = 0; + pRAID_Context = &io_request->RaidContext.raid_context; + pRAID_Context->reg_lock_flags = 0; + pRAID_Context->reg_lock_row_lba = 0; + pRAID_Context->reg_lock_length = 0; io_request->DataLength = cpu_to_le32(scsi_bufflen(scmd)); io_request->LUN[1] = scmd->device->lun; - pRAID_Context->RAIDFlags = MR_RAID_FLAGS_IO_SUB_TYPE_SYSTEM_PD + pRAID_Context->raid_flags = MR_RAID_FLAGS_IO_SUB_TYPE_SYSTEM_PD << MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT; /* If FW supports PD sequence number */ @@ -1999,24 +2245,32 @@ megasas_build_syspd_fusion(struct megasas_instance *instance, /* TgtId must be incremented by 255 as jbod seq number is index * below raid map */ - pRAID_Context->VirtualDiskTgtId = + /* More than 256 PD/JBOD support for Ventura */ + if (instance->support_morethan256jbod) + pRAID_Context->virtual_disk_tgt_id = + pd_sync->seq[pd_index].pd_target_id; + else + pRAID_Context->virtual_disk_tgt_id = cpu_to_le16(device_id + (MAX_PHYSICAL_DEVICES - 1)); - pRAID_Context->configSeqNum = pd_sync->seq[pd_index].seqNum; + pRAID_Context->config_seq_num = pd_sync->seq[pd_index].seqNum; io_request->DevHandle = pd_sync->seq[pd_index].devHandle; - pRAID_Context->regLockFlags |= + if (instance->is_ventura) + io_request->RaidContext.raid_context_g35.routing_flags.bits.sqn = 1; + else + pRAID_Context->reg_lock_flags |= (MR_RL_FLAGS_SEQ_NUM_ENABLE|MR_RL_FLAGS_GRANT_DESTINATION_CUDA); - pRAID_Context->Type = MPI2_TYPE_CUDA; + pRAID_Context->type = MPI2_TYPE_CUDA; pRAID_Context->nseg = 0x1; } else if (fusion->fast_path_io) { - pRAID_Context->VirtualDiskTgtId = cpu_to_le16(device_id); - pRAID_Context->configSeqNum = 0; + pRAID_Context->virtual_disk_tgt_id = cpu_to_le16(device_id); + pRAID_Context->config_seq_num = 0; local_map_ptr = fusion->ld_drv_map[(instance->map_id & 1)]; io_request->DevHandle = local_map_ptr->raidMap.devHndlInfo[device_id].curDevHdl; } else { /* Want to send all IO via FW path */ - pRAID_Context->VirtualDiskTgtId = cpu_to_le16(device_id); - pRAID_Context->configSeqNum = 0; + pRAID_Context->virtual_disk_tgt_id = cpu_to_le16(device_id); + pRAID_Context->config_seq_num = 0; io_request->DevHandle = cpu_to_le16(0xFFFF); } @@ -2032,17 +2286,17 @@ megasas_build_syspd_fusion(struct megasas_instance *instance, cmd->request_desc->SCSIIO.RequestFlags = (MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO << MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); - pRAID_Context->timeoutValue = cpu_to_le16(os_timeout_value); - pRAID_Context->VirtualDiskTgtId = cpu_to_le16(device_id); + pRAID_Context->timeout_value = cpu_to_le16(os_timeout_value); + pRAID_Context->virtual_disk_tgt_id = cpu_to_le16(device_id); } else { /* system pd Fast Path */ io_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST; timeout_limit = (scmd->device->type == TYPE_DISK) ? 255 : 0xFFFF; - pRAID_Context->timeoutValue = + pRAID_Context->timeout_value = cpu_to_le16((os_timeout_value > timeout_limit) ? timeout_limit : os_timeout_value); - if (fusion->adapter_type == INVADER_SERIES) + if (fusion->adapter_type >= INVADER_SERIES) io_request->IoFlags |= cpu_to_le16(MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH); @@ -2078,9 +2332,9 @@ megasas_build_io_fusion(struct megasas_instance *instance, io_request->Control = 0; io_request->EEDPBlockSize = 0; io_request->ChainOffset = 0; - io_request->RaidContext.RAIDFlags = 0; - io_request->RaidContext.Type = 0; - io_request->RaidContext.nseg = 0; + io_request->RaidContext.raid_context.raid_flags = 0; + io_request->RaidContext.raid_context.type = 0; + io_request->RaidContext.raid_context.nseg = 0; memcpy(io_request->CDB.CDB32, scp->cmnd, scp->cmd_len); /* @@ -2124,11 +2378,16 @@ megasas_build_io_fusion(struct megasas_instance *instance, return 1; } - /* numSGE store lower 8 bit of sge_count. - * numSGEExt store higher 8 bit of sge_count - */ - io_request->RaidContext.numSGE = sge_count; - io_request->RaidContext.numSGEExt = (u8)(sge_count >> 8); + if (instance->is_ventura) + io_request->RaidContext.raid_context_g35.num_sge = sge_count; + else { + /* numSGE store lower 8 bit of sge_count. + * numSGEExt store higher 8 bit of sge_count + */ + io_request->RaidContext.raid_context.num_sge = sge_count; + io_request->RaidContext.raid_context.num_sge_ext = + (u8)(sge_count >> 8); + } io_request->SGLFlags = cpu_to_le16(MPI2_SGE_FLAGS_64_BIT_ADDRESSING); @@ -2155,19 +2414,151 @@ megasas_get_request_descriptor(struct megasas_instance *instance, u16 index) u8 *p; struct fusion_context *fusion; - if (index >= instance->max_fw_cmds) { + if (index >= instance->max_mpt_cmds) { dev_err(&instance->pdev->dev, "Invalid SMID (0x%x)request for " "descriptor for scsi%d\n", index, instance->host->host_no); return NULL; } fusion = instance->ctrl_context; - p = fusion->req_frames_desc - +sizeof(union MEGASAS_REQUEST_DESCRIPTOR_UNION) *index; + p = fusion->req_frames_desc + + sizeof(union MEGASAS_REQUEST_DESCRIPTOR_UNION) * index; return (union MEGASAS_REQUEST_DESCRIPTOR_UNION *)p; } +/* + * megasas_fpio_to_ldio- + * This function converts an fp io to ldio + */ + +void megasas_fpio_to_ldio(struct megasas_instance *instance, + struct megasas_cmd_fusion *cmd, struct scsi_cmnd *scmd) +{ + struct fusion_context *fusion; + union RAID_CONTEXT_UNION *praid_context; + struct MR_LD_RAID *raid; + struct MR_DRV_RAID_MAP_ALL *local_map_ptr; + u32 device_id, ld; + + fusion = instance->ctrl_context; + cmd->request_desc->SCSIIO.RequestFlags = + (MEGASAS_REQ_DESCRIPT_FLAGS_LD_IO + << MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); + cmd->io_request->Function = MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST; + cmd->io_request->DevHandle = cpu_to_le16(MEGASAS_DEV_INDEX(scmd)); + + /*remove FAST PATH ENABLE bit in IoFlags */ + cmd->io_request->IoFlags &= + cpu_to_le16(~MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH); + + /* if the numSGE > max_sge_in_main_sge set the chain offset*/ + if (cmd->io_request->RaidContext.raid_context_g35.num_sge > + fusion->max_sge_in_main_msg) + cmd->io_request->ChainOffset = fusion->chain_offset_io_request; + memcpy(cmd->io_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len); + cmd->io_request->CDB.EEDP32.PrimaryReferenceTag = 0; + cmd->io_request->CDB.EEDP32.PrimaryApplicationTagMask = 0; + cmd->io_request->EEDPFlags = 0; + cmd->io_request->Control = 0; + cmd->io_request->EEDPBlockSize = 0; + cmd->is_raid_1_fp_write = 0; + + device_id = MEGASAS_DEV_INDEX(cmd->scmd); + local_map_ptr = fusion->ld_drv_map[(instance->map_id & 1)]; + ld = MR_TargetIdToLdGet(device_id, local_map_ptr); + raid = MR_LdRaidGet(ld, local_map_ptr); + praid_context = &cmd->io_request->RaidContext; + if (cmd->scmd->sc_data_direction == PCI_DMA_FROMDEVICE) { + if ((raid->cpuAffinity.ldRead.cpu0) + && (raid->cpuAffinity.ldRead.cpu1)) + praid_context->raid_context_g35.routing_flags.bits.cpu_sel + = MR_RAID_CTX_CPUSEL_FCFS; + else if (raid->cpuAffinity.ldRead.cpu1) + praid_context->raid_context_g35.routing_flags.bits.cpu_sel + = MR_RAID_CTX_CPUSEL_1; + else + praid_context->raid_context_g35.routing_flags.bits.cpu_sel + = MR_RAID_CTX_CPUSEL_0; + } else { + if ((raid->cpuAffinity.ldWrite.cpu0) + && (raid->cpuAffinity.ldWrite.cpu1)) + praid_context->raid_context_g35.routing_flags.bits.cpu_sel + = MR_RAID_CTX_CPUSEL_FCFS; + else if (raid->cpuAffinity.ldWrite.cpu1) + praid_context->raid_context_g35.routing_flags.bits.cpu_sel + = MR_RAID_CTX_CPUSEL_1; + else + praid_context->raid_context_g35.routing_flags.bits.cpu_sel + = MR_RAID_CTX_CPUSEL_0; + } +} + +/* megasas_prepate_secondRaid1_IO + * It prepares the raid 1 second IO + */ +void megasas_prepare_secondRaid1_IO(struct megasas_instance *instance, + struct megasas_cmd_fusion *cmd, + struct megasas_cmd_fusion *r1_cmd) +{ + union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc, *req_desc2 = NULL; + struct fusion_context *fusion; + + fusion = instance->ctrl_context; + req_desc = cmd->request_desc; + if (r1_cmd) { + /* copy the io request frame as well + * as 8 SGEs data for r1 command + */ + memcpy(r1_cmd->io_request, cmd->io_request, + sizeof(struct MPI2_RAID_SCSI_IO_REQUEST)); + memcpy(&r1_cmd->io_request->SGL, &cmd->io_request->SGL, + (fusion->max_sge_in_main_msg * + sizeof(union MPI2_SGE_IO_UNION))); + /*sense buffer is different for r1 command*/ + r1_cmd->io_request->SenseBufferLowAddress = + cpu_to_le32(r1_cmd->sense_phys_addr); + r1_cmd->scmd = cmd->scmd; + req_desc2 = + megasas_get_request_descriptor(instance, r1_cmd->index-1); + if (req_desc2) { + req_desc2->Words = 0; + r1_cmd->request_desc = req_desc2; + req_desc2->SCSIIO.SMID = + cpu_to_le16(r1_cmd->index); + req_desc2->SCSIIO.RequestFlags = + req_desc->SCSIIO.RequestFlags; + r1_cmd->is_raid_1_fp_write = 1; + r1_cmd->request_desc->SCSIIO.DevHandle = + cmd->r1_alt_dev_handle; + r1_cmd->io_request->DevHandle = cmd->r1_alt_dev_handle; + cmd->io_request->RaidContext.raid_context_g35.smid.peer_smid = + cpu_to_le16(r1_cmd->index); + r1_cmd->io_request->RaidContext.raid_context_g35.smid.peer_smid = + cpu_to_le16(cmd->index); + /* MSIxIndex of both commands request + * descriptors should be same + */ + r1_cmd->request_desc->SCSIIO.MSIxIndex = + cmd->request_desc->SCSIIO.MSIxIndex; + /*span arm is different for r1 cmd*/ + r1_cmd->io_request->RaidContext.raid_context_g35.span_arm = + cmd->io_request->RaidContext.raid_context_g35.span_arm + 1; + } else { + megasas_return_cmd_fusion(instance, r1_cmd); + dev_info(&instance->pdev->dev, + "unable to get request descriptor, firing as normal IO\n"); + atomic_dec(&instance->fw_outstanding); + megasas_fpio_to_ldio(instance, cmd, cmd->scmd); + } + } else { + dev_info(&instance->pdev->dev, + "unable to get command, firing as normal IO\n"); + atomic_dec(&instance->fw_outstanding); + megasas_fpio_to_ldio(instance, cmd, cmd->scmd); + } +} + /** * megasas_build_and_issue_cmd_fusion -Main routine for building and * issuing non IOCTL cmd @@ -2178,7 +2569,7 @@ static u32 megasas_build_and_issue_cmd_fusion(struct megasas_instance *instance, struct scsi_cmnd *scmd) { - struct megasas_cmd_fusion *cmd; + struct megasas_cmd_fusion *cmd, *r1_cmd = NULL; union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc; u32 index; struct fusion_context *fusion; @@ -2193,13 +2584,26 @@ megasas_build_and_issue_cmd_fusion(struct megasas_instance *instance, return SCSI_MLQUEUE_DEVICE_BUSY; } + if (atomic_inc_return(&instance->fw_outstanding) > + instance->host->can_queue) { + atomic_dec(&instance->fw_outstanding); + return SCSI_MLQUEUE_HOST_BUSY; + } + cmd = megasas_get_cmd_fusion(instance, scmd->request->tag); + if (!cmd) { + atomic_dec(&instance->fw_outstanding); + return SCSI_MLQUEUE_HOST_BUSY; + } + index = cmd->index; req_desc = megasas_get_request_descriptor(instance, index-1); - if (!req_desc) + if (!req_desc) { + atomic_dec(&instance->fw_outstanding); return SCSI_MLQUEUE_HOST_BUSY; + } req_desc->Words = 0; cmd->request_desc = req_desc; @@ -2208,6 +2612,7 @@ megasas_build_and_issue_cmd_fusion(struct megasas_instance *instance, megasas_return_cmd_fusion(instance, cmd); dev_err(&instance->pdev->dev, "Error building command\n"); cmd->request_desc = NULL; + atomic_dec(&instance->fw_outstanding); return SCSI_MLQUEUE_HOST_BUSY; } @@ -2218,13 +2623,41 @@ megasas_build_and_issue_cmd_fusion(struct megasas_instance *instance, cmd->io_request->ChainOffset != 0xF) dev_err(&instance->pdev->dev, "The chain offset value is not " "correct : %x\n", cmd->io_request->ChainOffset); + /* + * if it is raid 1/10 fp write capable. + * try to get second command from pool and construct it. + * From FW, it has confirmed that lba values of two PDs + * corresponds to single R1/10 LD are always same + * + */ + /* driver side count always should be less than max_fw_cmds + * to get new command + */ + if (cmd->is_raid_1_fp_write && + (atomic_inc_return(&instance->fw_outstanding) > + (instance->host->can_queue) || + (!atomic_read(&instance->r1_write_fp_capable)))) { + megasas_fpio_to_ldio(instance, cmd, cmd->scmd); + atomic_dec(&instance->fw_outstanding); + } else if (cmd->is_raid_1_fp_write) { + r1_cmd = megasas_get_cmd_fusion(instance, + (scmd->request->tag + instance->max_fw_cmds)); + megasas_prepare_secondRaid1_IO(instance, cmd, r1_cmd); + } /* * Issue the command to the FW */ - atomic_inc(&instance->fw_outstanding); + if (scmd->sc_data_direction == PCI_DMA_TODEVICE && instance->is_ventura) + atomic64_add(scsi_bufflen(scmd), &instance->bytes_wrote); - megasas_fire_cmd_fusion(instance, req_desc); + megasas_fire_cmd_fusion(instance, req_desc, instance->is_ventura); + + if (r1_cmd) { + atomic64_add(scsi_bufflen(scmd), &instance->bytes_wrote); + megasas_fire_cmd_fusion(instance, r1_cmd->request_desc, + instance->is_ventura); + } return 0; } @@ -2242,10 +2675,10 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex) struct MPI2_RAID_SCSI_IO_REQUEST *scsi_io_req; struct fusion_context *fusion; struct megasas_cmd *cmd_mfi; - struct megasas_cmd_fusion *cmd_fusion; + struct megasas_cmd_fusion *cmd_fusion, *r1_cmd = NULL; u16 smid, num_completed; - u8 reply_descript_type; - u32 status, extStatus, device_id; + u8 reply_descript_type, *sense; + u32 status, extStatus, device_id, data_length; union desc_value d_val; struct LD_LOAD_BALANCE_INFO *lbinfo; int threshold_reply_count = 0; @@ -2275,6 +2708,15 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex) while (d_val.u.low != cpu_to_le32(UINT_MAX) && d_val.u.high != cpu_to_le32(UINT_MAX)) { + /* + * Ensure that the peer command is NULL here in case a + * command has completed but the R1 FP Write peer has + * not completed yet.If not null, it's possible that + * another thread will complete the peer + * command and should not. + */ + r1_cmd = NULL; + smid = le16_to_cpu(reply_desc->SMID); cmd_fusion = fusion->cmd_list[smid - 1]; @@ -2287,8 +2729,10 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex) cmd_fusion->scmd->SCp.ptr = NULL; scmd_local = cmd_fusion->scmd; - status = scsi_io_req->RaidContext.status; - extStatus = scsi_io_req->RaidContext.exStatus; + status = scsi_io_req->RaidContext.raid_context.status; + extStatus = scsi_io_req->RaidContext.raid_context.ex_status; + sense = cmd_fusion->sense; + data_length = scsi_io_req->DataLength; switch (scsi_io_req->Function) { case MPI2_FUNCTION_SCSI_TASK_MGMT: @@ -2305,12 +2749,28 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex) /* Update load balancing info */ device_id = MEGASAS_DEV_INDEX(scmd_local); lbinfo = &fusion->load_balance_info[device_id]; - if (cmd_fusion->scmd->SCp.Status & - MEGASAS_LOAD_BALANCE_FLAG) { + /* + * check for the raid 1/10 fast path writes + */ + if (!cmd_fusion->is_raid_1_fp_write && + (cmd_fusion->scmd->SCp.Status & + MEGASAS_LOAD_BALANCE_FLAG)) { atomic_dec(&lbinfo->scsi_pending_cmds[cmd_fusion->pd_r1_lb]); cmd_fusion->scmd->SCp.Status &= ~MEGASAS_LOAD_BALANCE_FLAG; + } else if (cmd_fusion->is_raid_1_fp_write) { + /* get peer command */ + if (cmd_fusion->index < instance->max_fw_cmds) + r1_cmd = fusion->cmd_list[(cmd_fusion->index + + instance->max_fw_cmds)-1]; + else { + r1_cmd = + fusion->cmd_list[(cmd_fusion->index - + instance->max_fw_cmds)-1]; + } + cmd_fusion->cmd_completed = true; } + if (reply_descript_type == MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS) { if (megasas_dbg_lvl == 5) @@ -2320,14 +2780,49 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex) /* Fall thru and complete IO */ case MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST: /* LD-IO Path */ /* Map the FW Cmd Status */ - map_cmd_status(cmd_fusion, status, extStatus); - scsi_io_req->RaidContext.status = 0; - scsi_io_req->RaidContext.exStatus = 0; - if (megasas_cmd_type(scmd_local) == READ_WRITE_LDIO) - atomic_dec(&instance->ldio_outstanding); - megasas_return_cmd_fusion(instance, cmd_fusion); - scsi_dma_unmap(scmd_local); - scmd_local->scsi_done(scmd_local); + /* + * check for the raid 1/10 fast path writes + */ + if (r1_cmd && r1_cmd->is_raid_1_fp_write + && r1_cmd->cmd_completed) { + /* + * if the peer Raid 1/10 fast path failed, + * mark IO as failed to the scsi layer. + * over write the current status by the failed + * status makes sure that if any one of + * command fails,return fail status to + * scsi layer + */ + if (r1_cmd->io_request->RaidContext.raid_context.status != + MFI_STAT_OK) { + status = + r1_cmd->io_request->RaidContext.raid_context.status; + extStatus = + r1_cmd->io_request->RaidContext.raid_context.ex_status; + data_length = + r1_cmd->io_request->DataLength; + sense = r1_cmd->sense; + } + r1_cmd->io_request->RaidContext.raid_context.status = 0; + r1_cmd->io_request->RaidContext.raid_context.ex_status = 0; + cmd_fusion->is_raid_1_fp_write = 0; + r1_cmd->is_raid_1_fp_write = 0; + r1_cmd->cmd_completed = false; + cmd_fusion->cmd_completed = false; + megasas_return_cmd_fusion(instance, r1_cmd); + } + if (!cmd_fusion->is_raid_1_fp_write) { + map_cmd_status(fusion, scmd_local, status, + extStatus, data_length, sense); + scsi_io_req->RaidContext.raid_context.status = 0; + scsi_io_req->RaidContext.raid_context.ex_status = 0; + if (instance->ldio_threshold + && megasas_cmd_type(scmd_local) == READ_WRITE_LDIO) + atomic_dec(&instance->ldio_outstanding); + megasas_return_cmd_fusion(instance, cmd_fusion); + scsi_dma_unmap(scmd_local); + scmd_local->scsi_done(scmd_local); + } atomic_dec(&instance->fw_outstanding); break; @@ -2376,7 +2871,7 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex) * pending to be completed */ if (threshold_reply_count >= THRESHOLD_REPLY_COUNT) { - if (fusion->adapter_type == INVADER_SERIES) + if (instance->msix_combined) writel(((MSIxIndex & 0x7) << 24) | fusion->last_reply_idx[MSIxIndex], instance->reply_post_host_index_addr[MSIxIndex/8]); @@ -2392,7 +2887,7 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex) return IRQ_NONE; wmb(); - if (fusion->adapter_type == INVADER_SERIES) + if (instance->msix_combined) writel(((MSIxIndex & 0x7) << 24) | fusion->last_reply_idx[MSIxIndex], instance->reply_post_host_index_addr[MSIxIndex/8]); @@ -2518,7 +3013,7 @@ build_mpt_mfi_pass_thru(struct megasas_instance *instance, io_req = cmd->io_request; - if (fusion->adapter_type == INVADER_SERIES) { + if (fusion->adapter_type >= INVADER_SERIES) { struct MPI25_IEEE_SGE_CHAIN64 *sgl_ptr_end = (struct MPI25_IEEE_SGE_CHAIN64 *)&io_req->SGL; sgl_ptr_end += fusion->max_sge_in_main_msg - 1; @@ -2595,7 +3090,7 @@ megasas_issue_dcmd_fusion(struct megasas_instance *instance, return DCMD_NOT_FIRED; } - megasas_fire_cmd_fusion(instance, req_desc); + megasas_fire_cmd_fusion(instance, req_desc, instance->is_ventura); return DCMD_SUCCESS; } @@ -2888,7 +3383,8 @@ void megasas_refire_mgmt_cmd(struct megasas_instance *instance) cpu_to_le32(MR_DCMD_SYSTEM_PD_MAP_GET_INFO))) && !(cmd_mfi->flags & DRV_DCMD_SKIP_REFIRE); if (refire_cmd) - megasas_fire_cmd_fusion(instance, req_desc); + megasas_fire_cmd_fusion(instance, req_desc, + instance->is_ventura); else megasas_return_cmd(instance, cmd_mfi); } @@ -3067,7 +3563,7 @@ megasas_issue_tm(struct megasas_instance *instance, u16 device_handle, mr_request->tmReqFlags.isTMForLD = 1; init_completion(&cmd_fusion->done); - megasas_fire_cmd_fusion(instance, req_desc); + megasas_fire_cmd_fusion(instance, req_desc, instance->is_ventura); timeleft = wait_for_completion_timeout(&cmd_fusion->done, 50 * HZ); @@ -3377,9 +3873,9 @@ int megasas_check_mpio_paths(struct megasas_instance *instance, /* Core fusion reset function */ int megasas_reset_fusion(struct Scsi_Host *shost, int reason) { - int retval = SUCCESS, i, convert = 0; + int retval = SUCCESS, i, j, convert = 0; struct megasas_instance *instance; - struct megasas_cmd_fusion *cmd_fusion; + struct megasas_cmd_fusion *cmd_fusion, *mpt_cmd_fusion; struct fusion_context *fusion; u32 abs_state, status_reg, reset_adapter; u32 io_timeout_in_crash_mode = 0; @@ -3454,20 +3950,34 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason) /* Now return commands back to the OS */ for (i = 0 ; i < instance->max_scsi_cmds; i++) { cmd_fusion = fusion->cmd_list[i]; + /*check for extra commands issued by driver*/ + if (instance->is_ventura) { + cmd_fusion->is_raid_1_fp_write = 0; + cmd_fusion->cmd_completed = false; + mpt_cmd_fusion = + fusion->cmd_list[i + instance->max_fw_cmds]; + mpt_cmd_fusion->is_raid_1_fp_write = 0; + mpt_cmd_fusion->cmd_completed = false; + if (mpt_cmd_fusion->scmd) + megasas_return_cmd_fusion(instance, + mpt_cmd_fusion); + } scmd_local = cmd_fusion->scmd; if (cmd_fusion->scmd) { scmd_local->result = megasas_check_mpio_paths(instance, scmd_local); - if (megasas_cmd_type(scmd_local) == READ_WRITE_LDIO) + if (instance->ldio_threshold && + megasas_cmd_type(scmd_local) == READ_WRITE_LDIO) atomic_dec(&instance->ldio_outstanding); megasas_return_cmd_fusion(instance, cmd_fusion); scsi_dma_unmap(scmd_local); scmd_local->scsi_done(scmd_local); - atomic_dec(&instance->fw_outstanding); } } + atomic_set(&instance->fw_outstanding, 0); + status_reg = instance->instancet->read_fw_status_reg( instance->reg_set); abs_state = status_reg & MFI_STATE_MASK; @@ -3542,6 +4052,16 @@ transition_to_ready: shost_for_each_device(sdev, shost) megasas_update_sdev_properties(sdev); + /* reset stream detection array */ + if (instance->is_ventura) { + for (j = 0; j < MAX_LOGICAL_DRIVES_EXT; ++j) { + memset(fusion->stream_detect_by_ld[j], + 0, sizeof(struct LD_STREAM_DETECT)); + fusion->stream_detect_by_ld[j]->mru_bit_map + = MR_STREAM_BITMAP; + } + } + clear_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags); instance->instancet->enable_intr(instance); diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h index e3bee04c1eb1..3addd0cb2e99 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.h +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h @@ -59,6 +59,8 @@ #define MR_RL_FLAGS_GRANT_DESTINATION_CPU1 0x10 #define MR_RL_FLAGS_GRANT_DESTINATION_CUDA 0x80 #define MR_RL_FLAGS_SEQ_NUM_ENABLE 0x8 +#define MR_RL_WRITE_THROUGH_MODE 0x00 +#define MR_RL_WRITE_BACK_MODE 0x01 /* T10 PI defines */ #define MR_PROT_INFO_TYPE_CONTROLLER 0x8 @@ -81,6 +83,11 @@ enum MR_RAID_FLAGS_IO_SUB_TYPE { MR_RAID_FLAGS_IO_SUB_TYPE_NONE = 0, MR_RAID_FLAGS_IO_SUB_TYPE_SYSTEM_PD = 1, + MR_RAID_FLAGS_IO_SUB_TYPE_RMW_DATA = 2, + MR_RAID_FLAGS_IO_SUB_TYPE_RMW_P = 3, + MR_RAID_FLAGS_IO_SUB_TYPE_RMW_Q = 4, + MR_RAID_FLAGS_IO_SUB_TYPE_CACHE_BYPASS = 6, + MR_RAID_FLAGS_IO_SUB_TYPE_LDIO_BW_LIMIT = 7 }; /* @@ -94,11 +101,13 @@ enum MR_RAID_FLAGS_IO_SUB_TYPE { #define MEGASAS_FP_CMD_LEN 16 #define MEGASAS_FUSION_IN_RESET 0 #define THRESHOLD_REPLY_COUNT 50 +#define RAID_1_10_RMW_CMDS 3 #define JBOD_MAPS_COUNT 2 enum MR_FUSION_ADAPTER_TYPE { THUNDERBOLT_SERIES = 0, INVADER_SERIES = 1, + VENTURA_SERIES = 2, }; /* @@ -108,29 +117,104 @@ enum MR_FUSION_ADAPTER_TYPE { struct RAID_CONTEXT { #if defined(__BIG_ENDIAN_BITFIELD) - u8 nseg:4; - u8 Type:4; + u8 nseg:4; + u8 type:4; #else - u8 Type:4; - u8 nseg:4; + u8 type:4; + u8 nseg:4; #endif - u8 resvd0; - __le16 timeoutValue; - u8 regLockFlags; - u8 resvd1; - __le16 VirtualDiskTgtId; - __le64 regLockRowLBA; - __le32 regLockLength; - __le16 nextLMId; - u8 exStatus; - u8 status; - u8 RAIDFlags; - u8 numSGE; - __le16 configSeqNum; - u8 spanArm; - u8 priority; - u8 numSGEExt; - u8 resvd2; + u8 resvd0; + __le16 timeout_value; + u8 reg_lock_flags; + u8 resvd1; + __le16 virtual_disk_tgt_id; + __le64 reg_lock_row_lba; + __le32 reg_lock_length; + __le16 next_lmid; + u8 ex_status; + u8 status; + u8 raid_flags; + u8 num_sge; + __le16 config_seq_num; + u8 span_arm; + u8 priority; + u8 num_sge_ext; + u8 resvd2; +}; + +/* + * Raid Context structure which describes ventura MegaRAID specific + * IO Paramenters ,This resides at offset 0x60 where the SGL normally + * starts in MPT IO Frames + */ +struct RAID_CONTEXT_G35 { +#if defined(__BIG_ENDIAN_BITFIELD) + u16 resvd0:8; + u16 nseg:4; + u16 type:4; +#else + u16 type:4; /* 0x00 */ + u16 nseg:4; /* 0x00 */ + u16 resvd0:8; +#endif + u16 timeout_value; /* 0x02 -0x03 */ + union { + struct { +#if defined(__BIG_ENDIAN_BITFIELD) + u16 set_divert:4; + u16 cpu_sel:4; + u16 log:1; + u16 rw:1; + u16 sbs:1; + u16 sqn:1; + u16 fwn:1; + u16 c2f:1; + u16 sld:1; + u16 reserved:1; +#else + u16 reserved:1; + u16 sld:1; + u16 c2f:1; + u16 fwn:1; + u16 sqn:1; + u16 sbs:1; + u16 rw:1; + u16 log:1; + u16 cpu_sel:4; + u16 set_divert:4; +#endif + } bits; + u16 s; + } routing_flags; /* 0x04 -0x05 routing flags */ + u16 virtual_disk_tgt_id; /* 0x06 -0x07 */ + u64 reg_lock_row_lba; /* 0x08 - 0x0F */ + u32 reg_lock_length; /* 0x10 - 0x13 */ + union { + u16 next_lmid; /* 0x14 - 0x15 */ + u16 peer_smid; /* used for the raid 1/10 fp writes */ + } smid; + u8 ex_status; /* 0x16 : OUT */ + u8 status; /* 0x17 status */ + u8 raid_flags; /* 0x18 resvd[7:6], ioSubType[5:4], + * resvd[3:1], preferredCpu[0] + */ + u8 span_arm; /* 0x1C span[7:5], arm[4:0] */ + u16 config_seq_num; /* 0x1A -0x1B */ +#if defined(__BIG_ENDIAN_BITFIELD) /* 0x1C - 0x1D */ + u16 stream_detected:1; + u16 reserved:3; + u16 num_sge:12; +#else + u16 num_sge:12; + u16 reserved:3; + u16 stream_detected:1; +#endif + u8 resvd2[2]; /* 0x1E-0x1F */ +}; + +union RAID_CONTEXT_UNION { + struct RAID_CONTEXT raid_context; + struct RAID_CONTEXT_G35 raid_context_g35; }; #define RAID_CTX_SPANARM_ARM_SHIFT (0) @@ -139,6 +223,14 @@ struct RAID_CONTEXT { #define RAID_CTX_SPANARM_SPAN_SHIFT (5) #define RAID_CTX_SPANARM_SPAN_MASK (0xE0) +/* number of bits per index in U32 TrackStream */ +#define BITS_PER_INDEX_STREAM 4 +#define INVALID_STREAM_NUM 16 +#define MR_STREAM_BITMAP 0x76543210 +#define STREAM_MASK ((1 << BITS_PER_INDEX_STREAM) - 1) +#define ZERO_LAST_STREAM 0x0fffffff +#define MAX_STREAMS_TRACKED 8 + /* * define region lock types */ @@ -175,6 +267,8 @@ enum REGION_TYPE { #define MPI2_SCSIIO_EEDPFLAGS_CHECK_APPTAG (0x0200) #define MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD (0x0100) #define MPI2_SCSIIO_EEDPFLAGS_INSERT_OP (0x0004) +/* EEDP escape mode */ +#define MPI25_SCSIIO_EEDPFLAGS_DO_NOT_DISABLE_MODE (0x0040) #define MPI2_FUNCTION_SCSI_IO_REQUEST (0x00) /* SCSI IO */ #define MPI2_FUNCTION_SCSI_TASK_MGMT (0x01) #define MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY (0x03) @@ -407,7 +501,7 @@ struct MPI2_RAID_SCSI_IO_REQUEST { u8 LUN[8]; /* 0x34 */ __le32 Control; /* 0x3C */ union MPI2_SCSI_IO_CDB_UNION CDB; /* 0x40 */ - struct RAID_CONTEXT RaidContext; /* 0x60 */ + union RAID_CONTEXT_UNION RaidContext; /* 0x60 */ union MPI2_SGE_IO_UNION SGL; /* 0x80 */ }; @@ -586,14 +680,17 @@ struct MPI2_IOC_INIT_REQUEST { #define MAX_RAIDMAP_ROW_SIZE (MAX_ROW_SIZE) #define MAX_LOGICAL_DRIVES 64 #define MAX_LOGICAL_DRIVES_EXT 256 +#define MAX_LOGICAL_DRIVES_DYN 512 #define MAX_RAIDMAP_LOGICAL_DRIVES (MAX_LOGICAL_DRIVES) #define MAX_RAIDMAP_VIEWS (MAX_LOGICAL_DRIVES) #define MAX_ARRAYS 128 #define MAX_RAIDMAP_ARRAYS (MAX_ARRAYS) #define MAX_ARRAYS_EXT 256 #define MAX_API_ARRAYS_EXT (MAX_ARRAYS_EXT) +#define MAX_API_ARRAYS_DYN 512 #define MAX_PHYSICAL_DEVICES 256 #define MAX_RAIDMAP_PHYSICAL_DEVICES (MAX_PHYSICAL_DEVICES) +#define MAX_RAIDMAP_PHYSICAL_DEVICES_DYN 512 #define MR_DCMD_LD_MAP_GET_INFO 0x0300e101 #define MR_DCMD_SYSTEM_PD_MAP_GET_INFO 0x0200e102 #define MR_DCMD_CTRL_SHARED_HOST_MEM_ALLOC 0x010e8485 /* SR-IOV HB alloc*/ @@ -640,10 +737,56 @@ struct MR_SPAN_BLOCK_INFO { struct MR_SPAN_INFO block_span_info; }; +#define MR_RAID_CTX_CPUSEL_0 0 +#define MR_RAID_CTX_CPUSEL_1 1 +#define MR_RAID_CTX_CPUSEL_2 2 +#define MR_RAID_CTX_CPUSEL_3 3 +#define MR_RAID_CTX_CPUSEL_FCFS 0xF + +struct MR_CPU_AFFINITY_MASK { + union { + struct { +#ifndef MFI_BIG_ENDIAN + u8 hw_path:1; + u8 cpu0:1; + u8 cpu1:1; + u8 cpu2:1; + u8 cpu3:1; + u8 reserved:3; +#else + u8 reserved:3; + u8 cpu3:1; + u8 cpu2:1; + u8 cpu1:1; + u8 cpu0:1; + u8 hw_path:1; +#endif + }; + u8 core_mask; + }; +}; + +struct MR_IO_AFFINITY { + union { + struct { + struct MR_CPU_AFFINITY_MASK pdRead; + struct MR_CPU_AFFINITY_MASK pdWrite; + struct MR_CPU_AFFINITY_MASK ldRead; + struct MR_CPU_AFFINITY_MASK ldWrite; + }; + u32 word; + }; + u8 maxCores; /* Total cores + HW Path in ROC */ + u8 reserved[3]; +}; + struct MR_LD_RAID { struct { #if defined(__BIG_ENDIAN_BITFIELD) - u32 reserved4:5; + u32 reserved4:2; + u32 fp_cache_bypass_capable:1; + u32 fp_rmw_capable:1; + u32 disable_coalescing:1; u32 fpBypassRegionLock:1; u32 tmCapable:1; u32 fpNonRWCapable:1; @@ -654,11 +797,13 @@ struct MR_LD_RAID { u32 encryptionType:8; u32 pdPiMode:4; u32 ldPiMode:4; - u32 reserved5:3; + u32 reserved5:2; + u32 ra_capable:1; u32 fpCapable:1; #else u32 fpCapable:1; - u32 reserved5:3; + u32 ra_capable:1; + u32 reserved5:2; u32 ldPiMode:4; u32 pdPiMode:4; u32 encryptionType:8; @@ -669,7 +814,10 @@ struct MR_LD_RAID { u32 fpNonRWCapable:1; u32 tmCapable:1; u32 fpBypassRegionLock:1; - u32 reserved4:5; + u32 disable_coalescing:1; + u32 fp_rmw_capable:1; + u32 fp_cache_bypass_capable:1; + u32 reserved4:2; #endif } capability; __le32 reserved6; @@ -696,7 +844,36 @@ struct MR_LD_RAID { u8 LUN[8]; /* 0x24 8 byte LUN field used for SCSI IO's */ u8 fpIoTimeoutForLd;/*0x2C timeout value used by driver in FP IO*/ - u8 reserved3[0x80-0x2D]; /* 0x2D */ + /* Ox2D This LD accept priority boost of this type */ + u8 ld_accept_priority_type; + u8 reserved2[2]; /* 0x2E - 0x2F */ + /* 0x30 - 0x33, Logical block size for the LD */ + u32 logical_block_length; + struct { +#ifndef MFI_BIG_ENDIAN + /* 0x34, P_I_EXPONENT from READ CAPACITY 16 */ + u32 ld_pi_exp:4; + /* 0x34, LOGICAL BLOCKS PER PHYSICAL + * BLOCK EXPONENT from READ CAPACITY 16 + */ + u32 ld_logical_block_exp:4; + u32 reserved1:24; /* 0x34 */ +#else + u32 reserved1:24; /* 0x34 */ + /* 0x34, LOGICAL BLOCKS PER PHYSICAL + * BLOCK EXPONENT from READ CAPACITY 16 + */ + u32 ld_logical_block_exp:4; + /* 0x34, P_I_EXPONENT from READ CAPACITY 16 */ + u32 ld_pi_exp:4; +#endif + }; /* 0x34 - 0x37 */ + /* 0x38 - 0x3f, This will determine which + * core will process LD IO and PD IO. + */ + struct MR_IO_AFFINITY cpuAffinity; + /* Bit definiations are specified by MR_IO_AFFINITY */ + u8 reserved3[0x80-0x40]; /* 0x40 - 0x7f */ }; struct MR_LD_SPAN_MAP { @@ -743,6 +920,9 @@ struct IO_REQUEST_INFO { u64 start_row; u8 span_arm; /* span[7:5], arm[4:0] */ u8 pd_after_lb; + u16 r1_alt_dev_handle; /* raid 1/10 only */ + bool is_raid_1_fp_write; + bool ra_capable; }; struct MR_LD_TARGET_SYNC { @@ -751,6 +931,91 @@ struct MR_LD_TARGET_SYNC { __le16 seqNum; }; +/* + * RAID Map descriptor Types. + * Each element should uniquely idetify one data structure in the RAID map + */ +enum MR_RAID_MAP_DESC_TYPE { + /* MR_DEV_HANDLE_INFO data */ + RAID_MAP_DESC_TYPE_DEVHDL_INFO = 0x0, + /* target to Ld num Index map */ + RAID_MAP_DESC_TYPE_TGTID_INFO = 0x1, + /* MR_ARRAY_INFO data */ + RAID_MAP_DESC_TYPE_ARRAY_INFO = 0x2, + /* MR_LD_SPAN_MAP data */ + RAID_MAP_DESC_TYPE_SPAN_INFO = 0x3, + RAID_MAP_DESC_TYPE_COUNT, +}; + +/* + * This table defines the offset, size and num elements of each descriptor + * type in the RAID Map buffer + */ +struct MR_RAID_MAP_DESC_TABLE { + /* Raid map descriptor type */ + u32 raid_map_desc_type; + /* Offset into the RAID map buffer where + * descriptor data is saved + */ + u32 raid_map_desc_offset; + /* total size of the + * descriptor buffer + */ + u32 raid_map_desc_buffer_size; + /* Number of elements contained in the + * descriptor buffer + */ + u32 raid_map_desc_elements; +}; + +/* + * Dynamic Raid Map Structure. + */ +struct MR_FW_RAID_MAP_DYNAMIC { + u32 raid_map_size; /* total size of RAID Map structure */ + u32 desc_table_offset;/* Offset of desc table into RAID map*/ + u32 desc_table_size; /* Total Size of desc table */ + /* Total Number of elements in the desc table */ + u32 desc_table_num_elements; + u64 pci_threshold_bandwidth; + u32 reserved2[3]; /*future use */ + /* timeout value used by driver in FP IOs */ + u8 fp_pd_io_timeout_sec; + u8 reserved3[3]; + /* when this seqNum increments, driver needs to + * release RMW buffers asap + */ + u32 rmw_fp_seq_num; + u16 ld_count; /* count of lds. */ + u16 ar_count; /* count of arrays */ + u16 span_count; /* count of spans */ + u16 reserved4[3]; +/* + * The below structure of pointers is only to be used by the driver. + * This is added in the ,API to reduce the amount of code changes + * needed in the driver to support dynamic RAID map Firmware should + * not update these pointers while preparing the raid map + */ + union { + struct { + struct MR_DEV_HANDLE_INFO *dev_hndl_info; + u16 *ld_tgt_id_to_ld; + struct MR_ARRAY_INFO *ar_map_info; + struct MR_LD_SPAN_MAP *ld_span_map; + }; + u64 ptr_structure_size[RAID_MAP_DESC_TYPE_COUNT]; + }; +/* + * RAID Map descriptor table defines the layout of data in the RAID Map. + * The size of the descriptor table itself could change. + */ + /* Variable Size descriptor Table. */ + struct MR_RAID_MAP_DESC_TABLE + raid_map_desc_table[RAID_MAP_DESC_TYPE_COUNT]; + /* Variable Size buffer containing all data */ + u32 raid_map_desc_data[1]; +}; /* Dynamicaly sized RAID MAp structure */ + #define IEEE_SGE_FLAGS_ADDR_MASK (0x03) #define IEEE_SGE_FLAGS_SYSTEM_ADDR (0x00) #define IEEE_SGE_FLAGS_IOCDDR_ADDR (0x01) @@ -795,6 +1060,10 @@ struct megasas_cmd_fusion { u32 index; u8 pd_r1_lb; struct completion done; + bool is_raid_1_fp_write; + u16 r1_alt_dev_handle; /* raid 1/10 only*/ + bool cmd_completed; /* raid 1/10 fp writes status holder */ + }; struct LD_LOAD_BALANCE_INFO { @@ -856,9 +1125,10 @@ struct MR_DRV_RAID_MAP { __le16 spanCount; __le16 reserve3; - struct MR_DEV_HANDLE_INFO devHndlInfo[MAX_RAIDMAP_PHYSICAL_DEVICES]; - u8 ldTgtIdToLd[MAX_LOGICAL_DRIVES_EXT]; - struct MR_ARRAY_INFO arMapInfo[MAX_API_ARRAYS_EXT]; + struct MR_DEV_HANDLE_INFO + devHndlInfo[MAX_RAIDMAP_PHYSICAL_DEVICES_DYN]; + u16 ldTgtIdToLd[MAX_LOGICAL_DRIVES_DYN]; + struct MR_ARRAY_INFO arMapInfo[MAX_API_ARRAYS_DYN]; struct MR_LD_SPAN_MAP ldSpanMap[1]; }; @@ -870,7 +1140,7 @@ struct MR_DRV_RAID_MAP { struct MR_DRV_RAID_MAP_ALL { struct MR_DRV_RAID_MAP raidMap; - struct MR_LD_SPAN_MAP ldSpanMap[MAX_LOGICAL_DRIVES_EXT - 1]; + struct MR_LD_SPAN_MAP ldSpanMap[MAX_LOGICAL_DRIVES_DYN - 1]; } __packed; @@ -919,7 +1189,8 @@ struct MR_PD_CFG_SEQ { u8 reserved:7; #endif } capability; - u8 reserved[3]; + u8 reserved; + u16 pd_target_id; } __packed; struct MR_PD_CFG_SEQ_NUM_SYNC { @@ -928,6 +1199,30 @@ struct MR_PD_CFG_SEQ_NUM_SYNC { struct MR_PD_CFG_SEQ seq[1]; } __packed; +/* stream detection */ +struct STREAM_DETECT { + u64 next_seq_lba; /* next LBA to match sequential access */ + struct megasas_cmd_fusion *first_cmd_fusion; /* first cmd in group */ + struct megasas_cmd_fusion *last_cmd_fusion; /* last cmd in group */ + u32 count_cmds_in_stream; /* count of host commands in this stream */ + u16 num_sges_in_group; /* total number of SGEs in grouped IOs */ + u8 is_read; /* SCSI OpCode for this stream */ + u8 group_depth; /* total number of host commands in group */ + /* TRUE if cannot add any more commands to this group */ + bool group_flush; + u8 reserved[7]; /* pad to 64-bit alignment */ +}; + +struct LD_STREAM_DETECT { + bool write_back; /* TRUE if WB, FALSE if WT */ + bool fp_write_enabled; + bool members_ssds; + bool fp_cache_bypass_capable; + u32 mru_bit_map; /* bitmap used to track MRU and LRU stream indicies */ + /* this is the array of stream detect structures (one per stream) */ + struct STREAM_DETECT stream_track[MAX_STREAMS_TRACKED]; +}; + struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY { u64 RDPQBaseAddress; u32 Reserved1; @@ -965,7 +1260,7 @@ struct fusion_context { u8 chain_offset_io_request; u8 chain_offset_mfi_pthru; - struct MR_FW_RAID_MAP_ALL *ld_map[2]; + struct MR_FW_RAID_MAP_DYNAMIC *ld_map[2]; dma_addr_t ld_map_phys[2]; /*Non dma-able memory. Driver local copy.*/ @@ -973,6 +1268,8 @@ struct fusion_context { u32 max_map_sz; u32 current_map_sz; + u32 old_map_sz; + u32 new_map_sz; u32 drv_map_sz; u32 drv_map_pages; struct MR_PD_CFG_SEQ_NUM_SYNC *pd_seq_sync[JBOD_MAPS_COUNT]; @@ -981,6 +1278,7 @@ struct fusion_context { struct LD_LOAD_BALANCE_INFO load_balance_info[MAX_LOGICAL_DRIVES_EXT]; LD_SPAN_INFO log_to_span[MAX_LOGICAL_DRIVES_EXT]; u8 adapter_type; + struct LD_STREAM_DETECT **stream_detect_by_ld; }; union desc_value { diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_ioc.h b/drivers/scsi/mpt3sas/mpi/mpi2_ioc.h index 8bae305bc156..af4be403582e 100644 --- a/drivers/scsi/mpt3sas/mpi/mpi2_ioc.h +++ b/drivers/scsi/mpt3sas/mpi/mpi2_ioc.h @@ -624,6 +624,8 @@ typedef struct _MPI26_EVENT_DATA_ACTIVE_CABLE_EXCEPT { /* defines for ReasonCode field */ #define MPI26_EVENT_ACTIVE_CABLE_INSUFFICIENT_POWER (0x00) +#define MPI26_EVENT_ACTIVE_CABLE_PRESENT (0x01) +#define MPI26_EVENT_ACTIVE_CABLE_DEGRADED (0x02) /*Hard Reset Received Event data */ diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index f00ef88a378a..a3fe1fb55c17 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -1040,6 +1040,25 @@ _base_interrupt(int irq, void *bus_id) reply_q->reply_post_free[reply_q->reply_post_host_index]. Default.ReplyFlags & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; completed_cmds++; + /* Update the reply post host index after continuously + * processing the threshold number of Reply Descriptors. + * So that FW can find enough entries to post the Reply + * Descriptors in the reply descriptor post queue. + */ + if (completed_cmds > ioc->hba_queue_depth/3) { + if (ioc->combined_reply_queue) { + writel(reply_q->reply_post_host_index | + ((msix_index & 7) << + MPI2_RPHI_MSIX_INDEX_SHIFT), + ioc->replyPostRegisterIndex[msix_index/8]); + } else { + writel(reply_q->reply_post_host_index | + (msix_index << + MPI2_RPHI_MSIX_INDEX_SHIFT), + &ioc->chip->ReplyPostHostIndex); + } + completed_cmds = 1; + } if (request_desript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) goto out; if (!reply_q->reply_post_host_index) @@ -5522,6 +5541,7 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc) goto out_free_resources; ioc->non_operational_loop = 0; + ioc->got_task_abort_from_ioctl = 0; return 0; out_free_resources: diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h index dcb33f4fa687..4ab634fc27df 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.h +++ b/drivers/scsi/mpt3sas/mpt3sas_base.h @@ -73,9 +73,9 @@ #define MPT3SAS_DRIVER_NAME "mpt3sas" #define MPT3SAS_AUTHOR "Avago Technologies <MPT-FusionLinux.pdl@avagotech.com>" #define MPT3SAS_DESCRIPTION "LSI MPT Fusion SAS 3.0 Device Driver" -#define MPT3SAS_DRIVER_VERSION "14.101.00.00" -#define MPT3SAS_MAJOR_VERSION 14 -#define MPT3SAS_MINOR_VERSION 101 +#define MPT3SAS_DRIVER_VERSION "15.100.00.00" +#define MPT3SAS_MAJOR_VERSION 15 +#define MPT3SAS_MINOR_VERSION 100 #define MPT3SAS_BUILD_VERSION 0 #define MPT3SAS_RELEASE_VERSION 00 @@ -1000,6 +1000,7 @@ struct MPT3SAS_ADAPTER { u8 broadcast_aen_busy; u16 broadcast_aen_pending; u8 shost_recovery; + u8 got_task_abort_from_ioctl; struct mutex reset_in_progress_mutex; spinlock_t ioc_reset_in_progress_lock; diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.c b/drivers/scsi/mpt3sas/mpt3sas_ctl.c index 95f0f24bac05..02fe1c4aae2f 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_ctl.c +++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.c @@ -826,16 +826,18 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, "TASK_MGMT: handle(0x%04x), task_type(0x%02x)\n", ioc->name, le16_to_cpu(tm_request->DevHandle), tm_request->TaskType)); - + ioc->got_task_abort_from_ioctl = 1; if (tm_request->TaskType == MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK || tm_request->TaskType == MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK) { if (_ctl_set_task_mid(ioc, &karg, tm_request)) { mpt3sas_base_free_smid(ioc, smid); + ioc->got_task_abort_from_ioctl = 0; goto out; } } + ioc->got_task_abort_from_ioctl = 0; if (test_bit(device_handle, ioc->device_remove_in_progress)) { dtmprintk(ioc, pr_info(MPT3SAS_FMT diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index 75f3fce1c867..81a64678390d 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -1074,6 +1074,26 @@ _scsih_scsi_lookup_get(struct MPT3SAS_ADAPTER *ioc, u16 smid) } /** + * __scsih_scsi_lookup_get_clear - returns scmd entry without + * holding any lock. + * @ioc: per adapter object + * @smid: system request message index + * + * Returns the smid stored scmd pointer. + * Then will dereference the stored scmd pointer. + */ +static inline struct scsi_cmnd * +__scsih_scsi_lookup_get_clear(struct MPT3SAS_ADAPTER *ioc, + u16 smid) +{ + struct scsi_cmnd *scmd = NULL; + + swap(scmd, ioc->scsi_lookup[smid - 1].scmd); + + return scmd; +} + +/** * _scsih_scsi_lookup_get_clear - returns scmd entry * @ioc: per adapter object * @smid: system request message index @@ -1088,8 +1108,7 @@ _scsih_scsi_lookup_get_clear(struct MPT3SAS_ADAPTER *ioc, u16 smid) struct scsi_cmnd *scmd; spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - scmd = ioc->scsi_lookup[smid - 1].scmd; - ioc->scsi_lookup[smid - 1].scmd = NULL; + scmd = __scsih_scsi_lookup_get_clear(ioc, smid); spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); return scmd; @@ -4657,9 +4676,16 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) struct MPT3SAS_DEVICE *sas_device_priv_data; u32 response_code = 0; unsigned long flags; + unsigned int sector_sz; mpi_reply = mpt3sas_base_get_reply_virt_addr(ioc, reply); - scmd = _scsih_scsi_lookup_get_clear(ioc, smid); + + if (ioc->broadcast_aen_busy || ioc->pci_error_recovery || + ioc->got_task_abort_from_ioctl) + scmd = _scsih_scsi_lookup_get_clear(ioc, smid); + else + scmd = __scsih_scsi_lookup_get_clear(ioc, smid); + if (scmd == NULL) return 1; @@ -4715,6 +4741,20 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) } xfer_cnt = le32_to_cpu(mpi_reply->TransferCount); + + /* In case of bogus fw or device, we could end up having + * unaligned partial completion. We can force alignment here, + * then scsi-ml does not need to handle this misbehavior. + */ + sector_sz = scmd->device->sector_size; + if (unlikely(!blk_rq_is_passthrough(scmd->request) && sector_sz && + xfer_cnt % sector_sz)) { + sdev_printk(KERN_INFO, scmd->device, + "unaligned partial completion avoided (xfer_cnt=%u, sector_sz=%u)\n", + xfer_cnt, sector_sz); + xfer_cnt = round_down(xfer_cnt, sector_sz); + } + scsi_set_resid(scmd, scsi_bufflen(scmd) - xfer_cnt); if (ioc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) log_info = le32_to_cpu(mpi_reply->IOCLogInfo); @@ -8028,15 +8068,24 @@ mpt3sas_scsih_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index, case MPI2_EVENT_ACTIVE_CABLE_EXCEPTION: ActiveCableEventData = (Mpi26EventDataActiveCableExcept_t *) mpi_reply->EventData; - if (ActiveCableEventData->ReasonCode == - MPI26_EVENT_ACTIVE_CABLE_INSUFFICIENT_POWER) { - pr_info(MPT3SAS_FMT "Currently an active cable with ReceptacleID %d", - ioc->name, ActiveCableEventData->ReceptacleID); - pr_info("cannot be powered and devices connected to this active cable"); - pr_info("will not be seen. This active cable"); - pr_info("requires %d mW of power", - ActiveCableEventData->ActiveCablePowerRequirement); + switch (ActiveCableEventData->ReasonCode) { + case MPI26_EVENT_ACTIVE_CABLE_INSUFFICIENT_POWER: + pr_notice(MPT3SAS_FMT "Receptacle ID %d: This active cable" + " requires %d mW of power\n", ioc->name, + ActiveCableEventData->ReceptacleID, + ActiveCableEventData->ActiveCablePowerRequirement); + pr_notice(MPT3SAS_FMT "Receptacle ID %d: Devices connected" + " to this active cable will not be seen\n", + ioc->name, ActiveCableEventData->ReceptacleID); + break; + + case MPI26_EVENT_ACTIVE_CABLE_DEGRADED: + pr_notice(MPT3SAS_FMT "ReceptacleID %d: This cable", + ioc->name, ActiveCableEventData->ReceptacleID); + pr_notice(" is not running at an optimal speed(12 Gb/s)\n"); + break; } + break; default: /* ignore the rest */ diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c index 337982cf3d63..49e70a383afa 100644 --- a/drivers/scsi/pmcraid.c +++ b/drivers/scsi/pmcraid.c @@ -4587,16 +4587,14 @@ static void pmcraid_tasklet_function(unsigned long instance) static void pmcraid_unregister_interrupt_handler(struct pmcraid_instance *pinstance) { + struct pci_dev *pdev = pinstance->pdev; int i; for (i = 0; i < pinstance->num_hrrq; i++) - free_irq(pinstance->hrrq_vector[i].vector, - &(pinstance->hrrq_vector[i])); + free_irq(pci_irq_vector(pdev, i), &pinstance->hrrq_vector[i]); - if (pinstance->interrupt_mode) { - pci_disable_msix(pinstance->pdev); - pinstance->interrupt_mode = 0; - } + pinstance->interrupt_mode = 0; + pci_free_irq_vectors(pdev); } /** @@ -4609,60 +4607,52 @@ void pmcraid_unregister_interrupt_handler(struct pmcraid_instance *pinstance) static int pmcraid_register_interrupt_handler(struct pmcraid_instance *pinstance) { - int rc; struct pci_dev *pdev = pinstance->pdev; + unsigned int irq_flag = PCI_IRQ_LEGACY, flag; + int num_hrrq, rc, i; + irq_handler_t isr; - if ((pmcraid_enable_msix) && - (pci_find_capability(pdev, PCI_CAP_ID_MSIX))) { - int num_hrrq = PMCRAID_NUM_MSIX_VECTORS; - struct msix_entry entries[PMCRAID_NUM_MSIX_VECTORS]; - int i; - for (i = 0; i < PMCRAID_NUM_MSIX_VECTORS; i++) - entries[i].entry = i; - - num_hrrq = pci_enable_msix_range(pdev, entries, 1, num_hrrq); - if (num_hrrq < 0) - goto pmcraid_isr_legacy; - - for (i = 0; i < num_hrrq; i++) { - pinstance->hrrq_vector[i].hrrq_id = i; - pinstance->hrrq_vector[i].drv_inst = pinstance; - pinstance->hrrq_vector[i].vector = entries[i].vector; - rc = request_irq(pinstance->hrrq_vector[i].vector, - pmcraid_isr_msix, 0, - PMCRAID_DRIVER_NAME, - &(pinstance->hrrq_vector[i])); - - if (rc) { - int j; - for (j = 0; j < i; j++) - free_irq(entries[j].vector, - &(pinstance->hrrq_vector[j])); - pci_disable_msix(pdev); - goto pmcraid_isr_legacy; - } - } + if (pmcraid_enable_msix) + irq_flag |= PCI_IRQ_MSIX; - pinstance->num_hrrq = num_hrrq; + num_hrrq = pci_alloc_irq_vectors(pdev, 1, PMCRAID_NUM_MSIX_VECTORS, + irq_flag); + if (num_hrrq < 0) + return num_hrrq; + + if (pdev->msix_enabled) { + flag = 0; + isr = pmcraid_isr_msix; + } else { + flag = IRQF_SHARED; + isr = pmcraid_isr; + } + + for (i = 0; i < num_hrrq; i++) { + struct pmcraid_isr_param *vec = &pinstance->hrrq_vector[i]; + + vec->hrrq_id = i; + vec->drv_inst = pinstance; + rc = request_irq(pci_irq_vector(pdev, i), isr, flag, + PMCRAID_DRIVER_NAME, vec); + if (rc) + goto out_unwind; + } + + pinstance->num_hrrq = num_hrrq; + if (pdev->msix_enabled) { pinstance->interrupt_mode = 1; iowrite32(DOORBELL_INTR_MODE_MSIX, pinstance->int_regs.host_ioa_interrupt_reg); ioread32(pinstance->int_regs.host_ioa_interrupt_reg); - goto pmcraid_isr_out; } -pmcraid_isr_legacy: - /* If MSI-X registration failed fallback to legacy mode, where - * only one hrrq entry will be used - */ - pinstance->hrrq_vector[0].hrrq_id = 0; - pinstance->hrrq_vector[0].drv_inst = pinstance; - pinstance->hrrq_vector[0].vector = pdev->irq; - pinstance->num_hrrq = 1; - - rc = request_irq(pdev->irq, pmcraid_isr, IRQF_SHARED, - PMCRAID_DRIVER_NAME, &pinstance->hrrq_vector[0]); -pmcraid_isr_out: + return 0; + +out_unwind: + while (--i > 0) + free_irq(pci_irq_vector(pdev, i), &pinstance->hrrq_vector[i]); + pci_free_irq_vectors(pdev); return rc; } diff --git a/drivers/scsi/pmcraid.h b/drivers/scsi/pmcraid.h index e1d150f3fd4d..568b18a2f47d 100644 --- a/drivers/scsi/pmcraid.h +++ b/drivers/scsi/pmcraid.h @@ -628,7 +628,6 @@ struct pmcraid_interrupts { /* ISR parameters LLD allocates (one for each MSI-X if enabled) vectors */ struct pmcraid_isr_param { struct pmcraid_instance *drv_inst; - u16 vector; /* allocated msi-x vector */ u8 hrrq_id; /* hrrq entry index */ }; diff --git a/drivers/scsi/qedi/qedi_dbg.c b/drivers/scsi/qedi/qedi_dbg.c index 2bdedb9c39bc..8fd28b056f73 100644 --- a/drivers/scsi/qedi/qedi_dbg.c +++ b/drivers/scsi/qedi/qedi_dbg.c @@ -52,7 +52,7 @@ qedi_dbg_warn(struct qedi_dbg_ctx *qedi, const char *func, u32 line, vaf.va = &va; if (!(qedi_dbg_log & QEDI_LOG_WARN)) - return; + goto ret; if (likely(qedi) && likely(qedi->pdev)) pr_warn("[%s]:[%s:%d]:%d: %pV", dev_name(&qedi->pdev->dev), @@ -60,6 +60,7 @@ qedi_dbg_warn(struct qedi_dbg_ctx *qedi, const char *func, u32 line, else pr_warn("[0000:00:00.0]:[%s:%d]: %pV", nfunc, line, &vaf); +ret: va_end(va); } @@ -80,7 +81,7 @@ qedi_dbg_notice(struct qedi_dbg_ctx *qedi, const char *func, u32 line, vaf.va = &va; if (!(qedi_dbg_log & QEDI_LOG_NOTICE)) - return; + goto ret; if (likely(qedi) && likely(qedi->pdev)) pr_notice("[%s]:[%s:%d]:%d: %pV", @@ -89,6 +90,7 @@ qedi_dbg_notice(struct qedi_dbg_ctx *qedi, const char *func, u32 line, else pr_notice("[0000:00:00.0]:[%s:%d]: %pV", nfunc, line, &vaf); +ret: va_end(va); } @@ -109,7 +111,7 @@ qedi_dbg_info(struct qedi_dbg_ctx *qedi, const char *func, u32 line, vaf.va = &va; if (!(qedi_dbg_log & level)) - return; + goto ret; if (likely(qedi) && likely(qedi->pdev)) pr_info("[%s]:[%s:%d]:%d: %pV", dev_name(&qedi->pdev->dev), @@ -117,6 +119,7 @@ qedi_dbg_info(struct qedi_dbg_ctx *qedi, const char *func, u32 line, else pr_info("[0000:00:00.0]:[%s:%d]: %pV", nfunc, line, &vaf); +ret: va_end(va); } diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 5b1287a63c49..2f14adfab018 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -2248,7 +2248,7 @@ struct ct_fdmiv2_hba_attr { uint32_t num_ports; uint8_t fabric_name[WWN_SIZE]; uint8_t bios_name[32]; - uint8_t vendor_indentifer[8]; + uint8_t vendor_identifier[8]; } a; }; @@ -2423,7 +2423,7 @@ struct ct_sns_req { } rsnn_nn; struct { - uint8_t hba_indentifier[8]; + uint8_t hba_identifier[8]; } ghat; struct { diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index 94e8a8592f69..ee3df8794806 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -1939,15 +1939,15 @@ qla2x00_fdmiv2_rhba(scsi_qla_host_t *vha) /* Vendor Identifier */ eiter = entries + size; eiter->type = cpu_to_be16(FDMI_HBA_TYPE_VENDOR_IDENTIFIER); - snprintf(eiter->a.vendor_indentifer, sizeof(eiter->a.vendor_indentifer), + snprintf(eiter->a.vendor_identifier, sizeof(eiter->a.vendor_identifier), "%s", "QLGC"); - alen = strlen(eiter->a.vendor_indentifer); + alen = strlen(eiter->a.vendor_identifier); alen += 4 - (alen & 3); eiter->len = cpu_to_be16(4 + alen); size += 4 + alen; ql_dbg(ql_dbg_disc, vha, 0x20b1, - "Vendor Identifier = %s.\n", eiter->a.vendor_indentifer); + "Vendor Identifier = %s.\n", eiter->a.vendor_identifier); /* Update MS request size. */ qla2x00_update_ms_fdmi_iocb(vha, size + 16); diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 67e157d81da8..edc2264db45b 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -2997,14 +2997,14 @@ struct qla_init_msix_entry { irq_handler_t handler; }; -static struct qla_init_msix_entry msix_entries[] = { +static const struct qla_init_msix_entry msix_entries[] = { { "qla2xxx (default)", qla24xx_msix_default }, { "qla2xxx (rsp_q)", qla24xx_msix_rsp_q }, { "qla2xxx (atio_q)", qla83xx_msix_atio_q }, { "qla2xxx (qpair_multiq)", qla2xxx_msix_rsp_q }, }; -static struct qla_init_msix_entry qla82xx_msix_entries[] = { +static const struct qla_init_msix_entry qla82xx_msix_entries[] = { { "qla2xxx (default)", qla82xx_msix_default }, { "qla2xxx (rsp_q)", qla82xx_msix_rsp_q }, }; @@ -3078,7 +3078,7 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp) qentry->handle = rsp; rsp->msix = qentry; scnprintf(qentry->name, sizeof(qentry->name), - msix_entries[i].name); + "%s", msix_entries[i].name); if (IS_P3P_TYPE(ha)) ret = request_irq(qentry->vector, qla82xx_msix_entries[i].handler, @@ -3102,7 +3102,7 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp) rsp->msix = qentry; qentry->handle = rsp; scnprintf(qentry->name, sizeof(qentry->name), - msix_entries[QLA_ATIO_VECTOR].name); + "%s", msix_entries[QLA_ATIO_VECTOR].name); qentry->in_use = 1; ret = request_irq(qentry->vector, msix_entries[QLA_ATIO_VECTOR].handler, @@ -3244,7 +3244,7 @@ qla2x00_free_irqs(scsi_qla_host_t *vha) * from a probe failure context. */ if (!ha->rsp_q_map || !ha->rsp_q_map[0]) - return; + goto free_irqs; rsp = ha->rsp_q_map[0]; if (ha->flags.msix_enabled) { @@ -3264,13 +3264,14 @@ qla2x00_free_irqs(scsi_qla_host_t *vha) free_irq(pci_irq_vector(ha->pdev, 0), rsp); } +free_irqs: pci_free_irq_vectors(ha->pdev); } int qla25xx_request_irq(struct qla_hw_data *ha, struct qla_qpair *qpair, struct qla_msix_entry *msix, int vector_type) { - struct qla_init_msix_entry *intr = &msix_entries[vector_type]; + const struct qla_init_msix_entry *intr = &msix_entries[vector_type]; scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); int ret; diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 0a000ecf0881..40660461a4b5 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1616,7 +1616,7 @@ qla2x00_abort_all_cmds(scsi_qla_host_t *vha, int res) /* Don't abort commands in adapter during EEH * recovery as it's not accessible/responding. */ - if (!ha->flags.eeh_busy) { + if (GET_CMD_SP(sp) && !ha->flags.eeh_busy) { /* Get a reference to the sp and drop the lock. * The reference ensures this sp->done() call * - and not the call in qla2xxx_eh_abort() - diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h index aeebefb1e9f8..fc233717355f 100644 --- a/drivers/scsi/qla4xxx/ql4_def.h +++ b/drivers/scsi/qla4xxx/ql4_def.h @@ -408,9 +408,6 @@ struct qla4_8xxx_legacy_intr_set { }; /* MSI-X Support */ - -#define QLA_MSIX_DEFAULT 0 -#define QLA_MSIX_RSP_Q 1 #define QLA_MSIX_ENTRIES 2 /* diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 9fbb33fc90c7..ac52150d1569 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -9539,15 +9539,15 @@ exit_host_reset: * driver calls the following device driver's callbacks * * - Fatal Errors - link_reset - * - Non-Fatal Errors - driver's pci_error_detected() which + * - Non-Fatal Errors - driver's error_detected() which * returns CAN_RECOVER, NEED_RESET or DISCONNECT. * * PCI AER driver calls - * CAN_RECOVER - driver's pci_mmio_enabled(), mmio_enabled + * CAN_RECOVER - driver's mmio_enabled(), mmio_enabled() * returns RECOVERED or NEED_RESET if fw_hung * NEED_RESET - driver's slot_reset() * DISCONNECT - device is dead & cannot recover - * RECOVERED - driver's pci_resume() + * RECOVERED - driver's resume() */ static pci_ers_result_t qla4xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 03051e12a072..17249c3650fe 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -125,6 +125,7 @@ static const char *sdebug_version_date = "20160430"; #define DEF_OPTS 0 #define DEF_OPT_BLKS 1024 #define DEF_PHYSBLK_EXP 0 +#define DEF_OPT_XFERLEN_EXP 0 #define DEF_PTYPE TYPE_DISK #define DEF_REMOVABLE false #define DEF_SCSI_LEVEL 7 /* INQUIRY, byte2 [6->SPC-4; 7->SPC-5] */ @@ -590,6 +591,7 @@ static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */ static int sdebug_opt_blks = DEF_OPT_BLKS; static int sdebug_opts = DEF_OPTS; static int sdebug_physblk_exp = DEF_PHYSBLK_EXP; +static int sdebug_opt_xferlen_exp = DEF_OPT_XFERLEN_EXP; static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral device type */ static int sdebug_scsi_level = DEF_SCSI_LEVEL; static int sdebug_sector_size = DEF_SECTOR_SIZE; @@ -1205,7 +1207,11 @@ static int inquiry_vpd_b0(unsigned char *arr) memcpy(arr, vpdb0_data, sizeof(vpdb0_data)); /* Optimal transfer length granularity */ - gran = 1 << sdebug_physblk_exp; + if (sdebug_opt_xferlen_exp != 0 && + sdebug_physblk_exp < sdebug_opt_xferlen_exp) + gran = 1 << sdebug_opt_xferlen_exp; + else + gran = 1 << sdebug_physblk_exp; put_unaligned_be16(gran, arr + 2); /* Maximum Transfer Length */ @@ -4161,6 +4167,7 @@ module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR); module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO); module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR); module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO); +module_param_named(opt_xferlen_exp, sdebug_opt_xferlen_exp, int, S_IRUGO); module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR); module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR); module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO); @@ -4212,6 +4219,7 @@ MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)"); MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)"); MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)"); MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)"); +MODULE_PARM_DESC(opt_xferlen_exp, "optimal transfer length granularity exponent (def=physblk_exp)"); MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])"); MODULE_PARM_DESC(removable, "claim to have removable media (def=0)"); MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])"); diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 40b4038c019e..cb6e68dd6df0 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -703,7 +703,7 @@ 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 one + * @sdp: scsi device to operate on * @rq: Request to prepare * * Will issue either UNMAP or WRITE SAME(16) depending on preference @@ -3226,7 +3226,7 @@ static int sd_probe(struct device *dev) * sd_remove - called whenever a scsi disk (previously recognized by * sd_probe) is detached from the system. It is called (potentially * multiple times) during sd module unload. - * @sdp: pointer to mid level scsi device object + * @dev: pointer to device object * * Note: this function is invoked from the scsi mid-level. * This function potentially frees up a device name (e.g. /dev/sdc) diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index 05526b71541b..ceadf6b4ebc1 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -136,6 +136,8 @@ struct hv_fc_wwn_packet { #define SRB_FLAGS_PORT_DRIVER_RESERVED 0x0F000000 #define SRB_FLAGS_CLASS_DRIVER_RESERVED 0xF0000000 +#define SP_UNTAGGED ((unsigned char) ~0) +#define SRB_SIMPLE_TAG_REQUEST 0x20 /* * Platform neutral description of a scsi request - @@ -375,6 +377,7 @@ enum storvsc_request_type { #define SRB_STATUS_SUCCESS 0x01 #define SRB_STATUS_ABORTED 0x02 #define SRB_STATUS_ERROR 0x04 +#define SRB_STATUS_DATA_OVERRUN 0x12 #define SRB_STATUS(status) \ (status & ~(SRB_STATUS_AUTOSENSE_VALID | SRB_STATUS_QUEUE_FROZEN)) @@ -458,6 +461,15 @@ struct storvsc_device { * Max I/O, the device can support. */ u32 max_transfer_bytes; + /* + * Number of sub-channels we will open. + */ + u16 num_sc; + struct vmbus_channel **stor_chns; + /* + * Mask of CPUs bound to subchannels. + */ + struct cpumask alloced_cpus; /* Used for vsc/vsp channel reset process */ struct storvsc_cmd_request init_request; struct storvsc_cmd_request reset_request; @@ -635,6 +647,11 @@ static void handle_sc_creation(struct vmbus_channel *new_sc) (void *)&props, sizeof(struct vmstorage_channel_properties), storvsc_on_channel_callback, new_sc); + + if (new_sc->state == CHANNEL_OPENED_STATE) { + stor_device->stor_chns[new_sc->target_cpu] = new_sc; + cpumask_set_cpu(new_sc->target_cpu, &stor_device->alloced_cpus); + } } static void handle_multichannel_storage(struct hv_device *device, int max_chns) @@ -651,6 +668,7 @@ static void handle_multichannel_storage(struct hv_device *device, int max_chns) if (!stor_device) return; + stor_device->num_sc = num_sc; request = &stor_device->init_request; vstor_packet = &request->vstor_packet; @@ -838,6 +856,25 @@ static int storvsc_channel_init(struct hv_device *device, bool is_fc) * support multi-channel. */ max_chns = vstor_packet->storage_channel_properties.max_channel_cnt; + + /* + * Allocate state to manage the sub-channels. + * We allocate an array based on the numbers of possible CPUs + * (Hyper-V does not support cpu online/offline). + * This Array will be sparseley populated with unique + * channels - primary + sub-channels. + * We will however populate all the slots to evenly distribute + * the load. + */ + stor_device->stor_chns = kzalloc(sizeof(void *) * num_possible_cpus(), + GFP_KERNEL); + if (stor_device->stor_chns == NULL) + return -ENOMEM; + + stor_device->stor_chns[device->channel->target_cpu] = device->channel; + cpumask_set_cpu(device->channel->target_cpu, + &stor_device->alloced_cpus); + if (vmstor_proto_version >= VMSTOR_PROTO_VERSION_WIN8) { if (vstor_packet->storage_channel_properties.flags & STORAGE_CHANNEL_SUPPORTS_MULTI_CHANNEL) @@ -889,6 +926,13 @@ static void storvsc_handle_error(struct vmscsi_request *vm_srb, switch (SRB_STATUS(vm_srb->srb_status)) { case SRB_STATUS_ERROR: /* + * Let upper layer deal with error when + * sense message is present. + */ + + if (vm_srb->srb_status & SRB_STATUS_AUTOSENSE_VALID) + break; + /* * If there is an error; offline the device since all * error recovery strategies would have already been * deployed on the host side. However, if the command @@ -953,6 +997,7 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request, struct scsi_cmnd *scmnd = cmd_request->cmd; struct scsi_sense_hdr sense_hdr; struct vmscsi_request *vm_srb; + u32 data_transfer_length; struct Scsi_Host *host; u32 payload_sz = cmd_request->payload_sz; void *payload = cmd_request->payload; @@ -960,6 +1005,7 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request, host = stor_dev->host; vm_srb = &cmd_request->vstor_packet.vm_srb; + data_transfer_length = vm_srb->data_transfer_length; scmnd->result = vm_srb->scsi_status; @@ -973,13 +1019,20 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request, &sense_hdr); } - if (vm_srb->srb_status != SRB_STATUS_SUCCESS) + if (vm_srb->srb_status != SRB_STATUS_SUCCESS) { storvsc_handle_error(vm_srb, scmnd, host, sense_hdr.asc, sense_hdr.ascq); + /* + * The Windows driver set data_transfer_length on + * SRB_STATUS_DATA_OVERRUN. On other errors, this value + * is untouched. In these cases we set it to 0. + */ + if (vm_srb->srb_status != SRB_STATUS_DATA_OVERRUN) + data_transfer_length = 0; + } scsi_set_resid(scmnd, - cmd_request->payload->range.len - - vm_srb->data_transfer_length); + cmd_request->payload->range.len - data_transfer_length); scmnd->scsi_done(scmnd); @@ -1198,17 +1251,64 @@ static int storvsc_dev_remove(struct hv_device *device) /* Close the channel */ vmbus_close(device->channel); + kfree(stor_device->stor_chns); kfree(stor_device); return 0; } +static struct vmbus_channel *get_og_chn(struct storvsc_device *stor_device, + u16 q_num) +{ + u16 slot = 0; + u16 hash_qnum; + struct cpumask alloced_mask; + int num_channels, tgt_cpu; + + if (stor_device->num_sc == 0) + return stor_device->device->channel; + + /* + * Our channel array is sparsley populated and we + * initiated I/O on a processor/hw-q that does not + * currently have a designated channel. Fix this. + * The strategy is simple: + * I. Ensure NUMA locality + * II. Distribute evenly (best effort) + * III. Mapping is persistent. + */ + + cpumask_and(&alloced_mask, &stor_device->alloced_cpus, + cpumask_of_node(cpu_to_node(q_num))); + + num_channels = cpumask_weight(&alloced_mask); + if (num_channels == 0) + return stor_device->device->channel; + + hash_qnum = q_num; + while (hash_qnum >= num_channels) + hash_qnum -= num_channels; + + for_each_cpu(tgt_cpu, &alloced_mask) { + if (slot == hash_qnum) + break; + slot++; + } + + stor_device->stor_chns[q_num] = stor_device->stor_chns[tgt_cpu]; + + return stor_device->stor_chns[q_num]; +} + + static int storvsc_do_io(struct hv_device *device, - struct storvsc_cmd_request *request) + struct storvsc_cmd_request *request, u16 q_num) { struct storvsc_device *stor_device; struct vstor_packet *vstor_packet; struct vmbus_channel *outgoing_channel; int ret = 0; + struct cpumask alloced_mask; + int tgt_cpu; vstor_packet = &request->vstor_packet; stor_device = get_out_stor_device(device); @@ -1222,7 +1322,26 @@ static int storvsc_do_io(struct hv_device *device, * Select an an appropriate channel to send the request out. */ - outgoing_channel = vmbus_get_outgoing_channel(device->channel); + if (stor_device->stor_chns[q_num] != NULL) { + outgoing_channel = stor_device->stor_chns[q_num]; + if (outgoing_channel->target_cpu == smp_processor_id()) { + /* + * Ideally, we want to pick a different channel if + * available on the same NUMA node. + */ + cpumask_and(&alloced_mask, &stor_device->alloced_cpus, + cpumask_of_node(cpu_to_node(q_num))); + for_each_cpu(tgt_cpu, &alloced_mask) { + if (tgt_cpu != outgoing_channel->target_cpu) { + outgoing_channel = + stor_device->stor_chns[tgt_cpu]; + break; + } + } + } + } else { + outgoing_channel = get_og_chn(stor_device, q_num); + } vstor_packet->flags |= REQUEST_COMPLETION_FLAG; @@ -1267,8 +1386,6 @@ static int storvsc_do_io(struct hv_device *device, static int storvsc_device_configure(struct scsi_device *sdevice) { - blk_queue_max_segment_size(sdevice->request_queue, PAGE_SIZE); - blk_queue_bounce_limit(sdevice->request_queue, BLK_BOUNCE_ANY); blk_queue_rq_timeout(sdevice->request_queue, (storvsc_timeout * HZ)); @@ -1451,6 +1568,13 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd) vm_srb->win8_extension.srb_flags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER; + if (scmnd->device->tagged_supported) { + vm_srb->win8_extension.srb_flags |= + (SRB_FLAGS_QUEUE_ACTION_ENABLE | SRB_FLAGS_NO_QUEUE_FREEZE); + vm_srb->win8_extension.queue_tag = SP_UNTAGGED; + vm_srb->win8_extension.queue_action = SRB_SIMPLE_TAG_REQUEST; + } + /* Build the SRB */ switch (scmnd->sc_data_direction) { case DMA_TO_DEVICE: @@ -1511,20 +1635,14 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd) page_to_pfn(sg_page((cur_sgl))); cur_sgl = sg_next(cur_sgl); } - - } else if (scsi_sglist(scmnd)) { - payload->range.len = length; - payload->range.offset = - virt_to_phys(scsi_sglist(scmnd)) & (PAGE_SIZE-1); - payload->range.pfn_array[0] = - virt_to_phys(scsi_sglist(scmnd)) >> PAGE_SHIFT; } cmd_request->payload = payload; cmd_request->payload_sz = payload_sz; /* Invokes the vsc to start an IO */ - ret = storvsc_do_io(dev, cmd_request); + ret = storvsc_do_io(dev, cmd_request, get_cpu()); + put_cpu(); if (ret == -EAGAIN) { /* no more space */ @@ -1550,6 +1668,7 @@ static struct scsi_host_template scsi_driver = { /* Make sure we dont get a sg segment crosses a page boundary */ .dma_boundary = PAGE_SIZE-1, .no_write_same = 1, + .track_queue_depth = 1, }; enum { @@ -1680,6 +1799,11 @@ static int storvsc_probe(struct hv_device *device, * from the host. */ host->sg_tablesize = (stor_device->max_transfer_bytes >> PAGE_SHIFT); + /* + * Set the number of HW queues we are supporting. + */ + if (stor_device->num_sc != 0) + host->nr_hw_queues = stor_device->num_sc + 1; /* Register the HBA and start the scsi bus scan */ ret = scsi_add_host(host, &device->device); @@ -1716,6 +1840,7 @@ err_out2: goto err_out0; err_out1: + kfree(stor_device->stor_chns); kfree(stor_device); err_out0: diff --git a/drivers/scsi/sun3_scsi.c b/drivers/scsi/sun3_scsi.c index bcf7d05d1aab..e64b0c542f95 100644 --- a/drivers/scsi/sun3_scsi.c +++ b/drivers/scsi/sun3_scsi.c @@ -34,7 +34,6 @@ #include <asm/dvma.h> #include <scsi/scsi_host.h> -#include "sun3_scsi.h" /* minimum number of bytes to do dma on */ #define DMA_MIN_SIZE 129 @@ -56,11 +55,87 @@ #define NCR5380_dma_send_setup sun3scsi_dma_count #define NCR5380_dma_residual sun3scsi_dma_residual -#define NCR5380_acquire_dma_irq(instance) (1) -#define NCR5380_release_dma_irq(instance) - #include "NCR5380.h" +/* dma regs start at regbase + 8, directly after the NCR regs */ +struct sun3_dma_regs { + unsigned short dma_addr_hi; /* vme only */ + unsigned short dma_addr_lo; /* vme only */ + unsigned short dma_count_hi; /* vme only */ + unsigned short dma_count_lo; /* vme only */ + unsigned short udc_data; /* udc dma data reg (obio only) */ + unsigned short udc_addr; /* uda dma addr reg (obio only) */ + unsigned short fifo_data; /* fifo data reg, + * holds extra byte on odd dma reads + */ + unsigned short fifo_count; + unsigned short csr; /* control/status reg */ + unsigned short bpack_hi; /* vme only */ + unsigned short bpack_lo; /* vme only */ + unsigned short ivect; /* vme only */ + unsigned short fifo_count_hi; /* vme only */ +}; + +/* ucd chip specific regs - live in dvma space */ +struct sun3_udc_regs { + unsigned short rsel; /* select regs to load */ + unsigned short addr_hi; /* high word of addr */ + unsigned short addr_lo; /* low word */ + unsigned short count; /* words to be xfer'd */ + unsigned short mode_hi; /* high word of channel mode */ + unsigned short mode_lo; /* low word of channel mode */ +}; + +/* addresses of the udc registers */ +#define UDC_MODE 0x38 +#define UDC_CSR 0x2e /* command/status */ +#define UDC_CHN_HI 0x26 /* chain high word */ +#define UDC_CHN_LO 0x22 /* chain lo word */ +#define UDC_CURA_HI 0x1a /* cur reg A high */ +#define UDC_CURA_LO 0x0a /* cur reg A low */ +#define UDC_CURB_HI 0x12 /* cur reg B high */ +#define UDC_CURB_LO 0x02 /* cur reg B low */ +#define UDC_MODE_HI 0x56 /* mode reg high */ +#define UDC_MODE_LO 0x52 /* mode reg low */ +#define UDC_COUNT 0x32 /* words to xfer */ + +/* some udc commands */ +#define UDC_RESET 0 +#define UDC_CHN_START 0xa0 /* start chain */ +#define UDC_INT_ENABLE 0x32 /* channel 1 int on */ + +/* udc mode words */ +#define UDC_MODE_HIWORD 0x40 +#define UDC_MODE_LSEND 0xc2 +#define UDC_MODE_LRECV 0xd2 + +/* udc reg selections */ +#define UDC_RSEL_SEND 0x282 +#define UDC_RSEL_RECV 0x182 + +/* bits in csr reg */ +#define CSR_DMA_ACTIVE 0x8000 +#define CSR_DMA_CONFLICT 0x4000 +#define CSR_DMA_BUSERR 0x2000 + +#define CSR_FIFO_EMPTY 0x400 /* fifo flushed? */ +#define CSR_SDB_INT 0x200 /* sbc interrupt pending */ +#define CSR_DMA_INT 0x100 /* dma interrupt pending */ + +#define CSR_LEFT 0xc0 +#define CSR_LEFT_3 0xc0 +#define CSR_LEFT_2 0x80 +#define CSR_LEFT_1 0x40 +#define CSR_PACK_ENABLE 0x20 + +#define CSR_DMA_ENABLE 0x10 + +#define CSR_SEND 0x8 /* 1 = send 0 = recv */ +#define CSR_FIFO 0x2 /* reset fifo */ +#define CSR_INTR 0x4 /* interrupt enable */ +#define CSR_SCSI 0x1 + +#define VME_DATA24 0x3d00 extern int sun3_map_test(unsigned long, char *); diff --git a/drivers/scsi/sun3_scsi.h b/drivers/scsi/sun3_scsi.h deleted file mode 100644 index d22745fae328..000000000000 --- a/drivers/scsi/sun3_scsi.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Sun3 SCSI stuff by Erik Verbruggen (erik@bigmama.xtdnet.nl) - * - * Sun3 DMA additions by Sam Creasey (sammy@sammy.net) - * - * Adapted from mac_scsinew.h: - */ -/* - * Cumana Generic NCR5380 driver defines - * - * Copyright 1993, Drew Eckhardt - * Visionary Computing - * (Unix and Linux consulting and custom programming) - * drew@colorado.edu - * +1 (303) 440-4894 - */ - -#ifndef SUN3_SCSI_H -#define SUN3_SCSI_H - -/* additional registers - mainly DMA control regs */ -/* these start at regbase + 8 -- directly after the NCR regs */ -struct sun3_dma_regs { - unsigned short dma_addr_hi; /* vme only */ - unsigned short dma_addr_lo; /* vme only */ - unsigned short dma_count_hi; /* vme only */ - unsigned short dma_count_lo; /* vme only */ - unsigned short udc_data; /* udc dma data reg (obio only) */ - unsigned short udc_addr; /* uda dma addr reg (obio only) */ - unsigned short fifo_data; /* fifo data reg, holds extra byte on - odd dma reads */ - unsigned short fifo_count; - unsigned short csr; /* control/status reg */ - unsigned short bpack_hi; /* vme only */ - unsigned short bpack_lo; /* vme only */ - unsigned short ivect; /* vme only */ - unsigned short fifo_count_hi; /* vme only */ -}; - -/* ucd chip specific regs - live in dvma space */ -struct sun3_udc_regs { - unsigned short rsel; /* select regs to load */ - unsigned short addr_hi; /* high word of addr */ - unsigned short addr_lo; /* low word */ - unsigned short count; /* words to be xfer'd */ - unsigned short mode_hi; /* high word of channel mode */ - unsigned short mode_lo; /* low word of channel mode */ -}; - -/* addresses of the udc registers */ -#define UDC_MODE 0x38 -#define UDC_CSR 0x2e /* command/status */ -#define UDC_CHN_HI 0x26 /* chain high word */ -#define UDC_CHN_LO 0x22 /* chain lo word */ -#define UDC_CURA_HI 0x1a /* cur reg A high */ -#define UDC_CURA_LO 0x0a /* cur reg A low */ -#define UDC_CURB_HI 0x12 /* cur reg B high */ -#define UDC_CURB_LO 0x02 /* cur reg B low */ -#define UDC_MODE_HI 0x56 /* mode reg high */ -#define UDC_MODE_LO 0x52 /* mode reg low */ -#define UDC_COUNT 0x32 /* words to xfer */ - -/* some udc commands */ -#define UDC_RESET 0 -#define UDC_CHN_START 0xa0 /* start chain */ -#define UDC_INT_ENABLE 0x32 /* channel 1 int on */ - -/* udc mode words */ -#define UDC_MODE_HIWORD 0x40 -#define UDC_MODE_LSEND 0xc2 -#define UDC_MODE_LRECV 0xd2 - -/* udc reg selections */ -#define UDC_RSEL_SEND 0x282 -#define UDC_RSEL_RECV 0x182 - -/* bits in csr reg */ -#define CSR_DMA_ACTIVE 0x8000 -#define CSR_DMA_CONFLICT 0x4000 -#define CSR_DMA_BUSERR 0x2000 - -#define CSR_FIFO_EMPTY 0x400 /* fifo flushed? */ -#define CSR_SDB_INT 0x200 /* sbc interrupt pending */ -#define CSR_DMA_INT 0x100 /* dma interrupt pending */ - -#define CSR_LEFT 0xc0 -#define CSR_LEFT_3 0xc0 -#define CSR_LEFT_2 0x80 -#define CSR_LEFT_1 0x40 -#define CSR_PACK_ENABLE 0x20 - -#define CSR_DMA_ENABLE 0x10 - -#define CSR_SEND 0x8 /* 1 = send 0 = recv */ -#define CSR_FIFO 0x2 /* reset fifo */ -#define CSR_INTR 0x4 /* interrupt enable */ -#define CSR_SCSI 0x1 - -#define VME_DATA24 0x3d00 - -#endif /* SUN3_SCSI_H */ - diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index abe617372661..5ff8a6bf6fd3 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -1692,6 +1692,7 @@ static const struct of_device_id ufs_qcom_of_match[] = { { .compatible = "qcom,ufshc"}, {}, }; +MODULE_DEVICE_TABLE(of, ufs_qcom_of_match); static const struct dev_pm_ops ufs_qcom_pm_ops = { .suspend = ufshcd_pltfrm_suspend, diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h index 8e6709a3fb6b..318e4a1f76c9 100644 --- a/drivers/scsi/ufs/ufs.h +++ b/drivers/scsi/ufs/ufs.h @@ -523,4 +523,16 @@ struct ufs_dev_info { bool is_lu_power_on_wp; }; +#define MAX_MODEL_LEN 16 +/** + * ufs_dev_desc - ufs device details from the device descriptor + * + * @wmanufacturerid: card details + * @model: card model + */ +struct ufs_dev_desc { + u16 wmanufacturerid; + char model[MAX_MODEL_LEN + 1]; +}; + #endif /* End of Header */ diff --git a/drivers/scsi/ufs/ufs_quirks.h b/drivers/scsi/ufs/ufs_quirks.h index 08b799d4efcc..71f73d1d1ad1 100644 --- a/drivers/scsi/ufs/ufs_quirks.h +++ b/drivers/scsi/ufs/ufs_quirks.h @@ -21,41 +21,28 @@ #define UFS_ANY_VENDOR 0xFFFF #define UFS_ANY_MODEL "ANY_MODEL" -#define MAX_MODEL_LEN 16 - #define UFS_VENDOR_TOSHIBA 0x198 #define UFS_VENDOR_SAMSUNG 0x1CE #define UFS_VENDOR_SKHYNIX 0x1AD /** - * ufs_device_info - ufs device details - * @wmanufacturerid: card details - * @model: card model - */ -struct ufs_device_info { - u16 wmanufacturerid; - char model[MAX_MODEL_LEN + 1]; -}; - -/** * ufs_dev_fix - ufs device quirk info * @card: ufs card details * @quirk: device quirk */ struct ufs_dev_fix { - struct ufs_device_info card; + struct ufs_dev_desc card; unsigned int quirk; }; #define END_FIX { { 0 }, 0 } /* add specific device quirk */ -#define UFS_FIX(_vendor, _model, _quirk) \ - { \ - .card.wmanufacturerid = (_vendor),\ - .card.model = (_model), \ - .quirk = (_quirk), \ - } +#define UFS_FIX(_vendor, _model, _quirk) { \ + .card.wmanufacturerid = (_vendor),\ + .card.model = (_model), \ + .quirk = (_quirk), \ +} /* * If UFS device is having issue in processing LCC (Line Control @@ -144,7 +131,4 @@ struct ufs_dev_fix { */ #define UFS_DEVICE_QUIRK_HOST_PA_SAVECONFIGTIME (1 << 8) -struct ufs_hba; -void ufs_advertise_fixup_device(struct ufs_hba *hba); - #endif /* UFS_QUIRKS_H_ */ diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 20e5e5fb048c..a70bf066f277 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -45,6 +45,9 @@ #include "ufs_quirks.h" #include "unipro.h" +#define CREATE_TRACE_POINTS +#include <trace/events/ufs.h> + #define UFSHCD_REQ_SENSE_SIZE 18 #define UFSHCD_ENABLE_INTRS (UTP_TRANSFER_REQ_COMPL |\ @@ -94,6 +97,9 @@ _ret; \ }) +#define ufshcd_hex_dump(prefix_str, buf, len) \ +print_hex_dump(KERN_ERR, prefix_str, DUMP_PREFIX_OFFSET, 16, 4, buf, len, false) + static u32 ufs_query_desc_max_size[] = { QUERY_DESC_DEVICE_MAX_SIZE, QUERY_DESC_CONFIGURAION_MAX_SIZE, @@ -185,6 +191,22 @@ ufs_get_pm_lvl_to_link_pwr_state(enum ufs_pm_level lvl) return ufs_pm_lvl_states[lvl].link_state; } +static inline enum ufs_pm_level +ufs_get_desired_pm_lvl_for_dev_link_state(enum ufs_dev_pwr_mode dev_state, + enum uic_link_state link_state) +{ + enum ufs_pm_level lvl; + + for (lvl = UFS_PM_LVL_0; lvl < UFS_PM_LVL_MAX; lvl++) { + if ((ufs_pm_lvl_states[lvl].dev_state == dev_state) && + (ufs_pm_lvl_states[lvl].link_state == link_state)) + return lvl; + } + + /* if no match found, return the level 0 */ + return UFS_PM_LVL_0; +} + static struct ufs_dev_fix ufs_fixups[] = { /* UFS cards deviations table */ UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL, @@ -212,6 +234,7 @@ static struct ufs_dev_fix ufs_fixups[] = { static void ufshcd_tmc_handler(struct ufs_hba *hba); static void ufshcd_async_scan(void *data, async_cookie_t cookie); static int ufshcd_reset_and_restore(struct ufs_hba *hba); +static int ufshcd_eh_host_reset_handler(struct scsi_cmnd *cmd); static int ufshcd_clear_tm_cmd(struct ufs_hba *hba, int tag); static void ufshcd_hba_exit(struct ufs_hba *hba); static int ufshcd_probe_hba(struct ufs_hba *hba); @@ -223,6 +246,9 @@ static int ufshcd_uic_hibern8_exit(struct ufs_hba *hba); static int ufshcd_uic_hibern8_enter(struct ufs_hba *hba); static inline void ufshcd_add_delay_before_dme_cmd(struct ufs_hba *hba); static int ufshcd_host_reset_and_restore(struct ufs_hba *hba); +static void ufshcd_resume_clkscaling(struct ufs_hba *hba); +static void ufshcd_suspend_clkscaling(struct ufs_hba *hba); +static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up); static irqreturn_t ufshcd_intr(int irq, void *__hba); static int ufshcd_config_pwr_mode(struct ufs_hba *hba, struct ufs_pa_layer_attr *desired_pwr_mode); @@ -267,6 +293,192 @@ static inline void ufshcd_remove_non_printable(char *val) *val = ' '; } +static void ufshcd_add_command_trace(struct ufs_hba *hba, + unsigned int tag, const char *str) +{ + sector_t lba = -1; + u8 opcode = 0; + u32 intr, doorbell; + struct ufshcd_lrb *lrbp; + int transfer_len = -1; + + if (!trace_ufshcd_command_enabled()) + return; + + lrbp = &hba->lrb[tag]; + + if (lrbp->cmd) { /* data phase exists */ + opcode = (u8)(*lrbp->cmd->cmnd); + if ((opcode == READ_10) || (opcode == WRITE_10)) { + /* + * Currently we only fully trace read(10) and write(10) + * commands + */ + if (lrbp->cmd->request && lrbp->cmd->request->bio) + lba = + lrbp->cmd->request->bio->bi_iter.bi_sector; + transfer_len = be32_to_cpu( + lrbp->ucd_req_ptr->sc.exp_data_transfer_len); + } + } + + intr = ufshcd_readl(hba, REG_INTERRUPT_STATUS); + doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL); + trace_ufshcd_command(dev_name(hba->dev), str, tag, + doorbell, transfer_len, intr, lba, opcode); +} + +static void ufshcd_print_clk_freqs(struct ufs_hba *hba) +{ + struct ufs_clk_info *clki; + struct list_head *head = &hba->clk_list_head; + + if (!head || list_empty(head)) + return; + + list_for_each_entry(clki, head, list) { + if (!IS_ERR_OR_NULL(clki->clk) && clki->min_freq && + clki->max_freq) + dev_err(hba->dev, "clk: %s, rate: %u\n", + clki->name, clki->curr_freq); + } +} + +static void ufshcd_print_uic_err_hist(struct ufs_hba *hba, + struct ufs_uic_err_reg_hist *err_hist, char *err_name) +{ + int i; + + for (i = 0; i < UIC_ERR_REG_HIST_LENGTH; i++) { + int p = (i + err_hist->pos - 1) % UIC_ERR_REG_HIST_LENGTH; + + if (err_hist->reg[p] == 0) + continue; + dev_err(hba->dev, "%s[%d] = 0x%x at %lld us\n", err_name, i, + err_hist->reg[p], ktime_to_us(err_hist->tstamp[p])); + } +} + +static void ufshcd_print_host_regs(struct ufs_hba *hba) +{ + /* + * hex_dump reads its data without the readl macro. This might + * cause inconsistency issues on some platform, as the printed + * values may be from cache and not the most recent value. + * To know whether you are looking at an un-cached version verify + * that IORESOURCE_MEM flag is on when xxx_get_resource() is invoked + * during platform/pci probe function. + */ + ufshcd_hex_dump("host regs: ", hba->mmio_base, UFSHCI_REG_SPACE_SIZE); + dev_err(hba->dev, "hba->ufs_version = 0x%x, hba->capabilities = 0x%x\n", + hba->ufs_version, hba->capabilities); + dev_err(hba->dev, + "hba->outstanding_reqs = 0x%x, hba->outstanding_tasks = 0x%x\n", + (u32)hba->outstanding_reqs, (u32)hba->outstanding_tasks); + dev_err(hba->dev, + "last_hibern8_exit_tstamp at %lld us, hibern8_exit_cnt = %d\n", + ktime_to_us(hba->ufs_stats.last_hibern8_exit_tstamp), + hba->ufs_stats.hibern8_exit_cnt); + + ufshcd_print_uic_err_hist(hba, &hba->ufs_stats.pa_err, "pa_err"); + ufshcd_print_uic_err_hist(hba, &hba->ufs_stats.dl_err, "dl_err"); + ufshcd_print_uic_err_hist(hba, &hba->ufs_stats.nl_err, "nl_err"); + ufshcd_print_uic_err_hist(hba, &hba->ufs_stats.tl_err, "tl_err"); + ufshcd_print_uic_err_hist(hba, &hba->ufs_stats.dme_err, "dme_err"); + + ufshcd_print_clk_freqs(hba); + + if (hba->vops && hba->vops->dbg_register_dump) + hba->vops->dbg_register_dump(hba); +} + +static +void ufshcd_print_trs(struct ufs_hba *hba, unsigned long bitmap, bool pr_prdt) +{ + struct ufshcd_lrb *lrbp; + int tag; + + for_each_set_bit(tag, &bitmap, hba->nutrs) { + lrbp = &hba->lrb[tag]; + + dev_err(hba->dev, "UPIU[%d] - issue time %lld us\n", + tag, ktime_to_us(lrbp->issue_time_stamp)); + dev_err(hba->dev, + "UPIU[%d] - Transfer Request Descriptor phys@0x%llx\n", + tag, (u64)lrbp->utrd_dma_addr); + + ufshcd_hex_dump("UPIU TRD: ", lrbp->utr_descriptor_ptr, + sizeof(struct utp_transfer_req_desc)); + dev_err(hba->dev, "UPIU[%d] - Request UPIU phys@0x%llx\n", tag, + (u64)lrbp->ucd_req_dma_addr); + ufshcd_hex_dump("UPIU REQ: ", lrbp->ucd_req_ptr, + sizeof(struct utp_upiu_req)); + dev_err(hba->dev, "UPIU[%d] - Response UPIU phys@0x%llx\n", tag, + (u64)lrbp->ucd_rsp_dma_addr); + ufshcd_hex_dump("UPIU RSP: ", lrbp->ucd_rsp_ptr, + sizeof(struct utp_upiu_rsp)); + if (pr_prdt) { + int prdt_length = le16_to_cpu( + lrbp->utr_descriptor_ptr->prd_table_length); + + dev_err(hba->dev, + "UPIU[%d] - PRDT - %d entries phys@0x%llx\n", + tag, prdt_length, + (u64)lrbp->ucd_prdt_dma_addr); + ufshcd_hex_dump("UPIU PRDT: ", lrbp->ucd_prdt_ptr, + sizeof(struct ufshcd_sg_entry) * + prdt_length); + } + } +} + +static void ufshcd_print_tmrs(struct ufs_hba *hba, unsigned long bitmap) +{ + struct utp_task_req_desc *tmrdp; + int tag; + + for_each_set_bit(tag, &bitmap, hba->nutmrs) { + tmrdp = &hba->utmrdl_base_addr[tag]; + dev_err(hba->dev, "TM[%d] - Task Management Header\n", tag); + ufshcd_hex_dump("TM TRD: ", &tmrdp->header, + sizeof(struct request_desc_header)); + dev_err(hba->dev, "TM[%d] - Task Management Request UPIU\n", + tag); + ufshcd_hex_dump("TM REQ: ", tmrdp->task_req_upiu, + sizeof(struct utp_upiu_req)); + dev_err(hba->dev, "TM[%d] - Task Management Response UPIU\n", + tag); + ufshcd_hex_dump("TM RSP: ", tmrdp->task_rsp_upiu, + sizeof(struct utp_task_req_desc)); + } +} + +/** + * ufshcd_print_pwr_info - print power params as saved in hba + * power info + * @hba: per-adapter instance + */ +static void ufshcd_print_pwr_info(struct ufs_hba *hba) +{ + static const char * const names[] = { + "INVALID MODE", + "FAST MODE", + "SLOW_MODE", + "INVALID MODE", + "FASTAUTO_MODE", + "SLOWAUTO_MODE", + "INVALID MODE", + }; + + dev_err(hba->dev, "%s:[RX, TX]: gear=[%d, %d], lane[%d, %d], pwr[%s, %s], rate = %d\n", + __func__, + hba->pwr_info.gear_rx, hba->pwr_info.gear_tx, + hba->pwr_info.lane_rx, hba->pwr_info.lane_tx, + names[hba->pwr_info.pwr_rx], + names[hba->pwr_info.pwr_tx], + hba->pwr_info.hs_rate); +} + /* * ufshcd_wait_for_register - wait for register value to change * @hba - per-adapter interface @@ -605,6 +817,28 @@ static inline int ufshcd_is_hba_active(struct ufs_hba *hba) return (ufshcd_readl(hba, REG_CONTROLLER_ENABLE) & 0x1) ? 0 : 1; } +static const char *ufschd_uic_link_state_to_string( + enum uic_link_state state) +{ + switch (state) { + case UIC_LINK_OFF_STATE: return "OFF"; + case UIC_LINK_ACTIVE_STATE: return "ACTIVE"; + case UIC_LINK_HIBERN8_STATE: return "HIBERN8"; + default: return "UNKNOWN"; + } +} + +static const char *ufschd_ufs_dev_pwr_mode_to_string( + enum ufs_dev_pwr_mode state) +{ + switch (state) { + case UFS_ACTIVE_PWR_MODE: return "ACTIVE"; + case UFS_SLEEP_PWR_MODE: return "SLEEP"; + case UFS_POWERDOWN_PWR_MODE: return "POWERDOWN"; + default: return "UNKNOWN"; + } +} + u32 ufshcd_get_local_unipro_ver(struct ufs_hba *hba) { /* HCI version 1.0 and 1.1 supports UniPro 1.41 */ @@ -635,16 +869,58 @@ static bool ufshcd_is_unipro_pa_params_tuning_req(struct ufs_hba *hba) static void ufshcd_suspend_clkscaling(struct ufs_hba *hba) { - if (ufshcd_is_clkscaling_enabled(hba)) { - devfreq_suspend_device(hba->devfreq); - hba->clk_scaling.window_start_t = 0; - } + if (!ufshcd_is_clkscaling_supported(hba)) + return; + + devfreq_suspend_device(hba->devfreq); + hba->clk_scaling.window_start_t = 0; } static void ufshcd_resume_clkscaling(struct ufs_hba *hba) { - if (ufshcd_is_clkscaling_enabled(hba)) - devfreq_resume_device(hba->devfreq); + devfreq_resume_device(hba->devfreq); +} + +static ssize_t ufshcd_clkscale_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE, "%d\n", hba->clk_scaling.is_allowed); +} + +static ssize_t ufshcd_clkscale_enable_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + u32 value; + int err; + + if (kstrtou32(buf, 0, &value)) + return -EINVAL; + + value = !!value; + if (value == hba->clk_scaling.is_allowed) + goto out; + + pm_runtime_get_sync(hba->dev); + ufshcd_hold(hba, false); + + if (value) { + ufshcd_resume_clkscaling(hba); + } else { + ufshcd_suspend_clkscaling(hba); + err = ufshcd_scale_clks(hba, true); + if (err) + dev_err(hba->dev, "%s: failed to scale clocks up %d\n", + __func__, err); + } + hba->clk_scaling.is_allowed = value; + + ufshcd_release(hba); + pm_runtime_put_sync(hba->dev); +out: + return count; } static void ufshcd_ungate_work(struct work_struct *work) @@ -680,7 +956,8 @@ static void ufshcd_ungate_work(struct work_struct *work) hba->clk_gating.is_suspended = false; } unblock_reqs: - ufshcd_resume_clkscaling(hba); + if (hba->clk_scaling.is_allowed) + ufshcd_resume_clkscaling(hba); scsi_unblock_requests(hba->host); } @@ -727,6 +1004,8 @@ start: case REQ_CLKS_OFF: if (cancel_delayed_work(&hba->clk_gating.gate_work)) { hba->clk_gating.state = CLKS_ON; + trace_ufshcd_clk_gating(dev_name(hba->dev), + hba->clk_gating.state); break; } /* @@ -737,6 +1016,8 @@ start: case CLKS_OFF: scsi_block_requests(hba->host); hba->clk_gating.state = REQ_CLKS_ON; + trace_ufshcd_clk_gating(dev_name(hba->dev), + hba->clk_gating.state); schedule_work(&hba->clk_gating.ungate_work); /* * fall through to check if we should wait for this @@ -781,6 +1062,8 @@ static void ufshcd_gate_work(struct work_struct *work) if (hba->clk_gating.is_suspended || (hba->clk_gating.state == REQ_CLKS_ON)) { hba->clk_gating.state = CLKS_ON; + trace_ufshcd_clk_gating(dev_name(hba->dev), + hba->clk_gating.state); goto rel_lock; } @@ -796,6 +1079,8 @@ static void ufshcd_gate_work(struct work_struct *work) if (ufshcd_can_hibern8_during_gating(hba)) { if (ufshcd_uic_hibern8_enter(hba)) { hba->clk_gating.state = CLKS_ON; + trace_ufshcd_clk_gating(dev_name(hba->dev), + hba->clk_gating.state); goto out; } ufshcd_set_link_hibern8(hba); @@ -819,9 +1104,11 @@ static void ufshcd_gate_work(struct work_struct *work) * new requests arriving before the current cancel work is done. */ spin_lock_irqsave(hba->host->host_lock, flags); - if (hba->clk_gating.state == REQ_CLKS_OFF) + if (hba->clk_gating.state == REQ_CLKS_OFF) { hba->clk_gating.state = CLKS_OFF; - + trace_ufshcd_clk_gating(dev_name(hba->dev), + hba->clk_gating.state); + } rel_lock: spin_unlock_irqrestore(hba->host->host_lock, flags); out: @@ -844,6 +1131,7 @@ static void __ufshcd_release(struct ufs_hba *hba) return; hba->clk_gating.state = REQ_CLKS_OFF; + trace_ufshcd_clk_gating(dev_name(hba->dev), hba->clk_gating.state); schedule_delayed_work(&hba->clk_gating.gate_work, msecs_to_jiffies(hba->clk_gating.delay_ms)); } @@ -881,6 +1169,41 @@ static ssize_t ufshcd_clkgate_delay_store(struct device *dev, return count; } +static ssize_t ufshcd_clkgate_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE, "%d\n", hba->clk_gating.is_enabled); +} + +static ssize_t ufshcd_clkgate_enable_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + unsigned long flags; + u32 value; + + if (kstrtou32(buf, 0, &value)) + return -EINVAL; + + value = !!value; + if (value == hba->clk_gating.is_enabled) + goto out; + + if (value) { + ufshcd_release(hba); + } else { + spin_lock_irqsave(hba->host->host_lock, flags); + hba->clk_gating.active_reqs++; + spin_unlock_irqrestore(hba->host->host_lock, flags); + } + + hba->clk_gating.is_enabled = value; +out: + return count; +} + static void ufshcd_init_clk_gating(struct ufs_hba *hba) { if (!ufshcd_is_clkgating_allowed(hba)) @@ -890,13 +1213,23 @@ static void ufshcd_init_clk_gating(struct ufs_hba *hba) INIT_DELAYED_WORK(&hba->clk_gating.gate_work, ufshcd_gate_work); INIT_WORK(&hba->clk_gating.ungate_work, ufshcd_ungate_work); + hba->clk_gating.is_enabled = true; + hba->clk_gating.delay_attr.show = ufshcd_clkgate_delay_show; hba->clk_gating.delay_attr.store = ufshcd_clkgate_delay_store; sysfs_attr_init(&hba->clk_gating.delay_attr.attr); hba->clk_gating.delay_attr.attr.name = "clkgate_delay_ms"; - hba->clk_gating.delay_attr.attr.mode = S_IRUGO | S_IWUSR; + hba->clk_gating.delay_attr.attr.mode = 0644; if (device_create_file(hba->dev, &hba->clk_gating.delay_attr)) dev_err(hba->dev, "Failed to create sysfs for clkgate_delay\n"); + + hba->clk_gating.enable_attr.show = ufshcd_clkgate_enable_show; + hba->clk_gating.enable_attr.store = ufshcd_clkgate_enable_store; + sysfs_attr_init(&hba->clk_gating.enable_attr.attr); + hba->clk_gating.enable_attr.attr.name = "clkgate_enable"; + hba->clk_gating.enable_attr.attr.mode = 0644; + if (device_create_file(hba->dev, &hba->clk_gating.enable_attr)) + dev_err(hba->dev, "Failed to create sysfs for clkgate_enable\n"); } static void ufshcd_exit_clk_gating(struct ufs_hba *hba) @@ -904,6 +1237,7 @@ static void ufshcd_exit_clk_gating(struct ufs_hba *hba) if (!ufshcd_is_clkgating_allowed(hba)) return; device_remove_file(hba->dev, &hba->clk_gating.delay_attr); + device_remove_file(hba->dev, &hba->clk_gating.enable_attr); cancel_work_sync(&hba->clk_gating.ungate_work); cancel_delayed_work_sync(&hba->clk_gating.gate_work); } @@ -911,7 +1245,7 @@ static void ufshcd_exit_clk_gating(struct ufs_hba *hba) /* Must be called with host lock acquired */ static void ufshcd_clk_scaling_start_busy(struct ufs_hba *hba) { - if (!ufshcd_is_clkscaling_enabled(hba)) + if (!ufshcd_is_clkscaling_supported(hba)) return; if (!hba->clk_scaling.is_busy_started) { @@ -924,7 +1258,7 @@ static void ufshcd_clk_scaling_update_busy(struct ufs_hba *hba) { struct ufs_clk_scaling *scaling = &hba->clk_scaling; - if (!ufshcd_is_clkscaling_enabled(hba)) + if (!ufshcd_is_clkscaling_supported(hba)) return; if (!hba->outstanding_reqs && scaling->is_busy_started) { @@ -942,11 +1276,13 @@ static void ufshcd_clk_scaling_update_busy(struct ufs_hba *hba) static inline void ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag) { + hba->lrb[task_tag].issue_time_stamp = ktime_get(); ufshcd_clk_scaling_start_busy(hba); __set_bit(task_tag, &hba->outstanding_reqs); ufshcd_writel(hba, 1 << task_tag, REG_UTP_TRANSFER_REQ_DOOR_BELL); /* Make sure that doorbell is committed immediately */ wmb(); + ufshcd_add_command_trace(hba, task_tag, "send"); } /** @@ -1622,6 +1958,7 @@ ufshcd_dev_cmd_completion(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) int resp; int err = 0; + hba->ufs_stats.last_hibern8_exit_tstamp = ktime_set(0, 0); resp = ufshcd_get_req_rsp(lrbp->ucd_rsp_ptr); switch (resp) { @@ -2073,9 +2410,11 @@ out: * The buf_len parameter will contain, on return, the length parameter * received on the response. */ -int ufshcd_query_descriptor_retry(struct ufs_hba *hba, - enum query_opcode opcode, enum desc_idn idn, u8 index, - u8 selector, u8 *desc_buf, int *buf_len) +static int ufshcd_query_descriptor_retry(struct ufs_hba *hba, + enum query_opcode opcode, + enum desc_idn idn, u8 index, + u8 selector, + u8 *desc_buf, int *buf_len) { int err; int retries; @@ -2089,7 +2428,6 @@ int ufshcd_query_descriptor_retry(struct ufs_hba *hba, return err; } -EXPORT_SYMBOL(ufshcd_query_descriptor_retry); /** * ufshcd_read_desc_param - read the specified descriptor parameter @@ -2207,11 +2545,10 @@ static inline int ufshcd_read_power_desc(struct ufs_hba *hba, return err; } -int ufshcd_read_device_desc(struct ufs_hba *hba, u8 *buf, u32 size) +static int ufshcd_read_device_desc(struct ufs_hba *hba, u8 *buf, u32 size) { return ufshcd_read_desc(hba, QUERY_DESC_IDN_DEVICE, 0, buf, size); } -EXPORT_SYMBOL(ufshcd_read_device_desc); /** * ufshcd_read_string_desc - read string descriptor @@ -2223,8 +2560,9 @@ EXPORT_SYMBOL(ufshcd_read_device_desc); * * Return 0 in case of success, non-zero otherwise */ -int ufshcd_read_string_desc(struct ufs_hba *hba, int desc_index, u8 *buf, - u32 size, bool ascii) +#define ASCII_STD true +static int ufshcd_read_string_desc(struct ufs_hba *hba, int desc_index, + u8 *buf, u32 size, bool ascii) { int err = 0; @@ -2280,7 +2618,6 @@ int ufshcd_read_string_desc(struct ufs_hba *hba, int desc_index, u8 *buf, out: return err; } -EXPORT_SYMBOL(ufshcd_read_string_desc); /** * ufshcd_read_unit_desc_param - read the specified unit descriptor parameter @@ -2453,12 +2790,19 @@ static void ufshcd_host_memory_configure(struct ufs_hba *hba) } hba->lrb[i].utr_descriptor_ptr = (utrdlp + i); + hba->lrb[i].utrd_dma_addr = hba->utrdl_dma_addr + + (i * sizeof(struct utp_transfer_req_desc)); hba->lrb[i].ucd_req_ptr = (struct utp_upiu_req *)(cmd_descp + i); + hba->lrb[i].ucd_req_dma_addr = cmd_desc_element_addr; hba->lrb[i].ucd_rsp_ptr = (struct utp_upiu_rsp *)cmd_descp[i].response_upiu; + hba->lrb[i].ucd_rsp_dma_addr = cmd_desc_element_addr + + response_offset; hba->lrb[i].ucd_prdt_ptr = (struct ufshcd_sg_entry *)cmd_descp[i].prd_table; + hba->lrb[i].ucd_prdt_dma_addr = cmd_desc_element_addr + + prdt_offset; } } @@ -2482,7 +2826,7 @@ static int ufshcd_dme_link_startup(struct ufs_hba *hba) ret = ufshcd_send_uic_cmd(hba, &uic_cmd); if (ret) - dev_err(hba->dev, + dev_dbg(hba->dev, "dme-link-startup: error code %d\n", ret); return ret; } @@ -2776,11 +3120,14 @@ static int __ufshcd_uic_hibern8_enter(struct ufs_hba *hba) { int ret; struct uic_command uic_cmd = {0}; + ktime_t start = ktime_get(); ufshcd_vops_hibern8_notify(hba, UIC_CMD_DME_HIBER_ENTER, PRE_CHANGE); uic_cmd.command = UIC_CMD_DME_HIBER_ENTER; ret = ufshcd_uic_pwr_ctrl(hba, &uic_cmd); + trace_ufshcd_profile_hibern8(dev_name(hba->dev), "enter", + ktime_to_us(ktime_sub(ktime_get(), start)), ret); if (ret) { dev_err(hba->dev, "%s: hibern8 enter failed. ret = %d\n", @@ -2816,18 +3163,25 @@ static int ufshcd_uic_hibern8_exit(struct ufs_hba *hba) { struct uic_command uic_cmd = {0}; int ret; + ktime_t start = ktime_get(); ufshcd_vops_hibern8_notify(hba, UIC_CMD_DME_HIBER_EXIT, PRE_CHANGE); uic_cmd.command = UIC_CMD_DME_HIBER_EXIT; ret = ufshcd_uic_pwr_ctrl(hba, &uic_cmd); + trace_ufshcd_profile_hibern8(dev_name(hba->dev), "exit", + ktime_to_us(ktime_sub(ktime_get(), start)), ret); + if (ret) { dev_err(hba->dev, "%s: hibern8 exit failed. ret = %d\n", __func__, ret); ret = ufshcd_link_recovery(hba); - } else + } else { ufshcd_vops_hibern8_notify(hba, UIC_CMD_DME_HIBER_EXIT, POST_CHANGE); + hba->ufs_stats.last_hibern8_exit_tstamp = ktime_get(); + hba->ufs_stats.hibern8_exit_cnt++; + } return ret; } @@ -2973,6 +3327,8 @@ static int ufshcd_change_power_mode(struct ufs_hba *hba, sizeof(struct ufs_pa_layer_attr)); } + ufshcd_print_pwr_info(hba); + return ret; } @@ -3265,6 +3621,10 @@ link_startup: goto link_startup; } + /* Mark that link is up in PWM-G1, 1-lane, SLOW-AUTO mode */ + ufshcd_init_pwr_info(hba); + ufshcd_print_pwr_info(hba); + if (hba->quirks & UFSHCD_QUIRK_BROKEN_LCC) { ret = ufshcd_disable_device_tx_lcc(hba); if (ret) @@ -3591,7 +3951,7 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) switch (ocs) { case OCS_SUCCESS: result = ufshcd_get_req_rsp(lrbp->ucd_rsp_ptr); - + hba->ufs_stats.last_hibern8_exit_tstamp = ktime_set(0, 0); switch (result) { case UPIU_TRANSACTION_RESPONSE: /* @@ -3652,10 +4012,14 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) default: result |= DID_ERROR << 16; dev_err(hba->dev, - "OCS error from controller = %x\n", ocs); + "OCS error from controller = %x for tag %d\n", + ocs, lrbp->task_tag); + ufshcd_print_host_regs(hba); break; } /* end of switch */ + if (host_byte(result) != DID_OK) + ufshcd_print_trs(hba, 1 << lrbp->task_tag, true); return result; } @@ -3695,6 +4059,7 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba, lrbp = &hba->lrb[index]; cmd = lrbp->cmd; if (cmd) { + ufshcd_add_command_trace(hba, index, "complete"); result = ufshcd_transfer_rsp_status(hba, lrbp); scsi_dma_unmap(cmd); cmd->result = result; @@ -3706,8 +4071,11 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba, __ufshcd_release(hba); } else if (lrbp->command_type == UTP_CMD_TYPE_DEV_MANAGE || lrbp->command_type == UTP_CMD_TYPE_UFS_STORAGE) { - if (hba->dev_cmd.complete) + if (hba->dev_cmd.complete) { + ufshcd_add_command_trace(hba, index, + "dev_complete"); complete(hba->dev_cmd.complete); + } } } @@ -3828,6 +4196,7 @@ static int ufshcd_enable_auto_bkops(struct ufs_hba *hba) } hba->auto_bkops_enabled = true; + trace_ufshcd_auto_bkops_state(dev_name(hba->dev), "Enabled"); /* No need of URGENT_BKOPS exception from the device */ err = ufshcd_disable_ee(hba, MASK_EE_URGENT_BKOPS); @@ -3878,23 +4247,31 @@ static int ufshcd_disable_auto_bkops(struct ufs_hba *hba) } hba->auto_bkops_enabled = false; + trace_ufshcd_auto_bkops_state(dev_name(hba->dev), "Disabled"); out: return err; } /** - * ufshcd_force_reset_auto_bkops - force enable of auto bkops + * ufshcd_force_reset_auto_bkops - force reset auto bkops state * @hba: per adapter instance * * After a device reset the device may toggle the BKOPS_EN flag * to default value. The s/w tracking variables should be updated - * as well. Do this by forcing enable of auto bkops. + * as well. This function would change the auto-bkops state based on + * UFSHCD_CAP_KEEP_AUTO_BKOPS_ENABLED_EXCEPT_SUSPEND. */ -static void ufshcd_force_reset_auto_bkops(struct ufs_hba *hba) +static void ufshcd_force_reset_auto_bkops(struct ufs_hba *hba) { - hba->auto_bkops_enabled = false; - hba->ee_ctrl_mask |= MASK_EE_URGENT_BKOPS; - ufshcd_enable_auto_bkops(hba); + if (ufshcd_keep_autobkops_enabled_except_suspend(hba)) { + hba->auto_bkops_enabled = false; + hba->ee_ctrl_mask |= MASK_EE_URGENT_BKOPS; + ufshcd_enable_auto_bkops(hba); + } else { + hba->auto_bkops_enabled = true; + hba->ee_ctrl_mask &= ~MASK_EE_URGENT_BKOPS; + ufshcd_disable_auto_bkops(hba); + } } static inline int ufshcd_get_bkops_status(struct ufs_hba *hba, u32 *status) @@ -4246,6 +4623,14 @@ out: pm_runtime_put_sync(hba->dev); } +static void ufshcd_update_uic_reg_hist(struct ufs_uic_err_reg_hist *reg_hist, + u32 reg) +{ + reg_hist->reg[reg_hist->pos] = reg; + reg_hist->tstamp[reg_hist->pos] = ktime_get(); + reg_hist->pos = (reg_hist->pos + 1) % UIC_ERR_REG_HIST_LENGTH; +} + /** * ufshcd_update_uic_error - check and set fatal UIC error flags. * @hba: per-adapter instance @@ -4258,15 +4643,20 @@ static void ufshcd_update_uic_error(struct ufs_hba *hba) reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER); /* Ignore LINERESET indication, as this is not an error */ if ((reg & UIC_PHY_ADAPTER_LAYER_ERROR) && - (reg & UIC_PHY_ADAPTER_LAYER_LANE_ERR_MASK)) + (reg & UIC_PHY_ADAPTER_LAYER_LANE_ERR_MASK)) { /* * To know whether this error is fatal or not, DB timeout * must be checked but this error is handled separately. */ dev_dbg(hba->dev, "%s: UIC Lane error reported\n", __func__); + ufshcd_update_uic_reg_hist(&hba->ufs_stats.pa_err, reg); + } /* PA_INIT_ERROR is fatal and needs UIC reset */ reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_DATA_LINK_LAYER); + if (reg) + ufshcd_update_uic_reg_hist(&hba->ufs_stats.dl_err, reg); + if (reg & UIC_DATA_LINK_LAYER_ERROR_PA_INIT) hba->uic_error |= UFSHCD_UIC_DL_PA_INIT_ERROR; else if (hba->dev_quirks & @@ -4280,16 +4670,22 @@ static void ufshcd_update_uic_error(struct ufs_hba *hba) /* UIC NL/TL/DME errors needs software retry */ reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_NETWORK_LAYER); - if (reg) + if (reg) { + ufshcd_update_uic_reg_hist(&hba->ufs_stats.nl_err, reg); hba->uic_error |= UFSHCD_UIC_NL_ERROR; + } reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_TRANSPORT_LAYER); - if (reg) + if (reg) { + ufshcd_update_uic_reg_hist(&hba->ufs_stats.tl_err, reg); hba->uic_error |= UFSHCD_UIC_TL_ERROR; + } reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_DME); - if (reg) + if (reg) { + ufshcd_update_uic_reg_hist(&hba->ufs_stats.dme_err, reg); hba->uic_error |= UFSHCD_UIC_DME_ERROR; + } dev_dbg(hba->dev, "%s: UIC error flags = 0x%08x\n", __func__, hba->uic_error); @@ -4327,6 +4723,22 @@ static void ufshcd_check_errors(struct ufs_hba *hba) scsi_block_requests(hba->host); hba->ufshcd_state = UFSHCD_STATE_EH_SCHEDULED; + + /* dump controller state before resetting */ + if (hba->saved_err & (INT_FATAL_ERRORS | UIC_ERROR)) { + bool pr_prdt = !!(hba->saved_err & + SYSTEM_BUS_FATAL_ERROR); + + dev_err(hba->dev, "%s: saved_err 0x%x saved_uic_err 0x%x\n", + __func__, hba->saved_err, + hba->saved_uic_err); + + ufshcd_print_host_regs(hba); + ufshcd_print_pwr_info(hba); + ufshcd_print_tmrs(hba, hba->outstanding_tasks); + ufshcd_print_trs(hba, hba->outstanding_reqs, + pr_prdt); + } schedule_work(&hba->eh_work); } } @@ -4594,6 +5006,7 @@ static int ufshcd_abort(struct scsi_cmnd *cmd) host = cmd->device->host; hba = shost_priv(host); tag = cmd->request->tag; + lrbp = &hba->lrb[tag]; if (!ufshcd_valid_tag(hba, tag)) { dev_err(hba->dev, "%s: invalid command tag %d: cmd=0x%p, cmd->request=0x%p", @@ -4601,6 +5014,16 @@ static int ufshcd_abort(struct scsi_cmnd *cmd) BUG(); } + /* + * Task abort to the device W-LUN is illegal. When this command + * will fail, due to spec violation, scsi err handling next step + * will be to send LU reset which, again, is a spec violation. + * To avoid these unnecessary/illegal step we skip to the last error + * handling stage: reset and restore. + */ + if (lrbp->lun == UFS_UPIU_UFS_DEVICE_WLUN) + return ufshcd_eh_host_reset_handler(cmd); + ufshcd_hold(hba, false); reg = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL); /* If command is already aborted/completed, return SUCCESS */ @@ -4617,18 +5040,28 @@ static int ufshcd_abort(struct scsi_cmnd *cmd) __func__, tag); } - lrbp = &hba->lrb[tag]; + /* Print Transfer Request of aborted task */ + dev_err(hba->dev, "%s: Device abort task at tag %d\n", __func__, tag); + scsi_print_command(hba->lrb[tag].cmd); + ufshcd_print_host_regs(hba); + ufshcd_print_pwr_info(hba); + ufshcd_print_trs(hba, 1 << tag, true); + for (poll_cnt = 100; poll_cnt; poll_cnt--) { err = ufshcd_issue_tm_cmd(hba, lrbp->lun, lrbp->task_tag, UFS_QUERY_TASK, &resp); if (!err && resp == UPIU_TASK_MANAGEMENT_FUNC_SUCCEEDED) { /* cmd pending in the device */ + dev_err(hba->dev, "%s: cmd pending in the device. tag = %d\n", + __func__, tag); break; } else if (!err && resp == UPIU_TASK_MANAGEMENT_FUNC_COMPL) { /* * cmd not pending in the device, check if it is * in transition. */ + dev_err(hba->dev, "%s: cmd at tag %d not pending in the device.\n", + __func__, tag); reg = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL); if (reg & (1 << tag)) { /* sleep for max. 200us to stabilize */ @@ -4636,8 +5069,13 @@ static int ufshcd_abort(struct scsi_cmnd *cmd) continue; } /* command completed already */ + dev_err(hba->dev, "%s: cmd at tag %d successfully cleared from DB.\n", + __func__, tag); goto out; } else { + dev_err(hba->dev, + "%s: no response from device. tag = %d, err %d\n", + __func__, tag, err); if (!err) err = resp; /* service response error */ goto out; @@ -4652,14 +5090,20 @@ static int ufshcd_abort(struct scsi_cmnd *cmd) err = ufshcd_issue_tm_cmd(hba, lrbp->lun, lrbp->task_tag, UFS_ABORT_TASK, &resp); if (err || resp != UPIU_TASK_MANAGEMENT_FUNC_COMPL) { - if (!err) + if (!err) { err = resp; /* service response error */ + dev_err(hba->dev, "%s: issued. tag = %d, err %d\n", + __func__, tag, err); + } goto out; } err = ufshcd_clear_cmd(hba, tag); - if (err) + if (err) { + dev_err(hba->dev, "%s: Failed clearing cmd at tag %d, err %d\n", + __func__, tag, err); goto out; + } scsi_dma_unmap(cmd); @@ -4822,7 +5266,7 @@ static u32 ufshcd_get_max_icc_level(int sup_curr_uA, u32 start_scan, char *buff) u16 unit; for (i = start_scan; i >= 0; i--) { - data = be16_to_cpu(*((u16 *)(buff + 2*i))); + data = be16_to_cpup((__be16 *)&buff[2 * i]); unit = (data & ATTR_ICC_LVL_UNIT_MASK) >> ATTR_ICC_LVL_UNIT_OFFSET; curr_uA = data & ATTR_ICC_LVL_VALUE_MASK; @@ -5008,8 +5452,8 @@ out: return ret; } -static int ufs_get_device_info(struct ufs_hba *hba, - struct ufs_device_info *card_data) +static int ufs_get_device_desc(struct ufs_hba *hba, + struct ufs_dev_desc *dev_desc) { int err; u8 model_index; @@ -5028,7 +5472,7 @@ static int ufs_get_device_info(struct ufs_hba *hba, * getting vendor (manufacturerID) and Bank Index in big endian * format */ - card_data->wmanufacturerid = desc_buf[DEVICE_DESC_PARAM_MANF_ID] << 8 | + dev_desc->wmanufacturerid = desc_buf[DEVICE_DESC_PARAM_MANF_ID] << 8 | desc_buf[DEVICE_DESC_PARAM_MANF_ID + 1]; model_index = desc_buf[DEVICE_DESC_PARAM_PRDCT_NAME]; @@ -5042,36 +5486,26 @@ static int ufs_get_device_info(struct ufs_hba *hba, } str_desc_buf[QUERY_DESC_STRING_MAX_SIZE] = '\0'; - strlcpy(card_data->model, (str_desc_buf + QUERY_DESC_HDR_SIZE), + strlcpy(dev_desc->model, (str_desc_buf + QUERY_DESC_HDR_SIZE), min_t(u8, str_desc_buf[QUERY_DESC_LENGTH_OFFSET], MAX_MODEL_LEN)); /* Null terminate the model string */ - card_data->model[MAX_MODEL_LEN] = '\0'; + dev_desc->model[MAX_MODEL_LEN] = '\0'; out: return err; } -void ufs_advertise_fixup_device(struct ufs_hba *hba) +static void ufs_fixup_device_setup(struct ufs_hba *hba, + struct ufs_dev_desc *dev_desc) { - int err; struct ufs_dev_fix *f; - struct ufs_device_info card_data; - - card_data.wmanufacturerid = 0; - - err = ufs_get_device_info(hba, &card_data); - if (err) { - dev_err(hba->dev, "%s: Failed getting device info. err = %d\n", - __func__, err); - return; - } for (f = ufs_fixups; f->quirk; f++) { - if (((f->card.wmanufacturerid == card_data.wmanufacturerid) || - (f->card.wmanufacturerid == UFS_ANY_VENDOR)) && - (STR_PRFX_EQUAL(f->card.model, card_data.model) || + if ((f->card.wmanufacturerid == dev_desc->wmanufacturerid || + f->card.wmanufacturerid == UFS_ANY_VENDOR) && + (STR_PRFX_EQUAL(f->card.model, dev_desc->model) || !strcmp(f->card.model, UFS_ANY_MODEL))) hba->dev_quirks |= f->quirk; } @@ -5241,6 +5675,20 @@ static void ufshcd_tune_unipro_params(struct ufs_hba *hba) ufshcd_vops_apply_dev_quirks(hba); } +static void ufshcd_clear_dbg_ufs_stats(struct ufs_hba *hba) +{ + int err_reg_hist_size = sizeof(struct ufs_uic_err_reg_hist); + + hba->ufs_stats.hibern8_exit_cnt = 0; + hba->ufs_stats.last_hibern8_exit_tstamp = ktime_set(0, 0); + + memset(&hba->ufs_stats.pa_err, 0, err_reg_hist_size); + memset(&hba->ufs_stats.dl_err, 0, err_reg_hist_size); + memset(&hba->ufs_stats.nl_err, 0, err_reg_hist_size); + memset(&hba->ufs_stats.tl_err, 0, err_reg_hist_size); + memset(&hba->ufs_stats.dme_err, 0, err_reg_hist_size); +} + /** * ufshcd_probe_hba - probe hba to detect device and initialize * @hba: per-adapter instance @@ -5249,18 +5697,21 @@ static void ufshcd_tune_unipro_params(struct ufs_hba *hba) */ static int ufshcd_probe_hba(struct ufs_hba *hba) { + struct ufs_dev_desc card = {0}; int ret; + ktime_t start = ktime_get(); ret = ufshcd_link_startup(hba); if (ret) goto out; - ufshcd_init_pwr_info(hba); - /* set the default level for urgent bkops */ hba->urgent_bkops_lvl = BKOPS_STATUS_PERF_IMPACT; hba->is_urgent_bkops_lvl_checked = false; + /* Debug counters initialization */ + ufshcd_clear_dbg_ufs_stats(hba); + /* UniPro link is active now */ ufshcd_set_link_active(hba); @@ -5272,7 +5723,14 @@ static int ufshcd_probe_hba(struct ufs_hba *hba) if (ret) goto out; - ufs_advertise_fixup_device(hba); + ret = ufs_get_device_desc(hba, &card); + if (ret) { + dev_err(hba->dev, "%s: Failed getting device info. err = %d\n", + __func__, ret); + goto out; + } + + ufs_fixup_device_setup(hba, &card); ufshcd_tune_unipro_params(hba); ret = ufshcd_set_vccq_rail_unused(hba, @@ -5324,12 +5782,15 @@ static int ufshcd_probe_hba(struct ufs_hba *hba) pm_runtime_put_sync(hba->dev); } + /* Resume devfreq after UFS device is detected */ + if (ufshcd_is_clkscaling_supported(hba)) { + ufshcd_resume_clkscaling(hba); + hba->clk_scaling.is_allowed = true; + } + if (!hba->is_init_prefetch) hba->is_init_prefetch = true; - /* Resume devfreq after UFS device is detected */ - ufshcd_resume_clkscaling(hba); - out: /* * If we failed to initialize the device or the device is not @@ -5340,6 +5801,9 @@ out: ufshcd_hba_exit(hba); } + trace_ufshcd_init(dev_name(hba->dev), ret, + ktime_to_us(ktime_sub(ktime_get(), start)), + hba->curr_dev_pwr_mode, hba->uic_link_state); return ret; } @@ -5650,6 +6114,8 @@ static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool on, struct ufs_clk_info *clki; struct list_head *head = &hba->clk_list_head; unsigned long flags; + ktime_t start = ktime_get(); + bool clk_state_changed = false; if (!head || list_empty(head)) goto out; @@ -5663,6 +6129,7 @@ static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool on, if (skip_ref_clk && !strcmp(clki->name, "ref_clk")) continue; + clk_state_changed = on ^ clki->enabled; if (on && !clki->enabled) { ret = clk_prepare_enable(clki->clk); if (ret) { @@ -5689,11 +6156,18 @@ out: if (!IS_ERR_OR_NULL(clki->clk) && clki->enabled) clk_disable_unprepare(clki->clk); } - } else if (on) { + } else if (!ret && on) { spin_lock_irqsave(hba->host->host_lock, flags); hba->clk_gating.state = CLKS_ON; + trace_ufshcd_clk_gating(dev_name(hba->dev), + hba->clk_gating.state); spin_unlock_irqrestore(hba->host->host_lock, flags); } + + if (clk_state_changed) + trace_ufshcd_profile_clk_gating(dev_name(hba->dev), + (on ? "on" : "off"), + ktime_to_us(ktime_sub(ktime_get(), start)), ret); return ret; } @@ -6176,6 +6650,7 @@ disable_clks: __ufshcd_setup_clocks(hba, false, true); hba->clk_gating.state = CLKS_OFF; + trace_ufshcd_clk_gating(dev_name(hba->dev), hba->clk_gating.state); /* * Disable the host irq as host controller as there won't be any * host controller transaction expected till resume. @@ -6268,14 +6743,19 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) goto set_old_link_state; } - /* - * If BKOPs operations are urgently needed at this moment then - * keep auto-bkops enabled or else disable it. - */ - ufshcd_urgent_bkops(hba); + if (ufshcd_keep_autobkops_enabled_except_suspend(hba)) + ufshcd_enable_auto_bkops(hba); + else + /* + * If BKOPs operations are urgently needed at this moment then + * keep auto-bkops enabled or else disable it. + */ + ufshcd_urgent_bkops(hba); + hba->clk_gating.is_suspended = false; - ufshcd_resume_clkscaling(hba); + if (hba->clk_scaling.is_allowed) + ufshcd_resume_clkscaling(hba); /* Schedule clock gating in case of no access to UFS device yet */ ufshcd_release(hba); @@ -6308,6 +6788,7 @@ out: int ufshcd_system_suspend(struct ufs_hba *hba) { int ret = 0; + ktime_t start = ktime_get(); if (!hba || !hba->is_powered) return 0; @@ -6334,6 +6815,9 @@ int ufshcd_system_suspend(struct ufs_hba *hba) ret = ufshcd_suspend(hba, UFS_SYSTEM_PM); out: + trace_ufshcd_system_suspend(dev_name(hba->dev), ret, + ktime_to_us(ktime_sub(ktime_get(), start)), + hba->curr_dev_pwr_mode, hba->uic_link_state); if (!ret) hba->is_sys_suspended = true; return ret; @@ -6349,6 +6833,9 @@ EXPORT_SYMBOL(ufshcd_system_suspend); int ufshcd_system_resume(struct ufs_hba *hba) { + int ret = 0; + ktime_t start = ktime_get(); + if (!hba) return -EINVAL; @@ -6357,9 +6844,14 @@ int ufshcd_system_resume(struct ufs_hba *hba) * Let the runtime resume take care of resuming * if runtime suspended. */ - return 0; - - return ufshcd_resume(hba, UFS_SYSTEM_PM); + goto out; + else + ret = ufshcd_resume(hba, UFS_SYSTEM_PM); +out: + trace_ufshcd_system_resume(dev_name(hba->dev), ret, + ktime_to_us(ktime_sub(ktime_get(), start)), + hba->curr_dev_pwr_mode, hba->uic_link_state); + return ret; } EXPORT_SYMBOL(ufshcd_system_resume); @@ -6373,13 +6865,21 @@ EXPORT_SYMBOL(ufshcd_system_resume); */ int ufshcd_runtime_suspend(struct ufs_hba *hba) { + int ret = 0; + ktime_t start = ktime_get(); + if (!hba) return -EINVAL; if (!hba->is_powered) - return 0; - - return ufshcd_suspend(hba, UFS_RUNTIME_PM); + goto out; + else + ret = ufshcd_suspend(hba, UFS_RUNTIME_PM); +out: + trace_ufshcd_runtime_suspend(dev_name(hba->dev), ret, + ktime_to_us(ktime_sub(ktime_get(), start)), + hba->curr_dev_pwr_mode, hba->uic_link_state); + return ret; } EXPORT_SYMBOL(ufshcd_runtime_suspend); @@ -6406,13 +6906,21 @@ EXPORT_SYMBOL(ufshcd_runtime_suspend); */ int ufshcd_runtime_resume(struct ufs_hba *hba) { + int ret = 0; + ktime_t start = ktime_get(); + if (!hba) return -EINVAL; if (!hba->is_powered) - return 0; - - return ufshcd_resume(hba, UFS_RUNTIME_PM); + goto out; + else + ret = ufshcd_resume(hba, UFS_RUNTIME_PM); +out: + trace_ufshcd_runtime_resume(dev_name(hba->dev), ret, + ktime_to_us(ktime_sub(ktime_get(), start)), + hba->curr_dev_pwr_mode, hba->uic_link_state); + return ret; } EXPORT_SYMBOL(ufshcd_runtime_resume); @@ -6422,6 +6930,127 @@ int ufshcd_runtime_idle(struct ufs_hba *hba) } EXPORT_SYMBOL(ufshcd_runtime_idle); +static inline ssize_t ufshcd_pm_lvl_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count, + bool rpm) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + unsigned long flags, value; + + if (kstrtoul(buf, 0, &value)) + return -EINVAL; + + if ((value < UFS_PM_LVL_0) || (value >= UFS_PM_LVL_MAX)) + return -EINVAL; + + spin_lock_irqsave(hba->host->host_lock, flags); + if (rpm) + hba->rpm_lvl = value; + else + hba->spm_lvl = value; + spin_unlock_irqrestore(hba->host->host_lock, flags); + return count; +} + +static ssize_t ufshcd_rpm_lvl_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + int curr_len; + u8 lvl; + + curr_len = snprintf(buf, PAGE_SIZE, + "\nCurrent Runtime PM level [%d] => dev_state [%s] link_state [%s]\n", + hba->rpm_lvl, + ufschd_ufs_dev_pwr_mode_to_string( + ufs_pm_lvl_states[hba->rpm_lvl].dev_state), + ufschd_uic_link_state_to_string( + ufs_pm_lvl_states[hba->rpm_lvl].link_state)); + + curr_len += snprintf((buf + curr_len), (PAGE_SIZE - curr_len), + "\nAll available Runtime PM levels info:\n"); + for (lvl = UFS_PM_LVL_0; lvl < UFS_PM_LVL_MAX; lvl++) + curr_len += snprintf((buf + curr_len), (PAGE_SIZE - curr_len), + "\tRuntime PM level [%d] => dev_state [%s] link_state [%s]\n", + lvl, + ufschd_ufs_dev_pwr_mode_to_string( + ufs_pm_lvl_states[lvl].dev_state), + ufschd_uic_link_state_to_string( + ufs_pm_lvl_states[lvl].link_state)); + + return curr_len; +} + +static ssize_t ufshcd_rpm_lvl_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + return ufshcd_pm_lvl_store(dev, attr, buf, count, true); +} + +static void ufshcd_add_rpm_lvl_sysfs_nodes(struct ufs_hba *hba) +{ + hba->rpm_lvl_attr.show = ufshcd_rpm_lvl_show; + hba->rpm_lvl_attr.store = ufshcd_rpm_lvl_store; + sysfs_attr_init(&hba->rpm_lvl_attr.attr); + hba->rpm_lvl_attr.attr.name = "rpm_lvl"; + hba->rpm_lvl_attr.attr.mode = 0644; + if (device_create_file(hba->dev, &hba->rpm_lvl_attr)) + dev_err(hba->dev, "Failed to create sysfs for rpm_lvl\n"); +} + +static ssize_t ufshcd_spm_lvl_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + int curr_len; + u8 lvl; + + curr_len = snprintf(buf, PAGE_SIZE, + "\nCurrent System PM level [%d] => dev_state [%s] link_state [%s]\n", + hba->spm_lvl, + ufschd_ufs_dev_pwr_mode_to_string( + ufs_pm_lvl_states[hba->spm_lvl].dev_state), + ufschd_uic_link_state_to_string( + ufs_pm_lvl_states[hba->spm_lvl].link_state)); + + curr_len += snprintf((buf + curr_len), (PAGE_SIZE - curr_len), + "\nAll available System PM levels info:\n"); + for (lvl = UFS_PM_LVL_0; lvl < UFS_PM_LVL_MAX; lvl++) + curr_len += snprintf((buf + curr_len), (PAGE_SIZE - curr_len), + "\tSystem PM level [%d] => dev_state [%s] link_state [%s]\n", + lvl, + ufschd_ufs_dev_pwr_mode_to_string( + ufs_pm_lvl_states[lvl].dev_state), + ufschd_uic_link_state_to_string( + ufs_pm_lvl_states[lvl].link_state)); + + return curr_len; +} + +static ssize_t ufshcd_spm_lvl_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + return ufshcd_pm_lvl_store(dev, attr, buf, count, false); +} + +static void ufshcd_add_spm_lvl_sysfs_nodes(struct ufs_hba *hba) +{ + hba->spm_lvl_attr.show = ufshcd_spm_lvl_show; + hba->spm_lvl_attr.store = ufshcd_spm_lvl_store; + sysfs_attr_init(&hba->spm_lvl_attr.attr); + hba->spm_lvl_attr.attr.name = "spm_lvl"; + hba->spm_lvl_attr.attr.mode = 0644; + if (device_create_file(hba->dev, &hba->spm_lvl_attr)) + dev_err(hba->dev, "Failed to create sysfs for spm_lvl\n"); +} + +static inline void ufshcd_add_sysfs_nodes(struct ufs_hba *hba) +{ + ufshcd_add_rpm_lvl_sysfs_nodes(hba); + ufshcd_add_spm_lvl_sysfs_nodes(hba); +} + /** * ufshcd_shutdown - shutdown routine * @hba: per adapter instance @@ -6465,6 +7094,8 @@ void ufshcd_remove(struct ufs_hba *hba) ufshcd_hba_stop(hba, true); ufshcd_exit_clk_gating(hba); + if (ufshcd_is_clkscaling_supported(hba)) + device_remove_file(hba->dev, &hba->clk_scaling.enable_attr); ufshcd_hba_exit(hba); } EXPORT_SYMBOL_GPL(ufshcd_remove); @@ -6536,6 +7167,8 @@ static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up) int ret = 0; struct ufs_clk_info *clki; struct list_head *head = &hba->clk_list_head; + ktime_t start = ktime_get(); + bool clk_state_changed = false; if (!head || list_empty(head)) goto out; @@ -6549,6 +7182,8 @@ static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up) if (scale_up && clki->max_freq) { if (clki->curr_freq == clki->max_freq) continue; + + clk_state_changed = true; ret = clk_set_rate(clki->clk, clki->max_freq); if (ret) { dev_err(hba->dev, "%s: %s clk set rate(%dHz) failed, %d\n", @@ -6556,11 +7191,18 @@ static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up) clki->max_freq, ret); break; } + trace_ufshcd_clk_scaling(dev_name(hba->dev), + "scaled up", clki->name, + clki->curr_freq, + clki->max_freq); + clki->curr_freq = clki->max_freq; } else if (!scale_up && clki->min_freq) { if (clki->curr_freq == clki->min_freq) continue; + + clk_state_changed = true; ret = clk_set_rate(clki->clk, clki->min_freq); if (ret) { dev_err(hba->dev, "%s: %s clk set rate(%dHz) failed, %d\n", @@ -6568,6 +7210,10 @@ static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up) clki->min_freq, ret); break; } + trace_ufshcd_clk_scaling(dev_name(hba->dev), + "scaled down", clki->name, + clki->curr_freq, + clki->min_freq); clki->curr_freq = clki->min_freq; } } @@ -6578,6 +7224,10 @@ static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up) ret = ufshcd_vops_clk_scale_notify(hba, scale_up, POST_CHANGE); out: + if (clk_state_changed) + trace_ufshcd_profile_clk_scaling(dev_name(hba->dev), + (scale_up ? "up" : "down"), + ktime_to_us(ktime_sub(ktime_get(), start)), ret); return ret; } @@ -6589,7 +7239,7 @@ static int ufshcd_devfreq_target(struct device *dev, bool release_clk_hold = false; unsigned long irq_flags; - if (!ufshcd_is_clkscaling_enabled(hba)) + if (!ufshcd_is_clkscaling_supported(hba)) return -EINVAL; spin_lock_irqsave(hba->host->host_lock, irq_flags); @@ -6637,7 +7287,7 @@ static int ufshcd_devfreq_get_dev_status(struct device *dev, struct ufs_clk_scaling *scaling = &hba->clk_scaling; unsigned long flags; - if (!ufshcd_is_clkscaling_enabled(hba)) + if (!ufshcd_is_clkscaling_supported(hba)) return -EINVAL; memset(stat, 0, sizeof(*stat)); @@ -6673,6 +7323,16 @@ static struct devfreq_dev_profile ufs_devfreq_profile = { .target = ufshcd_devfreq_target, .get_dev_status = ufshcd_devfreq_get_dev_status, }; +static void ufshcd_clkscaling_init_sysfs(struct ufs_hba *hba) +{ + hba->clk_scaling.enable_attr.show = ufshcd_clkscale_enable_show; + hba->clk_scaling.enable_attr.store = ufshcd_clkscale_enable_store; + sysfs_attr_init(&hba->clk_scaling.enable_attr.attr); + hba->clk_scaling.enable_attr.attr.name = "clkscale_enable"; + hba->clk_scaling.enable_attr.attr.mode = 0644; + if (device_create_file(hba->dev, &hba->clk_scaling.enable_attr)) + dev_err(hba->dev, "Failed to create sysfs for clkscale_enable\n"); +} /** * ufshcd_init - Driver initialization routine @@ -6795,10 +7455,11 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) err = ufshcd_hba_enable(hba); if (err) { dev_err(hba->dev, "Host controller enable failed\n"); + ufshcd_print_host_regs(hba); goto out_remove_scsi_host; } - if (ufshcd_is_clkscaling_enabled(hba)) { + if (ufshcd_is_clkscaling_supported(hba)) { hba->devfreq = devm_devfreq_add_device(dev, &ufs_devfreq_profile, "simple_ondemand", NULL); if (IS_ERR(hba->devfreq)) { @@ -6809,8 +7470,21 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) } /* Suspend devfreq until the UFS device is detected */ ufshcd_suspend_clkscaling(hba); + ufshcd_clkscaling_init_sysfs(hba); } + /* + * Set the default power management level for runtime and system PM. + * Default power saving mode is to keep UFS link in Hibern8 state + * and UFS device in sleep state. + */ + hba->rpm_lvl = ufs_get_desired_pm_lvl_for_dev_link_state( + UFS_SLEEP_PWR_MODE, + UIC_LINK_HIBERN8_STATE); + hba->spm_lvl = ufs_get_desired_pm_lvl_for_dev_link_state( + UFS_SLEEP_PWR_MODE, + UIC_LINK_HIBERN8_STATE); + /* Hold auto suspend until async scan completes */ pm_runtime_get_sync(dev); @@ -6823,6 +7497,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) ufshcd_set_ufs_dev_active(hba); async_schedule(ufshcd_async_scan, hba); + ufshcd_add_sysfs_nodes(hba); return 0; diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 08cd26ed2382..7ffcde21975b 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -152,6 +152,10 @@ struct ufs_pm_lvl_states { * @ucd_req_ptr: UCD address of the command * @ucd_rsp_ptr: Response UPIU address for this command * @ucd_prdt_ptr: PRDT address of the command + * @utrd_dma_addr: UTRD dma address for debug + * @ucd_prdt_dma_addr: PRDT dma address for debug + * @ucd_rsp_dma_addr: UPIU response dma address for debug + * @ucd_req_dma_addr: UPIU request dma address for debug * @cmd: pointer to SCSI command * @sense_buffer: pointer to sense buffer address of the SCSI command * @sense_bufflen: Length of the sense buffer @@ -160,6 +164,7 @@ struct ufs_pm_lvl_states { * @task_tag: Task tag of the command * @lun: LUN of the command * @intr_cmd: Interrupt command (doesn't participate in interrupt aggregation) + * @issue_time_stamp: time stamp for debug purposes */ struct ufshcd_lrb { struct utp_transfer_req_desc *utr_descriptor_ptr; @@ -167,6 +172,11 @@ struct ufshcd_lrb { struct utp_upiu_rsp *ucd_rsp_ptr; struct ufshcd_sg_entry *ucd_prdt_ptr; + dma_addr_t utrd_dma_addr; + dma_addr_t ucd_req_dma_addr; + dma_addr_t ucd_rsp_dma_addr; + dma_addr_t ucd_prdt_dma_addr; + struct scsi_cmnd *cmd; u8 *sense_buffer; unsigned int sense_bufflen; @@ -176,6 +186,7 @@ struct ufshcd_lrb { int task_tag; u8 lun; /* UPIU LUN id field is only 8-bit wide */ bool intr_cmd; + ktime_t issue_time_stamp; }; /** @@ -320,6 +331,8 @@ enum clk_gating_state { * @is_suspended: clk gating is suspended when set to 1 which can be used * during suspend/resume * @delay_attr: sysfs attribute to control delay_attr + * @enable_attr: sysfs attribute to enable/disable clock gating + * @is_enabled: Indicates the current status of clock gating * @active_reqs: number of requests that are pending and should be waited for * completion before gating clocks. */ @@ -330,6 +343,8 @@ struct ufs_clk_gating { unsigned long delay_ms; bool is_suspended; struct device_attribute delay_attr; + struct device_attribute enable_attr; + bool is_enabled; int active_reqs; }; @@ -338,6 +353,8 @@ struct ufs_clk_scaling { bool is_busy_started; unsigned long tot_busy_t; unsigned long window_start_t; + struct device_attribute enable_attr; + bool is_allowed; }; /** @@ -349,6 +366,41 @@ struct ufs_init_prefetch { u32 icc_level; }; +#define UIC_ERR_REG_HIST_LENGTH 8 +/** + * struct ufs_uic_err_reg_hist - keeps history of uic errors + * @pos: index to indicate cyclic buffer position + * @reg: cyclic buffer for registers value + * @tstamp: cyclic buffer for time stamp + */ +struct ufs_uic_err_reg_hist { + int pos; + u32 reg[UIC_ERR_REG_HIST_LENGTH]; + ktime_t tstamp[UIC_ERR_REG_HIST_LENGTH]; +}; + +/** + * struct ufs_stats - keeps usage/err statistics + * @hibern8_exit_cnt: Counter to keep track of number of exits, + * reset this after link-startup. + * @last_hibern8_exit_tstamp: Set time after the hibern8 exit. + * Clear after the first successful command completion. + * @pa_err: tracks pa-uic errors + * @dl_err: tracks dl-uic errors + * @nl_err: tracks nl-uic errors + * @tl_err: tracks tl-uic errors + * @dme_err: tracks dme errors + */ +struct ufs_stats { + u32 hibern8_exit_cnt; + ktime_t last_hibern8_exit_tstamp; + struct ufs_uic_err_reg_hist pa_err; + struct ufs_uic_err_reg_hist dl_err; + struct ufs_uic_err_reg_hist nl_err; + struct ufs_uic_err_reg_hist tl_err; + struct ufs_uic_err_reg_hist dme_err; +}; + /** * struct ufs_hba - per adapter private structure * @mmio_base: UFSHCI base register address @@ -429,6 +481,8 @@ struct ufs_hba { enum ufs_pm_level rpm_lvl; /* Desired UFS power management level during system PM */ enum ufs_pm_level spm_lvl; + struct device_attribute rpm_lvl_attr; + struct device_attribute spm_lvl_attr; int pm_op_in_progress; struct ufshcd_lrb *lrb; @@ -523,6 +577,7 @@ struct ufs_hba { u32 uic_error; u32 saved_err; u32 saved_uic_err; + struct ufs_stats ufs_stats; /* Device management request data */ struct ufs_dev_cmd dev_cmd; @@ -558,6 +613,14 @@ struct ufs_hba { * CAUTION: Enabling this might reduce overall UFS throughput. */ #define UFSHCD_CAP_INTR_AGGR (1 << 4) + /* + * This capability allows the device auto-bkops to be always enabled + * except during suspend (both runtime and suspend). + * Enabling this capability means that device will always be allowed + * to do background operation when it's active but it might degrade + * the performance of ongoing read/write operations. + */ +#define UFSHCD_CAP_KEEP_AUTO_BKOPS_ENABLED_EXCEPT_SUSPEND (1 << 5) struct devfreq *devfreq; struct ufs_clk_scaling clk_scaling; @@ -576,7 +639,7 @@ static inline bool ufshcd_can_hibern8_during_gating(struct ufs_hba *hba) { return hba->caps & UFSHCD_CAP_HIBERN8_WITH_CLK_GATING; } -static inline int ufshcd_is_clkscaling_enabled(struct ufs_hba *hba) +static inline int ufshcd_is_clkscaling_supported(struct ufs_hba *hba) { return hba->caps & UFSHCD_CAP_CLK_SCALING; } @@ -655,6 +718,11 @@ static inline void *ufshcd_get_variant(struct ufs_hba *hba) BUG_ON(!hba); return hba->priv; } +static inline bool ufshcd_keep_autobkops_enabled_except_suspend( + struct ufs_hba *hba) +{ + return hba->caps & UFSHCD_CAP_KEEP_AUTO_BKOPS_ENABLED_EXCEPT_SUSPEND; +} extern int ufshcd_runtime_suspend(struct ufs_hba *hba); extern int ufshcd_runtime_resume(struct ufs_hba *hba); @@ -713,8 +781,6 @@ static inline int ufshcd_dme_peer_get(struct ufs_hba *hba, return ufshcd_dme_get_attr(hba, attr_sel, mib_val, DME_PEER); } -int ufshcd_read_device_desc(struct ufs_hba *hba, u8 *buf, u32 size); - static inline bool ufshcd_is_hs_mode(struct ufs_pa_layer_attr *pwr_info) { return (pwr_info->pwr_rx == FAST_MODE || @@ -723,11 +789,6 @@ static inline bool ufshcd_is_hs_mode(struct ufs_pa_layer_attr *pwr_info) pwr_info->pwr_tx == FASTAUTO_MODE); } -#define ASCII_STD true - -int ufshcd_read_string_desc(struct ufs_hba *hba, int desc_index, u8 *buf, - u32 size, bool ascii); - /* Expose Query-Request API */ int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode, enum flag_idn idn, bool *flag_res); diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h index 8c5190e2e1c9..d14e9b965d1e 100644 --- a/drivers/scsi/ufs/ufshci.h +++ b/drivers/scsi/ufs/ufshci.h @@ -72,6 +72,9 @@ enum { REG_UIC_COMMAND_ARG_1 = 0x94, REG_UIC_COMMAND_ARG_2 = 0x98, REG_UIC_COMMAND_ARG_3 = 0x9C, + + UFSHCI_REG_SPACE_SIZE = 0xA0, + REG_UFS_CCAP = 0x100, REG_UFS_CRYPTOCAP = 0x104, diff --git a/drivers/scsi/vmw_pvscsi.c b/drivers/scsi/vmw_pvscsi.c index 15ca09cd16f3..ef474a748744 100644 --- a/drivers/scsi/vmw_pvscsi.c +++ b/drivers/scsi/vmw_pvscsi.c @@ -68,10 +68,7 @@ struct pvscsi_ctx { struct pvscsi_adapter { char *mmioBase; - unsigned int irq; u8 rev; - bool use_msi; - bool use_msix; bool use_msg; bool use_req_threshold; @@ -1161,30 +1158,26 @@ static bool pvscsi_setup_req_threshold(struct pvscsi_adapter *adapter, static irqreturn_t pvscsi_isr(int irq, void *devp) { struct pvscsi_adapter *adapter = devp; - int handled; - - if (adapter->use_msi || adapter->use_msix) - handled = true; - else { - u32 val = pvscsi_read_intr_status(adapter); - handled = (val & PVSCSI_INTR_ALL_SUPPORTED) != 0; - if (handled) - pvscsi_write_intr_status(devp, val); - } - - if (handled) { - unsigned long flags; + unsigned long flags; - spin_lock_irqsave(&adapter->hw_lock, flags); + spin_lock_irqsave(&adapter->hw_lock, flags); + pvscsi_process_completion_ring(adapter); + if (adapter->use_msg && pvscsi_msg_pending(adapter)) + queue_work(adapter->workqueue, &adapter->work); + spin_unlock_irqrestore(&adapter->hw_lock, flags); - pvscsi_process_completion_ring(adapter); - if (adapter->use_msg && pvscsi_msg_pending(adapter)) - queue_work(adapter->workqueue, &adapter->work); + return IRQ_HANDLED; +} - spin_unlock_irqrestore(&adapter->hw_lock, flags); - } +static irqreturn_t pvscsi_shared_isr(int irq, void *devp) +{ + struct pvscsi_adapter *adapter = devp; + u32 val = pvscsi_read_intr_status(adapter); - return IRQ_RETVAL(handled); + if (!(val & PVSCSI_INTR_ALL_SUPPORTED)) + return IRQ_NONE; + pvscsi_write_intr_status(devp, val); + return pvscsi_isr(irq, devp); } static void pvscsi_free_sgls(const struct pvscsi_adapter *adapter) @@ -1196,34 +1189,10 @@ static void pvscsi_free_sgls(const struct pvscsi_adapter *adapter) free_pages((unsigned long)ctx->sgl, get_order(SGL_SIZE)); } -static int pvscsi_setup_msix(const struct pvscsi_adapter *adapter, - unsigned int *irq) -{ - struct msix_entry entry = { 0, PVSCSI_VECTOR_COMPLETION }; - int ret; - - ret = pci_enable_msix_exact(adapter->dev, &entry, 1); - if (ret) - return ret; - - *irq = entry.vector; - - return 0; -} - static void pvscsi_shutdown_intr(struct pvscsi_adapter *adapter) { - if (adapter->irq) { - free_irq(adapter->irq, adapter); - adapter->irq = 0; - } - if (adapter->use_msi) { - pci_disable_msi(adapter->dev); - adapter->use_msi = 0; - } else if (adapter->use_msix) { - pci_disable_msix(adapter->dev); - adapter->use_msix = 0; - } + free_irq(pci_irq_vector(adapter->dev, 0), adapter); + pci_free_irq_vectors(adapter->dev); } static void pvscsi_release_resources(struct pvscsi_adapter *adapter) @@ -1359,11 +1328,11 @@ exit: static int pvscsi_probe(struct pci_dev *pdev, const struct pci_device_id *id) { + unsigned int irq_flag = PCI_IRQ_MSIX | PCI_IRQ_MSI | PCI_IRQ_LEGACY; struct pvscsi_adapter *adapter; struct pvscsi_adapter adapter_temp; struct Scsi_Host *host = NULL; unsigned int i; - unsigned long flags = 0; int error; u32 max_id; @@ -1512,30 +1481,33 @@ static int pvscsi_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto out_reset_adapter; } - if (!pvscsi_disable_msix && - pvscsi_setup_msix(adapter, &adapter->irq) == 0) { - printk(KERN_INFO "vmw_pvscsi: using MSI-X\n"); - adapter->use_msix = 1; - } else if (!pvscsi_disable_msi && pci_enable_msi(pdev) == 0) { - printk(KERN_INFO "vmw_pvscsi: using MSI\n"); - adapter->use_msi = 1; - adapter->irq = pdev->irq; - } else { - printk(KERN_INFO "vmw_pvscsi: using INTx\n"); - adapter->irq = pdev->irq; - flags = IRQF_SHARED; - } + if (pvscsi_disable_msix) + irq_flag &= ~PCI_IRQ_MSIX; + if (pvscsi_disable_msi) + irq_flag &= ~PCI_IRQ_MSI; + + error = pci_alloc_irq_vectors(adapter->dev, 1, 1, irq_flag); + if (error) + goto out_reset_adapter; adapter->use_req_threshold = pvscsi_setup_req_threshold(adapter, true); printk(KERN_DEBUG "vmw_pvscsi: driver-based request coalescing %sabled\n", adapter->use_req_threshold ? "en" : "dis"); - error = request_irq(adapter->irq, pvscsi_isr, flags, - "vmw_pvscsi", adapter); + if (adapter->dev->msix_enabled || adapter->dev->msi_enabled) { + printk(KERN_INFO "vmw_pvscsi: using MSI%s\n", + adapter->dev->msix_enabled ? "-X" : ""); + error = request_irq(pci_irq_vector(pdev, 0), pvscsi_isr, + 0, "vmw_pvscsi", adapter); + } else { + printk(KERN_INFO "vmw_pvscsi: using INTx\n"); + error = request_irq(pci_irq_vector(pdev, 0), pvscsi_shared_isr, + IRQF_SHARED, "vmw_pvscsi", adapter); + } + if (error) { printk(KERN_ERR "vmw_pvscsi: unable to request IRQ: %d\n", error); - adapter->irq = 0; goto out_reset_adapter; } diff --git a/drivers/scsi/vmw_pvscsi.h b/drivers/scsi/vmw_pvscsi.h index d41292ef85f2..75966d3f326e 100644 --- a/drivers/scsi/vmw_pvscsi.h +++ b/drivers/scsi/vmw_pvscsi.h @@ -423,11 +423,6 @@ struct PVSCSIConfigPageController { #define PVSCSI_MAX_INTRS 24 /* - * Enumeration of supported MSI-X vectors - */ -#define PVSCSI_VECTOR_COMPLETION 0 - -/* * Misc constants for the rings. */ |