diff options
Diffstat (limited to 'drivers/scsi/qla2xxx')
23 files changed, 2794 insertions, 1470 deletions
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index d7e7043f9eab..97cabd7e0014 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -1324,6 +1324,79 @@ qla2x00_beacon_store(struct device *dev, struct device_attribute *attr, } static ssize_t +qla2x00_beacon_config_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); + struct qla_hw_data *ha = vha->hw; + uint16_t led[3] = { 0 }; + + if (!IS_QLA2031(ha) && !IS_QLA27XX(ha) && !IS_QLA28XX(ha)) + return -EPERM; + + if (ql26xx_led_config(vha, 0, led)) + return scnprintf(buf, PAGE_SIZE, "\n"); + + return scnprintf(buf, PAGE_SIZE, "%#04hx %#04hx %#04hx\n", + led[0], led[1], led[2]); +} + +static ssize_t +qla2x00_beacon_config_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); + struct qla_hw_data *ha = vha->hw; + uint16_t options = BIT_0; + uint16_t led[3] = { 0 }; + uint16_t word[4]; + int n; + + if (!IS_QLA2031(ha) && !IS_QLA27XX(ha) && !IS_QLA28XX(ha)) + return -EPERM; + + n = sscanf(buf, "%hx %hx %hx %hx", word+0, word+1, word+2, word+3); + if (n == 4) { + if (word[0] == 3) { + options |= BIT_3|BIT_2|BIT_1; + led[0] = word[1]; + led[1] = word[2]; + led[2] = word[3]; + goto write; + } + return -EINVAL; + } + + if (n == 2) { + /* check led index */ + if (word[0] == 0) { + options |= BIT_2; + led[0] = word[1]; + goto write; + } + if (word[0] == 1) { + options |= BIT_3; + led[1] = word[1]; + goto write; + } + if (word[0] == 2) { + options |= BIT_1; + led[2] = word[1]; + goto write; + } + return -EINVAL; + } + + return -EINVAL; + +write: + if (ql26xx_led_config(vha, options, led)) + return -EFAULT; + + return count; +} + +static ssize_t qla2x00_optrom_bios_version_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -2250,6 +2323,26 @@ qla2x00_port_no_show(struct device *dev, struct device_attribute *attr, return scnprintf(buf, PAGE_SIZE, "%u\n", vha->hw->port_no); } +static ssize_t +qla2x00_dport_diagnostics_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); + + if (!IS_QLA83XX(vha->hw) && !IS_QLA27XX(vha->hw) && + !IS_QLA28XX(vha->hw)) + return scnprintf(buf, PAGE_SIZE, "\n"); + + if (!*vha->dport_data) + return scnprintf(buf, PAGE_SIZE, "\n"); + + return scnprintf(buf, PAGE_SIZE, "%04x %04x %04x %04x\n", + vha->dport_data[0], vha->dport_data[1], + vha->dport_data[2], vha->dport_data[3]); +} +static DEVICE_ATTR(dport_diagnostics, 0444, + qla2x00_dport_diagnostics_show, NULL); + static DEVICE_ATTR(driver_version, S_IRUGO, qla2x00_driver_version_show, NULL); static DEVICE_ATTR(fw_version, S_IRUGO, qla2x00_fw_version_show, NULL); static DEVICE_ATTR(serial_num, S_IRUGO, qla2x00_serial_num_show, NULL); @@ -2264,6 +2357,8 @@ static DEVICE_ATTR(zio_timer, S_IRUGO | S_IWUSR, qla2x00_zio_timer_show, qla2x00_zio_timer_store); static DEVICE_ATTR(beacon, S_IRUGO | S_IWUSR, qla2x00_beacon_show, qla2x00_beacon_store); +static DEVICE_ATTR(beacon_config, 0644, qla2x00_beacon_config_show, + qla2x00_beacon_config_store); static DEVICE_ATTR(optrom_bios_version, S_IRUGO, qla2x00_optrom_bios_version_show, NULL); static DEVICE_ATTR(optrom_efi_version, S_IRUGO, @@ -2327,6 +2422,7 @@ struct device_attribute *qla2x00_host_attrs[] = { &dev_attr_zio, &dev_attr_zio_timer, &dev_attr_beacon, + &dev_attr_beacon_config, &dev_attr_optrom_bios_version, &dev_attr_optrom_efi_version, &dev_attr_optrom_fcode_version, @@ -2355,6 +2451,7 @@ struct device_attribute *qla2x00_host_attrs[] = { &dev_attr_port_speed, &dev_attr_port_no, &dev_attr_fw_attr, + &dev_attr_dport_diagnostics, NULL, /* reserve for qlini_mode */ NULL, /* reserve for ql2xiniexchg */ NULL, /* reserve for ql2xexchoffld */ @@ -2648,22 +2745,28 @@ qla2x00_get_fc_host_stats(struct Scsi_Host *shost) if (rval != QLA_SUCCESS) goto done_free; - p->link_failure_count = stats->link_fail_cnt; - p->loss_of_sync_count = stats->loss_sync_cnt; - p->loss_of_signal_count = stats->loss_sig_cnt; - p->prim_seq_protocol_err_count = stats->prim_seq_err_cnt; - p->invalid_tx_word_count = stats->inval_xmit_word_cnt; - p->invalid_crc_count = stats->inval_crc_cnt; + p->link_failure_count = le32_to_cpu(stats->link_fail_cnt); + p->loss_of_sync_count = le32_to_cpu(stats->loss_sync_cnt); + p->loss_of_signal_count = le32_to_cpu(stats->loss_sig_cnt); + p->prim_seq_protocol_err_count = le32_to_cpu(stats->prim_seq_err_cnt); + p->invalid_tx_word_count = le32_to_cpu(stats->inval_xmit_word_cnt); + p->invalid_crc_count = le32_to_cpu(stats->inval_crc_cnt); if (IS_FWI2_CAPABLE(ha)) { - p->lip_count = stats->lip_cnt; - p->tx_frames = stats->tx_frames; - p->rx_frames = stats->rx_frames; - p->dumped_frames = stats->discarded_frames; - p->nos_count = stats->nos_rcvd; + p->lip_count = le32_to_cpu(stats->lip_cnt); + p->tx_frames = le32_to_cpu(stats->tx_frames); + p->rx_frames = le32_to_cpu(stats->rx_frames); + p->dumped_frames = le32_to_cpu(stats->discarded_frames); + p->nos_count = le32_to_cpu(stats->nos_rcvd); p->error_frames = - stats->dropped_frames + stats->discarded_frames; - p->rx_words = vha->qla_stats.input_bytes; - p->tx_words = vha->qla_stats.output_bytes; + le32_to_cpu(stats->dropped_frames) + + le32_to_cpu(stats->discarded_frames); + if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) { + p->rx_words = le64_to_cpu(stats->fpm_recv_word_cnt); + p->tx_words = le64_to_cpu(stats->fpm_xmit_word_cnt); + } else { + p->rx_words = vha->qla_stats.input_bytes; + p->tx_words = vha->qla_stats.output_bytes; + } } p->fcp_control_requests = vha->qla_stats.control_requests; p->fcp_input_requests = vha->qla_stats.input_requests; @@ -2671,7 +2774,7 @@ qla2x00_get_fc_host_stats(struct Scsi_Host *shost) p->fcp_input_megabytes = vha->qla_stats.input_bytes >> 20; p->fcp_output_megabytes = vha->qla_stats.output_bytes >> 20; p->seconds_since_last_reset = - get_jiffies_64() - vha->qla_stats.jiffies_at_last_reset; + get_jiffies_64() - vha->qla_stats.jiffies_at_last_reset; do_div(p->seconds_since_last_reset, HZ); done_free: diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c index d7169e43f5e1..97b51c477972 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.c +++ b/drivers/scsi/qla2xxx/qla_bsg.c @@ -11,6 +11,14 @@ #include <linux/delay.h> #include <linux/bsg-lib.h> +static void qla2xxx_free_fcport_work(struct work_struct *work) +{ + struct fc_port *fcport = container_of(work, typeof(*fcport), + free_work); + + qla2x00_free_fcport(fcport); +} + /* BSG support for ELS/CT pass through */ void qla2x00_bsg_job_done(srb_t *sp, int res) { @@ -53,8 +61,10 @@ void qla2x00_bsg_sp_free(srb_t *sp) if (sp->type == SRB_CT_CMD || sp->type == SRB_FXIOCB_BCMD || - sp->type == SRB_ELS_CMD_HST) - qla2x00_free_fcport(sp->fcport); + sp->type == SRB_ELS_CMD_HST) { + INIT_WORK(&sp->fcport->free_work, qla2xxx_free_fcport_work); + queue_work(ha->wq, &sp->fcport->free_work); + } qla2x00_rel_sp(sp); } @@ -718,7 +728,7 @@ qla2x00_process_loopback(struct bsg_job *bsg_job) uint16_t response[MAILBOX_REGISTER_COUNT]; uint16_t config[4], new_config[4]; uint8_t *fw_sts_ptr; - uint8_t *req_data = NULL; + void *req_data = NULL; dma_addr_t req_data_dma; uint32_t req_data_len; uint8_t *rsp_data = NULL; @@ -796,10 +806,11 @@ qla2x00_process_loopback(struct bsg_job *bsg_job) bsg_request->rqst_data.h_vendor.vendor_cmd[2]; if (atomic_read(&vha->loop_state) == LOOP_READY && - (ha->current_topology == ISP_CFG_F || - (get_unaligned_le32(req_data) == ELS_OPCODE_BYTE && - req_data_len == MAX_ELS_FRAME_PAYLOAD)) && - elreq.options == EXTERNAL_LOOPBACK) { + ((ha->current_topology == ISP_CFG_F && (elreq.options & 7) >= 2) || + ((IS_QLA81XX(ha) || IS_QLA8031(ha) || IS_QLA8044(ha)) && + get_unaligned_le32(req_data) == ELS_OPCODE_BYTE && + req_data_len == MAX_ELS_FRAME_PAYLOAD && + elreq.options == EXTERNAL_LOOPBACK))) { type = "FC_BSG_HST_VENDOR_ECHO_DIAG"; ql_dbg(ql_dbg_user, vha, 0x701e, "BSG request type: %s.\n", type); @@ -1506,10 +1517,15 @@ qla2x00_update_optrom(struct bsg_job *bsg_job) bsg_job->request_payload.sg_cnt, ha->optrom_buffer, ha->optrom_region_size); - ha->isp_ops->write_optrom(vha, ha->optrom_buffer, + rval = ha->isp_ops->write_optrom(vha, ha->optrom_buffer, ha->optrom_region_start, ha->optrom_region_size); - bsg_reply->result = DID_OK; + if (rval) { + bsg_reply->result = -EINVAL; + rval = -EINVAL; + } else { + bsg_reply->result = DID_OK; + } vfree(ha->optrom_buffer); ha->optrom_buffer = NULL; ha->optrom_state = QLA_SWAITING; @@ -2404,7 +2420,7 @@ qla2x00_get_flash_image_status(struct bsg_job *bsg_job) regions.global_image = active_regions.global; if (IS_QLA28XX(ha)) { - qla27xx_get_active_image(vha, &active_regions); + qla28xx_get_aux_images(vha, &active_regions); regions.board_config = active_regions.aux.board_config; regions.vpd_nvram = active_regions.aux.vpd_nvram; regions.npiv_config_0_1 = active_regions.aux.npiv_config_0_1; diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index 88a56e8480f7..bf1e98f11990 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.c +++ b/drivers/scsi/qla2xxx/qla_dbg.c @@ -73,6 +73,8 @@ #include "qla_def.h" #include <linux/delay.h> +#define CREATE_TRACE_POINTS +#include <trace/events/qla.h> static uint32_t ql_dbg_offset = 0x800; @@ -2538,14 +2540,30 @@ ql_dbg(uint level, scsi_qla_host_t *vha, uint 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 (!ql_mask_match(level)) { + char pbuf[64]; + + if (vha != NULL) { + const struct pci_dev *pdev = vha->hw->pdev; + /* <module-name> <msg-id>:<host> Message */ + snprintf(pbuf, sizeof(pbuf), "%s [%s]-%04x:%ld: ", + QL_MSGHDR, dev_name(&(pdev->dev)), id, + vha->host_no); + } else { + snprintf(pbuf, sizeof(pbuf), "%s [%s]-%04x: : ", + QL_MSGHDR, "0000:00:00.0", id); + } + pbuf[sizeof(pbuf) - 1] = 0; + trace_ql_dbg_log(pbuf, &vaf); + va_end(va); + return; + } + if (vha != NULL) { const struct pci_dev *pdev = vha->hw->pdev; /* <module-name> <pci-name> <msg-id>:<host> Message */ diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index ed32e9715794..47c7a56438b5 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -119,7 +119,10 @@ typedef struct { #define LSD(x) ((uint32_t)((uint64_t)(x))) #define MSD(x) ((uint32_t)((((uint64_t)(x)) >> 16) >> 16)) -#define MAKE_HANDLE(x, y) ((uint32_t)((((uint32_t)(x)) << 16) | (uint32_t)(y))) +static inline uint32_t make_handle(uint16_t x, uint16_t y) +{ + return ((uint32_t)x << 16) | y; +} /* * I/O register @@ -414,7 +417,7 @@ struct els_logo_payload { struct els_plogi_payload { uint8_t opcode; uint8_t rsvd[3]; - uint8_t data[112]; + __be32 data[112 / 4]; }; struct ct_arg { @@ -597,9 +600,6 @@ typedef struct srb { struct fc_port *fcport; struct scsi_qla_host *vha; unsigned int start_timer:1; - unsigned int abort:1; - unsigned int aborted:1; - unsigned int completed:1; uint32_t handle; uint16_t flags; @@ -1049,6 +1049,7 @@ static inline bool qla2xxx_is_valid_mbs(unsigned int mbs) #define MBA_TEMPERATURE_ALERT 0x8070 /* Temperature Alert */ #define MBA_DPORT_DIAGNOSTICS 0x8080 /* D-port Diagnostics */ #define MBA_TRANS_INSERT 0x8130 /* Transceiver Insertion */ +#define MBA_TRANS_REMOVE 0x8131 /* Transceiver Removal */ #define MBA_FW_INIT_FAILURE 0x8401 /* Firmware initialization failure */ #define MBA_MIRROR_LUN_CHANGE 0x8402 /* Mirror LUN State Change Notification */ @@ -1134,6 +1135,7 @@ static inline bool qla2xxx_is_valid_mbs(unsigned int mbs) #define MBC_GET_FIRMWARE_OPTION 0x28 /* Get Firmware Options. */ #define MBC_GET_MEM_OFFLOAD_CNTRL_STAT 0x34 /* Memory Offload ctrl/Stat*/ #define MBC_SET_FIRMWARE_OPTION 0x38 /* Set Firmware Options. */ +#define MBC_SET_GET_FC_LED_CONFIG 0x3b /* Set/Get FC LED config */ #define MBC_LOOP_PORT_BYPASS 0x40 /* Loop Port Bypass. */ #define MBC_LOOP_PORT_ENABLE 0x41 /* Loop Port Enable. */ #define MBC_GET_RESOURCE_COUNTS 0x42 /* Get Resource Counts. */ @@ -1260,10 +1262,15 @@ static inline bool qla2xxx_is_valid_mbs(unsigned int mbs) #define MBX_1 BIT_1 #define MBX_0 BIT_0 +#define RNID_TYPE_ELS_CMD 0x5 #define RNID_TYPE_PORT_LOGIN 0x7 +#define RNID_BUFFER_CREDITS 0x8 #define RNID_TYPE_SET_VERSION 0x9 #define RNID_TYPE_ASIC_TEMP 0xC +#define ELS_CMD_MAP_SIZE 32 +#define ELS_COMMAND_RDP 0x18 + /* * Firmware state codes from get firmware state mailbox command */ @@ -1474,47 +1481,44 @@ typedef struct { #define GLSO_USE_DID BIT_3 struct link_statistics { - uint32_t link_fail_cnt; - uint32_t loss_sync_cnt; - uint32_t loss_sig_cnt; - uint32_t prim_seq_err_cnt; - uint32_t inval_xmit_word_cnt; - uint32_t inval_crc_cnt; - uint32_t lip_cnt; - uint32_t link_up_cnt; - uint32_t link_down_loop_init_tmo; - uint32_t link_down_los; - uint32_t link_down_loss_rcv_clk; + __le32 link_fail_cnt; + __le32 loss_sync_cnt; + __le32 loss_sig_cnt; + __le32 prim_seq_err_cnt; + __le32 inval_xmit_word_cnt; + __le32 inval_crc_cnt; + __le32 lip_cnt; + __le32 link_up_cnt; + __le32 link_down_loop_init_tmo; + __le32 link_down_los; + __le32 link_down_loss_rcv_clk; uint32_t reserved0[5]; - uint32_t port_cfg_chg; + __le32 port_cfg_chg; uint32_t reserved1[11]; - uint32_t rsp_q_full; - uint32_t atio_q_full; - uint32_t drop_ae; - uint32_t els_proto_err; - uint32_t reserved2; - uint32_t tx_frames; - uint32_t rx_frames; - uint32_t discarded_frames; - uint32_t dropped_frames; + __le32 rsp_q_full; + __le32 atio_q_full; + __le32 drop_ae; + __le32 els_proto_err; + __le32 reserved2; + __le32 tx_frames; + __le32 rx_frames; + __le32 discarded_frames; + __le32 dropped_frames; uint32_t reserved3; - uint32_t nos_rcvd; + __le32 nos_rcvd; uint32_t reserved4[4]; - uint32_t tx_prjt; - uint32_t rcv_exfail; - uint32_t rcv_abts; - uint32_t seq_frm_miss; - uint32_t corr_err; - uint32_t mb_rqst; - uint32_t nport_full; - uint32_t eofa; + __le32 tx_prjt; + __le32 rcv_exfail; + __le32 rcv_abts; + __le32 seq_frm_miss; + __le32 corr_err; + __le32 mb_rqst; + __le32 nport_full; + __le32 eofa; uint32_t reserved5; - uint32_t fpm_recv_word_cnt_lo; - uint32_t fpm_recv_word_cnt_hi; - uint32_t fpm_disc_word_cnt_lo; - uint32_t fpm_disc_word_cnt_hi; - uint32_t fpm_xmit_word_cnt_lo; - uint32_t fpm_xmit_word_cnt_hi; + __le64 fpm_recv_word_cnt; + __le64 fpm_disc_word_cnt; + __le64 fpm_xmit_word_cnt; uint32_t reserved6[70]; }; @@ -2624,10 +2628,11 @@ static const char * const port_dstate_str[] = { #define GFF_ID_RSP_SIZE (16 + 128) /* - * HBA attribute types. + * FDMI HBA attribute types. */ -#define FDMI_HBA_ATTR_COUNT 9 -#define FDMIV2_HBA_ATTR_COUNT 17 +#define FDMI1_HBA_ATTR_COUNT 9 +#define FDMI2_HBA_ATTR_COUNT 17 + #define FDMI_HBA_NODE_NAME 0x1 #define FDMI_HBA_MANUFACTURER 0x2 #define FDMI_HBA_SERIAL_NUMBER 0x3 @@ -2639,12 +2644,13 @@ static const char * const port_dstate_str[] = { #define FDMI_HBA_FIRMWARE_VERSION 0x9 #define FDMI_HBA_OS_NAME_AND_VERSION 0xa #define FDMI_HBA_MAXIMUM_CT_PAYLOAD_LENGTH 0xb + #define FDMI_HBA_NODE_SYMBOLIC_NAME 0xc -#define FDMI_HBA_VENDOR_ID 0xd +#define FDMI_HBA_VENDOR_SPECIFIC_INFO 0xd #define FDMI_HBA_NUM_PORTS 0xe #define FDMI_HBA_FABRIC_NAME 0xf #define FDMI_HBA_BOOT_BIOS_NAME 0x10 -#define FDMI_HBA_TYPE_VENDOR_IDENTIFIER 0xe0 +#define FDMI_HBA_VENDOR_IDENTIFIER 0xe0 struct ct_fdmi_hba_attr { uint16_t type; @@ -2661,31 +2667,9 @@ struct ct_fdmi_hba_attr { uint8_t fw_version[32]; uint8_t os_version[128]; uint32_t max_ct_len; - } a; -}; - -struct ct_fdmi_hba_attributes { - uint32_t count; - struct ct_fdmi_hba_attr entry[FDMI_HBA_ATTR_COUNT]; -}; -struct ct_fdmiv2_hba_attr { - uint16_t type; - uint16_t len; - union { - uint8_t node_name[WWN_SIZE]; - uint8_t manufacturer[64]; - uint8_t serial_num[32]; - uint8_t model[16+1]; - uint8_t model_desc[80]; - uint8_t hw_version[16]; - uint8_t driver_version[32]; - uint8_t orom_version[16]; - uint8_t fw_version[32]; - uint8_t os_version[128]; - uint32_t max_ct_len; uint8_t sym_name[256]; - uint32_t vendor_id; + uint32_t vendor_specific_info; uint32_t num_ports; uint8_t fabric_name[WWN_SIZE]; uint8_t bios_name[32]; @@ -2693,22 +2677,30 @@ struct ct_fdmiv2_hba_attr { } a; }; -struct ct_fdmiv2_hba_attributes { +struct ct_fdmi1_hba_attributes { uint32_t count; - struct ct_fdmiv2_hba_attr entry[FDMIV2_HBA_ATTR_COUNT]; + struct ct_fdmi_hba_attr entry[FDMI1_HBA_ATTR_COUNT]; +}; + +struct ct_fdmi2_hba_attributes { + uint32_t count; + struct ct_fdmi_hba_attr entry[FDMI2_HBA_ATTR_COUNT]; }; /* - * Port attribute types. + * FDMI Port attribute types. */ -#define FDMI_PORT_ATTR_COUNT 6 -#define FDMIV2_PORT_ATTR_COUNT 16 +#define FDMI1_PORT_ATTR_COUNT 6 +#define FDMI2_PORT_ATTR_COUNT 16 +#define FDMI2_SMARTSAN_PORT_ATTR_COUNT 23 + #define FDMI_PORT_FC4_TYPES 0x1 #define FDMI_PORT_SUPPORT_SPEED 0x2 #define FDMI_PORT_CURRENT_SPEED 0x3 #define FDMI_PORT_MAX_FRAME_SIZE 0x4 #define FDMI_PORT_OS_DEVICE_NAME 0x5 #define FDMI_PORT_HOST_NAME 0x6 + #define FDMI_PORT_NODE_NAME 0x7 #define FDMI_PORT_NAME 0x8 #define FDMI_PORT_SYM_NAME 0x9 @@ -2718,7 +2710,15 @@ struct ct_fdmiv2_hba_attributes { #define FDMI_PORT_FC4_TYPE 0xd #define FDMI_PORT_STATE 0x101 #define FDMI_PORT_COUNT 0x102 -#define FDMI_PORT_ID 0x103 +#define FDMI_PORT_IDENTIFIER 0x103 + +#define FDMI_SMARTSAN_SERVICE 0xF100 +#define FDMI_SMARTSAN_GUID 0xF101 +#define FDMI_SMARTSAN_VERSION 0xF102 +#define FDMI_SMARTSAN_PROD_NAME 0xF103 +#define FDMI_SMARTSAN_PORT_INFO 0xF104 +#define FDMI_SMARTSAN_QOS_SUPPORT 0xF105 +#define FDMI_SMARTSAN_SECURITY_SUPPORT 0xF106 #define FDMI_PORT_SPEED_1GB 0x1 #define FDMI_PORT_SPEED_2GB 0x2 @@ -2734,7 +2734,7 @@ struct ct_fdmiv2_hba_attributes { #define FC_CLASS_3 0x08 #define FC_CLASS_2_3 0x0C -struct ct_fdmiv2_port_attr { +struct ct_fdmi_port_attr { uint16_t type; uint16_t len; union { @@ -2744,6 +2744,7 @@ struct ct_fdmiv2_port_attr { uint32_t max_frame_size; uint8_t os_dev_name[32]; uint8_t host_name[256]; + uint8_t node_name[WWN_SIZE]; uint8_t port_name[WWN_SIZE]; uint8_t port_sym_name[128]; @@ -2754,35 +2755,38 @@ struct ct_fdmiv2_port_attr { uint32_t port_state; uint32_t num_ports; uint32_t port_id; + + uint8_t smartsan_service[24]; + uint8_t smartsan_guid[16]; + uint8_t smartsan_version[24]; + uint8_t smartsan_prod_name[16]; + uint32_t smartsan_port_info; + uint32_t smartsan_qos_support; + uint32_t smartsan_security_support; } a; }; -/* - * Port Attribute Block. - */ -struct ct_fdmiv2_port_attributes { +struct ct_fdmi1_port_attributes { uint32_t count; - struct ct_fdmiv2_port_attr entry[FDMIV2_PORT_ATTR_COUNT]; -}; - -struct ct_fdmi_port_attr { - uint16_t type; - uint16_t len; - union { - uint8_t fc4_types[32]; - uint32_t sup_speed; - uint32_t cur_speed; - uint32_t max_frame_size; - uint8_t os_dev_name[32]; - uint8_t host_name[256]; - } a; + struct ct_fdmi_port_attr entry[FDMI1_PORT_ATTR_COUNT]; }; -struct ct_fdmi_port_attributes { +struct ct_fdmi2_port_attributes { uint32_t count; - struct ct_fdmi_port_attr entry[FDMI_PORT_ATTR_COUNT]; + struct ct_fdmi_port_attr entry[FDMI2_PORT_ATTR_COUNT]; }; +#define FDMI_ATTR_TYPELEN(obj) \ + (sizeof((obj)->type) + sizeof((obj)->len)) + +#define FDMI_ATTR_ALIGNMENT(len) \ + (4 - ((len) & 3)) + +/* FDMI register call options */ +#define CALLOPT_FDMI1 0 +#define CALLOPT_FDMI2 1 +#define CALLOPT_FDMI2_SMARTSAN 2 + /* FDMI definitions. */ #define GRHL_CMD 0x100 #define GHAT_CMD 0x101 @@ -2793,10 +2797,13 @@ struct ct_fdmi_port_attributes { #define RHBA_RSP_SIZE 16 #define RHAT_CMD 0x201 + #define RPRT_CMD 0x210 +#define RPRT_RSP_SIZE 24 #define RPA_CMD 0x211 #define RPA_RSP_SIZE 16 +#define SMARTSAN_RPA_RSP_SIZE 24 #define DHBA_CMD 0x300 #define DHBA_REQ_SIZE (16 + 8) @@ -2879,30 +2886,24 @@ struct ct_sns_req { uint8_t hba_identifier[8]; uint32_t entry_count; uint8_t port_name[8]; - struct ct_fdmi_hba_attributes attrs; + struct ct_fdmi2_hba_attributes attrs; } rhba; struct { uint8_t hba_identifier[8]; - uint32_t entry_count; - uint8_t port_name[8]; - struct ct_fdmiv2_hba_attributes attrs; - } rhba2; - - struct { - uint8_t hba_identifier[8]; - struct ct_fdmi_hba_attributes attrs; + struct ct_fdmi1_hba_attributes attrs; } rhat; struct { uint8_t port_name[8]; - struct ct_fdmi_port_attributes attrs; + struct ct_fdmi2_port_attributes attrs; } rpa; struct { + uint8_t hba_identifier[8]; uint8_t port_name[8]; - struct ct_fdmiv2_port_attributes attrs; - } rpa2; + struct ct_fdmi2_port_attributes attrs; + } rprt; struct { uint8_t port_name[8]; @@ -3016,7 +3017,7 @@ struct ct_sns_rsp { struct { uint32_t entry_count; uint8_t port_name[8]; - struct ct_fdmi_hba_attributes attrs; + struct ct_fdmi1_hba_attributes attrs; } ghat; struct { @@ -3250,6 +3251,7 @@ struct isp_operations { #define QLA_MSIX_RSP_Q 0x01 #define QLA_ATIO_VECTOR 0x02 #define QLA_MSIX_QPAIR_MULTIQ_RSP_Q 0x03 +#define QLA_MSIX_QPAIR_MULTIQ_RSP_Q_HS 0x04 #define QLA_MIDX_DEFAULT 0 #define QLA_MIDX_RSP_Q 1 @@ -3562,6 +3564,134 @@ struct qlfc_fw { uint32_t len; }; +struct rdp_req_payload { + uint32_t els_request; + uint32_t desc_list_len; + + /* NPIV descriptor */ + struct { + uint32_t desc_tag; + uint32_t desc_len; + uint8_t reserved; + uint8_t nport_id[3]; + } npiv_desc; +}; + +struct rdp_rsp_payload { + struct { + uint32_t cmd; + uint32_t len; + } hdr; + + /* LS Request Info descriptor */ + struct { + uint32_t desc_tag; + uint32_t desc_len; + uint32_t req_payload_word_0; + } ls_req_info_desc; + + /* LS Request Info descriptor */ + struct { + uint32_t desc_tag; + uint32_t desc_len; + uint32_t req_payload_word_0; + } ls_req_info_desc2; + + /* SFP diagnostic param descriptor */ + struct { + uint32_t desc_tag; + uint32_t desc_len; + uint16_t temperature; + uint16_t vcc; + uint16_t tx_bias; + uint16_t tx_power; + uint16_t rx_power; + uint16_t sfp_flags; + } sfp_diag_desc; + + /* Port Speed Descriptor */ + struct { + uint32_t desc_tag; + uint32_t desc_len; + uint16_t speed_capab; + uint16_t operating_speed; + } port_speed_desc; + + /* Link Error Status Descriptor */ + struct { + uint32_t desc_tag; + uint32_t desc_len; + uint32_t link_fail_cnt; + uint32_t loss_sync_cnt; + uint32_t loss_sig_cnt; + uint32_t prim_seq_err_cnt; + uint32_t inval_xmit_word_cnt; + uint32_t inval_crc_cnt; + uint8_t pn_port_phy_type; + uint8_t reserved[3]; + } ls_err_desc; + + /* Port name description with diag param */ + struct { + uint32_t desc_tag; + uint32_t desc_len; + uint8_t WWNN[WWN_SIZE]; + uint8_t WWPN[WWN_SIZE]; + } port_name_diag_desc; + + /* Port Name desc for Direct attached Fx_Port or Nx_Port */ + struct { + uint32_t desc_tag; + uint32_t desc_len; + uint8_t WWNN[WWN_SIZE]; + uint8_t WWPN[WWN_SIZE]; + } port_name_direct_desc; + + /* Buffer Credit descriptor */ + struct { + uint32_t desc_tag; + uint32_t desc_len; + uint32_t fcport_b2b; + uint32_t attached_fcport_b2b; + uint32_t fcport_rtt; + } buffer_credit_desc; + + /* Optical Element Data Descriptor */ + struct { + uint32_t desc_tag; + uint32_t desc_len; + uint16_t high_alarm; + uint16_t low_alarm; + uint16_t high_warn; + uint16_t low_warn; + uint32_t element_flags; + } optical_elmt_desc[5]; + + /* Optical Product Data Descriptor */ + struct { + uint32_t desc_tag; + uint32_t desc_len; + uint8_t vendor_name[16]; + uint8_t part_number[16]; + uint8_t serial_number[16]; + uint8_t revision[4]; + uint8_t date[8]; + } optical_prod_desc; +}; + +#define RDP_DESC_LEN(obj) \ + (sizeof(obj) - sizeof((obj).desc_tag) - sizeof((obj).desc_len)) + +#define RDP_PORT_SPEED_1GB BIT_15 +#define RDP_PORT_SPEED_2GB BIT_14 +#define RDP_PORT_SPEED_4GB BIT_13 +#define RDP_PORT_SPEED_10GB BIT_12 +#define RDP_PORT_SPEED_8GB BIT_11 +#define RDP_PORT_SPEED_16GB BIT_10 +#define RDP_PORT_SPEED_32GB BIT_9 +#define RDP_PORT_SPEED_64GB BIT_8 +#define RDP_PORT_SPEED_UNKNOWN BIT_0 + struct scsi_qlt_host { void *target_lport_ptr; struct mutex tgt_mutex; @@ -3673,8 +3803,8 @@ struct qla_hw_data { uint32_t fw_started:1; uint32_t fw_init_done:1; - uint32_t detected_lr_sfp:1; - uint32_t using_lr_setting:1; + uint32_t lr_detected:1; + uint32_t rida_fmt2:1; uint32_t purge_mbox:1; uint32_t n2n_bigger:1; @@ -3683,7 +3813,7 @@ struct qla_hw_data { } flags; uint16_t max_exchg; - uint16_t long_range_distance; /* 32G & above */ + uint16_t lr_distance; /* 32G & above */ #define LR_DISTANCE_5K 1 #define LR_DISTANCE_10K 0 @@ -3965,6 +4095,8 @@ struct qla_hw_data { #define SFP_DEV_SIZE 512 #define SFP_BLOCK_SIZE 64 +#define SFP_RTDI_LEN SFP_BLOCK_SIZE + void *sfp_data; dma_addr_t sfp_data_dma; @@ -4344,6 +4476,15 @@ struct active_regions { #define QLA_SET_DATA_RATE_NOLR 1 #define QLA_SET_DATA_RATE_LR 2 /* Set speed and initiate LR */ +struct purex_item { + struct list_head list; + struct scsi_qla_host *vha; + void (*process_item)(struct scsi_qla_host *vha, void *pkt); + struct { + uint8_t iocb[64]; + } iocb; +}; + /* * Qlogic scsi host structure */ @@ -4424,6 +4565,8 @@ typedef struct scsi_qla_host { #define ISP_ABORT_TO_ROM 33 #define VPORT_DELETE 34 +#define PROCESS_PUREX_IOCB 63 + unsigned long pci_flags; #define PFLG_DISCONNECTED 0 /* PCI device removed */ #define PFLG_DRIVER_REMOVING 1 /* PCI driver .remove */ @@ -4461,6 +4604,7 @@ typedef struct scsi_qla_host { uint8_t node_name[WWN_SIZE]; uint8_t port_name[WWN_SIZE]; uint8_t fabric_node_name[WWN_SIZE]; + uint8_t fabric_port_name[WWN_SIZE]; struct nvme_fc_local_port *nvme_local_port; struct completion nvme_del_done; @@ -4531,6 +4675,11 @@ typedef struct scsi_qla_host { uint16_t ql2xexchoffld; uint16_t ql2xiniexchg; + struct purex_list { + struct list_head head; + spinlock_t lock; + } purex_list; + struct name_list_extended gnl; /* Count of active session/fcport */ int fcport_count; @@ -4540,6 +4689,7 @@ typedef struct scsi_qla_host { uint8_t n2n_node_name[WWN_SIZE]; uint8_t n2n_port_name[WWN_SIZE]; uint16_t n2n_id; + __le16 dport_data[4]; struct list_head gpnid_list; struct fab_scan scan; @@ -4822,11 +4972,14 @@ struct sff_8247_a0 { u8 resv2[128]; }; -#define AUTO_DETECT_SFP_SUPPORT(_vha)\ - (ql2xautodetectsfp && !_vha->vp_idx && \ - (IS_QLA25XX(_vha->hw) || IS_QLA81XX(_vha->hw) ||\ - IS_QLA83XX(_vha->hw) || IS_QLA27XX(_vha->hw) || \ - IS_QLA28XX(_vha->hw))) +/* BPM -- Buffer Plus Management support. */ +#define IS_BPM_CAPABLE(ha) \ + (IS_QLA25XX(ha) || IS_QLA81XX(ha) || IS_QLA83XX(ha) || \ + IS_QLA27XX(ha) || IS_QLA28XX(ha)) +#define IS_BPM_RANGE_CAPABLE(ha) \ + (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) +#define IS_BPM_ENABLED(vha) \ + (ql2xautodetectsfp && !vha->vp_idx && IS_BPM_CAPABLE(vha->hw)) #define FLASH_SEMAPHORE_REGISTER_ADDR 0x00101016 diff --git a/drivers/scsi/qla2xxx/qla_dfs.c b/drivers/scsi/qla2xxx/qla_dfs.c index 0a6fb359f4d5..e62b2115235e 100644 --- a/drivers/scsi/qla2xxx/qla_dfs.c +++ b/drivers/scsi/qla2xxx/qla_dfs.c @@ -134,11 +134,11 @@ qla_dfs_fw_resource_cnt_show(struct seq_file *s, void *unused) } else { seq_puts(s, "FW Resource count\n\n"); seq_printf(s, "Original TGT exchg count[%d]\n", mb[1]); - seq_printf(s, "current TGT exchg count[%d]\n", mb[2]); - seq_printf(s, "original Initiator Exchange count[%d]\n", mb[3]); - seq_printf(s, "Current Initiator Exchange count[%d]\n", mb[6]); - seq_printf(s, "Original IOCB count[%d]\n", mb[7]); - seq_printf(s, "Current IOCB count[%d]\n", mb[10]); + seq_printf(s, "Current TGT exchg count[%d]\n", mb[2]); + seq_printf(s, "Current Initiator Exchange count[%d]\n", mb[3]); + seq_printf(s, "Original Initiator Exchange count[%d]\n", mb[6]); + seq_printf(s, "Current IOCB count[%d]\n", mb[7]); + seq_printf(s, "Original IOCB count[%d]\n", mb[10]); seq_printf(s, "MAX VP count[%d]\n", mb[11]); seq_printf(s, "MAX FCF count[%d]\n", mb[12]); seq_printf(s, "Current free pageable XCB buffer cnt[%d]\n", @@ -149,7 +149,6 @@ qla_dfs_fw_resource_cnt_show(struct seq_file *s, void *unused) mb[22]); seq_printf(s, "Original Target fast XCB buffer cnt[%d]\n", mb[23]); - } return 0; diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h index d641918cdd46..f9bad5bd7198 100644 --- a/drivers/scsi/qla2xxx/qla_fw.h +++ b/drivers/scsi/qla2xxx/qla_fw.h @@ -31,6 +31,9 @@ #define PDO_FORCE_ADISC BIT_1 #define PDO_FORCE_PLOGI BIT_0 +struct buffer_credit_24xx { + u32 parameter[28]; +}; #define PORT_DATABASE_24XX_SIZE 64 struct port_database_24xx { @@ -721,6 +724,48 @@ struct ct_entry_24xx { }; /* + * ISP queue - PUREX IOCB entry structure definition + */ +#define PUREX_IOCB_TYPE 0x51 /* CT Pass Through IOCB entry */ +struct purex_entry_24xx { + uint8_t entry_type; /* Entry type. */ + uint8_t entry_count; /* Entry count. */ + uint8_t sys_define; /* System defined. */ + uint8_t entry_status; /* Entry Status. */ + + uint16_t reserved1; + uint8_t vp_idx; + uint8_t reserved2; + + uint16_t status_flags; + uint16_t nport_handle; + + uint16_t frame_size; + uint16_t trunc_frame_size; + + uint32_t rx_xchg_addr; + + 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; + + uint8_t els_frame_payload[20]; +}; + +/* * ISP queue - ELS Pass-Through entry structure definition. */ #define ELS_IOCB_TYPE 0x53 /* ELS Pass-Through IOCB entry */ @@ -732,9 +777,8 @@ struct els_entry_24xx { uint32_t handle; /* System handle. */ - uint16_t reserved_1; - - uint16_t nport_handle; /* N_PORT handle. */ + uint16_t comp_status; /* response only */ + uint16_t nport_handle; uint16_t tx_dsd_count; @@ -749,7 +793,7 @@ struct els_entry_24xx { uint8_t opcode; uint8_t reserved_2; - uint8_t port_id[3]; + uint8_t d_id[3]; uint8_t s_id[3]; uint16_t control_flags; /* Control flags. */ @@ -761,13 +805,24 @@ struct els_entry_24xx { #define ECF_CLR_PASSTHRU_PEND BIT_12 #define ECF_INCL_FRAME_HDR BIT_11 - __le32 rx_byte_count; - __le32 tx_byte_count; + union { + struct { + __le32 rx_byte_count; + __le32 tx_byte_count; - __le64 tx_address __packed; /* Data segment 0 address. */ - __le32 tx_len; /* Data segment 0 length. */ - __le64 rx_address __packed; /* Data segment 1 address. */ - __le32 rx_len; /* Data segment 1 length. */ + __le64 tx_address __packed; /* DSD 0 address. */ + __le32 tx_len; /* DSD 0 length. */ + + __le64 rx_address __packed; /* DSD 1 address. */ + __le32 rx_len; /* DSD 1 length. */ + }; + struct { + uint32_t total_byte_count; + uint32_t error_subcode_1; + uint32_t error_subcode_2; + uint32_t error_subcode_3; + }; + }; }; struct els_sts_entry_24xx { @@ -793,15 +848,16 @@ struct els_sts_entry_24xx { uint8_t opcode; uint8_t reserved_3; - uint8_t port_id[3]; - uint8_t reserved_4; - - uint16_t reserved_5; + uint8_t d_id[3]; + uint8_t s_id[3]; uint16_t control_flags; /* Control flags. */ uint32_t total_byte_count; uint32_t error_subcode_1; uint32_t error_subcode_2; + uint32_t error_subcode_3; + + uint32_t reserved_4[4]; }; /* * ISP queue - Mailbox Command entry structure definition. @@ -942,6 +998,91 @@ struct abort_entry_24xx { uint8_t reserved_2[12]; }; +#define ABTS_RCV_TYPE 0x54 +#define ABTS_RSP_TYPE 0x55 +struct abts_entry_24xx { + uint8_t entry_type; + uint8_t entry_count; + uint8_t handle_count; + uint8_t entry_status; + + uint32_t handle; /* type 0x55 only */ + + uint16_t comp_status; /* type 0x55 only */ + uint16_t nport_handle; /* type 0x54 only */ + + uint16_t control_flags; /* type 0x55 only */ + uint8_t vp_idx; + uint8_t sof_type; /* sof_type is upper nibble */ + + uint32_t rx_xch_addr; + + 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; + + union { + struct { + uint32_t subcode3; + uint32_t rsvd; + uint32_t subcode1; + uint32_t subcode2; + } error; + struct { + uint16_t rsrvd1; + uint8_t last_seq_id; + uint8_t seq_id_valid; + uint16_t aborted_rx_id; + uint16_t aborted_ox_id; + uint16_t high_seq_cnt; + uint16_t low_seq_cnt; + } ba_acc; + struct { + uint8_t vendor_unique; + uint8_t explanation; + uint8_t reason; + } ba_rjt; + } payload; + + uint32_t rx_xch_addr_to_abort; +} __packed; + +/* ABTS payload explanation values */ +#define BA_RJT_EXP_NO_ADDITIONAL 0 +#define BA_RJT_EXP_INV_OX_RX_ID 3 +#define BA_RJT_EXP_SEQ_ABORTED 5 + +/* ABTS payload reason values */ +#define BA_RJT_RSN_INV_CMD_CODE 1 +#define BA_RJT_RSN_LOGICAL_ERROR 3 +#define BA_RJT_RSN_LOGICAL_BUSY 5 +#define BA_RJT_RSN_PROTOCOL_ERROR 7 +#define BA_RJT_RSN_UNABLE_TO_PERFORM 9 +#define BA_RJT_RSN_VENDOR_SPECIFIC 0xff + +/* FC_F values */ +#define FC_TYPE_BLD 0x000 /* Basic link data */ +#define FC_F_CTL_RSP_CNTXT 0x800000 /* Responder of exchange */ +#define FC_F_CTL_LAST_SEQ 0x100000 /* Last sequence */ +#define FC_F_CTL_END_SEQ 0x80000 /* Last sequence */ +#define FC_F_CTL_SEQ_INIT 0x010000 /* Sequence initiative */ +#define FC_ROUTING_BLD 0x80 /* Basic link data frame */ +#define FC_R_CTL_BLD_BA_ACC 0x04 /* BA_ACC (basic accept) */ + /* * ISP I/O Register Set structure definitions. */ @@ -1726,9 +1867,8 @@ struct access_chip_rsp_84xx { /* LR Distance bit positions */ #define LR_DIST_NV_POS 2 +#define LR_DIST_NV_MASK 0xf #define LR_DIST_FW_POS 12 -#define LR_DIST_FW_SHIFT (LR_DIST_FW_POS - LR_DIST_NV_POS) -#define LR_DIST_FW_FIELD(x) ((x) << LR_DIST_FW_SHIFT & 0xf000) /* FAC semaphore defines */ #define FAC_SEMAPHORE_UNLOCK 0 @@ -1883,6 +2023,7 @@ struct nvram_81xx { * BIT 6-15 = Unused */ uint16_t enhanced_features; + uint16_t reserved_24[4]; /* Offset 416. */ diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 2a64729a2bc5..1b93f5b4d77d 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -31,7 +31,7 @@ extern int qla24xx_nvram_config(struct scsi_qla_host *); extern int qla81xx_nvram_config(struct scsi_qla_host *); extern void qla2x00_update_fw_options(struct scsi_qla_host *); extern void qla24xx_update_fw_options(scsi_qla_host_t *); -extern void qla81xx_update_fw_options(scsi_qla_host_t *); + extern int qla2x00_load_risc(struct scsi_qla_host *, uint32_t *); extern int qla24xx_load_risc(scsi_qla_host_t *, uint32_t *); extern int qla81xx_load_risc(scsi_qla_host_t *, uint32_t *); @@ -109,7 +109,7 @@ int qla24xx_async_notify_ack(scsi_qla_host_t *, fc_port_t *, int qla24xx_post_newsess_work(struct scsi_qla_host *, port_id_t *, u8 *, u8*, void *, u8); int qla24xx_fcport_handle_login(struct scsi_qla_host *, fc_port_t *); -int qla24xx_detect_sfp(scsi_qla_host_t *vha); +int qla24xx_detect_sfp(scsi_qla_host_t *); int qla24xx_post_gpdb_work(struct scsi_qla_host *, fc_port_t *, u8); extern void qla28xx_get_aux_images(struct scsi_qla_host *, @@ -142,6 +142,8 @@ extern int qlport_down_retry; extern int ql2xplogiabsentdevice; extern int ql2xloginretrycount; extern int ql2xfdmienable; +extern int ql2xrdpenable; +extern int ql2xsmartsan; extern int ql2xallocfwdump; extern int ql2xextended_error_logging; extern int ql2xiidmaenable; @@ -226,6 +228,7 @@ void qla2x00_handle_login_done_event(struct scsi_qla_host *, fc_port_t *, int qla24xx_post_gnl_work(struct scsi_qla_host *, fc_port_t *); int qla24xx_post_relogin_work(struct scsi_qla_host *vha); void qla2x00_wait_for_sess_deletion(scsi_qla_host_t *); +void qla24xx_process_purex_rdp(struct scsi_qla_host *vha, void *pkt); /* * Global Functions in qla_mid.c source file. @@ -354,6 +357,9 @@ extern int qla2x00_get_port_database(scsi_qla_host_t *, fc_port_t *, uint8_t); extern int +qla24xx_get_port_database(scsi_qla_host_t *, u16, struct port_database_24xx *); + +extern int qla2x00_get_firmware_state(scsi_qla_host_t *, uint16_t *); extern int @@ -452,6 +458,13 @@ extern int qla25xx_set_driver_version(scsi_qla_host_t *, char *); extern int +qla25xx_set_els_cmds_supported(scsi_qla_host_t *); + +extern int +qla24xx_get_buffer_credits(scsi_qla_host_t *, struct buffer_credit_24xx *, + dma_addr_t); + +extern int qla2x00_read_sfp(scsi_qla_host_t *, dma_addr_t, uint8_t *, uint16_t, uint16_t, uint16_t, uint16_t); @@ -552,6 +565,8 @@ qla2x00_process_completed_request(struct scsi_qla_host *, struct req_que *, uint32_t); extern irqreturn_t qla2xxx_msix_rsp_q(int irq, void *dev_id); +extern irqreturn_t +qla2xxx_msix_rsp_q_hs(int irq, void *dev_id); fc_port_t *qla2x00_find_fcport_by_loopid(scsi_qla_host_t *, uint16_t); fc_port_t *qla2x00_find_fcport_by_wwpn(scsi_qla_host_t *, u8 *, u8); fc_port_t *qla2x00_find_fcport_by_nportid(scsi_qla_host_t *, port_id_t *, u8); @@ -656,7 +671,7 @@ extern void *qla24xx_prep_ms_fdmi_iocb(scsi_qla_host_t *, uint32_t, uint32_t); extern int qla2x00_fdmi_register(scsi_qla_host_t *); extern int qla2x00_gfpn_id(scsi_qla_host_t *, sw_info_t *); extern int qla2x00_gpsc(scsi_qla_host_t *, sw_info_t *); -extern void qla2x00_get_sym_node_name(scsi_qla_host_t *, uint8_t *, size_t); +extern size_t qla2x00_get_sym_node_name(scsi_qla_host_t *, uint8_t *, size_t); extern int qla2x00_chk_ms_status(scsi_qla_host_t *, ms_iocb_entry_t *, struct ct_sns_rsp *, const char *); extern void qla2x00_async_iocb_timeout(void *data); @@ -844,6 +859,7 @@ extern void qla82xx_clear_pending_mbx(scsi_qla_host_t *); extern int qla82xx_read_temperature(scsi_qla_host_t *); extern int qla8044_read_temperature(scsi_qla_host_t *); extern int qla2x00_read_sfp_dev(struct scsi_qla_host *, char *, int); +extern int ql26xx_led_config(scsi_qla_host_t *, uint16_t, uint16_t *); /* BSG related functions */ extern int qla24xx_bsg_request(struct bsg_job *); @@ -913,6 +929,7 @@ void qlt_remove_target_resources(struct qla_hw_data *); void qlt_clr_qp_table(struct scsi_qla_host *vha); void qlt_set_mode(struct scsi_qla_host *); int qla2x00_set_data_rate(scsi_qla_host_t *vha, uint16_t mode); +extern void qla24xx_process_purex_list(struct purex_list *); /* nvme.c */ void qla_nvme_unregister_remote_port(struct fc_port *fcport); diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index aaa4a5bbf2ff..42c3ad27f1cb 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -19,6 +19,8 @@ static int qla_async_rffid(scsi_qla_host_t *, port_id_t *, u8, u8); static int qla_async_rnnid(scsi_qla_host_t *, port_id_t *, u8*); static int qla_async_rsnn_nn(scsi_qla_host_t *); + + /** * qla2x00_prep_ms_iocb() - Prepare common MS/CT IOCB fields for SNS CT query. * @vha: HA context @@ -844,19 +846,18 @@ done: return rval; } -void +size_t qla2x00_get_sym_node_name(scsi_qla_host_t *vha, uint8_t *snn, size_t size) { struct qla_hw_data *ha = vha->hw; if (IS_QLAFX00(ha)) - snprintf(snn, size, "%s FW:v%s DVR:v%s", ha->model_number, - ha->mr.fw_version, qla2x00_version_str); - else - snprintf(snn, size, - "%s FW:v%d.%02d.%02d DVR:v%s", ha->model_number, - ha->fw_major_version, ha->fw_minor_version, - ha->fw_subminor_version, qla2x00_version_str); + return scnprintf(snn, size, "%s FW:v%s DVR:v%s", + ha->model_number, ha->mr.fw_version, qla2x00_version_str); + + return scnprintf(snn, size, "%s FW:v%d.%02d.%02d DVR:v%s", + ha->model_number, ha->fw_major_version, ha->fw_minor_version, + ha->fw_subminor_version, qla2x00_version_str); } /** @@ -1501,747 +1502,732 @@ qla2x00_prep_ct_fdmi_req(struct ct_sns_pkt *p, uint16_t cmd, return &p->p.req; } +static uint +qla25xx_fdmi_port_speed_capability(struct qla_hw_data *ha) +{ + if (IS_CNA_CAPABLE(ha)) + return FDMI_PORT_SPEED_10GB; + if (IS_QLA28XX(ha) || IS_QLA27XX(ha)) { + uint speeds = 0; + + if (ha->max_supported_speed == 2) { + if (ha->min_supported_speed <= 6) + speeds |= FDMI_PORT_SPEED_64GB; + } + if (ha->max_supported_speed == 2 || + ha->max_supported_speed == 1) { + if (ha->min_supported_speed <= 5) + speeds |= FDMI_PORT_SPEED_32GB; + } + if (ha->max_supported_speed == 2 || + ha->max_supported_speed == 1 || + ha->max_supported_speed == 0) { + if (ha->min_supported_speed <= 4) + speeds |= FDMI_PORT_SPEED_16GB; + } + if (ha->max_supported_speed == 1 || + ha->max_supported_speed == 0) { + if (ha->min_supported_speed <= 3) + speeds |= FDMI_PORT_SPEED_8GB; + } + if (ha->max_supported_speed == 0) { + if (ha->min_supported_speed <= 2) + speeds |= FDMI_PORT_SPEED_4GB; + } + return speeds; + } + if (IS_QLA2031(ha)) + return FDMI_PORT_SPEED_16GB|FDMI_PORT_SPEED_8GB| + FDMI_PORT_SPEED_4GB; + if (IS_QLA25XX(ha)) + return FDMI_PORT_SPEED_8GB|FDMI_PORT_SPEED_4GB| + FDMI_PORT_SPEED_2GB|FDMI_PORT_SPEED_1GB; + if (IS_QLA24XX_TYPE(ha)) + return FDMI_PORT_SPEED_4GB|FDMI_PORT_SPEED_2GB| + FDMI_PORT_SPEED_1GB; + if (IS_QLA23XX(ha)) + return FDMI_PORT_SPEED_2GB|FDMI_PORT_SPEED_1GB; + return FDMI_PORT_SPEED_1GB; +} +static uint +qla25xx_fdmi_port_speed_currently(struct qla_hw_data *ha) +{ + switch (ha->link_data_rate) { + case PORT_SPEED_1GB: + return FDMI_PORT_SPEED_1GB; + case PORT_SPEED_2GB: + return FDMI_PORT_SPEED_2GB; + case PORT_SPEED_4GB: + return FDMI_PORT_SPEED_4GB; + case PORT_SPEED_8GB: + return FDMI_PORT_SPEED_8GB; + case PORT_SPEED_10GB: + return FDMI_PORT_SPEED_10GB; + case PORT_SPEED_16GB: + return FDMI_PORT_SPEED_16GB; + case PORT_SPEED_32GB: + return FDMI_PORT_SPEED_32GB; + case PORT_SPEED_64GB: + return FDMI_PORT_SPEED_64GB; + default: + return FDMI_PORT_SPEED_UNKNOWN; + } +} + /** - * qla2x00_fdmi_rhba() - perform RHBA FDMI registration + * qla2x00_hba_attributes() perform HBA attributes registration * @vha: HA context + * @entries: number of entries to use + * @callopt: Option to issue extended or standard FDMI + * command parameter * * Returns 0 on success. */ -static int -qla2x00_fdmi_rhba(scsi_qla_host_t *vha) +static unsigned long +qla2x00_hba_attributes(scsi_qla_host_t *vha, void *entries, + unsigned int callopt) { - int rval, alen; - uint32_t size, sn; - - ms_iocb_entry_t *ms_pkt; - struct ct_sns_req *ct_req; - struct ct_sns_rsp *ct_rsp; - void *entries; - struct ct_fdmi_hba_attr *eiter; struct qla_hw_data *ha = vha->hw; - - /* Issue RHBA */ - /* Prepare common MS IOCB */ - /* Request size adjusted after CT preparation */ - ms_pkt = ha->isp_ops->prep_ms_fdmi_iocb(vha, 0, RHBA_RSP_SIZE); - - /* Prepare CT request */ - ct_req = qla2x00_prep_ct_fdmi_req(ha->ct_sns, RHBA_CMD, RHBA_RSP_SIZE); - ct_rsp = &ha->ct_sns->p.rsp; - - /* Prepare FDMI command arguments -- attribute block, attributes. */ - memcpy(ct_req->req.rhba.hba_identifier, vha->port_name, WWN_SIZE); - ct_req->req.rhba.entry_count = cpu_to_be32(1); - memcpy(ct_req->req.rhba.port_name, vha->port_name, WWN_SIZE); - size = 2 * WWN_SIZE + 4 + 4; - - /* Attributes */ - ct_req->req.rhba.attrs.count = - cpu_to_be32(FDMI_HBA_ATTR_COUNT); - entries = &ct_req->req; + struct init_cb_24xx *icb24 = (void *)ha->init_cb; + struct new_utsname *p_sysid = utsname(); + struct ct_fdmi_hba_attr *eiter; + uint16_t alen; + unsigned long size = 0; /* Nodename. */ eiter = entries + size; eiter->type = cpu_to_be16(FDMI_HBA_NODE_NAME); - eiter->len = cpu_to_be16(4 + WWN_SIZE); - memcpy(eiter->a.node_name, vha->node_name, WWN_SIZE); - size += 4 + WWN_SIZE; - - ql_dbg(ql_dbg_disc, vha, 0x2025, - "NodeName = %8phN.\n", eiter->a.node_name); - + memcpy(eiter->a.node_name, vha->node_name, sizeof(eiter->a.node_name)); + alen = sizeof(eiter->a.node_name); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20a0, + "NODENAME = %016llx.\n", wwn_to_u64(eiter->a.node_name)); /* Manufacturer. */ eiter = entries + size; eiter->type = cpu_to_be16(FDMI_HBA_MANUFACTURER); - alen = strlen(QLA2XXX_MANUFACTURER); - snprintf(eiter->a.manufacturer, sizeof(eiter->a.manufacturer), - "%s", "QLogic Corporation"); - alen += 4 - (alen & 3); - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; - - ql_dbg(ql_dbg_disc, vha, 0x2026, - "Manufacturer = %s.\n", eiter->a.manufacturer); - + alen = scnprintf( + eiter->a.manufacturer, sizeof(eiter->a.manufacturer), + "%s", "QLogic Corporation"); + alen += FDMI_ATTR_ALIGNMENT(alen); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20a1, + "MANUFACTURER = %s.\n", eiter->a.manufacturer); /* Serial number. */ eiter = entries + size; eiter->type = cpu_to_be16(FDMI_HBA_SERIAL_NUMBER); - if (IS_FWI2_CAPABLE(ha)) - qla2xxx_get_vpd_field(vha, "SN", eiter->a.serial_num, - sizeof(eiter->a.serial_num)); - else { - sn = ((ha->serial0 & 0x1f) << 16) | + alen = 0; + if (IS_FWI2_CAPABLE(ha)) { + alen = qla2xxx_get_vpd_field(vha, "SN", + eiter->a.serial_num, sizeof(eiter->a.serial_num)); + } + if (!alen) { + uint32_t sn = ((ha->serial0 & 0x1f) << 16) | (ha->serial2 << 8) | ha->serial1; - snprintf(eiter->a.serial_num, sizeof(eiter->a.serial_num), - "%c%05d", 'A' + sn / 100000, sn % 100000); + alen = scnprintf( + eiter->a.serial_num, sizeof(eiter->a.serial_num), + "%c%05d", 'A' + sn / 100000, sn % 100000); } - alen = strlen(eiter->a.serial_num); - alen += 4 - (alen & 3); - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; - - ql_dbg(ql_dbg_disc, vha, 0x2027, - "Serial no. = %s.\n", eiter->a.serial_num); - + alen += FDMI_ATTR_ALIGNMENT(alen); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20a2, + "SERIAL NUMBER = %s.\n", eiter->a.serial_num); /* Model name. */ eiter = entries + size; eiter->type = cpu_to_be16(FDMI_HBA_MODEL); - snprintf(eiter->a.model, sizeof(eiter->a.model), - "%s", ha->model_number); - alen = strlen(eiter->a.model); - alen += 4 - (alen & 3); - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; - - ql_dbg(ql_dbg_disc, vha, 0x2028, - "Model Name = %s.\n", eiter->a.model); - + alen = scnprintf( + eiter->a.model, sizeof(eiter->a.model), + "%s", ha->model_number); + alen += FDMI_ATTR_ALIGNMENT(alen); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20a3, + "MODEL NAME = %s.\n", eiter->a.model); /* Model description. */ eiter = entries + size; eiter->type = cpu_to_be16(FDMI_HBA_MODEL_DESCRIPTION); - snprintf(eiter->a.model_desc, sizeof(eiter->a.model_desc), - "%s", ha->model_desc); - alen = strlen(eiter->a.model_desc); - alen += 4 - (alen & 3); - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; - - ql_dbg(ql_dbg_disc, vha, 0x2029, - "Model Desc = %s.\n", eiter->a.model_desc); - + alen = scnprintf( + eiter->a.model_desc, sizeof(eiter->a.model_desc), + "%s", ha->model_desc); + alen += FDMI_ATTR_ALIGNMENT(alen); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20a4, + "MODEL DESCRIPTION = %s.\n", eiter->a.model_desc); /* Hardware version. */ eiter = entries + size; eiter->type = cpu_to_be16(FDMI_HBA_HARDWARE_VERSION); - if (!IS_FWI2_CAPABLE(ha)) { - snprintf(eiter->a.hw_version, sizeof(eiter->a.hw_version), - "HW:%s", ha->adapter_id); - } else if (qla2xxx_get_vpd_field(vha, "MN", eiter->a.hw_version, - sizeof(eiter->a.hw_version))) { - ; - } else if (qla2xxx_get_vpd_field(vha, "EC", eiter->a.hw_version, - sizeof(eiter->a.hw_version))) { - ; - } else { - snprintf(eiter->a.hw_version, sizeof(eiter->a.hw_version), - "HW:%s", ha->adapter_id); + alen = 0; + if (IS_FWI2_CAPABLE(ha)) { + if (!alen) { + alen = qla2xxx_get_vpd_field(vha, "MN", + eiter->a.hw_version, sizeof(eiter->a.hw_version)); + } + if (!alen) { + alen = qla2xxx_get_vpd_field(vha, "EC", + eiter->a.hw_version, sizeof(eiter->a.hw_version)); + } } - alen = strlen(eiter->a.hw_version); - alen += 4 - (alen & 3); - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; - - ql_dbg(ql_dbg_disc, vha, 0x202a, - "Hardware ver = %s.\n", eiter->a.hw_version); - + if (!alen) { + alen = scnprintf( + eiter->a.hw_version, sizeof(eiter->a.hw_version), + "HW:%s", ha->adapter_id); + } + alen += FDMI_ATTR_ALIGNMENT(alen); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20a5, + "HARDWARE VERSION = %s.\n", eiter->a.hw_version); /* Driver version. */ eiter = entries + size; eiter->type = cpu_to_be16(FDMI_HBA_DRIVER_VERSION); - snprintf(eiter->a.driver_version, sizeof(eiter->a.driver_version), - "%s", qla2x00_version_str); - alen = strlen(eiter->a.driver_version); - alen += 4 - (alen & 3); - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; - - ql_dbg(ql_dbg_disc, vha, 0x202b, - "Driver ver = %s.\n", eiter->a.driver_version); - + alen = scnprintf( + eiter->a.driver_version, sizeof(eiter->a.driver_version), + "%s", qla2x00_version_str); + alen += FDMI_ATTR_ALIGNMENT(alen); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20a6, + "DRIVER VERSION = %s.\n", eiter->a.driver_version); /* Option ROM version. */ eiter = entries + size; eiter->type = cpu_to_be16(FDMI_HBA_OPTION_ROM_VERSION); - snprintf(eiter->a.orom_version, sizeof(eiter->a.orom_version), - "%d.%02d", ha->bios_revision[1], ha->bios_revision[0]); - alen = strlen(eiter->a.orom_version); - alen += 4 - (alen & 3); - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; - - ql_dbg(ql_dbg_disc, vha , 0x202c, - "Optrom vers = %s.\n", eiter->a.orom_version); + alen = scnprintf( + eiter->a.orom_version, sizeof(eiter->a.orom_version), + "%d.%02d", ha->bios_revision[1], ha->bios_revision[0]); + alen += FDMI_ATTR_ALIGNMENT(alen); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20a7, + "OPTROM VERSION = %d.%02d.\n", + eiter->a.orom_version[1], eiter->a.orom_version[0]); /* Firmware version */ eiter = entries + size; eiter->type = cpu_to_be16(FDMI_HBA_FIRMWARE_VERSION); ha->isp_ops->fw_version_str(vha, eiter->a.fw_version, sizeof(eiter->a.fw_version)); - alen = strlen(eiter->a.fw_version); - alen += 4 - (alen & 3); - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; - - ql_dbg(ql_dbg_disc, vha, 0x202d, - "Firmware vers = %s.\n", eiter->a.fw_version); - - /* Update MS request size. */ - qla2x00_update_ms_fdmi_iocb(vha, size + 16); - - ql_dbg(ql_dbg_disc, vha, 0x202e, - "RHBA identifier = %8phN size=%d.\n", - ct_req->req.rhba.hba_identifier, size); - ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x2076, - entries, size); - - /* Execute MS IOCB */ - rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma, - sizeof(ms_iocb_entry_t)); - if (rval != QLA_SUCCESS) { - /*EMPTY*/ - ql_dbg(ql_dbg_disc, vha, 0x2030, - "RHBA issue IOCB failed (%d).\n", rval); - } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "RHBA") != - QLA_SUCCESS) { - rval = QLA_FUNCTION_FAILED; - if (ct_rsp->header.reason_code == CT_REASON_CANNOT_PERFORM && - ct_rsp->header.explanation_code == - CT_EXPL_ALREADY_REGISTERED) { - ql_dbg(ql_dbg_disc, vha, 0x2034, - "HBA already registered.\n"); - rval = QLA_ALREADY_REGISTERED; - } else { - ql_dbg(ql_dbg_disc, vha, 0x20ad, - "RHBA FDMI registration failed, CT Reason code: 0x%x, CT Explanation 0x%x\n", - ct_rsp->header.reason_code, - ct_rsp->header.explanation_code); - } - } else { - ql_dbg(ql_dbg_disc, vha, 0x2035, - "RHBA exiting normally.\n"); + alen += FDMI_ATTR_ALIGNMENT(alen); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20a8, + "FIRMWARE VERSION = %s.\n", eiter->a.fw_version); + if (callopt == CALLOPT_FDMI1) + goto done; + /* OS Name and Version */ + eiter = entries + size; + eiter->type = cpu_to_be16(FDMI_HBA_OS_NAME_AND_VERSION); + alen = 0; + if (p_sysid) { + alen = scnprintf( + eiter->a.os_version, sizeof(eiter->a.os_version), + "%s %s %s", + p_sysid->sysname, p_sysid->release, p_sysid->machine); } - - return rval; + if (!alen) { + alen = scnprintf( + eiter->a.os_version, sizeof(eiter->a.os_version), + "%s %s", + "Linux", fc_host_system_hostname(vha->host)); + } + alen += FDMI_ATTR_ALIGNMENT(alen); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20a9, + "OS VERSION = %s.\n", eiter->a.os_version); + /* MAX CT Payload Length */ + eiter = entries + size; + eiter->type = cpu_to_be16(FDMI_HBA_MAXIMUM_CT_PAYLOAD_LENGTH); + eiter->a.max_ct_len = cpu_to_be32(le16_to_cpu(IS_FWI2_CAPABLE(ha) ? + icb24->frame_payload_size : ha->init_cb->frame_payload_size)); + alen = sizeof(eiter->a.max_ct_len); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20aa, + "CT PAYLOAD LENGTH = 0x%x.\n", be32_to_cpu(eiter->a.max_ct_len)); + /* Node Sybolic Name */ + eiter = entries + size; + eiter->type = cpu_to_be16(FDMI_HBA_NODE_SYMBOLIC_NAME); + alen = qla2x00_get_sym_node_name(vha, eiter->a.sym_name, + sizeof(eiter->a.sym_name)); + alen += FDMI_ATTR_ALIGNMENT(alen); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20ab, + "SYMBOLIC NAME = %s.\n", eiter->a.sym_name); + /* Vendor Specific information */ + eiter = entries + size; + eiter->type = cpu_to_be16(FDMI_HBA_VENDOR_SPECIFIC_INFO); + eiter->a.vendor_specific_info = cpu_to_be32(PCI_VENDOR_ID_QLOGIC); + alen = sizeof(eiter->a.vendor_specific_info); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20ac, + "VENDOR SPECIFIC INFO = 0x%x.\n", + be32_to_cpu(eiter->a.vendor_specific_info)); + /* Num Ports */ + eiter = entries + size; + eiter->type = cpu_to_be16(FDMI_HBA_NUM_PORTS); + eiter->a.num_ports = cpu_to_be32(1); + alen = sizeof(eiter->a.num_ports); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20ad, + "PORT COUNT = %x.\n", be32_to_cpu(eiter->a.num_ports)); + /* Fabric Name */ + eiter = entries + size; + eiter->type = cpu_to_be16(FDMI_HBA_FABRIC_NAME); + memcpy(eiter->a.fabric_name, vha->fabric_node_name, + sizeof(eiter->a.fabric_name)); + alen = sizeof(eiter->a.fabric_name); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20ae, + "FABRIC NAME = %016llx.\n", wwn_to_u64(eiter->a.fabric_name)); + /* BIOS Version */ + eiter = entries + size; + eiter->type = cpu_to_be16(FDMI_HBA_BOOT_BIOS_NAME); + alen = scnprintf( + eiter->a.bios_name, sizeof(eiter->a.bios_name), + "BIOS %d.%02d", ha->bios_revision[1], ha->bios_revision[0]); + alen += FDMI_ATTR_ALIGNMENT(alen); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20af, + "BIOS NAME = %s\n", eiter->a.bios_name); + /* Vendor Identifier */ + eiter = entries + size; + eiter->type = cpu_to_be16(FDMI_HBA_VENDOR_IDENTIFIER); + alen = scnprintf( + eiter->a.vendor_identifier, sizeof(eiter->a.vendor_identifier), + "%s", "QLGC"); + alen += FDMI_ATTR_ALIGNMENT(alen); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20b0, + "VENDOR IDENTIFIER = %s.\n", eiter->a.vendor_identifier); +done: + return size; } /** - * qla2x00_fdmi_rpa() - perform RPA registration + * qla2x00_port_attributes() perform Port attributes registration * @vha: HA context + * @entries: number of entries to use + * @callopt: Option to issue extended or standard FDMI + * command parameter * * Returns 0 on success. */ -static int -qla2x00_fdmi_rpa(scsi_qla_host_t *vha) +static unsigned long +qla2x00_port_attributes(scsi_qla_host_t *vha, void *entries, + unsigned int callopt) { - int rval, alen; - uint32_t size; struct qla_hw_data *ha = vha->hw; - ms_iocb_entry_t *ms_pkt; - struct ct_sns_req *ct_req; - struct ct_sns_rsp *ct_rsp; - void *entries; + struct init_cb_24xx *icb24 = (void *)ha->init_cb; + struct new_utsname *p_sysid = utsname(); + char *hostname = p_sysid ? + p_sysid->nodename : fc_host_system_hostname(vha->host); struct ct_fdmi_port_attr *eiter; - struct init_cb_24xx *icb24 = (struct init_cb_24xx *)ha->init_cb; - struct new_utsname *p_sysid = NULL; - - /* Issue RPA */ - /* Prepare common MS IOCB */ - /* Request size adjusted after CT preparation */ - ms_pkt = ha->isp_ops->prep_ms_fdmi_iocb(vha, 0, RPA_RSP_SIZE); - - /* Prepare CT request */ - ct_req = qla2x00_prep_ct_fdmi_req(ha->ct_sns, RPA_CMD, - RPA_RSP_SIZE); - ct_rsp = &ha->ct_sns->p.rsp; - - /* Prepare FDMI command arguments -- attribute block, attributes. */ - memcpy(ct_req->req.rpa.port_name, vha->port_name, WWN_SIZE); - size = WWN_SIZE + 4; - - /* Attributes */ - ct_req->req.rpa.attrs.count = cpu_to_be32(FDMI_PORT_ATTR_COUNT); - entries = &ct_req->req; + uint16_t alen; + unsigned long size = 0; /* FC4 types. */ eiter = entries + size; eiter->type = cpu_to_be16(FDMI_PORT_FC4_TYPES); - eiter->len = cpu_to_be16(4 + 32); + eiter->a.fc4_types[0] = 0x00; + eiter->a.fc4_types[1] = 0x00; eiter->a.fc4_types[2] = 0x01; - size += 4 + 32; - - ql_dbg(ql_dbg_disc, vha, 0x2039, - "FC4_TYPES=%02x %02x.\n", - eiter->a.fc4_types[2], - eiter->a.fc4_types[1]); - + eiter->a.fc4_types[3] = 0x00; + alen = sizeof(eiter->a.fc4_types); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20c0, + "FC4 TYPES = %016llx.\n", *(uint64_t *)eiter->a.fc4_types); + 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); - eiter->len = cpu_to_be16(4 + 4); - if (IS_CNA_CAPABLE(ha)) - eiter->a.sup_speed = cpu_to_be32( - FDMI_PORT_SPEED_10GB); - else if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) - eiter->a.sup_speed = cpu_to_be32( - FDMI_PORT_SPEED_32GB| - FDMI_PORT_SPEED_16GB| - FDMI_PORT_SPEED_8GB); - else if (IS_QLA2031(ha)) - eiter->a.sup_speed = cpu_to_be32( - FDMI_PORT_SPEED_16GB| - FDMI_PORT_SPEED_8GB| - FDMI_PORT_SPEED_4GB); - else if (IS_QLA25XX(ha)) - eiter->a.sup_speed = cpu_to_be32( - FDMI_PORT_SPEED_8GB| - FDMI_PORT_SPEED_4GB| - FDMI_PORT_SPEED_2GB| - FDMI_PORT_SPEED_1GB); - else if (IS_QLA24XX_TYPE(ha)) - eiter->a.sup_speed = cpu_to_be32( - FDMI_PORT_SPEED_4GB| - FDMI_PORT_SPEED_2GB| - FDMI_PORT_SPEED_1GB); - else if (IS_QLA23XX(ha)) - eiter->a.sup_speed = cpu_to_be32( - FDMI_PORT_SPEED_2GB| - FDMI_PORT_SPEED_1GB); - else - eiter->a.sup_speed = cpu_to_be32( - FDMI_PORT_SPEED_1GB); - size += 4 + 4; - - ql_dbg(ql_dbg_disc, vha, 0x203a, - "Supported_Speed=%x.\n", eiter->a.sup_speed); - + eiter->a.sup_speed = cpu_to_be32( + qla25xx_fdmi_port_speed_capability(ha)); + alen = sizeof(eiter->a.sup_speed); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20c1, + "SUPPORTED SPEED = %x.\n", be32_to_cpu(eiter->a.sup_speed)); /* Current speed. */ eiter = entries + size; eiter->type = cpu_to_be16(FDMI_PORT_CURRENT_SPEED); - eiter->len = cpu_to_be16(4 + 4); - switch (ha->link_data_rate) { - case PORT_SPEED_1GB: - eiter->a.cur_speed = - cpu_to_be32(FDMI_PORT_SPEED_1GB); - break; - case PORT_SPEED_2GB: - eiter->a.cur_speed = - cpu_to_be32(FDMI_PORT_SPEED_2GB); - break; - case PORT_SPEED_4GB: - eiter->a.cur_speed = - cpu_to_be32(FDMI_PORT_SPEED_4GB); - break; - case PORT_SPEED_8GB: - eiter->a.cur_speed = - cpu_to_be32(FDMI_PORT_SPEED_8GB); - break; - case PORT_SPEED_10GB: - eiter->a.cur_speed = - cpu_to_be32(FDMI_PORT_SPEED_10GB); - break; - case PORT_SPEED_16GB: - eiter->a.cur_speed = - cpu_to_be32(FDMI_PORT_SPEED_16GB); - break; - case PORT_SPEED_32GB: - eiter->a.cur_speed = - cpu_to_be32(FDMI_PORT_SPEED_32GB); - break; - default: - eiter->a.cur_speed = - cpu_to_be32(FDMI_PORT_SPEED_UNKNOWN); - break; - } - size += 4 + 4; - - ql_dbg(ql_dbg_disc, vha, 0x203b, - "Current_Speed=%x.\n", eiter->a.cur_speed); - + eiter->a.cur_speed = cpu_to_be32( + qla25xx_fdmi_port_speed_currently(ha)); + alen = sizeof(eiter->a.cur_speed); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20c2, + "CURRENT SPEED = %x.\n", be32_to_cpu(eiter->a.cur_speed)); /* Max frame size. */ eiter = entries + size; eiter->type = cpu_to_be16(FDMI_PORT_MAX_FRAME_SIZE); - eiter->len = cpu_to_be16(4 + 4); - eiter->a.max_frame_size = IS_FWI2_CAPABLE(ha) ? - le16_to_cpu(icb24->frame_payload_size) : - le16_to_cpu(ha->init_cb->frame_payload_size); - eiter->a.max_frame_size = cpu_to_be32(eiter->a.max_frame_size); - size += 4 + 4; - - ql_dbg(ql_dbg_disc, vha, 0x203c, - "Max_Frame_Size=%x.\n", eiter->a.max_frame_size); - + eiter->a.max_frame_size = cpu_to_be32(le16_to_cpu(IS_FWI2_CAPABLE(ha) ? + icb24->frame_payload_size : ha->init_cb->frame_payload_size)); + alen = sizeof(eiter->a.max_frame_size); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20c3, + "MAX FRAME SIZE = %x.\n", be32_to_cpu(eiter->a.max_frame_size)); /* OS device name. */ eiter = entries + size; eiter->type = cpu_to_be16(FDMI_PORT_OS_DEVICE_NAME); - snprintf(eiter->a.os_dev_name, sizeof(eiter->a.os_dev_name), - "%s:host%lu", QLA2XXX_DRIVER_NAME, vha->host_no); - alen = strlen(eiter->a.os_dev_name); - alen += 4 - (alen & 3); - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; - - ql_dbg(ql_dbg_disc, vha, 0x204b, - "OS_Device_Name=%s.\n", eiter->a.os_dev_name); - + alen = scnprintf( + eiter->a.os_dev_name, sizeof(eiter->a.os_dev_name), + "%s:host%lu", QLA2XXX_DRIVER_NAME, vha->host_no); + alen += FDMI_ATTR_ALIGNMENT(alen); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20c4, + "OS DEVICE NAME = %s.\n", eiter->a.os_dev_name); /* Hostname. */ eiter = entries + size; eiter->type = cpu_to_be16(FDMI_PORT_HOST_NAME); - p_sysid = utsname(); - if (p_sysid) { - snprintf(eiter->a.host_name, sizeof(eiter->a.host_name), - "%s", p_sysid->nodename); - } else { - snprintf(eiter->a.host_name, sizeof(eiter->a.host_name), - "%s", fc_host_system_hostname(vha->host)); - } - alen = strlen(eiter->a.host_name); - alen += 4 - (alen & 3); - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; - - ql_dbg(ql_dbg_disc, vha, 0x203d, "HostName=%s.\n", eiter->a.host_name); - - /* Update MS request size. */ - qla2x00_update_ms_fdmi_iocb(vha, size + 16); - - ql_dbg(ql_dbg_disc, vha, 0x203e, - "RPA portname %016llx, size = %d.\n", - wwn_to_u64(ct_req->req.rpa.port_name), size); - ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x2079, - entries, size); - - /* Execute MS IOCB */ - rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma, - sizeof(ms_iocb_entry_t)); - if (rval != QLA_SUCCESS) { - /*EMPTY*/ - ql_dbg(ql_dbg_disc, vha, 0x2040, - "RPA issue IOCB failed (%d).\n", rval); - } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "RPA") != - QLA_SUCCESS) { - rval = QLA_FUNCTION_FAILED; - if (ct_rsp->header.reason_code == CT_REASON_CANNOT_PERFORM && - ct_rsp->header.explanation_code == - CT_EXPL_ALREADY_REGISTERED) { - ql_dbg(ql_dbg_disc, vha, 0x20cd, - "RPA already registered.\n"); - rval = QLA_ALREADY_REGISTERED; - } - - } else { - ql_dbg(ql_dbg_disc, vha, 0x2041, - "RPA exiting normally.\n"); - } - - return rval; -} - -/** - * qla2x00_fdmiv2_rhba() - perform RHBA FDMI v2 registration - * @vha: HA context - * - * Returns 0 on success. - */ -static int -qla2x00_fdmiv2_rhba(scsi_qla_host_t *vha) -{ - int rval, alen; - uint32_t size, sn; - ms_iocb_entry_t *ms_pkt; - struct ct_sns_req *ct_req; - struct ct_sns_rsp *ct_rsp; - void *entries; - struct ct_fdmiv2_hba_attr *eiter; - struct qla_hw_data *ha = vha->hw; - struct new_utsname *p_sysid = NULL; - - /* Issue RHBA */ - /* Prepare common MS IOCB */ - /* Request size adjusted after CT preparation */ - ms_pkt = ha->isp_ops->prep_ms_fdmi_iocb(vha, 0, RHBA_RSP_SIZE); - - /* Prepare CT request */ - ct_req = qla2x00_prep_ct_fdmi_req(ha->ct_sns, RHBA_CMD, - RHBA_RSP_SIZE); - ct_rsp = &ha->ct_sns->p.rsp; - - /* Prepare FDMI command arguments -- attribute block, attributes. */ - memcpy(ct_req->req.rhba2.hba_identifier, vha->port_name, WWN_SIZE); - ct_req->req.rhba2.entry_count = cpu_to_be32(1); - memcpy(ct_req->req.rhba2.port_name, vha->port_name, WWN_SIZE); - size = 2 * WWN_SIZE + 4 + 4; + if (!*hostname || !strncmp(hostname, "(none)", 6)) + hostname = "Linux-default"; + alen = scnprintf( + eiter->a.host_name, sizeof(eiter->a.host_name), + "%s", hostname); + alen += FDMI_ATTR_ALIGNMENT(alen); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20c5, + "HOSTNAME = %s.\n", eiter->a.host_name); - /* Attributes */ - ct_req->req.rhba2.attrs.count = cpu_to_be32(FDMIV2_HBA_ATTR_COUNT); - entries = &ct_req->req; + if (callopt == CALLOPT_FDMI1) + goto done; - /* Nodename. */ + /* Node Name */ eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_HBA_NODE_NAME); - eiter->len = cpu_to_be16(4 + WWN_SIZE); - memcpy(eiter->a.node_name, vha->node_name, WWN_SIZE); - size += 4 + WWN_SIZE; - - ql_dbg(ql_dbg_disc, vha, 0x207d, - "NodeName = %016llx.\n", wwn_to_u64(eiter->a.node_name)); + eiter->type = cpu_to_be16(FDMI_PORT_NODE_NAME); + memcpy(eiter->a.node_name, vha->node_name, sizeof(eiter->a.node_name)); + alen = sizeof(eiter->a.node_name); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20c6, + "NODENAME = %016llx.\n", wwn_to_u64(eiter->a.node_name)); - /* Manufacturer. */ + /* Port Name */ eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_HBA_MANUFACTURER); - snprintf(eiter->a.manufacturer, sizeof(eiter->a.manufacturer), - "%s", "QLogic Corporation"); - eiter->a.manufacturer[strlen("QLogic Corporation")] = '\0'; - alen = strlen(eiter->a.manufacturer); - alen += 4 - (alen & 3); - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; - - ql_dbg(ql_dbg_disc, vha, 0x20a5, - "Manufacturer = %s.\n", eiter->a.manufacturer); + eiter->type = cpu_to_be16(FDMI_PORT_NAME); + memcpy(eiter->a.port_name, vha->port_name, sizeof(eiter->a.port_name)); + alen = sizeof(eiter->a.port_name); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20c7, + "PORTNAME = %016llx.\n", wwn_to_u64(eiter->a.port_name)); - /* Serial number. */ + /* Port Symbolic Name */ eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_HBA_SERIAL_NUMBER); - if (IS_FWI2_CAPABLE(ha)) - qla2xxx_get_vpd_field(vha, "SN", eiter->a.serial_num, - sizeof(eiter->a.serial_num)); - else { - sn = ((ha->serial0 & 0x1f) << 16) | - (ha->serial2 << 8) | ha->serial1; - snprintf(eiter->a.serial_num, sizeof(eiter->a.serial_num), - "%c%05d", 'A' + sn / 100000, sn % 100000); - } - alen = strlen(eiter->a.serial_num); - alen += 4 - (alen & 3); - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; - - ql_dbg(ql_dbg_disc, vha, 0x20a6, - "Serial no. = %s.\n", eiter->a.serial_num); + eiter->type = cpu_to_be16(FDMI_PORT_SYM_NAME); + alen = qla2x00_get_sym_node_name(vha, eiter->a.port_sym_name, + sizeof(eiter->a.port_sym_name)); + alen += FDMI_ATTR_ALIGNMENT(alen); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20c8, + "PORT SYMBOLIC NAME = %s\n", eiter->a.port_sym_name); - /* Model name. */ + /* Port Type */ eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_HBA_MODEL); - snprintf(eiter->a.model, sizeof(eiter->a.model), - "%s", ha->model_number); - alen = strlen(eiter->a.model); - alen += 4 - (alen & 3); - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; - - ql_dbg(ql_dbg_disc, vha, 0x20a7, - "Model Name = %s.\n", eiter->a.model); - - /* Model description. */ + eiter->type = cpu_to_be16(FDMI_PORT_TYPE); + eiter->a.port_type = cpu_to_be32(NS_NX_PORT_TYPE); + alen = sizeof(eiter->a.port_type); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20c9, + "PORT TYPE = %x.\n", be32_to_cpu(eiter->a.port_type)); + + /* Supported Class of Service */ eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_HBA_MODEL_DESCRIPTION); - snprintf(eiter->a.model_desc, sizeof(eiter->a.model_desc), - "%s", ha->model_desc); - alen = strlen(eiter->a.model_desc); - alen += 4 - (alen & 3); - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; - - ql_dbg(ql_dbg_disc, vha, 0x20a8, - "Model Desc = %s.\n", eiter->a.model_desc); + eiter->type = cpu_to_be16(FDMI_PORT_SUPP_COS); + eiter->a.port_supported_cos = cpu_to_be32(FC_CLASS_3); + alen = sizeof(eiter->a.port_supported_cos); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20ca, + "SUPPORTED COS = %08x\n", be32_to_cpu(eiter->a.port_supported_cos)); - /* Hardware version. */ + /* Port Fabric Name */ eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_HBA_HARDWARE_VERSION); - if (!IS_FWI2_CAPABLE(ha)) { - snprintf(eiter->a.hw_version, sizeof(eiter->a.hw_version), - "HW:%s", ha->adapter_id); - } else if (qla2xxx_get_vpd_field(vha, "MN", eiter->a.hw_version, - sizeof(eiter->a.hw_version))) { - ; - } else if (qla2xxx_get_vpd_field(vha, "EC", eiter->a.hw_version, - sizeof(eiter->a.hw_version))) { - ; - } else { - snprintf(eiter->a.hw_version, sizeof(eiter->a.hw_version), - "HW:%s", ha->adapter_id); - } - alen = strlen(eiter->a.hw_version); - alen += 4 - (alen & 3); - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; - - ql_dbg(ql_dbg_disc, vha, 0x20a9, - "Hardware ver = %s.\n", eiter->a.hw_version); + eiter->type = cpu_to_be16(FDMI_PORT_FABRIC_NAME); + memcpy(eiter->a.fabric_name, vha->fabric_node_name, + sizeof(eiter->a.fabric_name)); + alen = sizeof(eiter->a.fabric_name); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20cb, + "FABRIC NAME = %016llx.\n", wwn_to_u64(eiter->a.fabric_name)); - /* Driver version. */ + /* FC4_type */ eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_HBA_DRIVER_VERSION); - snprintf(eiter->a.driver_version, sizeof(eiter->a.driver_version), - "%s", qla2x00_version_str); - alen = strlen(eiter->a.driver_version); - alen += 4 - (alen & 3); - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; - - ql_dbg(ql_dbg_disc, vha, 0x20aa, - "Driver ver = %s.\n", eiter->a.driver_version); + eiter->type = cpu_to_be16(FDMI_PORT_FC4_TYPE); + eiter->a.port_fc4_type[0] = 0x00; + eiter->a.port_fc4_type[1] = 0x00; + eiter->a.port_fc4_type[2] = 0x01; + eiter->a.port_fc4_type[3] = 0x00; + alen = sizeof(eiter->a.port_fc4_type); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20cc, + "PORT ACTIVE FC4 TYPE = %016llx.\n", + *(uint64_t *)eiter->a.port_fc4_type); - /* Option ROM version. */ + /* Port State */ eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_HBA_OPTION_ROM_VERSION); - snprintf(eiter->a.orom_version, sizeof(eiter->a.orom_version), - "%d.%02d", ha->bios_revision[1], ha->bios_revision[0]); - alen = strlen(eiter->a.orom_version); - alen += 4 - (alen & 3); - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; - - ql_dbg(ql_dbg_disc, vha , 0x20ab, - "Optrom version = %d.%02d.\n", eiter->a.orom_version[1], - eiter->a.orom_version[0]); + eiter->type = cpu_to_be16(FDMI_PORT_STATE); + eiter->a.port_state = cpu_to_be32(2); + alen = sizeof(eiter->a.port_state); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20cd, + "PORT_STATE = %x.\n", be32_to_cpu(eiter->a.port_state)); - /* Firmware version */ + /* Number of Ports */ eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_HBA_FIRMWARE_VERSION); - ha->isp_ops->fw_version_str(vha, eiter->a.fw_version, - sizeof(eiter->a.fw_version)); - alen = strlen(eiter->a.fw_version); - alen += 4 - (alen & 3); - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; - - ql_dbg(ql_dbg_disc, vha, 0x20ac, - "Firmware vers = %s.\n", eiter->a.fw_version); - - /* OS Name and Version */ + eiter->type = cpu_to_be16(FDMI_PORT_COUNT); + eiter->a.num_ports = cpu_to_be32(1); + alen = sizeof(eiter->a.num_ports); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20ce, + "PORT COUNT = %x.\n", be32_to_cpu(eiter->a.num_ports)); + + /* Port Identifier */ eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_HBA_OS_NAME_AND_VERSION); - p_sysid = utsname(); - if (p_sysid) { - snprintf(eiter->a.os_version, sizeof(eiter->a.os_version), - "%s %s %s", - p_sysid->sysname, p_sysid->release, p_sysid->version); - } else { - snprintf(eiter->a.os_version, sizeof(eiter->a.os_version), - "%s %s", "Linux", fc_host_system_hostname(vha->host)); - } - alen = strlen(eiter->a.os_version); - alen += 4 - (alen & 3); - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; - - ql_dbg(ql_dbg_disc, vha, 0x20ae, - "OS Name and Version = %s.\n", eiter->a.os_version); + eiter->type = cpu_to_be16(FDMI_PORT_IDENTIFIER); + eiter->a.port_id = cpu_to_be32(vha->d_id.b24); + alen = sizeof(eiter->a.port_id); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20cf, + "PORT ID = %x.\n", be32_to_cpu(eiter->a.port_id)); + + if (callopt == CALLOPT_FDMI2 || !ql2xsmartsan) + goto done; - /* MAX CT Payload Length */ + /* Smart SAN Service Category (Populate Smart SAN Initiator)*/ eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_HBA_MAXIMUM_CT_PAYLOAD_LENGTH); - eiter->a.max_ct_len = cpu_to_be32(ha->frame_payload_size); - eiter->a.max_ct_len = cpu_to_be32(eiter->a.max_ct_len); - eiter->len = cpu_to_be16(4 + 4); - size += 4 + 4; + eiter->type = cpu_to_be16(FDMI_SMARTSAN_SERVICE); + alen = scnprintf( + eiter->a.smartsan_service, sizeof(eiter->a.smartsan_service), + "%s", "Smart SAN Initiator"); + alen += FDMI_ATTR_ALIGNMENT(alen); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20d0, + "SMARTSAN SERVICE CATEGORY = %s.\n", eiter->a.smartsan_service); + + /* Smart SAN GUID (NWWN+PWWN) */ + eiter = entries + size; + eiter->type = cpu_to_be16(FDMI_SMARTSAN_GUID); + memcpy(eiter->a.smartsan_guid, vha->node_name, WWN_SIZE); + memcpy(eiter->a.smartsan_guid + WWN_SIZE, vha->port_name, WWN_SIZE); + alen = sizeof(eiter->a.smartsan_guid); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20d1, + "Smart SAN GUID = %016llx-%016llx\n", + wwn_to_u64(eiter->a.smartsan_guid), + wwn_to_u64(eiter->a.smartsan_guid + WWN_SIZE)); + + /* Smart SAN Version (populate "Smart SAN Version 1.0") */ + eiter = entries + size; + eiter->type = cpu_to_be16(FDMI_SMARTSAN_VERSION); + alen = scnprintf( + eiter->a.smartsan_version, sizeof(eiter->a.smartsan_version), + "%s", "Smart SAN Version 2.0"); + alen += FDMI_ATTR_ALIGNMENT(alen); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20d2, + "SMARTSAN VERSION = %s\n", eiter->a.smartsan_version); + + /* Smart SAN Product Name (Specify Adapter Model No) */ + eiter = entries + size; + eiter->type = cpu_to_be16(FDMI_SMARTSAN_PROD_NAME); + alen = scnprintf(eiter->a.smartsan_prod_name, + sizeof(eiter->a.smartsan_prod_name), + "ISP%04x", ha->pdev->device); + alen += FDMI_ATTR_ALIGNMENT(alen); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20d3, + "SMARTSAN PRODUCT NAME = %s\n", eiter->a.smartsan_prod_name); + + /* Smart SAN Port Info (specify: 1=Physical, 2=NPIV, 3=SRIOV) */ + eiter = entries + size; + eiter->type = cpu_to_be16(FDMI_SMARTSAN_PORT_INFO); + eiter->a.smartsan_port_info = cpu_to_be32(vha->vp_idx ? 2 : 1); + alen = sizeof(eiter->a.smartsan_port_info); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20d4, + "SMARTSAN PORT INFO = %x\n", eiter->a.smartsan_port_info); + + /* Smart SAN Security Support */ + eiter = entries + size; + eiter->type = cpu_to_be16(FDMI_SMARTSAN_SECURITY_SUPPORT); + eiter->a.smartsan_security_support = cpu_to_be32(1); + alen = sizeof(eiter->a.smartsan_security_support); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20d6, + "SMARTSAN SECURITY SUPPORT = %d\n", + be32_to_cpu(eiter->a.smartsan_security_support)); - ql_dbg(ql_dbg_disc, vha, 0x20af, - "CT Payload Length = 0x%x.\n", eiter->a.max_ct_len); +done: + return size; +} - /* Node Sybolic Name */ - eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_HBA_NODE_SYMBOLIC_NAME); - qla2x00_get_sym_node_name(vha, eiter->a.sym_name, - sizeof(eiter->a.sym_name)); - alen = strlen(eiter->a.sym_name); - alen += 4 - (alen & 3); - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; +/** + * qla2x00_fdmi_rhba() - perform RHBA FDMI registration + * @vha: HA context + * @callopt: Option to issue FDMI registration + * + * Returns 0 on success. + */ +static int +qla2x00_fdmi_rhba(scsi_qla_host_t *vha, unsigned int callopt) +{ + struct qla_hw_data *ha = vha->hw; + unsigned long size = 0; + unsigned int rval, count; + ms_iocb_entry_t *ms_pkt; + struct ct_sns_req *ct_req; + struct ct_sns_rsp *ct_rsp; + void *entries; - ql_dbg(ql_dbg_disc, vha, 0x20b0, - "Symbolic Name = %s.\n", eiter->a.sym_name); + count = callopt != CALLOPT_FDMI1 ? + FDMI2_HBA_ATTR_COUNT : FDMI1_HBA_ATTR_COUNT; - /* Vendor Id */ - eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_HBA_VENDOR_ID); - eiter->a.vendor_id = cpu_to_be32(0x1077); - eiter->len = cpu_to_be16(4 + 4); - size += 4 + 4; + size = RHBA_RSP_SIZE; - ql_dbg(ql_dbg_disc, vha, 0x20b1, - "Vendor Id = %x.\n", eiter->a.vendor_id); + ql_dbg(ql_dbg_disc, vha, 0x20e0, + "RHBA (callopt=%x count=%u size=%lu).\n", callopt, count, size); - /* Num Ports */ - eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_HBA_NUM_PORTS); - eiter->a.num_ports = cpu_to_be32(1); - eiter->len = cpu_to_be16(4 + 4); - size += 4 + 4; + /* Request size adjusted after CT preparation */ + ms_pkt = ha->isp_ops->prep_ms_fdmi_iocb(vha, 0, size); - ql_dbg(ql_dbg_disc, vha, 0x20b2, - "Port Num = %x.\n", eiter->a.num_ports); + /* Prepare CT request */ + ct_req = qla2x00_prep_ct_fdmi_req(ha->ct_sns, RHBA_CMD, size); + ct_rsp = &ha->ct_sns->p.rsp; - /* Fabric Name */ - eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_HBA_FABRIC_NAME); - memcpy(eiter->a.fabric_name, vha->fabric_node_name, WWN_SIZE); - eiter->len = cpu_to_be16(4 + WWN_SIZE); - size += 4 + WWN_SIZE; + /* Prepare FDMI command entries */ + memcpy(ct_req->req.rhba.hba_identifier, vha->port_name, + sizeof(ct_req->req.rhba.hba_identifier)); + size += sizeof(ct_req->req.rhba.hba_identifier); - ql_dbg(ql_dbg_disc, vha, 0x20b3, - "Fabric Name = %016llx.\n", wwn_to_u64(eiter->a.fabric_name)); + ct_req->req.rhba.entry_count = cpu_to_be32(1); + size += sizeof(ct_req->req.rhba.entry_count); - /* BIOS Version */ - eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_HBA_BOOT_BIOS_NAME); - snprintf(eiter->a.bios_name, sizeof(eiter->a.bios_name), - "BIOS %d.%02d", ha->bios_revision[1], ha->bios_revision[0]); - alen = strlen(eiter->a.bios_name); - alen += 4 - (alen & 3); - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; + memcpy(ct_req->req.rhba.port_name, vha->port_name, + sizeof(ct_req->req.rhba.port_name)); + size += sizeof(ct_req->req.rhba.port_name); - ql_dbg(ql_dbg_disc, vha, 0x20b4, - "BIOS Name = %s\n", eiter->a.bios_name); + /* Attribute count */ + ct_req->req.rhba.attrs.count = cpu_to_be32(count); + size += sizeof(ct_req->req.rhba.attrs.count); - /* Vendor Identifier */ - eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_HBA_TYPE_VENDOR_IDENTIFIER); - snprintf(eiter->a.vendor_identifier, sizeof(eiter->a.vendor_identifier), - "%s", "QLGC"); - alen = strlen(eiter->a.vendor_identifier); - alen += 4 - (alen & 3); - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; + /* Attribute block */ + entries = &ct_req->req.rhba.attrs.entry; - ql_dbg(ql_dbg_disc, vha, 0x201b, - "Vendor Identifier = %s.\n", eiter->a.vendor_identifier); + size += qla2x00_hba_attributes(vha, entries, callopt); /* Update MS request size. */ qla2x00_update_ms_fdmi_iocb(vha, size + 16); - ql_dbg(ql_dbg_disc, vha, 0x20b5, - "RHBA identifier = %016llx.\n", - wwn_to_u64(ct_req->req.rhba2.hba_identifier)); - ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x20b6, + ql_dbg(ql_dbg_disc, vha, 0x20e1, + "RHBA %016llx %016llx.\n", + wwn_to_u64(ct_req->req.rhba.hba_identifier), + wwn_to_u64(ct_req->req.rhba.port_name)); + + ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x20e2, entries, size); /* Execute MS IOCB */ rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma, - sizeof(ms_iocb_entry_t)); - if (rval != QLA_SUCCESS) { - /*EMPTY*/ - ql_dbg(ql_dbg_disc, vha, 0x20b7, - "RHBA issue IOCB failed (%d).\n", rval); - } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "RHBA") != - QLA_SUCCESS) { - rval = QLA_FUNCTION_FAILED; + sizeof(*ha->ms_iocb)); + if (rval) { + ql_dbg(ql_dbg_disc, vha, 0x20e3, + "RHBA iocb failed (%d).\n", rval); + return rval; + } + rval = qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "RHBA"); + if (rval) { if (ct_rsp->header.reason_code == CT_REASON_CANNOT_PERFORM && ct_rsp->header.explanation_code == CT_EXPL_ALREADY_REGISTERED) { - ql_dbg(ql_dbg_disc, vha, 0x20b8, - "HBA already registered.\n"); - rval = QLA_ALREADY_REGISTERED; - } else { - ql_dbg(ql_dbg_disc, vha, 0x2016, - "RHBA FDMI v2 failed, CT Reason code: 0x%x, CT Explanation 0x%x\n", - ct_rsp->header.reason_code, - ct_rsp->header.explanation_code); + ql_dbg(ql_dbg_disc, vha, 0x20e4, + "RHBA already registered.\n"); + return QLA_ALREADY_REGISTERED; } - } else { - ql_dbg(ql_dbg_disc, vha, 0x20b9, - "RHBA FDMI V2 exiting normally.\n"); + + ql_dbg(ql_dbg_disc, vha, 0x20e5, + "RHBA failed, CT Reason %#x, CT Explanation %#x\n", + ct_rsp->header.reason_code, + ct_rsp->header.explanation_code); + return rval; } + ql_dbg(ql_dbg_disc, vha, 0x20e6, "RHBA exiting normally.\n"); return rval; } -/** - * qla2x00_fdmi_dhba() - - * @vha: HA context - * - * Returns 0 on success. - */ + static int qla2x00_fdmi_dhba(scsi_qla_host_t *vha) { @@ -2250,22 +2236,17 @@ qla2x00_fdmi_dhba(scsi_qla_host_t *vha) ms_iocb_entry_t *ms_pkt; struct ct_sns_req *ct_req; struct ct_sns_rsp *ct_rsp; - /* Issue RPA */ /* Prepare common MS IOCB */ ms_pkt = ha->isp_ops->prep_ms_fdmi_iocb(vha, DHBA_REQ_SIZE, DHBA_RSP_SIZE); - /* Prepare CT request */ ct_req = qla2x00_prep_ct_fdmi_req(ha->ct_sns, DHBA_CMD, DHBA_RSP_SIZE); ct_rsp = &ha->ct_sns->p.rsp; - /* Prepare FDMI command arguments -- portname. */ memcpy(ct_req->req.dhba.port_name, vha->port_name, WWN_SIZE); - ql_dbg(ql_dbg_disc, vha, 0x2036, "DHBA portname = %8phN.\n", ct_req->req.dhba.port_name); - /* Execute MS IOCB */ rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma, sizeof(ms_iocb_entry_t)); @@ -2280,337 +2261,178 @@ qla2x00_fdmi_dhba(scsi_qla_host_t *vha) ql_dbg(ql_dbg_disc, vha, 0x2038, "DHBA exiting normally.\n"); } - return rval; } /** - * qla2x00_fdmiv2_rpa() - + * qla2x00_fdmi_rprt() perform RPRT registration * @vha: HA context + * @callopt: Option to issue extended or standard FDMI + * command parameter * * Returns 0 on success. */ static int -qla2x00_fdmiv2_rpa(scsi_qla_host_t *vha) +qla2x00_fdmi_rprt(scsi_qla_host_t *vha, int callopt) { - int rval, alen; - uint32_t size; + struct scsi_qla_host *base_vha = pci_get_drvdata(vha->hw->pdev); struct qla_hw_data *ha = vha->hw; + ulong size = 0; + uint rval, count; ms_iocb_entry_t *ms_pkt; struct ct_sns_req *ct_req; struct ct_sns_rsp *ct_rsp; void *entries; - struct ct_fdmiv2_port_attr *eiter; - struct init_cb_24xx *icb24 = (struct init_cb_24xx *)ha->init_cb; - struct new_utsname *p_sysid = NULL; - - /* Issue RPA */ - /* Prepare common MS IOCB */ - /* Request size adjusted after CT preparation */ - ms_pkt = ha->isp_ops->prep_ms_fdmi_iocb(vha, 0, RPA_RSP_SIZE); - + count = callopt == CALLOPT_FDMI2_SMARTSAN && ql2xsmartsan ? + FDMI2_SMARTSAN_PORT_ATTR_COUNT : + callopt != CALLOPT_FDMI1 ? + FDMI2_PORT_ATTR_COUNT : FDMI1_PORT_ATTR_COUNT; + + size = RPRT_RSP_SIZE; + ql_dbg(ql_dbg_disc, vha, 0x20e8, + "RPRT (callopt=%x count=%u size=%lu).\n", callopt, count, size); + /* Request size adjusted after CT preparation */ + ms_pkt = ha->isp_ops->prep_ms_fdmi_iocb(vha, 0, size); /* Prepare CT request */ - ct_req = qla2x00_prep_ct_fdmi_req(ha->ct_sns, RPA_CMD, RPA_RSP_SIZE); + ct_req = qla2x00_prep_ct_fdmi_req(ha->ct_sns, RPRT_CMD, size); ct_rsp = &ha->ct_sns->p.rsp; - - /* Prepare FDMI command arguments -- attribute block, attributes. */ - memcpy(ct_req->req.rpa2.port_name, vha->port_name, WWN_SIZE); - size = WWN_SIZE + 4; - - /* Attributes */ - ct_req->req.rpa2.attrs.count = cpu_to_be32(FDMIV2_PORT_ATTR_COUNT); - entries = &ct_req->req; - - /* FC4 types. */ - eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_PORT_FC4_TYPES); - eiter->len = cpu_to_be16(4 + 32); - eiter->a.fc4_types[2] = 0x01; - size += 4 + 32; - - ql_dbg(ql_dbg_disc, vha, 0x20ba, - "FC4_TYPES=%02x %02x.\n", - 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); - eiter->len = cpu_to_be16(4 + 4); - if (IS_CNA_CAPABLE(ha)) - eiter->a.sup_speed = cpu_to_be32( - FDMI_PORT_SPEED_10GB); - else if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) - eiter->a.sup_speed = cpu_to_be32( - FDMI_PORT_SPEED_32GB| - FDMI_PORT_SPEED_16GB| - FDMI_PORT_SPEED_8GB); - else if (IS_QLA2031(ha)) - eiter->a.sup_speed = cpu_to_be32( - FDMI_PORT_SPEED_16GB| - FDMI_PORT_SPEED_8GB| - FDMI_PORT_SPEED_4GB); - else if (IS_QLA25XX(ha)) - eiter->a.sup_speed = cpu_to_be32( - FDMI_PORT_SPEED_8GB| - FDMI_PORT_SPEED_4GB| - FDMI_PORT_SPEED_2GB| - FDMI_PORT_SPEED_1GB); - else if (IS_QLA24XX_TYPE(ha)) - eiter->a.sup_speed = cpu_to_be32( - FDMI_PORT_SPEED_4GB| - FDMI_PORT_SPEED_2GB| - FDMI_PORT_SPEED_1GB); - else if (IS_QLA23XX(ha)) - eiter->a.sup_speed = cpu_to_be32( - FDMI_PORT_SPEED_2GB| - FDMI_PORT_SPEED_1GB); - else - eiter->a.sup_speed = cpu_to_be32( - FDMI_PORT_SPEED_1GB); - size += 4 + 4; - - ql_dbg(ql_dbg_disc, vha, 0x20bb, - "Supported Port Speed = %x.\n", eiter->a.sup_speed); - - /* Current speed. */ - eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_PORT_CURRENT_SPEED); - eiter->len = cpu_to_be16(4 + 4); - switch (ha->link_data_rate) { - case PORT_SPEED_1GB: - eiter->a.cur_speed = cpu_to_be32(FDMI_PORT_SPEED_1GB); - break; - case PORT_SPEED_2GB: - eiter->a.cur_speed = cpu_to_be32(FDMI_PORT_SPEED_2GB); - break; - case PORT_SPEED_4GB: - eiter->a.cur_speed = cpu_to_be32(FDMI_PORT_SPEED_4GB); - break; - case PORT_SPEED_8GB: - eiter->a.cur_speed = cpu_to_be32(FDMI_PORT_SPEED_8GB); - break; - case PORT_SPEED_10GB: - eiter->a.cur_speed = cpu_to_be32(FDMI_PORT_SPEED_10GB); - break; - case PORT_SPEED_16GB: - eiter->a.cur_speed = cpu_to_be32(FDMI_PORT_SPEED_16GB); - break; - case PORT_SPEED_32GB: - eiter->a.cur_speed = cpu_to_be32(FDMI_PORT_SPEED_32GB); - break; - default: - eiter->a.cur_speed = cpu_to_be32(FDMI_PORT_SPEED_UNKNOWN); - break; + /* Prepare FDMI command entries */ + memcpy(ct_req->req.rprt.hba_identifier, base_vha->port_name, + sizeof(ct_req->req.rprt.hba_identifier)); + size += sizeof(ct_req->req.rprt.hba_identifier); + memcpy(ct_req->req.rprt.port_name, vha->port_name, + sizeof(ct_req->req.rprt.port_name)); + size += sizeof(ct_req->req.rprt.port_name); + /* Attribute count */ + ct_req->req.rprt.attrs.count = cpu_to_be32(count); + size += sizeof(ct_req->req.rprt.attrs.count); + /* Attribute block */ + entries = ct_req->req.rprt.attrs.entry; + size += qla2x00_port_attributes(vha, entries, callopt); + /* Update MS request size. */ + qla2x00_update_ms_fdmi_iocb(vha, size + 16); + ql_dbg(ql_dbg_disc, vha, 0x20e9, + "RPRT %016llx %016llx.\n", + wwn_to_u64(ct_req->req.rprt.port_name), + wwn_to_u64(ct_req->req.rprt.port_name)); + ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x20ea, + entries, size); + /* Execute MS IOCB */ + rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma, + sizeof(*ha->ms_iocb)); + if (rval) { + ql_dbg(ql_dbg_disc, vha, 0x20eb, + "RPRT iocb failed (%d).\n", rval); + return rval; } - size += 4 + 4; - - ql_dbg(ql_dbg_disc, vha, 0x2017, - "Current_Speed = %x.\n", eiter->a.cur_speed); - - /* Max frame size. */ - eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_PORT_MAX_FRAME_SIZE); - eiter->len = cpu_to_be16(4 + 4); - eiter->a.max_frame_size = IS_FWI2_CAPABLE(ha) ? - le16_to_cpu(icb24->frame_payload_size) : - le16_to_cpu(ha->init_cb->frame_payload_size); - eiter->a.max_frame_size = cpu_to_be32(eiter->a.max_frame_size); - size += 4 + 4; - - ql_dbg(ql_dbg_disc, vha, 0x20bc, - "Max_Frame_Size = %x.\n", eiter->a.max_frame_size); - - /* OS device name. */ - eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_PORT_OS_DEVICE_NAME); - alen = strlen(QLA2XXX_DRIVER_NAME); - snprintf(eiter->a.os_dev_name, sizeof(eiter->a.os_dev_name), - "%s:host%lu", QLA2XXX_DRIVER_NAME, vha->host_no); - alen += 4 - (alen & 3); - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; - - ql_dbg(ql_dbg_disc, vha, 0x20be, - "OS_Device_Name = %s.\n", eiter->a.os_dev_name); + rval = qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "RPRT"); + if (rval) { + if (ct_rsp->header.reason_code == CT_REASON_CANNOT_PERFORM && + ct_rsp->header.explanation_code == + CT_EXPL_ALREADY_REGISTERED) { + ql_dbg(ql_dbg_disc, vha, 0x20ec, + "RPRT already registered.\n"); + return QLA_ALREADY_REGISTERED; + } - /* Hostname. */ - eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_PORT_HOST_NAME); - p_sysid = utsname(); - if (p_sysid) { - snprintf(eiter->a.host_name, sizeof(eiter->a.host_name), - "%s", p_sysid->nodename); - } else { - snprintf(eiter->a.host_name, sizeof(eiter->a.host_name), - "%s", fc_host_system_hostname(vha->host)); + ql_dbg(ql_dbg_disc, vha, 0x20ed, + "RPRT failed, CT Reason code: %#x, CT Explanation %#x\n", + ct_rsp->header.reason_code, + ct_rsp->header.explanation_code); + return rval; } - alen = strlen(eiter->a.host_name); - alen += 4 - (alen & 3); - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; - - ql_dbg(ql_dbg_disc, vha, 0x201a, - "HostName=%s.\n", eiter->a.host_name); - - /* Node Name */ - eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_PORT_NODE_NAME); - memcpy(eiter->a.node_name, vha->node_name, WWN_SIZE); - eiter->len = cpu_to_be16(4 + WWN_SIZE); - size += 4 + WWN_SIZE; - - ql_dbg(ql_dbg_disc, vha, 0x20c0, - "Node Name = %016llx.\n", wwn_to_u64(eiter->a.node_name)); - - /* Port Name */ - eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_PORT_NAME); - memcpy(eiter->a.port_name, vha->port_name, WWN_SIZE); - eiter->len = cpu_to_be16(4 + WWN_SIZE); - size += 4 + WWN_SIZE; - - ql_dbg(ql_dbg_disc, vha, 0x20c1, - "Port Name = %016llx.\n", wwn_to_u64(eiter->a.port_name)); - - /* Port Symbolic Name */ - eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_PORT_SYM_NAME); - qla2x00_get_sym_node_name(vha, eiter->a.port_sym_name, - sizeof(eiter->a.port_sym_name)); - alen = strlen(eiter->a.port_sym_name); - alen += 4 - (alen & 3); - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; - - ql_dbg(ql_dbg_disc, vha, 0x20c2, - "port symbolic name = %s\n", eiter->a.port_sym_name); - - /* Port Type */ - eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_PORT_TYPE); - eiter->a.port_type = cpu_to_be32(NS_NX_PORT_TYPE); - eiter->len = cpu_to_be16(4 + 4); - size += 4 + 4; - - ql_dbg(ql_dbg_disc, vha, 0x20c3, - "Port Type = %x.\n", eiter->a.port_type); - - /* Class of Service */ - eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_PORT_SUPP_COS); - eiter->a.port_supported_cos = cpu_to_be32(FC_CLASS_3); - eiter->len = cpu_to_be16(4 + 4); - size += 4 + 4; - - ql_dbg(ql_dbg_disc, vha, 0x20c4, - "Supported COS = %08x\n", eiter->a.port_supported_cos); + ql_dbg(ql_dbg_disc, vha, 0x20ee, "RPRT exiting normally.\n"); + return rval; +} - /* Port Fabric Name */ - eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_PORT_FABRIC_NAME); - memcpy(eiter->a.fabric_name, vha->fabric_node_name, WWN_SIZE); - eiter->len = cpu_to_be16(4 + WWN_SIZE); - size += 4 + WWN_SIZE; +/** + * qla2x00_fdmi_rpa() - perform RPA registration + * @vha: HA context + * @callopt: Option to issue FDMI registration + * + * Returns 0 on success. + */ +static int +qla2x00_fdmi_rpa(scsi_qla_host_t *vha, uint callopt) +{ + struct qla_hw_data *ha = vha->hw; + ulong size = 0; + uint rval, count; + ms_iocb_entry_t *ms_pkt; + struct ct_sns_req *ct_req; + struct ct_sns_rsp *ct_rsp; + void *entries; - ql_dbg(ql_dbg_disc, vha, 0x20c5, - "Fabric Name = %016llx.\n", wwn_to_u64(eiter->a.fabric_name)); + count = + callopt == CALLOPT_FDMI2_SMARTSAN && ql2xsmartsan ? + FDMI2_SMARTSAN_PORT_ATTR_COUNT : + callopt != CALLOPT_FDMI1 ? + FDMI2_PORT_ATTR_COUNT : FDMI1_PORT_ATTR_COUNT; - /* FC4_type */ - eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_PORT_FC4_TYPE); - eiter->a.port_fc4_type[0] = 0; - eiter->a.port_fc4_type[1] = 0; - eiter->a.port_fc4_type[2] = 1; - eiter->a.port_fc4_type[3] = 0; - eiter->len = cpu_to_be16(4 + 32); - size += 4 + 32; + size = + callopt != CALLOPT_FDMI1 ? + SMARTSAN_RPA_RSP_SIZE : RPA_RSP_SIZE; - ql_dbg(ql_dbg_disc, vha, 0x20c6, - "Port Active FC4 Type = %02x %02x.\n", - eiter->a.port_fc4_type[2], eiter->a.port_fc4_type[1]); + ql_dbg(ql_dbg_disc, vha, 0x20f0, + "RPA (callopt=%x count=%u size=%lu).\n", callopt, count, size); - 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]); - } + /* Request size adjusted after CT preparation */ + ms_pkt = ha->isp_ops->prep_ms_fdmi_iocb(vha, 0, size); - /* Port State */ - eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_PORT_STATE); - eiter->a.port_state = cpu_to_be32(1); - eiter->len = cpu_to_be16(4 + 4); - size += 4 + 4; + /* Prepare CT request */ + ct_req = qla2x00_prep_ct_fdmi_req(ha->ct_sns, RPA_CMD, size); + ct_rsp = &ha->ct_sns->p.rsp; - ql_dbg(ql_dbg_disc, vha, 0x20c7, - "Port State = %x.\n", eiter->a.port_state); + /* Prepare FDMI command entries. */ + memcpy(ct_req->req.rpa.port_name, vha->port_name, + sizeof(ct_req->req.rpa.port_name)); + size += sizeof(ct_req->req.rpa.port_name); - /* Number of Ports */ - eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_PORT_COUNT); - eiter->a.num_ports = cpu_to_be32(1); - eiter->len = cpu_to_be16(4 + 4); - size += 4 + 4; - - ql_dbg(ql_dbg_disc, vha, 0x20c8, - "Number of ports = %x.\n", eiter->a.num_ports); + /* Attribute count */ + ct_req->req.rpa.attrs.count = cpu_to_be32(count); + size += sizeof(ct_req->req.rpa.attrs.count); - /* Port Id */ - eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_PORT_ID); - eiter->a.port_id = cpu_to_be32(vha->d_id.b24); - eiter->len = cpu_to_be16(4 + 4); - size += 4 + 4; + /* Attribute block */ + entries = ct_req->req.rpa.attrs.entry; - ql_dbg(ql_dbg_disc, vha, 0x201c, - "Port Id = %x.\n", eiter->a.port_id); + size += qla2x00_port_attributes(vha, entries, callopt); /* Update MS request size. */ qla2x00_update_ms_fdmi_iocb(vha, size + 16); - 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, + ql_dbg(ql_dbg_disc, vha, 0x20f1, + "RPA %016llx.\n", wwn_to_u64(ct_req->req.rpa.port_name)); + + ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x20f2, entries, size); /* Execute MS IOCB */ rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma, - sizeof(ms_iocb_entry_t)); - if (rval != QLA_SUCCESS) { - /*EMPTY*/ - ql_dbg(ql_dbg_disc, vha, 0x20cb, - "RPA FDMI v2 issue IOCB failed (%d).\n", rval); - } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "RPA") != - QLA_SUCCESS) { - rval = QLA_FUNCTION_FAILED; + sizeof(*ha->ms_iocb)); + if (rval) { + ql_dbg(ql_dbg_disc, vha, 0x20f3, + "RPA iocb failed (%d).\n", rval); + return rval; + } + + rval = qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "RPA"); + if (rval) { if (ct_rsp->header.reason_code == CT_REASON_CANNOT_PERFORM && ct_rsp->header.explanation_code == CT_EXPL_ALREADY_REGISTERED) { - ql_dbg(ql_dbg_disc, vha, 0x20ce, - "RPA FDMI v2 already registered\n"); - rval = QLA_ALREADY_REGISTERED; - } else { - ql_dbg(ql_dbg_disc, vha, 0x2020, - "RPA FDMI v2 failed, CT Reason code: 0x%x, CT Explanation 0x%x\n", - ct_rsp->header.reason_code, - ct_rsp->header.explanation_code); + ql_dbg(ql_dbg_disc, vha, 0x20f4, + "RPA already registered.\n"); + return QLA_ALREADY_REGISTERED; } - } else { - ql_dbg(ql_dbg_disc, vha, 0x20cc, - "RPA FDMI V2 exiting normally.\n"); + + ql_dbg(ql_dbg_disc, vha, 0x20f5, + "RPA failed, CT Reason code: %#x, CT Explanation %#x\n", + ct_rsp->header.reason_code, + ct_rsp->header.explanation_code); + return rval; } + ql_dbg(ql_dbg_disc, vha, 0x20f6, "RPA exiting normally.\n"); return rval; } @@ -2623,18 +2445,31 @@ qla2x00_fdmiv2_rpa(scsi_qla_host_t *vha) int qla2x00_fdmi_register(scsi_qla_host_t *vha) { - int rval = QLA_FUNCTION_FAILED; + int rval = QLA_SUCCESS; struct qla_hw_data *ha = vha->hw; if (IS_QLA2100(ha) || IS_QLA2200(ha) || IS_QLAFX00(ha)) - return QLA_FUNCTION_FAILED; + return rval; rval = qla2x00_mgmt_svr_login(vha); if (rval) return rval; - rval = qla2x00_fdmiv2_rhba(vha); + /* For npiv/vport send rprt only */ + if (vha->vp_idx) { + if (ql2xsmartsan) + rval = qla2x00_fdmi_rprt(vha, CALLOPT_FDMI2_SMARTSAN); + if (rval || !ql2xsmartsan) + rval = qla2x00_fdmi_rprt(vha, CALLOPT_FDMI2); + if (rval) + rval = qla2x00_fdmi_rprt(vha, CALLOPT_FDMI1); + + return rval; + } + + /* Try fdmi2 first, if fails then try fdmi1 */ + rval = qla2x00_fdmi_rhba(vha, CALLOPT_FDMI2); if (rval) { if (rval != QLA_ALREADY_REGISTERED) goto try_fdmi; @@ -2643,18 +2478,22 @@ qla2x00_fdmi_register(scsi_qla_host_t *vha) if (rval) goto try_fdmi; - rval = qla2x00_fdmiv2_rhba(vha); + rval = qla2x00_fdmi_rhba(vha, CALLOPT_FDMI2); if (rval) goto try_fdmi; } - rval = qla2x00_fdmiv2_rpa(vha); + + if (ql2xsmartsan) + rval = qla2x00_fdmi_rpa(vha, CALLOPT_FDMI2_SMARTSAN); + if (rval || !ql2xsmartsan) + rval = qla2x00_fdmi_rpa(vha, CALLOPT_FDMI2); if (rval) goto try_fdmi; - goto out; + return rval; try_fdmi: - rval = qla2x00_fdmi_rhba(vha); + rval = qla2x00_fdmi_rhba(vha, CALLOPT_FDMI1); if (rval) { if (rval != QLA_ALREADY_REGISTERED) return rval; @@ -2663,12 +2502,13 @@ try_fdmi: if (rval) return rval; - rval = qla2x00_fdmi_rhba(vha); + rval = qla2x00_fdmi_rhba(vha, CALLOPT_FDMI1); if (rval) return rval; } - rval = qla2x00_fdmi_rpa(vha); -out: + + rval = qla2x00_fdmi_rpa(vha, CALLOPT_FDMI1); + return rval; } @@ -2893,7 +2733,7 @@ qla2x00_gff_id(scsi_qla_host_t *vha, sw_info_t *list) for (i = 0; i < ha->max_fibre_devices; i++) { /* Set default FC4 Type as UNKNOWN so the default is to * Process this port */ - list[i].fc4_type = FC4_TYPE_UNKNOWN; + list[i].fc4_type = 0; /* Do not attempt GFF_ID if we are not FWI_2 capable */ if (!IS_FWI2_CAPABLE(ha)) @@ -3243,7 +3083,7 @@ void qla24xx_handle_gpnid_event(scsi_qla_host_t *vha, struct event_arg *ea) "%s %d %8phC post new sess\n", __func__, __LINE__, ea->port_name); qla24xx_post_newsess_work(vha, &ea->id, - ea->port_name, NULL, NULL, FC4_TYPE_UNKNOWN); + ea->port_name, NULL, NULL, 0); } } } @@ -3647,6 +3487,7 @@ void qla24xx_async_gnnft_done(scsi_qla_host_t *vha, srb_t *sp) if (memcmp(rp->port_name, fcport->port_name, WWN_SIZE)) continue; fcport->scan_state = QLA_FCPORT_FOUND; + fcport->last_rscn_gen = fcport->rscn_gen; found = true; /* * If device was not a fabric device before. diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 9e6b56527b25..caa6b840e459 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -1043,7 +1043,7 @@ static void qla24xx_async_gnl_sp_done(srb_t *sp, int res) __func__, __LINE__, (u8 *)&wwn, id.b24); wwnn = wwn_to_u64(e->node_name); qla24xx_post_newsess_work(vha, &id, (u8 *)&wwn, - (u8 *)&wwnn, NULL, FC4_TYPE_UNKNOWN); + (u8 *)&wwnn, NULL, 0); } } @@ -2219,10 +2219,10 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha) /* Check for secure flash support */ if (IS_QLA28XX(ha)) { - if (RD_REG_DWORD(®->mailbox12) & BIT_0) { - ql_log(ql_log_info, vha, 0xffff, "Adapter is Secure\n"); + if (RD_REG_DWORD(®->mailbox12) & BIT_0) ha->flags.secure_adapter = 1; - } + ql_log(ql_log_info, vha, 0xffff, "Secure Adapter: %s\n", + (ha->flags.secure_adapter) ? "Yes" : "No"); } @@ -2270,6 +2270,12 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha) ql_dbg(ql_dbg_init, vha, 0x0078, "Verifying loaded RISC code...\n"); + /* If smartsan enabled then require fdmi and rdp enabled */ + if (ql2xsmartsan) { + ql2xfdmienable = 1; + ql2xrdpenable = 1; + } + if (qla2x00_isp_firmware(vha) != QLA_SUCCESS) { rval = ha->isp_ops->chip_diag(vha); if (rval) @@ -3544,53 +3550,75 @@ static void qla2xxx_print_sfp_info(struct scsi_qla_host *vha) } -/* - * Return Code: - * QLA_SUCCESS: no action - * QLA_INTERFACE_ERROR: SFP is not there. - * QLA_FUNCTION_FAILED: detected New SFP +/** + * qla24xx_detect_sfp() + * + * @vha: adapter state pointer. + * + * @return + * 0 -- Configure firmware to use short-range settings -- normal + * buffer-to-buffer credits. + * + * 1 -- Configure firmware to use long-range settings -- extra + * buffer-to-buffer credits should be allocated with + * ha->lr_distance containing distance settings from NVRAM or SFP + * (if supported). */ int qla24xx_detect_sfp(scsi_qla_host_t *vha) { - int rc = QLA_SUCCESS; + int rc, used_nvram; struct sff_8247_a0 *a; struct qla_hw_data *ha = vha->hw; - - if (!AUTO_DETECT_SFP_SUPPORT(vha)) + struct nvram_81xx *nv = ha->nvram; +#define LR_DISTANCE_UNKNOWN 2 + static const char * const types[] = { "Short", "Long" }; + static const char * const lengths[] = { "(10km)", "(5km)", "" }; + u8 ll = 0; + + /* Seed with NVRAM settings. */ + used_nvram = 0; + ha->flags.lr_detected = 0; + if (IS_BPM_RANGE_CAPABLE(ha) && + (nv->enhanced_features & NEF_LR_DIST_ENABLE)) { + used_nvram = 1; + ha->flags.lr_detected = 1; + ha->lr_distance = + (nv->enhanced_features >> LR_DIST_NV_POS) + & LR_DIST_NV_MASK; + } + + if (!IS_BPM_ENABLED(vha)) goto out; - + /* Determine SR/LR capabilities of SFP/Transceiver. */ rc = qla2x00_read_sfp_dev(vha, NULL, 0); if (rc) goto out; + used_nvram = 0; a = (struct sff_8247_a0 *)vha->hw->sfp_data; qla2xxx_print_sfp_info(vha); - if (a->fc_ll_cc7 & FC_LL_VL || a->fc_ll_cc7 & FC_LL_L) { - /* long range */ - ha->flags.detected_lr_sfp = 1; + ha->flags.lr_detected = 0; + ll = a->fc_ll_cc7; + if (ll & FC_LL_VL || ll & FC_LL_L) { + /* Long range, track length. */ + ha->flags.lr_detected = 1; if (a->length_km > 5 || a->length_100m > 50) - ha->long_range_distance = LR_DISTANCE_10K; + ha->lr_distance = LR_DISTANCE_10K; else - ha->long_range_distance = LR_DISTANCE_5K; - - if (ha->flags.detected_lr_sfp != ha->flags.using_lr_setting) - ql_dbg(ql_dbg_async, vha, 0x507b, - "Detected Long Range SFP.\n"); - } else { - /* short range */ - ha->flags.detected_lr_sfp = 0; - if (ha->flags.using_lr_setting) - ql_dbg(ql_dbg_async, vha, 0x5084, - "Detected Short Range SFP.\n"); + ha->lr_distance = LR_DISTANCE_5K; } - if (!vha->flags.init_done) - rc = QLA_SUCCESS; out: - return rc; + ql_dbg(ql_dbg_async, vha, 0x507b, + "SFP detect: %s-Range SFP %s (nvr=%x ll=%x lr=%x lrd=%x).\n", + types[ha->flags.lr_detected], + ha->flags.lr_detected ? lengths[ha->lr_distance] : + lengths[LR_DISTANCE_UNKNOWN], + used_nvram, ll, ha->flags.lr_detected, ha->lr_distance); + return ha->flags.lr_detected; } /** @@ -3608,6 +3636,7 @@ qla2x00_setup_chip(scsi_qla_host_t *vha) struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; unsigned long flags; uint16_t fw_major_version; + int done_once = 0; if (IS_P3P_TYPE(ha)) { rval = ha->isp_ops->load_risc(vha, &srisc_address); @@ -3628,6 +3657,7 @@ qla2x00_setup_chip(scsi_qla_host_t *vha) qla81xx_mpi_sync(vha); +execute_fw_with_lr: /* Load firmware sequences */ rval = ha->isp_ops->load_risc(vha, &srisc_address); if (rval == QLA_SUCCESS) { @@ -3649,7 +3679,15 @@ qla2x00_setup_chip(scsi_qla_host_t *vha) rval = qla2x00_execute_fw(vha, srisc_address); /* Retrieve firmware information. */ if (rval == QLA_SUCCESS) { - qla24xx_detect_sfp(vha); + /* Enable BPM support? */ + if (!done_once++ && qla24xx_detect_sfp(vha)) { + ql_dbg(ql_dbg_init, vha, 0x00ca, + "Re-starting firmware -- BPM.\n"); + /* Best-effort - re-init. */ + ha->isp_ops->reset_chip(vha); + ha->isp_ops->chip_diag(vha); + goto execute_fw_with_lr; + } if ((IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) && @@ -3708,6 +3746,10 @@ enable_82xx_npiv: "ISP Firmware failed checksum.\n"); goto failed; } + + /* Enable PUREX PASSTHRU */ + if (ql2xrdpenable) + qla25xx_set_els_cmds_supported(vha); } else goto failed; @@ -3919,6 +3961,13 @@ qla24xx_update_fw_options(scsi_qla_host_t *vha) ha->fw_options[2] &= ~BIT_8; } + if (ql2xrdpenable) + ha->fw_options[1] |= ADD_FO1_ENABLE_PUREX_IOCB; + + /* Enable Async 8130/8131 events -- transceiver insertion/removal */ + if (IS_BPM_RANGE_CAPABLE(ha)) + ha->fw_options[3] |= BIT_10; + 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], @@ -5060,7 +5109,7 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha) if (N2N_TOPO(ha)) { if (test_and_clear_bit(N2N_LOGIN_NEEDED, &vha->dpc_flags)) { /* borrowing */ - u32 *bp, i, sz; + u32 *bp, sz; memset(ha->init_cb, 0, ha->init_cb_size); sz = min_t(int, sizeof(struct els_plogi_payload), @@ -5068,13 +5117,12 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha) rval = qla24xx_get_port_login_templ(vha, ha->init_cb_dma, (void *)ha->init_cb, sz); if (rval == QLA_SUCCESS) { + __be32 *q = &ha->plogi_els_payld.data[0]; + bp = (uint32_t *)ha->init_cb; - for (i = 0; i < sz/4 ; i++, bp++) - *bp = cpu_to_be32(*bp); + cpu_to_be32_array(q, bp, sz / 4); - memcpy(&ha->plogi_els_payld.data, - (void *)ha->init_cb, - sizeof(ha->plogi_els_payld.data)); + memcpy(bp, q, sizeof(ha->plogi_els_payld.data)); } else { ql_dbg(ql_dbg_init, vha, 0x00d1, "PLOGI ELS param read fail.\n"); @@ -5097,6 +5145,7 @@ skip_login: set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); } + return QLA_FUNCTION_FAILED; } found_devs = 0; @@ -5541,24 +5590,22 @@ qla2x00_configure_fabric(scsi_qla_host_t *vha) } vha->device_flags |= SWITCH_FOUND; + rval = qla2x00_get_port_name(vha, loop_id, vha->fabric_port_name, 0); + if (rval != QLA_SUCCESS) + ql_dbg(ql_dbg_disc, vha, 0x20ff, + "Failed to get Fabric Port Name\n"); if (qla_tgt_mode_enabled(vha) || qla_dual_mode_enabled(vha)) { rval = qla2x00_send_change_request(vha, 0x3, 0); if (rval != QLA_SUCCESS) ql_log(ql_log_warn, vha, 0x121, - "Failed to enable receiving of RSCN requests: 0x%x.\n", - rval); + "Failed to enable receiving of RSCN requests: 0x%x.\n", + rval); } - do { qla2x00_mgmt_svr_login(vha); - /* FDMI support. */ - if (ql2xfdmienable && - test_and_clear_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags)) - qla2x00_fdmi_register(vha); - /* Ensure we are logged into the SNS. */ loop_id = NPH_SNS_LID(ha); rval = ha->isp_ops->fabric_login(vha, loop_id, 0xff, 0xff, @@ -5570,6 +5617,12 @@ qla2x00_configure_fabric(scsi_qla_host_t *vha) set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); return rval; } + + /* FDMI support. */ + if (ql2xfdmienable && + test_and_clear_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags)) + qla2x00_fdmi_register(vha); + if (test_and_clear_bit(REGISTER_FC4_NEEDED, &vha->dpc_flags)) { if (qla2x00_rft_id(vha)) { /* EMPTY */ @@ -5812,7 +5865,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha) /* Bypass ports whose FCP-4 type is not FCP_SCSI */ if (ql2xgffidenable && (!(new_fcport->fc4_type & FS_FC4TYPE_FCP) && - new_fcport->fc4_type != FC4_TYPE_UNKNOWN)) + new_fcport->fc4_type != 0)) continue; spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); @@ -6656,7 +6709,7 @@ qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha) ha->flags.n2n_ae = 0; ha->flags.lip_ae = 0; ha->current_topology = 0; - ha->flags.fw_started = 0; + QLA_FW_STOPPED(ha); ha->flags.fw_init_done = 0; ha->chip_reset++; ha->base_qpair->chip_reset = ha->chip_reset; @@ -8663,61 +8716,6 @@ qla82xx_restart_isp(scsi_qla_host_t *vha) return status; } -void -qla81xx_update_fw_options(scsi_qla_host_t *vha) -{ - struct qla_hw_data *ha = vha->hw; - - /* Hold status IOCBs until ABTS response received. */ - if (ql2xfwholdabts) - ha->fw_options[3] |= BIT_12; - - /* Set Retry FLOGI in case of P2P connection */ - if (ha->operating_mode == P2P) { - ha->fw_options[2] |= BIT_3; - ql_dbg(ql_dbg_disc, vha, 0x2103, - "(%s): Setting FLOGI retry BIT in fw_options[2]: 0x%x\n", - __func__, ha->fw_options[2]); - } - - /* Move PUREX, ABTS RX & RIDA to ATIOQ */ - if (ql2xmvasynctoatio) { - if (qla_tgt_mode_enabled(vha) || - qla_dual_mode_enabled(vha)) - ha->fw_options[2] |= BIT_11; - else - 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, 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); -} - /* * qla24xx_get_fcp_prio * Gets the fcp cmd priority value for the logged in port. diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index 47bf60a9490a..182bd68c79ac 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -530,7 +530,7 @@ __qla2x00_marker(struct scsi_qla_host *vha, struct qla_qpair *qpair, int_to_scsilun(lun, (struct scsi_lun *)&mrk24->lun); host_to_fcp_swap(mrk24->lun, sizeof(mrk24->lun)); mrk24->vp_index = vha->vp_idx; - mrk24->handle = MAKE_HANDLE(req->id, mrk24->handle); + mrk24->handle = make_handle(req->id, mrk24->handle); } else { SET_TARGET_ID(ha, mrk->target, loop_id); mrk->lun = cpu_to_le16((uint16_t)lun); @@ -1655,7 +1655,7 @@ qla24xx_start_scsi(srb_t *sp) req->cnt -= req_cnt; cmd_pkt = (struct cmd_type_7 *)req->ring_ptr; - cmd_pkt->handle = MAKE_HANDLE(req->id, handle); + cmd_pkt->handle = make_handle(req->id, handle); /* Zero out remaining portion of packet. */ /* tagged queuing modifier -- default is TSK_SIMPLE (0). */ @@ -1843,7 +1843,7 @@ qla24xx_dif_start_scsi(srb_t *sp) /* Fill-in common area */ cmd_pkt = (struct cmd_type_crc_2 *)req->ring_ptr; - cmd_pkt->handle = MAKE_HANDLE(req->id, handle); + cmd_pkt->handle = make_handle(req->id, handle); clr_ptr = (uint32_t *)cmd_pkt + 2; memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8); @@ -1975,7 +1975,7 @@ qla2xxx_start_scsi_mq(srb_t *sp) req->cnt -= req_cnt; cmd_pkt = (struct cmd_type_7 *)req->ring_ptr; - cmd_pkt->handle = MAKE_HANDLE(req->id, handle); + cmd_pkt->handle = make_handle(req->id, handle); /* Zero out remaining portion of packet. */ /* tagged queuing modifier -- default is TSK_SIMPLE (0). */ @@ -2178,7 +2178,7 @@ qla2xxx_dif_start_scsi_mq(srb_t *sp) /* Fill-in common area */ cmd_pkt = (struct cmd_type_crc_2 *)req->ring_ptr; - cmd_pkt->handle = MAKE_HANDLE(req->id, handle); + cmd_pkt->handle = make_handle(req->id, handle); clr_ptr = (uint32_t *)cmd_pkt + 2; memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8); @@ -2362,6 +2362,8 @@ qla24xx_login_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_PLOGI); + if (lio->u.logio.flags & SRB_LOGIN_PRLI_ONLY) { logio->control_flags = cpu_to_le16(LCF_COMMAND_PRLI); } else { @@ -2489,7 +2491,7 @@ qla24xx_tm_iocb(srb_t *sp, struct tsk_mgmt_entry *tsk) tsk->entry_type = TSK_MGMT_IOCB_TYPE; tsk->entry_count = 1; - tsk->handle = MAKE_HANDLE(req->id, tsk->handle); + tsk->handle = make_handle(req->id, tsk->handle); tsk->nport_handle = cpu_to_le16(fcport->loop_id); tsk->timeout = cpu_to_le16(ha->r_a_tov / 10 * 2); tsk->control_flags = cpu_to_le32(flags); @@ -2684,9 +2686,9 @@ qla24xx_els_logo_iocb(srb_t *sp, struct els_entry_24xx *els_iocb) els_iocb->rx_dsd_count = 0; els_iocb->opcode = elsio->u.els_logo.els_cmd; - els_iocb->port_id[0] = sp->fcport->d_id.b.al_pa; - els_iocb->port_id[1] = sp->fcport->d_id.b.area; - els_iocb->port_id[2] = sp->fcport->d_id.b.domain; + els_iocb->d_id[0] = sp->fcport->d_id.b.al_pa; + els_iocb->d_id[1] = sp->fcport->d_id.b.area; + els_iocb->d_id[2] = sp->fcport->d_id.b.domain; /* For SID the byte order is different than DID */ els_iocb->s_id[1] = vha->d_id.b.al_pa; els_iocb->s_id[2] = vha->d_id.b.area; @@ -2939,7 +2941,6 @@ qla24xx_els_dcmd2_iocb(scsi_qla_host_t *vha, int els_opcode, sp->fcport = fcport; elsio->timeout = qla2x00_els_dcmd2_iocb_timeout; - init_completion(&elsio->u.els_plogi.comp); if (wait) sp->flags = SRB_WAKEUP_ON_COMP; @@ -2949,7 +2950,7 @@ qla24xx_els_dcmd2_iocb(scsi_qla_host_t *vha, int els_opcode, elsio->u.els_plogi.tx_size = elsio->u.els_plogi.rx_size = DMA_POOL_SIZE; ptr = elsio->u.els_plogi.els_plogi_pyld = - dma_alloc_coherent(&ha->pdev->dev, DMA_POOL_SIZE, + dma_alloc_coherent(&ha->pdev->dev, elsio->u.els_plogi.tx_size, &elsio->u.els_plogi.els_plogi_pyld_dma, GFP_KERNEL); if (!elsio->u.els_plogi.els_plogi_pyld) { @@ -2958,7 +2959,7 @@ qla24xx_els_dcmd2_iocb(scsi_qla_host_t *vha, int els_opcode, } resp_ptr = elsio->u.els_plogi.els_resp_pyld = - dma_alloc_coherent(&ha->pdev->dev, DMA_POOL_SIZE, + dma_alloc_coherent(&ha->pdev->dev, elsio->u.els_plogi.rx_size, &elsio->u.els_plogi.els_resp_pyld_dma, GFP_KERNEL); if (!elsio->u.els_plogi.els_resp_pyld) { @@ -2982,6 +2983,7 @@ qla24xx_els_dcmd2_iocb(scsi_qla_host_t *vha, int els_opcode, (uint8_t *)elsio->u.els_plogi.els_plogi_pyld, sizeof(*elsio->u.els_plogi.els_plogi_pyld)); + init_completion(&elsio->u.els_plogi.comp); rval = qla2x00_start_sp(sp); if (rval != QLA_SUCCESS) { rval = QLA_FUNCTION_FAILED; @@ -3030,9 +3032,9 @@ qla24xx_els_iocb(srb_t *sp, struct els_entry_24xx *els_iocb) sp->type == SRB_ELS_CMD_RPT ? bsg_request->rqst_data.r_els.els_code : bsg_request->rqst_data.h_els.command_code; - els_iocb->port_id[0] = sp->fcport->d_id.b.al_pa; - els_iocb->port_id[1] = sp->fcport->d_id.b.area; - els_iocb->port_id[2] = sp->fcport->d_id.b.domain; + els_iocb->d_id[0] = sp->fcport->d_id.b.al_pa; + els_iocb->d_id[1] = sp->fcport->d_id.b.area; + els_iocb->d_id[2] = sp->fcport->d_id.b.domain; els_iocb->control_flags = 0; els_iocb->rx_byte_count = cpu_to_le32(bsg_job->reply_payload.payload_len); @@ -3358,7 +3360,7 @@ sufficient_dsds: } cmd_pkt = (struct cmd_type_6 *)req->ring_ptr; - cmd_pkt->handle = MAKE_HANDLE(req->id, handle); + cmd_pkt->handle = make_handle(req->id, handle); /* Zero out remaining portion of packet. */ /* tagged queuing modifier -- default is TSK_SIMPLE (0). */ @@ -3429,7 +3431,7 @@ sufficient_dsds: goto queuing_error; cmd_pkt = (struct cmd_type_7 *)req->ring_ptr; - cmd_pkt->handle = MAKE_HANDLE(req->id, handle); + cmd_pkt->handle = make_handle(req->id, handle); /* Zero out remaining portion of packet. */ /* tagged queuing modifier -- default is TSK_SIMPLE (0).*/ @@ -3534,7 +3536,7 @@ qla24xx_abort_iocb(srb_t *sp, struct abort_entry_24xx *abt_iocb) memset(abt_iocb, 0, sizeof(struct abort_entry_24xx)); abt_iocb->entry_type = ABORT_IOCB_TYPE; abt_iocb->entry_count = 1; - abt_iocb->handle = cpu_to_le32(MAKE_HANDLE(req->id, sp->handle)); + abt_iocb->handle = cpu_to_le32(make_handle(req->id, sp->handle)); if (sp->fcport) { abt_iocb->nport_handle = cpu_to_le16(sp->fcport->loop_id); abt_iocb->port_id[0] = sp->fcport->d_id.b.al_pa; @@ -3542,7 +3544,7 @@ qla24xx_abort_iocb(srb_t *sp, struct abort_entry_24xx *abt_iocb) abt_iocb->port_id[2] = sp->fcport->d_id.b.domain; } abt_iocb->handle_to_abort = - cpu_to_le32(MAKE_HANDLE(aio->u.abt.req_que_no, + cpu_to_le32(make_handle(aio->u.abt.req_que_no, aio->u.abt.cmd_hndl)); abt_iocb->vp_index = vha->vp_idx; abt_iocb->req_que_no = cpu_to_le16(aio->u.abt.req_que_no); @@ -3905,7 +3907,7 @@ qla2x00_start_bidir(srb_t *sp, struct scsi_qla_host *vha, uint32_t tot_dsds) } cmd_pkt = (struct cmd_bidir *)req->ring_ptr; - cmd_pkt->handle = MAKE_HANDLE(req->id, handle); + cmd_pkt->handle = make_handle(req->id, handle); /* Zero out remaining portion of packet. */ /* tagged queuing modifier -- default is TSK_SIMPLE (0).*/ diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index e40705d38cea..8a78d395bbc8 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -31,6 +31,143 @@ const char *const port_state_str[] = { "ONLINE" }; +static void qla24xx_purex_iocb(scsi_qla_host_t *vha, void *pkt, + void (*process_item)(struct scsi_qla_host *vha, void *pkt)) +{ + struct purex_list *list = &vha->purex_list; + struct purex_item *item; + ulong flags; + + item = kzalloc(sizeof(*item), GFP_KERNEL); + if (!item) { + ql_log(ql_log_warn, vha, 0x5092, + ">> Failed allocate purex list item.\n"); + return; + } + + item->vha = vha; + item->process_item = process_item; + memcpy(&item->iocb, pkt, sizeof(item->iocb)); + + spin_lock_irqsave(&list->lock, flags); + list_add_tail(&item->list, &list->head); + spin_unlock_irqrestore(&list->lock, flags); + + set_bit(PROCESS_PUREX_IOCB, &vha->dpc_flags); +} + +static void +qla24xx_process_abts(struct scsi_qla_host *vha, void *pkt) +{ + struct abts_entry_24xx *abts = pkt; + struct qla_hw_data *ha = vha->hw; + struct els_entry_24xx *rsp_els; + struct abts_entry_24xx *abts_rsp; + dma_addr_t dma; + uint32_t fctl; + int rval; + + ql_dbg(ql_dbg_init, vha, 0x0286, "%s: entered.\n", __func__); + + ql_log(ql_log_warn, vha, 0x0287, + "Processing ABTS xchg=%#x oxid=%#x rxid=%#x seqid=%#x seqcnt=%#x\n", + abts->rx_xch_addr_to_abort, abts->ox_id, abts->rx_id, + abts->seq_id, abts->seq_cnt); + ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x0287, + "-------- ABTS RCV -------\n"); + ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha, 0x0287, + (uint8_t *)abts, sizeof(*abts)); + + rsp_els = dma_alloc_coherent(&ha->pdev->dev, sizeof(*rsp_els), &dma, + GFP_KERNEL); + if (!rsp_els) { + ql_log(ql_log_warn, vha, 0x0287, + "Failed allocate dma buffer ABTS/ELS RSP.\n"); + return; + } + + /* terminate exchange */ + rsp_els->entry_type = ELS_IOCB_TYPE; + rsp_els->entry_count = 1; + rsp_els->nport_handle = ~0; + rsp_els->rx_xchg_address = abts->rx_xch_addr_to_abort; + rsp_els->control_flags = EPD_RX_XCHG; + ql_dbg(ql_dbg_init, vha, 0x0283, + "Sending ELS Response to terminate exchange %#x...\n", + abts->rx_xch_addr_to_abort); + ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x0283, + "-------- ELS RSP -------\n"); + ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha, 0x0283, + (uint8_t *)rsp_els, sizeof(*rsp_els)); + rval = qla2x00_issue_iocb(vha, rsp_els, dma, 0); + if (rval) { + ql_log(ql_log_warn, vha, 0x0288, + "%s: iocb failed to execute -> %x\n", __func__, rval); + } else if (rsp_els->comp_status) { + ql_log(ql_log_warn, vha, 0x0289, + "%s: iocb failed to complete -> completion=%#x subcode=(%#x,%#x)\n", + __func__, rsp_els->comp_status, + rsp_els->error_subcode_1, rsp_els->error_subcode_2); + } else { + ql_dbg(ql_dbg_init, vha, 0x028a, + "%s: abort exchange done.\n", __func__); + } + + /* send ABTS response */ + abts_rsp = (void *)rsp_els; + memset(abts_rsp, 0, sizeof(*abts_rsp)); + abts_rsp->entry_type = ABTS_RSP_TYPE; + abts_rsp->entry_count = 1; + abts_rsp->nport_handle = abts->nport_handle; + abts_rsp->vp_idx = abts->vp_idx; + abts_rsp->sof_type = abts->sof_type & 0xf0; + abts_rsp->rx_xch_addr = abts->rx_xch_addr; + abts_rsp->d_id[0] = abts->s_id[0]; + abts_rsp->d_id[1] = abts->s_id[1]; + abts_rsp->d_id[2] = abts->s_id[2]; + abts_rsp->r_ctl = FC_ROUTING_BLD | FC_R_CTL_BLD_BA_ACC; + abts_rsp->s_id[0] = abts->d_id[0]; + abts_rsp->s_id[1] = abts->d_id[1]; + abts_rsp->s_id[2] = abts->d_id[2]; + abts_rsp->cs_ctl = abts->cs_ctl; + /* include flipping bit23 in fctl */ + fctl = ~(abts->f_ctl[2] | 0x7F) << 16 | + FC_F_CTL_LAST_SEQ | FC_F_CTL_END_SEQ | FC_F_CTL_SEQ_INIT; + abts_rsp->f_ctl[0] = fctl >> 0 & 0xff; + abts_rsp->f_ctl[1] = fctl >> 8 & 0xff; + abts_rsp->f_ctl[2] = fctl >> 16 & 0xff; + abts_rsp->type = FC_TYPE_BLD; + abts_rsp->rx_id = abts->rx_id; + abts_rsp->ox_id = abts->ox_id; + abts_rsp->payload.ba_acc.aborted_rx_id = abts->rx_id; + abts_rsp->payload.ba_acc.aborted_ox_id = abts->ox_id; + abts_rsp->payload.ba_acc.high_seq_cnt = ~0; + abts_rsp->rx_xch_addr_to_abort = abts->rx_xch_addr_to_abort; + ql_dbg(ql_dbg_init, vha, 0x028b, + "Sending BA ACC response to ABTS %#x...\n", + abts->rx_xch_addr_to_abort); + ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x028b, + "-------- ELS RSP -------\n"); + ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha, 0x028b, + (uint8_t *)abts_rsp, sizeof(*abts_rsp)); + rval = qla2x00_issue_iocb(vha, abts_rsp, dma, 0); + if (rval) { + ql_log(ql_log_warn, vha, 0x028c, + "%s: iocb failed to execute -> %x\n", __func__, rval); + } else if (abts_rsp->comp_status) { + ql_log(ql_log_warn, vha, 0x028d, + "%s: iocb failed to complete -> completion=%#x subcode=(%#x,%#x)\n", + __func__, abts_rsp->comp_status, + abts_rsp->payload.error.subcode1, + abts_rsp->payload.error.subcode2); + } else { + ql_dbg(ql_dbg_init, vha, 0x028ea, + "%s: done.\n", __func__); + } + + dma_free_coherent(&ha->pdev->dev, sizeof(*rsp_els), rsp_els, dma); +} + /** * qla2100_intr_handler() - Process interrupts for the ISP2100 and ISP2200. * @irq: interrupt number @@ -716,12 +853,24 @@ skip_rio: break; case MBA_SYSTEM_ERR: /* System Error */ - mbx = (IS_QLA81XX(ha) || IS_QLA83XX(ha) || IS_QLA27XX(ha) || - IS_QLA28XX(ha)) ? - RD_REG_WORD(®24->mailbox7) : 0; - ql_log(ql_log_warn, vha, 0x5003, - "ISP System Error - mbx1=%xh mbx2=%xh mbx3=%xh " - "mbx7=%xh.\n", mb[1], mb[2], mb[3], mbx); + mbx = 0; + if (IS_QLA81XX(ha) || IS_QLA83XX(ha) || + IS_QLA27XX(ha) || IS_QLA28XX(ha)) { + u16 m[4]; + + m[0] = RD_REG_WORD(®24->mailbox4); + m[1] = RD_REG_WORD(®24->mailbox5); + m[2] = RD_REG_WORD(®24->mailbox6); + mbx = m[3] = RD_REG_WORD(®24->mailbox7); + + ql_log(ql_log_warn, vha, 0x5003, + "ISP System Error - mbx1=%xh mbx2=%xh mbx3=%xh mbx4=%xh mbx5=%xh mbx6=%xh mbx7=%xh.\n", + mb[1], mb[2], mb[3], m[0], m[1], m[2], m[3]); + } else + ql_log(ql_log_warn, vha, 0x5003, + "ISP System Error - mbx1=%xh mbx2=%xh mbx3=%xh.\n ", + mb[1], mb[2], mb[3]); + ha->fw_dump_mpi = (IS_QLA27XX(ha) || IS_QLA28XX(ha)) && RD_REG_WORD(®24->mailbox7) & BIT_8; @@ -813,13 +962,15 @@ skip_rio: "LOOP UP detected (%s Gbps).\n", qla2x00_get_link_speed_str(ha, ha->link_data_rate)); + if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) { + if (mb[2] & BIT_0) + ql_log(ql_log_info, vha, 0x11a0, + "FEC=enabled (link up).\n"); + } + vha->flags.management_server_logged_in = 0; qla2x00_post_aen_work(vha, FCH_EVT_LINKUP, ha->link_data_rate); - if (AUTO_DETECT_SFP_SUPPORT(vha)) { - set_bit(DETECT_SFP_CHANGE, &vha->dpc_flags); - qla2xxx_wake_dpc(vha); - } break; case MBA_LOOP_DOWN: /* Loop Down Event */ @@ -1254,6 +1405,7 @@ global_port_update: ql_dbg(ql_dbg_async, vha, 0x5052, "D-Port Diagnostics: %04x %04x %04x %04x\n", mb[0], mb[1], mb[2], mb[3]); + memcpy(vha->dport_data, mb, sizeof(vha->dport_data)); if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) { static char *results[] = { "start", "done(pass)", "done(error)", "undefined" }; @@ -1291,6 +1443,11 @@ global_port_update: case MBA_TRANS_INSERT: ql_dbg(ql_dbg_async, vha, 0x5091, "Transceiver Insertion: %04x\n", mb[1]); + set_bit(DETECT_SFP_CHANGE, &vha->dpc_flags); + break; + + case MBA_TRANS_REMOVE: + ql_dbg(ql_dbg_async, vha, 0x5091, "Transceiver Removal\n"); break; default: @@ -1754,11 +1911,9 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req, } if (le16_to_cpu(logio->comp_status) == CS_COMPLETE) { - ql_dbg(ql_dbg_async, fcport->vha, 0x5036, - "Async-%s complete - %8phC hdl=%x portid=%02x%02x%02x " - "iop0=%x.\n", type, fcport->port_name, sp->handle, - fcport->d_id.b.domain, - fcport->d_id.b.area, fcport->d_id.b.al_pa, + ql_dbg(ql_dbg_async, sp->vha, 0x5036, + "Async-%s complete: handle=%x pid=%06x wwpn=%8phC iop0=%x\n", + type, sp->handle, fcport->d_id.b24, fcport->port_name, le32_to_cpu(logio->io_parameter[0])); vha->hw->exch_starvation = 0; @@ -1837,11 +1992,9 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req, break; } - ql_dbg(ql_dbg_async, fcport->vha, 0x5037, - "Async-%s failed - %8phC hdl=%x portid=%02x%02x%02x comp=%x " - "iop0=%x iop1=%x.\n", type, fcport->port_name, - sp->handle, fcport->d_id.b.domain, - fcport->d_id.b.area, fcport->d_id.b.al_pa, + ql_dbg(ql_dbg_async, sp->vha, 0x5037, + "Async-%s failed: handle=%x pid=%06x wwpn=%8phC comp_status=%x iop0=%x iop1=%x\n", + type, sp->handle, fcport->d_id.b24, fcport->port_name, le16_to_cpu(logio->comp_status), le32_to_cpu(logio->io_parameter[0]), le32_to_cpu(logio->io_parameter[1])); @@ -1910,6 +2063,7 @@ static void qla24xx_nvme_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, struct nvmefc_fcp_req *fd; uint16_t ret = QLA_SUCCESS; uint16_t comp_status = le16_to_cpu(sts->comp_status); + int logit = 0; iocb = &sp->u.iocb_cmd; fcport = sp->fcport; @@ -1920,6 +2074,12 @@ static void qla24xx_nvme_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, if (unlikely(iocb->u.nvme.aen_op)) atomic_dec(&sp->vha->hw->nvme_active_aen_cnt); + if (unlikely(comp_status != CS_COMPLETE)) + logit = 1; + + fd->transferred_length = fd->payload_length - + le32_to_cpu(sts->residual_len); + /* * State flags: Bit 6 and 0. * If 0 is set, we don't care about 6. @@ -1930,8 +2090,20 @@ static void qla24xx_nvme_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, */ 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)) { + } else if ((state_flags & (SF_FCP_RSP_DMA | SF_NVME_ERSP)) == + (SF_FCP_RSP_DMA | SF_NVME_ERSP)) { + /* Response already DMA'd to fd->rspaddr. */ iocb->u.nvme.rsp_pyld_len = le16_to_cpu(sts->nvme_rsp_pyld_len); + } else if ((state_flags & SF_FCP_RSP_DMA)) { + /* + * Non-zero value in first 12 bytes of NVMe_RSP IU, treat this + * as an error. + */ + iocb->u.nvme.rsp_pyld_len = 0; + fd->transferred_length = 0; + ql_dbg(ql_dbg_io, fcport->vha, 0x307a, + "Unexpected values in NVMe_RSP IU.\n"); + logit = 1; } else if (state_flags & SF_NVME_ERSP) { uint32_t *inbuf, *outbuf; uint16_t iter; @@ -1954,16 +2126,28 @@ static void qla24xx_nvme_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, 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 (state_flags & SF_NVME_ERSP) { + struct nvme_fc_ersp_iu *rsp_iu = fd->rspaddr; + u32 tgt_xfer_len; - if (unlikely(comp_status != CS_COMPLETE)) + tgt_xfer_len = be32_to_cpu(rsp_iu->xfrd_len); + if (fd->transferred_length != tgt_xfer_len) { + ql_dbg(ql_dbg_io, fcport->vha, 0x3079, + "Dropped frame(s) detected (sent/rcvd=%u/%u).\n", + tgt_xfer_len, fd->transferred_length); + logit = 1; + } else if (comp_status == CS_DATA_UNDERRUN) { + /* + * Do not log if this is just an underflow and there + * is no data loss. + */ + logit = 0; + } + } + + if (unlikely(logit)) ql_log(ql_log_warn, fcport->vha, 0x5060, "NVME-%s ERR Handling - hdl=%x status(%x) tr_len:%x resid=%x ox_id=%x\n", sp->name, sp->handle, comp_status, @@ -2516,11 +2700,6 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) return; } - if (sp->abort) - sp->aborted = 1; - else - sp->completed = 1; - if (sp->cmd_type != TYPE_SRB) { req->outstanding_cmds[handle] = NULL; ql_dbg(ql_dbg_io, vha, 0x3015, @@ -3083,6 +3262,11 @@ process_err: qla24xx_els_ct_entry(vha, rsp->req, pkt, ELS_IOCB_TYPE); break; case ABTS_RECV_24XX: + if (qla_ini_mode_enabled(vha)) { + qla24xx_purex_iocb(vha, pkt, + qla24xx_process_abts); + break; + } if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) { /* ensure that the ATIO queue is empty */ @@ -3127,6 +3311,19 @@ process_err: qla_ctrlvp_completed(vha, rsp->req, (struct vp_ctrl_entry_24xx *)pkt); break; + case PUREX_IOCB_TYPE: + { + struct purex_entry_24xx *purex = (void *)pkt; + + if (purex->els_frame_payload[3] != ELS_COMMAND_RDP) { + ql_dbg(ql_dbg_init, vha, 0x5091, + "Discarding ELS Request opcode %#x...\n", + purex->els_frame_payload[3]); + break; + } + qla24xx_purex_iocb(vha, pkt, qla24xx_process_purex_rdp); + break; + } default: /* Type Not Supported. */ ql_dbg(ql_dbg_async, vha, 0x5042, @@ -3442,6 +3639,25 @@ qla2xxx_msix_rsp_q(int irq, void *dev_id) { struct qla_hw_data *ha; struct qla_qpair *qpair; + + qpair = dev_id; + if (!qpair) { + ql_log(ql_log_info, NULL, 0x505b, + "%s: NULL response queue pointer.\n", __func__); + return IRQ_NONE; + } + ha = qpair->hw; + + queue_work(ha->wq, &qpair->q_work); + + return IRQ_HANDLED; +} + +irqreturn_t +qla2xxx_msix_rsp_q_hs(int irq, void *dev_id) +{ + struct qla_hw_data *ha; + struct qla_qpair *qpair; struct device_reg_24xx __iomem *reg; unsigned long flags; @@ -3453,13 +3669,10 @@ qla2xxx_msix_rsp_q(int irq, void *dev_id) } ha = qpair->hw; - /* Clear the interrupt, if enabled, for this response queue */ - if (unlikely(!ha->flags.disable_msix_handshake)) { - reg = &ha->iobase->isp24; - spin_lock_irqsave(&ha->hardware_lock, flags); - WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - } + reg = &ha->iobase->isp24; + spin_lock_irqsave(&ha->hardware_lock, flags); + WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT); + spin_unlock_irqrestore(&ha->hardware_lock, flags); queue_work(ha->wq, &qpair->q_work); @@ -3478,6 +3691,7 @@ static const struct qla_init_msix_entry msix_entries[] = { { "rsp_q", qla24xx_msix_rsp_q }, { "atio_q", qla83xx_msix_atio_q }, { "qpair_multiq", qla2xxx_msix_rsp_q }, + { "qpair_multiq_hs", qla2xxx_msix_rsp_q_hs }, }; static const struct qla_init_msix_entry qla82xx_msix_entries[] = { diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 9e09964f5c0e..4ed90437e8c4 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -117,10 +117,9 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) ql_dbg(ql_dbg_mbx, vha, 0x1000, "Entered %s.\n", __func__); - if (ha->pdev->error_state > pci_channel_io_frozen) { + if (ha->pdev->error_state == pci_channel_io_perm_failure) { ql_log(ql_log_warn, vha, 0x1001, - "error_state is greater than pci_channel_io_frozen, " - "exiting.\n"); + "PCI channel failed permanently, exiting.\n"); return QLA_FUNCTION_TIMEOUT; } @@ -643,30 +642,7 @@ qla2x00_load_ram(scsi_qla_host_t *vha, dma_addr_t req_dma, uint32_t risc_addr, return rval; } -#define EXTENDED_BB_CREDITS BIT_0 #define NVME_ENABLE_FLAG BIT_3 -static inline uint16_t qla25xx_set_sfp_lr_dist(struct qla_hw_data *ha) -{ - uint16_t mb4 = BIT_0; - - if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) - mb4 |= ha->long_range_distance << LR_DIST_FW_POS; - - return mb4; -} - -static inline uint16_t qla25xx_set_nvr_lr_dist(struct qla_hw_data *ha) -{ - uint16_t mb4 = BIT_0; - - if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) { - struct nvram_81xx *nv = ha->nvram; - - mb4 |= LR_DIST_FW_FIELD(nv->enhanced_features); - } - - return mb4; -} /* * qla2x00_execute_fw @@ -690,10 +666,14 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr) struct qla_hw_data *ha = vha->hw; mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; + u8 semaphore = 0; +#define EXE_FW_FORCE_SEMAPHORE BIT_7 + u8 retry = 3; ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1025, "Entered %s.\n", __func__); +again: mcp->mb[0] = MBC_EXECUTE_FIRMWARE; mcp->out_mb = MBX_0; mcp->in_mb = MBX_0; @@ -703,25 +683,13 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr) mcp->mb[3] = 0; mcp->mb[4] = 0; mcp->mb[11] = 0; - ha->flags.using_lr_setting = 0; - if (IS_QLA25XX(ha) || IS_QLA81XX(ha) || IS_QLA83XX(ha) || - IS_QLA27XX(ha) || IS_QLA28XX(ha)) { - if (ql2xautodetectsfp) { - if (ha->flags.detected_lr_sfp) { - mcp->mb[4] |= - qla25xx_set_sfp_lr_dist(ha); - ha->flags.using_lr_setting = 1; - } - } else { - struct nvram_81xx *nv = ha->nvram; - /* set LR distance if specified in nvram */ - if (nv->enhanced_features & - NEF_LR_DIST_ENABLE) { - mcp->mb[4] |= - qla25xx_set_nvr_lr_dist(ha); - ha->flags.using_lr_setting = 1; - } - } + + /* Enable BPM? */ + if (ha->flags.lr_detected) { + mcp->mb[4] = BIT_0; + if (IS_BPM_RANGE_CAPABLE(ha)) + mcp->mb[4] |= + ha->lr_distance << LR_DIST_FW_POS; } if (ql2xnvmeenable && (IS_QLA27XX(ha) || IS_QLA28XX(ha))) @@ -747,6 +715,9 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr) if (ha->flags.exchoffld_enabled) mcp->mb[4] |= ENABLE_EXCHANGE_OFFLD; + if (semaphore) + mcp->mb[11] |= EXE_FW_FORCE_SEMAPHORE; + mcp->out_mb |= MBX_4 | MBX_3 | MBX_2 | MBX_1 | MBX_11; mcp->in_mb |= MBX_3 | MBX_2 | MBX_1; } else { @@ -763,6 +734,15 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr) rval = qla2x00_mailbox_command(vha, mcp); if (rval != QLA_SUCCESS) { + if (IS_QLA28XX(ha) && rval == QLA_COMMAND_ERROR && + mcp->mb[1] == 0x27 && retry) { + semaphore = 1; + retry--; + ql_dbg(ql_dbg_async, vha, 0x1026, + "Exe FW: force semaphore.\n"); + goto again; + } + ql_dbg(ql_dbg_mbx, vha, 0x1026, "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); return rval; @@ -1137,11 +1117,13 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha) ha->fw_ddr_ram_start = (mcp->mb[23] << 16) | mcp->mb[22]; ha->fw_ddr_ram_end = (mcp->mb[25] << 16) | mcp->mb[24]; if (IS_QLA28XX(ha)) { - if (mcp->mb[16] & BIT_10) { - ql_log(ql_log_info, vha, 0xffff, - "FW support secure flash updates\n"); + if (mcp->mb[16] & BIT_10) ha->flags.secure_fw = 1; - } + + ql_log(ql_log_info, vha, 0xffff, + "Secure Flash Update in FW: %s\n", + (ha->flags.secure_fw) ? "Supported" : + "Not Supported"); } } @@ -1405,17 +1387,20 @@ qla2x00_issue_iocb_timeout(scsi_qla_host_t *vha, void *buffer, mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; + if (!vha->hw->flags.fw_started) + return QLA_INVALID_COMMAND; + ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1038, "Entered %s.\n", __func__); mcp->mb[0] = MBC_IOCB_COMMAND_A64; mcp->mb[1] = 0; - mcp->mb[2] = MSW(phys_addr); - mcp->mb[3] = LSW(phys_addr); + mcp->mb[2] = MSW(LSD(phys_addr)); + mcp->mb[3] = LSW(LSD(phys_addr)); mcp->mb[6] = MSW(MSD(phys_addr)); mcp->mb[7] = LSW(MSD(phys_addr)); mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; - mcp->in_mb = MBX_2|MBX_0; + mcp->in_mb = MBX_1|MBX_0; mcp->tov = tov; mcp->flags = 0; rval = qla2x00_mailbox_command(vha, mcp); @@ -1424,13 +1409,14 @@ qla2x00_issue_iocb_timeout(scsi_qla_host_t *vha, void *buffer, /*EMPTY*/ ql_dbg(ql_dbg_mbx, vha, 0x1039, "Failed=%x.\n", rval); } else { - sts_entry_t *sts_entry = (sts_entry_t *) buffer; + sts_entry_t *sts_entry = buffer; /* Mask reserved bits. */ sts_entry->entry_status &= IS_FWI2_CAPABLE(vha->hw) ? RF_MASK_24XX : RF_MASK; ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x103a, - "Done %s.\n", __func__); + "Done %s (status=%x).\n", __func__, + sts_entry->entry_status); } return rval; @@ -1475,7 +1461,7 @@ qla2x00_abort_command(srb_t *sp) ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x103b, "Entered %s.\n", __func__); - if (vha->flags.qpairs_available && sp->qpair) + if (sp->qpair) req = sp->qpair->req; else req = vha->req; @@ -2045,6 +2031,57 @@ gpd_error_out: return rval; } +int +qla24xx_get_port_database(scsi_qla_host_t *vha, u16 nport_handle, + struct port_database_24xx *pdb) +{ + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + dma_addr_t pdb_dma; + int rval; + + ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1115, + "Entered %s.\n", __func__); + + memset(pdb, 0, sizeof(*pdb)); + + pdb_dma = dma_map_single(&vha->hw->pdev->dev, pdb, + sizeof(*pdb), DMA_FROM_DEVICE); + if (!pdb_dma) { + ql_log(ql_log_warn, vha, 0x1116, "Failed to map dma buffer.\n"); + return QLA_MEMORY_ALLOC_FAILED; + } + + mcp->mb[0] = MBC_GET_PORT_DATABASE; + mcp->mb[1] = nport_handle; + mcp->mb[2] = MSW(LSD(pdb_dma)); + mcp->mb[3] = LSW(LSD(pdb_dma)); + mcp->mb[6] = MSW(MSD(pdb_dma)); + mcp->mb[7] = LSW(MSD(pdb_dma)); + mcp->mb[9] = 0; + mcp->mb[10] = 0; + mcp->out_mb = MBX_10|MBX_9|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; + mcp->in_mb = MBX_1|MBX_0; + mcp->buf_size = sizeof(*pdb); + mcp->flags = MBX_DMA_IN; + mcp->tov = vha->hw->login_timeout * 2; + rval = qla2x00_mailbox_command(vha, mcp); + + if (rval != QLA_SUCCESS) { + ql_dbg(ql_dbg_mbx, vha, 0x111a, + "Failed=%x mb[0]=%x mb[1]=%x.\n", + rval, mcp->mb[0], mcp->mb[1]); + } else { + ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x111b, + "Done %s.\n", __func__); + } + + dma_unmap_single(&vha->hw->pdev->dev, pdb_dma, + sizeof(*pdb), DMA_FROM_DEVICE); + + return rval; +} + /* * qla2x00_get_firmware_state * Get adapter firmware state. @@ -2384,7 +2421,7 @@ qla24xx_login_fabric(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain, lg->entry_type = LOGINOUT_PORT_IOCB_TYPE; lg->entry_count = 1; - lg->handle = MAKE_HANDLE(req->id, lg->handle); + lg->handle = make_handle(req->id, lg->handle); lg->nport_handle = cpu_to_le16(loop_id); lg->control_flags = cpu_to_le16(LCF_COMMAND_PLOGI); if (opt & BIT_0) @@ -2654,7 +2691,7 @@ qla24xx_fabric_logout(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain, req = vha->req; lg->entry_type = LOGINOUT_PORT_IOCB_TYPE; lg->entry_count = 1; - lg->handle = MAKE_HANDLE(req->id, lg->handle); + lg->handle = make_handle(req->id, lg->handle); lg->nport_handle = cpu_to_le16(loop_id); lg->control_flags = cpu_to_le16(LCF_COMMAND_LOGO|LCF_IMPL_LOGO| @@ -3060,18 +3097,19 @@ qla24xx_get_isp_stats(scsi_qla_host_t *vha, struct link_statistics *stats, int rval; mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - uint32_t *iter, dwords; + uint32_t *iter = (void *)stats; + ushort dwords = sizeof(*stats)/sizeof(*iter); ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1088, "Entered %s.\n", __func__); memset(&mc, 0, sizeof(mc)); mc.mb[0] = MBC_GET_LINK_PRIV_STATS; - mc.mb[2] = MSW(stats_dma); - mc.mb[3] = LSW(stats_dma); + mc.mb[2] = MSW(LSD(stats_dma)); + mc.mb[3] = LSW(LSD(stats_dma)); mc.mb[6] = MSW(MSD(stats_dma)); mc.mb[7] = LSW(MSD(stats_dma)); - mc.mb[8] = sizeof(struct link_statistics) / 4; + mc.mb[8] = dwords; mc.mb[9] = cpu_to_le16(vha->vp_idx); mc.mb[10] = cpu_to_le16(options); @@ -3086,8 +3124,6 @@ qla24xx_get_isp_stats(scsi_qla_host_t *vha, struct link_statistics *stats, ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x108a, "Done %s.\n", __func__); /* Re-endianize - firmware data is le32. */ - dwords = sizeof(struct link_statistics) / 4; - iter = &stats->link_fail_cnt; for ( ; dwords--; iter++) le32_to_cpus(iter); } @@ -3145,9 +3181,9 @@ qla24xx_abort_command(srb_t *sp) abt->entry_type = ABORT_IOCB_TYPE; abt->entry_count = 1; - abt->handle = MAKE_HANDLE(req->id, abt->handle); + abt->handle = make_handle(req->id, abt->handle); abt->nport_handle = cpu_to_le16(fcport->loop_id); - abt->handle_to_abort = MAKE_HANDLE(req->id, handle); + abt->handle_to_abort = make_handle(req->id, handle); abt->port_id[0] = fcport->d_id.b.al_pa; abt->port_id[1] = fcport->d_id.b.area; abt->port_id[2] = fcport->d_id.b.domain; @@ -3224,7 +3260,7 @@ __qla24xx_issue_tmf(char *name, uint32_t type, struct fc_port *fcport, tsk->p.tsk.entry_type = TSK_MGMT_IOCB_TYPE; tsk->p.tsk.entry_count = 1; - tsk->p.tsk.handle = MAKE_HANDLE(req->id, tsk->p.tsk.handle); + tsk->p.tsk.handle = make_handle(req->id, tsk->p.tsk.handle); tsk->p.tsk.nport_handle = cpu_to_le16(fcport->loop_id); tsk->p.tsk.timeout = cpu_to_le16(ha->r_a_tov / 10 * 2); tsk->p.tsk.control_flags = cpu_to_le32(type); @@ -3888,11 +3924,29 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha, fcport->scan_state = QLA_FCPORT_SCAN; fcport->n2n_flag = 0; } + id.b24 = 0; + if (wwn_to_u64(vha->port_name) > + wwn_to_u64(rptid_entry->u.f1.port_name)) { + vha->d_id.b24 = 0; + vha->d_id.b.al_pa = 1; + ha->flags.n2n_bigger = 1; + + id.b.al_pa = 2; + ql_dbg(ql_dbg_async, vha, 0x5075, + "Format 1: assign local id %x remote id %x\n", + vha->d_id.b24, id.b24); + } else { + ql_dbg(ql_dbg_async, vha, 0x5075, + "Format 1: Remote login - Waiting for WWPN %8phC.\n", + rptid_entry->u.f1.port_name); + ha->flags.n2n_bigger = 0; + } fcport = qla2x00_find_fcport_by_wwpn(vha, rptid_entry->u.f1.port_name, 1); spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); + if (fcport) { fcport->plogi_nack_done_deadline = jiffies + HZ; fcport->dm_login_expire = jiffies + 2*HZ; @@ -3903,6 +3957,11 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha, if (vha->flags.nvme_enabled) fcport->fc4_type |= FS_FC4TYPE_NVME; + if (wwn_to_u64(vha->port_name) > + wwn_to_u64(fcport->port_name)) { + fcport->d_id = id; + } + switch (fcport->disc_state) { case DSC_DELETED: set_bit(RELOGIN_NEEDED, @@ -3915,25 +3974,6 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha, break; } } else { - id.b24 = 0; - if (wwn_to_u64(vha->port_name) > - wwn_to_u64(rptid_entry->u.f1.port_name)) { - vha->d_id.b24 = 0; - vha->d_id.b.al_pa = 1; - ha->flags.n2n_bigger = 1; - ha->flags.n2n_ae = 0; - - id.b.al_pa = 2; - ql_dbg(ql_dbg_async, vha, 0x5075, - "Format 1: assign local id %x remote id %x\n", - vha->d_id.b24, id.b24); - } else { - ql_dbg(ql_dbg_async, vha, 0x5075, - "Format 1: Remote login - Waiting for WWPN %8phC.\n", - rptid_entry->u.f1.port_name); - ha->flags.n2n_bigger = 0; - ha->flags.n2n_ae = 1; - } qla24xx_post_newsess_work(vha, &id, rptid_entry->u.f1.port_name, rptid_entry->u.f1.node_name, @@ -4827,6 +4867,101 @@ qla24xx_get_port_login_templ(scsi_qla_host_t *vha, dma_addr_t buf_dma, return rval; } +int +qla25xx_set_els_cmds_supported(scsi_qla_host_t *vha) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + uint8_t *els_cmd_map; + dma_addr_t els_cmd_map_dma; + uint cmd_opcode = ELS_COMMAND_RDP; + uint index = cmd_opcode / 8; + uint bit = cmd_opcode % 8; + struct qla_hw_data *ha = vha->hw; + + if (!IS_QLA25XX(ha) && !IS_QLA2031(ha) && !IS_QLA27XX(ha)) + return QLA_SUCCESS; + + ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1197, + "Entered %s.\n", __func__); + + els_cmd_map = dma_alloc_coherent(&ha->pdev->dev, ELS_CMD_MAP_SIZE, + &els_cmd_map_dma, GFP_KERNEL); + if (!els_cmd_map) { + ql_log(ql_log_warn, vha, 0x7101, + "Failed to allocate RDP els command param.\n"); + return QLA_MEMORY_ALLOC_FAILED; + } + + els_cmd_map[index] |= 1 << bit; + + mcp->mb[0] = MBC_SET_RNID_PARAMS; + mcp->mb[1] = RNID_TYPE_ELS_CMD << 8; + mcp->mb[2] = MSW(LSD(els_cmd_map_dma)); + mcp->mb[3] = LSW(LSD(els_cmd_map_dma)); + mcp->mb[6] = MSW(MSD(els_cmd_map_dma)); + mcp->mb[7] = LSW(MSD(els_cmd_map_dma)); + mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; + mcp->in_mb = MBX_1|MBX_0; + mcp->tov = MBX_TOV_SECONDS; + mcp->flags = MBX_DMA_OUT; + mcp->buf_size = ELS_CMD_MAP_SIZE; + rval = qla2x00_mailbox_command(vha, mcp); + + if (rval != QLA_SUCCESS) { + ql_dbg(ql_dbg_mbx, vha, 0x118d, + "Failed=%x (%x,%x).\n", rval, mcp->mb[0], mcp->mb[1]); + } else { + ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x118c, + "Done %s.\n", __func__); + } + + dma_free_coherent(&ha->pdev->dev, DMA_POOL_SIZE, + els_cmd_map, els_cmd_map_dma); + + return rval; +} + +int +qla24xx_get_buffer_credits(scsi_qla_host_t *vha, struct buffer_credit_24xx *bbc, + dma_addr_t bbc_dma) +{ + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + int rval; + + if (!IS_FWI2_CAPABLE(vha->hw)) + return QLA_FUNCTION_FAILED; + + ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x118e, + "Entered %s.\n", __func__); + + mcp->mb[0] = MBC_GET_RNID_PARAMS; + mcp->mb[1] = RNID_BUFFER_CREDITS << 8; + mcp->mb[2] = MSW(LSD(bbc_dma)); + mcp->mb[3] = LSW(LSD(bbc_dma)); + mcp->mb[6] = MSW(MSD(bbc_dma)); + mcp->mb[7] = LSW(MSD(bbc_dma)); + mcp->mb[8] = sizeof(*bbc) / sizeof(*bbc->parameter); + mcp->out_mb = MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; + mcp->in_mb = MBX_1|MBX_0; + mcp->buf_size = sizeof(*bbc); + mcp->flags = MBX_DMA_IN; + mcp->tov = MBX_TOV_SECONDS; + rval = qla2x00_mailbox_command(vha, mcp); + + if (rval != QLA_SUCCESS) { + ql_dbg(ql_dbg_mbx, vha, 0x118f, + "Failed=%x mb[0]=%x,%x.\n", rval, mcp->mb[0], mcp->mb[1]); + } else { + ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1190, + "Done %s.\n", __func__); + } + + return rval; +} + static int qla2x00_read_asic_temperature(scsi_qla_host_t *vha, uint16_t *temp) { @@ -4880,8 +5015,8 @@ qla2x00_read_sfp(scsi_qla_host_t *vha, dma_addr_t sfp_dma, uint8_t *sfp, mcp->mb[0] = MBC_READ_SFP; mcp->mb[1] = dev; - mcp->mb[2] = MSW(sfp_dma); - mcp->mb[3] = LSW(sfp_dma); + mcp->mb[2] = MSW(LSD(sfp_dma)); + mcp->mb[3] = LSW(LSD(sfp_dma)); mcp->mb[6] = MSW(MSD(sfp_dma)); mcp->mb[7] = LSW(MSD(sfp_dma)); mcp->mb[8] = len; @@ -4934,8 +5069,8 @@ qla2x00_write_sfp(scsi_qla_host_t *vha, dma_addr_t sfp_dma, uint8_t *sfp, mcp->mb[0] = MBC_WRITE_SFP; mcp->mb[1] = dev; - mcp->mb[2] = MSW(sfp_dma); - mcp->mb[3] = LSW(sfp_dma); + mcp->mb[2] = MSW(LSD(sfp_dma)); + mcp->mb[3] = LSW(LSD(sfp_dma)); mcp->mb[6] = MSW(MSD(sfp_dma)); mcp->mb[7] = LSW(MSD(sfp_dma)); mcp->mb[8] = len; @@ -5170,10 +5305,11 @@ qla2x00_echo_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq, mcp->out_mb |= MBX_2; mcp->in_mb = MBX_0; - if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) || - IS_CNA_CAPABLE(ha) || IS_QLA2031(ha)) + if (IS_CNA_CAPABLE(ha) || IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) || + IS_QLA2031(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) mcp->in_mb |= MBX_1; - if (IS_CNA_CAPABLE(ha) || IS_QLA2031(ha)) + if (IS_CNA_CAPABLE(ha) || IS_QLA2031(ha) || IS_QLA27XX(ha) || + IS_QLA28XX(ha)) mcp->in_mb |= MBX_3; mcp->tov = MBX_TOV_SECONDS; @@ -5407,6 +5543,15 @@ qla2x00_get_data_rate(scsi_qla_host_t *vha) ql_dbg(ql_dbg_mbx, vha, 0x1107, "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); } else { + if (mcp->mb[1] != 0x7) + ha->link_data_rate = mcp->mb[1]; + + if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) { + if (mcp->mb[4] & BIT_0) + ql_log(ql_log_info, vha, 0x11a2, + "FEC=enabled (data rate).\n"); + } + ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1108, "Done %s.\n", __func__); if (mcp->mb[1] != 0x7) @@ -6688,3 +6833,60 @@ int qla2xxx_read_remote_register(scsi_qla_host_t *vha, uint32_t addr, return rval; } + +int +ql26xx_led_config(scsi_qla_host_t *vha, uint16_t options, uint16_t *led) +{ + struct qla_hw_data *ha = vha->hw; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + int rval; + + if (!IS_QLA2031(ha) && !IS_QLA27XX(ha) && !IS_QLA28XX(ha)) + return QLA_FUNCTION_FAILED; + + ql_dbg(ql_dbg_mbx, vha, 0x7070, "Entered %s (options=%x).\n", + __func__, options); + + mcp->mb[0] = MBC_SET_GET_FC_LED_CONFIG; + mcp->mb[1] = options; + mcp->out_mb = MBX_1|MBX_0; + mcp->in_mb = MBX_1|MBX_0; + if (options & BIT_0) { + if (options & BIT_1) { + mcp->mb[2] = led[2]; + mcp->out_mb |= MBX_2; + } + if (options & BIT_2) { + mcp->mb[3] = led[0]; + mcp->out_mb |= MBX_3; + } + if (options & BIT_3) { + mcp->mb[4] = led[1]; + mcp->out_mb |= MBX_4; + } + } else { + mcp->in_mb |= MBX_4|MBX_3|MBX_2; + } + mcp->tov = MBX_TOV_SECONDS; + mcp->flags = 0; + rval = qla2x00_mailbox_command(vha, mcp); + if (rval) { + ql_dbg(ql_dbg_mbx, vha, 0x7071, "Failed %s %x (mb=%x,%x)\n", + __func__, rval, mcp->mb[0], mcp->mb[1]); + return rval; + } + + if (options & BIT_0) { + ha->beacon_blink_led = 0; + ql_dbg(ql_dbg_mbx, vha, 0x7072, "Done %s\n", __func__); + } else { + led[2] = mcp->mb[2]; + led[0] = mcp->mb[3]; + led[1] = mcp->mb[4]; + ql_dbg(ql_dbg_mbx, vha, 0x7073, "Done %s (led=%x,%x,%x)\n", + __func__, led[0], led[1], led[2]); + } + + return rval; +} diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c index 8ae639d089d1..d82e92da529a 100644 --- a/drivers/scsi/qla2xxx/qla_mid.c +++ b/drivers/scsi/qla2xxx/qla_mid.c @@ -361,6 +361,13 @@ qla2x00_do_dpc_vp(scsi_qla_host_t *vha) } } + if (test_bit(PROCESS_PUREX_IOCB, &vha->dpc_flags)) { + if (atomic_read(&vha->loop_state) == LOOP_READY) { + qla24xx_process_purex_list(&vha->purex_list); + clear_bit(PROCESS_PUREX_IOCB, &vha->dpc_flags); + } + } + if (test_bit(FCPORT_UPDATE_NEEDED, &vha->dpc_flags)) { ql_dbg(ql_dbg_dpc, vha, 0x4016, "FCPort update scheduled.\n"); @@ -509,6 +516,9 @@ qla24xx_create_vhost(struct fc_vport *fc_vport) vha->mgmt_svr_loop_id = qla2x00_reserve_mgmt_server_loop_id(vha); vha->dpc_flags = 0L; + ha->dpc_active = 0; + set_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags); + set_bit(REGISTER_FC4_NEEDED, &vha->dpc_flags); /* * To fix the issue of processing a parent's RSCN for the vport before @@ -886,7 +896,8 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options, rsp->rsp_q_out); ret = qla25xx_request_irq(ha, qpair, qpair->msix, - QLA_MSIX_QPAIR_MULTIQ_RSP_Q); + ha->flags.disable_msix_handshake ? + QLA_MSIX_QPAIR_MULTIQ_RSP_Q : QLA_MSIX_QPAIR_MULTIQ_RSP_Q_HS); if (ret) goto que_failed; diff --git a/drivers/scsi/qla2xxx/qla_mr.c b/drivers/scsi/qla2xxx/qla_mr.c index cad1fc2a1b28..df99911b8bb9 100644 --- a/drivers/scsi/qla2xxx/qla_mr.c +++ b/drivers/scsi/qla2xxx/qla_mr.c @@ -53,10 +53,9 @@ qlafx00_mailbox_command(scsi_qla_host_t *vha, struct mbx_cmd_32 *mcp) struct qla_hw_data *ha = vha->hw; scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev); - if (ha->pdev->error_state > pci_channel_io_frozen) { + if (ha->pdev->error_state == pci_channel_io_perm_failure) { ql_log(ql_log_warn, vha, 0x115c, - "error_state is greater than pci_channel_io_frozen, " - "exiting.\n"); + "PCI channel failed permanently, exiting.\n"); return QLA_FUNCTION_TIMEOUT; } @@ -3136,7 +3135,7 @@ qlafx00_start_scsi(srb_t *sp) memset(&lcmd_pkt, 0, REQUEST_ENTRY_SIZE); - lcmd_pkt.handle = MAKE_HANDLE(req->id, sp->handle); + lcmd_pkt.handle = make_handle(req->id, sp->handle); lcmd_pkt.reserved_0 = 0; lcmd_pkt.port_path_ctrl = 0; lcmd_pkt.reserved_1 = 0; @@ -3206,7 +3205,7 @@ qlafx00_tm_iocb(srb_t *sp, struct tsk_mgmt_entry_fx00 *ptm_iocb) memset(&tm_iocb, 0, sizeof(struct tsk_mgmt_entry_fx00)); tm_iocb.entry_type = TSK_MGMT_IOCB_TYPE_FX00; tm_iocb.entry_count = 1; - tm_iocb.handle = cpu_to_le32(MAKE_HANDLE(req->id, sp->handle)); + tm_iocb.handle = cpu_to_le32(make_handle(req->id, sp->handle)); tm_iocb.reserved_0 = 0; tm_iocb.tgt_id = cpu_to_le16(sp->fcport->tgt_id); tm_iocb.control_flags = cpu_to_le32(fxio->u.tmf.flags); @@ -3232,9 +3231,9 @@ qlafx00_abort_iocb(srb_t *sp, struct abort_iocb_entry_fx00 *pabt_iocb) memset(&abt_iocb, 0, sizeof(struct abort_iocb_entry_fx00)); abt_iocb.entry_type = ABORT_IOCB_TYPE_FX00; abt_iocb.entry_count = 1; - abt_iocb.handle = cpu_to_le32(MAKE_HANDLE(req->id, sp->handle)); + abt_iocb.handle = cpu_to_le32(make_handle(req->id, sp->handle)); abt_iocb.abort_handle = - cpu_to_le32(MAKE_HANDLE(req->id, fxio->u.abt.cmd_hndl)); + cpu_to_le32(make_handle(req->id, fxio->u.abt.cmd_hndl)); abt_iocb.tgt_id_sts = cpu_to_le16(sp->fcport->tgt_id); abt_iocb.req_que_no = cpu_to_le16(req->id); diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c index bfcd02fdf2b8..4886d247df6f 100644 --- a/drivers/scsi/qla2xxx/qla_nvme.c +++ b/drivers/scsi/qla2xxx/qla_nvme.c @@ -413,7 +413,7 @@ static inline int qla2x00_start_nvme_mq(srb_t *sp) req->cnt -= req_cnt; cmd_pkt = (struct cmd_nvme *)req->ring_ptr; - cmd_pkt->handle = MAKE_HANDLE(req->id, handle); + cmd_pkt->handle = make_handle(req->id, handle); /* Zero out remaining portion of packet. */ clr_ptr = (uint32_t *)cmd_pkt + 2; @@ -610,7 +610,6 @@ static void qla_nvme_remoteport_delete(struct nvme_fc_remote_port *rport) } static struct nvme_fc_port_template qla_nvme_fc_transport = { - .module = THIS_MODULE, .localport_delete = qla_nvme_localport_delete, .remoteport_delete = qla_nvme_remoteport_delete, .create_queue = qla_nvme_alloc_queue, diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 7a94e1171c72..d190db5ea7d9 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -113,7 +113,8 @@ module_param(ql2xfdmienable, int, S_IRUGO|S_IWUSR); module_param_named(fdmi, ql2xfdmienable, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(ql2xfdmienable, "Enables FDMI registrations. " - "0 - no FDMI. Default is 1 - perform FDMI."); + "0 - no FDMI registrations. " + "1 - provide FDMI registrations (default)."); #define MAX_Q_DEPTH 64 static int ql2xmaxqdepth = MAX_Q_DEPTH; @@ -122,11 +123,7 @@ MODULE_PARM_DESC(ql2xmaxqdepth, "Maximum queue depth to set for each LUN. " "Default is 64."); -#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" @@ -306,6 +303,22 @@ MODULE_PARM_DESC(ql2xdifbundlinginternalbuffers, "0 (Default). Based on check.\n" "1 Force using internal buffers\n"); +int ql2xsmartsan; +module_param(ql2xsmartsan, int, 0444); +module_param_named(smartsan, ql2xsmartsan, int, 0444); +MODULE_PARM_DESC(ql2xsmartsan, + "Send SmartSAN Management Attributes for FDMI Registration." + " Default is 0 - No SmartSAN registration," + " 1 - Register SmartSAN Management Attributes."); + +int ql2xrdpenable; +module_param(ql2xrdpenable, int, 0444); +module_param_named(rdpenable, ql2xrdpenable, int, 0444); +MODULE_PARM_DESC(ql2xrdpenable, + "Enables RDP responses. " + "0 - no RDP responses (default). " + "1 - provide RDP responses."); + static void qla2x00_clear_drv_active(struct qla_hw_data *); static void qla2x00_free_device(scsi_qla_host_t *); static int qla2xxx_map_queues(struct Scsi_Host *shost); @@ -583,6 +596,9 @@ qla24xx_pci_info_str(struct scsi_qla_host *vha, char *str, size_t str_len) case 3: speed_str = "8.0GT/s"; break; + case 4: + speed_str = "16.0GT/s"; + break; default: speed_str = "<unknown>"; break; @@ -1253,17 +1269,6 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) return SUCCESS; spin_lock_irqsave(qpair->qp_lock_ptr, flags); - if (sp->completed) { - spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); - return SUCCESS; - } - - if (sp->abort || sp->aborted) { - spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); - return FAILED; - } - - sp->abort = 1; sp->comp = ∁ spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); @@ -1688,6 +1693,10 @@ qla2x00_loop_reset(scsi_qla_host_t *vha) return QLA_SUCCESS; } +/* + * The caller must ensure that no completion interrupts will happen + * while this function is in progress. + */ static void qla2x00_abort_srb(struct qla_qpair *qp, srb_t *sp, const int res, unsigned long *flags) __releases(qp->qp_lock_ptr) @@ -1696,10 +1705,13 @@ static void qla2x00_abort_srb(struct qla_qpair *qp, srb_t *sp, const int res, DECLARE_COMPLETION_ONSTACK(comp); scsi_qla_host_t *vha = qp->vha; struct qla_hw_data *ha = vha->hw; + struct scsi_cmnd *cmd = GET_CMD_SP(sp); int rval; bool ret_cmd; uint32_t ratov_j; + lockdep_assert_held(qp->qp_lock_ptr); + if (qla2x00_chip_is_down(vha)) { sp->done(sp, res); return; @@ -1715,7 +1727,6 @@ static void qla2x00_abort_srb(struct qla_qpair *qp, srb_t *sp, const int res, } sp->comp = ∁ - sp->abort = 1; spin_unlock_irqrestore(qp->qp_lock_ptr, *flags); rval = ha->isp_ops->abort_command(sp); @@ -1739,13 +1750,17 @@ static void qla2x00_abort_srb(struct qla_qpair *qp, srb_t *sp, const int res, } spin_lock_irqsave(qp->qp_lock_ptr, *flags); - if (ret_cmd && (!sp->completed || !sp->aborted)) + if (ret_cmd && blk_mq_request_started(cmd->request)) sp->done(sp, res); } else { sp->done(sp, res); } } +/* + * The caller must ensure that no completion interrupts will happen + * while this function is in progress. + */ static void __qla2x00_abort_all_cmds(struct qla_qpair *qp, int res) { @@ -1792,6 +1807,10 @@ __qla2x00_abort_all_cmds(struct qla_qpair *qp, int res) spin_unlock_irqrestore(qp->qp_lock_ptr, flags); } +/* + * The caller must ensure that no completion interrupts will happen + * while this function is in progress. + */ void qla2x00_abort_all_cmds(scsi_qla_host_t *vha, int res) { @@ -2285,7 +2304,7 @@ static struct isp_operations qla81xx_isp_ops = { .config_rings = qla24xx_config_rings, .reset_adapter = qla24xx_reset_adapter, .nvram_config = qla81xx_nvram_config, - .update_fw_options = qla81xx_update_fw_options, + .update_fw_options = qla24xx_update_fw_options, .load_risc = qla81xx_load_risc, .pci_info_str = qla24xx_pci_info_str, .fw_version_str = qla24xx_fw_version_str, @@ -2402,7 +2421,7 @@ static struct isp_operations qla83xx_isp_ops = { .config_rings = qla24xx_config_rings, .reset_adapter = qla24xx_reset_adapter, .nvram_config = qla81xx_nvram_config, - .update_fw_options = qla81xx_update_fw_options, + .update_fw_options = qla24xx_update_fw_options, .load_risc = qla81xx_load_risc, .pci_info_str = qla24xx_pci_info_str, .fw_version_str = qla24xx_fw_version_str, @@ -3439,13 +3458,6 @@ skip_dpc: if (test_bit(UNLOADING, &base_vha->dpc_flags)) return -ENODEV; - if (ha->flags.detected_lr_sfp) { - ql_log(ql_log_info, base_vha, 0xffff, - "Reset chip to pick up LR SFP setting\n"); - set_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags); - qla2xxx_wake_dpc(base_vha); - } - return 0; probe_failed: @@ -3806,6 +3818,20 @@ qla2x00_remove_one(struct pci_dev *pdev) pci_disable_device(pdev); } +static inline void +qla24xx_free_purex_list(struct purex_list *list) +{ + struct list_head *item, *next; + ulong flags; + + spin_lock_irqsave(&list->lock, flags); + list_for_each_safe(item, next, &list->head) { + list_del(item); + kfree(list_entry(item, struct purex_item, list)); + } + spin_unlock_irqrestore(&list->lock, flags); +} + static void qla2x00_free_device(scsi_qla_host_t *vha) { @@ -3838,6 +3864,8 @@ qla2x00_free_device(scsi_qla_host_t *vha) } + qla24xx_free_purex_list(&vha->purex_list); + qla2x00_mem_free(ha); qla82xx_md_free(vha); @@ -3907,19 +3935,6 @@ void qla2x00_mark_device_lost(scsi_qla_host_t *vha, fc_port_t *fcport, set_bit(RELOGIN_NEEDED, &vha->dpc_flags); } -/* - * qla2x00_mark_all_devices_lost - * Updates fcport state when device goes offline. - * - * Input: - * ha = adapter block pointer. - * fcport = port structure pointer. - * - * Return: - * None. - * - * Context: - */ void qla2x00_mark_all_devices_lost(scsi_qla_host_t *vha) { @@ -3931,16 +3946,6 @@ qla2x00_mark_all_devices_lost(scsi_qla_host_t *vha) list_for_each_entry(fcport, &vha->vp_fcports, list) { fcport->scan_state = 0; qlt_schedule_sess_for_deletion(fcport); - - if (vha->vp_idx != 0 && vha->vp_idx != fcport->vha->vp_idx) - continue; - - /* - * No point in marking the device as lost, if the device is - * already DEAD. - */ - if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD) - continue; } } @@ -4811,6 +4816,9 @@ struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht, INIT_LIST_HEAD(&vha->gpnid_list); INIT_WORK(&vha->iocb_work, qla2x00_iocb_work_fn); + INIT_LIST_HEAD(&vha->purex_list.head); + spin_lock_init(&vha->purex_list.lock); + spin_lock_init(&vha->work_lock); spin_lock_init(&vha->cmd_list_lock); init_waitqueue_head(&vha->fcport_waitQ); @@ -5168,9 +5176,8 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e) fcport->n2n_flag = 1; } fcport->fw_login_state = 0; - /* - * wait link init done before sending login - */ + + schedule_delayed_work(&vha->scan.scan_work, 5); } else { qla24xx_fcport_handle_login(vha, fcport); } @@ -5731,6 +5738,583 @@ retry_lock: return; } +static bool +qla25xx_rdp_rsp_reduce_size(struct scsi_qla_host *vha, + struct purex_entry_24xx *purex) +{ + char fwstr[16]; + u32 sid = purex->s_id[2] << 16 | purex->s_id[1] << 8 | purex->s_id[0]; + struct port_database_24xx *pdb; + + /* Domain Controller is always logged-out. */ + /* if RDP request is not from Domain Controller: */ + if (sid != 0xfffc01) + return false; + + ql_dbg(ql_dbg_init, vha, 0x0181, "%s: s_id=%#x\n", __func__, sid); + + pdb = kzalloc(sizeof(*pdb), GFP_KERNEL); + if (!pdb) { + ql_dbg(ql_dbg_init, vha, 0x0181, + "%s: Failed allocate pdb\n", __func__); + } else if (qla24xx_get_port_database(vha, purex->nport_handle, pdb)) { + ql_dbg(ql_dbg_init, vha, 0x0181, + "%s: Failed get pdb sid=%x\n", __func__, sid); + } else if (pdb->current_login_state != PDS_PLOGI_COMPLETE && + pdb->current_login_state != PDS_PRLI_COMPLETE) { + ql_dbg(ql_dbg_init, vha, 0x0181, + "%s: Port not logged in sid=%#x\n", __func__, sid); + } else { + /* RDP request is from logged in port */ + kfree(pdb); + return false; + } + kfree(pdb); + + vha->hw->isp_ops->fw_version_str(vha, fwstr, sizeof(fwstr)); + fwstr[strcspn(fwstr, " ")] = 0; + /* if FW version allows RDP response length upto 2048 bytes: */ + if (strcmp(fwstr, "8.09.00") > 0 || strcmp(fwstr, "8.05.65") == 0) + return false; + + ql_dbg(ql_dbg_init, vha, 0x0181, "%s: fw=%s\n", __func__, fwstr); + + /* RDP response length is to be reduced to maximum 256 bytes */ + return true; +} + +static uint +qla25xx_rdp_port_speed_capability(struct qla_hw_data *ha) +{ + if (IS_CNA_CAPABLE(ha)) + return RDP_PORT_SPEED_10GB; + + if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) { + unsigned int speeds = 0; + + if (ha->max_supported_speed == 2) { + if (ha->min_supported_speed <= 6) + speeds |= RDP_PORT_SPEED_64GB; + } + + if (ha->max_supported_speed == 2 || + ha->max_supported_speed == 1) { + if (ha->min_supported_speed <= 5) + speeds |= RDP_PORT_SPEED_32GB; + } + + if (ha->max_supported_speed == 2 || + ha->max_supported_speed == 1 || + ha->max_supported_speed == 0) { + if (ha->min_supported_speed <= 4) + speeds |= RDP_PORT_SPEED_16GB; + } + + if (ha->max_supported_speed == 1 || + ha->max_supported_speed == 0) { + if (ha->min_supported_speed <= 3) + speeds |= RDP_PORT_SPEED_8GB; + } + + if (ha->max_supported_speed == 0) { + if (ha->min_supported_speed <= 2) + speeds |= RDP_PORT_SPEED_4GB; + } + + return speeds; + } + + if (IS_QLA2031(ha)) + return RDP_PORT_SPEED_16GB|RDP_PORT_SPEED_8GB| + RDP_PORT_SPEED_4GB; + + if (IS_QLA25XX(ha)) + return RDP_PORT_SPEED_8GB|RDP_PORT_SPEED_4GB| + RDP_PORT_SPEED_2GB|RDP_PORT_SPEED_1GB; + + if (IS_QLA24XX_TYPE(ha)) + return RDP_PORT_SPEED_4GB|RDP_PORT_SPEED_2GB| + RDP_PORT_SPEED_1GB; + + if (IS_QLA23XX(ha)) + return RDP_PORT_SPEED_2GB|RDP_PORT_SPEED_1GB; + + return RDP_PORT_SPEED_1GB; +} + +static uint +qla25xx_rdp_port_speed_currently(struct qla_hw_data *ha) +{ + switch (ha->link_data_rate) { + case PORT_SPEED_1GB: + return RDP_PORT_SPEED_1GB; + + case PORT_SPEED_2GB: + return RDP_PORT_SPEED_2GB; + + case PORT_SPEED_4GB: + return RDP_PORT_SPEED_4GB; + + case PORT_SPEED_8GB: + return RDP_PORT_SPEED_8GB; + + case PORT_SPEED_10GB: + return RDP_PORT_SPEED_10GB; + + case PORT_SPEED_16GB: + return RDP_PORT_SPEED_16GB; + + case PORT_SPEED_32GB: + return RDP_PORT_SPEED_32GB; + + case PORT_SPEED_64GB: + return RDP_PORT_SPEED_64GB; + + default: + return RDP_PORT_SPEED_UNKNOWN; + } +} + +/* + * Function Name: qla24xx_process_purex_iocb + * + * Description: + * Prepare a RDP response and send to Fabric switch + * + * PARAMETERS: + * vha: SCSI qla host + * purex: RDP request received by HBA + */ +void qla24xx_process_purex_rdp(struct scsi_qla_host *vha, void *pkt) +{ + struct qla_hw_data *ha = vha->hw; + struct purex_entry_24xx *purex = pkt; + dma_addr_t rsp_els_dma; + dma_addr_t rsp_payload_dma; + dma_addr_t stat_dma; + dma_addr_t bbc_dma; + dma_addr_t sfp_dma; + struct els_entry_24xx *rsp_els = NULL; + struct rdp_rsp_payload *rsp_payload = NULL; + struct link_statistics *stat = NULL; + struct buffer_credit_24xx *bbc = NULL; + uint8_t *sfp = NULL; + uint16_t sfp_flags = 0; + uint rsp_payload_length = sizeof(*rsp_payload); + int rval; + + ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x0180, + "%s: Enter\n", __func__); + + ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x0181, + "-------- ELS REQ -------\n"); + ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha, 0x0182, + (void *)purex, sizeof(*purex)); + + if (qla25xx_rdp_rsp_reduce_size(vha, purex)) { + rsp_payload_length = + offsetof(typeof(*rsp_payload), optical_elmt_desc); + ql_dbg(ql_dbg_init, vha, 0x0181, + "Reducing RSP payload length to %u bytes...\n", + rsp_payload_length); + } + + rsp_els = dma_alloc_coherent(&ha->pdev->dev, sizeof(*rsp_els), + &rsp_els_dma, GFP_KERNEL); + if (!rsp_els) { + ql_log(ql_log_warn, vha, 0x0183, + "Failed allocate dma buffer ELS RSP.\n"); + goto dealloc; + } + + rsp_payload = dma_alloc_coherent(&ha->pdev->dev, sizeof(*rsp_payload), + &rsp_payload_dma, GFP_KERNEL); + if (!rsp_payload) { + ql_log(ql_log_warn, vha, 0x0184, + "Failed allocate dma buffer ELS RSP payload.\n"); + goto dealloc; + } + + sfp = dma_alloc_coherent(&ha->pdev->dev, SFP_RTDI_LEN, + &sfp_dma, GFP_KERNEL); + + stat = dma_alloc_coherent(&ha->pdev->dev, sizeof(*stat), + &stat_dma, GFP_KERNEL); + + bbc = dma_alloc_coherent(&ha->pdev->dev, sizeof(*bbc), + &bbc_dma, GFP_KERNEL); + + /* Prepare Response IOCB */ + rsp_els->entry_type = ELS_IOCB_TYPE; + rsp_els->entry_count = 1; + rsp_els->sys_define = 0; + rsp_els->entry_status = 0; + rsp_els->handle = 0; + rsp_els->nport_handle = purex->nport_handle; + rsp_els->tx_dsd_count = 1; + rsp_els->vp_index = purex->vp_idx; + rsp_els->sof_type = EST_SOFI3; + rsp_els->rx_xchg_address = purex->rx_xchg_addr; + rsp_els->rx_dsd_count = 0; + rsp_els->opcode = purex->els_frame_payload[0]; + + rsp_els->d_id[0] = purex->s_id[0]; + rsp_els->d_id[1] = purex->s_id[1]; + rsp_els->d_id[2] = purex->s_id[2]; + + rsp_els->control_flags = EPD_ELS_ACC; + rsp_els->rx_byte_count = 0; + rsp_els->tx_byte_count = cpu_to_le32(rsp_payload_length); + + put_unaligned_le64(rsp_payload_dma, &rsp_els->tx_address); + rsp_els->tx_len = rsp_els->tx_byte_count; + + rsp_els->rx_address = 0; + rsp_els->rx_len = 0; + + /* Prepare Response Payload */ + rsp_payload->hdr.cmd = cpu_to_be32(0x2 << 24); /* LS_ACC */ + rsp_payload->hdr.len = cpu_to_be32( + rsp_els->tx_byte_count - sizeof(rsp_payload->hdr)); + + /* Link service Request Info Descriptor */ + rsp_payload->ls_req_info_desc.desc_tag = cpu_to_be32(0x1); + rsp_payload->ls_req_info_desc.desc_len = + cpu_to_be32(RDP_DESC_LEN(rsp_payload->ls_req_info_desc)); + rsp_payload->ls_req_info_desc.req_payload_word_0 = + cpu_to_be32p((uint32_t *)purex->els_frame_payload); + + /* Link service Request Info Descriptor 2 */ + rsp_payload->ls_req_info_desc2.desc_tag = cpu_to_be32(0x1); + rsp_payload->ls_req_info_desc2.desc_len = + cpu_to_be32(RDP_DESC_LEN(rsp_payload->ls_req_info_desc2)); + rsp_payload->ls_req_info_desc2.req_payload_word_0 = + cpu_to_be32p((uint32_t *)purex->els_frame_payload); + + + rsp_payload->sfp_diag_desc.desc_tag = cpu_to_be32(0x10000); + rsp_payload->sfp_diag_desc.desc_len = + cpu_to_be32(RDP_DESC_LEN(rsp_payload->sfp_diag_desc)); + + if (sfp) { + /* SFP Flags */ + memset(sfp, 0, SFP_RTDI_LEN); + rval = qla2x00_read_sfp(vha, sfp_dma, sfp, 0xa0, 0x7, 2, 0); + if (!rval) { + /* SFP Flags bits 3-0: Port Tx Laser Type */ + if (sfp[0] & BIT_2 || sfp[1] & (BIT_6|BIT_5)) + sfp_flags |= BIT_0; /* short wave */ + else if (sfp[0] & BIT_1) + sfp_flags |= BIT_1; /* long wave 1310nm */ + else if (sfp[1] & BIT_4) + sfp_flags |= BIT_1|BIT_0; /* long wave 1550nm */ + } + + /* SFP Type */ + memset(sfp, 0, SFP_RTDI_LEN); + rval = qla2x00_read_sfp(vha, sfp_dma, sfp, 0xa0, 0x0, 1, 0); + if (!rval) { + sfp_flags |= BIT_4; /* optical */ + if (sfp[0] == 0x3) + sfp_flags |= BIT_6; /* sfp+ */ + } + + rsp_payload->sfp_diag_desc.sfp_flags = cpu_to_be16(sfp_flags); + + /* SFP Diagnostics */ + memset(sfp, 0, SFP_RTDI_LEN); + rval = qla2x00_read_sfp(vha, sfp_dma, sfp, 0xa2, 0x60, 10, 0); + if (!rval) { + uint16_t *trx = (void *)sfp; /* already be16 */ + rsp_payload->sfp_diag_desc.temperature = trx[0]; + rsp_payload->sfp_diag_desc.vcc = trx[1]; + rsp_payload->sfp_diag_desc.tx_bias = trx[2]; + rsp_payload->sfp_diag_desc.tx_power = trx[3]; + rsp_payload->sfp_diag_desc.rx_power = trx[4]; + } + } + + /* Port Speed Descriptor */ + rsp_payload->port_speed_desc.desc_tag = cpu_to_be32(0x10001); + rsp_payload->port_speed_desc.desc_len = + cpu_to_be32(RDP_DESC_LEN(rsp_payload->port_speed_desc)); + rsp_payload->port_speed_desc.speed_capab = cpu_to_be16( + qla25xx_rdp_port_speed_capability(ha)); + rsp_payload->port_speed_desc.operating_speed = cpu_to_be16( + qla25xx_rdp_port_speed_currently(ha)); + + /* Link Error Status Descriptor */ + rsp_payload->ls_err_desc.desc_tag = cpu_to_be32(0x10002); + rsp_payload->ls_err_desc.desc_len = + cpu_to_be32(RDP_DESC_LEN(rsp_payload->ls_err_desc)); + + if (stat) { + rval = qla24xx_get_isp_stats(vha, stat, stat_dma, 0); + if (!rval) { + rsp_payload->ls_err_desc.link_fail_cnt = + cpu_to_be32(stat->link_fail_cnt); + rsp_payload->ls_err_desc.loss_sync_cnt = + cpu_to_be32(stat->loss_sync_cnt); + rsp_payload->ls_err_desc.loss_sig_cnt = + cpu_to_be32(stat->loss_sig_cnt); + rsp_payload->ls_err_desc.prim_seq_err_cnt = + cpu_to_be32(stat->prim_seq_err_cnt); + rsp_payload->ls_err_desc.inval_xmit_word_cnt = + cpu_to_be32(stat->inval_xmit_word_cnt); + rsp_payload->ls_err_desc.inval_crc_cnt = + cpu_to_be32(stat->inval_crc_cnt); + rsp_payload->ls_err_desc.pn_port_phy_type |= BIT_6; + } + } + + /* Portname Descriptor */ + rsp_payload->port_name_diag_desc.desc_tag = cpu_to_be32(0x10003); + rsp_payload->port_name_diag_desc.desc_len = + cpu_to_be32(RDP_DESC_LEN(rsp_payload->port_name_diag_desc)); + memcpy(rsp_payload->port_name_diag_desc.WWNN, + vha->node_name, + sizeof(rsp_payload->port_name_diag_desc.WWNN)); + memcpy(rsp_payload->port_name_diag_desc.WWPN, + vha->port_name, + sizeof(rsp_payload->port_name_diag_desc.WWPN)); + + /* F-Port Portname Descriptor */ + rsp_payload->port_name_direct_desc.desc_tag = cpu_to_be32(0x10003); + rsp_payload->port_name_direct_desc.desc_len = + cpu_to_be32(RDP_DESC_LEN(rsp_payload->port_name_direct_desc)); + memcpy(rsp_payload->port_name_direct_desc.WWNN, + vha->fabric_node_name, + sizeof(rsp_payload->port_name_direct_desc.WWNN)); + memcpy(rsp_payload->port_name_direct_desc.WWPN, + vha->fabric_port_name, + sizeof(rsp_payload->port_name_direct_desc.WWPN)); + + /* Bufer Credit Descriptor */ + rsp_payload->buffer_credit_desc.desc_tag = cpu_to_be32(0x10006); + rsp_payload->buffer_credit_desc.desc_len = + cpu_to_be32(RDP_DESC_LEN(rsp_payload->buffer_credit_desc)); + rsp_payload->buffer_credit_desc.fcport_b2b = 0; + rsp_payload->buffer_credit_desc.attached_fcport_b2b = cpu_to_be32(0); + rsp_payload->buffer_credit_desc.fcport_rtt = cpu_to_be32(0); + + if (bbc) { + memset(bbc, 0, sizeof(*bbc)); + rval = qla24xx_get_buffer_credits(vha, bbc, bbc_dma); + if (!rval) { + rsp_payload->buffer_credit_desc.fcport_b2b = + cpu_to_be32(LSW(bbc->parameter[0])); + } + } + + if (rsp_payload_length < sizeof(*rsp_payload)) + goto send; + + /* Optical Element Descriptor, Temperature */ + rsp_payload->optical_elmt_desc[0].desc_tag = cpu_to_be32(0x10007); + rsp_payload->optical_elmt_desc[0].desc_len = + cpu_to_be32(RDP_DESC_LEN(*rsp_payload->optical_elmt_desc)); + /* Optical Element Descriptor, Voltage */ + rsp_payload->optical_elmt_desc[1].desc_tag = cpu_to_be32(0x10007); + rsp_payload->optical_elmt_desc[1].desc_len = + cpu_to_be32(RDP_DESC_LEN(*rsp_payload->optical_elmt_desc)); + /* Optical Element Descriptor, Tx Bias Current */ + rsp_payload->optical_elmt_desc[2].desc_tag = cpu_to_be32(0x10007); + rsp_payload->optical_elmt_desc[2].desc_len = + cpu_to_be32(RDP_DESC_LEN(*rsp_payload->optical_elmt_desc)); + /* Optical Element Descriptor, Tx Power */ + rsp_payload->optical_elmt_desc[3].desc_tag = cpu_to_be32(0x10007); + rsp_payload->optical_elmt_desc[3].desc_len = + cpu_to_be32(RDP_DESC_LEN(*rsp_payload->optical_elmt_desc)); + /* Optical Element Descriptor, Rx Power */ + rsp_payload->optical_elmt_desc[4].desc_tag = cpu_to_be32(0x10007); + rsp_payload->optical_elmt_desc[4].desc_len = + cpu_to_be32(RDP_DESC_LEN(*rsp_payload->optical_elmt_desc)); + + if (sfp) { + memset(sfp, 0, SFP_RTDI_LEN); + rval = qla2x00_read_sfp(vha, sfp_dma, sfp, 0xa2, 0, 64, 0); + if (!rval) { + uint16_t *trx = (void *)sfp; /* already be16 */ + + /* Optical Element Descriptor, Temperature */ + rsp_payload->optical_elmt_desc[0].high_alarm = trx[0]; + rsp_payload->optical_elmt_desc[0].low_alarm = trx[1]; + rsp_payload->optical_elmt_desc[0].high_warn = trx[2]; + rsp_payload->optical_elmt_desc[0].low_warn = trx[3]; + rsp_payload->optical_elmt_desc[0].element_flags = + cpu_to_be32(1 << 28); + + /* Optical Element Descriptor, Voltage */ + rsp_payload->optical_elmt_desc[1].high_alarm = trx[4]; + rsp_payload->optical_elmt_desc[1].low_alarm = trx[5]; + rsp_payload->optical_elmt_desc[1].high_warn = trx[6]; + rsp_payload->optical_elmt_desc[1].low_warn = trx[7]; + rsp_payload->optical_elmt_desc[1].element_flags = + cpu_to_be32(2 << 28); + + /* Optical Element Descriptor, Tx Bias Current */ + rsp_payload->optical_elmt_desc[2].high_alarm = trx[8]; + rsp_payload->optical_elmt_desc[2].low_alarm = trx[9]; + rsp_payload->optical_elmt_desc[2].high_warn = trx[10]; + rsp_payload->optical_elmt_desc[2].low_warn = trx[11]; + rsp_payload->optical_elmt_desc[2].element_flags = + cpu_to_be32(3 << 28); + + /* Optical Element Descriptor, Tx Power */ + rsp_payload->optical_elmt_desc[3].high_alarm = trx[12]; + rsp_payload->optical_elmt_desc[3].low_alarm = trx[13]; + rsp_payload->optical_elmt_desc[3].high_warn = trx[14]; + rsp_payload->optical_elmt_desc[3].low_warn = trx[15]; + rsp_payload->optical_elmt_desc[3].element_flags = + cpu_to_be32(4 << 28); + + /* Optical Element Descriptor, Rx Power */ + rsp_payload->optical_elmt_desc[4].high_alarm = trx[16]; + rsp_payload->optical_elmt_desc[4].low_alarm = trx[17]; + rsp_payload->optical_elmt_desc[4].high_warn = trx[18]; + rsp_payload->optical_elmt_desc[4].low_warn = trx[19]; + rsp_payload->optical_elmt_desc[4].element_flags = + cpu_to_be32(5 << 28); + } + + memset(sfp, 0, SFP_RTDI_LEN); + rval = qla2x00_read_sfp(vha, sfp_dma, sfp, 0xa2, 112, 64, 0); + if (!rval) { + /* Temperature high/low alarm/warning */ + rsp_payload->optical_elmt_desc[0].element_flags |= + cpu_to_be32( + (sfp[0] >> 7 & 1) << 3 | + (sfp[0] >> 6 & 1) << 2 | + (sfp[4] >> 7 & 1) << 1 | + (sfp[4] >> 6 & 1) << 0); + + /* Voltage high/low alarm/warning */ + rsp_payload->optical_elmt_desc[1].element_flags |= + cpu_to_be32( + (sfp[0] >> 5 & 1) << 3 | + (sfp[0] >> 4 & 1) << 2 | + (sfp[4] >> 5 & 1) << 1 | + (sfp[4] >> 4 & 1) << 0); + + /* Tx Bias Current high/low alarm/warning */ + rsp_payload->optical_elmt_desc[2].element_flags |= + cpu_to_be32( + (sfp[0] >> 3 & 1) << 3 | + (sfp[0] >> 2 & 1) << 2 | + (sfp[4] >> 3 & 1) << 1 | + (sfp[4] >> 2 & 1) << 0); + + /* Tx Power high/low alarm/warning */ + rsp_payload->optical_elmt_desc[3].element_flags |= + cpu_to_be32( + (sfp[0] >> 1 & 1) << 3 | + (sfp[0] >> 0 & 1) << 2 | + (sfp[4] >> 1 & 1) << 1 | + (sfp[4] >> 0 & 1) << 0); + + /* Rx Power high/low alarm/warning */ + rsp_payload->optical_elmt_desc[4].element_flags |= + cpu_to_be32( + (sfp[1] >> 7 & 1) << 3 | + (sfp[1] >> 6 & 1) << 2 | + (sfp[5] >> 7 & 1) << 1 | + (sfp[5] >> 6 & 1) << 0); + } + } + + /* Optical Product Data Descriptor */ + rsp_payload->optical_prod_desc.desc_tag = cpu_to_be32(0x10008); + rsp_payload->optical_prod_desc.desc_len = + cpu_to_be32(RDP_DESC_LEN(rsp_payload->optical_prod_desc)); + + if (sfp) { + memset(sfp, 0, SFP_RTDI_LEN); + rval = qla2x00_read_sfp(vha, sfp_dma, sfp, 0xa0, 20, 64, 0); + if (!rval) { + memcpy(rsp_payload->optical_prod_desc.vendor_name, + sfp + 0, + sizeof(rsp_payload->optical_prod_desc.vendor_name)); + memcpy(rsp_payload->optical_prod_desc.part_number, + sfp + 20, + sizeof(rsp_payload->optical_prod_desc.part_number)); + memcpy(rsp_payload->optical_prod_desc.revision, + sfp + 36, + sizeof(rsp_payload->optical_prod_desc.revision)); + memcpy(rsp_payload->optical_prod_desc.serial_number, + sfp + 48, + sizeof(rsp_payload->optical_prod_desc.serial_number)); + } + + memset(sfp, 0, SFP_RTDI_LEN); + rval = qla2x00_read_sfp(vha, sfp_dma, sfp, 0xa0, 84, 8, 0); + if (!rval) { + memcpy(rsp_payload->optical_prod_desc.date, + sfp + 0, + sizeof(rsp_payload->optical_prod_desc.date)); + } + } + +send: + ql_dbg(ql_dbg_init, vha, 0x0183, + "Sending ELS Response to RDP Request...\n"); + ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x0184, + "-------- ELS RSP -------\n"); + ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha, 0x0185, + (void *)rsp_els, sizeof(*rsp_els)); + ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x0186, + "-------- ELS RSP PAYLOAD -------\n"); + ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha, 0x0187, + (void *)rsp_payload, rsp_payload_length); + + rval = qla2x00_issue_iocb(vha, rsp_els, rsp_els_dma, 0); + + if (rval) { + ql_log(ql_log_warn, vha, 0x0188, + "%s: iocb failed to execute -> %x\n", __func__, rval); + } else if (rsp_els->comp_status) { + ql_log(ql_log_warn, vha, 0x0189, + "%s: iocb failed to complete -> completion=%#x subcode=(%#x,%#x)\n", + __func__, rsp_els->comp_status, + rsp_els->error_subcode_1, rsp_els->error_subcode_2); + } else { + ql_dbg(ql_dbg_init, vha, 0x018a, "%s: done.\n", __func__); + } + +dealloc: + if (bbc) + dma_free_coherent(&ha->pdev->dev, sizeof(*bbc), + bbc, bbc_dma); + if (stat) + dma_free_coherent(&ha->pdev->dev, sizeof(*stat), + stat, stat_dma); + if (sfp) + dma_free_coherent(&ha->pdev->dev, SFP_RTDI_LEN, + sfp, sfp_dma); + if (rsp_payload) + dma_free_coherent(&ha->pdev->dev, sizeof(*rsp_payload), + rsp_payload, rsp_payload_dma); + if (rsp_els) + dma_free_coherent(&ha->pdev->dev, sizeof(*rsp_els), + rsp_els, rsp_els_dma); +} + +void qla24xx_process_purex_list(struct purex_list *list) +{ + struct list_head head = LIST_HEAD_INIT(head); + struct purex_item *item, *next; + ulong flags; + + spin_lock_irqsave(&list->lock, flags); + list_splice_init(&list->head, &head); + spin_unlock_irqrestore(&list->lock, flags); + + list_for_each_entry_safe(item, next, &head, list) { + list_del(&item->list); + item->process_item(item->vha, &item->iocb); + kfree(item); + } +} + void qla83xx_idc_unlock(scsi_qla_host_t *base_vha, uint16_t requester_id) { @@ -6254,13 +6838,14 @@ qla2x00_do_dpc(void *data) } if (test_and_clear_bit(DETECT_SFP_CHANGE, - &base_vha->dpc_flags) && - !test_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags)) { - qla24xx_detect_sfp(base_vha); - - if (ha->flags.detected_lr_sfp != - ha->flags.using_lr_setting) - set_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags); + &base_vha->dpc_flags)) { + /* Semantic: + * - NO-OP -- await next ISP-ABORT. Preferred method + * to minimize disruptions that will occur + * when a forced chip-reset occurs. + * - Force -- ISP-ABORT scheduled. + */ + /* set_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags); */ } if (test_and_clear_bit @@ -6301,6 +6886,15 @@ qla2x00_do_dpc(void *data) } } + if (test_bit(PROCESS_PUREX_IOCB, &base_vha->dpc_flags)) { + if (atomic_read(&base_vha->loop_state) == LOOP_READY) { + qla24xx_process_purex_list + (&base_vha->purex_list); + clear_bit(PROCESS_PUREX_IOCB, + &base_vha->dpc_flags); + } + } + if (test_and_clear_bit(FCPORT_UPDATE_NEEDED, &base_vha->dpc_flags)) { qla2x00_update_fcports(base_vha); @@ -6692,7 +7286,8 @@ qla2x00_timer(struct timer_list *t) test_bit(ISP_UNRECOVERABLE, &vha->dpc_flags) || test_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags) || test_bit(VP_DPC_NEEDED, &vha->dpc_flags) || - test_bit(RELOGIN_NEEDED, &vha->dpc_flags))) { + test_bit(RELOGIN_NEEDED, &vha->dpc_flags) || + test_bit(PROCESS_PUREX_IOCB, &vha->dpc_flags))) { ql_dbg(ql_dbg_timer, vha, 0x600b, "isp_abort_needed=%d loop_resync_needed=%d " "fcport_update_needed=%d start_dpc=%d " @@ -6705,12 +7300,13 @@ qla2x00_timer(struct timer_list *t) ql_dbg(ql_dbg_timer, vha, 0x600c, "beacon_blink_needed=%d isp_unrecoverable=%d " "fcoe_ctx_reset_needed=%d vp_dpc_needed=%d " - "relogin_needed=%d.\n", + "relogin_needed=%d, Process_purex_iocb=%d.\n", test_bit(BEACON_BLINK_NEEDED, &vha->dpc_flags), test_bit(ISP_UNRECOVERABLE, &vha->dpc_flags), test_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags), test_bit(VP_DPC_NEEDED, &vha->dpc_flags), - test_bit(RELOGIN_NEEDED, &vha->dpc_flags)); + test_bit(RELOGIN_NEEDED, &vha->dpc_flags), + test_bit(PROCESS_PUREX_IOCB, &vha->dpc_flags)); qla2xxx_wake_dpc(vha); } diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c index 76a38bf86cbc..3da79ee1d88e 100644 --- a/drivers/scsi/qla2xxx/qla_sup.c +++ b/drivers/scsi/qla2xxx/qla_sup.c @@ -2683,7 +2683,7 @@ qla28xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr, uint32_t sec_mask, rest_addr, fdata; void *optrom = NULL; dma_addr_t optrom_dma; - int rval; + int rval, ret; struct secure_flash_update_block *sfub; dma_addr_t sfub_dma; uint32_t offset = faddr << 2; @@ -2939,11 +2939,12 @@ qla28xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr, write_protect: ql_log(ql_log_warn + ql_dbg_verbose, vha, 0x7095, "Protect flash...\n"); - rval = qla24xx_protect_flash(vha); - if (rval) { + ret = qla24xx_protect_flash(vha); + if (ret) { qla81xx_fac_semaphore_access(vha, FAC_SEMAPHORE_UNLOCK); ql_log(ql_log_warn, vha, 0x7099, "Failed protect flash\n"); + rval = QLA_COMMAND_ERROR; } if (reset_to_rom == true) { @@ -2951,10 +2952,12 @@ write_protect: set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); qla2xxx_wake_dpc(vha); - rval = qla2x00_wait_for_hba_online(vha); - if (rval != QLA_SUCCESS) + ret = qla2x00_wait_for_hba_online(vha); + if (ret != QLA_SUCCESS) { ql_log(ql_log_warn, vha, 0xffff, "Adapter did not come out of reset\n"); + rval = QLA_COMMAND_ERROR; + } } done: diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index 70081b395fb2..622e7337affc 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -27,8 +27,6 @@ #include <scsi/scsi.h> #include <scsi/scsi_host.h> #include <scsi/scsi_tcq.h> -#include <target/target_core_base.h> -#include <target/target_core_fabric.h> #include "qla_def.h" #include "qla_target.h" @@ -1760,7 +1758,7 @@ static int qlt_build_abts_resp_iocb(struct qla_tgt_mgmt_cmd *mcmd) qpair->req->outstanding_cmds[h] = (srb_t *)mcmd; } - resp->handle = MAKE_HANDLE(qpair->req->id, h); + resp->handle = make_handle(qpair->req->id, h); resp->entry_type = ABTS_RESP_24XX; resp->entry_count = 1; resp->nport_handle = abts->nport_handle; @@ -2582,7 +2580,7 @@ static int qlt_24xx_build_ctio_pkt(struct qla_qpair *qpair, } else qpair->req->outstanding_cmds[h] = (srb_t *)prm->cmd; - pkt->handle = MAKE_HANDLE(qpair->req->id, h); + 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); @@ -3095,7 +3093,7 @@ qlt_build_ctio_crc2_pkt(struct qla_qpair *qpair, struct qla_tgt_prm *prm) } else qpair->req->outstanding_cmds[h] = (srb_t *)prm->cmd; - pkt->handle = MAKE_HANDLE(qpair->req->id, h); + 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); @@ -3816,7 +3814,7 @@ void qlt_free_cmd(struct qla_tgt_cmd *cmd) return; } cmd->jiffies_at_free = get_jiffies_64(); - target_free_tag(sess->se_sess, &cmd->se_cmd); + cmd->vha->hw->tgt.tgt_ops->rel_cmd(cmd); } EXPORT_SYMBOL(qlt_free_cmd); @@ -4150,7 +4148,7 @@ out_term: qlt_send_term_exchange(qpair, NULL, &cmd->atio, 1, 0); qlt_decr_num_pend_cmds(vha); - target_free_tag(sess->se_sess, &cmd->se_cmd); + cmd->vha->hw->tgt.tgt_ops->rel_cmd(cmd); spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); ha->tgt.tgt_ops->put_sess(sess); @@ -4277,24 +4275,18 @@ static struct qla_tgt_cmd *qlt_get_tag(scsi_qla_host_t *vha, struct fc_port *sess, struct atio_from_isp *atio) { - struct se_session *se_sess = sess->se_sess; struct qla_tgt_cmd *cmd; - int tag, cpu; - tag = sbitmap_queue_get(&se_sess->sess_tag_pool, &cpu); - if (tag < 0) + cmd = vha->hw->tgt.tgt_ops->get_cmd(sess); + if (!cmd) return NULL; - 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; qlt_incr_num_pend_cmds(vha); cmd->vha = vha; - cmd->se_cmd.map_tag = tag; - cmd->se_cmd.map_cpu = cpu; cmd->sess = sess; cmd->loop_id = sess->loop_id; cmd->conf_compl_supported = sess->conf_compl_supported; @@ -4747,11 +4739,11 @@ static int qlt_handle_login(struct scsi_qla_host *vha, qla24xx_post_newsess_work(vha, &port_id, iocb->u.isp24.port_name, iocb->u.isp24.u.plogi.node_name, - pla, FC4_TYPE_UNKNOWN); + pla, 0); else qla24xx_post_newsess_work(vha, &port_id, iocb->u.isp24.port_name, NULL, - pla, FC4_TYPE_UNKNOWN); + pla, 0); goto out; } @@ -5352,9 +5344,7 @@ qlt_alloc_qfull_cmd(struct scsi_qla_host *vha, struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; struct qla_hw_data *ha = vha->hw; struct fc_port *sess; - struct se_session *se_sess; struct qla_tgt_cmd *cmd; - int tag, cpu; unsigned long flags; if (unlikely(tgt->tgt_stop)) { @@ -5384,10 +5374,8 @@ qlt_alloc_qfull_cmd(struct scsi_qla_host *vha, if (!sess) return; - se_sess = sess->se_sess; - - tag = sbitmap_queue_get(&se_sess->sess_tag_pool, &cpu); - if (tag < 0) { + cmd = ha->tgt.tgt_ops->get_cmd(sess); + if (!cmd) { ql_dbg(ql_dbg_io, vha, 0x3009, "qla_target(%d): %s: Allocation of cmd failed\n", vha->vp_idx, __func__); @@ -5402,9 +5390,6 @@ qlt_alloc_qfull_cmd(struct scsi_qla_host *vha, return; } - cmd = &((struct qla_tgt_cmd *)se_sess->sess_cmd_map)[tag]; - memset(cmd, 0, sizeof(struct qla_tgt_cmd)); - qlt_incr_num_pend_cmds(vha); INIT_LIST_HEAD(&cmd->cmd_list); memcpy(&cmd->atio, atio, sizeof(*atio)); @@ -5414,7 +5399,6 @@ qlt_alloc_qfull_cmd(struct scsi_qla_host *vha, cmd->reset_count = ha->base_qpair->chip_reset; cmd->q_full = 1; cmd->qpair = ha->base_qpair; - cmd->se_cmd.map_cpu = cpu; if (qfull) { cmd->q_full = 1; diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h index 6539499e9e95..3cf8590feeac 100644 --- a/drivers/scsi/qla2xxx/qla_target.h +++ b/drivers/scsi/qla2xxx/qla_target.h @@ -671,6 +671,8 @@ struct qla_tgt_func_tmpl { void (*handle_data)(struct qla_tgt_cmd *); int (*handle_tmr)(struct qla_tgt_mgmt_cmd *, u64, uint16_t, uint32_t); + struct qla_tgt_cmd *(*get_cmd)(struct fc_port *); + void (*rel_cmd)(struct qla_tgt_cmd *); void (*free_cmd)(struct qla_tgt_cmd *); void (*free_mcmd)(struct qla_tgt_mgmt_cmd *); void (*free_session)(struct fc_port *); diff --git a/drivers/scsi/qla2xxx/qla_tmpl.c b/drivers/scsi/qla2xxx/qla_tmpl.c index 5b0c057def2b..6aeb1c3fb7a8 100644 --- a/drivers/scsi/qla2xxx/qla_tmpl.c +++ b/drivers/scsi/qla2xxx/qla_tmpl.c @@ -870,7 +870,7 @@ bailout: static void qla27xx_time_stamp(struct qla27xx_fwdt_template *tmp) { - tmp->capture_timestamp = jiffies; + tmp->capture_timestamp = cpu_to_le32(jiffies); } static void @@ -882,9 +882,10 @@ qla27xx_driver_info(struct qla27xx_fwdt_template *tmp) "%hhu.%hhu.%hhu.%hhu.%hhu.%hhu", v+0, v+1, v+2, v+3, v+4, v+5) != 6); - tmp->driver_info[0] = v[3] << 24 | v[2] << 16 | v[1] << 8 | v[0]; - tmp->driver_info[1] = v[5] << 8 | v[4]; - tmp->driver_info[2] = 0x12345678; + tmp->driver_info[0] = cpu_to_le32( + v[3] << 24 | v[2] << 16 | v[1] << 8 | v[0]); + tmp->driver_info[1] = cpu_to_le32(v[5] << 8 | v[4]); + tmp->driver_info[2] = __constant_cpu_to_le32(0x12345678); } static void @@ -894,10 +895,10 @@ qla27xx_firmware_info(struct scsi_qla_host *vha, tmp->firmware_version[0] = vha->hw->fw_major_version; tmp->firmware_version[1] = vha->hw->fw_minor_version; tmp->firmware_version[2] = vha->hw->fw_subminor_version; - tmp->firmware_version[3] = - vha->hw->fw_attributes_h << 16 | vha->hw->fw_attributes; - tmp->firmware_version[4] = - vha->hw->fw_attributes_ext[1] << 16 | vha->hw->fw_attributes_ext[0]; + tmp->firmware_version[3] = cpu_to_le32( + vha->hw->fw_attributes_h << 16 | vha->hw->fw_attributes); + tmp->firmware_version[4] = cpu_to_le32( + vha->hw->fw_attributes_ext[1] << 16 | vha->hw->fw_attributes_ext[0]); } static void diff --git a/drivers/scsi/qla2xxx/qla_tmpl.h b/drivers/scsi/qla2xxx/qla_tmpl.h index d2a0014e8b21..bba8dc90acfb 100644 --- a/drivers/scsi/qla2xxx/qla_tmpl.h +++ b/drivers/scsi/qla2xxx/qla_tmpl.h @@ -18,11 +18,11 @@ struct __packed qla27xx_fwdt_template { __le32 entry_count; uint32_t template_version; - uint32_t capture_timestamp; + __le32 capture_timestamp; uint32_t template_checksum; uint32_t reserved_2; - uint32_t driver_info[3]; + __le32 driver_info[3]; uint32_t saved_state[16]; diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index bb03c022e023..8ccd9ba1ddef 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -7,7 +7,7 @@ /* * Driver version */ -#define QLA2XXX_VERSION "10.01.00.22-k" +#define QLA2XXX_VERSION "10.01.00.25-k" #define QLA_DRIVER_MAJOR_VER 10 #define QLA_DRIVER_MINOR_VER 1 diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index abe7f79bb789..1f0a185b2a95 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -268,6 +268,29 @@ static void tcm_qla2xxx_complete_free(struct work_struct *work) transport_generic_free_cmd(&cmd->se_cmd, 0); } +static struct qla_tgt_cmd *tcm_qla2xxx_get_cmd(struct fc_port *sess) +{ + struct se_session *se_sess = sess->se_sess; + struct qla_tgt_cmd *cmd; + int tag, cpu; + + tag = sbitmap_queue_get(&se_sess->sess_tag_pool, &cpu); + if (tag < 0) + return NULL; + + cmd = &((struct qla_tgt_cmd *)se_sess->sess_cmd_map)[tag]; + memset(cmd, 0, sizeof(struct qla_tgt_cmd)); + cmd->se_cmd.map_tag = tag; + cmd->se_cmd.map_cpu = cpu; + + return cmd; +} + +static void tcm_qla2xxx_rel_cmd(struct qla_tgt_cmd *cmd) +{ + target_free_tag(cmd->sess->se_sess, &cmd->se_cmd); +} + /* * Called from qla_target_template->free_cmd(), and will call * tcm_qla2xxx_release_cmd via normal struct target_core_fabric_ops @@ -1549,6 +1572,8 @@ static struct qla_tgt_func_tmpl tcm_qla2xxx_template = { .handle_cmd = tcm_qla2xxx_handle_cmd, .handle_data = tcm_qla2xxx_handle_data, .handle_tmr = tcm_qla2xxx_handle_tmr, + .get_cmd = tcm_qla2xxx_get_cmd, + .rel_cmd = tcm_qla2xxx_rel_cmd, .free_cmd = tcm_qla2xxx_free_cmd, .free_mcmd = tcm_qla2xxx_free_mcmd, .free_session = tcm_qla2xxx_free_session, |