diff options
Diffstat (limited to 'drivers/scsi/qla2xxx')
28 files changed, 3641 insertions, 1245 deletions
diff --git a/drivers/scsi/qla2xxx/Kconfig b/drivers/scsi/qla2xxx/Kconfig index de952935b5d2..036cc3f217b1 100644 --- a/drivers/scsi/qla2xxx/Kconfig +++ b/drivers/scsi/qla2xxx/Kconfig @@ -2,6 +2,7 @@ config SCSI_QLA_FC tristate "QLogic QLA2XXX Fibre Channel Support" depends on PCI && SCSI depends on SCSI_FC_ATTRS + depends on NVME_FC || !NVME_FC select FW_LOADER select BTREE ---help--- diff --git a/drivers/scsi/qla2xxx/Makefile b/drivers/scsi/qla2xxx/Makefile index 44def6bb4bb0..0b767a0bb308 100644 --- a/drivers/scsi/qla2xxx/Makefile +++ b/drivers/scsi/qla2xxx/Makefile @@ -1,6 +1,6 @@ qla2xxx-y := qla_os.o qla_init.o qla_mbx.o qla_iocb.o qla_isr.o qla_gs.o \ qla_dbg.o qla_sup.o qla_attr.o qla_mid.o qla_dfs.o qla_bsg.o \ - qla_nx.o qla_mr.o qla_nx2.o qla_target.o qla_tmpl.o + qla_nx.o qla_mr.o qla_nx2.o qla_target.o qla_tmpl.o qla_nvme.o obj-$(CONFIG_SCSI_QLA_FC) += qla2xxx.o obj-$(CONFIG_TCM_QLA2XXX) += tcm_qla2xxx.o diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 7c8d6c54ab70..08a1feb3a195 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -769,7 +769,7 @@ qla2x00_issue_logo(struct file *filp, struct kobject *kobj, did.b.area = (type & 0x0000ff00) >> 8; did.b.al_pa = (type & 0x000000ff); - ql_log(ql_log_info, vha, 0x70e3, "portid=%02x%02x%02x done\n", + ql_log(ql_log_info, vha, 0xd04d, "portid=%02x%02x%02x done\n", did.b.domain, did.b.area, did.b.al_pa); ql_log(ql_log_info, vha, 0x70e4, "%s: %d\n", __func__, type); @@ -929,7 +929,7 @@ qla2x00_alloc_sysfs_attr(scsi_qla_host_t *vha) iter->name, ret); else ql_dbg(ql_dbg_init, vha, 0x00f4, - "Successfully created sysfs %s binary attribure.\n", + "Successfully created sysfs %s binary attribute.\n", iter->name); } } @@ -2096,7 +2096,7 @@ qla24xx_vport_create(struct fc_vport *fc_vport, bool disable) } if (qos) { - qpair = qla2xxx_create_qpair(vha, qos, vha->vp_idx); + qpair = qla2xxx_create_qpair(vha, qos, vha->vp_idx, true); if (!qpair) ql_log(ql_log_warn, vha, 0x7084, "Can't create qpair for VP[%d]\n", @@ -2289,7 +2289,7 @@ qla2x00_init_host_attr(scsi_qla_host_t *vha) fc_host_dev_loss_tmo(vha->host) = ha->port_down_retry_count; fc_host_node_name(vha->host) = wwn_to_u64(vha->node_name); fc_host_port_name(vha->host) = wwn_to_u64(vha->port_name); - fc_host_supported_classes(vha->host) = ha->tgt.enable_class_2 ? + fc_host_supported_classes(vha->host) = ha->base_qpair->enable_class_2 ? (FC_COS_CLASS2|FC_COS_CLASS3) : FC_COS_CLASS3; fc_host_max_npiv_vports(vha->host) = ha->max_npiv_vports; fc_host_npiv_vports_inuse(vha->host) = ha->cur_vport_count; diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c index ca3420de5a01..2ea0ef93f5cb 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.c +++ b/drivers/scsi/qla2xxx/qla_bsg.c @@ -293,7 +293,7 @@ qla2x00_process_els(struct bsg_job *bsg_job) if (bsg_job->request_payload.sg_cnt > 1 || bsg_job->reply_payload.sg_cnt > 1) { ql_dbg(ql_dbg_user, vha, 0x7002, - "Multiple SG's are not suppored for ELS requests, " + "Multiple SG's are not supported for ELS requests, " "request_sg_cnt=%x reply_sg_cnt=%x.\n", bsg_job->request_payload.sg_cnt, bsg_job->reply_payload.sg_cnt); @@ -2135,7 +2135,7 @@ qla8044_serdes_op(struct bsg_job *bsg_job) bsg_reply->reply_payload_rcv_len = sizeof(sr); break; default: - ql_dbg(ql_dbg_user, vha, 0x70cf, + ql_dbg(ql_dbg_user, vha, 0x7020, "Unknown serdes cmd %x.\n", sr.cmd); rval = -EINVAL; break; diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index 88748a6ab73f..26751d34bcf2 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.c +++ b/drivers/scsi/qla2xxx/qla_dbg.c @@ -15,9 +15,10 @@ * | | | 0x015b-0x0160 | * | | | 0x016e | * | Mailbox commands | 0x1199 | 0x1193 | - * | Device Discovery | 0x2004 | 0x2016 | - * | | | 0x2011-0x2012, | - * | | | 0x2099-0x20a4 | + * | Device Discovery | 0x2134 | 0x210e-0x2116 | + * | | | 0x211a | + * | | | 0x211c-0x2128 | + * | | | 0x212a-0x2130 | * | Queue Command and IO tracing | 0x3074 | 0x300b | * | | | 0x3027-0x3028 | * | | | 0x303d-0x3041 | @@ -59,10 +60,10 @@ * | | | 0xb13c-0xb140 | * | | | 0xb149 | * | MultiQ | 0xc010 | | - * | Misc | 0xd301 | 0xd031-0xd0ff | + * | Misc | 0xd302 | 0xd031-0xd0ff | * | | | 0xd101-0xd1fe | * | | | 0xd214-0xd2fe | - * | Target Mode | 0xe080 | | + * | Target Mode | 0xe081 | | * | Target Mode Management | 0xf09b | 0xf002 | * | | | 0xf046-0xf049 | * | Target Mode Task Management | 0x1000d | | @@ -498,6 +499,50 @@ qla25xx_copy_fce(struct qla_hw_data *ha, void *ptr, uint32_t **last_chain) } static inline void * +qla25xx_copy_exlogin(struct qla_hw_data *ha, void *ptr, uint32_t **last_chain) +{ + struct qla2xxx_offld_chain *c = ptr; + + if (!ha->exlogin_buf) + return ptr; + + *last_chain = &c->type; + + c->type = cpu_to_be32(DUMP_CHAIN_EXLOGIN); + c->chain_size = cpu_to_be32(sizeof(struct qla2xxx_offld_chain) + + ha->exlogin_size); + c->size = cpu_to_be32(ha->exlogin_size); + c->addr = cpu_to_be64(ha->exlogin_buf_dma); + + ptr += sizeof(struct qla2xxx_offld_chain); + memcpy(ptr, ha->exlogin_buf, ha->exlogin_size); + + return (char *)ptr + cpu_to_be32(c->size); +} + +static inline void * +qla81xx_copy_exchoffld(struct qla_hw_data *ha, void *ptr, uint32_t **last_chain) +{ + struct qla2xxx_offld_chain *c = ptr; + + if (!ha->exchoffld_buf) + return ptr; + + *last_chain = &c->type; + + c->type = cpu_to_be32(DUMP_CHAIN_EXCHG); + c->chain_size = cpu_to_be32(sizeof(struct qla2xxx_offld_chain) + + ha->exchoffld_size); + c->size = cpu_to_be32(ha->exchoffld_size); + c->addr = cpu_to_be64(ha->exchoffld_buf_dma); + + ptr += sizeof(struct qla2xxx_offld_chain); + memcpy(ptr, ha->exchoffld_buf, ha->exchoffld_size); + + return (char *)ptr + cpu_to_be32(c->size); +} + +static inline void * qla2xxx_copy_atioqueues(struct qla_hw_data *ha, void *ptr, uint32_t **last_chain) { @@ -1606,6 +1651,7 @@ qla25xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked) nxt_chain = qla25xx_copy_fce(ha, nxt_chain, &last_chain); nxt_chain = qla25xx_copy_mqueues(ha, nxt_chain, &last_chain); nxt_chain = qla2xxx_copy_atioqueues(ha, nxt_chain, &last_chain); + nxt_chain = qla25xx_copy_exlogin(ha, nxt_chain, &last_chain); if (last_chain) { ha->fw_dump->version |= htonl(DUMP_CHAIN_VARIANT); *last_chain |= htonl(DUMP_CHAIN_LAST); @@ -1932,6 +1978,8 @@ qla81xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked) nxt_chain = qla25xx_copy_fce(ha, nxt_chain, &last_chain); nxt_chain = qla25xx_copy_mqueues(ha, nxt_chain, &last_chain); nxt_chain = qla2xxx_copy_atioqueues(ha, nxt_chain, &last_chain); + nxt_chain = qla25xx_copy_exlogin(ha, nxt_chain, &last_chain); + nxt_chain = qla81xx_copy_exchoffld(ha, nxt_chain, &last_chain); if (last_chain) { ha->fw_dump->version |= htonl(DUMP_CHAIN_VARIANT); *last_chain |= htonl(DUMP_CHAIN_LAST); @@ -2443,6 +2491,8 @@ copy_queue: nxt_chain = qla25xx_copy_fce(ha, nxt_chain, &last_chain); nxt_chain = qla25xx_copy_mqueues(ha, nxt_chain, &last_chain); nxt_chain = qla2xxx_copy_atioqueues(ha, nxt_chain, &last_chain); + nxt_chain = qla25xx_copy_exlogin(ha, nxt_chain, &last_chain); + nxt_chain = qla81xx_copy_exchoffld(ha, nxt_chain, &last_chain); if (last_chain) { ha->fw_dump->version |= htonl(DUMP_CHAIN_VARIANT); *last_chain |= htonl(DUMP_CHAIN_LAST); @@ -2713,3 +2763,104 @@ ql_dump_buffer(uint32_t level, scsi_qla_host_t *vha, int32_t id, buf + cnt, min(16U, size - cnt), false); } } + +/* + * This function is for formatting and logging log messages. + * It is to be used when vha is available. It formats the message + * and logs it to the messages file. All the messages will be logged + * irrespective of value of ql2xextended_error_logging. + * parameters: + * level: The level of the log messages to be printed in the + * messages file. + * vha: Pointer to the scsi_qla_host_t + * id: This is a unique id for the level. It identifies the + * part of the code from where the message originated. + * msg: The message to be displayed. + */ +void +ql_log_qp(uint32_t level, struct qla_qpair *qpair, int32_t id, + const char *fmt, ...) +{ + va_list va; + struct va_format vaf; + char pbuf[128]; + + if (level > ql_errlev) + return; + + if (qpair != NULL) { + const struct pci_dev *pdev = qpair->pdev; + /* <module-name> <msg-id>:<host> Message */ + snprintf(pbuf, sizeof(pbuf), "%s [%s]-%04x: ", + QL_MSGHDR, dev_name(&(pdev->dev)), id); + } else { + snprintf(pbuf, sizeof(pbuf), "%s [%s]-%04x: : ", + QL_MSGHDR, "0000:00:00.0", id); + } + pbuf[sizeof(pbuf) - 1] = 0; + + va_start(va, fmt); + + vaf.fmt = fmt; + vaf.va = &va; + + switch (level) { + case ql_log_fatal: /* FATAL LOG */ + pr_crit("%s%pV", pbuf, &vaf); + break; + case ql_log_warn: + pr_err("%s%pV", pbuf, &vaf); + break; + case ql_log_info: + pr_warn("%s%pV", pbuf, &vaf); + break; + default: + pr_info("%s%pV", pbuf, &vaf); + break; + } + + va_end(va); +} + +/* + * This function is for formatting and logging debug information. + * It is to be used when vha is available. It formats the message + * and logs it to the messages file. + * parameters: + * level: The level of the debug messages to be printed. + * If ql2xextended_error_logging value is correctly set, + * this message will appear in the messages file. + * vha: Pointer to the scsi_qla_host_t. + * id: This is a unique identifier for the level. It identifies the + * part of the code from where the message originated. + * msg: The message to be displayed. + */ +void +ql_dbg_qp(uint32_t level, struct qla_qpair *qpair, int32_t id, + const char *fmt, ...) +{ + va_list va; + struct va_format vaf; + + if (!ql_mask_match(level)) + return; + + va_start(va, fmt); + + vaf.fmt = fmt; + vaf.va = &va; + + if (qpair != NULL) { + const struct pci_dev *pdev = qpair->pdev; + /* <module-name> <pci-name> <msg-id>:<host> Message */ + pr_warn("%s [%s]-%04x: %pV", + QL_MSGHDR, dev_name(&(pdev->dev)), id + ql_dbg_offset, + &vaf); + } else { + pr_warn("%s [%s]-%04x: : %pV", + QL_MSGHDR, "0000:00:00.0", id + ql_dbg_offset, &vaf); + } + + va_end(va); + +} diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h index c6bffe929fe7..8877aa97d829 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.h +++ b/drivers/scsi/qla2xxx/qla_dbg.h @@ -232,6 +232,15 @@ struct qla2xxx_fce_chain { uint32_t eregs[8]; }; +/* used by exchange off load and extended login offload */ +struct qla2xxx_offld_chain { + uint32_t type; + uint32_t chain_size; + + uint32_t size; + u64 addr; +}; + struct qla2xxx_mq_chain { uint32_t type; uint32_t chain_size; @@ -258,6 +267,8 @@ struct qla2xxx_mqueue_chain { #define DUMP_CHAIN_FCE 0x7FFFFAF0 #define DUMP_CHAIN_MQ 0x7FFFFAF1 #define DUMP_CHAIN_QUEUE 0x7FFFFAF2 +#define DUMP_CHAIN_EXLOGIN 0x7FFFFAF3 +#define DUMP_CHAIN_EXCHG 0x7FFFFAF4 #define DUMP_CHAIN_LAST 0x80000000 struct qla2xxx_fw_dump { @@ -313,12 +324,18 @@ void __attribute__((format (printf, 4, 5))) ql_dbg(uint32_t, scsi_qla_host_t *vha, int32_t, const char *fmt, ...); void __attribute__((format (printf, 4, 5))) ql_dbg_pci(uint32_t, struct pci_dev *pdev, int32_t, const char *fmt, ...); +void __attribute__((format (printf, 4, 5))) +ql_dbg_qp(uint32_t, struct qla_qpair *, int32_t, const char *fmt, ...); + void __attribute__((format (printf, 4, 5))) ql_log(uint32_t, scsi_qla_host_t *vha, int32_t, const char *fmt, ...); void __attribute__((format (printf, 4, 5))) ql_log_pci(uint32_t, struct pci_dev *pdev, int32_t, const char *fmt, ...); +void __attribute__((format (printf, 4, 5))) +ql_log_qp(uint32_t, struct qla_qpair *, int32_t, const char *fmt, ...); + /* Debug Levels */ /* The 0x40000000 is the max value any debug level can have * as ql2xextended_error_logging is of type signed int diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index eddbc1218a39..0730b10b4280 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -37,6 +37,7 @@ #include "qla_bsg.h" #include "qla_nx.h" #include "qla_nx2.h" +#include "qla_nvme.h" #define QLA2XXX_DRIVER_NAME "qla2xxx" #define QLA2XXX_APIDEV "ql2xapidev" #define QLA2XXX_MANUFACTURER "QLogic Corporation" @@ -252,6 +253,8 @@ #define NPH_F_PORT 0x7fe /* FFFFFE */ #define NPH_IP_BROADCAST 0x7ff /* FFFFFF */ +#define NPH_SNS_LID(ha) (IS_FWI2_CAPABLE(ha) ? NPH_SNS : SIMPLE_NAME_SERVER) + #define MAX_CMDSZ 16 /* SCSI maximum CDB size. */ #include "qla_fw.h" @@ -284,7 +287,7 @@ struct name_list_extended { #define RESPONSE_ENTRY_CNT_MQ 128 /* Number of response entries.*/ #define ATIO_ENTRY_CNT_24XX 4096 /* Number of ATIO entries. */ #define RESPONSE_ENTRY_CNT_FX00 256 /* Number of response entries.*/ -#define EXTENDED_EXCH_ENTRY_CNT 32768 /* Entries for offload case */ +#define FW_DEF_EXCHANGES_CNT 2048 struct req_que; struct qla_tgt_sess; @@ -341,6 +344,7 @@ struct srb_iocb { #define SRB_LOGIN_RETRIED BIT_0 #define SRB_LOGIN_COND_PLOGI BIT_1 #define SRB_LOGIN_SKIP_PRLI BIT_2 +#define SRB_LOGIN_NVME_PRLI BIT_3 uint16_t data[2]; u32 iop[2]; } logio; @@ -409,6 +413,21 @@ struct srb_iocb { struct { struct imm_ntfy_from_isp *ntfy; } nack; + struct { + __le16 comp_status; + uint16_t rsp_pyld_len; + uint8_t aen_op; + void *desc; + + /* These are only used with ls4 requests */ + int cmd_len; + int rsp_len; + dma_addr_t cmd_dma; + dma_addr_t rsp_dma; + enum nvmefc_fcp_datadir dir; + uint32_t dl; + uint32_t timeout_sec; + } nvme; } u; struct timer_list timer; @@ -434,9 +453,24 @@ struct srb_iocb { #define SRB_NACK_PLOGI 16 #define SRB_NACK_PRLI 17 #define SRB_NACK_LOGO 18 +#define SRB_NVME_CMD 19 +#define SRB_NVME_LS 20 +#define SRB_PRLI_CMD 21 + +enum { + TYPE_SRB, + TYPE_TGT_CMD, +}; typedef struct srb { + /* + * Do not move cmd_type field, it needs to + * line up with qla_tgt_cmd->cmd_type + */ + uint8_t cmd_type; + uint8_t pad[3]; atomic_t ref_count; + wait_queue_head_t nvme_ls_waitQ; struct fc_port *fcport; struct scsi_qla_host *vha; uint32_t handle; @@ -1075,6 +1109,7 @@ struct mbx_cmd_32 { #define MBX_1 BIT_1 #define MBX_0 BIT_0 +#define RNID_TYPE_PORT_LOGIN 0x7 #define RNID_TYPE_SET_VERSION 0x9 #define RNID_TYPE_ASIC_TEMP 0xC @@ -2139,6 +2174,7 @@ typedef struct { uint8_t fabric_port_name[WWN_SIZE]; uint16_t fp_speed; uint8_t fc4_type; + uint8_t fc4f_nvme; /* nvme fc4 feature bits */ } sw_info_t; /* FCP-4 types */ @@ -2167,7 +2203,8 @@ typedef enum { FCT_SWITCH, FCT_BROADCAST, FCT_INITIATOR, - FCT_TARGET + FCT_TARGET, + FCT_NVME } fc_port_type_t; enum qla_sess_deletion { @@ -2224,10 +2261,12 @@ enum fcport_mgt_event { FCME_RSCN, FCME_GIDPN_DONE, FCME_PLOGI_DONE, /* Initiator side sent LLIOCB */ + FCME_PRLI_DONE, FCME_GNL_DONE, FCME_GPSC_DONE, FCME_GPDB_DONE, FCME_GPNID_DONE, + FCME_GFFID_DONE, FCME_DELETE_DONE, }; @@ -2261,6 +2300,17 @@ typedef struct fc_port { unsigned int login_pause:1; unsigned int login_succ:1; + struct work_struct nvme_del_work; + atomic_t nvme_ref_count; + wait_queue_head_t nvme_waitQ; + uint32_t nvme_prli_service_param; +#define NVME_PRLI_SP_CONF BIT_7 +#define NVME_PRLI_SP_INITIATOR BIT_5 +#define NVME_PRLI_SP_TARGET BIT_4 +#define NVME_PRLI_SP_DISCOVERY BIT_3 + uint8_t nvme_flag; +#define NVME_FLAG_REGISTERED 4 + struct fc_port *conflict; unsigned char logout_completed; int generation; @@ -2293,6 +2343,7 @@ typedef struct fc_port { u32 supported_classes; uint8_t fc4_type; + uint8_t fc4f_nvme; uint8_t scan_state; unsigned long last_queue_full; @@ -2300,6 +2351,8 @@ typedef struct fc_port { uint16_t port_id; + struct nvme_fc_remote_port *nvme_remote_port; + unsigned long retry_delay_timestamp; struct qla_tgt_sess *tgt_session; struct ct_sns_desc ct_desc; @@ -2732,7 +2785,7 @@ struct ct_sns_req { struct { uint8_t reserved; - uint8_t port_name[3]; + uint8_t port_id[3]; } gff_id; struct { @@ -2814,6 +2867,7 @@ struct ct_sns_rsp { } gpsc; #define GFF_FCP_SCSI_OFFSET 7 +#define GFF_NVME_OFFSET 23 /* type = 28h */ struct { uint8_t fc4_features[128]; } gff_id; @@ -3039,6 +3093,7 @@ enum qla_work_type { QLA_EVT_GPNID_DONE, QLA_EVT_NEW_SESS, QLA_EVT_GPDB, + QLA_EVT_PRLI, QLA_EVT_GPSC, QLA_EVT_UPD_FCPORT, QLA_EVT_GNL, @@ -3169,6 +3224,21 @@ struct qla_tc_param { #define QLA_PRECONFIG_VPORTS 32 #define QLA_MAX_VPORTS_QLA24XX 128 #define QLA_MAX_VPORTS_QLA25XX 256 + +struct qla_tgt_counters { + uint64_t qla_core_sbt_cmd; + uint64_t core_qla_que_buf; + uint64_t qla_core_ret_ctio; + uint64_t core_qla_snd_status; + uint64_t qla_core_ret_sta_ctio; + uint64_t core_qla_free_cmd; + uint64_t num_q_full_sent; + uint64_t num_alloc_iocb_failed; + uint64_t num_term_xchg_sent; +}; + +struct qla_qpair; + /* Response queue data structure */ struct rsp_que { dma_addr_t dma; @@ -3188,6 +3258,7 @@ struct rsp_que { struct qla_msix_entry *msix; struct req_que *req; srb_t *status_srb; /* status continuation entry */ + struct qla_qpair *qpair; dma_addr_t dma_fx00; response_t *ring_fx00; @@ -3228,6 +3299,15 @@ struct req_que { struct qla_qpair { spinlock_t qp_lock; atomic_t ref_count; + uint32_t lun_cnt; + /* + * For qpair 0, qp_lock_ptr will point at hardware_lock due to + * legacy code. For other Qpair(s), it will point at qp_lock. + */ + spinlock_t *qp_lock_ptr; + struct scsi_qla_host *vha; + u32 chip_reset; + /* distill these fields down to 'online=0/1' * ha->flags.eeh_busy * ha->flags.pci_channel_io_perm_failure @@ -3237,14 +3317,18 @@ struct qla_qpair { /* move vha->flags.difdix_supported here */ uint32_t difdix_supported:1; uint32_t delete_in_progress:1; + uint32_t fw_started:1; + uint32_t enable_class_2:1; + uint32_t enable_explicit_conf:1; + uint32_t use_shadow_reg:1; uint16_t id; /* qp number used with FW */ - uint16_t num_active_cmd; /* cmds down at firmware */ - cpumask_t cpu_mask; /* CPU mask for cpu affinity operation */ uint16_t vp_idx; /* vport ID */ - mempool_t *srb_mempool; + struct pci_dev *pdev; + void (*reqq_start_iocbs)(struct qla_qpair *); + /* to do: New driver: move queues to here instead of pointers */ struct req_que *req; struct rsp_que *rsp; @@ -3253,7 +3337,9 @@ struct qla_qpair { struct qla_hw_data *hw; struct work_struct q_work; struct list_head qp_list_elem; /* vha->qp_list */ - struct scsi_qla_host *vha; + struct list_head hints_list; + uint16_t cpuid; + struct qla_tgt_counters tgt_counters; }; /* Place holder for FW buffer parameters */ @@ -3272,8 +3358,6 @@ struct scsi_qlt_host { struct qlt_hw_data { /* Protected by hw lock */ - uint32_t enable_class_2:1; - uint32_t enable_explicit_conf:1; uint32_t node_name_set:1; dma_addr_t atio_dma; /* Physical address. */ @@ -3285,9 +3369,6 @@ struct qlt_hw_data { uint32_t __iomem *atio_q_out; struct qla_tgt_func_tmpl *tgt_ops; - struct qla_tgt_cmd *cmds[DEFAULT_OUTSTANDING_COMMANDS]; - uint16_t current_handle; - struct qla_tgt_vp_map *tgt_vp_map; int saved_set; @@ -3302,6 +3383,7 @@ struct qlt_hw_data { struct dentry *dfs_tgt_sess; struct dentry *dfs_tgt_port_database; + struct dentry *dfs_naqp; struct list_head q_full_list; uint32_t num_pend_cmds; @@ -3310,7 +3392,8 @@ struct qlt_hw_data { spinlock_t q_full_lock; uint32_t leak_exchg_thresh_hold; spinlock_t sess_lock; - int rspq_vector_cpuid; + int num_act_qpairs; +#define DEFAULT_NAQP 2 spinlock_t atio_lock ____cacheline_aligned; struct btree_head32 host_map; }; @@ -3591,6 +3674,10 @@ struct qla_hw_data { #define IS_SHADOW_REG_CAPABLE(ha) (IS_QLA27XX(ha)) #define IS_DPORT_CAPABLE(ha) (IS_QLA83XX(ha) || IS_QLA27XX(ha)) #define IS_FAWWN_CAPABLE(ha) (IS_QLA83XX(ha) || IS_QLA27XX(ha)) +#define IS_EXCHG_OFFLD_CAPABLE(ha) \ + (IS_QLA81XX(ha) || IS_QLA83XX(ha) || IS_QLA27XX(ha)) +#define IS_EXLOGIN_OFFLD_CAPABLE(ha) \ + (IS_QLA25XX(ha) || IS_QLA81XX(ha) || IS_QLA83XX(ha) || IS_QLA27XX(ha)) /* HBA serial number */ uint8_t serial0; @@ -3927,24 +4014,11 @@ struct qla_hw_data { struct work_struct board_disable; struct mr_data_fx00 mr; - uint32_t chip_reset; struct qlt_hw_data tgt; int allow_cna_fw_dump; }; -struct qla_tgt_counters { - uint64_t qla_core_sbt_cmd; - uint64_t core_qla_que_buf; - uint64_t qla_core_ret_ctio; - uint64_t core_qla_snd_status; - uint64_t qla_core_ret_sta_ctio; - uint64_t core_qla_free_cmd; - uint64_t num_q_full_sent; - uint64_t num_alloc_iocb_failed; - uint64_t num_term_xchg_sent; -}; - /* * Qlogic scsi host structure */ @@ -3973,6 +4047,9 @@ typedef struct scsi_qla_host { uint32_t fw_tgt_reported:1; uint32_t bbcr_enable:1; uint32_t qpairs_available:1; + uint32_t qpairs_req_created:1; + uint32_t qpairs_rsp_created:1; + uint32_t nvme_enabled:1; } flags; atomic_t loop_state; @@ -4017,7 +4094,6 @@ typedef struct scsi_qla_host { #define PFLG_DISCONNECTED 0 /* PCI device removed */ #define PFLG_DRIVER_REMOVING 1 /* PCI driver .remove */ #define PFLG_DRIVER_PROBING 2 /* PCI driver .probe */ -#define PCI_ERR 30 uint32_t device_flags; #define SWITCH_FOUND BIT_0 @@ -4052,6 +4128,13 @@ typedef struct scsi_qla_host { uint8_t port_name[WWN_SIZE]; uint8_t fabric_node_name[WWN_SIZE]; + struct nvme_fc_local_port *nvme_local_port; + atomic_t nvme_ref_count; + wait_queue_head_t nvme_waitQ; + struct list_head nvme_rport_list; + atomic_t nvme_active_aen_cnt; + uint16_t nvme_last_rptd_aen; + uint16_t fcoe_vlan_id; uint16_t fcoe_fcf_idx; uint8_t fcoe_vn_port_mac[6]; @@ -4108,10 +4191,8 @@ typedef struct scsi_qla_host { struct fc_host_statistics fc_host_stat; struct qla_statistics qla_stats; struct bidi_statistics bidi_stats; - atomic_t vref_count; struct qla8044_reset_template reset_tmplt; - struct qla_tgt_counters tgt_counters; uint16_t bbcr; struct name_list_extended gnl; /* Count of active session/fcport */ @@ -4156,6 +4237,26 @@ struct qla2_sgx { srb_t *sp; }; +#define QLA_FW_STARTED(_ha) { \ + int i; \ + _ha->flags.fw_started = 1; \ + _ha->base_qpair->fw_started = 1; \ + for (i = 0; i < _ha->max_qpairs; i++) { \ + if (_ha->queue_pair_map[i]) \ + _ha->queue_pair_map[i]->fw_started = 1; \ + } \ +} + +#define QLA_FW_STOPPED(_ha) { \ + int i; \ + _ha->flags.fw_started = 0; \ + _ha->base_qpair->fw_started = 0; \ + for (i = 0; i < _ha->max_qpairs; i++) { \ + if (_ha->queue_pair_map[i]) \ + _ha->queue_pair_map[i]->fw_started = 0; \ + } \ +} + /* * Macros to help code, maintain, etc. */ @@ -4199,6 +4300,25 @@ struct qla2_sgx { #define QLA_QPAIR_MARK_NOT_BUSY(__qpair) \ atomic_dec(&__qpair->ref_count); \ + +#define QLA_ENA_CONF(_ha) {\ + int i;\ + _ha->base_qpair->enable_explicit_conf = 1; \ + for (i = 0; i < _ha->max_qpairs; i++) { \ + if (_ha->queue_pair_map[i]) \ + _ha->queue_pair_map[i]->enable_explicit_conf = 1; \ + } \ +} + +#define QLA_DIS_CONF(_ha) {\ + int i;\ + _ha->base_qpair->enable_explicit_conf = 0; \ + for (i = 0; i < _ha->max_qpairs; i++) { \ + if (_ha->queue_pair_map[i]) \ + _ha->queue_pair_map[i]->enable_explicit_conf = 0; \ + } \ +} + /* * qla2x00 local function return status codes */ @@ -4253,6 +4373,10 @@ enum nexus_wait_type { WAIT_LUN, }; +#define USER_CTRL_IRQ(_ha) (ql2xuctrlirq && QLA_TGT_MODE_ENABLED() && \ + (IS_QLA27XX(_ha) || IS_QLA83XX(_ha))) + +#include "qla_target.h" #include "qla_gbl.h" #include "qla_dbg.h" #include "qla_inline.h" diff --git a/drivers/scsi/qla2xxx/qla_dfs.c b/drivers/scsi/qla2xxx/qla_dfs.c index 989e17b0758c..d231e7156134 100644 --- a/drivers/scsi/qla2xxx/qla_dfs.c +++ b/drivers/scsi/qla2xxx/qla_dfs.c @@ -70,7 +70,7 @@ qla2x00_dfs_tgt_port_database_show(struct seq_file *s, void *unused) qla2x00_gid_list_size(ha), &gid_list_dma, GFP_KERNEL); if (!gid_list) { - ql_dbg(ql_dbg_user, vha, 0x705c, + ql_dbg(ql_dbg_user, vha, 0x7018, "DMA allocation failed for %u\n", qla2x00_gid_list_size(ha)); return 0; @@ -164,26 +164,56 @@ static int qla_dfs_tgt_counters_show(struct seq_file *s, void *unused) { struct scsi_qla_host *vha = s->private; + struct qla_qpair *qpair = vha->hw->base_qpair; + uint64_t qla_core_sbt_cmd, core_qla_que_buf, qla_core_ret_ctio, + core_qla_snd_status, qla_core_ret_sta_ctio, core_qla_free_cmd, + num_q_full_sent, num_alloc_iocb_failed, num_term_xchg_sent; + u16 i; + + qla_core_sbt_cmd = qpair->tgt_counters.qla_core_sbt_cmd; + core_qla_que_buf = qpair->tgt_counters.core_qla_que_buf; + qla_core_ret_ctio = qpair->tgt_counters.qla_core_ret_ctio; + core_qla_snd_status = qpair->tgt_counters.core_qla_snd_status; + qla_core_ret_sta_ctio = qpair->tgt_counters.qla_core_ret_sta_ctio; + core_qla_free_cmd = qpair->tgt_counters.core_qla_free_cmd; + num_q_full_sent = qpair->tgt_counters.num_q_full_sent; + num_alloc_iocb_failed = qpair->tgt_counters.num_alloc_iocb_failed; + num_term_xchg_sent = qpair->tgt_counters.num_term_xchg_sent; + + for (i = 0; i < vha->hw->max_qpairs; i++) { + qpair = vha->hw->queue_pair_map[i]; + qla_core_sbt_cmd += qpair->tgt_counters.qla_core_sbt_cmd; + core_qla_que_buf += qpair->tgt_counters.core_qla_que_buf; + qla_core_ret_ctio += qpair->tgt_counters.qla_core_ret_ctio; + core_qla_snd_status += qpair->tgt_counters.core_qla_snd_status; + qla_core_ret_sta_ctio += + qpair->tgt_counters.qla_core_ret_sta_ctio; + core_qla_free_cmd += qpair->tgt_counters.core_qla_free_cmd; + num_q_full_sent += qpair->tgt_counters.num_q_full_sent; + num_alloc_iocb_failed += + qpair->tgt_counters.num_alloc_iocb_failed; + num_term_xchg_sent += qpair->tgt_counters.num_term_xchg_sent; + } seq_puts(s, "Target Counters\n"); seq_printf(s, "qla_core_sbt_cmd = %lld\n", - vha->tgt_counters.qla_core_sbt_cmd); + qla_core_sbt_cmd); seq_printf(s, "qla_core_ret_sta_ctio = %lld\n", - vha->tgt_counters.qla_core_ret_sta_ctio); + qla_core_ret_sta_ctio); seq_printf(s, "qla_core_ret_ctio = %lld\n", - vha->tgt_counters.qla_core_ret_ctio); + qla_core_ret_ctio); seq_printf(s, "core_qla_que_buf = %lld\n", - vha->tgt_counters.core_qla_que_buf); + core_qla_que_buf); seq_printf(s, "core_qla_snd_status = %lld\n", - vha->tgt_counters.core_qla_snd_status); + core_qla_snd_status); seq_printf(s, "core_qla_free_cmd = %lld\n", - vha->tgt_counters.core_qla_free_cmd); + core_qla_free_cmd); seq_printf(s, "num alloc iocb failed = %lld\n", - vha->tgt_counters.num_alloc_iocb_failed); + num_alloc_iocb_failed); seq_printf(s, "num term exchange sent = %lld\n", - vha->tgt_counters.num_term_xchg_sent); + num_term_xchg_sent); seq_printf(s, "num Q full sent = %lld\n", - vha->tgt_counters.num_q_full_sent); + num_q_full_sent); /* DIF stats */ seq_printf(s, "DIF Inp Bytes = %lld\n", @@ -314,6 +344,81 @@ static const struct file_operations dfs_fce_ops = { .release = qla2x00_dfs_fce_release, }; +static int +qla_dfs_naqp_show(struct seq_file *s, void *unused) +{ + struct scsi_qla_host *vha = s->private; + struct qla_hw_data *ha = vha->hw; + + seq_printf(s, "%d\n", ha->tgt.num_act_qpairs); + return 0; +} + +static int +qla_dfs_naqp_open(struct inode *inode, struct file *file) +{ + struct scsi_qla_host *vha = inode->i_private; + + return single_open(file, qla_dfs_naqp_show, vha); +} + +static ssize_t +qla_dfs_naqp_write(struct file *file, const char __user *buffer, + size_t count, loff_t *pos) +{ + struct seq_file *s = file->private_data; + struct scsi_qla_host *vha = s->private; + struct qla_hw_data *ha = vha->hw; + char *buf; + int rc = 0; + unsigned long num_act_qp; + + if (!(IS_QLA27XX(ha) || IS_QLA83XX(ha))) { + pr_err("host%ld: this adapter does not support Multi Q.", + vha->host_no); + return -EINVAL; + } + + if (!vha->flags.qpairs_available) { + pr_err("host%ld: Driver is not setup with Multi Q.", + vha->host_no); + return -EINVAL; + } + buf = memdup_user_nul(buffer, count); + if (IS_ERR(buf)) { + pr_err("host%ld: fail to copy user buffer.", + vha->host_no); + return PTR_ERR(buf); + } + + num_act_qp = simple_strtoul(buf, NULL, 0); + + if (num_act_qp >= vha->hw->max_qpairs) { + pr_err("User set invalid number of qpairs %lu. Max = %d", + num_act_qp, vha->hw->max_qpairs); + rc = -EINVAL; + goto out_free; + } + + if (num_act_qp != ha->tgt.num_act_qpairs) { + ha->tgt.num_act_qpairs = num_act_qp; + qlt_clr_qp_table(vha); + } + rc = count; +out_free: + kfree(buf); + return rc; +} + +static const struct file_operations dfs_naqp_ops = { + .open = qla_dfs_naqp_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = qla_dfs_naqp_write, +}; + + int qla2x00_dfs_setup(scsi_qla_host_t *vha) { @@ -370,7 +475,7 @@ create_nodes: ha->tgt.dfs_tgt_port_database = debugfs_create_file("tgt_port_database", S_IRUSR, ha->dfs_dir, vha, &dfs_tgt_port_database_ops); if (!ha->tgt.dfs_tgt_port_database) { - ql_log(ql_log_warn, vha, 0xffff, + ql_log(ql_log_warn, vha, 0xd03f, "Unable to create debugFS tgt_port_database node.\n"); goto out; } @@ -386,11 +491,20 @@ create_nodes: ha->tgt.dfs_tgt_sess = debugfs_create_file("tgt_sess", S_IRUSR, ha->dfs_dir, vha, &dfs_tgt_sess_ops); if (!ha->tgt.dfs_tgt_sess) { - ql_log(ql_log_warn, vha, 0xffff, - "Unable to create debugFS tgt_sess node.\n"); + ql_log(ql_log_warn, vha, 0xd040, + "Unable to create debugFS tgt_sess node.\n"); goto out; } + if (IS_QLA27XX(ha) || IS_QLA83XX(ha)) { + ha->tgt.dfs_naqp = debugfs_create_file("naqp", + 0400, ha->dfs_dir, vha, &dfs_naqp_ops); + if (!ha->tgt.dfs_naqp) { + ql_log(ql_log_warn, vha, 0xd011, + "Unable to create debugFS naqp node.\n"); + goto out; + } + } out: return 0; } @@ -400,6 +514,11 @@ qla2x00_dfs_remove(scsi_qla_host_t *vha) { struct qla_hw_data *ha = vha->hw; + if (ha->tgt.dfs_naqp) { + debugfs_remove(ha->tgt.dfs_naqp); + ha->tgt.dfs_naqp = NULL; + } + if (ha->tgt.dfs_tgt_sess) { debugfs_remove(ha->tgt.dfs_tgt_sess); ha->tgt.dfs_tgt_sess = NULL; diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h index 1f808928763b..b9c9886e8b1d 100644 --- a/drivers/scsi/qla2xxx/qla_fw.h +++ b/drivers/scsi/qla2xxx/qla_fw.h @@ -7,6 +7,9 @@ #ifndef __QLA_FW_H #define __QLA_FW_H +#include <linux/nvme.h> +#include <linux/nvme-fc.h> + #define MBS_CHECKSUM_ERROR 0x4010 #define MBS_INVALID_PRODUCT_KEY 0x4020 @@ -37,6 +40,12 @@ struct port_database_24xx { #define PDF_CLASS_2 BIT_4 #define PDF_HARD_ADDR BIT_1 + /* + * for NVMe, the login_state field has been + * split into nibbles. + * The lower nibble is for FCP. + * The upper nibble is for NVMe. + */ uint8_t current_login_state; uint8_t last_login_state; #define PDS_PLOGI_PENDING 0x03 @@ -69,7 +78,11 @@ struct port_database_24xx { uint8_t port_name[WWN_SIZE]; uint8_t node_name[WWN_SIZE]; - uint8_t reserved_3[24]; + uint8_t reserved_3[4]; + uint16_t prli_nvme_svc_param_word_0; /* Bits 15-0 of word 0 */ + uint16_t prli_nvme_svc_param_word_3; /* Bits 15-0 of word 3 */ + uint16_t nvme_first_burst_size; + uint8_t reserved_4[14]; }; /* @@ -593,9 +606,14 @@ struct sts_entry_24xx { uint32_t residual_len; /* FW calc residual transfer length. */ - uint16_t reserved_1; + union { + uint16_t reserved_1; + uint16_t nvme_rsp_pyld_len; + }; + uint16_t state_flags; /* State flags. */ #define SF_TRANSFERRED_DATA BIT_11 +#define SF_NVME_ERSP BIT_6 #define SF_FCP_RSP_DMA BIT_0 uint16_t retry_delay; @@ -605,8 +623,16 @@ struct sts_entry_24xx { uint32_t rsp_residual_count; /* FCP RSP residual count. */ uint32_t sense_len; /* FCP SENSE length. */ - uint32_t rsp_data_len; /* FCP response data length. */ - uint8_t data[28]; /* FCP response/sense information. */ + + union { + struct { + uint32_t rsp_data_len; /* FCP response data length */ + uint8_t data[28]; /* FCP rsp/sense information */ + }; + struct nvme_fc_ersp_iu nvme_ersp; + uint8_t nvme_ersp_data[32]; + }; + /* * If DIF Error is set in comp_status, these additional fields are * defined: @@ -819,6 +845,7 @@ struct logio_entry_24xx { #define LCF_CLASS_2 BIT_8 /* Enable class 2 during PLOGI. */ #define LCF_FREE_NPORT BIT_7 /* Release NPORT handle after LOGO. */ #define LCF_EXPL_LOGO BIT_6 /* Perform an explicit LOGO. */ +#define LCF_NVME_PRLI BIT_6 /* Perform NVME FC4 PRLI */ #define LCF_SKIP_PRLI BIT_5 /* Skip PRLI after PLOGI. */ #define LCF_IMPL_LOGO_ALL BIT_5 /* Implicit LOGO to all ports. */ #define LCF_COND_PLOGI BIT_4 /* PLOGI only if not logged-in. */ diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 5b2451745e9f..cadb6e3baacc 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -10,6 +10,17 @@ #include <linux/interrupt.h> /* + * Global functions prototype in qla_nvme.c source file. + */ +extern void qla_nvme_register_hba(scsi_qla_host_t *); +extern int qla_nvme_register_remote(scsi_qla_host_t *, fc_port_t *); +extern void qla_nvme_delete(scsi_qla_host_t *); +extern void qla_nvme_abort(struct qla_hw_data *, srb_t *sp); +extern void qla24xx_nvme_ls4_iocb(scsi_qla_host_t *, struct pt_ls4_request *, + struct req_que *); +extern void qla24xx_async_gffid_sp_done(void *, int); + +/* * Global Function Prototypes in qla_init.c source file. */ extern int qla2x00_initialize_adapter(scsi_qla_host_t *); @@ -77,8 +88,7 @@ struct qla_work_evt *qla2x00_alloc_work(struct scsi_qla_host *, enum qla_work_type); extern int qla24xx_async_gnl(struct scsi_qla_host *, fc_port_t *); int qla2x00_post_work(struct scsi_qla_host *vha, struct qla_work_evt *e); -extern void *qla2x00_alloc_iocbs(struct scsi_qla_host *, srb_t *); -extern void *qla2x00_alloc_iocbs_ready(struct scsi_qla_host *, srb_t *); +extern void *qla2x00_alloc_iocbs_ready(struct qla_qpair *, srb_t *); extern int qla24xx_update_fcport_fcp_prio(scsi_qla_host_t *, fc_port_t *); extern fc_port_t * @@ -96,10 +106,11 @@ qla2x00_alloc_outstanding_cmds(struct qla_hw_data *, struct req_que *); extern int qla2x00_init_rings(scsi_qla_host_t *); extern uint8_t qla27xx_find_valid_image(struct scsi_qla_host *); extern struct qla_qpair *qla2xxx_create_qpair(struct scsi_qla_host *, - int, int); + int, int, bool); extern int qla2xxx_delete_qpair(struct scsi_qla_host *, struct qla_qpair *); void qla2x00_fcport_event_handler(scsi_qla_host_t *, struct event_arg *); int qla24xx_async_gpdb(struct scsi_qla_host *, fc_port_t *, u8); +int qla24xx_async_prli(struct scsi_qla_host *, fc_port_t *); int qla24xx_async_notify_ack(scsi_qla_host_t *, fc_port_t *, struct imm_ntfy_from_isp *, int); int qla24xx_post_newsess_work(struct scsi_qla_host *, port_id_t *, u8 *, @@ -137,8 +148,11 @@ extern int ql2xmdcapmask; extern int ql2xmdenable; extern int ql2xexlogins; extern int ql2xexchoffld; +extern int ql2xiniexchg; extern int ql2xfwholdabts; extern int ql2xmvasynctoatio; +extern int ql2xuctrlirq; +extern int ql2xnvmeenable; extern int qla2x00_loop_reset(scsi_qla_host_t *); extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int); @@ -254,7 +268,8 @@ extern int qla2x00_start_bidir(srb_t *, struct scsi_qla_host *, uint32_t); extern int qla2xxx_dif_start_scsi_mq(srb_t *); extern unsigned long qla2x00_get_async_timeout(struct scsi_qla_host *); -extern void *qla2x00_alloc_iocbs(scsi_qla_host_t *, srb_t *); +extern void *qla2x00_alloc_iocbs(struct scsi_qla_host *, srb_t *); +extern void *__qla2x00_alloc_iocbs(struct qla_qpair *, srb_t *); extern int qla2x00_issue_marker(scsi_qla_host_t *, int); extern int qla24xx_walk_and_build_sglist_no_difb(struct qla_hw_data *, srb_t *, uint32_t *, uint16_t, struct qla_tc_param *); @@ -604,7 +619,7 @@ extern int qla2x00_gpn_id(scsi_qla_host_t *, sw_info_t *); extern int qla2x00_gnn_id(scsi_qla_host_t *, sw_info_t *); extern void qla2x00_gff_id(scsi_qla_host_t *, sw_info_t *); extern int qla2x00_rft_id(scsi_qla_host_t *); -extern int qla2x00_rff_id(scsi_qla_host_t *); +extern int qla2x00_rff_id(scsi_qla_host_t *, u8); extern int qla2x00_rnn_id(scsi_qla_host_t *); extern int qla2x00_rsnn_nn(scsi_qla_host_t *); extern void *qla2x00_prep_ms_fdmi_iocb(scsi_qla_host_t *, uint32_t, uint32_t); @@ -630,7 +645,8 @@ void qla24xx_handle_gpnid_event(scsi_qla_host_t *, struct event_arg *); int qla24xx_post_gpsc_work(struct scsi_qla_host *, fc_port_t *); int qla24xx_async_gpsc(scsi_qla_host_t *, fc_port_t *); int qla2x00_mgmt_svr_login(scsi_qla_host_t *); - +void qla24xx_handle_gffid_event(scsi_qla_host_t *vha, struct event_arg *ea); +int qla24xx_async_gffid(scsi_qla_host_t *vha, fc_port_t *fcport); /* * Global Function Prototypes in qla_attr.c source file. */ @@ -662,9 +678,9 @@ extern int qla25xx_request_irq(struct qla_hw_data *, struct qla_qpair *, extern int qla25xx_init_req_que(struct scsi_qla_host *, struct req_que *); extern int qla25xx_init_rsp_que(struct scsi_qla_host *, struct rsp_que *); extern int qla25xx_create_req_que(struct qla_hw_data *, uint16_t, uint8_t, - uint16_t, int, uint8_t); + uint16_t, int, uint8_t, bool); extern int qla25xx_create_rsp_que(struct qla_hw_data *, uint16_t, uint8_t, - uint16_t, struct qla_qpair *); + uint16_t, struct qla_qpair *, bool); extern void qla2x00_init_response_q_entries(struct rsp_que *); extern int qla25xx_delete_req_que(struct scsi_qla_host *, struct req_que *); @@ -833,14 +849,13 @@ extern irqreturn_t qla8044_intr_handler(int, void *); extern void qla82xx_mbx_completion(scsi_qla_host_t *, uint16_t); extern int qla8044_abort_isp(scsi_qla_host_t *); extern int qla8044_check_fw_alive(struct scsi_qla_host *); - -extern void qlt_host_reset_handler(struct qla_hw_data *ha); extern int qla_get_exlogin_status(scsi_qla_host_t *, uint16_t *, uint16_t *); extern int qla_set_exlogin_mem_cfg(scsi_qla_host_t *vha, dma_addr_t phys_addr); extern int qla_get_exchoffld_status(scsi_qla_host_t *, uint16_t *, uint16_t *); -extern int qla_set_exchoffld_mem_cfg(scsi_qla_host_t *, dma_addr_t); -extern void qlt_handle_abts_recv(struct scsi_qla_host *, response_t *); +extern int qla_set_exchoffld_mem_cfg(scsi_qla_host_t *); +extern void qlt_handle_abts_recv(struct scsi_qla_host *, struct rsp_que *, + response_t *); int qla24xx_async_notify_ack(scsi_qla_host_t *, fc_port_t *, struct imm_ntfy_from_isp *, int); @@ -856,5 +871,6 @@ void qla24xx_delete_sess_fn(struct work_struct *); void qlt_unknown_atio_work_fn(struct work_struct *); void qlt_update_host_map(struct scsi_qla_host *, port_id_t); void qlt_remove_target_resources(struct qla_hw_data *); +void qlt_clr_qp_table(struct scsi_qla_host *vha); #endif /* _QLA_GBL_H */ diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index 9bc9aa9e164a..b323a7c71eda 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -124,6 +124,7 @@ qla2x00_chk_ms_status(scsi_qla_host_t *vha, ms_iocb_entry_t *ms_pkt, int rval; uint16_t comp_status; struct qla_hw_data *ha = vha->hw; + bool lid_is_sns = false; rval = QLA_FUNCTION_FAILED; if (ms_pkt->entry_status != 0) { @@ -155,6 +156,25 @@ qla2x00_chk_ms_status(scsi_qla_host_t *vha, ms_iocb_entry_t *ms_pkt, } else rval = QLA_SUCCESS; break; + case CS_PORT_LOGGED_OUT: + if (IS_FWI2_CAPABLE(ha)) { + if (le16_to_cpu(ms_pkt->loop_id.extended) == + NPH_SNS) + lid_is_sns = true; + } else { + if (le16_to_cpu(ms_pkt->loop_id.extended) == + SIMPLE_NAME_SERVER) + lid_is_sns = true; + } + if (lid_is_sns) { + ql_dbg(ql_dbg_async, vha, 0x502b, + "%s failed, Name server has logged out", + routine); + rval = QLA_NOT_LOGGED_IN; + set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); + set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); + } + break; default: ql_dbg(ql_dbg_disc, vha, 0x2033, "%s failed, completion status (%x) on port_id: " @@ -530,6 +550,8 @@ qla2x00_rft_id(scsi_qla_host_t *vha) ct_req->req.rft_id.fc4_types[2] = 0x01; /* FCP-3 */ + if (vha->flags.nvme_enabled) + ct_req->req.rft_id.fc4_types[6] = 1; /* NVMe type 28h */ /* Execute MS IOCB */ rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma, sizeof(ms_iocb_entry_t)); @@ -555,7 +577,7 @@ qla2x00_rft_id(scsi_qla_host_t *vha) * Returns 0 on success. */ int -qla2x00_rff_id(scsi_qla_host_t *vha) +qla2x00_rff_id(scsi_qla_host_t *vha, u8 type) { int rval; struct qla_hw_data *ha = vha->hw; @@ -593,7 +615,7 @@ qla2x00_rff_id(scsi_qla_host_t *vha) qlt_rff_id(vha, ct_req); - ct_req->req.rff_id.fc4_type = 0x08; /* SCSI - FCP */ + ct_req->req.rff_id.fc4_type = type; /* SCSI - FCP */ /* Execute MS IOCB */ rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma, @@ -2004,7 +2026,7 @@ qla2x00_fdmiv2_rhba(scsi_qla_host_t *vha) eiter->len = cpu_to_be16(4 + alen); size += 4 + alen; - ql_dbg(ql_dbg_disc, vha, 0x20b1, + ql_dbg(ql_dbg_disc, vha, 0x201b, "Vendor Identifier = %s.\n", eiter->a.vendor_identifier); /* Update MS request size. */ @@ -2144,6 +2166,13 @@ qla2x00_fdmiv2_rpa(scsi_qla_host_t *vha) eiter->a.fc4_types[2], eiter->a.fc4_types[1]); + if (vha->flags.nvme_enabled) { + eiter->a.fc4_types[6] = 1; /* NVMe type 28h */ + ql_dbg(ql_dbg_disc, vha, 0x211f, + "NVME FC4 Type = %02x 0x0 0x0 0x0 0x0 0x0.\n", + eiter->a.fc4_types[6]); + } + /* Supported speed. */ eiter = entries + size; eiter->type = cpu_to_be16(FDMI_PORT_SUPPORT_SPEED); @@ -2216,7 +2245,7 @@ qla2x00_fdmiv2_rpa(scsi_qla_host_t *vha) } size += 4 + 4; - ql_dbg(ql_dbg_disc, vha, 0x20bc, + ql_dbg(ql_dbg_disc, vha, 0x2017, "Current_Speed = %x.\n", eiter->a.cur_speed); /* Max frame size. */ @@ -2261,7 +2290,7 @@ qla2x00_fdmiv2_rpa(scsi_qla_host_t *vha) eiter->len = cpu_to_be16(4 + alen); size += 4 + alen; - ql_dbg(ql_dbg_disc, vha, 0x203d, + ql_dbg(ql_dbg_disc, vha, 0x201a, "HostName=%s.\n", eiter->a.host_name); /* Node Name */ @@ -2341,6 +2370,15 @@ qla2x00_fdmiv2_rpa(scsi_qla_host_t *vha) "Port Active FC4 Type = %02x %02x.\n", eiter->a.port_fc4_type[2], eiter->a.port_fc4_type[1]); + if (vha->flags.nvme_enabled) { + eiter->a.port_fc4_type[4] = 0; + eiter->a.port_fc4_type[5] = 0; + eiter->a.port_fc4_type[6] = 1; /* NVMe type 28h */ + ql_dbg(ql_dbg_disc, vha, 0x2120, + "NVME Port Active FC4 Type = %02x 0x0 0x0 0x0 0x0 0x0.\n", + eiter->a.port_fc4_type[6]); + } + /* Port State */ eiter = entries + size; eiter->type = cpu_to_be16(FDMI_PORT_STATE); @@ -2368,13 +2406,13 @@ qla2x00_fdmiv2_rpa(scsi_qla_host_t *vha) eiter->len = cpu_to_be16(4 + 4); size += 4 + 4; - ql_dbg(ql_dbg_disc, vha, 0x20c8, + ql_dbg(ql_dbg_disc, vha, 0x201c, "Port Id = %x.\n", eiter->a.port_id); /* Update MS request size. */ qla2x00_update_ms_fdmi_iocb(vha, size + 16); - ql_dbg(ql_dbg_disc, vha, 0x203e, + ql_dbg(ql_dbg_disc, vha, 0x2018, "RPA portname= %8phN size=%d.\n", ct_req->req.rpa.port_name, size); ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x20ca, entries, size); @@ -2734,6 +2772,10 @@ qla2x00_gff_id(scsi_qla_host_t *vha, sw_info_t *list) list[i].fc4_type = FC4_TYPE_FCP_SCSI; else list[i].fc4_type = FC4_TYPE_OTHER; + + list[i].fc4f_nvme = + ct_rsp->rsp.gff_id.fc4_features[GFF_NVME_OFFSET]; + list[i].fc4f_nvme &= 0xf; } /* Last device exit. */ @@ -2747,13 +2789,13 @@ void qla24xx_handle_gidpn_event(scsi_qla_host_t *vha, struct event_arg *ea) { fc_port_t *fcport = ea->fcport; - ql_dbg(ql_dbg_disc, vha, 0xffff, - "%s %8phC login state %d \n", - __func__, fcport->port_name, fcport->fw_login_state); + ql_dbg(ql_dbg_disc, vha, 0x201d, + "%s %8phC login state %d\n", + __func__, fcport->port_name, fcport->fw_login_state); if (ea->sp->gen2 != fcport->login_gen) { /* PLOGI/PRLI/LOGO came in while cmd was out.*/ - ql_dbg(ql_dbg_disc, vha, 0xffff, + ql_dbg(ql_dbg_disc, vha, 0x201e, "%s %8phC generation changed rscn %d|%d login %d|%d \n", __func__, fcport->port_name, fcport->last_rscn_gen, fcport->rscn_gen, fcport->last_login_gen, fcport->login_gen); @@ -2777,7 +2819,7 @@ void qla24xx_handle_gidpn_event(scsi_qla_host_t *vha, struct event_arg *ea) if (atomic_read(&fcport->state) == FCS_ONLINE) break; - ql_dbg(ql_dbg_disc, vha, 0xffff, + ql_dbg(ql_dbg_disc, vha, 0x201f, "%s %d %8phC post gnl\n", __func__, __LINE__, fcport->port_name); qla24xx_post_gnl_work(vha, fcport); @@ -2786,14 +2828,14 @@ void qla24xx_handle_gidpn_event(scsi_qla_host_t *vha, struct event_arg *ea) } else { /* fcport->d_id.b24 != ea->id.b24 */ fcport->d_id.b24 = ea->id.b24; if (fcport->deleted == QLA_SESS_DELETED) { - ql_dbg(ql_dbg_disc, vha, 0xffff, + ql_dbg(ql_dbg_disc, vha, 0x2021, "%s %d %8phC post del sess\n", __func__, __LINE__, fcport->port_name); qlt_schedule_sess_for_deletion_lock(fcport); } } } else { /* ea->sp->gen1 != fcport->rscn_gen */ - ql_dbg(ql_dbg_disc, vha, 0xffff, + ql_dbg(ql_dbg_disc, vha, 0x2022, "%s %d %8phC post gidpn\n", __func__, __LINE__, fcport->port_name); /* rscn came in while cmd was out */ @@ -2803,18 +2845,18 @@ void qla24xx_handle_gidpn_event(scsi_qla_host_t *vha, struct event_arg *ea) /* cable pulled */ if (ea->sp->gen1 == fcport->rscn_gen) { if (ea->sp->gen2 == fcport->login_gen) { - ql_dbg(ql_dbg_disc, vha, 0xffff, + ql_dbg(ql_dbg_disc, vha, 0x2042, "%s %d %8phC post del sess\n", __func__, __LINE__, fcport->port_name); qlt_schedule_sess_for_deletion_lock(fcport); } else { - ql_dbg(ql_dbg_disc, vha, 0xffff, + ql_dbg(ql_dbg_disc, vha, 0x2045, "%s %d %8phC login\n", __func__, __LINE__, fcport->port_name); qla24xx_fcport_handle_login(vha, fcport); } } else { - ql_dbg(ql_dbg_disc, vha, 0xffff, + ql_dbg(ql_dbg_disc, vha, 0x2049, "%s %d %8phC post gidpn\n", __func__, __LINE__, fcport->port_name); qla24xx_post_gidpn_work(vha, fcport); @@ -2841,7 +2883,7 @@ static void qla2x00_async_gidpn_sp_done(void *s, int res) ea.rc = res; ea.event = FCME_GIDPN_DONE; - ql_dbg(ql_dbg_disc, vha, 0xffff, + ql_dbg(ql_dbg_disc, vha, 0x204f, "Async done-%s res %x, WWPN %8phC ID %3phC \n", sp->name, res, fcport->port_name, id); @@ -2897,11 +2939,11 @@ int qla24xx_async_gidpn(scsi_qla_host_t *vha, fc_port_t *fcport) if (rval != QLA_SUCCESS) goto done_free_sp; - ql_dbg(ql_dbg_disc, vha, 0x206f, - "Async-%s - %8phC hdl=%x loopid=%x portid %02x%02x%02x.\n", - sp->name, fcport->port_name, - sp->handle, fcport->loop_id, fcport->d_id.b.domain, - fcport->d_id.b.area, fcport->d_id.b.al_pa); + ql_dbg(ql_dbg_disc, vha, 0x20a4, + "Async-%s - %8phC hdl=%x loopid=%x portid %02x%02x%02x.\n", + sp->name, fcport->port_name, + sp->handle, fcport->loop_id, fcport->d_id.b.domain, + fcport->d_id.b.area, fcport->d_id.b.al_pa); return rval; done_free_sp: @@ -2952,7 +2994,7 @@ static void qla24xx_async_gpsc_sp_done(void *s, int res) ct_rsp = &fcport->ct_desc.ct_sns->p.rsp; - ql_dbg(ql_dbg_disc, vha, 0xffff, + ql_dbg(ql_dbg_disc, vha, 0x2053, "Async done-%s res %x, WWPN %8phC \n", sp->name, res, fcport->port_name); @@ -2965,10 +3007,9 @@ static void qla24xx_async_gpsc_sp_done(void *s, int res) if ((ct_rsp->header.reason_code == CT_REASON_INVALID_COMMAND_CODE) || (ct_rsp->header.reason_code == - CT_REASON_COMMAND_UNSUPPORTED)) { - ql_dbg(ql_dbg_disc, vha, 0x205a, - "GPSC command unsupported, disabling " - "query.\n"); + CT_REASON_COMMAND_UNSUPPORTED)) { + ql_dbg(ql_dbg_disc, vha, 0x2019, + "GPSC command unsupported, disabling query.\n"); ha->flags.gpsc_supported = 0; res = QLA_SUCCESS; } @@ -2997,12 +3038,11 @@ static void qla24xx_async_gpsc_sp_done(void *s, int res) break; } - ql_dbg(ql_dbg_disc, vha, 0xffff, - "Async-%s OUT WWPN %8phC speeds=%04x speed=%04x.\n", - sp->name, - fcport->fabric_port_name, - be16_to_cpu(ct_rsp->rsp.gpsc.speeds), - be16_to_cpu(ct_rsp->rsp.gpsc.speed)); + ql_dbg(ql_dbg_disc, vha, 0x2054, + "Async-%s OUT WWPN %8phC speeds=%04x speed=%04x.\n", + sp->name, fcport->fabric_port_name, + be16_to_cpu(ct_rsp->rsp.gpsc.speeds), + be16_to_cpu(ct_rsp->rsp.gpsc.speed)); } done: memset(&ea, 0, sizeof(ea)); @@ -3058,11 +3098,11 @@ int qla24xx_async_gpsc(scsi_qla_host_t *vha, fc_port_t *fcport) if (rval != QLA_SUCCESS) goto done_free_sp; - ql_dbg(ql_dbg_disc, vha, 0xffff, - "Async-%s %8phC hdl=%x loopid=%x portid=%02x%02x%02x.\n", - sp->name, fcport->port_name, sp->handle, - fcport->loop_id, fcport->d_id.b.domain, - fcport->d_id.b.area, fcport->d_id.b.al_pa); + ql_dbg(ql_dbg_disc, vha, 0x205e, + "Async-%s %8phC hdl=%x loopid=%x portid=%02x%02x%02x.\n", + sp->name, fcport->port_name, sp->handle, + fcport->loop_id, fcport->d_id.b.domain, + fcport->d_id.b.area, fcport->d_id.b.al_pa); return rval; done_free_sp: @@ -3118,21 +3158,32 @@ void qla24xx_handle_gpnid_event(scsi_qla_host_t *vha, struct event_arg *ea) if (fcport) { /* cable moved. just plugged in */ - ql_dbg(ql_dbg_disc, vha, 0xffff, - "%s %d %8phC post del sess\n", - __func__, __LINE__, fcport->port_name); - fcport->rscn_gen++; fcport->d_id = ea->id; fcport->scan_state = QLA_FCPORT_FOUND; fcport->flags |= FCF_FABRIC_DEVICE; - qlt_schedule_sess_for_deletion_lock(fcport); + switch (fcport->disc_state) { + case DSC_DELETED: + ql_dbg(ql_dbg_disc, vha, 0x210d, + "%s %d %8phC login\n", __func__, __LINE__, + fcport->port_name); + qla24xx_fcport_handle_login(vha, fcport); + break; + case DSC_DELETE_PEND: + break; + default: + ql_dbg(ql_dbg_disc, vha, 0x2064, + "%s %d %8phC post del sess\n", + __func__, __LINE__, fcport->port_name); + qlt_schedule_sess_for_deletion_lock(fcport); + break; + } } else { /* create new fcport */ - ql_dbg(ql_dbg_disc, vha, 0xffff, - "%s %d %8phC post new sess\n", - __func__, __LINE__, ea->port_name); + ql_dbg(ql_dbg_disc, vha, 0x2065, + "%s %d %8phC post new sess\n", + __func__, __LINE__, ea->port_name); qla24xx_post_newsess_work(vha, &ea->id, ea->port_name, NULL); } @@ -3149,10 +3200,10 @@ static void qla2x00_async_gpnid_sp_done(void *s, int res) struct event_arg ea; struct qla_work_evt *e; - ql_dbg(ql_dbg_disc, vha, 0xffff, - "Async done-%s res %x ID %3phC. %8phC\n", - sp->name, res, ct_req->req.port_id.port_id, - ct_rsp->rsp.gpn_id.port_name); + ql_dbg(ql_dbg_disc, vha, 0x2066, + "Async done-%s res %x ID %3phC. %8phC\n", + sp->name, res, ct_req->req.port_id.port_id, + ct_rsp->rsp.gpn_id.port_name); memset(&ea, 0, sizeof(ea)); memcpy(ea.port_name, ct_rsp->rsp.gpn_id.port_name, WWN_SIZE); @@ -3214,8 +3265,8 @@ int qla24xx_async_gpnid(scsi_qla_host_t *vha, port_id_t *id) sizeof(struct ct_sns_pkt), &sp->u.iocb_cmd.u.ctarg.req_dma, GFP_KERNEL); if (!sp->u.iocb_cmd.u.ctarg.req) { - ql_log(ql_log_warn, vha, 0xffff, - "Failed to allocate ct_sns request.\n"); + ql_log(ql_log_warn, vha, 0xd041, + "Failed to allocate ct_sns request.\n"); goto done_free_sp; } @@ -3223,8 +3274,8 @@ int qla24xx_async_gpnid(scsi_qla_host_t *vha, port_id_t *id) sizeof(struct ct_sns_pkt), &sp->u.iocb_cmd.u.ctarg.rsp_dma, GFP_KERNEL); if (!sp->u.iocb_cmd.u.ctarg.rsp) { - ql_log(ql_log_warn, vha, 0xffff, - "Failed to allocate ct_sns request.\n"); + ql_log(ql_log_warn, vha, 0xd042, + "Failed to allocate ct_sns request.\n"); goto done_free_sp; } @@ -3251,9 +3302,9 @@ int qla24xx_async_gpnid(scsi_qla_host_t *vha, port_id_t *id) if (rval != QLA_SUCCESS) goto done_free_sp; - ql_dbg(ql_dbg_disc, vha, 0xffff, - "Async-%s hdl=%x ID %3phC.\n", sp->name, - sp->handle, ct_req->req.port_id.port_id); + ql_dbg(ql_dbg_disc, vha, 0x2067, + "Async-%s hdl=%x ID %3phC.\n", sp->name, + sp->handle, ct_req->req.port_id.port_id); return rval; done_free_sp: @@ -3276,3 +3327,111 @@ done_free_sp: done: return rval; } + +void qla24xx_handle_gffid_event(scsi_qla_host_t *vha, struct event_arg *ea) +{ + fc_port_t *fcport = ea->fcport; + + qla24xx_post_gnl_work(vha, fcport); +} + +void qla24xx_async_gffid_sp_done(void *s, int res) +{ + struct srb *sp = s; + struct scsi_qla_host *vha = sp->vha; + fc_port_t *fcport = sp->fcport; + struct ct_sns_rsp *ct_rsp; + struct event_arg ea; + + ql_dbg(ql_dbg_disc, vha, 0x2133, + "Async done-%s res %x ID %x. %8phC\n", + sp->name, res, fcport->d_id.b24, fcport->port_name); + + fcport->flags &= ~FCF_ASYNC_SENT; + ct_rsp = &fcport->ct_desc.ct_sns->p.rsp; + /* + * FC-GS-7, 5.2.3.12 FC-4 Features - format + * The format of the FC-4 Features object, as defined by the FC-4, + * Shall be an array of 4-bit values, one for each type code value + */ + if (!res) { + if (ct_rsp->rsp.gff_id.fc4_features[GFF_FCP_SCSI_OFFSET] & 0xf) { + /* w1 b00:03 */ + fcport->fc4_type = + ct_rsp->rsp.gff_id.fc4_features[GFF_FCP_SCSI_OFFSET]; + fcport->fc4_type &= 0xf; + } + + if (ct_rsp->rsp.gff_id.fc4_features[GFF_NVME_OFFSET] & 0xf) { + /* w5 [00:03]/28h */ + fcport->fc4f_nvme = + ct_rsp->rsp.gff_id.fc4_features[GFF_NVME_OFFSET]; + fcport->fc4f_nvme &= 0xf; + } + } + + memset(&ea, 0, sizeof(ea)); + ea.sp = sp; + ea.fcport = sp->fcport; + ea.rc = res; + ea.event = FCME_GFFID_DONE; + + qla2x00_fcport_event_handler(vha, &ea); + sp->free(sp); +} + +/* Get FC4 Feature with Nport ID. */ +int qla24xx_async_gffid(scsi_qla_host_t *vha, fc_port_t *fcport) +{ + int rval = QLA_FUNCTION_FAILED; + struct ct_sns_req *ct_req; + srb_t *sp; + + if (!vha->flags.online) + return rval; + + sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL); + if (!sp) + return rval; + + fcport->flags |= FCF_ASYNC_SENT; + sp->type = SRB_CT_PTHRU_CMD; + sp->name = "gffid"; + sp->gen1 = fcport->rscn_gen; + sp->gen2 = fcport->login_gen; + + qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2); + + /* CT_IU preamble */ + ct_req = qla2x00_prep_ct_req(fcport->ct_desc.ct_sns, GFF_ID_CMD, + GFF_ID_RSP_SIZE); + + ct_req->req.gff_id.port_id[0] = fcport->d_id.b.domain; + ct_req->req.gff_id.port_id[1] = fcport->d_id.b.area; + ct_req->req.gff_id.port_id[2] = fcport->d_id.b.al_pa; + + sp->u.iocb_cmd.u.ctarg.req = fcport->ct_desc.ct_sns; + sp->u.iocb_cmd.u.ctarg.req_dma = fcport->ct_desc.ct_sns_dma; + sp->u.iocb_cmd.u.ctarg.rsp = fcport->ct_desc.ct_sns; + sp->u.iocb_cmd.u.ctarg.rsp_dma = fcport->ct_desc.ct_sns_dma; + sp->u.iocb_cmd.u.ctarg.req_size = GFF_ID_REQ_SIZE; + sp->u.iocb_cmd.u.ctarg.rsp_size = GFF_ID_RSP_SIZE; + sp->u.iocb_cmd.u.ctarg.nport_handle = NPH_SNS; + + sp->u.iocb_cmd.timeout = qla2x00_async_iocb_timeout; + sp->done = qla24xx_async_gffid_sp_done; + + rval = qla2x00_start_sp(sp); + if (rval != QLA_SUCCESS) + goto done_free_sp; + + ql_dbg(ql_dbg_disc, vha, 0x2132, + "Async-%s hdl=%x %8phC.\n", sp->name, + sp->handle, fcport->port_name); + + return rval; +done_free_sp: + sp->free(sp); + fcport->flags &= ~FCF_ASYNC_SENT; + return rval; +} diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 0391fc317003..072ad1aa5505 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -37,8 +37,11 @@ static struct qla_chip_state_84xx *qla84xx_get_chip(struct scsi_qla_host *); static int qla84xx_init_chip(scsi_qla_host_t *); static int qla25xx_init_queues(struct qla_hw_data *); static int qla24xx_post_gpdb_work(struct scsi_qla_host *, fc_port_t *, u8); +static int qla24xx_post_prli_work(struct scsi_qla_host*, fc_port_t *); static void qla24xx_handle_plogi_done_event(struct scsi_qla_host *, struct event_arg *); +static void qla24xx_handle_prli_done_event(struct scsi_qla_host *, + struct event_arg *); /* SRB Extensions ---------------------------------------------------------- */ @@ -141,7 +144,7 @@ qla2x00_async_login_sp_done(void *ptr, int res) struct srb_iocb *lio = &sp->u.iocb_cmd; struct event_arg ea; - ql_dbg(ql_dbg_disc, vha, 0xffff, + ql_dbg(ql_dbg_disc, vha, 0x20dd, "%s %8phC res %d \n", __func__, sp->fcport->port_name, res); sp->fcport->flags &= ~FCF_ASYNC_SENT; @@ -191,6 +194,10 @@ qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport, lio->timeout = qla2x00_async_iocb_timeout; sp->done = qla2x00_async_login_sp_done; lio->u.logio.flags |= SRB_LOGIN_COND_PLOGI; + + if (fcport->fc4f_nvme) + lio->u.logio.flags |= SRB_LOGIN_SKIP_PRLI; + if (data[1] & QLA_LOGIO_LOGIN_RETRIED) lio->u.logio.flags |= SRB_LOGIN_RETRIED; rval = qla2x00_start_sp(sp); @@ -327,38 +334,38 @@ static void qla24xx_handle_gnl_done_event(scsi_qla_host_t *vha, u16 i, n, found = 0, loop_id; port_id_t id; u64 wwn; - u8 opt = 0; + u8 opt = 0, current_login_state; fcport = ea->fcport; if (ea->rc) { /* rval */ if (fcport->login_retry == 0) { fcport->login_retry = vha->hw->login_retry_count; - ql_dbg(ql_dbg_disc, vha, 0xffff, - "GNL failed Port login retry %8phN, retry cnt=%d.\n", - fcport->port_name, fcport->login_retry); + ql_dbg(ql_dbg_disc, vha, 0x20de, + "GNL failed Port login retry %8phN, retry cnt=%d.\n", + fcport->port_name, fcport->login_retry); } return; } if (fcport->last_rscn_gen != fcport->rscn_gen) { - ql_dbg(ql_dbg_disc, vha, 0xffff, + ql_dbg(ql_dbg_disc, vha, 0x20df, "%s %8phC rscn gen changed rscn %d|%d \n", __func__, fcport->port_name, fcport->last_rscn_gen, fcport->rscn_gen); qla24xx_post_gidpn_work(vha, fcport); return; } else if (fcport->last_login_gen != fcport->login_gen) { - ql_dbg(ql_dbg_disc, vha, 0xffff, - "%s %8phC login gen changed login %d|%d \n", - __func__, fcport->port_name, - fcport->last_login_gen, fcport->login_gen); + ql_dbg(ql_dbg_disc, vha, 0x20e0, + "%s %8phC login gen changed login %d|%d\n", + __func__, fcport->port_name, + fcport->last_login_gen, fcport->login_gen); return; } n = ea->data[0] / sizeof(struct get_name_list_extended); - ql_dbg(ql_dbg_disc, vha, 0xffff, + ql_dbg(ql_dbg_disc, vha, 0x20e1, "%s %d %8phC n %d %02x%02x%02x lid %d \n", __func__, __LINE__, fcport->port_name, n, fcport->d_id.b.domain, fcport->d_id.b.area, @@ -380,20 +387,20 @@ static void qla24xx_handle_gnl_done_event(scsi_qla_host_t *vha, loop_id = le16_to_cpu(e->nport_handle); loop_id = (loop_id & 0x7fff); - ql_dbg(ql_dbg_disc, vha, 0xffff, - "%s found %8phC CLS [%d|%d] ID[%02x%02x%02x|%02x%02x%02x] lid[%d|%d]\n", - __func__, fcport->port_name, - e->current_login_state, fcport->fw_login_state, - id.b.domain, id.b.area, id.b.al_pa, - fcport->d_id.b.domain, fcport->d_id.b.area, - fcport->d_id.b.al_pa, loop_id, fcport->loop_id); + ql_dbg(ql_dbg_disc, vha, 0x20e2, + "%s found %8phC CLS [%d|%d] ID[%02x%02x%02x|%02x%02x%02x] lid[%d|%d]\n", + __func__, fcport->port_name, + e->current_login_state, fcport->fw_login_state, + id.b.domain, id.b.area, id.b.al_pa, + fcport->d_id.b.domain, fcport->d_id.b.area, + fcport->d_id.b.al_pa, loop_id, fcport->loop_id); if ((id.b24 != fcport->d_id.b24) || ((fcport->loop_id != FC_NO_LOOP_ID) && (fcport->loop_id != loop_id))) { - ql_dbg(ql_dbg_disc, vha, 0xffff, - "%s %d %8phC post del sess\n", - __func__, __LINE__, fcport->port_name); + ql_dbg(ql_dbg_disc, vha, 0x20e3, + "%s %d %8phC post del sess\n", + __func__, __LINE__, fcport->port_name); qlt_schedule_sess_for_deletion(fcport, 1); return; } @@ -414,24 +421,28 @@ static void qla24xx_handle_gnl_done_event(scsi_qla_host_t *vha, fcport->login_pause = 1; } - switch (e->current_login_state) { + if (fcport->fc4f_nvme) + current_login_state = e->current_login_state >> 4; + else + current_login_state = e->current_login_state & 0xf; + + switch (current_login_state) { case DSC_LS_PRLI_COMP: - ql_dbg(ql_dbg_disc, vha, 0xffff, - "%s %d %8phC post gpdb\n", - __func__, __LINE__, fcport->port_name); + ql_dbg(ql_dbg_disc, vha, 0x20e4, + "%s %d %8phC post gpdb\n", + __func__, __LINE__, fcport->port_name); opt = PDO_FORCE_ADISC; qla24xx_post_gpdb_work(vha, fcport, opt); break; - case DSC_LS_PORT_UNAVAIL: default: if (fcport->loop_id == FC_NO_LOOP_ID) { qla2x00_find_new_loop_id(vha, fcport); fcport->fw_login_state = DSC_LS_PORT_UNAVAIL; } - ql_dbg(ql_dbg_disc, vha, 0xffff, - "%s %d %8phC \n", - __func__, __LINE__, fcport->port_name); + ql_dbg(ql_dbg_disc, vha, 0x20e5, + "%s %d %8phC\n", + __func__, __LINE__, fcport->port_name); qla24xx_fcport_handle_login(vha, fcport); break; } @@ -456,7 +467,7 @@ static void qla24xx_handle_gnl_done_event(scsi_qla_host_t *vha, qla2x00_find_fcport_by_wwpn(vha, e->port_name, 0); - ql_dbg(ql_dbg_disc, vha, 0xffff, + ql_dbg(ql_dbg_disc, vha, 0x20e6, "%s %d %8phC post del sess\n", __func__, __LINE__, conflict_fcport->port_name); @@ -487,7 +498,7 @@ qla24xx_async_gnl_sp_done(void *s, int res) u64 wwn; struct list_head h; - ql_dbg(ql_dbg_disc, vha, 0xffff, + ql_dbg(ql_dbg_disc, vha, 0x20e7, "Async done-%s res %x mb[1]=%x mb[2]=%x \n", sp->name, res, sp->u.iocb_cmd.u.mbx.in_mb[1], sp->u.iocb_cmd.u.mbx.in_mb[2]); @@ -512,7 +523,7 @@ qla24xx_async_gnl_sp_done(void *s, int res) set_bit(loop_id, vha->hw->loop_id_map); wwn = wwn_to_u64(e->port_name); - ql_dbg(ql_dbg_disc + ql_dbg_verbose, vha, 0xffff, + ql_dbg(ql_dbg_disc + ql_dbg_verbose, vha, 0x20e8, "%s %8phC %02x:%02x:%02x state %d/%d lid %x \n", __func__, (void *)&wwn, e->port_id[2], e->port_id[1], e->port_id[0], e->current_login_state, e->last_login_state, @@ -551,7 +562,7 @@ int qla24xx_async_gnl(struct scsi_qla_host *vha, fc_port_t *fcport) if (!vha->flags.online) goto done; - ql_dbg(ql_dbg_disc, vha, 0xffff, + ql_dbg(ql_dbg_disc, vha, 0x20d9, "Async-gnlist WWPN %8phC \n", fcport->port_name); spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); @@ -598,9 +609,9 @@ int qla24xx_async_gnl(struct scsi_qla_host *vha, fc_port_t *fcport) if (rval != QLA_SUCCESS) goto done_free_sp; - ql_dbg(ql_dbg_disc, vha, 0xffff, - "Async-%s - OUT WWPN %8phC hndl %x\n", - sp->name, fcport->port_name, sp->handle); + ql_dbg(ql_dbg_disc, vha, 0x20da, + "Async-%s - OUT WWPN %8phC hndl %x\n", + sp->name, fcport->port_name, sp->handle); return rval; @@ -635,7 +646,7 @@ void qla24xx_async_gpdb_sp_done(void *s, int res) int rval = QLA_SUCCESS; struct event_arg ea; - ql_dbg(ql_dbg_disc, vha, 0xffff, + ql_dbg(ql_dbg_disc, vha, 0x20db, "Async done-%s res %x, WWPN %8phC mb[1]=%x mb[2]=%x \n", sp->name, res, fcport->port_name, mb[1], mb[2]); @@ -665,6 +676,104 @@ gpd_error_out: sp->free(sp); } +static int qla24xx_post_prli_work(struct scsi_qla_host *vha, fc_port_t *fcport) +{ + struct qla_work_evt *e; + + e = qla2x00_alloc_work(vha, QLA_EVT_PRLI); + if (!e) + return QLA_FUNCTION_FAILED; + + e->u.fcport.fcport = fcport; + + return qla2x00_post_work(vha, e); +} + +static void +qla2x00_async_prli_sp_done(void *ptr, int res) +{ + srb_t *sp = ptr; + struct scsi_qla_host *vha = sp->vha; + struct srb_iocb *lio = &sp->u.iocb_cmd; + struct event_arg ea; + + ql_dbg(ql_dbg_disc, vha, 0x2129, + "%s %8phC res %d \n", __func__, + sp->fcport->port_name, res); + + sp->fcport->flags &= ~FCF_ASYNC_SENT; + + if (!test_bit(UNLOADING, &vha->dpc_flags)) { + memset(&ea, 0, sizeof(ea)); + ea.event = FCME_PRLI_DONE; + ea.fcport = sp->fcport; + ea.data[0] = lio->u.logio.data[0]; + ea.data[1] = lio->u.logio.data[1]; + ea.iop[0] = lio->u.logio.iop[0]; + ea.iop[1] = lio->u.logio.iop[1]; + ea.sp = sp; + + qla2x00_fcport_event_handler(vha, &ea); + } + + sp->free(sp); +} + +int +qla24xx_async_prli(struct scsi_qla_host *vha, fc_port_t *fcport) +{ + srb_t *sp; + struct srb_iocb *lio; + int rval = QLA_FUNCTION_FAILED; + + if (!vha->flags.online) + return rval; + + if (fcport->fw_login_state == DSC_LS_PLOGI_PEND || + fcport->fw_login_state == DSC_LS_PLOGI_COMP || + fcport->fw_login_state == DSC_LS_PRLI_PEND) + return rval; + + sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL); + if (!sp) + return rval; + + fcport->flags |= FCF_ASYNC_SENT; + fcport->logout_completed = 0; + + sp->type = SRB_PRLI_CMD; + sp->name = "prli"; + qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2); + + lio = &sp->u.iocb_cmd; + lio->timeout = qla2x00_async_iocb_timeout; + sp->done = qla2x00_async_prli_sp_done; + lio->u.logio.flags = 0; + + if (fcport->fc4f_nvme) + lio->u.logio.flags |= SRB_LOGIN_NVME_PRLI; + + rval = qla2x00_start_sp(sp); + if (rval != QLA_SUCCESS) { + fcport->flags &= ~FCF_ASYNC_SENT; + fcport->flags |= FCF_LOGIN_NEEDED; + set_bit(RELOGIN_NEEDED, &vha->dpc_flags); + goto done_free_sp; + } + + ql_dbg(ql_dbg_disc, vha, 0x211b, + "Async-prli - %8phC hdl=%x, loopid=%x portid=%06x retries=%d.\n", + fcport->port_name, sp->handle, fcport->loop_id, + fcport->d_id.b24, fcport->login_retry); + + return rval; + +done_free_sp: + sp->free(sp); + fcport->flags &= ~FCF_ASYNC_SENT; + return rval; +} + static int qla24xx_post_gpdb_work(struct scsi_qla_host *vha, fc_port_t *fcport, u8 opt) { @@ -701,8 +810,8 @@ int qla24xx_async_gpdb(struct scsi_qla_host *vha, fc_port_t *fcport, u8 opt) pd = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &pd_dma); if (pd == NULL) { - ql_log(ql_log_warn, vha, 0xffff, - "Failed to allocate port database structure.\n"); + ql_log(ql_log_warn, vha, 0xd043, + "Failed to allocate port database structure.\n"); goto done_free_sp; } memset(pd, 0, max(PORT_DATABASE_SIZE, PORT_DATABASE_24XX_SIZE)); @@ -734,9 +843,9 @@ int qla24xx_async_gpdb(struct scsi_qla_host *vha, fc_port_t *fcport, u8 opt) if (rval != QLA_SUCCESS) goto done_free_sp; - ql_dbg(ql_dbg_disc, vha, 0xffff, - "Async-%s %8phC hndl %x opt %x\n", - sp->name, fcport->port_name, sp->handle, opt); + ql_dbg(ql_dbg_disc, vha, 0x20dc, + "Async-%s %8phC hndl %x opt %x\n", + sp->name, fcport->port_name, sp->handle, opt); return rval; @@ -760,27 +869,27 @@ void qla24xx_handle_gpdb_event(scsi_qla_host_t *vha, struct event_arg *ea) fcport->flags &= ~FCF_ASYNC_SENT; - ql_dbg(ql_dbg_disc, vha, 0xffff, + ql_dbg(ql_dbg_disc, vha, 0x20d2, "%s %8phC DS %d LS %d rval %d\n", __func__, fcport->port_name, fcport->disc_state, fcport->fw_login_state, rval); if (ea->sp->gen2 != fcport->login_gen) { /* target side must have changed it. */ - ql_dbg(ql_dbg_disc, vha, 0xffff, + ql_dbg(ql_dbg_disc, vha, 0x20d3, "%s %8phC generation changed rscn %d|%d login %d|%d \n", __func__, fcport->port_name, fcport->last_rscn_gen, fcport->rscn_gen, fcport->last_login_gen, fcport->login_gen); return; } else if (ea->sp->gen1 != fcport->rscn_gen) { - ql_dbg(ql_dbg_disc, vha, 0xffff, "%s %d %8phC post gidpn\n", + ql_dbg(ql_dbg_disc, vha, 0x20d4, "%s %d %8phC post gidpn\n", __func__, __LINE__, fcport->port_name); qla24xx_post_gidpn_work(vha, fcport); return; } if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_disc, vha, 0xffff, "%s %d %8phC post del sess\n", + ql_dbg(ql_dbg_disc, vha, 0x20d5, "%s %d %8phC post del sess\n", __func__, __LINE__, fcport->port_name); qlt_schedule_sess_for_deletion_lock(fcport); return; @@ -797,14 +906,14 @@ void qla24xx_handle_gpdb_event(scsi_qla_host_t *vha, struct event_arg *ea) if (!IS_IIDMA_CAPABLE(vha->hw) || !vha->hw->flags.gpsc_supported) { - ql_dbg(ql_dbg_disc, vha, 0xffff, + ql_dbg(ql_dbg_disc, vha, 0x20d6, "%s %d %8phC post upd_fcport fcp_cnt %d\n", __func__, __LINE__, fcport->port_name, vha->fcport_count); qla24xx_post_upd_fcport_work(vha, fcport); } else { - ql_dbg(ql_dbg_disc, vha, 0xffff, + ql_dbg(ql_dbg_disc, vha, 0x20d7, "%s %d %8phC post gpsc fcp_cnt %d\n", __func__, __LINE__, fcport->port_name, vha->fcport_count); @@ -823,7 +932,7 @@ int qla24xx_fcport_handle_login(struct scsi_qla_host *vha, fc_port_t *fcport) if (fcport->scan_state != QLA_FCPORT_FOUND) return 0; - ql_dbg(ql_dbg_disc, vha, 0xffff, + ql_dbg(ql_dbg_disc, vha, 0x20d8, "%s %8phC DS %d LS %d P %d fl %x confl %p rscn %d|%d login %d|%d retry %d lid %d\n", __func__, fcport->port_name, fcport->disc_state, fcport->fw_login_state, fcport->login_pause, fcport->flags, @@ -854,14 +963,14 @@ int qla24xx_fcport_handle_login(struct scsi_qla_host *vha, fc_port_t *fcport) switch (fcport->disc_state) { case DSC_DELETED: if (fcport->loop_id == FC_NO_LOOP_ID) { - ql_dbg(ql_dbg_disc, vha, 0xffff, - "%s %d %8phC post gnl\n", - __func__, __LINE__, fcport->port_name); + ql_dbg(ql_dbg_disc, vha, 0x20bd, + "%s %d %8phC post gnl\n", + __func__, __LINE__, fcport->port_name); qla24xx_async_gnl(vha, fcport); } else { - ql_dbg(ql_dbg_disc, vha, 0xffff, - "%s %d %8phC post login\n", - __func__, __LINE__, fcport->port_name); + ql_dbg(ql_dbg_disc, vha, 0x20bf, + "%s %d %8phC post login\n", + __func__, __LINE__, fcport->port_name); fcport->disc_state = DSC_LOGIN_PEND; qla2x00_post_async_login_work(vha, fcport, NULL); } @@ -878,16 +987,16 @@ int qla24xx_fcport_handle_login(struct scsi_qla_host *vha, fc_port_t *fcport) if (fcport->flags & FCF_FCP2_DEVICE) { u8 opt = PDO_FORCE_ADISC; - ql_dbg(ql_dbg_disc, vha, 0xffff, - "%s %d %8phC post gpdb\n", - __func__, __LINE__, fcport->port_name); + ql_dbg(ql_dbg_disc, vha, 0x20c9, + "%s %d %8phC post gpdb\n", + __func__, __LINE__, fcport->port_name); fcport->disc_state = DSC_GPDB; qla24xx_post_gpdb_work(vha, fcport, opt); } else { - ql_dbg(ql_dbg_disc, vha, 0xffff, - "%s %d %8phC post login \n", - __func__, __LINE__, fcport->port_name); + ql_dbg(ql_dbg_disc, vha, 0x20cf, + "%s %d %8phC post login\n", + __func__, __LINE__, fcport->port_name); fcport->disc_state = DSC_LOGIN_PEND; qla2x00_post_async_login_work(vha, fcport, NULL); } @@ -895,18 +1004,18 @@ int qla24xx_fcport_handle_login(struct scsi_qla_host *vha, fc_port_t *fcport) break; case DSC_LOGIN_FAILED: - ql_dbg(ql_dbg_disc, vha, 0xffff, - "%s %d %8phC post gidpn \n", - __func__, __LINE__, fcport->port_name); + ql_dbg(ql_dbg_disc, vha, 0x20d0, + "%s %d %8phC post gidpn\n", + __func__, __LINE__, fcport->port_name); qla24xx_post_gidpn_work(vha, fcport); break; case DSC_LOGIN_COMPLETE: /* recheck login state */ - ql_dbg(ql_dbg_disc, vha, 0xffff, - "%s %d %8phC post gpdb \n", - __func__, __LINE__, fcport->port_name); + ql_dbg(ql_dbg_disc, vha, 0x20d1, + "%s %d %8phC post gpdb\n", + __func__, __LINE__, fcport->port_name); qla24xx_post_gpdb_work(vha, fcport, PDO_FORCE_ADISC); break; @@ -923,10 +1032,10 @@ void qla24xx_handle_rscn_event(fc_port_t *fcport, struct event_arg *ea) { fcport->rscn_gen++; - ql_dbg(ql_dbg_disc, fcport->vha, 0xffff, - "%s %8phC DS %d LS %d\n", - __func__, fcport->port_name, fcport->disc_state, - fcport->fw_login_state); + ql_dbg(ql_dbg_disc, fcport->vha, 0x210c, + "%s %8phC DS %d LS %d\n", + __func__, fcport->port_name, fcport->disc_state, + fcport->fw_login_state); if (fcport->flags & FCF_ASYNC_SENT) return; @@ -993,14 +1102,14 @@ void qla24xx_handle_relogin_event(scsi_qla_host_t *vha, return; } - ql_dbg(ql_dbg_disc, vha, 0xffff, - "%s %8phC DS %d LS %d P %d del %d cnfl %p rscn %d|%d login %d|%d fl %x\n", - __func__, fcport->port_name, fcport->disc_state, - fcport->fw_login_state, fcport->login_pause, - fcport->deleted, fcport->conflict, - fcport->last_rscn_gen, fcport->rscn_gen, - fcport->last_login_gen, fcport->login_gen, - fcport->flags); + ql_dbg(ql_dbg_disc, vha, 0x2102, + "%s %8phC DS %d LS %d P %d del %d cnfl %p rscn %d|%d login %d|%d fl %x\n", + __func__, fcport->port_name, fcport->disc_state, + fcport->fw_login_state, fcport->login_pause, + fcport->deleted, fcport->conflict, + fcport->last_rscn_gen, fcport->rscn_gen, + fcport->last_login_gen, fcport->login_gen, + fcport->flags); if ((fcport->fw_login_state == DSC_LS_PLOGI_PEND) || (fcport->fw_login_state == DSC_LS_PRLI_PEND)) @@ -1023,7 +1132,7 @@ void qla24xx_handle_relogin_event(scsi_qla_host_t *vha, } if (fcport->last_rscn_gen != fcport->rscn_gen) { - ql_dbg(ql_dbg_disc, vha, 0xffff, "%s %d %8phC post gidpn\n", + ql_dbg(ql_dbg_disc, vha, 0x20e9, "%s %d %8phC post gidpn\n", __func__, __LINE__, fcport->port_name); qla24xx_async_gidpn(vha, fcport); @@ -1041,6 +1150,20 @@ void qla2x00_fcport_event_handler(scsi_qla_host_t *vha, struct event_arg *ea) switch (ea->event) { case FCME_RELOGIN: + case FCME_RSCN: + case FCME_GIDPN_DONE: + case FCME_GPSC_DONE: + case FCME_GPNID_DONE: + if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags) || + test_bit(LOOP_RESYNC_ACTIVE, &vha->dpc_flags)) + return; + break; + default: + break; + } + + switch (ea->event) { + case FCME_RELOGIN: if (test_bit(UNLOADING, &vha->dpc_flags)) return; @@ -1056,10 +1179,10 @@ void qla2x00_fcport_event_handler(scsi_qla_host_t *vha, struct event_arg *ea) /* cable moved */ rc = qla24xx_post_gpnid_work(vha, &ea->id); if (rc) { - ql_log(ql_log_warn, vha, 0xffff, - "RSCN GPNID work failed %02x%02x%02x\n", - ea->id.b.domain, ea->id.b.area, - ea->id.b.al_pa); + ql_log(ql_log_warn, vha, 0xd044, + "RSCN GPNID work failed %02x%02x%02x\n", + ea->id.b.domain, ea->id.b.area, + ea->id.b.al_pa); } } else { ea->fcport = fcport; @@ -1070,14 +1193,14 @@ void qla2x00_fcport_event_handler(scsi_qla_host_t *vha, struct event_arg *ea) case RSCN_DOM_ADDR: if (ea->id.b.rsvd_1 == RSCN_AREA_ADDR) { mask = 0xffff00; - ql_log(ql_dbg_async, vha, 0xffff, - "RSCN: Area 0x%06x was affected\n", - ea->id.b24); + ql_dbg(ql_dbg_async, vha, 0x5044, + "RSCN: Area 0x%06x was affected\n", + ea->id.b24); } else { mask = 0xff0000; - ql_log(ql_dbg_async, vha, 0xffff, - "RSCN: Domain 0x%06x was affected\n", - ea->id.b24); + ql_dbg(ql_dbg_async, vha, 0x507a, + "RSCN: Domain 0x%06x was affected\n", + ea->id.b24); } rid = ea->id.b24 & mask; @@ -1092,9 +1215,9 @@ void qla2x00_fcport_event_handler(scsi_qla_host_t *vha, struct event_arg *ea) break; case RSCN_FAB_ADDR: default: - ql_log(ql_log_warn, vha, 0xffff, - "RSCN: Fabric was affected. Addr format %d\n", - ea->id.b.rsvd_1); + ql_log(ql_log_warn, vha, 0xd045, + "RSCN: Fabric was affected. Addr format %d\n", + ea->id.b.rsvd_1); qla2x00_mark_all_devices_lost(vha, 1); set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); @@ -1112,12 +1235,18 @@ void qla2x00_fcport_event_handler(scsi_qla_host_t *vha, struct event_arg *ea) case FCME_PLOGI_DONE: /* Initiator side sent LLIOCB */ qla24xx_handle_plogi_done_event(vha, ea); break; + case FCME_PRLI_DONE: + qla24xx_handle_prli_done_event(vha, ea); + break; case FCME_GPDB_DONE: qla24xx_handle_gpdb_event(vha, ea); break; case FCME_GPNID_DONE: qla24xx_handle_gpnid_event(vha, ea); break; + case FCME_GFFID_DONE: + qla24xx_handle_gffid_event(vha, ea); + break; case FCME_DELETE_DONE: qla24xx_handle_delete_done_event(vha, ea); break; @@ -1294,6 +1423,27 @@ qla24xx_async_abort_command(srb_t *sp) } static void +qla24xx_handle_prli_done_event(struct scsi_qla_host *vha, struct event_arg *ea) +{ + switch (ea->data[0]) { + case MBS_COMMAND_COMPLETE: + ql_dbg(ql_dbg_disc, vha, 0x2118, + "%s %d %8phC post gpdb\n", + __func__, __LINE__, ea->fcport->port_name); + + ea->fcport->chip_reset = vha->hw->base_qpair->chip_reset; + ea->fcport->logout_on_delete = 1; + qla24xx_post_gpdb_work(vha, ea->fcport, 0); + break; + default: + ql_dbg(ql_dbg_disc, vha, 0x2119, + "%s %d %8phC unhandle event of %x\n", + __func__, __LINE__, ea->fcport->port_name, ea->data[0]); + break; + } +} + +static void qla24xx_handle_plogi_done_event(struct scsi_qla_host *vha, struct event_arg *ea) { port_id_t cid; /* conflict Nport id */ @@ -1305,15 +1455,22 @@ qla24xx_handle_plogi_done_event(struct scsi_qla_host *vha, struct event_arg *ea) * force a relogin attempt via implicit LOGO, PLOGI, and PRLI * requests. */ - ql_dbg(ql_dbg_disc, vha, 0xffff, - "%s %d %8phC post gpdb\n", - __func__, __LINE__, ea->fcport->port_name); - ea->fcport->chip_reset = vha->hw->chip_reset; - ea->fcport->logout_on_delete = 1; - qla24xx_post_gpdb_work(vha, ea->fcport, 0); + if (ea->fcport->fc4f_nvme) { + ql_dbg(ql_dbg_disc, vha, 0x2117, + "%s %d %8phC post prli\n", + __func__, __LINE__, ea->fcport->port_name); + qla24xx_post_prli_work(vha, ea->fcport); + } else { + ql_dbg(ql_dbg_disc, vha, 0x20ea, + "%s %d %8phC post gpdb\n", + __func__, __LINE__, ea->fcport->port_name); + ea->fcport->chip_reset = vha->hw->base_qpair->chip_reset; + ea->fcport->logout_on_delete = 1; + qla24xx_post_gpdb_work(vha, ea->fcport, 0); + } break; case MBS_COMMAND_ERROR: - ql_dbg(ql_dbg_disc, vha, 0xffff, "%s %d %8phC cmd error %x\n", + ql_dbg(ql_dbg_disc, vha, 0x20eb, "%s %d %8phC cmd error %x\n", __func__, __LINE__, ea->fcport->port_name, ea->data[1]); ea->fcport->flags &= ~FCF_ASYNC_SENT; @@ -1330,10 +1487,10 @@ qla24xx_handle_plogi_done_event(struct scsi_qla_host *vha, struct event_arg *ea) cid.b.al_pa = ea->iop[1] & 0xff; cid.b.rsvd_1 = 0; - ql_dbg(ql_dbg_disc, vha, 0xffff, - "%s %d %8phC LoopID 0x%x in use post gnl\n", - __func__, __LINE__, ea->fcport->port_name, - ea->fcport->loop_id); + ql_dbg(ql_dbg_disc, vha, 0x20ec, + "%s %d %8phC LoopID 0x%x in use post gnl\n", + __func__, __LINE__, ea->fcport->port_name, + ea->fcport->loop_id); if (IS_SW_RESV_ADDR(cid)) { set_bit(ea->fcport->loop_id, vha->hw->loop_id_map); @@ -1344,11 +1501,11 @@ qla24xx_handle_plogi_done_event(struct scsi_qla_host *vha, struct event_arg *ea) qla24xx_post_gnl_work(vha, ea->fcport); break; case MBS_PORT_ID_USED: - ql_dbg(ql_dbg_disc, vha, 0xffff, - "%s %d %8phC NPortId %02x%02x%02x inuse post gidpn\n", - __func__, __LINE__, ea->fcport->port_name, - ea->fcport->d_id.b.domain, ea->fcport->d_id.b.area, - ea->fcport->d_id.b.al_pa); + ql_dbg(ql_dbg_disc, vha, 0x20ed, + "%s %d %8phC NPortId %02x%02x%02x inuse post gidpn\n", + __func__, __LINE__, ea->fcport->port_name, + ea->fcport->d_id.b.domain, ea->fcport->d_id.b.area, + ea->fcport->d_id.b.al_pa); qla2x00_clear_loop_id(ea->fcport); qla24xx_post_gidpn_work(vha, ea->fcport); @@ -2524,6 +2681,13 @@ cont_alloc: ha->chain_offset = dump_size; dump_size += mq_size + fce_size; + if (ha->exchoffld_buf) + dump_size += sizeof(struct qla2xxx_offld_chain) + + ha->exchoffld_size; + if (ha->exlogin_buf) + dump_size += sizeof(struct qla2xxx_offld_chain) + + ha->exlogin_size; + allocate: ha->fw_dump = vmalloc(dump_size); if (!ha->fw_dump) { @@ -2709,7 +2873,7 @@ qla2x00_setup_chip(scsi_qla_host_t *vha) if (ql2xexlogins) ha->flags.exlogins_enabled = 1; - if (ql2xexchoffld) + if (qla_is_exch_offld_enabled(vha)) ha->flags.exchoffld_enabled = 1; rval = qla2x00_execute_fw(vha, srisc_address); @@ -2946,7 +3110,8 @@ qla24xx_update_fw_options(scsi_qla_host_t *vha) } /* Move PUREX, ABTS RX & RIDA to ATIOQ */ - if (ql2xmvasynctoatio) { + if (ql2xmvasynctoatio && + (IS_QLA83XX(ha) || IS_QLA27XX(ha))) { if (qla_tgt_mode_enabled(vha) || qla_dual_mode_enabled(vha)) ha->fw_options[2] |= BIT_11; @@ -2954,11 +3119,25 @@ qla24xx_update_fw_options(scsi_qla_host_t *vha) ha->fw_options[2] &= ~BIT_11; } - ql_dbg(ql_dbg_init, vha, 0xffff, - "%s, add FW options 1-3 = 0x%04x 0x%04x 0x%04x mode %x\n", - __func__, ha->fw_options[1], ha->fw_options[2], - ha->fw_options[3], vha->host->active_mode); - qla2x00_set_fw_options(vha, ha->fw_options); + if (IS_QLA25XX(ha) || IS_QLA83XX(ha) || IS_QLA27XX(ha)) { + /* + * Tell FW to track each exchange to prevent + * driver from using stale exchange. + */ + if (qla_tgt_mode_enabled(vha) || + qla_dual_mode_enabled(vha)) + ha->fw_options[2] |= BIT_4; + else + ha->fw_options[2] &= ~BIT_4; + } + + ql_dbg(ql_dbg_init, vha, 0x00e8, + "%s, add FW options 1-3 = 0x%04x 0x%04x 0x%04x mode %x\n", + __func__, ha->fw_options[1], ha->fw_options[2], + ha->fw_options[3], vha->host->active_mode); + + if (ha->fw_options[1] || ha->fw_options[2] || ha->fw_options[3]) + qla2x00_set_fw_options(vha, ha->fw_options); /* Update Serial Link options. */ if ((le16_to_cpu(ha->fw_seriallink_options24[0]) & BIT_0) == 0) @@ -3036,7 +3215,7 @@ qla24xx_config_rings(struct scsi_qla_host *vha) icb->rid = cpu_to_le16(rid); if (ha->flags.msix_enabled) { msix = &ha->msix_entries[1]; - ql_dbg(ql_dbg_init, vha, 0x00fd, + ql_dbg(ql_dbg_init, vha, 0x0019, "Registering vector 0x%x for base que.\n", msix->entry); icb->msix = cpu_to_le16(msix->entry); @@ -3166,7 +3345,7 @@ qla2x00_init_rings(scsi_qla_host_t *vha) /* FA-WWPN Status */ ha->flags.fawwpn_enabled = (mid_init_cb->init_cb.firmware_options_1 & BIT_6) != 0; - ql_dbg(ql_dbg_init, vha, 0x0141, "FA-WWPN Support: %s.\n", + ql_dbg(ql_dbg_init, vha, 0x00bc, "FA-WWPN Support: %s.\n", (ha->flags.fawwpn_enabled) ? "enabled" : "disabled"); } @@ -3178,7 +3357,7 @@ next_check: } else { ql_dbg(ql_dbg_init, vha, 0x00d3, "Init Firmware -- success.\n"); - ha->flags.fw_started = 1; + QLA_FW_STARTED(ha); } return (rval); @@ -3840,10 +4019,10 @@ qla2x00_rport_del(void *data) fcport->drport = NULL; spin_unlock_irqrestore(fcport->vha->host->host_lock, flags); if (rport) { - ql_dbg(ql_dbg_disc, fcport->vha, 0xffff, - "%s %8phN. rport %p roles %x \n", - __func__, fcport->port_name, rport, - rport->roles); + ql_dbg(ql_dbg_disc, fcport->vha, 0x210b, + "%s %8phN. rport %p roles %x\n", + __func__, fcport->port_name, rport, + rport->roles); fc_remote_port_delete(rport); } @@ -3883,7 +4062,7 @@ qla2x00_alloc_fcport(scsi_qla_host_t *vha, gfp_t flags) fcport->logout_on_delete = 1; if (!fcport->ct_desc.ct_sns) { - ql_log(ql_log_warn, vha, 0xffff, + ql_log(ql_log_warn, vha, 0xd049, "Failed to allocate ct_sns request.\n"); kfree(fcport); fcport = NULL; @@ -3985,7 +4164,7 @@ qla2x00_configure_loop(scsi_qla_host_t *vha) if (rval == QLA_SUCCESS && test_bit(RSCN_UPDATE, &flags)) { if (LOOP_TRANSITION(vha)) { - ql_dbg(ql_dbg_disc, vha, 0x201e, + ql_dbg(ql_dbg_disc, vha, 0x2099, "Needs RSCN update and loop transition.\n"); rval = QLA_FUNCTION_FAILED; } @@ -4085,7 +4264,7 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha) if (rval != QLA_SUCCESS) goto cleanup_allocation; - ql_dbg(ql_dbg_disc, vha, 0x2017, + ql_dbg(ql_dbg_disc, vha, 0x2011, "Entries in ID list (%d).\n", entries); ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x2075, (uint8_t *)ha->gid_list, @@ -4094,7 +4273,7 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha) /* Allocate temporary fcport for any new fcports discovered. */ new_fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL); if (new_fcport == NULL) { - ql_log(ql_log_warn, vha, 0x2018, + ql_log(ql_log_warn, vha, 0x2012, "Memory allocation failed for fcport.\n"); rval = QLA_MEMORY_ALLOC_FAILED; goto cleanup_allocation; @@ -4109,7 +4288,7 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha) fcport->port_type != FCT_BROADCAST && (fcport->flags & FCF_FABRIC_DEVICE) == 0) { - ql_dbg(ql_dbg_disc, vha, 0x2019, + ql_dbg(ql_dbg_disc, vha, 0x2096, "Marking port lost loop_id=0x%04x.\n", fcport->loop_id); @@ -4154,11 +4333,11 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha) rval2 = qla2x00_get_port_database(vha, new_fcport, 0); if (rval2 != QLA_SUCCESS) { - ql_dbg(ql_dbg_disc, vha, 0x201a, + ql_dbg(ql_dbg_disc, vha, 0x2097, "Failed to retrieve fcport information " "-- get_port_database=%x, loop_id=0x%04x.\n", rval2, new_fcport->loop_id); - ql_dbg(ql_dbg_disc, vha, 0x201b, + ql_dbg(ql_dbg_disc, vha, 0x2105, "Scheduling resync.\n"); set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); continue; @@ -4207,7 +4386,7 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha) new_fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL); if (new_fcport == NULL) { - ql_log(ql_log_warn, vha, 0x201c, + ql_log(ql_log_warn, vha, 0xd031, "Failed to allocate memory for fcport.\n"); rval = QLA_MEMORY_ALLOC_FAILED; goto cleanup_allocation; @@ -4230,7 +4409,7 @@ cleanup_allocation: kfree(new_fcport); if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_disc, vha, 0x201d, + ql_dbg(ql_dbg_disc, vha, 0x2098, "Configure local loop error exit: rval=%x.\n", rval); } @@ -4300,10 +4479,10 @@ qla2x00_reg_remote_port(scsi_qla_host_t *vha, fc_port_t *fcport) if (fcport->port_type == FCT_TARGET) rport_ids.roles |= FC_RPORT_ROLE_FCP_TARGET; - ql_dbg(ql_dbg_disc, vha, 0xffff, - "%s %8phN. rport %p is %s mode \n", - __func__, fcport->port_name, rport, - (fcport->port_type == FCT_TARGET) ? "tgt" : "ini"); + ql_dbg(ql_dbg_disc, vha, 0x20ee, + "%s %8phN. rport %p is %s mode\n", + __func__, fcport->port_name, rport, + (fcport->port_type == FCT_TARGET) ? "tgt" : "ini"); fc_remote_port_rolechg(rport, rport_ids.roles); } @@ -4331,7 +4510,7 @@ qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport) if (IS_SW_RESV_ADDR(fcport->d_id)) return; - ql_dbg(ql_dbg_disc, vha, 0xffff, "%s %8phC \n", + ql_dbg(ql_dbg_disc, vha, 0x20ef, "%s %8phC\n", __func__, fcport->port_name); if (IS_QLAFX00(vha->hw)) { @@ -4344,6 +4523,11 @@ qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport) fcport->deleted = 0; fcport->logout_on_delete = 1; + if (fcport->fc4f_nvme) { + qla_nvme_register_remote(vha, fcport); + return; + } + qla2x00_set_fcport_state(fcport, FCS_ONLINE); qla2x00_iidma_fcport(vha, fcport); qla24xx_update_fcport_fcp_prio(vha, fcport); @@ -4398,7 +4582,7 @@ qla2x00_configure_fabric(scsi_qla_host_t *vha) loop_id = SNS_FL_PORT; rval = qla2x00_get_port_name(vha, loop_id, vha->fabric_node_name, 1); if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_disc, vha, 0x201f, + ql_dbg(ql_dbg_disc, vha, 0x20a0, "MBX_GET_PORT_NAME failed, No FL Port.\n"); vha->device_flags &= ~SWITCH_FOUND; @@ -4436,7 +4620,7 @@ qla2x00_configure_fabric(scsi_qla_host_t *vha) return rval; } if (mb[0] != MBS_COMMAND_COMPLETE) { - ql_dbg(ql_dbg_disc, vha, 0x2042, + ql_dbg(ql_dbg_disc, vha, 0x20a1, "Failed SNS login: loop_id=%x mb[0]=%x mb[1]=%x mb[2]=%x " "mb[6]=%x mb[7]=%x.\n", loop_id, mb[0], mb[1], mb[2], mb[6], mb[7]); @@ -4446,22 +4630,39 @@ qla2x00_configure_fabric(scsi_qla_host_t *vha) if (test_and_clear_bit(REGISTER_FC4_NEEDED, &vha->dpc_flags)) { if (qla2x00_rft_id(vha)) { /* EMPTY */ - ql_dbg(ql_dbg_disc, vha, 0x2045, + ql_dbg(ql_dbg_disc, vha, 0x20a2, "Register FC-4 TYPE failed.\n"); + if (test_bit(LOOP_RESYNC_NEEDED, + &vha->dpc_flags)) + break; } - if (qla2x00_rff_id(vha)) { + if (qla2x00_rff_id(vha, FC4_TYPE_FCP_SCSI)) { /* EMPTY */ - ql_dbg(ql_dbg_disc, vha, 0x2049, + ql_dbg(ql_dbg_disc, vha, 0x209a, "Register FC-4 Features failed.\n"); + if (test_bit(LOOP_RESYNC_NEEDED, + &vha->dpc_flags)) + break; + } + if (vha->flags.nvme_enabled) { + if (qla2x00_rff_id(vha, FC_TYPE_NVME)) { + ql_dbg(ql_dbg_disc, vha, 0x2049, + "Register NVME FC Type Features failed.\n"); + } } if (qla2x00_rnn_id(vha)) { /* EMPTY */ - ql_dbg(ql_dbg_disc, vha, 0x204f, + ql_dbg(ql_dbg_disc, vha, 0x2104, "Register Node Name failed.\n"); + if (test_bit(LOOP_RESYNC_NEEDED, + &vha->dpc_flags)) + break; } else if (qla2x00_rsnn_nn(vha)) { /* EMPTY */ - ql_dbg(ql_dbg_disc, vha, 0x2053, - "Register Symobilic Node Name failed.\n"); + ql_dbg(ql_dbg_disc, vha, 0x209b, + "Register Symbolic Node Name failed.\n"); + if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) + break; } } @@ -4482,6 +4683,9 @@ qla2x00_configure_fabric(scsi_qla_host_t *vha) break; } while (0); + if (!vha->nvme_local_port && vha->flags.nvme_enabled) + qla_nvme_register_hba(vha); + if (rval) ql_dbg(ql_dbg_disc, vha, 0x2068, "Configure fabric error exit rval=%d.\n", rval); @@ -4527,30 +4731,41 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha) swl = ha->swl; if (!swl) { /*EMPTY*/ - ql_dbg(ql_dbg_disc, vha, 0x2054, + ql_dbg(ql_dbg_disc, vha, 0x209c, "GID_PT allocations failed, fallback on GA_NXT.\n"); } else { memset(swl, 0, ha->max_fibre_devices * sizeof(sw_info_t)); if (qla2x00_gid_pt(vha, swl) != QLA_SUCCESS) { swl = NULL; + if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) + return rval; } else if (qla2x00_gpn_id(vha, swl) != QLA_SUCCESS) { swl = NULL; + if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) + return rval; } else if (qla2x00_gnn_id(vha, swl) != QLA_SUCCESS) { swl = NULL; + if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) + return rval; } else if (qla2x00_gfpn_id(vha, swl) != QLA_SUCCESS) { swl = NULL; + if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) + return rval; } /* If other queries succeeded probe for FC-4 type */ - if (swl) + if (swl) { qla2x00_gff_id(vha, swl); + if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) + return rval; + } } swl_idx = 0; /* Allocate temporary fcport for any new fcports discovered. */ new_fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL); if (new_fcport == NULL) { - ql_log(ql_log_warn, vha, 0x205e, + ql_log(ql_log_warn, vha, 0x209d, "Failed to allocate memory for fcport.\n"); return (QLA_MEMORY_ALLOC_FAILED); } @@ -4588,6 +4803,16 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha) new_fcport->fp_speed = swl[swl_idx].fp_speed; new_fcport->fc4_type = swl[swl_idx].fc4_type; + new_fcport->nvme_flag = 0; + if (vha->flags.nvme_enabled && + swl[swl_idx].fc4f_nvme) { + new_fcport->fc4f_nvme = + swl[swl_idx].fc4f_nvme; + ql_log(ql_log_info, vha, 0x2131, + "FOUND: NVME port %8phC as FC Type 28h\n", + new_fcport->port_name); + } + if (swl[swl_idx].d_id.b.rsvd_1 != 0) { last_dev = 1; } @@ -4597,7 +4822,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha) /* Send GA_NXT to the switch */ rval = qla2x00_ga_nxt(vha, new_fcport); if (rval != QLA_SUCCESS) { - ql_log(ql_log_warn, vha, 0x2064, + ql_log(ql_log_warn, vha, 0x209e, "SNS scan failed -- assuming " "zero-entry result.\n"); rval = QLA_SUCCESS; @@ -4610,7 +4835,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha) wrap.b24 = new_fcport->d_id.b24; first_dev = 0; } else if (new_fcport->d_id.b24 == wrap.b24) { - ql_dbg(ql_dbg_disc, vha, 0x2065, + ql_dbg(ql_dbg_disc, vha, 0x209f, "Device wrap (%02x%02x%02x).\n", new_fcport->d_id.b.domain, new_fcport->d_id.b.area, @@ -4722,7 +4947,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha) nxt_d_id.b24 = new_fcport->d_id.b24; new_fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL); if (new_fcport == NULL) { - ql_log(ql_log_warn, vha, 0x2066, + ql_log(ql_log_warn, vha, 0xd032, "Memory allocation failed for fcport.\n"); return (QLA_MEMORY_ALLOC_FAILED); } @@ -4753,7 +4978,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha) (fcport->flags & FCF_FCP2_DEVICE) == 0 && fcport->port_type != FCT_INITIATOR && fcport->port_type != FCT_BROADCAST) { - ql_dbg(ql_dbg_disc, vha, 0xffff, + ql_dbg(ql_dbg_disc, vha, 0x20f0, "%s %d %8phC post del sess\n", __func__, __LINE__, fcport->port_name); @@ -5473,6 +5698,7 @@ qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha) struct scsi_qla_host *vp; unsigned long flags; fc_port_t *fcport; + u16 i; /* For ISP82XX, driver waits for completion of the commands. * online flag should be set. @@ -5498,7 +5724,12 @@ qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha) ha->current_topology = 0; ha->flags.fw_started = 0; ha->flags.fw_init_done = 0; - ha->chip_reset++; + ha->base_qpair->chip_reset++; + for (i = 0; i < ha->max_qpairs; i++) { + if (ha->queue_pair_map[i]) + ha->queue_pair_map[i]->chip_reset = + ha->base_qpair->chip_reset; + } atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME); if (atomic_read(&vha->loop_state) != LOOP_DOWN) { @@ -6353,8 +6584,8 @@ qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr, "-> template size %x bytes\n", dlen); if (dlen > risc_size * sizeof(*dcode)) { ql_log(ql_log_warn, vha, 0x0167, - "Failed fwdump template exceeds array by %x bytes\n", - (uint32_t)(dlen - risc_size * sizeof(*dcode))); + "Failed fwdump template exceeds array by %zx bytes\n", + (size_t)(dlen - risc_size * sizeof(*dcode))); goto default_template; } ha->fw_dump_template_len = dlen; @@ -6655,8 +6886,8 @@ qla24xx_load_risc_blob(scsi_qla_host_t *vha, uint32_t *srisc_addr) "-> template size %x bytes\n", dlen); if (dlen > risc_size * sizeof(*fwcode)) { ql_log(ql_log_warn, vha, 0x0177, - "Failed fwdump template exceeds array by %x bytes\n", - (uint32_t)(dlen - risc_size * sizeof(*fwcode))); + "Failed fwdump template exceeds array by %zx bytes\n", + (size_t)(dlen - risc_size * sizeof(*fwcode))); goto default_template; } ha->fw_dump_template_len = dlen; @@ -6790,7 +7021,7 @@ qla2x00_try_to_stop_firmware(scsi_qla_host_t *vha) ret = qla2x00_stop_firmware(vha); } - ha->flags.fw_started = 0; + QLA_FW_STOPPED(ha); ha->flags.fw_init_done = 0; } @@ -7322,16 +7553,31 @@ qla81xx_update_fw_options(scsi_qla_host_t *vha) ha->fw_options[2] &= ~BIT_11; } + if (qla_tgt_mode_enabled(vha) || + qla_dual_mode_enabled(vha)) { + /* FW auto send SCSI status during */ + ha->fw_options[1] |= BIT_8; + ha->fw_options[10] |= (u16)SAM_STAT_BUSY << 8; + + /* FW perform Exchange validation */ + ha->fw_options[2] |= BIT_4; + } else { + ha->fw_options[1] &= ~BIT_8; + ha->fw_options[10] &= 0x00ff; + + ha->fw_options[2] &= ~BIT_4; + } + if (ql2xetsenable) { /* Enable ETS Burst. */ memset(ha->fw_options, 0, sizeof(ha->fw_options)); ha->fw_options[2] |= BIT_9; } - ql_dbg(ql_dbg_init, vha, 0xffff, - "%s, add FW options 1-3 = 0x%04x 0x%04x 0x%04x mode %x\n", - __func__, ha->fw_options[1], ha->fw_options[2], - ha->fw_options[3], vha->host->active_mode); + ql_dbg(ql_dbg_init, vha, 0x00e9, + "%s, add FW options 1-3 = 0x%04x 0x%04x 0x%04x mode %x\n", + __func__, ha->fw_options[1], ha->fw_options[2], + ha->fw_options[3], vha->host->active_mode); qla2x00_set_fw_options(vha, ha->fw_options); } @@ -7512,7 +7758,8 @@ qla24xx_update_all_fcp_prio(scsi_qla_host_t *vha) return ret; } -struct qla_qpair *qla2xxx_create_qpair(struct scsi_qla_host *vha, int qos, int vp_idx) +struct qla_qpair *qla2xxx_create_qpair(struct scsi_qla_host *vha, int qos, + int vp_idx, bool startqp) { int rsp_id = 0; int req_id = 0; @@ -7539,6 +7786,9 @@ struct qla_qpair *qla2xxx_create_qpair(struct scsi_qla_host *vha, int qos, int v qpair->hw = vha->hw; qpair->vha = vha; + qpair->qp_lock_ptr = &qpair->qp_lock; + spin_lock_init(&qpair->qp_lock); + qpair->use_shadow_reg = IS_SHADOW_REG_CAPABLE(ha) ? 1 : 0; /* Assign available que pair id */ mutex_lock(&ha->mq_lock); @@ -7554,13 +7804,18 @@ struct qla_qpair *qla2xxx_create_qpair(struct scsi_qla_host *vha, int qos, int v ha->queue_pair_map[qpair_id] = qpair; qpair->id = qpair_id; qpair->vp_idx = vp_idx; + INIT_LIST_HEAD(&qpair->hints_list); + qpair->chip_reset = ha->base_qpair->chip_reset; + qpair->enable_class_2 = ha->base_qpair->enable_class_2; + qpair->enable_explicit_conf = + ha->base_qpair->enable_explicit_conf; for (i = 0; i < ha->msix_count; i++) { msix = &ha->msix_entries[i]; if (msix->in_use) continue; qpair->msix = msix; - ql_log(ql_dbg_multiq, vha, 0xc00f, + ql_dbg(ql_dbg_multiq, vha, 0xc00f, "Vector %x selected for qpair\n", msix->vector); break; } @@ -7572,11 +7827,14 @@ struct qla_qpair *qla2xxx_create_qpair(struct scsi_qla_host *vha, int qos, int v qpair->msix->in_use = 1; list_add_tail(&qpair->qp_list_elem, &vha->qp_list); + qpair->pdev = ha->pdev; + if (IS_QLA27XX(ha) || IS_QLA83XX(ha)) + qpair->reqq_start_iocbs = qla_83xx_start_iocbs; mutex_unlock(&ha->mq_lock); /* Create response queue first */ - rsp_id = qla25xx_create_rsp_que(ha, 0, 0, 0, qpair); + rsp_id = qla25xx_create_rsp_que(ha, 0, 0, 0, qpair, startqp); if (!rsp_id) { ql_log(ql_log_warn, vha, 0x0185, "Failed to create response queue.\n"); @@ -7586,7 +7844,8 @@ struct qla_qpair *qla2xxx_create_qpair(struct scsi_qla_host *vha, int qos, int v qpair->rsp = ha->rsp_q_map[rsp_id]; /* Create request queue */ - req_id = qla25xx_create_req_que(ha, 0, vp_idx, 0, rsp_id, qos); + req_id = qla25xx_create_req_que(ha, 0, vp_idx, 0, rsp_id, qos, + startqp); if (!req_id) { ql_log(ql_log_warn, vha, 0x0186, "Failed to create request queue.\n"); @@ -7595,6 +7854,9 @@ struct qla_qpair *qla2xxx_create_qpair(struct scsi_qla_host *vha, int qos, int v qpair->req = ha->req_q_map[req_id]; qpair->rsp->req = qpair->req; + qpair->rsp->qpair = qpair; + /* init qpair to this cpu. Will adjust at run time. */ + qla_cpu_update(qpair, smp_processor_id()); if (IS_T10_PI_CAPABLE(ha) && ql2xenabledif) { if (ha->fw_attributes & BIT_4) @@ -7603,7 +7865,7 @@ struct qla_qpair *qla2xxx_create_qpair(struct scsi_qla_host *vha, int qos, int v qpair->srb_mempool = mempool_create_slab_pool(SRB_MIN_REQ, srb_cachep); if (!qpair->srb_mempool) { - ql_log(ql_log_warn, vha, 0x0191, + ql_log(ql_log_warn, vha, 0xd036, "Failed to create srb mempool for qpair %d\n", qpair->id); goto fail_mempool; @@ -7645,9 +7907,12 @@ fail_qid_map: int qla2xxx_delete_qpair(struct scsi_qla_host *vha, struct qla_qpair *qpair) { - int ret; + int ret = QLA_FUNCTION_FAILED; struct qla_hw_data *ha = qpair->hw; + if (!vha->flags.qpairs_req_created && !vha->flags.qpairs_rsp_created) + goto fail; + qpair->delete_in_progress = 1; while (atomic_read(&qpair->ref_count)) msleep(500); @@ -7664,8 +7929,11 @@ int qla2xxx_delete_qpair(struct scsi_qla_host *vha, struct qla_qpair *qpair) clear_bit(qpair->id, ha->qpair_qid_map); ha->num_qpairs--; list_del(&qpair->qp_list_elem); - if (list_empty(&vha->qp_list)) + if (list_empty(&vha->qp_list)) { vha->flags.qpairs_available = 0; + vha->flags.qpairs_req_created = 0; + vha->flags.qpairs_rsp_created = 0; + } mempool_destroy(qpair->srb_mempool); kfree(qpair); mutex_unlock(&ha->mq_lock); diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h index c61a6a871c8e..9a2c86eacf44 100644 --- a/drivers/scsi/qla2xxx/qla_inline.h +++ b/drivers/scsi/qla2xxx/qla_inline.h @@ -250,6 +250,7 @@ qla2x00_get_sp(scsi_qla_host_t *vha, fc_port_t *fcport, gfp_t flag) memset(sp, 0, sizeof(*sp)); sp->fcport = fcport; + sp->cmd_type = TYPE_SRB; sp->iocbs = 1; sp->vha = vha; done: @@ -307,3 +308,62 @@ qla2x00_set_retry_delay_timestamp(fc_port_t *fcport, uint16_t retry_delay) fcport->retry_delay_timestamp = jiffies + (retry_delay * HZ / 10); } + +static inline bool +qla_is_exch_offld_enabled(struct scsi_qla_host *vha) +{ + if (qla_ini_mode_enabled(vha) && + (ql2xiniexchg > FW_DEF_EXCHANGES_CNT)) + return true; + else if (qla_tgt_mode_enabled(vha) && + (ql2xexchoffld > FW_DEF_EXCHANGES_CNT)) + return true; + else if (qla_dual_mode_enabled(vha) && + ((ql2xiniexchg + ql2xexchoffld) > FW_DEF_EXCHANGES_CNT)) + return true; + else + return false; +} + +static inline void +qla_cpu_update(struct qla_qpair *qpair, uint16_t cpuid) +{ + qpair->cpuid = cpuid; + + if (!list_empty(&qpair->hints_list)) { + struct qla_qpair_hint *h; + + list_for_each_entry(h, &qpair->hints_list, hint_elem) + h->cpuid = qpair->cpuid; + } +} + +static inline struct qla_qpair_hint * +qla_qpair_to_hint(struct qla_tgt *tgt, struct qla_qpair *qpair) +{ + struct qla_qpair_hint *h; + u16 i; + + for (i = 0; i < tgt->ha->max_qpairs + 1; i++) { + h = &tgt->qphints[i]; + if (h->qpair == qpair) + return h; + } + + return NULL; +} + +static inline void +qla_83xx_start_iocbs(struct qla_qpair *qpair) +{ + struct req_que *req = qpair->req; + + req->ring_index++; + if (req->ring_index == req->length) { + req->ring_index = 0; + req->ring_ptr = req->ring; + } else + req->ring_ptr++; + + WRT_REG_DWORD(req->req_q_in, req->ring_index); +} diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index ea027f6a7fd4..a36c485fae50 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -464,7 +464,9 @@ qla2x00_start_iocbs(struct scsi_qla_host *vha, struct req_que *req) req->ring_ptr++; /* Set chip new ring index. */ - if (ha->mqenable || IS_QLA83XX(ha) || IS_QLA27XX(ha)) { + if (ha->mqenable || IS_QLA27XX(ha)) { + WRT_REG_DWORD(req->req_q_in, req->ring_index); + } else if (IS_QLA83XX(ha)) { WRT_REG_DWORD(req->req_q_in, req->ring_index); RD_REG_DWORD_RELAXED(&ha->iobase->isp24.hccr); } else if (IS_QLAFX00(ha)) { @@ -1768,6 +1770,9 @@ qla2xxx_start_scsi_mq(srb_t *sp) struct qla_hw_data *ha = vha->hw; struct qla_qpair *qpair = sp->qpair; + /* Acquire qpair specific lock */ + spin_lock_irqsave(&qpair->qp_lock, flags); + /* Setup qpair pointers */ rsp = qpair->rsp; req = qpair->req; @@ -1777,15 +1782,14 @@ qla2xxx_start_scsi_mq(srb_t *sp) /* Send marker if required */ if (vha->marker_needed != 0) { - if (qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL) != - QLA_SUCCESS) + if (__qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL) != + QLA_SUCCESS) { + spin_unlock_irqrestore(&qpair->qp_lock, flags); return QLA_FUNCTION_FAILED; + } vha->marker_needed = 0; } - /* Acquire qpair specific lock */ - spin_lock_irqsave(&qpair->qp_lock, flags); - /* Check for room in outstanding command list. */ handle = req->current_outstanding_cmd; for (index = 1; index < req->num_outstanding_cmds; index++) { @@ -1940,6 +1944,8 @@ qla2xxx_dif_start_scsi_mq(srb_t *sp) return qla2xxx_start_scsi_mq(sp); } + spin_lock_irqsave(&qpair->qp_lock, flags); + /* Setup qpair pointers */ rsp = qpair->rsp; req = qpair->req; @@ -1949,15 +1955,14 @@ qla2xxx_dif_start_scsi_mq(srb_t *sp) /* Send marker if required */ if (vha->marker_needed != 0) { - if (qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL) != - QLA_SUCCESS) + if (__qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL) != + QLA_SUCCESS) { + spin_unlock_irqrestore(&qpair->qp_lock, flags); return QLA_FUNCTION_FAILED; + } vha->marker_needed = 0; } - /* Acquire ring specific lock */ - spin_lock_irqsave(&qpair->qp_lock, flags); - /* Check for room in outstanding command list. */ handle = req->current_outstanding_cmd; for (index = 1; index < req->num_outstanding_cmds; index++) { @@ -2107,20 +2112,13 @@ queuing_error: /* Generic Control-SRB manipulation functions. */ /* hardware_lock assumed to be held. */ -void * -qla2x00_alloc_iocbs_ready(scsi_qla_host_t *vha, srb_t *sp) -{ - if (qla2x00_reset_active(vha)) - return NULL; - - return qla2x00_alloc_iocbs(vha, sp); -} void * -qla2x00_alloc_iocbs(scsi_qla_host_t *vha, srb_t *sp) +__qla2x00_alloc_iocbs(struct qla_qpair *qpair, srb_t *sp) { + scsi_qla_host_t *vha = qpair->vha; struct qla_hw_data *ha = vha->hw; - struct req_que *req = ha->req_q_map[0]; + struct req_que *req = qpair->req; device_reg_t *reg = ISP_QUE_REG(ha, req->id); uint32_t index, handle; request_t *pkt; @@ -2194,10 +2192,44 @@ skip_cmd_array: } queuing_error: - vha->tgt_counters.num_alloc_iocb_failed++; + qpair->tgt_counters.num_alloc_iocb_failed++; return pkt; } +void * +qla2x00_alloc_iocbs_ready(struct qla_qpair *qpair, srb_t *sp) +{ + scsi_qla_host_t *vha = qpair->vha; + + if (qla2x00_reset_active(vha)) + return NULL; + + return __qla2x00_alloc_iocbs(qpair, sp); +} + +void * +qla2x00_alloc_iocbs(struct scsi_qla_host *vha, srb_t *sp) +{ + return __qla2x00_alloc_iocbs(vha->hw->base_qpair, sp); +} + +static void +qla24xx_prli_iocb(srb_t *sp, struct logio_entry_24xx *logio) +{ + struct srb_iocb *lio = &sp->u.iocb_cmd; + + logio->entry_type = LOGINOUT_PORT_IOCB_TYPE; + logio->control_flags = cpu_to_le16(LCF_COMMAND_PRLI); + if (lio->u.logio.flags & SRB_LOGIN_NVME_PRLI) + logio->control_flags |= LCF_NVME_PRLI; + + logio->nport_handle = cpu_to_le16(sp->fcport->loop_id); + logio->port_id[0] = sp->fcport->d_id.b.al_pa; + logio->port_id[1] = sp->fcport->d_id.b.area; + logio->port_id[2] = sp->fcport->d_id.b.domain; + logio->vp_index = sp->vha->vp_idx; +} + static void qla24xx_login_iocb(srb_t *sp, struct logio_entry_24xx *logio) { @@ -2205,6 +2237,7 @@ qla24xx_login_iocb(srb_t *sp, struct logio_entry_24xx *logio) logio->entry_type = LOGINOUT_PORT_IOCB_TYPE; logio->control_flags = cpu_to_le16(LCF_COMMAND_PLOGI); + if (lio->u.logio.flags & SRB_LOGIN_COND_PLOGI) logio->control_flags |= cpu_to_le16(LCF_COND_PLOGI); if (lio->u.logio.flags & SRB_LOGIN_SKIP_PRLI) @@ -3125,6 +3158,39 @@ static void qla2x00_send_notify_ack_iocb(srb_t *sp, nack->u.isp24.vp_index = ntfy->u.isp24.vp_index; } +/* + * Build NVME LS request + */ +static int +qla_nvme_ls(srb_t *sp, struct pt_ls4_request *cmd_pkt) +{ + struct srb_iocb *nvme; + int rval = QLA_SUCCESS; + + nvme = &sp->u.iocb_cmd; + cmd_pkt->entry_type = PT_LS4_REQUEST; + cmd_pkt->entry_count = 1; + cmd_pkt->control_flags = CF_LS4_ORIGINATOR << CF_LS4_SHIFT; + + cmd_pkt->timeout = cpu_to_le16(nvme->u.nvme.timeout_sec); + cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id); + cmd_pkt->vp_index = sp->fcport->vha->vp_idx; + + cmd_pkt->tx_dseg_count = 1; + cmd_pkt->tx_byte_count = nvme->u.nvme.cmd_len; + cmd_pkt->dseg0_len = nvme->u.nvme.cmd_len; + cmd_pkt->dseg0_address[0] = cpu_to_le32(LSD(nvme->u.nvme.cmd_dma)); + cmd_pkt->dseg0_address[1] = cpu_to_le32(MSD(nvme->u.nvme.cmd_dma)); + + cmd_pkt->rx_dseg_count = 1; + cmd_pkt->rx_byte_count = nvme->u.nvme.rsp_len; + cmd_pkt->dseg1_len = nvme->u.nvme.rsp_len; + cmd_pkt->dseg1_address[0] = cpu_to_le32(LSD(nvme->u.nvme.rsp_dma)); + cmd_pkt->dseg1_address[1] = cpu_to_le32(MSD(nvme->u.nvme.rsp_dma)); + + return rval; +} + int qla2x00_start_sp(srb_t *sp) { @@ -3150,6 +3216,9 @@ qla2x00_start_sp(srb_t *sp) qla24xx_login_iocb(sp, pkt) : qla2x00_login_iocb(sp, pkt); break; + case SRB_PRLI_CMD: + qla24xx_prli_iocb(sp, pkt); + break; case SRB_LOGOUT_CMD: IS_FWI2_CAPABLE(ha) ? qla24xx_logout_iocb(sp, pkt) : @@ -3178,6 +3247,9 @@ qla2x00_start_sp(srb_t *sp) case SRB_FXIOCB_BCMD: qlafx00_fxdisc_iocb(sp, pkt); break; + case SRB_NVME_LS: + qla_nvme_ls(sp, pkt); + break; case SRB_ABT_CMD: IS_QLAFX00(ha) ? qlafx00_abort_iocb(sp, pkt) : diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 2572121b765b..6c6e624a5aa6 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -9,6 +9,7 @@ #include <linux/delay.h> #include <linux/slab.h> +#include <linux/cpu.h> #include <linux/t10-pi.h> #include <scsi/scsi_tcq.h> #include <scsi/scsi_bsg_fc.h> @@ -17,7 +18,7 @@ static void qla2x00_mbx_completion(scsi_qla_host_t *, uint16_t); static void qla2x00_status_entry(scsi_qla_host_t *, struct rsp_que *, void *); static void qla2x00_status_cont_entry(struct rsp_que *, sts_cont_entry_t *); -static void qla2x00_error_entry(scsi_qla_host_t *, struct rsp_que *, +static int qla2x00_error_entry(scsi_qla_host_t *, struct rsp_que *, sts_entry_t *); /** @@ -431,8 +432,7 @@ qla83xx_handle_8200_aen(scsi_qla_host_t *vha, uint16_t *mb) "Register: 0x%x%x.\n", mb[7], mb[3]); if (err_level == ERR_LEVEL_NON_FATAL) { ql_log(ql_log_warn, vha, 0x5063, - "Not a fatal error, f/w has recovered " - "iteself.\n"); + "Not a fatal error, f/w has recovered itself.\n"); } else if (err_level == ERR_LEVEL_RECOVERABLE_FATAL) { ql_log(ql_log_fatal, vha, 0x5064, "Recoverable Fatal error: Chip reset " @@ -709,7 +709,7 @@ skip_rio: ha->isp_ops->fw_dump(vha, 1); ha->flags.fw_init_done = 0; - ha->flags.fw_started = 0; + QLA_FW_STOPPED(ha); if (IS_FWI2_CAPABLE(ha)) { if (mb[1] == 0 && mb[2] == 0) { @@ -829,7 +829,7 @@ skip_rio: fc_host_port_name(vha->host) = wwn_to_u64(vha->port_name); ql_dbg(ql_dbg_init + ql_dbg_verbose, - vha, 0x0144, "LOOP DOWN detected," + vha, 0x00d8, "LOOP DOWN detected," "restore WWPN %016llx\n", wwn_to_u64(vha->port_name)); } @@ -973,6 +973,23 @@ skip_rio: if (mb[1] == 0xffff) goto global_port_update; + if (mb[1] == NPH_SNS_LID(ha)) { + set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); + set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); + break; + } + + /* use handle_cnt for loop id/nport handle */ + if (IS_FWI2_CAPABLE(ha)) + handle_cnt = NPH_SNS; + else + handle_cnt = SIMPLE_NAME_SERVER; + if (mb[1] == handle_cnt) { + set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); + set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); + break; + } + /* Port logout */ fcport = qla2x00_find_fcport_by_loopid(vha, mb[1]); if (!fcport) @@ -1701,7 +1718,7 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req, case LSC_SCODE_NOXCB: vha->hw->exch_starvation++; if (vha->hw->exch_starvation > 5) { - ql_log(ql_log_warn, vha, 0xffff, + ql_log(ql_log_warn, vha, 0xd046, "Exchange starvation. Resetting RISC\n"); vha->hw->exch_starvation = 0; @@ -1781,6 +1798,79 @@ qla24xx_tm_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, void *tsk) sp->done(sp, 0); } +static void +qla24xx_nvme_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, void *tsk) +{ + const char func[] = "NVME-IOCB"; + fc_port_t *fcport; + srb_t *sp; + struct srb_iocb *iocb; + struct sts_entry_24xx *sts = (struct sts_entry_24xx *)tsk; + uint16_t state_flags; + struct nvmefc_fcp_req *fd; + uint16_t ret = 0; + struct srb_iocb *nvme; + + sp = qla2x00_get_sp_from_handle(vha, func, req, tsk); + if (!sp) + return; + + iocb = &sp->u.iocb_cmd; + fcport = sp->fcport; + iocb->u.nvme.comp_status = le16_to_cpu(sts->comp_status); + state_flags = le16_to_cpu(sts->state_flags); + fd = iocb->u.nvme.desc; + nvme = &sp->u.iocb_cmd; + + if (unlikely(nvme->u.nvme.aen_op)) + atomic_dec(&sp->vha->nvme_active_aen_cnt); + + /* + * State flags: Bit 6 and 0. + * If 0 is set, we don't care about 6. + * both cases resp was dma'd to host buffer + * if both are 0, that is good path case. + * if six is set and 0 is clear, we need to + * copy resp data from status iocb to resp buffer. + */ + if (!(state_flags & (SF_FCP_RSP_DMA | SF_NVME_ERSP))) { + iocb->u.nvme.rsp_pyld_len = 0; + } else if ((state_flags & SF_FCP_RSP_DMA)) { + iocb->u.nvme.rsp_pyld_len = le16_to_cpu(sts->nvme_rsp_pyld_len); + } else if (state_flags & SF_NVME_ERSP) { + uint32_t *inbuf, *outbuf; + uint16_t iter; + + inbuf = (uint32_t *)&sts->nvme_ersp_data; + outbuf = (uint32_t *)fd->rspaddr; + iocb->u.nvme.rsp_pyld_len = le16_to_cpu(sts->nvme_rsp_pyld_len); + iter = iocb->u.nvme.rsp_pyld_len >> 2; + for (; iter; iter--) + *outbuf++ = swab32(*inbuf++); + } else { /* unhandled case */ + ql_log(ql_log_warn, fcport->vha, 0x503a, + "NVME-%s error. Unhandled state_flags of %x\n", + sp->name, state_flags); + } + + fd->transferred_length = fd->payload_length - + le32_to_cpu(sts->residual_len); + + if (sts->entry_status) { + ql_log(ql_log_warn, fcport->vha, 0x5038, + "NVME-%s error - hdl=%x entry-status(%x).\n", + sp->name, sp->handle, sts->entry_status); + ret = QLA_FUNCTION_FAILED; + } else if (sts->comp_status != cpu_to_le16(CS_COMPLETE)) { + ql_log(ql_log_warn, fcport->vha, 0x5039, + "NVME-%s error - hdl=%x completion status(%x) resid=%x ox_id=%x\n", + sp->name, sp->handle, sts->comp_status, + le32_to_cpu(sts->residual_len), sts->ox_id); + ret = QLA_FUNCTION_FAILED; + } + sp->done(sp, ret); +} + /** * qla2x00_process_response_queue() - Process response queue entries. * @ha: SCSI driver HA context @@ -2263,6 +2353,20 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) return; } + if (sp->cmd_type != TYPE_SRB) { + req->outstanding_cmds[handle] = NULL; + ql_dbg(ql_dbg_io, vha, 0x3015, + "Unknown sp->cmd_type %x %p).\n", + sp->cmd_type, sp); + return; + } + + /* NVME completion. */ + if (sp->type == SRB_NVME_CMD) { + qla24xx_nvme_iocb_entry(vha, req, pkt); + return; + } + if (unlikely((state_flags & BIT_1) && (sp->type == SRB_BIDI_CMD))) { qla25xx_process_bidir_status_iocb(vha, pkt, req, handle); return; @@ -2374,8 +2478,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) ((unsigned)(scsi_bufflen(cp) - resid) < cp->underflow)) { ql_dbg(ql_dbg_io, fcport->vha, 0x301a, - "Mid-layer underflow " - "detected (0x%x of 0x%x bytes).\n", + "Mid-layer underflow detected (0x%x of 0x%x bytes).\n", resid, scsi_bufflen(cp)); res = DID_ERROR << 16; @@ -2408,8 +2511,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) if (scsi_status & SS_RESIDUAL_UNDER) { if (IS_FWI2_CAPABLE(ha) && fw_resid_len != resid_len) { ql_dbg(ql_dbg_io, fcport->vha, 0x301d, - "Dropped frame(s) detected " - "(0x%x of 0x%x bytes).\n", + "Dropped frame(s) detected (0x%x of 0x%x bytes).\n", resid, scsi_bufflen(cp)); res = DID_ERROR << 16 | lscsi_status; @@ -2420,8 +2522,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) ((unsigned)(scsi_bufflen(cp) - resid) < cp->underflow)) { ql_dbg(ql_dbg_io, fcport->vha, 0x301e, - "Mid-layer underflow " - "detected (0x%x of 0x%x bytes).\n", + "Mid-layer underflow detected (0x%x of 0x%x bytes).\n", resid, scsi_bufflen(cp)); res = DID_ERROR << 16; @@ -2435,9 +2536,8 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) */ ql_dbg(ql_dbg_io, fcport->vha, 0x301f, - "Dropped frame(s) detected (0x%x " - "of 0x%x bytes).\n", resid, - scsi_bufflen(cp)); + "Dropped frame(s) detected (0x%x of 0x%x bytes).\n", + resid, scsi_bufflen(cp)); res = DID_ERROR << 16 | lscsi_status; goto check_scsi_status; @@ -2619,8 +2719,9 @@ qla2x00_status_cont_entry(struct rsp_que *rsp, sts_cont_entry_t *pkt) * qla2x00_error_entry() - Process an error entry. * @ha: SCSI driver HA context * @pkt: Entry pointer + * return : 1=allow further error analysis. 0=no additional error analysis. */ -static void +static int qla2x00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, sts_entry_t *pkt) { srb_t *sp; @@ -2631,7 +2732,8 @@ qla2x00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, sts_entry_t *pkt) int res = DID_ERROR << 16; ql_dbg(ql_dbg_async, vha, 0x502a, - "type of error status in response: 0x%x\n", pkt->entry_status); + "iocb type %xh with error status %xh, handle %xh, rspq id %d\n", + pkt->entry_type, pkt->entry_status, pkt->handle, rsp->id); if (que >= ha->max_req_queues || !ha->req_q_map[que]) goto fatal; @@ -2641,18 +2743,35 @@ qla2x00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, sts_entry_t *pkt) if (pkt->entry_status & RF_BUSY) res = DID_BUS_BUSY << 16; - if (pkt->entry_type == NOTIFY_ACK_TYPE && - pkt->handle == QLA_TGT_SKIP_HANDLE) - return; + if ((pkt->handle & ~QLA_TGT_HANDLE_MASK) == QLA_TGT_SKIP_HANDLE) + return 0; - sp = qla2x00_get_sp_from_handle(vha, func, req, pkt); - if (sp) { - sp->done(sp, res); - return; + switch (pkt->entry_type) { + case NOTIFY_ACK_TYPE: + case STATUS_TYPE: + case STATUS_CONT_TYPE: + case LOGINOUT_PORT_IOCB_TYPE: + case CT_IOCB_TYPE: + case ELS_IOCB_TYPE: + case ABORT_IOCB_TYPE: + case MBX_IOCB_TYPE: + sp = qla2x00_get_sp_from_handle(vha, func, req, pkt); + if (sp) { + sp->done(sp, res); + return 0; + } + break; + + case ABTS_RESP_24XX: + case CTIO_TYPE7: + case CTIO_CRC2: + default: + return 1; } fatal: ql_log(ql_log_warn, vha, 0x5030, "Error entry - invalid handle/queue (%04x).\n", que); + return 0; } /** @@ -2708,6 +2827,21 @@ qla24xx_abort_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, sp->done(sp, 0); } +void qla24xx_nvme_ls4_iocb(scsi_qla_host_t *vha, struct pt_ls4_request *pkt, + struct req_que *req) +{ + srb_t *sp; + const char func[] = "LS4_IOCB"; + uint16_t comp_status; + + sp = qla2x00_get_sp_from_handle(vha, func, req, pkt); + if (!sp) + return; + + comp_status = le16_to_cpu(pkt->status); + sp->done(sp, comp_status); +} + /** * qla24xx_process_response_queue() - Process response queue entries. * @ha: SCSI driver HA context @@ -2721,6 +2855,9 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha, if (!ha->flags.fw_started) return; + if (rsp->qpair->cpuid != smp_processor_id()) + qla_cpu_update(rsp->qpair, smp_processor_id()); + while (rsp->ring_ptr->signature != RESPONSE_PROCESSED) { pkt = (struct sts_entry_24xx *)rsp->ring_ptr; @@ -2733,9 +2870,7 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha, } if (pkt->entry_status != 0) { - qla2x00_error_entry(vha, rsp, (sts_entry_t *) pkt); - - if (qlt_24xx_process_response_error(vha, pkt)) + if (qla2x00_error_entry(vha, rsp, (sts_entry_t *) pkt)) goto process_err; ((response_t *)pkt)->signature = RESPONSE_PROCESSED; @@ -2768,7 +2903,8 @@ process_err: case ABTS_RECV_24XX: if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) { /* ensure that the ATIO queue is empty */ - qlt_handle_abts_recv(vha, (response_t *)pkt); + qlt_handle_abts_recv(vha, rsp, + (response_t *)pkt); break; } else { /* drop through */ @@ -2777,11 +2913,16 @@ process_err: case ABTS_RESP_24XX: case CTIO_TYPE7: case CTIO_CRC2: - qlt_response_pkt_all_vps(vha, (response_t *)pkt); + qlt_response_pkt_all_vps(vha, rsp, (response_t *)pkt); + break; + case PT_LS4_REQUEST: + qla24xx_nvme_ls4_iocb(vha, (struct pt_ls4_request *)pkt, + rsp->req); break; case NOTIFY_ACK_TYPE: if (pkt->handle == QLA_TGT_SKIP_HANDLE) - qlt_response_pkt_all_vps(vha, (response_t *)pkt); + qlt_response_pkt_all_vps(vha, rsp, + (response_t *)pkt); else qla24xxx_nack_iocb_entry(vha, rsp->req, (struct nack_to_isp *)pkt); @@ -3156,10 +3297,10 @@ struct qla_init_msix_entry { }; 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 }, + { "default", qla24xx_msix_default }, + { "rsp_q", qla24xx_msix_rsp_q }, + { "atio_q", qla83xx_msix_atio_q }, + { "qpair_multiq", qla2xxx_msix_rsp_q }, }; static const struct qla_init_msix_entry qla82xx_msix_entries[] = { @@ -3183,9 +3324,14 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp) min_vecs++; } - ret = pci_alloc_irq_vectors_affinity(ha->pdev, min_vecs, - ha->msix_count, PCI_IRQ_MSIX | PCI_IRQ_AFFINITY, - &desc); + if (USER_CTRL_IRQ(ha)) { + /* user wants to control IRQ setting for target mode */ + ret = pci_alloc_irq_vectors(ha->pdev, min_vecs, + ha->msix_count, PCI_IRQ_MSIX); + } else + ret = pci_alloc_irq_vectors_affinity(ha->pdev, min_vecs, + ha->msix_count, PCI_IRQ_MSIX | PCI_IRQ_AFFINITY, + &desc); if (ret < 0) { ql_log(ql_log_fatal, vha, 0x00c7, @@ -3239,7 +3385,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), - "%s", msix_entries[i].name); + "qla2xxx%lu_%s", vha->host_no, msix_entries[i].name); if (IS_P3P_TYPE(ha)) ret = request_irq(qentry->vector, qla82xx_msix_entries[i].handler, @@ -3247,7 +3393,7 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp) else ret = request_irq(qentry->vector, msix_entries[i].handler, - 0, msix_entries[i].name, rsp); + 0, qentry->name, rsp); if (ret) goto msix_register_fail; qentry->have_irq = 1; @@ -3263,11 +3409,12 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp) rsp->msix = qentry; qentry->handle = rsp; scnprintf(qentry->name, sizeof(qentry->name), - "%s", msix_entries[QLA_ATIO_VECTOR].name); + "qla2xxx%lu_%s", vha->host_no, + msix_entries[QLA_ATIO_VECTOR].name); qentry->in_use = 1; ret = request_irq(qentry->vector, msix_entries[QLA_ATIO_VECTOR].handler, - 0, msix_entries[QLA_ATIO_VECTOR].name, rsp); + 0, qentry->name, rsp); qentry->have_irq = 1; } diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index cba1fc5e8be9..7c6d1a404011 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -124,8 +124,9 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) } /* if PCI error, then avoid mbx processing.*/ - if (test_bit(PCI_ERR, &base_vha->dpc_flags)) { - ql_log(ql_log_warn, vha, 0x1191, + if (test_bit(PFLG_DISCONNECTED, &base_vha->dpc_flags) && + test_bit(UNLOADING, &base_vha->dpc_flags)) { + ql_log(ql_log_warn, vha, 0xd04e, "PCI error, exiting.\n"); return QLA_FUNCTION_TIMEOUT; } @@ -169,7 +170,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) */ if (!wait_for_completion_timeout(&ha->mbx_cmd_comp, mcp->tov * HZ)) { /* Timeout occurred. Return error. */ - ql_log(ql_log_warn, vha, 0x1005, + ql_log(ql_log_warn, vha, 0xd035, "Cmd access timeout, cmd=0x%x, Exiting.\n", mcp->mb[0]); return QLA_FUNCTION_TIMEOUT; @@ -317,7 +318,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) mcp->mb[0] = MBS_LINK_DOWN_ERROR; ha->mcp = NULL; rval = QLA_FUNCTION_FAILED; - ql_log(ql_log_warn, vha, 0x1015, + ql_log(ql_log_warn, vha, 0xd048, "FW hung = %d.\n", ha->flags.isp82xx_fw_hung); goto premature_exit; } @@ -359,7 +360,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) host_status = RD_REG_DWORD(®->isp24.host_status); hccr = RD_REG_DWORD(®->isp24.hccr); - ql_log(ql_log_warn, vha, 0x1119, + ql_log(ql_log_warn, vha, 0xd04c, "MBX Command timeout for cmd %x, iocontrol=%x jiffies=%lx " "mb[0-3]=[0x%x 0x%x 0x%x 0x%x] mb7 0x%x host_status 0x%x hccr 0x%x\n", command, ictrl, jiffies, mb[0], mb[1], mb[2], mb[3], @@ -384,8 +385,6 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) * then only PCI ERR flag would be set. * we will do premature exit for above case. */ - if (test_bit(UNLOADING, &base_vha->dpc_flags)) - set_bit(PCI_ERR, &base_vha->dpc_flags); ha->flags.mbox_busy = 0; rval = QLA_FUNCTION_TIMEOUT; goto premature_exit; @@ -561,6 +560,8 @@ qla2x00_load_ram(scsi_qla_host_t *vha, dma_addr_t req_dma, uint32_t risc_addr, } #define EXTENDED_BB_CREDITS BIT_0 +#define NVME_ENABLE_FLAG BIT_3 + /* * qla2x00_execute_fw * Start adapter firmware. @@ -602,6 +603,9 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr) } else mcp->mb[4] = 0; + if (ql2xnvmeenable && IS_QLA27XX(ha)) + mcp->mb[4] |= NVME_ENABLE_FLAG; + if (ha->flags.exlogins_enabled) mcp->mb[4] |= ENABLE_EXTENDED_LOGIN; @@ -822,7 +826,7 @@ qla_get_exchoffld_status(scsi_qla_host_t *vha, uint16_t *buf_sz, */ #define CONFIG_XCHOFFLD_MEM 0x3 int -qla_set_exchoffld_mem_cfg(scsi_qla_host_t *vha, dma_addr_t phys_addr) +qla_set_exchoffld_mem_cfg(scsi_qla_host_t *vha) { int rval; mbx_cmd_t mc; @@ -835,12 +839,12 @@ qla_set_exchoffld_mem_cfg(scsi_qla_host_t *vha, dma_addr_t phys_addr) memset(mcp->mb, 0 , sizeof(mcp->mb)); mcp->mb[0] = MBC_GET_MEM_OFFLOAD_CNTRL_STAT; mcp->mb[1] = CONFIG_XCHOFFLD_MEM; - mcp->mb[2] = MSW(phys_addr); - mcp->mb[3] = LSW(phys_addr); - mcp->mb[6] = MSW(MSD(phys_addr)); - mcp->mb[7] = LSW(MSD(phys_addr)); - mcp->mb[8] = MSW(ha->exlogin_size); - mcp->mb[9] = LSW(ha->exlogin_size); + mcp->mb[2] = MSW(ha->exchoffld_buf_dma); + mcp->mb[3] = LSW(ha->exchoffld_buf_dma); + mcp->mb[6] = MSW(MSD(ha->exchoffld_buf_dma)); + mcp->mb[7] = LSW(MSD(ha->exchoffld_buf_dma)); + mcp->mb[8] = MSW(ha->exchoffld_size); + mcp->mb[9] = LSW(ha->exchoffld_size); mcp->out_mb = MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; mcp->in_mb = MBX_11|MBX_0; mcp->tov = MBX_TOV_SECONDS; @@ -942,6 +946,22 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha) ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1191, "%s: Firmware supports Exchange Offload 0x%x\n", __func__, ha->fw_attributes_h); + + /* bit 26 of fw_attributes */ + if ((ha->fw_attributes_h & 0x400) && ql2xnvmeenable) { + struct init_cb_24xx *icb; + + icb = (struct init_cb_24xx *)ha->init_cb; + /* + * fw supports nvme and driver load + * parameter requested nvme + */ + vha->flags.nvme_enabled = 1; + icb->firmware_options_2 &= cpu_to_le32(~0xf); + ha->zio_mode = 0; + ha->zio_timer = 0; + } + } if (IS_QLA27XX(ha)) { @@ -1049,6 +1069,8 @@ qla2x00_set_fw_options(scsi_qla_host_t *vha, uint16_t *fwopts) mcp->in_mb = MBX_0; if (IS_FWI2_CAPABLE(vha->hw)) { mcp->in_mb |= MBX_1; + mcp->mb[10] = fwopts[10]; + mcp->out_mb |= MBX_10; } else { mcp->mb[10] = fwopts[10]; mcp->mb[11] = fwopts[11]; @@ -3213,7 +3235,7 @@ qla8044_write_serdes_word(scsi_qla_host_t *vha, uint32_t addr, uint32_t data) if (!IS_QLA8044(vha->hw)) return QLA_FUNCTION_FAILED; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1186, + ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x11a0, "Entered %s.\n", __func__); mcp->mb[0] = MBC_SET_GET_ETH_SERDES_REG; @@ -3229,7 +3251,7 @@ qla8044_write_serdes_word(scsi_qla_host_t *vha, uint32_t addr, uint32_t data) rval = qla2x00_mailbox_command(vha, mcp); if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x1187, + ql_dbg(ql_dbg_mbx, vha, 0x11a1, "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); } else { ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1188, @@ -3713,12 +3735,12 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha, set_bit(VP_DPC_NEEDED, &vha->dpc_flags); qla2xxx_wake_dpc(vha); } else if (rptid_entry->format == 2) { - ql_dbg(ql_dbg_async, vha, 0xffff, + ql_dbg(ql_dbg_async, vha, 0x505f, "RIDA: format 2/N2N Primary port id %02x%02x%02x.\n", rptid_entry->port_id[2], rptid_entry->port_id[1], rptid_entry->port_id[0]); - ql_dbg(ql_dbg_async, vha, 0xffff, + ql_dbg(ql_dbg_async, vha, 0x5075, "N2N: Remote WWPN %8phC.\n", rptid_entry->u.f2.port_name); @@ -3871,7 +3893,7 @@ qla24xx_control_vp(scsi_qla_host_t *vha, int cmd) rval = QLA_FUNCTION_FAILED; } else if (vce->comp_status != cpu_to_le16(CS_COMPLETE)) { ql_dbg(ql_dbg_mbx, vha, 0x10c5, - "Failed to complet IOCB -- completion status (%x).\n", + "Failed to complete IOCB -- completion status (%x).\n", le16_to_cpu(vce->comp_status)); rval = QLA_FUNCTION_FAILED; } else { @@ -5790,7 +5812,7 @@ qla26xx_dport_diagnostics(scsi_qla_host_t *vha, if (!IS_QLA83XX(vha->hw) && !IS_QLA27XX(vha->hw)) return QLA_FUNCTION_FAILED; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1192, + ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x119f, "Entered %s.\n", __func__); dd_dma = dma_map_single(&vha->hw->pdev->dev, @@ -5872,13 +5894,13 @@ int qla24xx_send_mb_cmd(struct scsi_qla_host *vha, mbx_cmd_t *mcp) rval = qla2x00_start_sp(sp); if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0xffff, + ql_dbg(ql_dbg_mbx, vha, 0x1018, "%s: %s Failed submission. %x.\n", __func__, sp->name, rval); goto done_free_sp; } - ql_dbg(ql_dbg_mbx, vha, 0xffff, "MB:%s hndl %x submitted\n", + ql_dbg(ql_dbg_mbx, vha, 0x113f, "MB:%s hndl %x submitted\n", sp->name, sp->handle); wait_for_completion(&c->u.mbx.comp); @@ -5887,16 +5909,16 @@ int qla24xx_send_mb_cmd(struct scsi_qla_host *vha, mbx_cmd_t *mcp) rval = c->u.mbx.rc; switch (rval) { case QLA_FUNCTION_TIMEOUT: - ql_dbg(ql_dbg_mbx, vha, 0xffff, "%s: %s Timeout. %x.\n", + ql_dbg(ql_dbg_mbx, vha, 0x1140, "%s: %s Timeout. %x.\n", __func__, sp->name, rval); break; case QLA_SUCCESS: - ql_dbg(ql_dbg_mbx, vha, 0xffff, "%s: %s done.\n", + ql_dbg(ql_dbg_mbx, vha, 0x119d, "%s: %s done.\n", __func__, sp->name); sp->free(sp); break; default: - ql_dbg(ql_dbg_mbx, vha, 0xffff, "%s: %s Failed. %x.\n", + ql_dbg(ql_dbg_mbx, vha, 0x119e, "%s: %s Failed. %x.\n", __func__, sp->name, rval); sp->free(sp); break; @@ -5927,8 +5949,8 @@ int qla24xx_gpdb_wait(struct scsi_qla_host *vha, fc_port_t *fcport, u8 opt) pd = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &pd_dma); if (pd == NULL) { - ql_log(ql_log_warn, vha, 0xffff, - "Failed to allocate port database structure.\n"); + ql_log(ql_log_warn, vha, 0xd047, + "Failed to allocate port database structure.\n"); goto done_free_sp; } memset(pd, 0, max(PORT_DATABASE_SIZE, PORT_DATABASE_24XX_SIZE)); @@ -5945,14 +5967,14 @@ int qla24xx_gpdb_wait(struct scsi_qla_host *vha, fc_port_t *fcport, u8 opt) rval = qla24xx_send_mb_cmd(vha, &mc); if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0xffff, + ql_dbg(ql_dbg_mbx, vha, 0x1193, "%s: %8phC fail\n", __func__, fcport->port_name); goto done_free_sp; } rval = __qla24xx_parse_gpdb(vha, fcport, pd); - ql_dbg(ql_dbg_mbx, vha, 0xffff, "%s: %8phC done\n", + ql_dbg(ql_dbg_mbx, vha, 0x1197, "%s: %8phC done\n", __func__, fcport->port_name); done_free_sp: @@ -5967,14 +5989,22 @@ int __qla24xx_parse_gpdb(struct scsi_qla_host *vha, fc_port_t *fcport, { int rval = QLA_SUCCESS; uint64_t zero = 0; + u8 current_login_state, last_login_state; + + if (fcport->fc4f_nvme) { + current_login_state = pd->current_login_state >> 4; + last_login_state = pd->last_login_state >> 4; + } else { + current_login_state = pd->current_login_state & 0xf; + last_login_state = pd->last_login_state & 0xf; + } /* Check for logged in state. */ - if (pd->current_login_state != PDS_PRLI_COMPLETE && - pd->last_login_state != PDS_PRLI_COMPLETE) { - ql_dbg(ql_dbg_mbx, vha, 0xffff, - "Unable to verify login-state (%x/%x) for " - "loop_id %x.\n", pd->current_login_state, - pd->last_login_state, fcport->loop_id); + if (current_login_state != PDS_PRLI_COMPLETE && + last_login_state != PDS_PRLI_COMPLETE) { + ql_dbg(ql_dbg_mbx, vha, 0x119a, + "Unable to verify login-state (%x/%x) for loop_id %x.\n", + current_login_state, last_login_state, fcport->loop_id); rval = QLA_FUNCTION_FAILED; goto gpd_error_out; } @@ -5997,12 +6027,17 @@ int __qla24xx_parse_gpdb(struct scsi_qla_host *vha, fc_port_t *fcport, fcport->d_id.b.al_pa = pd->port_id[2]; fcport->d_id.b.rsvd_1 = 0; - /* If not target must be initiator or unknown type. */ - if ((pd->prli_svc_param_word_3[0] & BIT_4) == 0) - fcport->port_type = FCT_INITIATOR; - else - fcport->port_type = FCT_TARGET; - + if (fcport->fc4f_nvme) { + fcport->nvme_prli_service_param = + pd->prli_nvme_svc_param_word_3; + fcport->port_type = FCT_NVME; + } else { + /* If not target must be initiator or unknown type. */ + if ((pd->prli_svc_param_word_3[0] & BIT_4) == 0) + fcport->port_type = FCT_INITIATOR; + else + fcport->port_type = FCT_TARGET; + } /* Passback COS information. */ fcport->supported_classes = (pd->flags & PDF_CLASS_2) ? FC_COS_CLASS2 : FC_COS_CLASS3; @@ -6040,12 +6075,12 @@ int qla24xx_gidlist_wait(struct scsi_qla_host *vha, rval = qla24xx_send_mb_cmd(vha, &mc); if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0xffff, - "%s: fail\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x119b, + "%s: fail\n", __func__); } else { *entries = mc.mb[1]; - ql_dbg(ql_dbg_mbx, vha, 0xffff, - "%s: done\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x119c, + "%s: done\n", __func__); } done: return rval; diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c index 09a490c98763..f0605cd196fb 100644 --- a/drivers/scsi/qla2xxx/qla_mid.c +++ b/drivers/scsi/qla2xxx/qla_mid.c @@ -640,11 +640,12 @@ qla25xx_delete_queues(struct scsi_qla_host *vha) int qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options, - uint8_t vp_idx, uint16_t rid, int rsp_que, uint8_t qos) + uint8_t vp_idx, uint16_t rid, int rsp_que, uint8_t qos, bool startqp) { int ret = 0; struct req_que *req = NULL; struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); + struct scsi_qla_host *vha = pci_get_drvdata(ha->pdev); uint16_t que_id = 0; device_reg_t *reg; uint32_t cnt; @@ -731,14 +732,17 @@ qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options, req->ring_ptr, req->ring_index, req->cnt, req->id, req->max_q_depth); - ret = qla25xx_init_req_que(base_vha, req); - if (ret != QLA_SUCCESS) { - ql_log(ql_log_fatal, base_vha, 0x00df, - "%s failed.\n", __func__); - mutex_lock(&ha->mq_lock); - clear_bit(que_id, ha->req_qid_map); - mutex_unlock(&ha->mq_lock); - goto que_failed; + if (startqp) { + ret = qla25xx_init_req_que(base_vha, req); + if (ret != QLA_SUCCESS) { + ql_log(ql_log_fatal, base_vha, 0x00df, + "%s failed.\n", __func__); + mutex_lock(&ha->mq_lock); + clear_bit(que_id, ha->req_qid_map); + mutex_unlock(&ha->mq_lock); + goto que_failed; + } + vha->flags.qpairs_req_created = 1; } return req->id; @@ -765,11 +769,12 @@ static void qla_do_work(struct work_struct *work) /* create response queue */ int qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options, - uint8_t vp_idx, uint16_t rid, struct qla_qpair *qpair) + uint8_t vp_idx, uint16_t rid, struct qla_qpair *qpair, bool startqp) { int ret = 0; struct rsp_que *rsp = NULL; struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); + struct scsi_qla_host *vha = pci_get_drvdata(ha->pdev); uint16_t que_id = 0; device_reg_t *reg; @@ -843,14 +848,17 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options, if (ret) goto que_failed; - ret = qla25xx_init_rsp_que(base_vha, rsp); - if (ret != QLA_SUCCESS) { - ql_log(ql_log_fatal, base_vha, 0x00e7, - "%s failed.\n", __func__); - mutex_lock(&ha->mq_lock); - clear_bit(que_id, ha->rsp_qid_map); - mutex_unlock(&ha->mq_lock); - goto que_failed; + if (startqp) { + ret = qla25xx_init_rsp_que(base_vha, rsp); + if (ret != QLA_SUCCESS) { + ql_log(ql_log_fatal, base_vha, 0x00e7, + "%s failed.\n", __func__); + mutex_lock(&ha->mq_lock); + clear_bit(que_id, ha->rsp_qid_map); + mutex_unlock(&ha->mq_lock); + goto que_failed; + } + vha->flags.qpairs_rsp_created = 1; } rsp->req = NULL; diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c new file mode 100644 index 000000000000..f3710a75fe1f --- /dev/null +++ b/drivers/scsi/qla2xxx/qla_nvme.c @@ -0,0 +1,761 @@ +/* + * QLogic Fibre Channel HBA Driver + * Copyright (c) 2003-2017 QLogic Corporation + * + * See LICENSE.qla2xxx for copyright and licensing details. + */ +#include "qla_nvme.h" +#include "qla_def.h" +#include <linux/scatterlist.h> +#include <linux/delay.h> +#include <linux/nvme.h> +#include <linux/nvme-fc.h> + +static struct nvme_fc_port_template qla_nvme_fc_transport; + +static void qla_nvme_unregister_remote_port(struct work_struct *); + +int qla_nvme_register_remote(scsi_qla_host_t *vha, fc_port_t *fcport) +{ + struct nvme_rport *rport; + int ret; + + if (!IS_ENABLED(CONFIG_NVME_FC)) + return 0; + + if (fcport->nvme_flag & NVME_FLAG_REGISTERED) + return 0; + + if (!vha->flags.nvme_enabled) { + ql_log(ql_log_info, vha, 0x2100, + "%s: Not registering target since Host NVME is not enabled\n", + __func__); + return 0; + } + + if (!(fcport->nvme_prli_service_param & + (NVME_PRLI_SP_TARGET | NVME_PRLI_SP_DISCOVERY))) + return 0; + + INIT_WORK(&fcport->nvme_del_work, qla_nvme_unregister_remote_port); + rport = kzalloc(sizeof(*rport), GFP_KERNEL); + if (!rport) { + ql_log(ql_log_warn, vha, 0x2101, + "%s: unable to alloc memory\n", __func__); + return -ENOMEM; + } + + rport->req.port_name = wwn_to_u64(fcport->port_name); + rport->req.node_name = wwn_to_u64(fcport->node_name); + rport->req.port_role = 0; + + if (fcport->nvme_prli_service_param & NVME_PRLI_SP_INITIATOR) + rport->req.port_role = FC_PORT_ROLE_NVME_INITIATOR; + + if (fcport->nvme_prli_service_param & NVME_PRLI_SP_TARGET) + rport->req.port_role |= FC_PORT_ROLE_NVME_TARGET; + + if (fcport->nvme_prli_service_param & NVME_PRLI_SP_DISCOVERY) + rport->req.port_role |= FC_PORT_ROLE_NVME_DISCOVERY; + + rport->req.port_id = fcport->d_id.b24; + + ql_log(ql_log_info, vha, 0x2102, + "%s: traddr=pn-0x%016llx:nn-0x%016llx PortID:%06x\n", + __func__, rport->req.port_name, rport->req.node_name, + rport->req.port_id); + + ret = nvme_fc_register_remoteport(vha->nvme_local_port, &rport->req, + &fcport->nvme_remote_port); + if (ret) { + ql_log(ql_log_warn, vha, 0x212e, + "Failed to register remote port. Transport returned %d\n", + ret); + return ret; + } + + fcport->nvme_remote_port->private = fcport; + fcport->nvme_flag |= NVME_FLAG_REGISTERED; + atomic_set(&fcport->nvme_ref_count, 1); + init_waitqueue_head(&fcport->nvme_waitQ); + rport->fcport = fcport; + list_add_tail(&rport->list, &vha->nvme_rport_list); + return 0; +} + +/* Allocate a queue for NVMe traffic */ +static int qla_nvme_alloc_queue(struct nvme_fc_local_port *lport, unsigned int qidx, + u16 qsize, void **handle) +{ + struct scsi_qla_host *vha; + struct qla_hw_data *ha; + struct qla_qpair *qpair; + + if (!qidx) + qidx++; + + vha = (struct scsi_qla_host *)lport->private; + ha = vha->hw; + + ql_log(ql_log_info, vha, 0x2104, + "%s: handle %p, idx =%d, qsize %d\n", + __func__, handle, qidx, qsize); + + if (qidx > qla_nvme_fc_transport.max_hw_queues) { + ql_log(ql_log_warn, vha, 0x212f, + "%s: Illegal qidx=%d. Max=%d\n", + __func__, qidx, qla_nvme_fc_transport.max_hw_queues); + return -EINVAL; + } + + if (ha->queue_pair_map[qidx]) { + *handle = ha->queue_pair_map[qidx]; + ql_log(ql_log_info, vha, 0x2121, + "Returning existing qpair of %p for idx=%x\n", + *handle, qidx); + return 0; + } + + ql_log(ql_log_warn, vha, 0xffff, + "allocating q for idx=%x w/o cpu mask\n", qidx); + qpair = qla2xxx_create_qpair(vha, 5, vha->vp_idx, true); + if (qpair == NULL) { + ql_log(ql_log_warn, vha, 0x2122, + "Failed to allocate qpair\n"); + return -EINVAL; + } + *handle = qpair; + + return 0; +} + +static void qla_nvme_sp_ls_done(void *ptr, int res) +{ + srb_t *sp = ptr; + struct srb_iocb *nvme; + struct nvmefc_ls_req *fd; + struct nvme_private *priv; + + if (atomic_read(&sp->ref_count) == 0) { + ql_log(ql_log_warn, sp->fcport->vha, 0x2123, + "SP reference-count to ZERO on LS_done -- sp=%p.\n", sp); + return; + } + + if (!atomic_dec_and_test(&sp->ref_count)) + return; + + if (res) + res = -EINVAL; + + nvme = &sp->u.iocb_cmd; + fd = nvme->u.nvme.desc; + priv = fd->private; + priv->comp_status = res; + schedule_work(&priv->ls_work); + /* work schedule doesn't need the sp */ + qla2x00_rel_sp(sp); +} + +static void qla_nvme_sp_done(void *ptr, int res) +{ + srb_t *sp = ptr; + struct srb_iocb *nvme; + struct nvmefc_fcp_req *fd; + + nvme = &sp->u.iocb_cmd; + fd = nvme->u.nvme.desc; + + if (!atomic_dec_and_test(&sp->ref_count)) + return; + + if (!(sp->fcport->nvme_flag & NVME_FLAG_REGISTERED)) + goto rel; + + if (unlikely(nvme->u.nvme.comp_status || res)) + fd->status = -EINVAL; + else + fd->status = 0; + + fd->rcv_rsplen = nvme->u.nvme.rsp_pyld_len; + fd->done(fd); +rel: + qla2xxx_rel_qpair_sp(sp->qpair, sp); +} + +static void qla_nvme_ls_abort(struct nvme_fc_local_port *lport, + struct nvme_fc_remote_port *rport, struct nvmefc_ls_req *fd) +{ + struct nvme_private *priv = fd->private; + fc_port_t *fcport = rport->private; + srb_t *sp = priv->sp; + int rval; + struct qla_hw_data *ha = fcport->vha->hw; + + rval = ha->isp_ops->abort_command(sp); + if (rval != QLA_SUCCESS) + ql_log(ql_log_warn, fcport->vha, 0x2125, + "%s: failed to abort LS command for SP:%p rval=%x\n", + __func__, sp, rval); + + ql_dbg(ql_dbg_io, fcport->vha, 0x212b, + "%s: aborted sp:%p on fcport:%p\n", __func__, sp, fcport); +} + +static void qla_nvme_ls_complete(struct work_struct *work) +{ + struct nvme_private *priv = + container_of(work, struct nvme_private, ls_work); + struct nvmefc_ls_req *fd = priv->fd; + + fd->done(fd, priv->comp_status); +} + +static int qla_nvme_ls_req(struct nvme_fc_local_port *lport, + struct nvme_fc_remote_port *rport, struct nvmefc_ls_req *fd) +{ + fc_port_t *fcport = (fc_port_t *)rport->private; + struct srb_iocb *nvme; + struct nvme_private *priv = fd->private; + struct scsi_qla_host *vha; + int rval = QLA_FUNCTION_FAILED; + struct qla_hw_data *ha; + srb_t *sp; + + if (!(fcport->nvme_flag & NVME_FLAG_REGISTERED)) + return rval; + + vha = fcport->vha; + ha = vha->hw; + /* Alloc SRB structure */ + sp = qla2x00_get_sp(vha, fcport, GFP_ATOMIC); + if (!sp) + return rval; + + sp->type = SRB_NVME_LS; + sp->name = "nvme_ls"; + sp->done = qla_nvme_sp_ls_done; + atomic_set(&sp->ref_count, 1); + init_waitqueue_head(&sp->nvme_ls_waitQ); + nvme = &sp->u.iocb_cmd; + priv->sp = sp; + priv->fd = fd; + INIT_WORK(&priv->ls_work, qla_nvme_ls_complete); + nvme->u.nvme.desc = fd; + nvme->u.nvme.dir = 0; + nvme->u.nvme.dl = 0; + nvme->u.nvme.cmd_len = fd->rqstlen; + nvme->u.nvme.rsp_len = fd->rsplen; + nvme->u.nvme.rsp_dma = fd->rspdma; + nvme->u.nvme.timeout_sec = fd->timeout; + nvme->u.nvme.cmd_dma = dma_map_single(&ha->pdev->dev, fd->rqstaddr, + fd->rqstlen, DMA_TO_DEVICE); + dma_sync_single_for_device(&ha->pdev->dev, nvme->u.nvme.cmd_dma, + fd->rqstlen, DMA_TO_DEVICE); + + rval = qla2x00_start_sp(sp); + if (rval != QLA_SUCCESS) { + ql_log(ql_log_warn, vha, 0x700e, + "qla2x00_start_sp failed = %d\n", rval); + atomic_dec(&sp->ref_count); + wake_up(&sp->nvme_ls_waitQ); + return rval; + } + + return rval; +} + +static void qla_nvme_fcp_abort(struct nvme_fc_local_port *lport, + struct nvme_fc_remote_port *rport, void *hw_queue_handle, + struct nvmefc_fcp_req *fd) +{ + struct nvme_private *priv = fd->private; + srb_t *sp = priv->sp; + int rval; + fc_port_t *fcport = rport->private; + struct qla_hw_data *ha = fcport->vha->hw; + + rval = ha->isp_ops->abort_command(sp); + if (!rval) + ql_log(ql_log_warn, fcport->vha, 0x2127, + "%s: failed to abort command for SP:%p rval=%x\n", + __func__, sp, rval); + + ql_dbg(ql_dbg_io, fcport->vha, 0x2126, + "%s: aborted sp:%p on fcport:%p\n", __func__, sp, fcport); +} + +static void qla_nvme_poll(struct nvme_fc_local_port *lport, void *hw_queue_handle) +{ + struct scsi_qla_host *vha = lport->private; + unsigned long flags; + struct qla_qpair *qpair = (struct qla_qpair *)hw_queue_handle; + + /* Acquire ring specific lock */ + spin_lock_irqsave(&qpair->qp_lock, flags); + qla24xx_process_response_queue(vha, qpair->rsp); + spin_unlock_irqrestore(&qpair->qp_lock, flags); +} + +static int qla2x00_start_nvme_mq(srb_t *sp) +{ + unsigned long flags; + uint32_t *clr_ptr; + uint32_t index; + uint32_t handle; + struct cmd_nvme *cmd_pkt; + uint16_t cnt, i; + uint16_t req_cnt; + uint16_t tot_dsds; + uint16_t avail_dsds; + uint32_t *cur_dsd; + struct req_que *req = NULL; + struct scsi_qla_host *vha = sp->fcport->vha; + struct qla_hw_data *ha = vha->hw; + struct qla_qpair *qpair = sp->qpair; + struct srb_iocb *nvme = &sp->u.iocb_cmd; + struct scatterlist *sgl, *sg; + struct nvmefc_fcp_req *fd = nvme->u.nvme.desc; + uint32_t rval = QLA_SUCCESS; + + /* Setup qpair pointers */ + req = qpair->req; + tot_dsds = fd->sg_cnt; + + /* Acquire qpair specific lock */ + spin_lock_irqsave(&qpair->qp_lock, flags); + + /* Check for room in outstanding command list. */ + handle = req->current_outstanding_cmd; + for (index = 1; index < req->num_outstanding_cmds; index++) { + handle++; + if (handle == req->num_outstanding_cmds) + handle = 1; + if (!req->outstanding_cmds[handle]) + break; + } + + if (index == req->num_outstanding_cmds) { + rval = -1; + goto queuing_error; + } + req_cnt = qla24xx_calc_iocbs(vha, tot_dsds); + if (req->cnt < (req_cnt + 2)) { + cnt = IS_SHADOW_REG_CAPABLE(ha) ? *req->out_ptr : + RD_REG_DWORD_RELAXED(req->req_q_out); + + if (req->ring_index < cnt) + req->cnt = cnt - req->ring_index; + else + req->cnt = req->length - (req->ring_index - cnt); + + if (req->cnt < (req_cnt + 2)){ + rval = -1; + goto queuing_error; + } + } + + if (unlikely(!fd->sqid)) { + struct nvme_fc_cmd_iu *cmd = fd->cmdaddr; + if (cmd->sqe.common.opcode == nvme_admin_async_event) { + nvme->u.nvme.aen_op = 1; + atomic_inc(&vha->nvme_active_aen_cnt); + } + } + + /* Build command packet. */ + req->current_outstanding_cmd = handle; + req->outstanding_cmds[handle] = sp; + sp->handle = handle; + req->cnt -= req_cnt; + + cmd_pkt = (struct cmd_nvme *)req->ring_ptr; + cmd_pkt->handle = MAKE_HANDLE(req->id, handle); + + /* Zero out remaining portion of packet. */ + clr_ptr = (uint32_t *)cmd_pkt + 2; + memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8); + + cmd_pkt->entry_status = 0; + + /* Update entry type to indicate Command NVME IOCB */ + cmd_pkt->entry_type = COMMAND_NVME; + + /* No data transfer how do we check buffer len == 0?? */ + if (fd->io_dir == NVMEFC_FCP_READ) { + cmd_pkt->control_flags = + cpu_to_le16(CF_READ_DATA | CF_NVME_ENABLE); + vha->qla_stats.input_bytes += fd->payload_length; + vha->qla_stats.input_requests++; + } else if (fd->io_dir == NVMEFC_FCP_WRITE) { + cmd_pkt->control_flags = + cpu_to_le16(CF_WRITE_DATA | CF_NVME_ENABLE); + vha->qla_stats.output_bytes += fd->payload_length; + vha->qla_stats.output_requests++; + } else if (fd->io_dir == 0) { + cmd_pkt->control_flags = cpu_to_le16(CF_NVME_ENABLE); + } + + /* Set NPORT-ID */ + cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id); + cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa; + cmd_pkt->port_id[1] = sp->fcport->d_id.b.area; + cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain; + cmd_pkt->vp_index = sp->fcport->vha->vp_idx; + + /* NVME RSP IU */ + cmd_pkt->nvme_rsp_dsd_len = cpu_to_le16(fd->rsplen); + cmd_pkt->nvme_rsp_dseg_address[0] = cpu_to_le32(LSD(fd->rspdma)); + cmd_pkt->nvme_rsp_dseg_address[1] = cpu_to_le32(MSD(fd->rspdma)); + + /* NVME CNMD IU */ + cmd_pkt->nvme_cmnd_dseg_len = cpu_to_le16(fd->cmdlen); + cmd_pkt->nvme_cmnd_dseg_address[0] = cpu_to_le32(LSD(fd->cmddma)); + cmd_pkt->nvme_cmnd_dseg_address[1] = cpu_to_le32(MSD(fd->cmddma)); + + cmd_pkt->dseg_count = cpu_to_le16(tot_dsds); + cmd_pkt->byte_count = cpu_to_le32(fd->payload_length); + + /* One DSD is available in the Command Type NVME IOCB */ + avail_dsds = 1; + cur_dsd = (uint32_t *)&cmd_pkt->nvme_data_dseg_address[0]; + sgl = fd->first_sgl; + + /* Load data segments */ + for_each_sg(sgl, sg, tot_dsds, i) { + dma_addr_t sle_dma; + cont_a64_entry_t *cont_pkt; + + /* Allocate additional continuation packets? */ + if (avail_dsds == 0) { + /* + * Five DSDs are available in the Continuation + * Type 1 IOCB. + */ + + /* Adjust ring index */ + req->ring_index++; + if (req->ring_index == req->length) { + req->ring_index = 0; + req->ring_ptr = req->ring; + } else { + req->ring_ptr++; + } + cont_pkt = (cont_a64_entry_t *)req->ring_ptr; + *((uint32_t *)(&cont_pkt->entry_type)) = + cpu_to_le32(CONTINUE_A64_TYPE); + + cur_dsd = (uint32_t *)cont_pkt->dseg_0_address; + avail_dsds = 5; + } + + sle_dma = sg_dma_address(sg); + *cur_dsd++ = cpu_to_le32(LSD(sle_dma)); + *cur_dsd++ = cpu_to_le32(MSD(sle_dma)); + *cur_dsd++ = cpu_to_le32(sg_dma_len(sg)); + avail_dsds--; + } + + /* Set total entry count. */ + cmd_pkt->entry_count = (uint8_t)req_cnt; + wmb(); + + /* Adjust ring index. */ + req->ring_index++; + if (req->ring_index == req->length) { + req->ring_index = 0; + req->ring_ptr = req->ring; + } else { + req->ring_ptr++; + } + + /* Set chip new ring index. */ + WRT_REG_DWORD(req->req_q_in, req->ring_index); + +queuing_error: + spin_unlock_irqrestore(&qpair->qp_lock, flags); + return rval; +} + +/* Post a command */ +static int qla_nvme_post_cmd(struct nvme_fc_local_port *lport, + struct nvme_fc_remote_port *rport, void *hw_queue_handle, + struct nvmefc_fcp_req *fd) +{ + fc_port_t *fcport; + struct srb_iocb *nvme; + struct scsi_qla_host *vha; + int rval = QLA_FUNCTION_FAILED; + srb_t *sp; + struct qla_qpair *qpair = (struct qla_qpair *)hw_queue_handle; + struct nvme_private *priv; + + if (!fd) { + ql_log(ql_log_warn, NULL, 0x2134, "NO NVMe FCP request\n"); + return rval; + } + + priv = fd->private; + fcport = (fc_port_t *)rport->private; + if (!fcport) { + ql_log(ql_log_warn, NULL, 0x210e, "No fcport ptr\n"); + return rval; + } + + vha = fcport->vha; + if ((!qpair) || (!(fcport->nvme_flag & NVME_FLAG_REGISTERED))) + return -EBUSY; + + /* Alloc SRB structure */ + sp = qla2xxx_get_qpair_sp(qpair, fcport, GFP_ATOMIC); + if (!sp) + return -EIO; + + atomic_set(&sp->ref_count, 1); + init_waitqueue_head(&sp->nvme_ls_waitQ); + priv->sp = sp; + sp->type = SRB_NVME_CMD; + sp->name = "nvme_cmd"; + sp->done = qla_nvme_sp_done; + sp->qpair = qpair; + nvme = &sp->u.iocb_cmd; + nvme->u.nvme.desc = fd; + + rval = qla2x00_start_nvme_mq(sp); + if (rval != QLA_SUCCESS) { + ql_log(ql_log_warn, vha, 0x212d, + "qla2x00_start_nvme_mq failed = %d\n", rval); + atomic_dec(&sp->ref_count); + wake_up(&sp->nvme_ls_waitQ); + return -EIO; + } + + return rval; +} + +static void qla_nvme_localport_delete(struct nvme_fc_local_port *lport) +{ + struct scsi_qla_host *vha = lport->private; + + atomic_dec(&vha->nvme_ref_count); + wake_up_all(&vha->nvme_waitQ); + + ql_log(ql_log_info, vha, 0x210f, + "localport delete of %p completed.\n", vha->nvme_local_port); + vha->nvme_local_port = NULL; +} + +static void qla_nvme_remoteport_delete(struct nvme_fc_remote_port *rport) +{ + fc_port_t *fcport; + struct nvme_rport *r_port, *trport; + + fcport = (fc_port_t *)rport->private; + fcport->nvme_remote_port = NULL; + fcport->nvme_flag &= ~NVME_FLAG_REGISTERED; + atomic_dec(&fcport->nvme_ref_count); + wake_up_all(&fcport->nvme_waitQ); + + list_for_each_entry_safe(r_port, trport, + &fcport->vha->nvme_rport_list, list) { + if (r_port->fcport == fcport) { + list_del(&r_port->list); + break; + } + } + kfree(r_port); + + ql_log(ql_log_info, fcport->vha, 0x2110, + "remoteport_delete of %p completed.\n", fcport); +} + +static struct nvme_fc_port_template qla_nvme_fc_transport = { + .localport_delete = qla_nvme_localport_delete, + .remoteport_delete = qla_nvme_remoteport_delete, + .create_queue = qla_nvme_alloc_queue, + .delete_queue = NULL, + .ls_req = qla_nvme_ls_req, + .ls_abort = qla_nvme_ls_abort, + .fcp_io = qla_nvme_post_cmd, + .fcp_abort = qla_nvme_fcp_abort, + .poll_queue = qla_nvme_poll, + .max_hw_queues = 8, + .max_sgl_segments = 128, + .max_dif_sgl_segments = 64, + .dma_boundary = 0xFFFFFFFF, + .local_priv_sz = 8, + .remote_priv_sz = 0, + .lsrqst_priv_sz = sizeof(struct nvme_private), + .fcprqst_priv_sz = sizeof(struct nvme_private), +}; + +#define NVME_ABORT_POLLING_PERIOD 2 +static int qla_nvme_wait_on_command(srb_t *sp) +{ + int ret = QLA_SUCCESS; + + wait_event_timeout(sp->nvme_ls_waitQ, (atomic_read(&sp->ref_count) > 1), + NVME_ABORT_POLLING_PERIOD*HZ); + + if (atomic_read(&sp->ref_count) > 1) + ret = QLA_FUNCTION_FAILED; + + return ret; +} + +static int qla_nvme_wait_on_rport_del(fc_port_t *fcport) +{ + int ret = QLA_SUCCESS; + + wait_event_timeout(fcport->nvme_waitQ, + atomic_read(&fcport->nvme_ref_count), + NVME_ABORT_POLLING_PERIOD*HZ); + + if (atomic_read(&fcport->nvme_ref_count)) { + ret = QLA_FUNCTION_FAILED; + ql_log(ql_log_info, fcport->vha, 0x2111, + "timed out waiting for fcport=%p to delete\n", fcport); + } + + return ret; +} + +void qla_nvme_abort(struct qla_hw_data *ha, srb_t *sp) +{ + int rval; + + rval = ha->isp_ops->abort_command(sp); + if (!rval) { + if (!qla_nvme_wait_on_command(sp)) + ql_log(ql_log_warn, NULL, 0x2112, + "nvme_wait_on_command timed out waiting on sp=%p\n", + sp); + } +} + +static void qla_nvme_abort_all(fc_port_t *fcport) +{ + int que, cnt; + unsigned long flags; + srb_t *sp; + struct qla_hw_data *ha = fcport->vha->hw; + struct req_que *req; + + spin_lock_irqsave(&ha->hardware_lock, flags); + for (que = 0; que < ha->max_req_queues; que++) { + req = ha->req_q_map[que]; + if (!req) + continue; + if (!req->outstanding_cmds) + continue; + for (cnt = 1; cnt < req->num_outstanding_cmds; cnt++) { + sp = req->outstanding_cmds[cnt]; + if ((sp) && ((sp->type == SRB_NVME_CMD) || + (sp->type == SRB_NVME_LS)) && + (sp->fcport == fcport)) { + atomic_inc(&sp->ref_count); + spin_unlock_irqrestore(&ha->hardware_lock, + flags); + qla_nvme_abort(ha, sp); + spin_lock_irqsave(&ha->hardware_lock, flags); + req->outstanding_cmds[cnt] = NULL; + sp->done(sp, 1); + } + } + } + spin_unlock_irqrestore(&ha->hardware_lock, flags); +} + +static void qla_nvme_unregister_remote_port(struct work_struct *work) +{ + struct fc_port *fcport = container_of(work, struct fc_port, + nvme_del_work); + struct nvme_rport *rport, *trport; + + if (!IS_ENABLED(CONFIG_NVME_FC)) + return; + + list_for_each_entry_safe(rport, trport, + &fcport->vha->nvme_rport_list, list) { + if (rport->fcport == fcport) { + ql_log(ql_log_info, fcport->vha, 0x2113, + "%s: fcport=%p\n", __func__, fcport); + nvme_fc_unregister_remoteport( + fcport->nvme_remote_port); + } + } +} + +void qla_nvme_delete(scsi_qla_host_t *vha) +{ + struct nvme_rport *rport, *trport; + fc_port_t *fcport; + int nv_ret; + + if (!IS_ENABLED(CONFIG_NVME_FC)) + return; + + list_for_each_entry_safe(rport, trport, &vha->nvme_rport_list, list) { + fcport = rport->fcport; + + ql_log(ql_log_info, fcport->vha, 0x2114, "%s: fcport=%p\n", + __func__, fcport); + + nvme_fc_unregister_remoteport(fcport->nvme_remote_port); + qla_nvme_wait_on_rport_del(fcport); + qla_nvme_abort_all(fcport); + } + + if (vha->nvme_local_port) { + nv_ret = nvme_fc_unregister_localport(vha->nvme_local_port); + if (nv_ret == 0) + ql_log(ql_log_info, vha, 0x2116, + "unregistered localport=%p\n", + vha->nvme_local_port); + else + ql_log(ql_log_info, vha, 0x2115, + "Unregister of localport failed\n"); + } +} + +void qla_nvme_register_hba(scsi_qla_host_t *vha) +{ + struct nvme_fc_port_template *tmpl; + struct qla_hw_data *ha; + struct nvme_fc_port_info pinfo; + int ret; + + if (!IS_ENABLED(CONFIG_NVME_FC)) + return; + + ha = vha->hw; + tmpl = &qla_nvme_fc_transport; + + WARN_ON(vha->nvme_local_port); + WARN_ON(ha->max_req_queues < 3); + + qla_nvme_fc_transport.max_hw_queues = + min((uint8_t)(qla_nvme_fc_transport.max_hw_queues), + (uint8_t)(ha->max_req_queues - 2)); + + pinfo.node_name = wwn_to_u64(vha->node_name); + pinfo.port_name = wwn_to_u64(vha->port_name); + pinfo.port_role = FC_PORT_ROLE_NVME_INITIATOR; + pinfo.port_id = vha->d_id.b24; + + ql_log(ql_log_info, vha, 0xffff, + "register_localport: host-traddr=pn-0x%llx:nn-0x%llx on portID:%x\n", + pinfo.port_name, pinfo.node_name, pinfo.port_id); + qla_nvme_fc_transport.dma_boundary = vha->host->dma_boundary; + + ret = nvme_fc_register_localport(&pinfo, tmpl, + get_device(&ha->pdev->dev), &vha->nvme_local_port); + if (ret) { + ql_log(ql_log_warn, vha, 0xffff, + "register_localport failed: ret=%x\n", ret); + return; + } + atomic_set(&vha->nvme_ref_count, 1); + vha->nvme_local_port->private = vha; + init_waitqueue_head(&vha->nvme_waitQ); +} diff --git a/drivers/scsi/qla2xxx/qla_nvme.h b/drivers/scsi/qla2xxx/qla_nvme.h new file mode 100644 index 000000000000..dfe56f207b28 --- /dev/null +++ b/drivers/scsi/qla2xxx/qla_nvme.h @@ -0,0 +1,132 @@ +/* + * QLogic Fibre Channel HBA Driver + * Copyright (c) 2003-2017 QLogic Corporation + * + * See LICENSE.qla2xxx for copyright and licensing details. + */ +#ifndef __QLA_NVME_H +#define __QLA_NVME_H + +#include <linux/blk-mq.h> +#include <uapi/scsi/fc/fc_fs.h> +#include <uapi/scsi/fc/fc_els.h> +#include <linux/nvme-fc-driver.h> + +#define NVME_ATIO_CMD_OFF 32 +#define NVME_FIRST_PACKET_CMDLEN (64 - NVME_ATIO_CMD_OFF) +#define Q2T_NVME_NUM_TAGS 2048 +#define QLA_MAX_FC_SEGMENTS 64 + +struct srb; +struct nvme_private { + struct srb *sp; + struct nvmefc_ls_req *fd; + struct work_struct ls_work; + int comp_status; +}; + +struct nvme_rport { + struct nvme_fc_port_info req; + struct list_head list; + struct fc_port *fcport; +}; + +#define COMMAND_NVME 0x88 /* Command Type FC-NVMe IOCB */ +struct cmd_nvme { + uint8_t entry_type; /* Entry type. */ + uint8_t entry_count; /* Entry count. */ + uint8_t sys_define; /* System defined. */ + uint8_t entry_status; /* Entry Status. */ + + uint32_t handle; /* System handle. */ + uint16_t nport_handle; /* N_PORT handle. */ + uint16_t timeout; /* Command timeout. */ + + uint16_t dseg_count; /* Data segment count. */ + uint16_t nvme_rsp_dsd_len; /* NVMe RSP DSD length */ + + uint64_t rsvd; + + uint16_t control_flags; /* Control Flags */ +#define CF_NVME_ENABLE BIT_9 +#define CF_DIF_SEG_DESCR_ENABLE BIT_3 +#define CF_DATA_SEG_DESCR_ENABLE BIT_2 +#define CF_READ_DATA BIT_1 +#define CF_WRITE_DATA BIT_0 + + uint16_t nvme_cmnd_dseg_len; /* Data segment length. */ + uint32_t nvme_cmnd_dseg_address[2]; /* Data segment address. */ + uint32_t nvme_rsp_dseg_address[2]; /* Data segment address. */ + + uint32_t byte_count; /* Total byte count. */ + + uint8_t port_id[3]; /* PortID of destination port. */ + uint8_t vp_index; + + uint32_t nvme_data_dseg_address[2]; /* Data segment address. */ + uint32_t nvme_data_dseg_len; /* Data segment length. */ +}; + +#define PT_LS4_REQUEST 0x89 /* Link Service pass-through IOCB (request) */ +struct pt_ls4_request { + uint8_t entry_type; + uint8_t entry_count; + uint8_t sys_define; + uint8_t entry_status; + uint32_t handle; + uint16_t status; + uint16_t nport_handle; + uint16_t tx_dseg_count; + uint8_t vp_index; + uint8_t rsvd; + uint16_t timeout; + uint16_t control_flags; +#define CF_LS4_SHIFT 13 +#define CF_LS4_ORIGINATOR 0 +#define CF_LS4_RESPONDER 1 +#define CF_LS4_RESPONDER_TERM 2 + + uint16_t rx_dseg_count; + uint16_t rsvd2; + uint32_t exchange_address; + uint32_t rsvd3; + uint32_t rx_byte_count; + uint32_t tx_byte_count; + uint32_t dseg0_address[2]; + uint32_t dseg0_len; + uint32_t dseg1_address[2]; + uint32_t dseg1_len; +}; + +#define PT_LS4_UNSOL 0x56 /* pass-up unsolicited rec FC-NVMe request */ +struct pt_ls4_rx_unsol { + uint8_t entry_type; + uint8_t entry_count; + uint16_t rsvd0; + uint16_t rsvd1; + uint8_t vp_index; + uint8_t rsvd2; + uint16_t rsvd3; + uint16_t nport_handle; + uint16_t frame_size; + uint16_t rsvd4; + uint32_t exchange_address; + uint8_t d_id[3]; + uint8_t r_ctl; + uint8_t s_id[3]; + uint8_t cs_ctl; + uint8_t f_ctl[3]; + uint8_t type; + uint16_t seq_cnt; + uint8_t df_ctl; + uint8_t seq_id; + uint16_t rx_id; + uint16_t ox_id; + uint32_t param; + uint32_t desc0; +#define PT_LS4_PAYLOAD_OFFSET 0x2c +#define PT_LS4_FIRST_PACKET_LEN 20 + uint32_t desc_len; + uint32_t payload[3]; +}; +#endif diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c index 0a1723cc08cf..a77c33987703 100644 --- a/drivers/scsi/qla2xxx/qla_nx.c +++ b/drivers/scsi/qla2xxx/qla_nx.c @@ -782,7 +782,7 @@ qla82xx_pci_mem_write_direct(struct qla_hw_data *ha, (qla82xx_pci_is_same_window(ha, off + size - 1) == 0)) { write_unlock_irqrestore(&ha->hw_lock, flags); ql_log(ql_log_fatal, vha, 0xb009, - "%s out of bount memory " + "%s out of bound memory " "access, offset is 0x%llx.\n", QLA2XXX_DRIVER_NAME, off); return -1; @@ -4250,7 +4250,7 @@ qla82xx_md_collect(scsi_qla_host_t *vha) ql_dbg(ql_dbg_p3p, vha, 0xb040, "[%s]: data ptr[%d]: %p, entry_hdr: %p\n" - "entry_type: 0x%x, captrue_mask: 0x%x\n", + "entry_type: 0x%x, capture_mask: 0x%x\n", __func__, i, data_ptr, entry_hdr, entry_hdr->entry_type, entry_hdr->d_ctrl.entry_capture_mask); diff --git a/drivers/scsi/qla2xxx/qla_nx.h b/drivers/scsi/qla2xxx/qla_nx.h index 77624eac95a4..71a41093530e 100644 --- a/drivers/scsi/qla2xxx/qla_nx.h +++ b/drivers/scsi/qla2xxx/qla_nx.h @@ -7,6 +7,8 @@ #ifndef __QLA_NX_H #define __QLA_NX_H +#include <linux/io-64-nonatomic-lo-hi.h> + /* * Following are the states of the Phantom. Phantom will set them and * Host will read to check if the fields are correct. @@ -819,21 +821,6 @@ struct qla82xx_uri_data_desc{ #define MIU_TEST_AGT_WRDATA_UPPER_LO (0x0b0) #define MIU_TEST_AGT_WRDATA_UPPER_HI (0x0b4) -#ifndef readq -static inline u64 readq(void __iomem *addr) -{ - return readl(addr) | (((u64) readl(addr + 4)) << 32LL); -} -#endif - -#ifndef writeq -static inline void writeq(u64 val, void __iomem *addr) -{ - writel(((u32) (val)), (addr)); - writel(((u32) (val >> 32)), (addr + 4)); -} -#endif - /* Request and response queue size */ #define REQUEST_ENTRY_CNT_82XX 128 /* Number of request entries. */ #define RESPONSE_ENTRY_CNT_82XX 128 /* Number of response entries.*/ diff --git a/drivers/scsi/qla2xxx/qla_nx2.c b/drivers/scsi/qla2xxx/qla_nx2.c index dc1ec9b61027..0aa9c38bf347 100644 --- a/drivers/scsi/qla2xxx/qla_nx2.c +++ b/drivers/scsi/qla2xxx/qla_nx2.c @@ -1572,7 +1572,7 @@ qla8044_read_reset_template(struct scsi_qla_host *vha) /* Copy rest of the template */ if (qla8044_read_flash_data(vha, p_buff, addr, tmplt_hdr_def_size)) { ql_log(ql_log_fatal, vha, 0xb0bd, - "%s: Failed to read reset tempelate\n", __func__); + "%s: Failed to read reset template\n", __func__); goto exit_read_template_error; } diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 79f050256c55..df57655779ed 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -120,7 +120,11 @@ MODULE_PARM_DESC(ql2xmaxqdepth, "Maximum queue depth to set for each LUN. " "Default is 32."); +#if (IS_ENABLED(CONFIG_NVME_FC)) +int ql2xenabledif; +#else int ql2xenabledif = 2; +#endif module_param(ql2xenabledif, int, S_IRUGO); MODULE_PARM_DESC(ql2xenabledif, " Enable T10-CRC-DIF:\n" @@ -129,6 +133,16 @@ MODULE_PARM_DESC(ql2xenabledif, " 1 -- Enable DIF for all types\n" " 2 -- Enable DIF for all types, except Type 0.\n"); +#if (IS_ENABLED(CONFIG_NVME_FC)) +int ql2xnvmeenable = 1; +#else +int ql2xnvmeenable; +#endif +module_param(ql2xnvmeenable, int, 0644); +MODULE_PARM_DESC(ql2xnvmeenable, + "Enables NVME support. " + "0 - no NVMe. Default is Y"); + int ql2xenablehba_err_chk = 2; module_param(ql2xenablehba_err_chk, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(ql2xenablehba_err_chk, @@ -224,11 +238,15 @@ MODULE_PARM_DESC(ql2xexlogins, "Number of extended Logins. " "0 (Default)- Disabled."); -int ql2xexchoffld = 0; -module_param(ql2xexchoffld, uint, S_IRUGO|S_IWUSR); +int ql2xexchoffld = 1024; +module_param(ql2xexchoffld, uint, 0644); MODULE_PARM_DESC(ql2xexchoffld, - "Number of exchanges to offload. " - "0 (Default)- Disabled."); + "Number of target exchanges."); + +int ql2xiniexchg = 1024; +module_param(ql2xiniexchg, uint, 0644); +MODULE_PARM_DESC(ql2xiniexchg, + "Number of initiator exchanges."); int ql2xfwholdabts = 0; module_param(ql2xfwholdabts, int, S_IRUGO); @@ -263,6 +281,7 @@ static void qla2x00_clear_drv_active(struct qla_hw_data *); static void qla2x00_free_device(scsi_qla_host_t *); static void qla83xx_disable_laser(scsi_qla_host_t *vha); static int qla2xxx_map_queues(struct Scsi_Host *shost); +static void qla2x00_destroy_deferred_work(struct qla_hw_data *); struct scsi_host_template qla2xxx_driver_template = { .module = THIS_MODULE, @@ -347,6 +366,28 @@ int qla2xxx_mqueuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd, struct qla_qpair *qpair); /* -------------------------------------------------------------------------- */ +static void qla_init_base_qpair(struct scsi_qla_host *vha, struct req_que *req, + struct rsp_que *rsp) +{ + struct qla_hw_data *ha = vha->hw; + rsp->qpair = ha->base_qpair; + rsp->req = req; + ha->base_qpair->req = req; + ha->base_qpair->rsp = rsp; + ha->base_qpair->vha = vha; + ha->base_qpair->qp_lock_ptr = &ha->hardware_lock; + ha->base_qpair->use_shadow_reg = IS_SHADOW_REG_CAPABLE(ha) ? 1 : 0; + ha->base_qpair->msix = &ha->msix_entries[QLA_MSIX_RSP_Q]; + INIT_LIST_HEAD(&ha->base_qpair->hints_list); + ha->base_qpair->enable_class_2 = ql2xenableclass2; + /* init qpair to this cpu. Will adjust at run time. */ + qla_cpu_update(rsp->qpair, smp_processor_id()); + ha->base_qpair->pdev = ha->pdev; + + if (IS_QLA27XX(ha) || IS_QLA83XX(ha)) + ha->base_qpair->reqq_start_iocbs = qla_83xx_start_iocbs; +} + static int qla2x00_alloc_queues(struct qla_hw_data *ha, struct req_que *req, struct rsp_que *rsp) { @@ -367,6 +408,15 @@ static int qla2x00_alloc_queues(struct qla_hw_data *ha, struct req_que *req, goto fail_rsp_map; } + ha->base_qpair = kzalloc(sizeof(struct qla_qpair), GFP_KERNEL); + if (ha->base_qpair == NULL) { + ql_log(ql_log_warn, vha, 0x00e0, + "Failed to allocate base queue pair memory.\n"); + goto fail_base_qpair; + } + + qla_init_base_qpair(vha, req, rsp); + if (ql2xmqsupport && ha->max_qpairs) { ha->queue_pair_map = kcalloc(ha->max_qpairs, sizeof(struct qla_qpair *), GFP_KERNEL); @@ -375,14 +425,6 @@ static int qla2x00_alloc_queues(struct qla_hw_data *ha, struct req_que *req, "Unable to allocate memory for queue pair ptrs.\n"); goto fail_qpair_map; } - ha->base_qpair = kzalloc(sizeof(struct qla_qpair), GFP_KERNEL); - if (ha->base_qpair == NULL) { - ql_log(ql_log_warn, vha, 0x0182, - "Failed to allocate base queue pair memory.\n"); - goto fail_base_qpair; - } - ha->base_qpair->req = req; - ha->base_qpair->rsp = rsp; } /* @@ -395,9 +437,10 @@ static int qla2x00_alloc_queues(struct qla_hw_data *ha, struct req_que *req, set_bit(0, ha->req_qid_map); return 1; -fail_base_qpair: - kfree(ha->queue_pair_map); fail_qpair_map: + kfree(ha->base_qpair); + ha->base_qpair = NULL; +fail_base_qpair: kfree(ha->rsp_q_map); ha->rsp_q_map = NULL; fail_rsp_map: @@ -447,6 +490,15 @@ static void qla2x00_free_queues(struct qla_hw_data *ha) int cnt; unsigned long flags; + if (ha->queue_pair_map) { + kfree(ha->queue_pair_map); + ha->queue_pair_map = NULL; + } + if (ha->base_qpair) { + kfree(ha->base_qpair); + ha->base_qpair = NULL; + } + spin_lock_irqsave(&ha->hardware_lock, flags); for (cnt = 0; cnt < ha->max_req_queues; cnt++) { if (!test_bit(cnt, ha->req_qid_map)) @@ -658,8 +710,10 @@ qla2x00_sp_free_dma(void *ptr) } end: - CMD_SP(cmd) = NULL; - qla2x00_rel_sp(sp); + if ((sp->type != SRB_NVME_CMD) && (sp->type != SRB_NVME_LS)) { + CMD_SP(cmd) = NULL; + qla2x00_rel_sp(sp); + } } void @@ -1062,9 +1116,9 @@ static inline int test_fcport_count(scsi_qla_host_t *vha) int res; spin_lock_irqsave(&ha->tgt.sess_lock, flags); - ql_dbg(ql_dbg_init, vha, 0xffff, - "tgt %p, fcport_count=%d\n", - vha, vha->fcport_count); + ql_dbg(ql_dbg_init, vha, 0x00ec, + "tgt %p, fcport_count=%d\n", + vha, vha->fcport_count); res = (vha->fcport_count == 0); spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); @@ -1645,8 +1699,9 @@ qla2x00_abort_all_cmds(scsi_qla_host_t *vha, int res) srb_t *sp; struct qla_hw_data *ha = vha->hw; struct req_que *req; - - qlt_host_reset_handler(ha); + struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; + struct qla_tgt_cmd *cmd; + uint8_t trace = 0; spin_lock_irqsave(&ha->hardware_lock, flags); for (que = 0; que < ha->max_req_queues; que++) { @@ -1658,27 +1713,65 @@ qla2x00_abort_all_cmds(scsi_qla_host_t *vha, int res) for (cnt = 1; cnt < req->num_outstanding_cmds; cnt++) { sp = req->outstanding_cmds[cnt]; if (sp) { - /* Don't abort commands in adapter during EEH - * recovery as it's not accessible/responding. - */ - if (GET_CMD_SP(sp) && !ha->flags.eeh_busy && - (sp->type == SRB_SCSI_CMD)) { - /* 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() - - * ends the SCSI command (with result 'res'). - */ - sp_get(sp); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - status = qla2xxx_eh_abort(GET_CMD_SP(sp)); - spin_lock_irqsave(&ha->hardware_lock, flags); - /* Get rid of extra reference if immediate exit - * from ql2xxx_eh_abort */ - if (status == FAILED && (qla2x00_isp_reg_stat(ha))) - atomic_dec(&sp->ref_count); - } req->outstanding_cmds[cnt] = NULL; - sp->done(sp, res); + if (sp->cmd_type == TYPE_SRB) { + if ((sp->type == SRB_NVME_CMD) || + (sp->type == SRB_NVME_LS)) { + sp_get(sp); + spin_unlock_irqrestore( + &ha->hardware_lock, flags); + qla_nvme_abort(ha, sp); + spin_lock_irqsave( + &ha->hardware_lock, flags); + } else if (GET_CMD_SP(sp) && + !ha->flags.eeh_busy && + (sp->type == SRB_SCSI_CMD)) { + /* + * Don't abort commands in + * adapter during EEH + * recovery as it's not + * accessible/responding. + * + * 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() + * ends the SCSI command (with + * result 'res'). + */ + sp_get(sp); + spin_unlock_irqrestore( + &ha->hardware_lock, flags); + status = qla2xxx_eh_abort( + GET_CMD_SP(sp)); + spin_lock_irqsave( + &ha->hardware_lock, flags); + /* + * Get rid of extra reference + * if immediate exit from + * ql2xxx_eh_abort + */ + if (status == FAILED && + (qla2x00_isp_reg_stat(ha))) + atomic_dec( + &sp->ref_count); + } + sp->done(sp, res); + } else { + if (!vha->hw->tgt.tgt_ops || !tgt || + qla_ini_mode_enabled(vha)) { + if (!trace) + ql_dbg(ql_dbg_tgt_mgt, + vha, 0xf003, + "HOST-ABORT-HNDLR: dpc_flags=%lx. Target mode disabled\n", + vha->dpc_flags); + continue; + } + cmd = (struct qla_tgt_cmd *)sp; + qlt_abort_cmd_on_host_reset(cmd->vha, + cmd); + } } } } @@ -1957,7 +2050,7 @@ qla83xx_iospace_config(struct qla_hw_data *ha) /* Read MSIX vector size of the board */ pci_read_config_word(ha->pdev, QLA_83XX_PCI_MSIX_CONTROL, &msix); - ha->msix_count = msix + 1; + ha->msix_count = (msix & PCI_MSIX_FLAGS_QSIZE) + 1; /* * By default, driver uses at least two msix vectors * (default & rspq) @@ -1975,7 +2068,7 @@ qla83xx_iospace_config(struct qla_hw_data *ha) /* Queue pairs is the max value minus * the base queue pair */ ha->max_qpairs = ha->max_req_queues - 1; - ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0190, + ql_dbg_pci(ql_dbg_init, ha->pdev, 0x00e3, "Max no of queues pairs: %d.\n", ha->max_qpairs); } ql_log_pci(ql_log_info, ha->pdev, 0x011c, @@ -2653,7 +2746,6 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) ql_dbg_pci(ql_dbg_init, pdev, 0x000a, "Memory allocated for ha=%p.\n", ha); ha->pdev = pdev; - ha->tgt.enable_class_2 = ql2xenableclass2; INIT_LIST_HEAD(&ha->tgt.q_full_list); spin_lock_init(&ha->tgt.q_full_lock); spin_lock_init(&ha->tgt.sess_lock); @@ -3073,12 +3165,26 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) host->can_queue, base_vha->req, base_vha->mgmt_svr_loop_id, host->sg_tablesize); - if (ha->mqenable && qla_ini_mode_enabled(base_vha)) { + if (ha->mqenable) { + bool mq = false; + bool startit = false; ha->wq = alloc_workqueue("qla2xxx_wq", WQ_MEM_RECLAIM, 1); - /* Create start of day qpairs for Block MQ */ - if (shost_use_blk_mq(host)) { + + if (QLA_TGT_MODE_ENABLED()) { + mq = true; + startit = false; + } + + if ((ql2x_ini_mode == QLA2XXX_INI_MODE_ENABLED) && + shost_use_blk_mq(host)) { + mq = true; + startit = true; + } + + if (mq) { + /* Create start of day qpairs for Block MQ */ for (i = 0; i < ha->max_qpairs; i++) - qla2xxx_create_qpair(base_vha, 5, 0); + qla2xxx_create_qpair(base_vha, 5, 0, startit); } } @@ -3451,6 +3557,9 @@ qla2x00_remove_one(struct pci_dev *pdev) return; set_bit(UNLOADING, &base_vha->dpc_flags); + + qla_nvme_delete(base_vha); + dma_free_coherent(&ha->pdev->dev, base_vha->gnl.size, base_vha->gnl.l, base_vha->gnl.ldma); @@ -3601,10 +3710,10 @@ qla2x00_schedule_rport_del(struct scsi_qla_host *vha, fc_port_t *fcport, } else { int now; if (rport) { - ql_dbg(ql_dbg_disc, fcport->vha, 0xffff, - "%s %8phN. rport %p roles %x \n", - __func__, fcport->port_name, rport, - rport->roles); + ql_dbg(ql_dbg_disc, fcport->vha, 0x2109, + "%s %8phN. rport %p roles %x\n", + __func__, fcport->port_name, rport, + rport->roles); fc_remote_port_delete(rport); } qlt_do_generation_tick(vha, &now); @@ -3649,7 +3758,7 @@ void qla2x00_mark_device_lost(scsi_qla_host_t *vha, fc_port_t *fcport, if (fcport->login_retry == 0) { fcport->login_retry = vha->hw->login_retry_count; - ql_dbg(ql_dbg_disc, vha, 0x2067, + ql_dbg(ql_dbg_disc, vha, 0x20a3, "Port login retry %8phN, lid 0x%04x retry cnt=%d.\n", fcport->port_name, fcport->loop_id, fcport->login_retry); } @@ -3673,8 +3782,8 @@ qla2x00_mark_all_devices_lost(scsi_qla_host_t *vha, int defer) { fc_port_t *fcport; - ql_dbg(ql_dbg_disc, vha, 0xffff, - "Mark all dev lost\n"); + ql_dbg(ql_dbg_disc, vha, 0x20f1, + "Mark all dev lost\n"); list_for_each_entry(fcport, &vha->vp_fcports, list) { fcport->scan_state = 0; @@ -3986,6 +4095,9 @@ qla2x00_set_exlogins_buffer(scsi_qla_host_t *vha) if (!ql2xexlogins) return QLA_SUCCESS; + if (!IS_EXLOGIN_OFFLD_CAPABLE(ha)) + return QLA_SUCCESS; + ql_log(ql_log_info, vha, 0xd021, "EXLOGIN count: %d.\n", ql2xexlogins); max_cnt = 0; rval = qla_get_exlogin_status(vha, &size, &max_cnt); @@ -3996,27 +4108,33 @@ qla2x00_set_exlogins_buffer(scsi_qla_host_t *vha) } temp = (ql2xexlogins > max_cnt) ? max_cnt : ql2xexlogins; - ha->exlogin_size = (size * temp); - ql_log(ql_log_info, vha, 0xd024, - "EXLOGIN: max_logins=%d, portdb=0x%x, total=%d.\n", - max_cnt, size, temp); - - ql_log(ql_log_info, vha, 0xd025, "EXLOGIN: requested size=0x%x\n", - ha->exlogin_size); - - /* Get consistent memory for extended logins */ - ha->exlogin_buf = dma_alloc_coherent(&ha->pdev->dev, - ha->exlogin_size, &ha->exlogin_buf_dma, GFP_KERNEL); - if (!ha->exlogin_buf) { - ql_log_pci(ql_log_fatal, ha->pdev, 0xd02a, + temp *= size; + + if (temp != ha->exlogin_size) { + qla2x00_free_exlogin_buffer(ha); + ha->exlogin_size = temp; + + ql_log(ql_log_info, vha, 0xd024, + "EXLOGIN: max_logins=%d, portdb=0x%x, total=%d.\n", + max_cnt, size, temp); + + ql_log(ql_log_info, vha, 0xd025, + "EXLOGIN: requested size=0x%x\n", ha->exlogin_size); + + /* Get consistent memory for extended logins */ + ha->exlogin_buf = dma_alloc_coherent(&ha->pdev->dev, + ha->exlogin_size, &ha->exlogin_buf_dma, GFP_KERNEL); + if (!ha->exlogin_buf) { + ql_log_pci(ql_log_fatal, ha->pdev, 0xd02a, "Failed to allocate memory for exlogin_buf_dma.\n"); - return -ENOMEM; + return -ENOMEM; + } } /* Now configure the dma buffer */ rval = qla_set_exlogin_mem_cfg(vha, ha->exlogin_buf_dma); if (rval) { - ql_log(ql_log_fatal, vha, 0x00cf, + ql_log(ql_log_fatal, vha, 0xd033, "Setup extended login buffer ****FAILED****.\n"); qla2x00_free_exlogin_buffer(ha); } @@ -4041,19 +4159,50 @@ qla2x00_free_exlogin_buffer(struct qla_hw_data *ha) } } +static void +qla2x00_number_of_exch(scsi_qla_host_t *vha, u32 *ret_cnt, u16 max_cnt) +{ + u32 temp; + *ret_cnt = FW_DEF_EXCHANGES_CNT; + + if (qla_ini_mode_enabled(vha)) { + if (ql2xiniexchg > max_cnt) + ql2xiniexchg = max_cnt; + + if (ql2xiniexchg > FW_DEF_EXCHANGES_CNT) + *ret_cnt = ql2xiniexchg; + } else if (qla_tgt_mode_enabled(vha)) { + if (ql2xexchoffld > max_cnt) + ql2xexchoffld = max_cnt; + + if (ql2xexchoffld > FW_DEF_EXCHANGES_CNT) + *ret_cnt = ql2xexchoffld; + } else if (qla_dual_mode_enabled(vha)) { + temp = ql2xiniexchg + ql2xexchoffld; + if (temp > max_cnt) { + ql2xiniexchg -= (temp - max_cnt)/2; + ql2xexchoffld -= (((temp - max_cnt)/2) + 1); + temp = max_cnt; + } + + if (temp > FW_DEF_EXCHANGES_CNT) + *ret_cnt = temp; + } +} + int qla2x00_set_exchoffld_buffer(scsi_qla_host_t *vha) { int rval; - uint16_t size, max_cnt, temp; + u16 size, max_cnt; + u32 temp; struct qla_hw_data *ha = vha->hw; - /* Return if we don't need to alloacate any extended logins */ - if (!ql2xexchoffld) + if (!ha->flags.exchoffld_enabled) return QLA_SUCCESS; - ql_log(ql_log_info, vha, 0xd014, - "Exchange offload count: %d.\n", ql2xexlogins); + if (!IS_EXCHG_OFFLD_CAPABLE(ha)) + return QLA_SUCCESS; max_cnt = 0; rval = qla_get_exchoffld_status(vha, &size, &max_cnt); @@ -4063,30 +4212,45 @@ qla2x00_set_exchoffld_buffer(scsi_qla_host_t *vha) return rval; } - temp = (ql2xexchoffld > max_cnt) ? max_cnt : ql2xexchoffld; - ha->exchoffld_size = (size * temp); - ql_log(ql_log_info, vha, 0xd016, - "Exchange offload: max_count=%d, buffers=0x%x, total=%d.\n", - max_cnt, size, temp); - - ql_log(ql_log_info, vha, 0xd017, - "Exchange Buffers requested size = 0x%x\n", ha->exchoffld_size); + qla2x00_number_of_exch(vha, &temp, max_cnt); + temp *= size; - /* Get consistent memory for extended logins */ - ha->exchoffld_buf = dma_alloc_coherent(&ha->pdev->dev, - ha->exchoffld_size, &ha->exchoffld_buf_dma, GFP_KERNEL); - if (!ha->exchoffld_buf) { - ql_log_pci(ql_log_fatal, ha->pdev, 0xd013, - "Failed to allocate memory for exchoffld_buf_dma.\n"); - return -ENOMEM; + if (temp != ha->exchoffld_size) { + qla2x00_free_exchoffld_buffer(ha); + ha->exchoffld_size = temp; + + ql_log(ql_log_info, vha, 0xd016, + "Exchange offload: max_count=%d, buffers=0x%x, total=%d.\n", + max_cnt, size, temp); + + ql_log(ql_log_info, vha, 0xd017, + "Exchange Buffers requested size = 0x%x\n", + ha->exchoffld_size); + + /* Get consistent memory for extended logins */ + ha->exchoffld_buf = dma_alloc_coherent(&ha->pdev->dev, + ha->exchoffld_size, &ha->exchoffld_buf_dma, GFP_KERNEL); + if (!ha->exchoffld_buf) { + ql_log_pci(ql_log_fatal, ha->pdev, 0xd013, + "Failed to allocate memory for exchoffld_buf_dma.\n"); + return -ENOMEM; + } } /* Now configure the dma buffer */ - rval = qla_set_exchoffld_mem_cfg(vha, ha->exchoffld_buf_dma); + rval = qla_set_exchoffld_mem_cfg(vha); if (rval) { ql_log(ql_log_fatal, vha, 0xd02e, "Setup exchange offload buffer ****FAILED****.\n"); qla2x00_free_exchoffld_buffer(ha); + } else { + /* re-adjust number of target exchange */ + struct init_cb_81xx *icb = (struct init_cb_81xx *)ha->init_cb; + + if (qla_ini_mode_enabled(vha)) + icb->exchange_count = 0; + else + icb->exchange_count = cpu_to_le16(ql2xexchoffld); } return rval; @@ -4292,6 +4456,7 @@ struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht, INIT_LIST_HEAD(&vha->plogi_ack_list); INIT_LIST_HEAD(&vha->qp_list); INIT_LIST_HEAD(&vha->gnl.fcports); + INIT_LIST_HEAD(&vha->nvme_rport_list); spin_lock_init(&vha->work_lock); spin_lock_init(&vha->cmd_list_lock); @@ -4303,7 +4468,7 @@ struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht, vha->gnl.l = dma_alloc_coherent(&ha->pdev->dev, vha->gnl.size, &vha->gnl.ldma, GFP_KERNEL); if (!vha->gnl.l) { - ql_log(ql_log_fatal, vha, 0xffff, + ql_log(ql_log_fatal, vha, 0xd04a, "Alloc failed for name list.\n"); scsi_remove_host(vha->host); return NULL; @@ -4581,6 +4746,9 @@ qla2x00_do_work(struct scsi_qla_host *vha) qla24xx_async_gpdb(vha, e->u.fcport.fcport, e->u.fcport.opt); break; + case QLA_EVT_PRLI: + qla24xx_async_prli(vha, e->u.fcport.fcport); + break; case QLA_EVT_GPSC: qla24xx_async_gpsc(vha, e->u.fcport.fcport); break; @@ -4620,7 +4788,7 @@ void qla2x00_relogin(struct scsi_qla_host *vha) fcport->login_retry && !(fcport->flags & FCF_ASYNC_SENT)) { fcport->login_retry--; if (fcport->flags & FCF_FABRIC_DEVICE) { - ql_dbg(ql_dbg_disc, fcport->vha, 0xffff, + ql_dbg(ql_dbg_disc, fcport->vha, 0x2108, "%s %8phC DS %d LS %d\n", __func__, fcport->port_name, fcport->disc_state, fcport->fw_login_state); @@ -5800,6 +5968,8 @@ qla2x00_timer(scsi_qla_host_t *vha) sp = req->outstanding_cmds[index]; if (!sp) continue; + if (sp->cmd_type != TYPE_SRB) + continue; if (sp->type != SRB_SCSI_CMD) continue; sfcp = sp->fcport; @@ -5851,6 +6021,18 @@ qla2x00_timer(scsi_qla_host_t *vha) if (!list_empty(&vha->work_list)) start_dpc++; + /* + * FC-NVME + * see if the active AEN count has changed from what was last reported. + */ + if (atomic_read(&vha->nvme_active_aen_cnt) != vha->nvme_last_rptd_aen) { + vha->nvme_last_rptd_aen = + atomic_read(&vha->nvme_active_aen_cnt); + ql_log(ql_log_info, vha, 0x3002, + "reporting new aen count of %d to the fw\n", + vha->nvme_last_rptd_aen); + } + /* Schedule the DPC routine if needed */ if ((test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) || test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags) || diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index e766d8412384..2a0173e5d10e 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -59,13 +59,20 @@ MODULE_PARM_DESC(qlini_mode, "when ready " "\"enabled\" (default) - initiator mode will always stay enabled."); -static int ql_dm_tgt_ex_pct = 50; +static int ql_dm_tgt_ex_pct = 0; module_param(ql_dm_tgt_ex_pct, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(ql_dm_tgt_ex_pct, "For Dual Mode (qlini_mode=dual), this parameter determines " "the percentage of exchanges/cmds FW will allocate resources " "for Target mode."); +int ql2xuctrlirq = 1; +module_param(ql2xuctrlirq, int, 0644); +MODULE_PARM_DESC(ql2xuctrlirq, + "User to control IRQ placement via smp_affinity." + "Valid with qlini_mode=disabled." + "1(default): enable"); + int ql2x_ini_mode = QLA2XXX_INI_MODE_EXCLUSIVE; static int temp_sam_status = SAM_STAT_BUSY; @@ -110,18 +117,17 @@ enum fcp_resp_rsp_codes { /* Predefs for callbacks handed to qla2xxx LLD */ static void qlt_24xx_atio_pkt(struct scsi_qla_host *ha, struct atio_from_isp *pkt, uint8_t); -static void qlt_response_pkt(struct scsi_qla_host *ha, response_t *pkt); +static void qlt_response_pkt(struct scsi_qla_host *ha, struct rsp_que *rsp, + response_t *pkt); static int qlt_issue_task_mgmt(struct fc_port *sess, u64 lun, int fn, void *iocb, int flags); -static void qlt_send_term_exchange(struct scsi_qla_host *ha, struct qla_tgt_cmd +static void qlt_send_term_exchange(struct qla_qpair *, struct qla_tgt_cmd *cmd, struct atio_from_isp *atio, int ha_locked, int ul_abort); -static void qlt_abort_cmd_on_host_reset(struct scsi_qla_host *vha, - struct qla_tgt_cmd *cmd); static void qlt_alloc_qfull_cmd(struct scsi_qla_host *vha, struct atio_from_isp *atio, uint16_t status, int qfull); static void qlt_disable_vha(struct scsi_qla_host *vha); static void qlt_clear_tgt_db(struct qla_tgt *tgt); -static void qlt_send_notify_ack(struct scsi_qla_host *vha, +static void qlt_send_notify_ack(struct qla_qpair *qpair, struct imm_ntfy_from_isp *ntfy, uint32_t add_flags, uint16_t resp_code, int resp_code_valid, uint16_t srr_flags, uint16_t srr_reject_code, uint8_t srr_explan); @@ -132,6 +138,8 @@ static struct fc_port *qlt_create_sess(struct scsi_qla_host *vha, void qlt_unreg_sess(struct fc_port *sess); static void qlt_24xx_handle_abts(struct scsi_qla_host *, struct abts_recv_from_24xx *); +static void qlt_send_busy(struct qla_qpair *, struct atio_from_isp *, + uint16_t); /* * Global Variables @@ -200,8 +208,8 @@ struct scsi_qla_host *qlt_find_host_by_d_id(struct scsi_qla_host *vha, host = btree_lookup32(&vha->hw->tgt.host_map, key); if (!host) - ql_dbg(ql_dbg_tgt_mgt, vha, 0xffff, - "Unable to find host %06x\n", key); + ql_dbg(ql_dbg_tgt_mgt, vha, 0xf005, + "Unable to find host %06x\n", key); return host; } @@ -245,26 +253,22 @@ static inline void qlt_decr_num_pend_cmds(struct scsi_qla_host *vha) static void qlt_queue_unknown_atio(scsi_qla_host_t *vha, - struct atio_from_isp *atio, uint8_t ha_locked) + struct atio_from_isp *atio, uint8_t ha_locked) { struct qla_tgt_sess_op *u; struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; unsigned long flags; if (tgt->tgt_stop) { - ql_dbg(ql_dbg_async, vha, 0xffff, - "qla_target(%d): dropping unknown ATIO_TYPE7, " - "because tgt is being stopped", vha->vp_idx); + ql_dbg(ql_dbg_async, vha, 0x502c, + "qla_target(%d): dropping unknown ATIO_TYPE7, because tgt is being stopped", + vha->vp_idx); goto out_term; } u = kzalloc(sizeof(*u), GFP_ATOMIC); - if (u == NULL) { - ql_dbg(ql_dbg_async, vha, 0xffff, - "Alloc of struct unknown_atio (size %zd) failed", sizeof(*u)); - /* It should be harmless and on the next retry should work well */ + if (u == NULL) goto out_term; - } u->vha = vha; memcpy(&u->atio, atio, sizeof(*atio)); @@ -280,7 +284,7 @@ out: return; out_term: - qlt_send_term_exchange(vha, NULL, atio, ha_locked, 0); + qlt_send_term_exchange(vha->hw->base_qpair, NULL, atio, ha_locked, 0); goto out; } @@ -295,29 +299,28 @@ static void qlt_try_to_dequeue_unknown_atios(struct scsi_qla_host *vha, list_for_each_entry_safe(u, t, &vha->unknown_atio_list, cmd_list) { if (u->aborted) { - ql_dbg(ql_dbg_async, vha, 0xffff, - "Freeing unknown %s %p, because of Abort", + ql_dbg(ql_dbg_async, vha, 0x502e, + "Freeing unknown %s %p, because of Abort\n", "ATIO_TYPE7", u); - qlt_send_term_exchange(vha, NULL, &u->atio, - ha_locked, 0); + qlt_send_term_exchange(vha->hw->base_qpair, NULL, + &u->atio, ha_locked, 0); goto abort; } host = qlt_find_host_by_d_id(vha, u->atio.u.isp24.fcp_hdr.d_id); if (host != NULL) { - ql_dbg(ql_dbg_async, vha, 0xffff, - "Requeuing unknown ATIO_TYPE7 %p", u); + ql_dbg(ql_dbg_async, vha, 0x502f, + "Requeuing unknown ATIO_TYPE7 %p\n", u); qlt_24xx_atio_pkt(host, &u->atio, ha_locked); } else if (tgt->tgt_stop) { - ql_dbg(ql_dbg_async, vha, 0xffff, - "Freeing unknown %s %p, because tgt is being stopped", - "ATIO_TYPE7", u); - qlt_send_term_exchange(vha, NULL, &u->atio, - ha_locked, 0); + ql_dbg(ql_dbg_async, vha, 0x503a, + "Freeing unknown %s %p, because tgt is being stopped\n", + "ATIO_TYPE7", u); + qlt_send_term_exchange(vha->hw->base_qpair, NULL, + &u->atio, ha_locked, 0); } else { - ql_dbg(ql_dbg_async, vha, 0xffff, - "u %p, vha %p, host %p, sched again..", u, - vha, host); + ql_dbg(ql_dbg_async, vha, 0x503d, + "Reschedule u %p, vha %p, host %p\n", u, vha, host); if (!queued) { queued = 1; schedule_delayed_work(&vha->unknown_atio_work, @@ -380,6 +383,8 @@ static bool qlt_24xx_atio_pkt_all_vps(struct scsi_qla_host *vha, struct imm_ntfy_from_isp *entry = (struct imm_ntfy_from_isp *)atio; + qlt_issue_marker(vha, ha_locked); + if ((entry->u.isp24.vp_index != 0xFF) && (entry->u.isp24.nport_handle != 0xFFFF)) { host = qlt_find_host_by_vp_idx(vha, @@ -411,7 +416,7 @@ static bool qlt_24xx_atio_pkt_all_vps(struct scsi_qla_host *vha, unsigned long flags; if (unlikely(!host)) { - ql_dbg(ql_dbg_tgt, vha, 0xffff, + ql_dbg(ql_dbg_tgt, vha, 0xe00a, "qla_target(%d): Response pkt (ABTS_RECV_24XX) " "received, with unknown vp_index %d\n", vha->vp_idx, entry->vp_index); @@ -437,7 +442,8 @@ static bool qlt_24xx_atio_pkt_all_vps(struct scsi_qla_host *vha, return false; } -void qlt_response_pkt_all_vps(struct scsi_qla_host *vha, response_t *pkt) +void qlt_response_pkt_all_vps(struct scsi_qla_host *vha, + struct rsp_que *rsp, response_t *pkt) { switch (pkt->entry_type) { case CTIO_CRC2: @@ -456,7 +462,7 @@ void qlt_response_pkt_all_vps(struct scsi_qla_host *vha, response_t *pkt) vha->vp_idx, entry->vp_index); break; } - qlt_response_pkt(host, pkt); + qlt_response_pkt(host, rsp, pkt); break; } @@ -474,7 +480,7 @@ void qlt_response_pkt_all_vps(struct scsi_qla_host *vha, response_t *pkt) vha->vp_idx, entry->u.isp24.vp_index); break; } - qlt_response_pkt(host, pkt); + qlt_response_pkt(host, rsp, pkt); break; } @@ -496,7 +502,7 @@ void qlt_response_pkt_all_vps(struct scsi_qla_host *vha, response_t *pkt) break; } } - qlt_response_pkt(host, pkt); + qlt_response_pkt(host, rsp, pkt); break; } @@ -513,7 +519,7 @@ void qlt_response_pkt_all_vps(struct scsi_qla_host *vha, response_t *pkt) "vp_index %d\n", vha->vp_idx, entry->vp_index); break; } - qlt_response_pkt(host, pkt); + qlt_response_pkt(host, rsp, pkt); break; } @@ -530,12 +536,12 @@ void qlt_response_pkt_all_vps(struct scsi_qla_host *vha, response_t *pkt) "vp_index %d\n", vha->vp_idx, entry->vp_index); break; } - qlt_response_pkt(host, pkt); + qlt_response_pkt(host, rsp, pkt); break; } default: - qlt_response_pkt(vha, pkt); + qlt_response_pkt(vha, rsp, pkt); break; } @@ -565,13 +571,13 @@ void qla2x00_async_nack_sp_done(void *s, int res) struct scsi_qla_host *vha = sp->vha; unsigned long flags; - ql_dbg(ql_dbg_disc, vha, 0xffff, - "Async done-%s res %x %8phC type %d\n", - sp->name, res, sp->fcport->port_name, sp->type); + ql_dbg(ql_dbg_disc, vha, 0x20f2, + "Async done-%s res %x %8phC type %d\n", + sp->name, res, sp->fcport->port_name, sp->type); spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); sp->fcport->flags &= ~FCF_ASYNC_SENT; - sp->fcport->chip_reset = vha->hw->chip_reset; + sp->fcport->chip_reset = vha->hw->base_qpair->chip_reset; switch (sp->type) { case SRB_NACK_PLOGI: @@ -593,19 +599,19 @@ void qla2x00_async_nack_sp_done(void *s, int res) if (!IS_IIDMA_CAPABLE(vha->hw) || !vha->hw->flags.gpsc_supported) { - ql_dbg(ql_dbg_disc, vha, 0xffff, - "%s %d %8phC post upd_fcport fcp_cnt %d\n", - __func__, __LINE__, - sp->fcport->port_name, - vha->fcport_count); + ql_dbg(ql_dbg_disc, vha, 0x20f3, + "%s %d %8phC post upd_fcport fcp_cnt %d\n", + __func__, __LINE__, + sp->fcport->port_name, + vha->fcport_count); qla24xx_post_upd_fcport_work(vha, sp->fcport); } else { - ql_dbg(ql_dbg_disc, vha, 0xffff, - "%s %d %8phC post gpsc fcp_cnt %d\n", - __func__, __LINE__, - sp->fcport->port_name, - vha->fcport_count); + ql_dbg(ql_dbg_disc, vha, 0x20f5, + "%s %d %8phC post gpsc fcp_cnt %d\n", + __func__, __LINE__, + sp->fcport->port_name, + vha->fcport_count); qla24xx_post_gpsc_work(vha, sp->fcport); } @@ -664,9 +670,9 @@ int qla24xx_async_notify_ack(scsi_qla_host_t *vha, fc_port_t *fcport, if (rval != QLA_SUCCESS) goto done_free_sp; - ql_dbg(ql_dbg_disc, vha, 0xffff, - "Async-%s %8phC hndl %x %s\n", - sp->name, fcport->port_name, sp->handle, c); + ql_dbg(ql_dbg_disc, vha, 0x20f4, + "Async-%s %8phC hndl %x %s\n", + sp->name, fcport->port_name, sp->handle, c); return rval; @@ -688,7 +694,7 @@ void qla24xx_do_nack_work(struct scsi_qla_host *vha, struct qla_work_evt *e) t = qlt_create_sess(vha, e->u.nack.fcport, 0); mutex_unlock(&vha->vha_tgt.tgt_mutex); if (t) { - ql_log(ql_log_info, vha, 0xffff, + ql_log(ql_log_info, vha, 0xd034, "%s create sess success %p", __func__, t); spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); /* create sess has an extra kref */ @@ -757,7 +763,7 @@ void qlt_fc_port_added(struct scsi_qla_host *vha, fc_port_t *fcport) } if (!kref_get_unless_zero(&sess->sess_kref)) { - ql_dbg(ql_dbg_disc, vha, 0xffff, + ql_dbg(ql_dbg_disc, vha, 0x2107, "%s: kref_get fail sess %8phC \n", __func__, sess->port_name); spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); @@ -957,7 +963,6 @@ static void qlt_free_session_done(struct work_struct *work) sess->logout_on_delete, sess->keep_nport_handle, sess->send_els_logo); - if (!IS_SW_RESV_ADDR(sess->d_id)) { if (sess->send_els_logo) { qlt_port_logo_t logo; @@ -1026,7 +1031,7 @@ static void qlt_free_session_done(struct work_struct *work) sess->login_succ = 0; } - if (sess->chip_reset != sess->vha->hw->chip_reset) + if (sess->chip_reset != ha->base_qpair->chip_reset) qla2x00_clear_loop_id(sess); if (sess->conflict) { @@ -1098,7 +1103,7 @@ void qlt_unreg_sess(struct fc_port *sess) { struct scsi_qla_host *vha = sess->vha; - ql_dbg(ql_dbg_disc, sess->vha, 0xffff, + ql_dbg(ql_dbg_disc, sess->vha, 0x210a, "%s sess %p for deletion %8phC\n", __func__, sess, sess->port_name); @@ -1112,6 +1117,9 @@ void qlt_unreg_sess(struct fc_port *sess) sess->last_rscn_gen = sess->rscn_gen; sess->last_login_gen = sess->login_gen; + if (sess->nvme_flag & NVME_FLAG_REGISTERED) + schedule_work(&sess->nvme_del_work); + INIT_WORK(&sess->free_work, qlt_free_session_done); schedule_work(&sess->free_work); } @@ -1156,7 +1164,7 @@ static int qlt_reset(struct scsi_qla_host *vha, void *iocb, int mcmd) static void qla24xx_chk_fcp_state(struct fc_port *sess) { - if (sess->chip_reset != sess->vha->hw->chip_reset) { + if (sess->chip_reset != sess->vha->hw->base_qpair->chip_reset) { sess->logout_on_delete = 0; sess->logo_ack_needed = 0; sess->fw_login_state = DSC_LS_PORT_UNAVAIL; @@ -1288,7 +1296,7 @@ static struct fc_port *qlt_create_sess( if (fcport->se_sess) { if (!kref_get_unless_zero(&sess->sess_kref)) { - ql_dbg(ql_dbg_disc, vha, 0xffff, + ql_dbg(ql_dbg_disc, vha, 0x20f6, "%s: kref_get_unless_zero failed for %8phC\n", __func__, sess->port_name); return NULL; @@ -1310,7 +1318,7 @@ static struct fc_port *qlt_create_sess( if (ha->tgt.tgt_ops->check_initiator_node_acl(vha, &fcport->port_name[0], sess) < 0) { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xffff, + ql_dbg(ql_dbg_tgt_mgt, vha, 0xf015, "(%d) %8phC check_initiator_node_acl failed\n", vha->vp_idx, fcport->port_name); return NULL; @@ -1321,7 +1329,7 @@ static struct fc_port *qlt_create_sess( * fc_port access across ->tgt.sess_lock reaquire. */ if (!kref_get_unless_zero(&sess->sess_kref)) { - ql_dbg(ql_dbg_disc, vha, 0xffff, + ql_dbg(ql_dbg_disc, vha, 0x20f7, "%s: kref_get_unless_zero failed for %8phC\n", __func__, sess->port_name); return NULL; @@ -1432,6 +1440,8 @@ int qlt_stop_phase1(struct qla_tgt *tgt) if (npiv_vports) { mutex_unlock(&qla_tgt_mutex); + ql_dbg(ql_dbg_tgt_mgt, vha, 0xf021, + "NPIV is in use. Can not stop target\n"); return -EPERM; } } @@ -1442,7 +1452,7 @@ int qlt_stop_phase1(struct qla_tgt *tgt) return -EPERM; } - ql_dbg(ql_dbg_tgt, vha, 0xe003, "Stopping target for host %ld(%p)\n", + ql_dbg(ql_dbg_tgt_mgt, vha, 0xe003, "Stopping target for host %ld(%p)\n", vha->host_no, vha); /* * Mutex needed to sync with qla_tgt_fc_port_[added,deleted]. @@ -1485,9 +1495,7 @@ EXPORT_SYMBOL(qlt_stop_phase1); /* Called by tcm_qla2xxx configfs code */ void qlt_stop_phase2(struct qla_tgt *tgt) { - struct qla_hw_data *ha = tgt->ha; - scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); - unsigned long flags; + scsi_qla_host_t *vha = tgt->vha; if (tgt->tgt_stopped) { ql_dbg(ql_dbg_tgt_mgt, vha, 0xf04f, @@ -1495,24 +1503,19 @@ void qlt_stop_phase2(struct qla_tgt *tgt) dump_stack(); return; } - - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf00b, - "Waiting for %d IRQ commands to complete (tgt %p)", - tgt->irq_cmd_count, tgt); + if (!tgt->tgt_stop) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0xf00b, + "%s: phase1 stop is not completed\n", __func__); + dump_stack(); + return; + } mutex_lock(&vha->vha_tgt.tgt_mutex); - spin_lock_irqsave(&ha->hardware_lock, flags); - while ((tgt->irq_cmd_count != 0) || (tgt->atio_irq_cmd_count != 0)) { - spin_unlock_irqrestore(&ha->hardware_lock, flags); - udelay(2); - spin_lock_irqsave(&ha->hardware_lock, flags); - } tgt->tgt_stop = 0; tgt->tgt_stopped = 1; - spin_unlock_irqrestore(&ha->hardware_lock, flags); mutex_unlock(&vha->vha_tgt.tgt_mutex); - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf00c, "Stop of tgt %p finished", + ql_dbg(ql_dbg_tgt_mgt, vha, 0xf00c, "Stop of tgt %p finished\n", tgt); } EXPORT_SYMBOL(qlt_stop_phase2); @@ -1521,10 +1524,36 @@ EXPORT_SYMBOL(qlt_stop_phase2); static void qlt_release(struct qla_tgt *tgt) { scsi_qla_host_t *vha = tgt->vha; + void *node; + u64 key = 0; + u16 i; + struct qla_qpair_hint *h; + + if ((vha->vha_tgt.qla_tgt != NULL) && !tgt->tgt_stop && + !tgt->tgt_stopped) + qlt_stop_phase1(tgt); if ((vha->vha_tgt.qla_tgt != NULL) && !tgt->tgt_stopped) qlt_stop_phase2(tgt); + for (i = 0; i < vha->hw->max_qpairs + 1; i++) { + unsigned long flags; + + h = &tgt->qphints[i]; + if (h->qpair) { + spin_lock_irqsave(h->qpair->qp_lock_ptr, flags); + list_del(&h->hint_elem); + spin_unlock_irqrestore(h->qpair->qp_lock_ptr, flags); + h->qpair = NULL; + } + } + kfree(tgt->qphints); + + btree_for_each_safe64(&tgt->lun_qpair_map, key, node) + btree_remove64(&tgt->lun_qpair_map, key); + + btree_destroy64(&tgt->lun_qpair_map); + vha->vha_tgt.qla_tgt = NULL; ql_dbg(ql_dbg_tgt_mgt, vha, 0xf00d, @@ -1568,11 +1597,12 @@ static int qlt_sched_sess_work(struct qla_tgt *tgt, int type, /* * ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire */ -static void qlt_send_notify_ack(struct scsi_qla_host *vha, +static void qlt_send_notify_ack(struct qla_qpair *qpair, struct imm_ntfy_from_isp *ntfy, uint32_t add_flags, uint16_t resp_code, int resp_code_valid, uint16_t srr_flags, uint16_t srr_reject_code, uint8_t srr_explan) { + struct scsi_qla_host *vha = qpair->vha; struct qla_hw_data *ha = vha->hw; request_t *pkt; struct nack_to_isp *nack; @@ -1582,11 +1612,7 @@ static void qlt_send_notify_ack(struct scsi_qla_host *vha, ql_dbg(ql_dbg_tgt, vha, 0xe004, "Sending NOTIFY_ACK (ha=%p)\n", ha); - /* Send marker if required */ - if (qlt_issue_marker(vha, 1) != QLA_SUCCESS) - return; - - pkt = (request_t *)qla2x00_alloc_iocbs(vha, NULL); + pkt = (request_t *)__qla2x00_alloc_iocbs(qpair, NULL); if (!pkt) { ql_dbg(ql_dbg_tgt, vha, 0xe049, "qla_target(%d): %s failed: unable to allocate " @@ -1627,16 +1653,17 @@ static void qlt_send_notify_ack(struct scsi_qla_host *vha, /* Memory Barrier */ wmb(); - qla2x00_start_iocbs(vha, vha->req); + qla2x00_start_iocbs(vha, qpair->req); } /* * ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire */ -static void qlt_24xx_send_abts_resp(struct scsi_qla_host *vha, +static void qlt_24xx_send_abts_resp(struct qla_qpair *qpair, struct abts_recv_from_24xx *abts, uint32_t status, bool ids_reversed) { + struct scsi_qla_host *vha = qpair->vha; struct qla_hw_data *ha = vha->hw; struct abts_resp_to_24xx *resp; uint32_t f_ctl; @@ -1646,11 +1673,8 @@ static void qlt_24xx_send_abts_resp(struct scsi_qla_host *vha, "Sending task mgmt ABTS response (ha=%p, atio=%p, status=%x\n", ha, abts, status); - /* Send marker if required */ - if (qlt_issue_marker(vha, 1) != QLA_SUCCESS) - return; - - resp = (struct abts_resp_to_24xx *)qla2x00_alloc_iocbs_ready(vha, NULL); + resp = (struct abts_resp_to_24xx *)qla2x00_alloc_iocbs_ready(qpair, + NULL); if (!resp) { ql_dbg(ql_dbg_tgt, vha, 0xe04a, "qla_target(%d): %s failed: unable to allocate " @@ -1706,7 +1730,10 @@ static void qlt_24xx_send_abts_resp(struct scsi_qla_host *vha, /* Memory Barrier */ wmb(); - qla2x00_start_iocbs(vha, vha->req); + if (qpair->reqq_start_iocbs) + qpair->reqq_start_iocbs(qpair); + else + qla2x00_start_iocbs(vha, qpair->req); } /* @@ -1719,11 +1746,9 @@ static void qlt_24xx_retry_term_exchange(struct scsi_qla_host *vha, ql_dbg(ql_dbg_tgt, vha, 0xe007, "Sending retry TERM EXCH CTIO7 (ha=%p)\n", vha->hw); - /* Send marker if required */ - if (qlt_issue_marker(vha, 1) != QLA_SUCCESS) - return; - ctio = (struct ctio7_to_24xx *)qla2x00_alloc_iocbs_ready(vha, NULL); + ctio = (struct ctio7_to_24xx *)qla2x00_alloc_iocbs_ready( + vha->hw->base_qpair, NULL); if (ctio == NULL) { ql_dbg(ql_dbg_tgt, vha, 0xe04b, "qla_target(%d): %s failed: unable to allocate " @@ -1754,7 +1779,8 @@ static void qlt_24xx_retry_term_exchange(struct scsi_qla_host *vha, wmb(); qla2x00_start_iocbs(vha, vha->req); - qlt_24xx_send_abts_resp(vha, (struct abts_recv_from_24xx *)entry, + qlt_24xx_send_abts_resp(vha->hw->base_qpair, + (struct abts_recv_from_24xx *)entry, FCP_TMF_CMPL, true); } @@ -1762,13 +1788,13 @@ static int abort_cmd_for_tag(struct scsi_qla_host *vha, uint32_t tag) { struct qla_tgt_sess_op *op; struct qla_tgt_cmd *cmd; + unsigned long flags; - spin_lock(&vha->cmd_list_lock); - + spin_lock_irqsave(&vha->cmd_list_lock, flags); list_for_each_entry(op, &vha->qla_sess_op_cmd_list, cmd_list) { if (tag == op->atio.u.isp24.exchange_addr) { op->aborted = true; - spin_unlock(&vha->cmd_list_lock); + spin_unlock_irqrestore(&vha->cmd_list_lock, flags); return 1; } } @@ -1776,7 +1802,7 @@ static int abort_cmd_for_tag(struct scsi_qla_host *vha, uint32_t tag) list_for_each_entry(op, &vha->unknown_atio_list, cmd_list) { if (tag == op->atio.u.isp24.exchange_addr) { op->aborted = true; - spin_unlock(&vha->cmd_list_lock); + spin_unlock_irqrestore(&vha->cmd_list_lock, flags); return 1; } } @@ -1784,12 +1810,12 @@ static int abort_cmd_for_tag(struct scsi_qla_host *vha, uint32_t tag) list_for_each_entry(cmd, &vha->qla_cmd_list, cmd_list) { if (tag == cmd->atio.u.isp24.exchange_addr) { cmd->aborted = 1; - spin_unlock(&vha->cmd_list_lock); + spin_unlock_irqrestore(&vha->cmd_list_lock, flags); return 1; } } + spin_unlock_irqrestore(&vha->cmd_list_lock, flags); - spin_unlock(&vha->cmd_list_lock); return 0; } @@ -1799,17 +1825,18 @@ static int abort_cmd_for_tag(struct scsi_qla_host *vha, uint32_t tag) * for the same lun) */ static void abort_cmds_for_lun(struct scsi_qla_host *vha, - uint32_t lun, uint8_t *s_id) + u64 lun, uint8_t *s_id) { struct qla_tgt_sess_op *op; struct qla_tgt_cmd *cmd; uint32_t key; + unsigned long flags; key = sid_to_key(s_id); - spin_lock(&vha->cmd_list_lock); + spin_lock_irqsave(&vha->cmd_list_lock, flags); list_for_each_entry(op, &vha->qla_sess_op_cmd_list, cmd_list) { uint32_t op_key; - uint32_t op_lun; + u64 op_lun; op_key = sid_to_key(op->atio.u.isp24.fcp_hdr.s_id); op_lun = scsilun_to_int( @@ -1831,7 +1858,7 @@ static void abort_cmds_for_lun(struct scsi_qla_host *vha, list_for_each_entry(cmd, &vha->qla_cmd_list, cmd_list) { uint32_t cmd_key; - uint32_t cmd_lun; + u64 cmd_lun; cmd_key = sid_to_key(cmd->atio.u.isp24.fcp_hdr.s_id); cmd_lun = scsilun_to_int( @@ -1839,7 +1866,7 @@ static void abort_cmds_for_lun(struct scsi_qla_host *vha, if (cmd_key == key && cmd_lun == lun) cmd->aborted = 1; } - spin_unlock(&vha->cmd_list_lock); + spin_unlock_irqrestore(&vha->cmd_list_lock, flags); } /* ha->hardware_lock supposed to be held on entry */ @@ -1849,18 +1876,15 @@ static int __qlt_24xx_handle_abts(struct scsi_qla_host *vha, struct qla_hw_data *ha = vha->hw; struct se_session *se_sess = sess->se_sess; struct qla_tgt_mgmt_cmd *mcmd; + struct qla_tgt_cmd *cmd; struct se_cmd *se_cmd; - u32 lun = 0; int rc; bool found_lun = false; unsigned long flags; spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); list_for_each_entry(se_cmd, &se_sess->sess_cmd_list, se_cmd_list) { - struct qla_tgt_cmd *cmd = - container_of(se_cmd, struct qla_tgt_cmd, se_cmd); if (se_cmd->tag == abts->exchange_addr_to_abort) { - lun = cmd->unpacked_lun; found_lun = true; break; } @@ -1871,7 +1895,8 @@ static int __qlt_24xx_handle_abts(struct scsi_qla_host *vha, if (!found_lun) { if (abort_cmd_for_tag(vha, abts->exchange_addr_to_abort)) { /* send TASK_ABORT response immediately */ - qlt_24xx_send_abts_resp(vha, abts, FCP_TMF_CMPL, false); + qlt_24xx_send_abts_resp(ha->base_qpair, abts, + FCP_TMF_CMPL, false); return 0; } else { ql_dbg(ql_dbg_tgt_mgt, vha, 0xf081, @@ -1894,12 +1919,14 @@ static int __qlt_24xx_handle_abts(struct scsi_qla_host *vha, } memset(mcmd, 0, sizeof(*mcmd)); + cmd = container_of(se_cmd, struct qla_tgt_cmd, se_cmd); mcmd->sess = sess; memcpy(&mcmd->orig_iocb.abts, abts, sizeof(mcmd->orig_iocb.abts)); - mcmd->reset_count = vha->hw->chip_reset; + mcmd->reset_count = ha->base_qpair->chip_reset; mcmd->tmr_func = QLA_TGT_ABTS; + mcmd->qpair = ha->base_qpair; - rc = ha->tgt.tgt_ops->handle_tmr(mcmd, lun, mcmd->tmr_func, + rc = ha->tgt.tgt_ops->handle_tmr(mcmd, cmd->unpacked_lun, mcmd->tmr_func, abts->exchange_addr_to_abort); if (rc != 0) { ql_dbg(ql_dbg_tgt_mgt, vha, 0xf052, @@ -1929,7 +1956,8 @@ static void qlt_24xx_handle_abts(struct scsi_qla_host *vha, ql_dbg(ql_dbg_tgt_mgt, vha, 0xf053, "qla_target(%d): ABTS: Abort Sequence not " "supported\n", vha->vp_idx); - qlt_24xx_send_abts_resp(vha, abts, FCP_TMF_REJECTED, false); + qlt_24xx_send_abts_resp(ha->base_qpair, abts, FCP_TMF_REJECTED, + false); return; } @@ -1937,7 +1965,8 @@ static void qlt_24xx_handle_abts(struct scsi_qla_host *vha, ql_dbg(ql_dbg_tgt_mgt, vha, 0xf010, "qla_target(%d): ABTS: Unknown Exchange " "Address received\n", vha->vp_idx); - qlt_24xx_send_abts_resp(vha, abts, FCP_TMF_REJECTED, false); + qlt_24xx_send_abts_resp(ha->base_qpair, abts, FCP_TMF_REJECTED, + false); return; } @@ -1963,8 +1992,8 @@ static void qlt_24xx_handle_abts(struct scsi_qla_host *vha, spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); if (rc != 0) { - qlt_24xx_send_abts_resp(vha, abts, FCP_TMF_REJECTED, - false); + qlt_24xx_send_abts_resp(ha->base_qpair, abts, + FCP_TMF_REJECTED, false); } return; } @@ -1972,7 +2001,8 @@ static void qlt_24xx_handle_abts(struct scsi_qla_host *vha, if (sess->deleted) { - qlt_24xx_send_abts_resp(vha, abts, FCP_TMF_REJECTED, false); + qlt_24xx_send_abts_resp(ha->base_qpair, abts, FCP_TMF_REJECTED, + false); return; } @@ -1981,7 +2011,8 @@ static void qlt_24xx_handle_abts(struct scsi_qla_host *vha, ql_dbg(ql_dbg_tgt_mgt, vha, 0xf054, "qla_target(%d): __qlt_24xx_handle_abts() failed: %d\n", vha->vp_idx, rc); - qlt_24xx_send_abts_resp(vha, abts, FCP_TMF_REJECTED, false); + qlt_24xx_send_abts_resp(ha->base_qpair, abts, FCP_TMF_REJECTED, + false); return; } } @@ -1989,9 +2020,10 @@ static void qlt_24xx_handle_abts(struct scsi_qla_host *vha, /* * ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire */ -static void qlt_24xx_send_task_mgmt_ctio(struct scsi_qla_host *ha, +static void qlt_24xx_send_task_mgmt_ctio(struct qla_qpair *qpair, struct qla_tgt_mgmt_cmd *mcmd, uint32_t resp_code) { + struct scsi_qla_host *ha = qpair->vha; struct atio_from_isp *atio = &mcmd->orig_iocb.atio; struct ctio7_to_24xx *ctio; uint16_t temp; @@ -2000,11 +2032,8 @@ static void qlt_24xx_send_task_mgmt_ctio(struct scsi_qla_host *ha, "Sending task mgmt CTIO7 (ha=%p, atio=%p, resp_code=%x\n", ha, atio, resp_code); - /* Send marker if required */ - if (qlt_issue_marker(ha, 1) != QLA_SUCCESS) - return; - ctio = (struct ctio7_to_24xx *)qla2x00_alloc_iocbs(ha, NULL); + ctio = (struct ctio7_to_24xx *)__qla2x00_alloc_iocbs(qpair, NULL); if (ctio == NULL) { ql_dbg(ql_dbg_tgt, ha, 0xe04c, "qla_target(%d): %s failed: unable to allocate " @@ -2022,8 +2051,9 @@ static void qlt_24xx_send_task_mgmt_ctio(struct scsi_qla_host *ha, ctio->initiator_id[1] = atio->u.isp24.fcp_hdr.s_id[1]; ctio->initiator_id[2] = atio->u.isp24.fcp_hdr.s_id[0]; ctio->exchange_addr = atio->u.isp24.exchange_addr; - ctio->u.status1.flags = (atio->u.isp24.attr << 9) | - cpu_to_le16(CTIO7_FLAGS_STATUS_MODE_1 | CTIO7_FLAGS_SEND_STATUS); + temp = (atio->u.isp24.attr << 9)| + CTIO7_FLAGS_STATUS_MODE_1 | CTIO7_FLAGS_SEND_STATUS; + ctio->u.status1.flags = cpu_to_le16(temp); temp = be16_to_cpu(atio->u.isp24.fcp_hdr.ox_id); ctio->u.status1.ox_id = cpu_to_le16(temp); ctio->u.status1.scsi_status = @@ -2033,7 +2063,10 @@ static void qlt_24xx_send_task_mgmt_ctio(struct scsi_qla_host *ha, /* Memory Barrier */ wmb(); - qla2x00_start_iocbs(ha, ha->req); + if (qpair->reqq_start_iocbs) + qpair->reqq_start_iocbs(qpair); + else + qla2x00_start_iocbs(ha, qpair->req); } void qlt_free_mcmd(struct qla_tgt_mgmt_cmd *mcmd) @@ -2046,12 +2079,13 @@ EXPORT_SYMBOL(qlt_free_mcmd); * ha->hardware_lock supposed to be held on entry. Might drop it, then * reacquire */ -void qlt_send_resp_ctio(scsi_qla_host_t *vha, struct qla_tgt_cmd *cmd, +void qlt_send_resp_ctio(struct qla_qpair *qpair, struct qla_tgt_cmd *cmd, uint8_t scsi_status, uint8_t sense_key, uint8_t asc, uint8_t ascq) { struct atio_from_isp *atio = &cmd->atio; struct ctio7_to_24xx *ctio; uint16_t temp; + struct scsi_qla_host *vha = cmd->vha; ql_dbg(ql_dbg_tgt_dif, vha, 0x3066, "Sending response CTIO7 (vha=%p, atio=%p, scsi_status=%02x, " @@ -2076,8 +2110,9 @@ void qlt_send_resp_ctio(scsi_qla_host_t *vha, struct qla_tgt_cmd *cmd, ctio->initiator_id[1] = atio->u.isp24.fcp_hdr.s_id[1]; ctio->initiator_id[2] = atio->u.isp24.fcp_hdr.s_id[0]; ctio->exchange_addr = atio->u.isp24.exchange_addr; - ctio->u.status1.flags = (atio->u.isp24.attr << 9) | - cpu_to_le16(CTIO7_FLAGS_STATUS_MODE_1 | CTIO7_FLAGS_SEND_STATUS); + temp = (atio->u.isp24.attr << 9) | + CTIO7_FLAGS_STATUS_MODE_1 | CTIO7_FLAGS_SEND_STATUS; + ctio->u.status1.flags = cpu_to_le16(temp); temp = be16_to_cpu(atio->u.isp24.fcp_hdr.ox_id); ctio->u.status1.ox_id = cpu_to_le16(temp); ctio->u.status1.scsi_status = @@ -2101,7 +2136,11 @@ void qlt_send_resp_ctio(scsi_qla_host_t *vha, struct qla_tgt_cmd *cmd, /* Memory Barrier */ wmb(); - qla2x00_start_iocbs(vha, vha->req); + if (qpair->reqq_start_iocbs) + qpair->reqq_start_iocbs(qpair); + else + qla2x00_start_iocbs(vha, qpair->req); + out: return; } @@ -2112,14 +2151,15 @@ void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *mcmd) struct scsi_qla_host *vha = mcmd->sess->vha; struct qla_hw_data *ha = vha->hw; unsigned long flags; + struct qla_qpair *qpair = mcmd->qpair; ql_dbg(ql_dbg_tgt_mgt, vha, 0xf013, "TM response mcmd (%p) status %#x state %#x", mcmd, mcmd->fc_tm_rsp, mcmd->flags); - spin_lock_irqsave(&ha->hardware_lock, flags); + spin_lock_irqsave(qpair->qp_lock_ptr, flags); - if (!vha->flags.online || mcmd->reset_count != ha->chip_reset) { + if (!vha->flags.online || mcmd->reset_count != qpair->chip_reset) { /* * Either the port is not online or this request was from * previous life, just abort the processing. @@ -2127,9 +2167,9 @@ void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *mcmd) ql_dbg(ql_dbg_async, vha, 0xe100, "RESET-TMR online/active/old-count/new-count = %d/%d/%d/%d.\n", vha->flags.online, qla2x00_reset_active(vha), - mcmd->reset_count, ha->chip_reset); + mcmd->reset_count, qpair->chip_reset); ha->tgt.tgt_ops->free_mcmd(mcmd); - spin_unlock_irqrestore(&ha->hardware_lock, flags); + spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); return; } @@ -2140,21 +2180,21 @@ void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *mcmd) ELS_PRLO || mcmd->orig_iocb.imm_ntfy.u.isp24.status_subcode == ELS_TPRLO) { - ql_dbg(ql_dbg_disc, vha, 0xffff, + ql_dbg(ql_dbg_disc, vha, 0x2106, "TM response logo %phC status %#x state %#x", mcmd->sess->port_name, mcmd->fc_tm_rsp, mcmd->flags); qlt_schedule_sess_for_deletion_lock(mcmd->sess); } else { - qlt_send_notify_ack(vha, &mcmd->orig_iocb.imm_ntfy, - 0, 0, 0, 0, 0, 0); + qlt_send_notify_ack(vha->hw->base_qpair, + &mcmd->orig_iocb.imm_ntfy, 0, 0, 0, 0, 0, 0); } } else { if (mcmd->orig_iocb.atio.u.raw.entry_type == ABTS_RECV_24XX) - qlt_24xx_send_abts_resp(vha, &mcmd->orig_iocb.abts, + qlt_24xx_send_abts_resp(qpair, &mcmd->orig_iocb.abts, mcmd->fc_tm_rsp, false); else - qlt_24xx_send_task_mgmt_ctio(vha, mcmd, + qlt_24xx_send_task_mgmt_ctio(qpair, mcmd, mcmd->fc_tm_rsp); } /* @@ -2166,7 +2206,7 @@ void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *mcmd) * qlt_xmit_tm_rsp() returns here.. */ ha->tgt.tgt_ops->free_mcmd(mcmd); - spin_unlock_irqrestore(&ha->hardware_lock, flags); + spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); } EXPORT_SYMBOL(qlt_xmit_tm_rsp); @@ -2178,7 +2218,7 @@ static int qlt_pci_map_calc_cnt(struct qla_tgt_prm *prm) BUG_ON(cmd->sg_cnt == 0); prm->sg = (struct scatterlist *)cmd->sg; - prm->seg_cnt = pci_map_sg(prm->tgt->ha->pdev, cmd->sg, + prm->seg_cnt = pci_map_sg(cmd->qpair->pdev, cmd->sg, cmd->sg_cnt, cmd->dma_data_direction); if (unlikely(prm->seg_cnt == 0)) goto out_err; @@ -2190,10 +2230,10 @@ static int qlt_pci_map_calc_cnt(struct qla_tgt_prm *prm) * If greater than four sg entries then we need to allocate * the continuation entries */ - if (prm->seg_cnt > prm->tgt->datasegs_per_cmd) + if (prm->seg_cnt > QLA_TGT_DATASEGS_PER_CMD_24XX) prm->req_cnt += DIV_ROUND_UP(prm->seg_cnt - - prm->tgt->datasegs_per_cmd, - prm->tgt->datasegs_per_cont); + QLA_TGT_DATASEGS_PER_CMD_24XX, + QLA_TGT_DATASEGS_PER_CONT_24XX); } else { /* DIF */ if ((cmd->se_cmd.prot_op == TARGET_PROT_DIN_INSERT) || @@ -2205,7 +2245,7 @@ static int qlt_pci_map_calc_cnt(struct qla_tgt_prm *prm) if (cmd->prot_sg_cnt) { prm->prot_sg = cmd->prot_sg; - prm->prot_seg_cnt = pci_map_sg(prm->tgt->ha->pdev, + prm->prot_seg_cnt = pci_map_sg(cmd->qpair->pdev, cmd->prot_sg, cmd->prot_sg_cnt, cmd->dma_data_direction); if (unlikely(prm->prot_seg_cnt == 0)) @@ -2225,7 +2265,7 @@ static int qlt_pci_map_calc_cnt(struct qla_tgt_prm *prm) return 0; out_err: - ql_dbg(ql_dbg_tgt, prm->cmd->vha, 0xe04d, + ql_dbg_qp(ql_dbg_tgt, prm->cmd->qpair, 0xe04d, "qla_target(%d): PCI mapping failed: sg_cnt=%d", 0, prm->cmd->sg_cnt); return -1; @@ -2233,53 +2273,50 @@ out_err: static void qlt_unmap_sg(struct scsi_qla_host *vha, struct qla_tgt_cmd *cmd) { - struct qla_hw_data *ha = vha->hw; - + struct qla_hw_data *ha; + struct qla_qpair *qpair; if (!cmd->sg_mapped) return; - pci_unmap_sg(ha->pdev, cmd->sg, cmd->sg_cnt, cmd->dma_data_direction); + qpair = cmd->qpair; + + pci_unmap_sg(qpair->pdev, cmd->sg, cmd->sg_cnt, + cmd->dma_data_direction); cmd->sg_mapped = 0; if (cmd->prot_sg_cnt) - pci_unmap_sg(ha->pdev, cmd->prot_sg, cmd->prot_sg_cnt, + pci_unmap_sg(qpair->pdev, cmd->prot_sg, cmd->prot_sg_cnt, cmd->dma_data_direction); if (!cmd->ctx) return; - + ha = vha->hw; if (cmd->ctx_dsd_alloced) qla2x00_clean_dsd_pool(ha, cmd->ctx); dma_pool_free(ha->dl_dma_pool, cmd->ctx, cmd->ctx->crc_ctx_dma); } -static int qlt_check_reserve_free_req(struct scsi_qla_host *vha, +static int qlt_check_reserve_free_req(struct qla_qpair *qpair, uint32_t req_cnt) { - uint32_t cnt, cnt_in; + uint32_t cnt; + struct req_que *req = qpair->req; - if (vha->req->cnt < (req_cnt + 2)) { - cnt = (uint16_t)RD_REG_DWORD(vha->req->req_q_out); - cnt_in = (uint16_t)RD_REG_DWORD(vha->req->req_q_in); + if (req->cnt < (req_cnt + 2)) { + cnt = (uint16_t)(qpair->use_shadow_reg ? *req->out_ptr : + RD_REG_DWORD_RELAXED(req->req_q_out)); - if (vha->req->ring_index < cnt) - vha->req->cnt = cnt - vha->req->ring_index; + if (req->ring_index < cnt) + req->cnt = cnt - req->ring_index; else - vha->req->cnt = vha->req->length - - (vha->req->ring_index - cnt); - - if (unlikely(vha->req->cnt < (req_cnt + 2))) { - ql_dbg(ql_dbg_io, vha, 0x305a, - "qla_target(%d): There is no room in the request ring: vha->req->ring_index=%d, vha->req->cnt=%d, req_cnt=%d Req-out=%d Req-in=%d Req-Length=%d\n", - vha->vp_idx, vha->req->ring_index, - vha->req->cnt, req_cnt, cnt, cnt_in, - vha->req->length); + req->cnt = req->length - (req->ring_index - cnt); + + if (unlikely(req->cnt < (req_cnt + 2))) return -EAGAIN; - } } - vha->req->cnt -= req_cnt; + req->cnt -= req_cnt; return 0; } @@ -2287,67 +2324,73 @@ static int qlt_check_reserve_free_req(struct scsi_qla_host *vha, /* * ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire */ -static inline void *qlt_get_req_pkt(struct scsi_qla_host *vha) +static inline void *qlt_get_req_pkt(struct req_que *req) { /* Adjust ring index. */ - vha->req->ring_index++; - if (vha->req->ring_index == vha->req->length) { - vha->req->ring_index = 0; - vha->req->ring_ptr = vha->req->ring; + req->ring_index++; + if (req->ring_index == req->length) { + req->ring_index = 0; + req->ring_ptr = req->ring; } else { - vha->req->ring_ptr++; + req->ring_ptr++; } - return (cont_entry_t *)vha->req->ring_ptr; + return (cont_entry_t *)req->ring_ptr; } /* ha->hardware_lock supposed to be held on entry */ -static inline uint32_t qlt_make_handle(struct scsi_qla_host *vha) +static inline uint32_t qlt_make_handle(struct qla_qpair *qpair) { - struct qla_hw_data *ha = vha->hw; uint32_t h; + int index; + uint8_t found = 0; + struct req_que *req = qpair->req; + + h = req->current_outstanding_cmd; + + for (index = 1; index < req->num_outstanding_cmds; index++) { + h++; + if (h == req->num_outstanding_cmds) + h = 1; - h = ha->tgt.current_handle; - /* always increment cmd handle */ - do { - ++h; - if (h > DEFAULT_OUTSTANDING_COMMANDS) - h = 1; /* 0 is QLA_TGT_NULL_HANDLE */ - if (h == ha->tgt.current_handle) { - ql_dbg(ql_dbg_io, vha, 0x305b, - "qla_target(%d): Ran out of " - "empty cmd slots in ha %p\n", vha->vp_idx, ha); - h = QLA_TGT_NULL_HANDLE; + if (h == QLA_TGT_SKIP_HANDLE) + continue; + + if (!req->outstanding_cmds[h]) { + found = 1; break; } - } while ((h == QLA_TGT_NULL_HANDLE) || - (h == QLA_TGT_SKIP_HANDLE) || - (ha->tgt.cmds[h-1] != NULL)); + } - if (h != QLA_TGT_NULL_HANDLE) - ha->tgt.current_handle = h; + if (found) { + req->current_outstanding_cmd = h; + } else { + ql_dbg(ql_dbg_io, qpair->vha, 0x305b, + "qla_target(%d): Ran out of empty cmd slots\n", + qpair->vha->vp_idx); + h = QLA_TGT_NULL_HANDLE; + } return h; } /* ha->hardware_lock supposed to be held on entry */ -static int qlt_24xx_build_ctio_pkt(struct qla_tgt_prm *prm, - struct scsi_qla_host *vha) +static int qlt_24xx_build_ctio_pkt(struct qla_qpair *qpair, + struct qla_tgt_prm *prm) { uint32_t h; struct ctio7_to_24xx *pkt; - struct qla_hw_data *ha = vha->hw; struct atio_from_isp *atio = &prm->cmd->atio; uint16_t temp; - pkt = (struct ctio7_to_24xx *)vha->req->ring_ptr; + pkt = (struct ctio7_to_24xx *)qpair->req->ring_ptr; prm->pkt = pkt; memset(pkt, 0, sizeof(*pkt)); pkt->entry_type = CTIO_TYPE7; pkt->entry_count = (uint8_t)prm->req_cnt; - pkt->vp_index = vha->vp_idx; + pkt->vp_index = prm->cmd->vp_idx; - h = qlt_make_handle(vha); + h = qlt_make_handle(qpair); if (unlikely(h == QLA_TGT_NULL_HANDLE)) { /* * CTIO type 7 from the firmware doesn't provide a way to @@ -2356,16 +2399,18 @@ static int qlt_24xx_build_ctio_pkt(struct qla_tgt_prm *prm, */ return -EAGAIN; } else - ha->tgt.cmds[h - 1] = prm->cmd; + qpair->req->outstanding_cmds[h] = (srb_t *)prm->cmd; - pkt->handle = h | CTIO_COMPLETION_HANDLE_MARK; - pkt->nport_handle = prm->cmd->loop_id; + pkt->handle = MAKE_HANDLE(qpair->req->id, h); + pkt->handle |= CTIO_COMPLETION_HANDLE_MARK; + pkt->nport_handle = cpu_to_le16(prm->cmd->loop_id); pkt->timeout = cpu_to_le16(QLA_TGT_TIMEOUT); pkt->initiator_id[0] = atio->u.isp24.fcp_hdr.s_id[2]; pkt->initiator_id[1] = atio->u.isp24.fcp_hdr.s_id[1]; pkt->initiator_id[2] = atio->u.isp24.fcp_hdr.s_id[0]; pkt->exchange_addr = atio->u.isp24.exchange_addr; - pkt->u.status0.flags |= (atio->u.isp24.attr << 9); + temp = atio->u.isp24.attr << 9; + pkt->u.status0.flags |= cpu_to_le16(temp); temp = be16_to_cpu(atio->u.isp24.fcp_hdr.ox_id); pkt->u.status0.ox_id = cpu_to_le16(temp); pkt->u.status0.relative_offset = cpu_to_le32(prm->cmd->offset); @@ -2377,17 +2422,16 @@ static int qlt_24xx_build_ctio_pkt(struct qla_tgt_prm *prm, * ha->hardware_lock supposed to be held on entry. We have already made sure * that there is sufficient amount of request entries to not drop it. */ -static void qlt_load_cont_data_segments(struct qla_tgt_prm *prm, - struct scsi_qla_host *vha) +static void qlt_load_cont_data_segments(struct qla_tgt_prm *prm) { int cnt; uint32_t *dword_ptr; - int enable_64bit_addressing = prm->tgt->tgt_enable_64bit_addr; /* Build continuation packets */ while (prm->seg_cnt > 0) { cont_a64_entry_t *cont_pkt64 = - (cont_a64_entry_t *)qlt_get_req_pkt(vha); + (cont_a64_entry_t *)qlt_get_req_pkt( + prm->cmd->qpair->req); /* * Make sure that from cont_pkt64 none of @@ -2401,30 +2445,18 @@ static void qlt_load_cont_data_segments(struct qla_tgt_prm *prm, cont_pkt64->entry_count = 1; cont_pkt64->sys_define = 0; - if (enable_64bit_addressing) { - cont_pkt64->entry_type = CONTINUE_A64_TYPE; - dword_ptr = - (uint32_t *)&cont_pkt64->dseg_0_address; - } else { - cont_pkt64->entry_type = CONTINUE_TYPE; - dword_ptr = - (uint32_t *)&((cont_entry_t *) - cont_pkt64)->dseg_0_address; - } + cont_pkt64->entry_type = CONTINUE_A64_TYPE; + dword_ptr = (uint32_t *)&cont_pkt64->dseg_0_address; /* Load continuation entry data segments */ for (cnt = 0; - cnt < prm->tgt->datasegs_per_cont && prm->seg_cnt; + cnt < QLA_TGT_DATASEGS_PER_CONT_24XX && prm->seg_cnt; cnt++, prm->seg_cnt--) { *dword_ptr++ = cpu_to_le32(pci_dma_lo32 (sg_dma_address(prm->sg))); - if (enable_64bit_addressing) { - *dword_ptr++ = - cpu_to_le32(pci_dma_hi32 - (sg_dma_address - (prm->sg))); - } + *dword_ptr++ = cpu_to_le32(pci_dma_hi32 + (sg_dma_address(prm->sg))); *dword_ptr++ = cpu_to_le32(sg_dma_len(prm->sg)); prm->sg = sg_next(prm->sg); @@ -2436,12 +2468,10 @@ static void qlt_load_cont_data_segments(struct qla_tgt_prm *prm, * ha->hardware_lock supposed to be held on entry. We have already made sure * that there is sufficient amount of request entries to not drop it. */ -static void qlt_load_data_segments(struct qla_tgt_prm *prm, - struct scsi_qla_host *vha) +static void qlt_load_data_segments(struct qla_tgt_prm *prm) { int cnt; uint32_t *dword_ptr; - int enable_64bit_addressing = prm->tgt->tgt_enable_64bit_addr; struct ctio7_to_24xx *pkt24 = (struct ctio7_to_24xx *)prm->pkt; pkt24->u.status0.transfer_length = cpu_to_le32(prm->cmd->bufflen); @@ -2464,21 +2494,20 @@ static void qlt_load_data_segments(struct qla_tgt_prm *prm, /* Load command entry data segments */ for (cnt = 0; - (cnt < prm->tgt->datasegs_per_cmd) && prm->seg_cnt; + (cnt < QLA_TGT_DATASEGS_PER_CMD_24XX) && prm->seg_cnt; cnt++, prm->seg_cnt--) { *dword_ptr++ = cpu_to_le32(pci_dma_lo32(sg_dma_address(prm->sg))); - if (enable_64bit_addressing) { - *dword_ptr++ = - cpu_to_le32(pci_dma_hi32( - sg_dma_address(prm->sg))); - } + + *dword_ptr++ = cpu_to_le32(pci_dma_hi32( + sg_dma_address(prm->sg))); + *dword_ptr++ = cpu_to_le32(sg_dma_len(prm->sg)); prm->sg = sg_next(prm->sg); } - qlt_load_cont_data_segments(prm, vha); + qlt_load_cont_data_segments(prm); } static inline int qlt_has_data(struct qla_tgt_cmd *cmd) @@ -2498,35 +2527,35 @@ static void qlt_print_dif_err(struct qla_tgt_prm *prm) /* ASCQ */ switch (prm->sense_buffer[13]) { case 1: - ql_dbg(ql_dbg_tgt_dif, vha, 0xffff, + ql_dbg(ql_dbg_tgt_dif, vha, 0xe00b, "BE detected Guard TAG ERR: lba[0x%llx|%lld] len[0x%x] " "se_cmd=%p tag[%x]", cmd->lba, cmd->lba, cmd->num_blks, &cmd->se_cmd, cmd->atio.u.isp24.exchange_addr); break; case 2: - ql_dbg(ql_dbg_tgt_dif, vha, 0xffff, + ql_dbg(ql_dbg_tgt_dif, vha, 0xe00c, "BE detected APP TAG ERR: lba[0x%llx|%lld] len[0x%x] " "se_cmd=%p tag[%x]", cmd->lba, cmd->lba, cmd->num_blks, &cmd->se_cmd, cmd->atio.u.isp24.exchange_addr); break; case 3: - ql_dbg(ql_dbg_tgt_dif, vha, 0xffff, + ql_dbg(ql_dbg_tgt_dif, vha, 0xe00f, "BE detected REF TAG ERR: lba[0x%llx|%lld] len[0x%x] " "se_cmd=%p tag[%x]", cmd->lba, cmd->lba, cmd->num_blks, &cmd->se_cmd, cmd->atio.u.isp24.exchange_addr); break; default: - ql_dbg(ql_dbg_tgt_dif, vha, 0xffff, + ql_dbg(ql_dbg_tgt_dif, vha, 0xe010, "BE detected Dif ERR: lba[%llx|%lld] len[%x] " "se_cmd=%p tag[%x]", cmd->lba, cmd->lba, cmd->num_blks, &cmd->se_cmd, cmd->atio.u.isp24.exchange_addr); break; } - ql_dump_buffer(ql_dbg_tgt_dif, vha, 0xffff, cmd->cdb, 16); + ql_dump_buffer(ql_dbg_tgt_dif, vha, 0xe011, cmd->cdb, 16); } } @@ -2537,24 +2566,23 @@ static int qlt_pre_xmit_response(struct qla_tgt_cmd *cmd, struct qla_tgt_prm *prm, int xmit_type, uint8_t scsi_status, uint32_t *full_req_cnt) { - struct qla_tgt *tgt = cmd->tgt; - struct scsi_qla_host *vha = tgt->vha; - struct qla_hw_data *ha = vha->hw; struct se_cmd *se_cmd = &cmd->se_cmd; + struct qla_qpair *qpair = cmd->qpair; prm->cmd = cmd; - prm->tgt = tgt; + prm->tgt = cmd->tgt; + prm->pkt = NULL; prm->rq_result = scsi_status; prm->sense_buffer = &cmd->sense_buffer[0]; prm->sense_buffer_len = TRANSPORT_SENSE_BUFFER; prm->sg = NULL; prm->seg_cnt = -1; prm->req_cnt = 1; + prm->residual = 0; prm->add_status_pkt = 0; - - /* Send marker if required */ - if (qlt_issue_marker(vha, 0) != QLA_SUCCESS) - return -EFAULT; + prm->prot_sg = NULL; + prm->prot_seg_cnt = 0; + prm->tot_dsds = 0; if ((xmit_type & QLA_TGT_XMIT_DATA) && qlt_has_data(cmd)) { if (qlt_pci_map_calc_cnt(prm) != 0) @@ -2565,7 +2593,7 @@ static int qlt_pre_xmit_response(struct qla_tgt_cmd *cmd, if (se_cmd->se_cmd_flags & SCF_UNDERFLOW_BIT) { prm->residual = se_cmd->residual_count; - ql_dbg(ql_dbg_io + ql_dbg_verbose, vha, 0x305c, + ql_dbg_qp(ql_dbg_io + ql_dbg_verbose, qpair, 0x305c, "Residual underflow: %d (tag %lld, op %x, bufflen %d, rq_result %x)\n", prm->residual, se_cmd->tag, se_cmd->t_task_cdb ? se_cmd->t_task_cdb[0] : 0, @@ -2573,7 +2601,7 @@ static int qlt_pre_xmit_response(struct qla_tgt_cmd *cmd, prm->rq_result |= SS_RESIDUAL_UNDER; } else if (se_cmd->se_cmd_flags & SCF_OVERFLOW_BIT) { prm->residual = se_cmd->residual_count; - ql_dbg(ql_dbg_io, vha, 0x305d, + ql_dbg_qp(ql_dbg_io, qpair, 0x305d, "Residual overflow: %d (tag %lld, op %x, bufflen %d, rq_result %x)\n", prm->residual, se_cmd->tag, se_cmd->t_task_cdb ? se_cmd->t_task_cdb[0] : 0, cmd->bufflen, prm->rq_result); @@ -2587,7 +2615,7 @@ static int qlt_pre_xmit_response(struct qla_tgt_cmd *cmd, */ if (qlt_has_data(cmd)) { if (QLA_TGT_SENSE_VALID(prm->sense_buffer) || - (IS_FWI2_CAPABLE(ha) && + (IS_FWI2_CAPABLE(cmd->vha->hw) && (prm->rq_result != 0))) { prm->add_status_pkt = 1; (*full_req_cnt)++; @@ -2598,17 +2626,17 @@ static int qlt_pre_xmit_response(struct qla_tgt_cmd *cmd, return 0; } -static inline int qlt_need_explicit_conf(struct qla_hw_data *ha, - struct qla_tgt_cmd *cmd, int sending_sense) +static inline int qlt_need_explicit_conf(struct qla_tgt_cmd *cmd, + int sending_sense) { - if (ha->tgt.enable_class_2) + if (cmd->qpair->enable_class_2) return 0; if (sending_sense) return cmd->conf_compl_supported; else - return ha->tgt.enable_explicit_conf && - cmd->conf_compl_supported; + return cmd->qpair->enable_explicit_conf && + cmd->conf_compl_supported; } static void qlt_24xx_init_ctio_to_isp(struct ctio7_to_24xx *ctio, @@ -2617,7 +2645,7 @@ static void qlt_24xx_init_ctio_to_isp(struct ctio7_to_24xx *ctio, prm->sense_buffer_len = min_t(uint32_t, prm->sense_buffer_len, (uint32_t)sizeof(ctio->u.status1.sense_data)); ctio->u.status0.flags |= cpu_to_le16(CTIO7_FLAGS_SEND_STATUS); - if (qlt_need_explicit_conf(prm->tgt->ha, prm->cmd, 0)) { + if (qlt_need_explicit_conf(prm->cmd, 0)) { ctio->u.status0.flags |= cpu_to_le16( CTIO7_FLAGS_EXPLICIT_CONFORM | CTIO7_FLAGS_CONFORM_REQ); @@ -2627,9 +2655,9 @@ static void qlt_24xx_init_ctio_to_isp(struct ctio7_to_24xx *ctio, if (QLA_TGT_SENSE_VALID(prm->sense_buffer)) { int i; - if (qlt_need_explicit_conf(prm->tgt->ha, prm->cmd, 1)) { + if (qlt_need_explicit_conf(prm->cmd, 1)) { if ((prm->rq_result & SS_SCSI_STATUS_BYTE) != 0) { - ql_dbg(ql_dbg_tgt, prm->cmd->vha, 0xe017, + ql_dbg_qp(ql_dbg_tgt, prm->cmd->qpair, 0xe017, "Skipping EXPLICIT_CONFORM and " "CTIO7_FLAGS_CONFORM_REQ for FCP READ w/ " "non GOOD status\n"); @@ -2797,7 +2825,7 @@ qla_tgt_set_dif_tags(struct qla_tgt_cmd *cmd, struct crc_context *ctx, } static inline int -qlt_build_ctio_crc2_pkt(struct qla_tgt_prm *prm, scsi_qla_host_t *vha) +qlt_build_ctio_crc2_pkt(struct qla_qpair *qpair, struct qla_tgt_prm *prm) { uint32_t *cur_dsd; uint32_t transfer_length = 0; @@ -2816,16 +2844,17 @@ qlt_build_ctio_crc2_pkt(struct qla_tgt_prm *prm, scsi_qla_host_t *vha) struct atio_from_isp *atio = &prm->cmd->atio; struct qla_tc_param tc; uint16_t t16; + scsi_qla_host_t *vha = cmd->vha; ha = vha->hw; - pkt = (struct ctio_crc2_to_fw *)vha->req->ring_ptr; + pkt = (struct ctio_crc2_to_fw *)qpair->req->ring_ptr; prm->pkt = pkt; memset(pkt, 0, sizeof(*pkt)); - ql_dbg(ql_dbg_tgt, vha, 0xe071, + ql_dbg_qp(ql_dbg_tgt, cmd->qpair, 0xe071, "qla_target(%d):%s: se_cmd[%p] CRC2 prot_op[0x%x] cmd prot sg:cnt[%p:%x] lba[%llu]\n", - vha->vp_idx, __func__, se_cmd, se_cmd->prot_op, + cmd->vp_idx, __func__, se_cmd, se_cmd->prot_op, prm->prot_sg, prm->prot_seg_cnt, se_cmd->t_task_lba); if ((se_cmd->prot_op == TARGET_PROT_DIN_INSERT) || @@ -2888,9 +2917,9 @@ qlt_build_ctio_crc2_pkt(struct qla_tgt_prm *prm, scsi_qla_host_t *vha) /* Update entry type to indicate Command Type CRC_2 IOCB */ pkt->entry_type = CTIO_CRC2; pkt->entry_count = 1; - pkt->vp_index = vha->vp_idx; + pkt->vp_index = cmd->vp_idx; - h = qlt_make_handle(vha); + h = qlt_make_handle(qpair); if (unlikely(h == QLA_TGT_NULL_HANDLE)) { /* * CTIO type 7 from the firmware doesn't provide a way to @@ -2899,9 +2928,10 @@ qlt_build_ctio_crc2_pkt(struct qla_tgt_prm *prm, scsi_qla_host_t *vha) */ return -EAGAIN; } else - ha->tgt.cmds[h-1] = prm->cmd; + qpair->req->outstanding_cmds[h] = (srb_t *)prm->cmd; - pkt->handle = h | CTIO_COMPLETION_HANDLE_MARK; + pkt->handle = MAKE_HANDLE(qpair->req->id, h); + pkt->handle |= CTIO_COMPLETION_HANDLE_MARK; pkt->nport_handle = cpu_to_le16(prm->cmd->loop_id); pkt->timeout = cpu_to_le16(QLA_TGT_TIMEOUT); pkt->initiator_id[0] = atio->u.isp24.fcp_hdr.s_id[2]; @@ -3005,7 +3035,7 @@ qlt_build_ctio_crc2_pkt(struct qla_tgt_prm *prm, scsi_qla_host_t *vha) crc_queuing_error: /* Cleanup will be performed by the caller */ - vha->hw->tgt.cmds[h - 1] = NULL; + qpair->req->outstanding_cmds[h] = NULL; return QLA_FUNCTION_FAILED; } @@ -3018,33 +3048,28 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type, uint8_t scsi_status) { struct scsi_qla_host *vha = cmd->vha; - struct qla_hw_data *ha = vha->hw; + struct qla_qpair *qpair = cmd->qpair; struct ctio7_to_24xx *pkt; struct qla_tgt_prm prm; uint32_t full_req_cnt = 0; unsigned long flags = 0; int res; - spin_lock_irqsave(&ha->hardware_lock, flags); if (cmd->sess && cmd->sess->deleted) { cmd->state = QLA_TGT_STATE_PROCESSED; if (cmd->sess->logout_completed) /* no need to terminate. FW already freed exchange. */ qlt_abort_cmd_on_host_reset(cmd->vha, cmd); else - qlt_send_term_exchange(vha, cmd, &cmd->atio, 1, 0); - spin_unlock_irqrestore(&ha->hardware_lock, flags); + qlt_send_term_exchange(qpair, cmd, &cmd->atio, 0, 0); return 0; } - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - memset(&prm, 0, sizeof(prm)); - ql_dbg(ql_dbg_tgt, cmd->vha, 0xe018, - "is_send_status=%d, cmd->bufflen=%d, cmd->sg_cnt=%d, cmd->dma_data_direction=%d se_cmd[%p]\n", + ql_dbg_qp(ql_dbg_tgt, qpair, 0xe018, + "is_send_status=%d, cmd->bufflen=%d, cmd->sg_cnt=%d, cmd->dma_data_direction=%d se_cmd[%p] qp %d\n", (xmit_type & QLA_TGT_XMIT_STATUS) ? 1 : 0, cmd->bufflen, cmd->sg_cnt, cmd->dma_data_direction, - &cmd->se_cmd); + &cmd->se_cmd, qpair->id); res = qlt_pre_xmit_response(cmd, &prm, xmit_type, scsi_status, &full_req_cnt); @@ -3052,39 +3077,39 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type, return res; } - spin_lock_irqsave(&ha->hardware_lock, flags); + spin_lock_irqsave(qpair->qp_lock_ptr, flags); if (xmit_type == QLA_TGT_XMIT_STATUS) - vha->tgt_counters.core_qla_snd_status++; + qpair->tgt_counters.core_qla_snd_status++; else - vha->tgt_counters.core_qla_que_buf++; + qpair->tgt_counters.core_qla_que_buf++; - if (!ha->flags.fw_started || cmd->reset_count != ha->chip_reset) { + if (!qpair->fw_started || cmd->reset_count != qpair->chip_reset) { /* * Either the port is not online or this request was from * previous life, just abort the processing. */ cmd->state = QLA_TGT_STATE_PROCESSED; qlt_abort_cmd_on_host_reset(cmd->vha, cmd); - ql_dbg(ql_dbg_async, vha, 0xe101, + ql_dbg_qp(ql_dbg_async, qpair, 0xe101, "RESET-RSP online/active/old-count/new-count = %d/%d/%d/%d.\n", vha->flags.online, qla2x00_reset_active(vha), - cmd->reset_count, ha->chip_reset); - spin_unlock_irqrestore(&ha->hardware_lock, flags); + cmd->reset_count, qpair->chip_reset); + spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); return 0; } /* Does F/W have an IOCBs for this request */ - res = qlt_check_reserve_free_req(vha, full_req_cnt); + res = qlt_check_reserve_free_req(qpair, full_req_cnt); if (unlikely(res)) goto out_unmap_unlock; if (cmd->se_cmd.prot_op && (xmit_type & QLA_TGT_XMIT_DATA)) - res = qlt_build_ctio_crc2_pkt(&prm, vha); + res = qlt_build_ctio_crc2_pkt(qpair, &prm); else - res = qlt_24xx_build_ctio_pkt(&prm, vha); + res = qlt_24xx_build_ctio_pkt(qpair, &prm); if (unlikely(res != 0)) { - vha->req->cnt += full_req_cnt; + qpair->req->cnt += full_req_cnt; goto out_unmap_unlock; } @@ -3096,7 +3121,7 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type, CTIO7_FLAGS_STATUS_MODE_0); if (cmd->se_cmd.prot_op == TARGET_PROT_NORMAL) - qlt_load_data_segments(&prm, vha); + qlt_load_data_segments(&prm); if (prm.add_status_pkt == 0) { if (xmit_type & QLA_TGT_XMIT_STATUS) { @@ -3106,7 +3131,7 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type, cpu_to_le32(prm.residual); pkt->u.status0.flags |= cpu_to_le16( CTIO7_FLAGS_SEND_STATUS); - if (qlt_need_explicit_conf(ha, cmd, 0)) { + if (qlt_need_explicit_conf(cmd, 0)) { pkt->u.status0.flags |= cpu_to_le16( CTIO7_FLAGS_EXPLICIT_CONFORM | @@ -3121,9 +3146,10 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type, * req_pkt(). */ struct ctio7_to_24xx *ctio = - (struct ctio7_to_24xx *)qlt_get_req_pkt(vha); + (struct ctio7_to_24xx *)qlt_get_req_pkt( + qpair->req); - ql_dbg(ql_dbg_io, vha, 0x305e, + ql_dbg_qp(ql_dbg_tgt, qpair, 0x305e, "Building additional status packet 0x%p.\n", ctio); @@ -3150,7 +3176,6 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type, */ qlt_24xx_init_ctio_to_isp((struct ctio7_to_24xx *)ctio, &prm); - pr_debug("Status CTIO7: %p\n", ctio); } } else qlt_24xx_init_ctio_to_isp(pkt, &prm); @@ -3161,14 +3186,17 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type, /* Memory Barrier */ wmb(); - qla2x00_start_iocbs(vha, vha->req); - spin_unlock_irqrestore(&ha->hardware_lock, flags); + if (qpair->reqq_start_iocbs) + qpair->reqq_start_iocbs(qpair); + else + qla2x00_start_iocbs(vha, qpair->req); + spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); return 0; out_unmap_unlock: qlt_unmap_sg(vha, cmd); - spin_unlock_irqrestore(&ha->hardware_lock, flags); + spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); return res; } @@ -3178,11 +3206,11 @@ int qlt_rdy_to_xfer(struct qla_tgt_cmd *cmd) { struct ctio7_to_24xx *pkt; struct scsi_qla_host *vha = cmd->vha; - struct qla_hw_data *ha = vha->hw; struct qla_tgt *tgt = cmd->tgt; struct qla_tgt_prm prm; - unsigned long flags; + unsigned long flags = 0; int res = 0; + struct qla_qpair *qpair = cmd->qpair; memset(&prm, 0, sizeof(prm)); prm.cmd = cmd; @@ -3190,17 +3218,11 @@ int qlt_rdy_to_xfer(struct qla_tgt_cmd *cmd) prm.sg = NULL; prm.req_cnt = 1; - /* Send marker if required */ - if (qlt_issue_marker(vha, 0) != QLA_SUCCESS) - return -EIO; - /* Calculate number of entries and segments required */ if (qlt_pci_map_calc_cnt(&prm) != 0) return -EAGAIN; - spin_lock_irqsave(&ha->hardware_lock, flags); - - if (!ha->flags.fw_started || (cmd->reset_count != ha->chip_reset) || + if (!qpair->fw_started || (cmd->reset_count != qpair->chip_reset) || (cmd->sess && cmd->sess->deleted)) { /* * Either the port is not online or this request was from @@ -3208,25 +3230,25 @@ int qlt_rdy_to_xfer(struct qla_tgt_cmd *cmd) */ cmd->state = QLA_TGT_STATE_NEED_DATA; qlt_abort_cmd_on_host_reset(cmd->vha, cmd); - ql_dbg(ql_dbg_async, vha, 0xe102, + ql_dbg_qp(ql_dbg_async, qpair, 0xe102, "RESET-XFR online/active/old-count/new-count = %d/%d/%d/%d.\n", vha->flags.online, qla2x00_reset_active(vha), - cmd->reset_count, ha->chip_reset); - spin_unlock_irqrestore(&ha->hardware_lock, flags); + cmd->reset_count, qpair->chip_reset); return 0; } + spin_lock_irqsave(qpair->qp_lock_ptr, flags); /* Does F/W have an IOCBs for this request */ - res = qlt_check_reserve_free_req(vha, prm.req_cnt); + res = qlt_check_reserve_free_req(qpair, prm.req_cnt); if (res != 0) goto out_unlock_free_unmap; if (cmd->se_cmd.prot_op) - res = qlt_build_ctio_crc2_pkt(&prm, vha); + res = qlt_build_ctio_crc2_pkt(qpair, &prm); else - res = qlt_24xx_build_ctio_pkt(&prm, vha); + res = qlt_24xx_build_ctio_pkt(qpair, &prm); if (unlikely(res != 0)) { - vha->req->cnt += prm.req_cnt; + qpair->req->cnt += prm.req_cnt; goto out_unlock_free_unmap; } @@ -3235,21 +3257,24 @@ int qlt_rdy_to_xfer(struct qla_tgt_cmd *cmd) CTIO7_FLAGS_STATUS_MODE_0); if (cmd->se_cmd.prot_op == TARGET_PROT_NORMAL) - qlt_load_data_segments(&prm, vha); + qlt_load_data_segments(&prm); cmd->state = QLA_TGT_STATE_NEED_DATA; cmd->cmd_sent_to_fw = 1; /* Memory Barrier */ wmb(); - qla2x00_start_iocbs(vha, vha->req); - spin_unlock_irqrestore(&ha->hardware_lock, flags); + if (qpair->reqq_start_iocbs) + qpair->reqq_start_iocbs(qpair); + else + qla2x00_start_iocbs(vha, qpair->req); + spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); return res; out_unlock_free_unmap: qlt_unmap_sg(vha, cmd); - spin_unlock_irqrestore(&ha->hardware_lock, flags); + spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); return res; } @@ -3260,7 +3285,7 @@ EXPORT_SYMBOL(qlt_rdy_to_xfer); * it is assumed either hardware_lock or qpair lock is held. */ static void -qlt_handle_dif_error(struct scsi_qla_host *vha, struct qla_tgt_cmd *cmd, +qlt_handle_dif_error(struct qla_qpair *qpair, struct qla_tgt_cmd *cmd, struct ctio_crc_from_fw *sts) { uint8_t *ap = &sts->actual_dif[0]; @@ -3268,6 +3293,7 @@ qlt_handle_dif_error(struct scsi_qla_host *vha, struct qla_tgt_cmd *cmd, uint64_t lba = cmd->se_cmd.t_task_lba; uint8_t scsi_status, sense_key, asc, ascq; unsigned long flags; + struct scsi_qla_host *vha = cmd->vha; cmd->trc_flags |= TRC_DIF_ERR; @@ -3286,15 +3312,12 @@ qlt_handle_dif_error(struct scsi_qla_host *vha, struct qla_tgt_cmd *cmd, /* check appl tag */ if (cmd->e_app_tag != cmd->a_app_tag) { - ql_dbg(ql_dbg_tgt_dif, vha, 0xffff, - "App Tag ERR: cdb[%x] lba[%llx %llx] blks[%x] [Actual|Expected] " - "Ref[%x|%x], App[%x|%x], " - "Guard [%x|%x] cmd=%p ox_id[%04x]", - cmd->cdb[0], lba, (lba+cmd->num_blks), cmd->num_blks, - cmd->a_ref_tag, cmd->e_ref_tag, - cmd->a_app_tag, cmd->e_app_tag, - cmd->a_guard, cmd->e_guard, - cmd, cmd->atio.u.isp24.fcp_hdr.ox_id); + ql_dbg(ql_dbg_tgt_dif, vha, 0xe00d, + "App Tag ERR: cdb[%x] lba[%llx %llx] blks[%x] [Actual|Expected] Ref[%x|%x], App[%x|%x], Guard [%x|%x] cmd=%p ox_id[%04x]", + cmd->cdb[0], lba, (lba+cmd->num_blks), cmd->num_blks, + cmd->a_ref_tag, cmd->e_ref_tag, cmd->a_app_tag, + cmd->e_app_tag, cmd->a_guard, cmd->e_guard, cmd, + cmd->atio.u.isp24.fcp_hdr.ox_id); cmd->dif_err_code = DIF_ERR_APP; scsi_status = SAM_STAT_CHECK_CONDITION; @@ -3305,15 +3328,12 @@ qlt_handle_dif_error(struct scsi_qla_host *vha, struct qla_tgt_cmd *cmd, /* check ref tag */ if (cmd->e_ref_tag != cmd->a_ref_tag) { - ql_dbg(ql_dbg_tgt_dif, vha, 0xffff, - "Ref Tag ERR: cdb[%x] lba[%llx %llx] blks[%x] [Actual|Expected] " - "Ref[%x|%x], App[%x|%x], " - "Guard[%x|%x] cmd=%p ox_id[%04x] ", - cmd->cdb[0], lba, (lba+cmd->num_blks), cmd->num_blks, - cmd->a_ref_tag, cmd->e_ref_tag, - cmd->a_app_tag, cmd->e_app_tag, - cmd->a_guard, cmd->e_guard, - cmd, cmd->atio.u.isp24.fcp_hdr.ox_id); + ql_dbg(ql_dbg_tgt_dif, vha, 0xe00e, + "Ref Tag ERR: cdb[%x] lba[%llx %llx] blks[%x] [Actual|Expected] Ref[%x|%x], App[%x|%x], Guard[%x|%x] cmd=%p ox_id[%04x] ", + cmd->cdb[0], lba, (lba+cmd->num_blks), cmd->num_blks, + cmd->a_ref_tag, cmd->e_ref_tag, cmd->a_app_tag, + cmd->e_app_tag, cmd->a_guard, cmd->e_guard, cmd, + cmd->atio.u.isp24.fcp_hdr.ox_id); cmd->dif_err_code = DIF_ERR_REF; scsi_status = SAM_STAT_CHECK_CONDITION; @@ -3325,15 +3345,13 @@ qlt_handle_dif_error(struct scsi_qla_host *vha, struct qla_tgt_cmd *cmd, /* check guard */ if (cmd->e_guard != cmd->a_guard) { - ql_dbg(ql_dbg_tgt_dif, vha, 0xffff, - "Guard ERR: cdb[%x] lba[%llx %llx] blks[%x] [Actual|Expected] " - "Ref[%x|%x], App[%x|%x], " - "Guard [%x|%x] cmd=%p ox_id[%04x]", - cmd->cdb[0], lba, (lba+cmd->num_blks), cmd->num_blks, - cmd->a_ref_tag, cmd->e_ref_tag, - cmd->a_app_tag, cmd->e_app_tag, - cmd->a_guard, cmd->e_guard, - cmd, cmd->atio.u.isp24.fcp_hdr.ox_id); + ql_dbg(ql_dbg_tgt_dif, vha, 0xe012, + "Guard ERR: cdb[%x] lba[%llx %llx] blks[%x] [Actual|Expected] Ref[%x|%x], App[%x|%x], Guard [%x|%x] cmd=%p ox_id[%04x]", + cmd->cdb[0], lba, (lba+cmd->num_blks), cmd->num_blks, + cmd->a_ref_tag, cmd->e_ref_tag, cmd->a_app_tag, + cmd->e_app_tag, cmd->a_guard, cmd->e_guard, cmd, + cmd->atio.u.isp24.fcp_hdr.ox_id); + cmd->dif_err_code = DIF_ERR_GRD; scsi_status = SAM_STAT_CHECK_CONDITION; sense_key = ABORTED_COMMAND; @@ -3356,7 +3374,8 @@ out: } spin_unlock_irqrestore(&cmd->cmd_lock, flags); - qlt_send_resp_ctio(vha, cmd, scsi_status, sense_key, asc, ascq); + qlt_send_resp_ctio(qpair, cmd, scsi_status, sense_key, asc, + ascq); /* assume scsi status gets out on the wire. * Will not wait for completion. */ @@ -3422,9 +3441,6 @@ static void qlt_send_term_imm_notif(struct scsi_qla_host *vha, unsigned long flags = 0; int rc; - if (qlt_issue_marker(vha, ha_locked) < 0) - return; - if (ha_locked) { rc = __qlt_send_term_imm_notif(vha, imm); @@ -3451,21 +3467,24 @@ done: spin_unlock_irqrestore(&vha->hw->hardware_lock, flags); } -/* If hardware_lock held on entry, might drop it, then reaquire */ -/* This function sends the appropriate CTIO to ISP 2xxx or 24xx */ -static int __qlt_send_term_exchange(struct scsi_qla_host *vha, +/* + * If hardware_lock held on entry, might drop it, then reaquire + * This function sends the appropriate CTIO to ISP 2xxx or 24xx + */ +static int __qlt_send_term_exchange(struct qla_qpair *qpair, struct qla_tgt_cmd *cmd, struct atio_from_isp *atio) { + struct scsi_qla_host *vha = qpair->vha; struct ctio7_to_24xx *ctio24; struct qla_hw_data *ha = vha->hw; request_t *pkt; int ret = 0; uint16_t temp; - ql_dbg(ql_dbg_tgt, vha, 0xe01c, "Sending TERM EXCH CTIO (ha=%p)\n", ha); + ql_dbg(ql_dbg_tgt, vha, 0xe009, "Sending TERM EXCH CTIO (ha=%p)\n", ha); - pkt = (request_t *)qla2x00_alloc_iocbs_ready(vha, NULL); + pkt = (request_t *)qla2x00_alloc_iocbs_ready(qpair, NULL); if (pkt == NULL) { ql_dbg(ql_dbg_tgt, vha, 0xe050, "qla_target(%d): %s failed: unable to allocate " @@ -3483,7 +3502,7 @@ static int __qlt_send_term_exchange(struct scsi_qla_host *vha, ret = 1; } - vha->tgt_counters.num_term_xchg_sent++; + qpair->tgt_counters.num_term_xchg_sent++; pkt->entry_count = 1; pkt->handle = QLA_TGT_SKIP_HANDLE | CTIO_COMPLETION_HANDLE_MARK; @@ -3496,9 +3515,9 @@ static int __qlt_send_term_exchange(struct scsi_qla_host *vha, ctio24->initiator_id[1] = atio->u.isp24.fcp_hdr.s_id[1]; ctio24->initiator_id[2] = atio->u.isp24.fcp_hdr.s_id[0]; ctio24->exchange_addr = atio->u.isp24.exchange_addr; - ctio24->u.status1.flags = (atio->u.isp24.attr << 9) | - cpu_to_le16(CTIO7_FLAGS_STATUS_MODE_1 | - CTIO7_FLAGS_TERMINATE); + temp = (atio->u.isp24.attr << 9) | CTIO7_FLAGS_STATUS_MODE_1 | + CTIO7_FLAGS_TERMINATE; + ctio24->u.status1.flags = cpu_to_le16(temp); temp = be16_to_cpu(atio->u.isp24.fcp_hdr.ox_id); ctio24->u.status1.ox_id = cpu_to_le16(temp); @@ -3511,28 +3530,35 @@ static int __qlt_send_term_exchange(struct scsi_qla_host *vha, /* Memory Barrier */ wmb(); - qla2x00_start_iocbs(vha, vha->req); + if (qpair->reqq_start_iocbs) + qpair->reqq_start_iocbs(qpair); + else + qla2x00_start_iocbs(vha, qpair->req); return ret; } -static void qlt_send_term_exchange(struct scsi_qla_host *vha, +static void qlt_send_term_exchange(struct qla_qpair *qpair, struct qla_tgt_cmd *cmd, struct atio_from_isp *atio, int ha_locked, int ul_abort) { + struct scsi_qla_host *vha; unsigned long flags = 0; int rc; - if (qlt_issue_marker(vha, ha_locked) < 0) - return; + /* why use different vha? NPIV */ + if (cmd) + vha = cmd->vha; + else + vha = qpair->vha; if (ha_locked) { - rc = __qlt_send_term_exchange(vha, cmd, atio); + rc = __qlt_send_term_exchange(qpair, cmd, atio); if (rc == -ENOMEM) qlt_alloc_qfull_cmd(vha, atio, 0, 0); goto done; } - spin_lock_irqsave(&vha->hw->hardware_lock, flags); - rc = __qlt_send_term_exchange(vha, cmd, atio); + spin_lock_irqsave(qpair->qp_lock_ptr, flags); + rc = __qlt_send_term_exchange(qpair, cmd, atio); if (rc == -ENOMEM) qlt_alloc_qfull_cmd(vha, atio, 0, 0); @@ -3544,7 +3570,7 @@ done: } if (!ha_locked) - spin_unlock_irqrestore(&vha->hw->hardware_lock, flags); + spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); return; } @@ -3616,17 +3642,17 @@ int qlt_abort_cmd(struct qla_tgt_cmd *cmd) * 1) XFER Rdy completion + CMD_T_ABORT * 2) TCM TMR - drain_state_list */ - ql_dbg(ql_dbg_tgt_mgt, vha, 0xffff, - "multiple abort. %p transport_state %x, t_state %x," - " se_cmd_flags %x \n", cmd, cmd->se_cmd.transport_state, - cmd->se_cmd.t_state,cmd->se_cmd.se_cmd_flags); + ql_dbg(ql_dbg_tgt_mgt, vha, 0xf016, + "multiple abort. %p transport_state %x, t_state %x, " + "se_cmd_flags %x\n", cmd, cmd->se_cmd.transport_state, + cmd->se_cmd.t_state, cmd->se_cmd.se_cmd_flags); return EIO; } cmd->aborted = 1; cmd->trc_flags |= TRC_ABORT; spin_unlock_irqrestore(&cmd->cmd_lock, flags); - qlt_send_term_exchange(vha, cmd, &cmd->atio, 0, 1); + qlt_send_term_exchange(cmd->qpair, cmd, &cmd->atio, 0, 1); return 0; } EXPORT_SYMBOL(qlt_abort_cmd); @@ -3665,13 +3691,14 @@ EXPORT_SYMBOL(qlt_free_cmd); /* * ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire */ -static int qlt_term_ctio_exchange(struct scsi_qla_host *vha, void *ctio, +static int qlt_term_ctio_exchange(struct qla_qpair *qpair, void *ctio, struct qla_tgt_cmd *cmd, uint32_t status) { int term = 0; + struct scsi_qla_host *vha = qpair->vha; if (cmd->se_cmd.prot_op) - ql_dbg(ql_dbg_tgt_dif, vha, 0xffff, + ql_dbg(ql_dbg_tgt_dif, vha, 0xe013, "Term DIF cmd: lba[0x%llx|%lld] len[0x%x] " "se_cmd=%p tag[%x] op %#x/%s", cmd->lba, cmd->lba, @@ -3688,55 +3715,53 @@ static int qlt_term_ctio_exchange(struct scsi_qla_host *vha, void *ctio, term = 1; if (term) - qlt_send_term_exchange(vha, cmd, &cmd->atio, 1, 0); + qlt_term_ctio_exchange(qpair, ctio, cmd, status); return term; } -/* ha->hardware_lock supposed to be held on entry */ -static inline struct qla_tgt_cmd *qlt_get_cmd(struct scsi_qla_host *vha, - uint32_t handle) -{ - struct qla_hw_data *ha = vha->hw; - - handle--; - if (ha->tgt.cmds[handle] != NULL) { - struct qla_tgt_cmd *cmd = ha->tgt.cmds[handle]; - ha->tgt.cmds[handle] = NULL; - return cmd; - } else - return NULL; -} /* ha->hardware_lock supposed to be held on entry */ static struct qla_tgt_cmd *qlt_ctio_to_cmd(struct scsi_qla_host *vha, - uint32_t handle, void *ctio) + struct rsp_que *rsp, uint32_t handle, void *ctio) { struct qla_tgt_cmd *cmd = NULL; + struct req_que *req; + int qid = GET_QID(handle); + uint32_t h = handle & ~QLA_TGT_HANDLE_MASK; - /* Clear out internal marks */ - handle &= ~(CTIO_COMPLETION_HANDLE_MARK | - CTIO_INTERMEDIATE_HANDLE_MARK); + if (unlikely(h == QLA_TGT_SKIP_HANDLE)) + return NULL; - if (handle != QLA_TGT_NULL_HANDLE) { - if (unlikely(handle == QLA_TGT_SKIP_HANDLE)) - return NULL; + if (qid == rsp->req->id) { + req = rsp->req; + } else if (vha->hw->req_q_map[qid]) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x1000a, + "qla_target(%d): CTIO completion with different QID %d handle %x\n", + vha->vp_idx, rsp->id, handle); + req = vha->hw->req_q_map[qid]; + } else { + return NULL; + } + + h &= QLA_CMD_HANDLE_MASK; - /* handle-1 is actually used */ - if (unlikely(handle > DEFAULT_OUTSTANDING_COMMANDS)) { + if (h != QLA_TGT_NULL_HANDLE) { + if (unlikely(h > req->num_outstanding_cmds)) { ql_dbg(ql_dbg_tgt, vha, 0xe052, "qla_target(%d): Wrong handle %x received\n", vha->vp_idx, handle); return NULL; } - cmd = qlt_get_cmd(vha, handle); + + cmd = (struct qla_tgt_cmd *)req->outstanding_cmds[h]; if (unlikely(cmd == NULL)) { - ql_dbg(ql_dbg_tgt, vha, 0xe053, - "qla_target(%d): Suspicious: unable to " - "find the command with handle %x\n", vha->vp_idx, - handle); + ql_dbg(ql_dbg_async, vha, 0xe053, + "qla_target(%d): Suspicious: unable to find the command with handle %x req->id %d rsp->id %d\n", + vha->vp_idx, handle, req->id, rsp->id); return NULL; } + req->outstanding_cmds[h] = NULL; } else if (ctio != NULL) { /* We can't get loop ID from CTIO7 */ ql_dbg(ql_dbg_tgt, vha, 0xe054, @@ -3749,33 +3774,30 @@ static struct qla_tgt_cmd *qlt_ctio_to_cmd(struct scsi_qla_host *vha, } /* hardware_lock should be held by caller. */ -static void +void qlt_abort_cmd_on_host_reset(struct scsi_qla_host *vha, struct qla_tgt_cmd *cmd) { struct qla_hw_data *ha = vha->hw; - uint32_t handle; if (cmd->sg_mapped) qlt_unmap_sg(vha, cmd); - handle = qlt_make_handle(vha); - /* TODO: fix debug message type and ids. */ if (cmd->state == QLA_TGT_STATE_PROCESSED) { ql_dbg(ql_dbg_io, vha, 0xff00, - "HOST-ABORT: handle=%d, state=PROCESSED.\n", handle); + "HOST-ABORT: state=PROCESSED.\n"); } else if (cmd->state == QLA_TGT_STATE_NEED_DATA) { cmd->write_data_transferred = 0; cmd->state = QLA_TGT_STATE_DATA_IN; ql_dbg(ql_dbg_io, vha, 0xff01, - "HOST-ABORT: handle=%d, state=DATA_IN.\n", handle); + "HOST-ABORT: state=DATA_IN.\n"); ha->tgt.tgt_ops->handle_data(cmd); return; } else { ql_dbg(ql_dbg_io, vha, 0xff03, - "HOST-ABORT: handle=%d, state=BAD(%d).\n", handle, + "HOST-ABORT: state=BAD(%d).\n", cmd->state); dump_stack(); } @@ -3784,51 +3806,16 @@ qlt_abort_cmd_on_host_reset(struct scsi_qla_host *vha, struct qla_tgt_cmd *cmd) ha->tgt.tgt_ops->free_cmd(cmd); } -void -qlt_host_reset_handler(struct qla_hw_data *ha) -{ - struct qla_tgt_cmd *cmd; - unsigned long flags; - scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev); - scsi_qla_host_t *vha = NULL; - struct qla_tgt *tgt = base_vha->vha_tgt.qla_tgt; - uint32_t i; - - if (!base_vha->hw->tgt.tgt_ops) - return; - - if (!tgt || qla_ini_mode_enabled(base_vha)) { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf003, - "Target mode disabled\n"); - return; - } - - ql_dbg(ql_dbg_tgt_mgt, vha, 0xff10, - "HOST-ABORT-HNDLR: base_vha->dpc_flags=%lx.\n", - base_vha->dpc_flags); - - spin_lock_irqsave(&ha->hardware_lock, flags); - for (i = 1; i < DEFAULT_OUTSTANDING_COMMANDS + 1; i++) { - cmd = qlt_get_cmd(base_vha, i); - if (!cmd) - continue; - /* ha->tgt.cmds entry is cleared by qlt_get_cmd. */ - vha = cmd->vha; - qlt_abort_cmd_on_host_reset(vha, cmd); - } - spin_unlock_irqrestore(&ha->hardware_lock, flags); -} - - /* * ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire */ -static void qlt_do_ctio_completion(struct scsi_qla_host *vha, uint32_t handle, - uint32_t status, void *ctio) +static void qlt_do_ctio_completion(struct scsi_qla_host *vha, + struct rsp_que *rsp, uint32_t handle, uint32_t status, void *ctio) { struct qla_hw_data *ha = vha->hw; struct se_cmd *se_cmd; struct qla_tgt_cmd *cmd; + struct qla_qpair *qpair = rsp->qpair; if (handle & CTIO_INTERMEDIATE_HANDLE_MARK) { /* That could happen only in case of an error/reset/abort */ @@ -3840,7 +3827,7 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, uint32_t handle, return; } - cmd = qlt_ctio_to_cmd(vha, handle, ctio); + cmd = qlt_ctio_to_cmd(vha, rsp, handle, ctio); if (cmd == NULL) return; @@ -3885,7 +3872,7 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, uint32_t handle, */ cmd->sess->logout_on_delete = 0; cmd->sess->send_els_logo = 1; - ql_dbg(ql_dbg_disc, vha, 0xffff, + ql_dbg(ql_dbg_disc, vha, 0x20f8, "%s %d %8phC post del sess\n", __func__, __LINE__, cmd->sess->port_name); @@ -3904,7 +3891,7 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, uint32_t handle, *((u64 *)&crc->actual_dif[0]), *((u64 *)&crc->expected_dif[0])); - qlt_handle_dif_error(vha, cmd, ctio); + qlt_handle_dif_error(qpair, cmd, ctio); return; } default: @@ -3924,7 +3911,7 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, uint32_t handle, if ((cmd->state != QLA_TGT_STATE_NEED_DATA) && (!cmd->aborted)) { cmd->trc_flags |= TRC_CTIO_ERR; - if (qlt_term_ctio_exchange(vha, ctio, cmd, status)) + if (qlt_term_ctio_exchange(qpair, ctio, cmd, status)) return; } } @@ -4000,18 +3987,16 @@ static void __qlt_do_work(struct qla_tgt_cmd *cmd) { scsi_qla_host_t *vha = cmd->vha; struct qla_hw_data *ha = vha->hw; - struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; struct fc_port *sess = cmd->sess; struct atio_from_isp *atio = &cmd->atio; unsigned char *cdb; unsigned long flags; uint32_t data_length; int ret, fcp_task_attr, data_dir, bidi = 0; + struct qla_qpair *qpair = cmd->qpair; cmd->cmd_in_wq = 0; cmd->trc_flags |= TRC_DO_WORK; - if (tgt->tgt_stop) - goto out_term; if (cmd->aborted) { ql_dbg(ql_dbg_tgt_mgt, vha, 0xf082, @@ -4023,8 +4008,6 @@ static void __qlt_do_work(struct qla_tgt_cmd *cmd) spin_lock_init(&cmd->cmd_lock); cdb = &atio->u.isp24.fcp_cmnd.cdb[0]; cmd->se_cmd.tag = atio->u.isp24.exchange_addr; - cmd->unpacked_lun = scsilun_to_int( - (struct scsi_lun *)&atio->u.isp24.fcp_cmnd.lun); if (atio->u.isp24.fcp_cmnd.rddata && atio->u.isp24.fcp_cmnd.wrdata) { @@ -4062,12 +4045,12 @@ out_term: * argument to qlt_send_term_exchange() and free the memory here. */ cmd->trc_flags |= TRC_DO_WORK_ERR; - spin_lock_irqsave(&ha->hardware_lock, flags); - qlt_send_term_exchange(vha, NULL, &cmd->atio, 1, 0); + spin_lock_irqsave(qpair->qp_lock_ptr, flags); + qlt_send_term_exchange(qpair, NULL, &cmd->atio, 1, 0); qlt_decr_num_pend_cmds(vha); percpu_ida_free(&sess->se_sess->sess_tag_pool, cmd->se_cmd.map_tag); - spin_unlock_irqrestore(&ha->hardware_lock, flags); + spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); spin_lock_irqsave(&ha->tgt.sess_lock, flags); ha->tgt.tgt_ops->put_sess(sess); @@ -4087,6 +4070,110 @@ static void qlt_do_work(struct work_struct *work) __qlt_do_work(cmd); } +void qlt_clr_qp_table(struct scsi_qla_host *vha) +{ + unsigned long flags; + struct qla_hw_data *ha = vha->hw; + struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; + void *node; + u64 key = 0; + + ql_log(ql_log_info, vha, 0x706c, + "User update Number of Active Qpairs %d\n", + ha->tgt.num_act_qpairs); + + spin_lock_irqsave(&ha->tgt.atio_lock, flags); + + btree_for_each_safe64(&tgt->lun_qpair_map, key, node) + btree_remove64(&tgt->lun_qpair_map, key); + + ha->base_qpair->lun_cnt = 0; + for (key = 0; key < ha->max_qpairs; key++) + if (ha->queue_pair_map[key]) + ha->queue_pair_map[key]->lun_cnt = 0; + + spin_unlock_irqrestore(&ha->tgt.atio_lock, flags); +} + +static void qlt_assign_qpair(struct scsi_qla_host *vha, + struct qla_tgt_cmd *cmd) +{ + struct qla_qpair *qpair, *qp; + struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; + struct qla_qpair_hint *h; + + if (vha->flags.qpairs_available) { + h = btree_lookup64(&tgt->lun_qpair_map, cmd->unpacked_lun); + if (unlikely(!h)) { + /* spread lun to qpair ratio evently */ + int lcnt = 0, rc; + struct scsi_qla_host *base_vha = + pci_get_drvdata(vha->hw->pdev); + + qpair = vha->hw->base_qpair; + if (qpair->lun_cnt == 0) { + qpair->lun_cnt++; + h = qla_qpair_to_hint(tgt, qpair); + BUG_ON(!h); + rc = btree_insert64(&tgt->lun_qpair_map, + cmd->unpacked_lun, h, GFP_ATOMIC); + if (rc) { + qpair->lun_cnt--; + ql_log(ql_log_info, vha, 0xd037, + "Unable to insert lun %llx into lun_qpair_map\n", + cmd->unpacked_lun); + } + goto out; + } else { + lcnt = qpair->lun_cnt; + } + + h = NULL; + list_for_each_entry(qp, &base_vha->qp_list, + qp_list_elem) { + if (qp->lun_cnt == 0) { + qp->lun_cnt++; + h = qla_qpair_to_hint(tgt, qp); + BUG_ON(!h); + rc = btree_insert64(&tgt->lun_qpair_map, + cmd->unpacked_lun, h, GFP_ATOMIC); + if (rc) { + qp->lun_cnt--; + ql_log(ql_log_info, vha, 0xd038, + "Unable to insert lun %llx into lun_qpair_map\n", + cmd->unpacked_lun); + } + qpair = qp; + goto out; + } else { + if (qp->lun_cnt < lcnt) { + lcnt = qp->lun_cnt; + qpair = qp; + continue; + } + } + } + BUG_ON(!qpair); + qpair->lun_cnt++; + h = qla_qpair_to_hint(tgt, qpair); + BUG_ON(!h); + rc = btree_insert64(&tgt->lun_qpair_map, + cmd->unpacked_lun, h, GFP_ATOMIC); + if (rc) { + qpair->lun_cnt--; + ql_log(ql_log_info, vha, 0xd039, + "Unable to insert lun %llx into lun_qpair_map\n", + cmd->unpacked_lun); + } + } + } else { + h = &tgt->qphints[0]; + } +out: + cmd->qpair = h->qpair; + cmd->se_cmd.cpuid = h->cpuid; +} + static struct qla_tgt_cmd *qlt_get_tag(scsi_qla_host_t *vha, struct fc_port *sess, struct atio_from_isp *atio) @@ -4101,7 +4188,7 @@ static struct qla_tgt_cmd *qlt_get_tag(scsi_qla_host_t *vha, cmd = &((struct qla_tgt_cmd *)se_sess->sess_cmd_map)[tag]; memset(cmd, 0, sizeof(struct qla_tgt_cmd)); - + cmd->cmd_type = TYPE_TGT_CMD; memcpy(&cmd->atio, atio, sizeof(*atio)); cmd->state = QLA_TGT_STATE_NEW; cmd->tgt = vha->vha_tgt.qla_tgt; @@ -4115,14 +4202,15 @@ static struct qla_tgt_cmd *qlt_get_tag(scsi_qla_host_t *vha, cmd->trc_flags = 0; cmd->jiffies_at_alloc = get_jiffies_64(); - cmd->reset_count = vha->hw->chip_reset; + cmd->unpacked_lun = scsilun_to_int( + (struct scsi_lun *)&atio->u.isp24.fcp_cmnd.lun); + qlt_assign_qpair(vha, cmd); + cmd->reset_count = vha->hw->base_qpair->chip_reset; + cmd->vp_idx = vha->vp_idx; return cmd; } -static void qlt_send_busy(struct scsi_qla_host *, struct atio_from_isp *, - uint16_t); - static void qlt_create_sess_from_atio(struct work_struct *work) { struct qla_tgt_sess_op *op = container_of(work, @@ -4168,10 +4256,15 @@ static void qlt_create_sess_from_atio(struct work_struct *work) */ cmd = qlt_get_tag(vha, sess, &op->atio); if (!cmd) { - spin_lock_irqsave(&ha->hardware_lock, flags); - qlt_send_busy(vha, &op->atio, SAM_STAT_BUSY); + struct qla_qpair *qpair = ha->base_qpair; + + spin_lock_irqsave(qpair->qp_lock_ptr, flags); + qlt_send_busy(qpair, &op->atio, SAM_STAT_BUSY); + spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); + + spin_lock_irqsave(&ha->tgt.sess_lock, flags); ha->tgt.tgt_ops->put_sess(sess); - spin_unlock_irqrestore(&ha->hardware_lock, flags); + spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); kfree(op); return; } @@ -4184,9 +4277,7 @@ static void qlt_create_sess_from_atio(struct work_struct *work) kfree(op); return; out_term: - spin_lock_irqsave(&ha->hardware_lock, flags); - qlt_send_term_exchange(vha, NULL, &op->atio, 1, 0); - spin_unlock_irqrestore(&ha->hardware_lock, flags); + qlt_send_term_exchange(vha->hw->base_qpair, NULL, &op->atio, 0, 0); kfree(op); } @@ -4216,9 +4307,9 @@ static int qlt_handle_cmd_for_atio(struct scsi_qla_host *vha, memcpy(&op->atio, atio, sizeof(*atio)); op->vha = vha; - spin_lock(&vha->cmd_list_lock); + spin_lock_irqsave(&vha->cmd_list_lock, flags); list_add_tail(&op->cmd_list, &vha->qla_sess_op_cmd_list); - spin_unlock(&vha->cmd_list_lock); + spin_unlock_irqrestore(&vha->cmd_list_lock, flags); INIT_WORK(&op->work, qlt_create_sess_from_atio); queue_work(qla_tgt_wq, &op->work); @@ -4228,7 +4319,7 @@ static int qlt_handle_cmd_for_atio(struct scsi_qla_host *vha, /* Another WWN used to have our s_id. Our PLOGI scheduled its * session deletion, but it's still in sess_del_work wq */ if (sess->deleted) { - ql_dbg(ql_dbg_io, vha, 0x3061, + ql_dbg(ql_dbg_tgt_mgt, vha, 0xf002, "New command while old session %p is being deleted\n", sess); return -EFAULT; @@ -4238,7 +4329,7 @@ static int qlt_handle_cmd_for_atio(struct scsi_qla_host *vha, * Do kref_get() before returning + dropping qla_hw_data->hardware_lock. */ if (!kref_get_unless_zero(&sess->sess_kref)) { - ql_dbg(ql_dbg_tgt, vha, 0xffff, + ql_dbg(ql_dbg_tgt_mgt, vha, 0xf004, "%s: kref_get fail, %8phC oxid %x \n", __func__, sess->port_name, be16_to_cpu(atio->u.isp24.fcp_hdr.ox_id)); @@ -4257,15 +4348,15 @@ static int qlt_handle_cmd_for_atio(struct scsi_qla_host *vha, cmd->cmd_in_wq = 1; cmd->trc_flags |= TRC_NEW_CMD; - cmd->se_cmd.cpuid = ha->msix_count ? - ha->tgt.rspq_vector_cpuid : WORK_CPU_UNBOUND; spin_lock_irqsave(&vha->cmd_list_lock, flags); list_add_tail(&cmd->cmd_list, &vha->qla_cmd_list); spin_unlock_irqrestore(&vha->cmd_list_lock, flags); INIT_WORK(&cmd->work, qlt_do_work); - if (ha->msix_count) { + if (vha->flags.qpairs_available) { + queue_work_on(cmd->se_cmd.cpuid, qla_tgt_wq, &cmd->work); + } else if (ha->msix_count) { if (cmd->atio.u.isp24.fcp_cmnd.rddata) queue_work_on(smp_processor_id(), qla_tgt_wq, &cmd->work); @@ -4275,8 +4366,8 @@ static int qlt_handle_cmd_for_atio(struct scsi_qla_host *vha, } else { queue_work(qla_tgt_wq, &cmd->work); } - return 0; + return 0; } /* ha->hardware_lock supposed to be held on entry */ @@ -4306,7 +4397,8 @@ static int qlt_issue_task_mgmt(struct fc_port *sess, u64 lun, } mcmd->tmr_func = fn; mcmd->flags = flags; - mcmd->reset_count = vha->hw->chip_reset; + mcmd->reset_count = ha->base_qpair->chip_reset; + mcmd->qpair = ha->base_qpair; switch (fn) { case QLA_TGT_LUN_RESET: @@ -4333,13 +4425,12 @@ static int qlt_handle_task_mgmt(struct scsi_qla_host *vha, void *iocb) struct qla_hw_data *ha = vha->hw; struct qla_tgt *tgt; struct fc_port *sess; - uint32_t lun, unpacked_lun; + u64 unpacked_lun; int fn; unsigned long flags; tgt = vha->vha_tgt.qla_tgt; - lun = a->u.isp24.fcp_cmnd.lun; fn = a->u.isp24.fcp_cmnd.task_mgmt_flags; spin_lock_irqsave(&ha->tgt.sess_lock, flags); @@ -4347,7 +4438,8 @@ static int qlt_handle_task_mgmt(struct scsi_qla_host *vha, void *iocb) a->u.isp24.fcp_hdr.s_id); spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); - unpacked_lun = scsilun_to_int((struct scsi_lun *)&lun); + unpacked_lun = + scsilun_to_int((struct scsi_lun *)&a->u.isp24.fcp_cmnd.lun); if (!sess) { ql_dbg(ql_dbg_tgt_mgt, vha, 0xf024, @@ -4370,7 +4462,7 @@ static int __qlt_abort_task(struct scsi_qla_host *vha, struct atio_from_isp *a = (struct atio_from_isp *)iocb; struct qla_hw_data *ha = vha->hw; struct qla_tgt_mgmt_cmd *mcmd; - uint32_t lun, unpacked_lun; + u64 unpacked_lun; int rc; mcmd = mempool_alloc(qla_tgt_mgmt_cmd_mempool, GFP_ATOMIC); @@ -4386,10 +4478,11 @@ static int __qlt_abort_task(struct scsi_qla_host *vha, memcpy(&mcmd->orig_iocb.imm_ntfy, iocb, sizeof(mcmd->orig_iocb.imm_ntfy)); - lun = a->u.isp24.fcp_cmnd.lun; - unpacked_lun = scsilun_to_int((struct scsi_lun *)&lun); - mcmd->reset_count = vha->hw->chip_reset; + unpacked_lun = + scsilun_to_int((struct scsi_lun *)&a->u.isp24.fcp_cmnd.lun); + mcmd->reset_count = ha->base_qpair->chip_reset; mcmd->tmr_func = QLA_TGT_2G_ABORT_TASK; + mcmd->qpair = ha->base_qpair; rc = ha->tgt.tgt_ops->handle_tmr(mcmd, unpacked_lun, mcmd->tmr_func, le16_to_cpu(iocb->u.isp2x.seq_id)); @@ -4493,7 +4586,7 @@ qlt_find_sess_invalidate_other(scsi_qla_host_t *vha, uint64_t wwn, * Another wwn used to have our s_id/loop_id * kill the session, but don't free the loop_id */ - ql_dbg(ql_dbg_tgt_tmr, vha, 0xffff, + ql_dbg(ql_dbg_tgt_tmr, vha, 0xf01b, "Invalidating sess %p loop_id %d wwn %llx.\n", other_sess, other_sess->loop_id, other_wwn); @@ -4529,12 +4622,13 @@ static int abort_cmds_for_s_id(struct scsi_qla_host *vha, port_id_t *s_id) struct qla_tgt_cmd *cmd; uint32_t key; int count = 0; + unsigned long flags; key = (((u32)s_id->b.domain << 16) | ((u32)s_id->b.area << 8) | ((u32)s_id->b.al_pa)); - spin_lock(&vha->cmd_list_lock); + spin_lock_irqsave(&vha->cmd_list_lock, flags); list_for_each_entry(op, &vha->qla_sess_op_cmd_list, cmd_list) { uint32_t op_key = sid_to_key(op->atio.u.isp24.fcp_hdr.s_id); @@ -4559,7 +4653,7 @@ static int abort_cmds_for_s_id(struct scsi_qla_host *vha, port_id_t *s_id) count++; } } - spin_unlock(&vha->cmd_list_lock); + spin_unlock_irqrestore(&vha->cmd_list_lock, flags); return count; } @@ -4672,9 +4766,9 @@ static int qlt_24xx_handle_els(struct scsi_qla_host *vha, sess->keep_nport_handle = ((sess->loop_id == loop_id) && (sess->d_id.b24 == port_id.b24)); - ql_dbg(ql_dbg_disc, vha, 0xffff, - "%s %d %8phC post del sess\n", - __func__, __LINE__, sess->port_name); + ql_dbg(ql_dbg_disc, vha, 0x20f9, + "%s %d %8phC post del sess\n", + __func__, __LINE__, sess->port_name); qlt_schedule_sess_for_deletion_lock(sess); @@ -4744,7 +4838,7 @@ static int qlt_24xx_handle_els(struct scsi_qla_host *vha, /* Make session global (not used in fabric mode) */ if (ha->current_topology != ISP_CFG_F) { if (sess) { - ql_dbg(ql_dbg_disc, vha, 0xffff, + ql_dbg(ql_dbg_disc, vha, 0x20fa, "%s %d %8phC post nack\n", __func__, __LINE__, sess->port_name); qla24xx_post_nack_work(vha, sess, iocb, @@ -4757,7 +4851,7 @@ static int qlt_24xx_handle_els(struct scsi_qla_host *vha, } } else { if (sess) { - ql_dbg(ql_dbg_disc, vha, 0xffff, + ql_dbg(ql_dbg_disc, vha, 0x20fb, "%s %d %8phC post nack\n", __func__, __LINE__, sess->port_name); qla24xx_post_nack_work(vha, sess, iocb, @@ -4791,7 +4885,7 @@ static int qlt_24xx_handle_els(struct scsi_qla_host *vha, res = qlt_reset(vha, iocb, QLA_TGT_NEXUS_LOSS_SESS); - ql_dbg(ql_dbg_disc, vha, 0xffff, + ql_dbg(ql_dbg_disc, vha, 0x20fc, "%s: logo %llx res %d sess %p ", __func__, wwn, res, sess); if (res == 0) { @@ -4815,15 +4909,15 @@ static int qlt_24xx_handle_els(struct scsi_qla_host *vha, { struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; if (tgt->link_reinit_iocb_pending) { - qlt_send_notify_ack(vha, &tgt->link_reinit_iocb, - 0, 0, 0, 0, 0, 0); + qlt_send_notify_ack(ha->base_qpair, + &tgt->link_reinit_iocb, 0, 0, 0, 0, 0, 0); tgt->link_reinit_iocb_pending = 0; } sess = qla2x00_find_fcport_by_wwpn(vha, iocb->u.isp24.port_name, 1); if (sess) { - ql_dbg(ql_dbg_disc, vha, 0xffff, + ql_dbg(ql_dbg_disc, vha, 0x20fd, "sess %p lid %d|%d DS %d LS %d\n", sess, sess->loop_id, loop_id, sess->disc_state, sess->fw_login_state); @@ -4879,8 +4973,8 @@ static void qlt_handle_imm_notify(struct scsi_qla_host *vha, le16_to_cpu(iocb->u.isp24.nport_handle), iocb->u.isp24.status_subcode); if (tgt->link_reinit_iocb_pending) { - qlt_send_notify_ack(vha, &tgt->link_reinit_iocb, - 0, 0, 0, 0, 0, 0); + qlt_send_notify_ack(ha->base_qpair, + &tgt->link_reinit_iocb, 0, 0, 0, 0, 0, 0); } memcpy(&tgt->link_reinit_iocb, iocb, sizeof(*iocb)); tgt->link_reinit_iocb_pending = 1; @@ -4974,33 +5068,36 @@ static void qlt_handle_imm_notify(struct scsi_qla_host *vha, } if (send_notify_ack) - qlt_send_notify_ack(vha, iocb, add_flags, 0, 0, 0, 0, 0); + qlt_send_notify_ack(ha->base_qpair, iocb, add_flags, 0, 0, 0, + 0, 0); } /* * ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire * This function sends busy to ISP 2xxx or 24xx. */ -static int __qlt_send_busy(struct scsi_qla_host *vha, +static int __qlt_send_busy(struct qla_qpair *qpair, struct atio_from_isp *atio, uint16_t status) { + struct scsi_qla_host *vha = qpair->vha; struct ctio7_to_24xx *ctio24; struct qla_hw_data *ha = vha->hw; request_t *pkt; struct fc_port *sess = NULL; unsigned long flags; + u16 temp; spin_lock_irqsave(&ha->tgt.sess_lock, flags); sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha, atio->u.isp24.fcp_hdr.s_id); spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); if (!sess) { - qlt_send_term_exchange(vha, NULL, atio, 1, 0); + qlt_send_term_exchange(qpair, NULL, atio, 1, 0); return 0; } /* Sending marker isn't necessary, since we called from ISR */ - pkt = (request_t *)qla2x00_alloc_iocbs(vha, NULL); + pkt = (request_t *)__qla2x00_alloc_iocbs(qpair, NULL); if (!pkt) { ql_dbg(ql_dbg_io, vha, 0x3063, "qla_target(%d): %s failed: unable to allocate " @@ -5008,7 +5105,7 @@ static int __qlt_send_busy(struct scsi_qla_host *vha, return -ENOMEM; } - vha->tgt_counters.num_q_full_sent++; + qpair->tgt_counters.num_q_full_sent++; pkt->entry_count = 1; pkt->handle = QLA_TGT_SKIP_HANDLE | CTIO_COMPLETION_HANDLE_MARK; @@ -5021,10 +5118,10 @@ static int __qlt_send_busy(struct scsi_qla_host *vha, ctio24->initiator_id[1] = atio->u.isp24.fcp_hdr.s_id[1]; ctio24->initiator_id[2] = atio->u.isp24.fcp_hdr.s_id[0]; ctio24->exchange_addr = atio->u.isp24.exchange_addr; - ctio24->u.status1.flags = (atio->u.isp24.attr << 9) | - cpu_to_le16( + temp = (atio->u.isp24.attr << 9) | CTIO7_FLAGS_STATUS_MODE_1 | CTIO7_FLAGS_SEND_STATUS | - CTIO7_FLAGS_DONT_RET_CTIO); + CTIO7_FLAGS_DONT_RET_CTIO; + ctio24->u.status1.flags = cpu_to_le16(temp); /* * CTIO from fw w/o se_cmd doesn't provide enough info to retry it, * if the explicit conformation is used. @@ -5033,7 +5130,10 @@ static int __qlt_send_busy(struct scsi_qla_host *vha, ctio24->u.status1.scsi_status = cpu_to_le16(status); /* Memory Barrier */ wmb(); - qla2x00_start_iocbs(vha, vha->req); + if (qpair->reqq_start_iocbs) + qpair->reqq_start_iocbs(qpair); + else + qla2x00_start_iocbs(vha, qpair->req); return 0; } @@ -5052,6 +5152,7 @@ qlt_alloc_qfull_cmd(struct scsi_qla_host *vha, struct se_session *se_sess; struct qla_tgt_cmd *cmd; int tag; + unsigned long flags; if (unlikely(tgt->tgt_stop)) { ql_dbg(ql_dbg_io, vha, 0x300a, @@ -5110,8 +5211,9 @@ qlt_alloc_qfull_cmd(struct scsi_qla_host *vha, cmd->tgt = vha->vha_tgt.qla_tgt; cmd->vha = vha; - cmd->reset_count = vha->hw->chip_reset; + cmd->reset_count = ha->base_qpair->chip_reset; cmd->q_full = 1; + cmd->qpair = ha->base_qpair; if (qfull) { cmd->q_full = 1; @@ -5120,6 +5222,7 @@ qlt_alloc_qfull_cmd(struct scsi_qla_host *vha, } else cmd->term_exchg = 1; + spin_lock_irqsave(&vha->hw->tgt.q_full_lock, flags); list_add_tail(&cmd->cmd_list, &vha->hw->tgt.q_full_list); vha->hw->tgt.num_qfull_cmds_alloc++; @@ -5127,35 +5230,41 @@ qlt_alloc_qfull_cmd(struct scsi_qla_host *vha, vha->qla_stats.stat_max_qfull_cmds_alloc) vha->qla_stats.stat_max_qfull_cmds_alloc = vha->hw->tgt.num_qfull_cmds_alloc; + spin_unlock_irqrestore(&vha->hw->tgt.q_full_lock, flags); } int -qlt_free_qfull_cmds(struct scsi_qla_host *vha) +qlt_free_qfull_cmds(struct qla_qpair *qpair) { + struct scsi_qla_host *vha = qpair->vha; struct qla_hw_data *ha = vha->hw; unsigned long flags; struct qla_tgt_cmd *cmd, *tcmd; - struct list_head free_list; + struct list_head free_list, q_full_list; int rc = 0; if (list_empty(&ha->tgt.q_full_list)) return 0; INIT_LIST_HEAD(&free_list); + INIT_LIST_HEAD(&q_full_list); - spin_lock_irqsave(&vha->hw->hardware_lock, flags); - + spin_lock_irqsave(&vha->hw->tgt.q_full_lock, flags); if (list_empty(&ha->tgt.q_full_list)) { - spin_unlock_irqrestore(&vha->hw->hardware_lock, flags); + spin_unlock_irqrestore(&vha->hw->tgt.q_full_lock, flags); return 0; } - list_for_each_entry_safe(cmd, tcmd, &ha->tgt.q_full_list, cmd_list) { + list_splice_init(&vha->hw->tgt.q_full_list, &q_full_list); + spin_unlock_irqrestore(&vha->hw->tgt.q_full_lock, flags); + + spin_lock_irqsave(qpair->qp_lock_ptr, flags); + list_for_each_entry_safe(cmd, tcmd, &q_full_list, cmd_list) { if (cmd->q_full) /* cmd->state is a borrowed field to hold status */ - rc = __qlt_send_busy(vha, &cmd->atio, cmd->state); + rc = __qlt_send_busy(qpair, &cmd->atio, cmd->state); else if (cmd->term_exchg) - rc = __qlt_send_term_exchange(vha, NULL, &cmd->atio); + rc = __qlt_send_term_exchange(qpair, NULL, &cmd->atio); if (rc == -ENOMEM) break; @@ -5179,7 +5288,7 @@ qlt_free_qfull_cmds(struct scsi_qla_host *vha) /* piggy back on hardware_lock for protection */ vha->hw->tgt.num_qfull_cmds_alloc--; } - spin_unlock_irqrestore(&vha->hw->hardware_lock, flags); + spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); cmd = NULL; @@ -5190,23 +5299,31 @@ qlt_free_qfull_cmds(struct scsi_qla_host *vha) */ qlt_free_cmd(cmd); } + + if (!list_empty(&q_full_list)) { + spin_lock_irqsave(&vha->hw->tgt.q_full_lock, flags); + list_splice(&q_full_list, &vha->hw->tgt.q_full_list); + spin_unlock_irqrestore(&vha->hw->tgt.q_full_lock, flags); + } + return rc; } static void -qlt_send_busy(struct scsi_qla_host *vha, - struct atio_from_isp *atio, uint16_t status) +qlt_send_busy(struct qla_qpair *qpair, struct atio_from_isp *atio, + uint16_t status) { int rc = 0; + struct scsi_qla_host *vha = qpair->vha; - rc = __qlt_send_busy(vha, atio, status); + rc = __qlt_send_busy(qpair, atio, status); if (rc == -ENOMEM) qlt_alloc_qfull_cmd(vha, atio, status, 1); } static int -qlt_chk_qfull_thresh_hold(struct scsi_qla_host *vha, - struct atio_from_isp *atio, bool ha_locked) +qlt_chk_qfull_thresh_hold(struct scsi_qla_host *vha, struct qla_qpair *qpair, + struct atio_from_isp *atio, uint8_t ha_locked) { struct qla_hw_data *ha = vha->hw; uint16_t status; @@ -5218,7 +5335,7 @@ qlt_chk_qfull_thresh_hold(struct scsi_qla_host *vha, if (!ha_locked) spin_lock_irqsave(&ha->hardware_lock, flags); status = temp_sam_status; - qlt_send_busy(vha, atio, status); + qlt_send_busy(qpair, atio, status); if (!ha_locked) spin_unlock_irqrestore(&ha->hardware_lock, flags); @@ -5257,16 +5374,17 @@ static void qlt_24xx_atio_pkt(struct scsi_qla_host *vha, "sending QUEUE_FULL\n", vha->vp_idx); if (!ha_locked) spin_lock_irqsave(&ha->hardware_lock, flags); - qlt_send_busy(vha, atio, SAM_STAT_TASK_SET_FULL); + qlt_send_busy(ha->base_qpair, atio, + SAM_STAT_TASK_SET_FULL); if (!ha_locked) - spin_unlock_irqrestore(&ha->hardware_lock, flags); + spin_unlock_irqrestore(&ha->hardware_lock, + flags); break; } - - if (likely(atio->u.isp24.fcp_cmnd.task_mgmt_flags == 0)) { - rc = qlt_chk_qfull_thresh_hold(vha, atio, ha_locked); + rc = qlt_chk_qfull_thresh_hold(vha, ha->base_qpair, + atio, ha_locked); if (rc != 0) { tgt->atio_irq_cmd_count--; return; @@ -5278,19 +5396,19 @@ static void qlt_24xx_atio_pkt(struct scsi_qla_host *vha, if (unlikely(rc != 0)) { if (rc == -ESRCH) { if (!ha_locked) - spin_lock_irqsave - (&ha->hardware_lock, flags); + spin_lock_irqsave(&ha->hardware_lock, + flags); #if 1 /* With TERM EXCHANGE some FC cards refuse to boot */ - qlt_send_busy(vha, atio, SAM_STAT_BUSY); + qlt_send_busy(ha->base_qpair, atio, + SAM_STAT_BUSY); #else - qlt_send_term_exchange(vha, NULL, atio, 1, 0); + qlt_send_term_exchange(ha->base_qpair, NULL, + atio, 1, 0); #endif - if (!ha_locked) - spin_unlock_irqrestore - (&ha->hardware_lock, flags); - + spin_unlock_irqrestore( + &ha->hardware_lock, flags); } else { if (tgt->tgt_stop) { ql_dbg(ql_dbg_tgt, vha, 0xe059, @@ -5305,7 +5423,8 @@ static void qlt_24xx_atio_pkt(struct scsi_qla_host *vha, if (!ha_locked) spin_lock_irqsave( &ha->hardware_lock, flags); - qlt_send_busy(vha, atio, SAM_STAT_BUSY); + qlt_send_busy(ha->base_qpair, + atio, SAM_STAT_BUSY); if (!ha_locked) spin_unlock_irqrestore( &ha->hardware_lock, flags); @@ -5346,15 +5465,15 @@ static void qlt_24xx_atio_pkt(struct scsi_qla_host *vha, /* ha->hardware_lock supposed to be held on entry */ /* called via callback from qla2xxx */ -static void qlt_response_pkt(struct scsi_qla_host *vha, response_t *pkt) +static void qlt_response_pkt(struct scsi_qla_host *vha, + struct rsp_que *rsp, response_t *pkt) { - struct qla_hw_data *ha = vha->hw; struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; if (unlikely(tgt == NULL)) { ql_dbg(ql_dbg_tgt, vha, 0xe05d, - "qla_target(%d): Response pkt %x received, but no " - "tgt (ha %p)\n", vha->vp_idx, pkt->entry_type, ha); + "qla_target(%d): Response pkt %x received, but no tgt (ha %p)\n", + vha->vp_idx, pkt->entry_type, vha->hw); return; } @@ -5363,14 +5482,12 @@ static void qlt_response_pkt(struct scsi_qla_host *vha, response_t *pkt) * Otherwise, some commands can stuck. */ - tgt->irq_cmd_count++; - switch (pkt->entry_type) { case CTIO_CRC2: case CTIO_TYPE7: { struct ctio7_from_24xx *entry = (struct ctio7_from_24xx *)pkt; - qlt_do_ctio_completion(vha, entry->handle, + qlt_do_ctio_completion(vha, rsp, entry->handle, le16_to_cpu(entry->status)|(pkt->entry_status << 16), entry); break; @@ -5389,19 +5506,17 @@ static void qlt_response_pkt(struct scsi_qla_host *vha, response_t *pkt) break; } - rc = qlt_chk_qfull_thresh_hold(vha, atio, true); - if (rc != 0) { - tgt->irq_cmd_count--; + rc = qlt_chk_qfull_thresh_hold(vha, rsp->qpair, atio, 1); + if (rc != 0) return; - } rc = qlt_handle_cmd_for_atio(vha, atio); if (unlikely(rc != 0)) { if (rc == -ESRCH) { #if 1 /* With TERM EXCHANGE some FC cards refuse to boot */ - qlt_send_busy(vha, atio, 0); + qlt_send_busy(rsp->qpair, atio, 0); #else - qlt_send_term_exchange(vha, NULL, atio, 1, 0); + qlt_send_term_exchange(rsp->qpair, NULL, atio, 1, 0); #endif } else { if (tgt->tgt_stop) { @@ -5409,14 +5524,14 @@ static void qlt_response_pkt(struct scsi_qla_host *vha, response_t *pkt) "qla_target: Unable to send " "command to target, sending TERM " "EXCHANGE for rsp\n"); - qlt_send_term_exchange(vha, NULL, + qlt_send_term_exchange(rsp->qpair, NULL, atio, 1, 0); } else { ql_dbg(ql_dbg_tgt, vha, 0xe060, "qla_target(%d): Unable to send " "command to target, sending BUSY " "status\n", vha->vp_idx); - qlt_send_busy(vha, atio, 0); + qlt_send_busy(rsp->qpair, atio, 0); } } } @@ -5426,7 +5541,7 @@ static void qlt_response_pkt(struct scsi_qla_host *vha, response_t *pkt) case CONTINUE_TGT_IO_TYPE: { struct ctio_to_2xxx *entry = (struct ctio_to_2xxx *)pkt; - qlt_do_ctio_completion(vha, entry->handle, + qlt_do_ctio_completion(vha, rsp, entry->handle, le16_to_cpu(entry->status)|(pkt->entry_status << 16), entry); break; @@ -5435,7 +5550,7 @@ static void qlt_response_pkt(struct scsi_qla_host *vha, response_t *pkt) case CTIO_A64_TYPE: { struct ctio_to_2xxx *entry = (struct ctio_to_2xxx *)pkt; - qlt_do_ctio_completion(vha, entry->handle, + qlt_do_ctio_completion(vha, rsp, entry->handle, le16_to_cpu(entry->status)|(pkt->entry_status << 16), entry); break; @@ -5525,7 +5640,6 @@ static void qlt_response_pkt(struct scsi_qla_host *vha, response_t *pkt) break; } - tgt->irq_cmd_count--; } /* @@ -5538,15 +5652,9 @@ void qlt_async_event(uint16_t code, struct scsi_qla_host *vha, struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; int login_code; - if (!ha->tgt.tgt_ops) + if (!tgt || tgt->tgt_stop || tgt->tgt_stopped) return; - if (unlikely(tgt == NULL)) { - ql_dbg(ql_dbg_tgt, vha, 0xe03a, - "ASYNC EVENT %#x, but no tgt (ha %p)\n", code, ha); - return; - } - if (((code == MBA_POINT_TO_POINT) || (code == MBA_CHG_IN_CONNECTION)) && IS_QLA2100(ha)) return; @@ -5555,7 +5663,6 @@ void qlt_async_event(uint16_t code, struct scsi_qla_host *vha, * Otherwise, some commands can stuck. */ - tgt->irq_cmd_count++; switch (code) { case MBA_RESET: /* Reset */ @@ -5578,7 +5685,8 @@ void qlt_async_event(uint16_t code, struct scsi_qla_host *vha, le16_to_cpu(mailbox[0]), le16_to_cpu(mailbox[1]), le16_to_cpu(mailbox[2]), le16_to_cpu(mailbox[3])); if (tgt->link_reinit_iocb_pending) { - qlt_send_notify_ack(vha, (void *)&tgt->link_reinit_iocb, + qlt_send_notify_ack(ha->base_qpair, + (void *)&tgt->link_reinit_iocb, 0, 0, 0, 0, 0, 0); tgt->link_reinit_iocb_pending = 0; } @@ -5597,17 +5705,17 @@ void qlt_async_event(uint16_t code, struct scsi_qla_host *vha, break; case MBA_REJECTED_FCP_CMD: - ql_dbg(ql_dbg_tgt_mgt, vha, 0xffff, - "qla_target(%d): Async event LS_REJECT occurred " - "(m[0]=%x, m[1]=%x, m[2]=%x, m[3]=%x)", vha->vp_idx, - le16_to_cpu(mailbox[0]), le16_to_cpu(mailbox[1]), - le16_to_cpu(mailbox[2]), le16_to_cpu(mailbox[3])); + ql_dbg(ql_dbg_tgt_mgt, vha, 0xf017, + "qla_target(%d): Async event LS_REJECT occurred (m[0]=%x, m[1]=%x, m[2]=%x, m[3]=%x)", + vha->vp_idx, + le16_to_cpu(mailbox[0]), le16_to_cpu(mailbox[1]), + le16_to_cpu(mailbox[2]), le16_to_cpu(mailbox[3])); if (le16_to_cpu(mailbox[3]) == 1) { /* exchange starvation. */ vha->hw->exch_starvation++; if (vha->hw->exch_starvation > 5) { - ql_log(ql_log_warn, vha, 0xffff, + ql_log(ql_log_warn, vha, 0xd03a, "Exchange starvation-. Resetting RISC\n"); vha->hw->exch_starvation = 0; @@ -5643,7 +5751,6 @@ void qlt_async_event(uint16_t code, struct scsi_qla_host *vha, break; } - tgt->irq_cmd_count--; } static fc_port_t *qlt_get_port_database(struct scsi_qla_host *vha, @@ -5707,12 +5814,12 @@ static fc_port_t *qlt_get_port_database(struct scsi_qla_host *vha, case MODE_DUAL: if (newfcport) { if (!IS_IIDMA_CAPABLE(vha->hw) || !vha->hw->flags.gpsc_supported) { - ql_dbg(ql_dbg_disc, vha, 0xffff, + ql_dbg(ql_dbg_disc, vha, 0x20fe, "%s %d %8phC post upd_fcport fcp_cnt %d\n", __func__, __LINE__, fcport->port_name, vha->fcport_count); qla24xx_post_upd_fcport_work(vha, fcport); } else { - ql_dbg(ql_dbg_disc, vha, 0xffff, + ql_dbg(ql_dbg_disc, vha, 0x20ff, "%s %d %8phC post gpsc fcp_cnt %d\n", __func__, __LINE__, fcport->port_name, vha->fcport_count); qla24xx_post_gpsc_work(vha, fcport); @@ -5838,7 +5945,7 @@ static void qlt_abort_work(struct qla_tgt *tgt, } if (!kref_get_unless_zero(&sess->sess_kref)) { - ql_dbg(ql_dbg_tgt_tmr, vha, 0xffff, + ql_dbg(ql_dbg_tgt_tmr, vha, 0xf01c, "%s: kref_get fail %8phC \n", __func__, sess->port_name); sess = NULL; @@ -5861,7 +5968,8 @@ out_term2: out_term: spin_lock_irqsave(&ha->hardware_lock, flags); - qlt_24xx_send_abts_resp(vha, &prm->abts, FCP_TMF_REJECTED, false); + qlt_24xx_send_abts_resp(ha->base_qpair, &prm->abts, + FCP_TMF_REJECTED, false); spin_unlock_irqrestore(&ha->hardware_lock, flags); } @@ -5875,7 +5983,7 @@ static void qlt_tmr_work(struct qla_tgt *tgt, unsigned long flags; uint8_t *s_id = NULL; /* to hide compiler warnings */ int rc; - uint32_t lun, unpacked_lun; + u64 unpacked_lun; int fn; void *iocb; @@ -5902,7 +6010,7 @@ static void qlt_tmr_work(struct qla_tgt *tgt, } if (!kref_get_unless_zero(&sess->sess_kref)) { - ql_dbg(ql_dbg_tgt_tmr, vha, 0xffff, + ql_dbg(ql_dbg_tgt_tmr, vha, 0xf020, "%s: kref_get fail %8phC\n", __func__, sess->port_name); sess = NULL; @@ -5911,9 +6019,9 @@ static void qlt_tmr_work(struct qla_tgt *tgt, } iocb = a; - lun = a->u.isp24.fcp_cmnd.lun; fn = a->u.isp24.fcp_cmnd.task_mgmt_flags; - unpacked_lun = scsilun_to_int((struct scsi_lun *)&lun); + unpacked_lun = + scsilun_to_int((struct scsi_lun *)&a->u.isp24.fcp_cmnd.lun); rc = qlt_issue_task_mgmt(sess, unpacked_lun, fn, iocb, 0); ha->tgt.tgt_ops->put_sess(sess); @@ -5928,7 +6036,7 @@ out_term2: ha->tgt.tgt_ops->put_sess(sess); spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); out_term: - qlt_send_term_exchange(vha, NULL, &prm->tm_iocb2, 1, 0); + qlt_send_term_exchange(ha->base_qpair, NULL, &prm->tm_iocb2, 1, 0); } static void qlt_sess_work_fn(struct work_struct *work) @@ -5976,6 +6084,8 @@ static void qlt_sess_work_fn(struct work_struct *work) int qlt_add_target(struct qla_hw_data *ha, struct scsi_qla_host *base_vha) { struct qla_tgt *tgt; + int rc, i; + struct qla_qpair_hint *h; if (!QLA_TGT_MODE_ENABLED()) return 0; @@ -5998,9 +6108,47 @@ int qlt_add_target(struct qla_hw_data *ha, struct scsi_qla_host *base_vha) return -ENOMEM; } + tgt->qphints = kzalloc((ha->max_qpairs + 1) * + sizeof(struct qla_qpair_hint), GFP_KERNEL); + if (!tgt->qphints) { + kfree(tgt); + ql_log(ql_log_warn, base_vha, 0x0197, + "Unable to allocate qpair hints.\n"); + return -ENOMEM; + } + if (!(base_vha->host->hostt->supported_mode & MODE_TARGET)) base_vha->host->hostt->supported_mode |= MODE_TARGET; + rc = btree_init64(&tgt->lun_qpair_map); + if (rc) { + kfree(tgt->qphints); + kfree(tgt); + ql_log(ql_log_info, base_vha, 0x0198, + "Unable to initialize lun_qpair_map btree\n"); + return -EIO; + } + h = &tgt->qphints[0]; + h->qpair = ha->base_qpair; + INIT_LIST_HEAD(&h->hint_elem); + h->cpuid = ha->base_qpair->cpuid; + list_add_tail(&h->hint_elem, &ha->base_qpair->hints_list); + + for (i = 0; i < ha->max_qpairs; i++) { + unsigned long flags; + + struct qla_qpair *qpair = ha->queue_pair_map[i]; + h = &tgt->qphints[i + 1]; + INIT_LIST_HEAD(&h->hint_elem); + if (qpair) { + h->qpair = qpair; + spin_lock_irqsave(qpair->qp_lock_ptr, flags); + list_add_tail(&h->hint_elem, &qpair->hints_list); + spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); + h->cpuid = qpair->cpuid; + } + } + tgt->ha = ha; tgt->vha = base_vha; init_waitqueue_head(&tgt->waitQ); @@ -6015,11 +6163,8 @@ int qlt_add_target(struct qla_hw_data *ha, struct scsi_qla_host *base_vha) ql_dbg(ql_dbg_tgt, base_vha, 0xe067, "qla_target(%d): using 64 Bit PCI addressing", base_vha->vp_idx); - tgt->tgt_enable_64bit_addr = 1; /* 3 is reserved */ tgt->sg_tablesize = QLA_TGT_MAX_SG_24XX(base_vha->req->length - 3); - tgt->datasegs_per_cmd = QLA_TGT_DATASEGS_PER_CMD_24XX; - tgt->datasegs_per_cont = QLA_TGT_DATASEGS_PER_CONT_24XX; mutex_lock(&qla_tgt_mutex); list_add_tail(&tgt->tgt_list_entry, &qla_tgt_glist); @@ -6231,7 +6376,6 @@ qlt_enable_vha(struct scsi_qla_host *vha) struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; unsigned long flags; scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev); - int rspq_ent = QLA83XX_RSPQ_MSIX_ENTRY_NUMBER; if (!tgt) { ql_dbg(ql_dbg_tgt, vha, 0xe069, @@ -6250,17 +6394,6 @@ qlt_enable_vha(struct scsi_qla_host *vha) qla24xx_disable_vp(vha); qla24xx_enable_vp(vha); } else { - if (ha->msix_entries) { - ql_dbg(ql_dbg_tgt, vha, 0xffff, - "%s: host%ld : vector %d cpu %d\n", - __func__, vha->host_no, - ha->msix_entries[rspq_ent].vector, - ha->msix_entries[rspq_ent].cpuid); - - ha->tgt.rspq_vector_cpuid = - ha->msix_entries[rspq_ent].cpuid; - } - set_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags); qla2xxx_wake_dpc(base_vha); qla2x00_wait_for_hba_online(base_vha); @@ -6387,14 +6520,15 @@ qlt_24xx_process_atio_queue(struct scsi_qla_host *vha, uint8_t ha_locked) * can not be trusted. There is no point in passing * it further up. */ - ql_log(ql_log_warn, vha, 0xffff, + ql_log(ql_log_warn, vha, 0xd03c, "corrupted fcp frame SID[%3phN] OXID[%04x] EXCG[%x] %64phN\n", pkt->u.isp24.fcp_hdr.s_id, be16_to_cpu(pkt->u.isp24.fcp_hdr.ox_id), le32_to_cpu(pkt->u.isp24.exchange_addr), pkt); adjust_corrupted_atio(pkt); - qlt_send_term_exchange(vha, NULL, pkt, ha_locked, 0); + qlt_send_term_exchange(ha->base_qpair, NULL, pkt, + ha_locked, 0); } else { qlt_24xx_atio_pkt_all_vps(vha, (struct atio_from_isp *)pkt, ha_locked); @@ -6445,8 +6579,9 @@ void qlt_24xx_config_nvram_stage1(struct scsi_qla_host *vha, struct nvram_24xx *nv) { struct qla_hw_data *ha = vha->hw; - u32 tmp; - u16 t; + + if (!QLA_TGT_MODE_ENABLED()) + return; if (qla_tgt_mode_enabled(vha) || qla_dual_mode_enabled(vha)) { if (!ha->tgt.saved_set) { @@ -6461,24 +6596,10 @@ qlt_24xx_config_nvram_stage1(struct scsi_qla_host *vha, struct nvram_24xx *nv) ha->tgt.saved_set = 1; } - if (qla_tgt_mode_enabled(vha)) { + if (qla_tgt_mode_enabled(vha)) nv->exchange_count = cpu_to_le16(0xFFFF); - } else { /* dual */ - if (ql_dm_tgt_ex_pct > 100) { - ql_dm_tgt_ex_pct = 50; - } else if (ql_dm_tgt_ex_pct == 100) { - /* leave some for FW */ - ql_dm_tgt_ex_pct = 95; - } - - tmp = ha->orig_fw_xcb_count * ql_dm_tgt_ex_pct; - tmp = tmp/100; - if (tmp > 0xffff) - tmp = 0xffff; - - t = tmp & 0xffff; - nv->exchange_count = cpu_to_le16(t); - } + else /* dual */ + nv->exchange_count = cpu_to_le16(ql2xexchoffld); /* Enable target mode */ nv->firmware_options_1 |= cpu_to_le32(BIT_4); @@ -6522,7 +6643,7 @@ qlt_24xx_config_nvram_stage1(struct scsi_qla_host *vha, struct nvram_24xx *nv) return; } - if (ha->tgt.enable_class_2) { + if (ha->base_qpair->enable_class_2) { if (vha->flags.init_done) fc_host_supported_classes(vha->host) = FC_COS_CLASS2 | FC_COS_CLASS3; @@ -6563,8 +6684,6 @@ void qlt_81xx_config_nvram_stage1(struct scsi_qla_host *vha, struct nvram_81xx *nv) { struct qla_hw_data *ha = vha->hw; - u32 tmp; - u16 t; if (!QLA_TGT_MODE_ENABLED()) return; @@ -6582,23 +6701,10 @@ qlt_81xx_config_nvram_stage1(struct scsi_qla_host *vha, struct nvram_81xx *nv) ha->tgt.saved_set = 1; } - if (qla_tgt_mode_enabled(vha)) { + if (qla_tgt_mode_enabled(vha)) nv->exchange_count = cpu_to_le16(0xFFFF); - } else { /* dual */ - if (ql_dm_tgt_ex_pct > 100) { - ql_dm_tgt_ex_pct = 50; - } else if (ql_dm_tgt_ex_pct == 100) { - /* leave some for FW */ - ql_dm_tgt_ex_pct = 95; - } - - tmp = ha->orig_fw_xcb_count * ql_dm_tgt_ex_pct; - tmp = tmp/100; - if (tmp > 0xffff) - tmp = 0xffff; - t = tmp & 0xffff; - nv->exchange_count = cpu_to_le16(t); - } + else /* dual */ + nv->exchange_count = cpu_to_le16(ql2xexchoffld); /* Enable target mode */ nv->firmware_options_1 |= cpu_to_le32(BIT_4); @@ -6641,7 +6747,7 @@ qlt_81xx_config_nvram_stage1(struct scsi_qla_host *vha, struct nvram_81xx *nv) return; } - if (ha->tgt.enable_class_2) { + if (ha->base_qpair->enable_class_2) { if (vha->flags.init_done) fc_host_supported_classes(vha->host) = FC_COS_CLASS2 | FC_COS_CLASS3; @@ -6688,21 +6794,6 @@ qlt_83xx_iospace_config(struct qla_hw_data *ha) ha->msix_count += 1; /* For ATIO Q */ } -int -qlt_24xx_process_response_error(struct scsi_qla_host *vha, - struct sts_entry_24xx *pkt) -{ - switch (pkt->entry_type) { - case ABTS_RECV_24XX: - case ABTS_RESP_24XX: - case CTIO_TYPE7: - case NOTIFY_ACK_TYPE: - case CTIO_CRC2: - return 1; - default: - return 0; - } -} void qlt_modify_vp_config(struct scsi_qla_host *vha, @@ -6744,7 +6835,7 @@ qlt_probe_one_stage1(struct scsi_qla_host *base_vha, struct qla_hw_data *ha) rc = btree_init32(&ha->tgt.host_map); if (rc) - ql_log(ql_log_info, base_vha, 0xffff, + ql_log(ql_log_info, base_vha, 0xd03d, "Unable to initialize ha->host_map btree\n"); qlt_update_vp_map(base_vha, SET_VP_IDX); @@ -6780,7 +6871,8 @@ qlt_handle_abts_recv_work(struct work_struct *work) struct qla_hw_data *ha = vha->hw; unsigned long flags; - if (qla2x00_reset_active(vha) || (op->chip_reset != ha->chip_reset)) + if (qla2x00_reset_active(vha) || + (op->chip_reset != ha->base_qpair->chip_reset)) return; spin_lock_irqsave(&ha->tgt.atio_lock, flags); @@ -6788,14 +6880,15 @@ qlt_handle_abts_recv_work(struct work_struct *work) spin_unlock_irqrestore(&ha->tgt.atio_lock, flags); spin_lock_irqsave(&ha->hardware_lock, flags); - qlt_response_pkt_all_vps(vha, (response_t *)&op->atio); + qlt_response_pkt_all_vps(vha, op->rsp, (response_t *)&op->atio); spin_unlock_irqrestore(&ha->hardware_lock, flags); kfree(op); } void -qlt_handle_abts_recv(struct scsi_qla_host *vha, response_t *pkt) +qlt_handle_abts_recv(struct scsi_qla_host *vha, struct rsp_que *rsp, + response_t *pkt) { struct qla_tgt_sess_op *op; @@ -6805,13 +6898,14 @@ qlt_handle_abts_recv(struct scsi_qla_host *vha, response_t *pkt) /* do not reach for ATIO queue here. This is best effort err * recovery at this point. */ - qlt_response_pkt_all_vps(vha, pkt); + qlt_response_pkt_all_vps(vha, rsp, pkt); return; } memcpy(&op->atio, pkt, sizeof(*pkt)); op->vha = vha; - op->chip_reset = vha->hw->chip_reset; + op->chip_reset = vha->hw->base_qpair->chip_reset; + op->rsp = rsp; INIT_WORK(&op->work, qlt_handle_abts_recv_work); queue_work(qla_tgt_wq, &op->work); return; @@ -6872,25 +6966,25 @@ qlt_update_vp_map(struct scsi_qla_host *vha, int cmd) case SET_AL_PA: slot = btree_lookup32(&vha->hw->tgt.host_map, key); if (!slot) { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xffff, + ql_dbg(ql_dbg_tgt_mgt, vha, 0xf018, "Save vha in host_map %p %06x\n", vha, key); rc = btree_insert32(&vha->hw->tgt.host_map, key, vha, GFP_ATOMIC); if (rc) - ql_log(ql_log_info, vha, 0xffff, + ql_log(ql_log_info, vha, 0xd03e, "Unable to insert s_id into host_map: %06x\n", key); return; } - ql_dbg(ql_dbg_tgt_mgt, vha, 0xffff, - "replace existing vha in host_map %p %06x\n", vha, key); + ql_dbg(ql_dbg_tgt_mgt, vha, 0xf019, + "replace existing vha in host_map %p %06x\n", vha, key); btree_update32(&vha->hw->tgt.host_map, key, vha); break; case RESET_VP_IDX: vha->hw->tgt.tgt_vp_map[vha->vp_idx].vha = NULL; break; case RESET_AL_PA: - ql_dbg(ql_dbg_tgt_mgt, vha, 0xffff, + ql_dbg(ql_dbg_tgt_mgt, vha, 0xf01a, "clear vha in host_map %p %06x\n", vha, key); slot = btree_lookup32(&vha->hw->tgt.host_map, key); if (slot) @@ -6952,7 +7046,7 @@ int __init qlt_init(void) sizeof(struct qla_tgt_mgmt_cmd), __alignof__(struct qla_tgt_mgmt_cmd), 0, NULL); if (!qla_tgt_mgmt_cmd_cachep) { - ql_log(ql_log_fatal, NULL, 0xe06d, + ql_log(ql_log_fatal, NULL, 0xd04b, "kmem_cache_create for qla_tgt_mgmt_cmd_cachep failed\n"); return -ENOMEM; } diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h index d64420251194..7fe02d036bdf 100644 --- a/drivers/scsi/qla2xxx/qla_target.h +++ b/drivers/scsi/qla2xxx/qla_target.h @@ -70,6 +70,16 @@ /* Used to mark CTIO as intermediate */ #define CTIO_INTERMEDIATE_HANDLE_MARK BIT_30 +#define QLA_TGT_NULL_HANDLE 0 + +#define QLA_TGT_HANDLE_MASK 0xF0000000 +#define QLA_QPID_HANDLE_MASK 0x00FF0000 /* qpair id mask */ +#define QLA_CMD_HANDLE_MASK 0x0000FFFF +#define QLA_TGT_SKIP_HANDLE (0xFFFFFFFF & ~QLA_TGT_HANDLE_MASK) + +#define QLA_QPID_HANDLE_SHIFT 16 +#define GET_QID(_h) ((_h & QLA_QPID_HANDLE_MASK) >> QLA_QPID_HANDLE_SHIFT) + #ifndef OF_SS_MODE_0 /* @@ -426,7 +436,7 @@ struct ctio7_to_24xx { } status0; struct { uint16_t sense_length; - uint16_t flags; + __le16 flags; uint32_t residual; __le16 ox_id; uint16_t scsi_status; @@ -664,6 +674,7 @@ struct abts_resp_from_24xx_fw { struct qla_tgt_mgmt_cmd; struct fc_port; +struct qla_tgt_cmd; /* * This structure provides a template of function calls that the @@ -675,7 +686,7 @@ struct qla_tgt_func_tmpl { int (*handle_cmd)(struct scsi_qla_host *, struct qla_tgt_cmd *, unsigned char *, uint32_t, int, int, int); void (*handle_data)(struct qla_tgt_cmd *); - int (*handle_tmr)(struct qla_tgt_mgmt_cmd *, uint32_t, uint16_t, + int (*handle_tmr)(struct qla_tgt_mgmt_cmd *, u64, uint16_t, uint32_t); void (*free_cmd)(struct qla_tgt_cmd *); void (*free_mcmd)(struct qla_tgt_mgmt_cmd *); @@ -744,11 +755,6 @@ int qla2x00_wait_for_hba_online(struct scsi_qla_host *); #define QLA_TGT_STATE_DATA_IN 2 /* Data arrived + target processing */ #define QLA_TGT_STATE_PROCESSED 3 /* target done processing */ - -/* Special handles */ -#define QLA_TGT_NULL_HANDLE 0 -#define QLA_TGT_SKIP_HANDLE (0xFFFFFFFF & ~CTIO_COMPLETION_HANDLE_MARK) - /* ATIO task_codes field */ #define ATIO_SIMPLE_QUEUE 0 #define ATIO_HEAD_OF_QUEUE 1 @@ -781,22 +787,28 @@ struct qla_port_24xx_data { uint16_t reserved; }; +struct qla_qpair_hint { + struct list_head hint_elem; + struct qla_qpair *qpair; + u16 cpuid; + uint8_t cmd_cnt; +}; + struct qla_tgt { struct scsi_qla_host *vha; struct qla_hw_data *ha; - + struct btree_head64 lun_qpair_map; + struct qla_qpair_hint *qphints; /* * To sync between IRQ handlers and qlt_target_release(). Needed, * because req_pkt() can drop/reaquire HW lock inside. Protected by * HW lock. */ - int irq_cmd_count; int atio_irq_cmd_count; - int datasegs_per_cmd, datasegs_per_cont, sg_tablesize; + int sg_tablesize; /* Target's flags, serialized by pha->hardware_lock */ - unsigned int tgt_enable_64bit_addr:1; /* 64-bits PCI addr enabled */ unsigned int link_reinit_iocb_pending:1; /* @@ -832,6 +844,7 @@ struct qla_tgt_sess_op { struct work_struct work; struct list_head cmd_list; bool aborted; + struct rsp_que *rsp; }; enum trace_flags { @@ -859,10 +872,16 @@ enum trace_flags { }; struct qla_tgt_cmd { + /* + * Do not move cmd_type field. it needs to line up with srb->cmd_type + */ + uint8_t cmd_type; + uint8_t pad[7]; struct se_cmd se_cmd; struct fc_port *sess; + struct qla_qpair *qpair; + uint32_t reset_count; int state; - struct work_struct free_work; struct work_struct work; /* Sense buffer that will be mapped into outgoing status */ unsigned char sense_buffer[TRANSPORT_SENSE_BUFFER]; @@ -885,10 +904,10 @@ struct qla_tgt_cmd { int sg_cnt; /* SG segments count */ int bufflen; /* cmd buffer length */ int offset; - uint32_t unpacked_lun; + u64 unpacked_lun; enum dma_data_direction dma_data_direction; - uint32_t reset_count; + uint16_t vp_idx; uint16_t loop_id; /* to save extra sess dereferences */ struct qla_tgt *tgt; /* to save extra sess dereferences */ struct scsi_qla_host *vha; @@ -939,6 +958,7 @@ struct qla_tgt_mgmt_cmd { uint16_t tmr_func; uint8_t fc_tm_rsp; struct fc_port *sess; + struct qla_qpair *qpair; struct se_cmd se_cmd; struct work_struct free_work; unsigned int flags; @@ -960,7 +980,6 @@ struct qla_tgt_prm { int seg_cnt; int req_cnt; uint16_t rq_result; - uint16_t scsi_status; int sense_buffer_len; int residual; int add_status_pkt; @@ -1040,7 +1059,8 @@ static inline void sid_to_portid(const uint8_t *s_id, port_id_t *p) /* * Exported symbols from qla_target.c LLD logic used by qla2xxx code.. */ -extern void qlt_response_pkt_all_vps(struct scsi_qla_host *, response_t *); +extern void qlt_response_pkt_all_vps(struct scsi_qla_host *, struct rsp_que *, + response_t *); extern int qlt_rdy_to_xfer(struct qla_tgt_cmd *); extern int qlt_xmit_response(struct qla_tgt_cmd *, int, uint8_t); extern int qlt_abort_cmd(struct qla_tgt_cmd *); @@ -1073,11 +1093,13 @@ extern int qlt_stop_phase1(struct qla_tgt *); extern void qlt_stop_phase2(struct qla_tgt *); extern irqreturn_t qla83xx_msix_atio_q(int, void *); extern void qlt_83xx_iospace_config(struct qla_hw_data *); -extern int qlt_free_qfull_cmds(struct scsi_qla_host *); +extern int qlt_free_qfull_cmds(struct qla_qpair *); extern void qlt_logo_completion_handler(fc_port_t *, int); extern void qlt_do_generation_tick(struct scsi_qla_host *, int *); -void qlt_send_resp_ctio(scsi_qla_host_t *, struct qla_tgt_cmd *, uint8_t, +void qlt_send_resp_ctio(struct qla_qpair *, struct qla_tgt_cmd *, uint8_t, uint8_t, uint8_t, uint8_t); +extern void qlt_abort_cmd_on_host_reset(struct scsi_qla_host *, + struct qla_tgt_cmd *); #endif /* __QLA_TARGET_H */ diff --git a/drivers/scsi/qla2xxx/qla_tmpl.c b/drivers/scsi/qla2xxx/qla_tmpl.c index c197972a3e2d..33142610882f 100644 --- a/drivers/scsi/qla2xxx/qla_tmpl.c +++ b/drivers/scsi/qla2xxx/qla_tmpl.c @@ -219,8 +219,6 @@ qla27xx_skip_entry(struct qla27xx_fwdt_entry *ent, void *buf) { if (buf) ent->hdr.driver_flags |= DRIVER_FLAG_SKIP_ENTRY; - ql_dbg(ql_dbg_misc + ql_dbg_verbose, NULL, 0xd011, - "Skipping entry %d\n", ent->hdr.entry_type); } static int @@ -818,6 +816,8 @@ qla27xx_walk_template(struct scsi_qla_host *vha, ql_dbg(ql_dbg_misc, vha, 0xd01a, "%s: entry count %lx\n", __func__, count); while (count--) { + if (buf && *len >= vha->hw->fw_dump_len) + break; if (qla27xx_find_entry(ent->hdr.entry_type)(vha, ent, buf, len)) break; ent = qla27xx_next_entry(ent); @@ -825,18 +825,20 @@ qla27xx_walk_template(struct scsi_qla_host *vha, if (count) ql_dbg(ql_dbg_misc, vha, 0xd018, - "%s: residual count (%lx)\n", __func__, count); + "%s: entry residual count (%lx)\n", __func__, count); if (ent->hdr.entry_type != ENTRY_TYPE_TMP_END) ql_dbg(ql_dbg_misc, vha, 0xd019, - "%s: missing end (%lx)\n", __func__, count); + "%s: missing end entry (%lx)\n", __func__, count); - ql_dbg(ql_dbg_misc, vha, 0xd01b, - "%s: len=%lx\n", __func__, *len); + if (buf && *len != vha->hw->fw_dump_len) + ql_dbg(ql_dbg_misc, vha, 0xd01b, + "%s: length=%#lx residual=%+ld\n", + __func__, *len, vha->hw->fw_dump_len - *len); if (buf) { ql_log(ql_log_warn, vha, 0xd015, - "Firmware dump saved to temp buffer (%ld/%p)\n", + "Firmware dump saved to temp buffer (%lu/%p)\n", vha->host_no, vha->hw->fw_dump); qla2x00_post_uevent_work(vha, QLA_UEVENT_CODE_FW_DUMP); } diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index 45bc84e8e3bf..005a378f7fab 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -7,9 +7,9 @@ /* * Driver version */ -#define QLA2XXX_VERSION "9.00.00.00-k" +#define QLA2XXX_VERSION "10.00.00.00-k" -#define QLA_DRIVER_MAJOR_VER 9 +#define QLA_DRIVER_MAJOR_VER 10 #define QLA_DRIVER_MINOR_VER 0 #define QLA_DRIVER_PATCH_VER 0 #define QLA_DRIVER_BETA_VER 0 diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index 7443e4efa3ae..c4b414833b86 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -25,7 +25,6 @@ #include <linux/module.h> #include <linux/moduleparam.h> -#include <generated/utsrelease.h> #include <linux/utsname.h> #include <linux/vmalloc.h> #include <linux/init.h> @@ -284,7 +283,7 @@ static void tcm_qla2xxx_complete_free(struct work_struct *work) WARN_ON(cmd->trc_flags & TRC_CMD_FREE); - cmd->vha->tgt_counters.qla_core_ret_sta_ctio++; + cmd->qpair->tgt_counters.qla_core_ret_sta_ctio++; cmd->trc_flags |= TRC_CMD_FREE; transport_generic_free_cmd(&cmd->se_cmd, 0); } @@ -296,7 +295,7 @@ static void tcm_qla2xxx_complete_free(struct work_struct *work) */ static void tcm_qla2xxx_free_cmd(struct qla_tgt_cmd *cmd) { - cmd->vha->tgt_counters.core_qla_free_cmd++; + cmd->qpair->tgt_counters.core_qla_free_cmd++; cmd->cmd_in_wq = 1; WARN_ON(cmd->trc_flags & TRC_CMD_DONE); @@ -492,7 +491,7 @@ static int tcm_qla2xxx_handle_cmd(scsi_qla_host_t *vha, struct qla_tgt_cmd *cmd, } #endif - cmd->vha->tgt_counters.qla_core_sbt_cmd++; + cmd->qpair->tgt_counters.qla_core_sbt_cmd++; return target_submit_cmd(se_cmd, se_sess, cdb, &cmd->sense_buffer[0], cmd->unpacked_lun, data_length, fcp_task_attr, data_dir, flags); @@ -520,7 +519,7 @@ static void tcm_qla2xxx_handle_data_work(struct work_struct *work) } spin_unlock_irqrestore(&cmd->cmd_lock, flags); - cmd->vha->tgt_counters.qla_core_ret_ctio++; + cmd->qpair->tgt_counters.qla_core_ret_ctio++; if (!cmd->write_data_transferred) { /* * Check if se_cmd has already been aborted via LUN_RESET, and @@ -595,7 +594,7 @@ static int tcm_qla2xxx_dif_tags(struct qla_tgt_cmd *cmd, /* * Called from qla_target.c:qlt_issue_task_mgmt() */ -static int tcm_qla2xxx_handle_tmr(struct qla_tgt_mgmt_cmd *mcmd, uint32_t lun, +static int tcm_qla2xxx_handle_tmr(struct qla_tgt_mgmt_cmd *mcmd, u64 lun, uint16_t tmr_func, uint32_t tag) { struct fc_port *sess = mcmd->sess; @@ -686,6 +685,19 @@ static int tcm_qla2xxx_queue_status(struct se_cmd *se_cmd) struct qla_tgt_cmd, se_cmd); int xmit_type = QLA_TGT_XMIT_STATUS; + if (cmd->aborted) { + /* + * Cmd can loop during Q-full. tcm_qla2xxx_aborted_task + * can get ahead of this cmd. tcm_qla2xxx_aborted_task + * already kick start the free. + */ + pr_debug( + "queue_data_in aborted cmd[%p] refcount %d transport_state %x, t_state %x, se_cmd_flags %x\n", + cmd, kref_read(&cmd->se_cmd.cmd_kref), + cmd->se_cmd.transport_state, cmd->se_cmd.t_state, + cmd->se_cmd.se_cmd_flags); + return 0; + } cmd->bufflen = se_cmd->data_length; cmd->sg = NULL; cmd->sg_cnt = 0; @@ -1870,9 +1882,9 @@ static ssize_t tcm_qla2xxx_wwn_version_show(struct config_item *item, char *page) { return sprintf(page, - "TCM QLOGIC QLA2XXX NPIV capable fabric module %s on %s/%s on " - UTS_RELEASE"\n", QLA2XXX_VERSION, utsname()->sysname, - utsname()->machine); + "TCM QLOGIC QLA2XXX NPIV capable fabric module %s on %s/%s on %s\n", + QLA2XXX_VERSION, utsname()->sysname, + utsname()->machine, utsname()->release); } CONFIGFS_ATTR_RO(tcm_qla2xxx_wwn_, version); @@ -1976,9 +1988,9 @@ static int tcm_qla2xxx_register_configfs(void) { int ret; - pr_debug("TCM QLOGIC QLA2XXX fabric module %s on %s/%s on " - UTS_RELEASE"\n", QLA2XXX_VERSION, utsname()->sysname, - utsname()->machine); + pr_debug("TCM QLOGIC QLA2XXX fabric module %s on %s/%s on %s\n", + QLA2XXX_VERSION, utsname()->sysname, + utsname()->machine, utsname()->release); ret = target_register_template(&tcm_qla2xxx_ops); if (ret) |