diff options
Diffstat (limited to 'drivers/scsi/qla2xxx')
-rw-r--r-- | drivers/scsi/qla2xxx/qla_attr.c | 136 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_dbg.h | 7 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_def.h | 157 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_gbl.h | 12 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_gs.c | 564 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_init.c | 24 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_iocb.c | 6 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_isr.c | 2 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_mbx.c | 97 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_os.c | 117 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_sup.c | 34 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_version.h | 4 |
12 files changed, 1009 insertions, 151 deletions
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 659a5d63467d..fe0fce71adc7 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -211,6 +211,138 @@ qla2x00_free_sysfs_attr(scsi_qla_host_t *ha) sysfs_remove_bin_file(&host->shost_gendev.kobj, &sysfs_nvram_attr); } +/* Scsi_Host attributes. */ + +static ssize_t +qla2x00_drvr_version_show(struct class_device *cdev, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%s\n", qla2x00_version_str); +} + +static ssize_t +qla2x00_fw_version_show(struct class_device *cdev, char *buf) +{ + scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev)); + char fw_str[30]; + + return snprintf(buf, PAGE_SIZE, "%s\n", + ha->isp_ops.fw_version_str(ha, fw_str)); +} + +static ssize_t +qla2x00_serial_num_show(struct class_device *cdev, char *buf) +{ + scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev)); + uint32_t sn; + + sn = ((ha->serial0 & 0x1f) << 16) | (ha->serial2 << 8) | ha->serial1; + return snprintf(buf, PAGE_SIZE, "%c%05d\n", 'A' + sn / 100000, + sn % 100000); +} + +static ssize_t +qla2x00_isp_name_show(struct class_device *cdev, char *buf) +{ + scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev)); + return snprintf(buf, PAGE_SIZE, "%s\n", ha->brd_info->isp_name); +} + +static ssize_t +qla2x00_isp_id_show(struct class_device *cdev, char *buf) +{ + scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev)); + return snprintf(buf, PAGE_SIZE, "%04x %04x %04x %04x\n", + ha->product_id[0], ha->product_id[1], ha->product_id[2], + ha->product_id[3]); +} + +static ssize_t +qla2x00_model_name_show(struct class_device *cdev, char *buf) +{ + scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev)); + return snprintf(buf, PAGE_SIZE, "%s\n", ha->model_number); +} + +static ssize_t +qla2x00_model_desc_show(struct class_device *cdev, char *buf) +{ + scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev)); + return snprintf(buf, PAGE_SIZE, "%s\n", + ha->model_desc ? ha->model_desc: ""); +} + +static ssize_t +qla2x00_pci_info_show(struct class_device *cdev, char *buf) +{ + scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev)); + char pci_info[30]; + + return snprintf(buf, PAGE_SIZE, "%s\n", + ha->isp_ops.pci_info_str(ha, pci_info)); +} + +static ssize_t +qla2x00_state_show(struct class_device *cdev, char *buf) +{ + scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev)); + int len = 0; + + if (atomic_read(&ha->loop_state) == LOOP_DOWN || + atomic_read(&ha->loop_state) == LOOP_DEAD) + len = snprintf(buf, PAGE_SIZE, "Link Down\n"); + else if (atomic_read(&ha->loop_state) != LOOP_READY || + test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags) || + test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags)) + len = snprintf(buf, PAGE_SIZE, "Unknown Link State\n"); + else { + len = snprintf(buf, PAGE_SIZE, "Link Up - "); + + switch (ha->current_topology) { + case ISP_CFG_NL: + len += snprintf(buf + len, PAGE_SIZE-len, "Loop\n"); + break; + case ISP_CFG_FL: + len += snprintf(buf + len, PAGE_SIZE-len, "FL_Port\n"); + break; + case ISP_CFG_N: + len += snprintf(buf + len, PAGE_SIZE-len, + "N_Port to N_Port\n"); + break; + case ISP_CFG_F: + len += snprintf(buf + len, PAGE_SIZE-len, "F_Port\n"); + break; + default: + len += snprintf(buf + len, PAGE_SIZE-len, "Loop\n"); + break; + } + } + return len; +} + +static CLASS_DEVICE_ATTR(driver_version, S_IRUGO, qla2x00_drvr_version_show, + NULL); +static CLASS_DEVICE_ATTR(fw_version, S_IRUGO, qla2x00_fw_version_show, NULL); +static CLASS_DEVICE_ATTR(serial_num, S_IRUGO, qla2x00_serial_num_show, NULL); +static CLASS_DEVICE_ATTR(isp_name, S_IRUGO, qla2x00_isp_name_show, NULL); +static CLASS_DEVICE_ATTR(isp_id, S_IRUGO, qla2x00_isp_id_show, NULL); +static CLASS_DEVICE_ATTR(model_name, S_IRUGO, qla2x00_model_name_show, NULL); +static CLASS_DEVICE_ATTR(model_desc, S_IRUGO, qla2x00_model_desc_show, NULL); +static CLASS_DEVICE_ATTR(pci_info, S_IRUGO, qla2x00_pci_info_show, NULL); +static CLASS_DEVICE_ATTR(state, S_IRUGO, qla2x00_state_show, NULL); + +struct class_device_attribute *qla2x00_host_attrs[] = { + &class_device_attr_driver_version, + &class_device_attr_fw_version, + &class_device_attr_serial_num, + &class_device_attr_isp_name, + &class_device_attr_isp_id, + &class_device_attr_model_name, + &class_device_attr_model_desc, + &class_device_attr_pci_info, + &class_device_attr_state, + NULL, +}; + /* Host attributes. */ static void @@ -304,10 +436,13 @@ struct fc_function_template qla2xxx_transport_functions = { .show_host_node_name = 1, .show_host_port_name = 1, + .show_host_supported_classes = 1, + .get_host_port_id = qla2x00_get_host_port_id, .show_host_port_id = 1, .dd_fcrport_size = sizeof(struct fc_port *), + .show_rport_supported_classes = 1, .get_starget_node_name = qla2x00_get_starget_node_name, .show_starget_node_name = 1, @@ -329,4 +464,5 @@ qla2x00_init_host_attr(scsi_qla_host_t *ha) be64_to_cpu(*(uint64_t *)ha->init_cb->node_name); fc_host_port_name(ha->host) = be64_to_cpu(*(uint64_t *)ha->init_cb->port_name); + fc_host_supported_classes(ha->host) = FC_COS_CLASS3; } diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h index b8d90e97e017..9684e7a91fa9 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.h +++ b/drivers/scsi/qla2xxx/qla_dbg.h @@ -81,6 +81,7 @@ #define DEBUG2_3_11(x) do {x;} while (0); #define DEBUG2_9_10(x) do {x;} while (0); #define DEBUG2_11(x) do {x;} while (0); +#define DEBUG2_13(x) do {x;} while (0); #else #define DEBUG2(x) do {} while (0); #endif @@ -169,8 +170,14 @@ #if defined(QL_DEBUG_LEVEL_13) #define DEBUG13(x) do {x;} while (0) +#if !defined(DEBUG2_13) +#define DEBUG2_13(x) do {x;} while(0) +#endif #else #define DEBUG13(x) do {} while (0) +#if !defined(QL_DEBUG_LEVEL_2) +#define DEBUG2_13(x) do {} while(0) +#endif #endif #if defined(QL_DEBUG_LEVEL_14) diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 1c6d366f4fad..b455c31405e4 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -214,6 +214,7 @@ * valid range of an N-PORT id is 0 through 0x7ef. */ #define NPH_LAST_HANDLE 0x7ef +#define NPH_MGMT_SERVER 0x7fa /* FFFFFA */ #define NPH_SNS 0x7fc /* FFFFFC */ #define NPH_FABRIC_CONTROLLER 0x7fd /* FFFFFD */ #define NPH_F_PORT 0x7fe /* FFFFFE */ @@ -630,6 +631,7 @@ typedef struct { #define MBC_WRITE_RAM_WORD_EXTENDED 0xd /* Write RAM word extended */ #define MBC_READ_RAM_EXTENDED 0xf /* Read RAM extended. */ #define MBC_IOCB_COMMAND 0x12 /* Execute IOCB command. */ +#define MBC_STOP_FIRMWARE 0x14 /* Stop firmware. */ #define MBC_ABORT_COMMAND 0x15 /* Abort IOCB command. */ #define MBC_ABORT_DEVICE 0x16 /* Abort device (ID/LUN). */ #define MBC_ABORT_TARGET 0x17 /* Abort target (ID). */ @@ -913,7 +915,7 @@ typedef struct { * MSB BIT 1 = * MSB BIT 2 = * MSB BIT 3 = - * MSB BIT 4 = + * MSB BIT 4 = LED mode * MSB BIT 5 = enable 50 ohm termination * MSB BIT 6 = Data Rate (2300 only) * MSB BIT 7 = Data Rate (2300 only) @@ -1035,7 +1037,7 @@ typedef struct { * MSB BIT 1 = * MSB BIT 2 = * MSB BIT 3 = - * MSB BIT 4 = + * MSB BIT 4 = LED mode * MSB BIT 5 = enable 50 ohm termination * MSB BIT 6 = Data Rate (2300 only) * MSB BIT 7 = Data Rate (2300 only) @@ -1131,10 +1133,7 @@ typedef struct { uint8_t link_down_timeout; - uint8_t adapter_id_0[4]; - uint8_t adapter_id_1[4]; - uint8_t adapter_id_2[4]; - uint8_t adapter_id_3[4]; + uint8_t adapter_id[16]; uint8_t alt1_boot_node_name[WWN_SIZE]; uint16_t alt1_boot_lun_number; @@ -1673,6 +1672,7 @@ typedef struct fc_port { uint8_t cur_path; /* current path id */ struct fc_rport *rport; + u32 supported_classes; } fc_port_t; /* @@ -1727,6 +1727,8 @@ typedef struct fc_port { #define CT_REJECT_RESPONSE 0x8001 #define CT_ACCEPT_RESPONSE 0x8002 +#define CT_REASON_CANNOT_PERFORM 0x09 +#define CT_EXPL_ALREADY_REGISTERED 0x10 #define NS_N_PORT_TYPE 0x01 #define NS_NL_PORT_TYPE 0x02 @@ -1768,6 +1770,100 @@ typedef struct fc_port { #define RSNN_NN_REQ_SIZE (16 + 8 + 1 + 255) #define RSNN_NN_RSP_SIZE 16 +/* + * HBA attribute types. + */ +#define FDMI_HBA_ATTR_COUNT 9 +#define FDMI_HBA_NODE_NAME 1 +#define FDMI_HBA_MANUFACTURER 2 +#define FDMI_HBA_SERIAL_NUMBER 3 +#define FDMI_HBA_MODEL 4 +#define FDMI_HBA_MODEL_DESCRIPTION 5 +#define FDMI_HBA_HARDWARE_VERSION 6 +#define FDMI_HBA_DRIVER_VERSION 7 +#define FDMI_HBA_OPTION_ROM_VERSION 8 +#define FDMI_HBA_FIRMWARE_VERSION 9 +#define FDMI_HBA_OS_NAME_AND_VERSION 0xa +#define FDMI_HBA_MAXIMUM_CT_PAYLOAD_LENGTH 0xb + +struct ct_fdmi_hba_attr { + uint16_t type; + uint16_t len; + union { + uint8_t node_name[WWN_SIZE]; + uint8_t manufacturer[32]; + uint8_t serial_num[8]; + uint8_t model[16]; + uint8_t model_desc[80]; + uint8_t hw_version[16]; + uint8_t driver_version[32]; + uint8_t orom_version[16]; + uint8_t fw_version[16]; + uint8_t os_version[128]; + uint8_t max_ct_len[4]; + } a; +}; + +struct ct_fdmi_hba_attributes { + uint32_t count; + struct ct_fdmi_hba_attr entry[FDMI_HBA_ATTR_COUNT]; +}; + +/* + * Port attribute types. + */ +#define FDMI_PORT_ATTR_COUNT 5 +#define FDMI_PORT_FC4_TYPES 1 +#define FDMI_PORT_SUPPORT_SPEED 2 +#define FDMI_PORT_CURRENT_SPEED 3 +#define FDMI_PORT_MAX_FRAME_SIZE 4 +#define FDMI_PORT_OS_DEVICE_NAME 5 +#define FDMI_PORT_HOST_NAME 6 + +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[32]; + } a; +}; + +/* + * Port Attribute Block. + */ +struct ct_fdmi_port_attributes { + uint32_t count; + struct ct_fdmi_port_attr entry[FDMI_PORT_ATTR_COUNT]; +}; + +/* FDMI definitions. */ +#define GRHL_CMD 0x100 +#define GHAT_CMD 0x101 +#define GRPL_CMD 0x102 +#define GPAT_CMD 0x110 + +#define RHBA_CMD 0x200 +#define RHBA_RSP_SIZE 16 + +#define RHAT_CMD 0x201 +#define RPRT_CMD 0x210 + +#define RPA_CMD 0x211 +#define RPA_RSP_SIZE 16 + +#define DHBA_CMD 0x300 +#define DHBA_REQ_SIZE (16 + 8) +#define DHBA_RSP_SIZE 16 + +#define DHAT_CMD 0x301 +#define DPRT_CMD 0x310 +#define DPA_CMD 0x311 + /* CT command header -- request/response common fields */ struct ct_cmd_hdr { uint8_t revision; @@ -1825,6 +1921,43 @@ struct ct_sns_req { uint8_t name_len; uint8_t sym_node_name[255]; } rsnn_nn; + + struct { + uint8_t hba_indentifier[8]; + } ghat; + + struct { + uint8_t hba_identifier[8]; + uint32_t entry_count; + uint8_t port_name[8]; + struct ct_fdmi_hba_attributes attrs; + } rhba; + + struct { + uint8_t hba_identifier[8]; + struct ct_fdmi_hba_attributes attrs; + } rhat; + + struct { + uint8_t port_name[8]; + struct ct_fdmi_port_attributes attrs; + } rpa; + + struct { + uint8_t port_name[8]; + } dhba; + + struct { + uint8_t port_name[8]; + } dhat; + + struct { + uint8_t port_name[8]; + } dprt; + + struct { + uint8_t port_name[8]; + } dpa; } req; }; @@ -1882,6 +2015,12 @@ struct ct_sns_rsp { struct { uint8_t fc4_types[32]; } gft_id; + + struct { + uint32_t entry_count; + uint8_t port_name[8]; + struct ct_fdmi_hba_attributes attrs; + } ghat; } rsp; }; @@ -2032,6 +2171,8 @@ struct isp_operations { uint16_t (*calc_req_entries) (uint16_t); void (*build_iocbs) (srb_t *, cmd_entry_t *, uint16_t); void * (*prep_ms_iocb) (struct scsi_qla_host *, uint32_t, uint32_t); + void * (*prep_ms_fdmi_iocb) (struct scsi_qla_host *, uint32_t, + uint32_t); uint8_t * (*read_nvram) (struct scsi_qla_host *, uint8_t *, uint32_t, uint32_t); @@ -2111,6 +2252,7 @@ typedef struct scsi_qla_host { #define IOCTL_ERROR_RECOVERY 23 #define LOOP_RESET_NEEDED 24 #define BEACON_BLINK_NEEDED 25 +#define REGISTER_FDMI_NEEDED 26 uint32_t device_flags; #define DFLG_LOCAL_DEVICES BIT_0 @@ -2204,6 +2346,7 @@ typedef struct scsi_qla_host { int port_down_retry_count; uint8_t mbx_count; uint16_t last_loop_id; + uint16_t mgmt_svr_loop_id; uint32_t login_retry_count; @@ -2318,6 +2461,7 @@ typedef struct scsi_qla_host { uint8_t model_number[16+1]; #define BINZERO "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" char *model_desc; + uint8_t adapter_id[16+1]; uint8_t *node_name; uint8_t *port_name; @@ -2377,6 +2521,7 @@ typedef struct scsi_qla_host { #define QLA_SUSPENDED 0x106 #define QLA_BUSY 0x107 #define QLA_RSCNS_HANDLED 0x108 +#define QLA_ALREADY_REGISTERED 0x109 /* * Stat info for all adpaters diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 665c203e0675..1ed32e7b5472 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -79,6 +79,7 @@ extern int ql2xplogiabsentdevice; extern int ql2xenablezio; extern int ql2xintrdelaytimer; extern int ql2xloginretrycount; +extern int ql2xfdmienable; extern void qla2x00_sp_compl(scsi_qla_host_t *, srb_t *); @@ -147,9 +148,6 @@ qla2x00_abort_target(fc_port_t *); #endif extern int -qla2x00_target_reset(scsi_qla_host_t *, struct fc_port *); - -extern int qla2x00_get_adapter_id(scsi_qla_host_t *, uint16_t *, uint8_t *, uint8_t *, uint8_t *, uint16_t *); @@ -215,6 +213,9 @@ qla2x00_get_serdes_params(scsi_qla_host_t *, uint16_t *, uint16_t *, extern int qla2x00_set_serdes_params(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t); +extern int +qla2x00_stop_firmware(scsi_qla_host_t *); + /* * Global Function Prototypes in qla_isr.c source file. */ @@ -269,6 +270,9 @@ extern int qla2x00_rft_id(scsi_qla_host_t *); extern int qla2x00_rff_id(scsi_qla_host_t *); extern int qla2x00_rnn_id(scsi_qla_host_t *); extern int qla2x00_rsnn_nn(scsi_qla_host_t *); +extern void *qla2x00_prep_ms_fdmi_iocb(scsi_qla_host_t *, uint32_t, uint32_t); +extern void *qla24xx_prep_ms_fdmi_iocb(scsi_qla_host_t *, uint32_t, uint32_t); +extern int qla2x00_fdmi_register(scsi_qla_host_t *); /* * Global Function Prototypes in qla_rscn.c source file. @@ -289,6 +293,8 @@ extern void qla2x00_cancel_io_descriptors(scsi_qla_host_t *); /* * Global Function Prototypes in qla_attr.c source file. */ +struct class_device_attribute; +extern struct class_device_attribute *qla2x00_host_attrs[]; struct fc_function_template; extern struct fc_function_template qla2xxx_transport_functions; extern void qla2x00_alloc_sysfs_attr(scsi_qla_host_t *); diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index 31ce4f62da13..e7b138c2e339 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -1099,3 +1099,567 @@ qla2x00_sns_rnn_id(scsi_qla_host_t *ha) return (rval); } + +/** + * qla2x00_mgmt_svr_login() - Login to fabric Managment Service. + * @ha: HA context + * + * Returns 0 on success. + */ +static int +qla2x00_mgmt_svr_login(scsi_qla_host_t *ha) +{ + int ret; + uint16_t mb[MAILBOX_REGISTER_COUNT]; + + ret = QLA_SUCCESS; + if (ha->flags.management_server_logged_in) + return ret; + + ha->isp_ops.fabric_login(ha, ha->mgmt_svr_loop_id, 0xff, 0xff, 0xfa, + mb, BIT_1); + if (mb[0] != MBS_COMMAND_COMPLETE) { + DEBUG2_13(printk("%s(%ld): Failed MANAGEMENT_SERVER login: " + "loop_id=%x mb[0]=%x mb[1]=%x mb[2]=%x mb[6]=%x mb[7]=%x\n", + __func__, ha->host_no, ha->mgmt_svr_loop_id, mb[0], mb[1], + mb[2], mb[6], mb[7])); + ret = QLA_FUNCTION_FAILED; + } else + ha->flags.management_server_logged_in = 1; + + return ret; +} + +/** + * qla2x00_prep_ms_fdmi_iocb() - Prepare common MS IOCB fields for FDMI query. + * @ha: HA context + * @req_size: request size in bytes + * @rsp_size: response size in bytes + * + * Returns a pointer to the @ha's ms_iocb. + */ +void * +qla2x00_prep_ms_fdmi_iocb(scsi_qla_host_t *ha, uint32_t req_size, + uint32_t rsp_size) +{ + ms_iocb_entry_t *ms_pkt; + + ms_pkt = ha->ms_iocb; + memset(ms_pkt, 0, sizeof(ms_iocb_entry_t)); + + ms_pkt->entry_type = MS_IOCB_TYPE; + ms_pkt->entry_count = 1; + SET_TARGET_ID(ha, ms_pkt->loop_id, ha->mgmt_svr_loop_id); + ms_pkt->control_flags = __constant_cpu_to_le16(CF_READ | CF_HEAD_TAG); + ms_pkt->timeout = __constant_cpu_to_le16(59); + ms_pkt->cmd_dsd_count = __constant_cpu_to_le16(1); + ms_pkt->total_dsd_count = __constant_cpu_to_le16(2); + ms_pkt->rsp_bytecount = cpu_to_le32(rsp_size); + ms_pkt->req_bytecount = cpu_to_le32(req_size); + + ms_pkt->dseg_req_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma)); + ms_pkt->dseg_req_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma)); + ms_pkt->dseg_req_length = ms_pkt->req_bytecount; + + ms_pkt->dseg_rsp_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma)); + ms_pkt->dseg_rsp_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma)); + ms_pkt->dseg_rsp_length = ms_pkt->rsp_bytecount; + + return ms_pkt; +} + +/** + * qla24xx_prep_ms_fdmi_iocb() - Prepare common MS IOCB fields for FDMI query. + * @ha: HA context + * @req_size: request size in bytes + * @rsp_size: response size in bytes + * + * Returns a pointer to the @ha's ms_iocb. + */ +void * +qla24xx_prep_ms_fdmi_iocb(scsi_qla_host_t *ha, uint32_t req_size, + uint32_t rsp_size) +{ + struct ct_entry_24xx *ct_pkt; + + ct_pkt = (struct ct_entry_24xx *)ha->ms_iocb; + memset(ct_pkt, 0, sizeof(struct ct_entry_24xx)); + + ct_pkt->entry_type = CT_IOCB_TYPE; + ct_pkt->entry_count = 1; + ct_pkt->nport_handle = cpu_to_le16(ha->mgmt_svr_loop_id); + ct_pkt->timeout = __constant_cpu_to_le16(59); + ct_pkt->cmd_dsd_count = __constant_cpu_to_le16(1); + ct_pkt->rsp_dsd_count = __constant_cpu_to_le16(1); + ct_pkt->rsp_byte_count = cpu_to_le32(rsp_size); + ct_pkt->cmd_byte_count = cpu_to_le32(req_size); + + ct_pkt->dseg_0_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma)); + ct_pkt->dseg_0_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma)); + ct_pkt->dseg_0_len = ct_pkt->cmd_byte_count; + + ct_pkt->dseg_1_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma)); + ct_pkt->dseg_1_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma)); + ct_pkt->dseg_1_len = ct_pkt->rsp_byte_count; + + return ct_pkt; +} + +static inline ms_iocb_entry_t * +qla2x00_update_ms_fdmi_iocb(scsi_qla_host_t *ha, uint32_t req_size) +{ + ms_iocb_entry_t *ms_pkt = ha->ms_iocb; + struct ct_entry_24xx *ct_pkt = (struct ct_entry_24xx *)ha->ms_iocb; + + if (IS_QLA24XX(ha) || IS_QLA25XX(ha)) { + ct_pkt->cmd_byte_count = cpu_to_le32(req_size); + ct_pkt->dseg_0_len = ct_pkt->cmd_byte_count; + } else { + ms_pkt->req_bytecount = cpu_to_le32(req_size); + ms_pkt->dseg_req_length = ms_pkt->req_bytecount; + } + + return ms_pkt; +} + +/** + * qla2x00_prep_ct_req() - Prepare common CT request fields for SNS query. + * @ct_req: CT request buffer + * @cmd: GS command + * @rsp_size: response size in bytes + * + * Returns a pointer to the intitialized @ct_req. + */ +static inline struct ct_sns_req * +qla2x00_prep_ct_fdmi_req(struct ct_sns_req *ct_req, uint16_t cmd, + uint16_t rsp_size) +{ + memset(ct_req, 0, sizeof(struct ct_sns_pkt)); + + ct_req->header.revision = 0x01; + ct_req->header.gs_type = 0xFA; + ct_req->header.gs_subtype = 0x10; + ct_req->command = cpu_to_be16(cmd); + ct_req->max_rsp_size = cpu_to_be16((rsp_size - 16) / 4); + + return ct_req; +} + +/** + * qla2x00_fdmi_rhba() - + * @ha: HA context + * + * Returns 0 on success. + */ +static int +qla2x00_fdmi_rhba(scsi_qla_host_t *ha) +{ + 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; + uint8_t *entries; + struct ct_fdmi_hba_attr *eiter; + + /* Issue RHBA */ + /* Prepare common MS IOCB */ + /* Request size adjusted after CT preparation */ + ms_pkt = ha->isp_ops.prep_ms_fdmi_iocb(ha, 0, RHBA_RSP_SIZE); + + /* Prepare CT request */ + ct_req = qla2x00_prep_ct_fdmi_req(&ha->ct_sns->p.req, 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, ha->port_name, WWN_SIZE); + ct_req->req.rhba.entry_count = __constant_cpu_to_be32(1); + memcpy(ct_req->req.rhba.port_name, ha->port_name, WWN_SIZE); + size = 2 * WWN_SIZE + 4 + 4; + + /* Attributes */ + ct_req->req.rhba.attrs.count = + __constant_cpu_to_be32(FDMI_HBA_ATTR_COUNT); + entries = ct_req->req.rhba.hba_identifier; + + /* Nodename. */ + eiter = (struct ct_fdmi_hba_attr *) (entries + size); + eiter->type = __constant_cpu_to_be16(FDMI_HBA_NODE_NAME); + eiter->len = __constant_cpu_to_be16(4 + WWN_SIZE); + memcpy(eiter->a.node_name, ha->node_name, WWN_SIZE); + size += 4 + WWN_SIZE; + + DEBUG13(printk("%s(%ld): NODENAME=%02x%02x%02x%02x%02x%02x%02x%02x.\n", + __func__, ha->host_no, + eiter->a.node_name[0], eiter->a.node_name[1], eiter->a.node_name[2], + eiter->a.node_name[3], eiter->a.node_name[4], eiter->a.node_name[5], + eiter->a.node_name[6], eiter->a.node_name[7])); + + /* Manufacturer. */ + eiter = (struct ct_fdmi_hba_attr *) (entries + size); + eiter->type = __constant_cpu_to_be16(FDMI_HBA_MANUFACTURER); + strcpy(eiter->a.manufacturer, "QLogic Corporation"); + alen = strlen(eiter->a.manufacturer); + alen += (alen & 3) ? (4 - (alen & 3)) : 4; + eiter->len = cpu_to_be16(4 + alen); + size += 4 + alen; + + DEBUG13(printk("%s(%ld): MANUFACTURER=%s.\n", __func__, ha->host_no, + eiter->a.manufacturer)); + + /* Serial number. */ + eiter = (struct ct_fdmi_hba_attr *) (entries + size); + eiter->type = __constant_cpu_to_be16(FDMI_HBA_SERIAL_NUMBER); + sn = ((ha->serial0 & 0x1f) << 16) | (ha->serial2 << 8) | ha->serial1; + sprintf(eiter->a.serial_num, "%c%05d", 'A' + sn / 100000, sn % 100000); + alen = strlen(eiter->a.serial_num); + alen += (alen & 3) ? (4 - (alen & 3)) : 4; + eiter->len = cpu_to_be16(4 + alen); + size += 4 + alen; + + DEBUG13(printk("%s(%ld): SERIALNO=%s.\n", __func__, ha->host_no, + eiter->a.serial_num)); + + /* Model name. */ + eiter = (struct ct_fdmi_hba_attr *) (entries + size); + eiter->type = __constant_cpu_to_be16(FDMI_HBA_MODEL); + strcpy(eiter->a.model, ha->model_number); + alen = strlen(eiter->a.model); + alen += (alen & 3) ? (4 - (alen & 3)) : 4; + eiter->len = cpu_to_be16(4 + alen); + size += 4 + alen; + + DEBUG13(printk("%s(%ld): MODEL_NAME=%s.\n", __func__, ha->host_no, + eiter->a.model)); + + /* Model description. */ + eiter = (struct ct_fdmi_hba_attr *) (entries + size); + eiter->type = __constant_cpu_to_be16(FDMI_HBA_MODEL_DESCRIPTION); + if (ha->model_desc) + strncpy(eiter->a.model_desc, ha->model_desc, 80); + alen = strlen(eiter->a.model_desc); + alen += (alen & 3) ? (4 - (alen & 3)) : 4; + eiter->len = cpu_to_be16(4 + alen); + size += 4 + alen; + + DEBUG13(printk("%s(%ld): MODEL_DESC=%s.\n", __func__, ha->host_no, + eiter->a.model_desc)); + + /* Hardware version. */ + eiter = (struct ct_fdmi_hba_attr *) (entries + size); + eiter->type = __constant_cpu_to_be16(FDMI_HBA_HARDWARE_VERSION); + strcpy(eiter->a.hw_version, ha->adapter_id); + alen = strlen(eiter->a.hw_version); + alen += (alen & 3) ? (4 - (alen & 3)) : 4; + eiter->len = cpu_to_be16(4 + alen); + size += 4 + alen; + + DEBUG13(printk("%s(%ld): HARDWAREVER=%s.\n", __func__, ha->host_no, + eiter->a.hw_version)); + + /* Driver version. */ + eiter = (struct ct_fdmi_hba_attr *) (entries + size); + eiter->type = __constant_cpu_to_be16(FDMI_HBA_DRIVER_VERSION); + strcpy(eiter->a.driver_version, qla2x00_version_str); + alen = strlen(eiter->a.driver_version); + alen += (alen & 3) ? (4 - (alen & 3)) : 4; + eiter->len = cpu_to_be16(4 + alen); + size += 4 + alen; + + DEBUG13(printk("%s(%ld): DRIVERVER=%s.\n", __func__, ha->host_no, + eiter->a.driver_version)); + + /* Option ROM version. */ + eiter = (struct ct_fdmi_hba_attr *) (entries + size); + eiter->type = __constant_cpu_to_be16(FDMI_HBA_OPTION_ROM_VERSION); + strcpy(eiter->a.orom_version, "0.00"); + alen = strlen(eiter->a.orom_version); + alen += (alen & 3) ? (4 - (alen & 3)) : 4; + eiter->len = cpu_to_be16(4 + alen); + size += 4 + alen; + + DEBUG13(printk("%s(%ld): OPTROMVER=%s.\n", __func__, ha->host_no, + eiter->a.orom_version)); + + /* Firmware version */ + eiter = (struct ct_fdmi_hba_attr *) (entries + size); + eiter->type = __constant_cpu_to_be16(FDMI_HBA_FIRMWARE_VERSION); + ha->isp_ops.fw_version_str(ha, eiter->a.fw_version); + alen = strlen(eiter->a.fw_version); + alen += (alen & 3) ? (4 - (alen & 3)) : 4; + eiter->len = cpu_to_be16(4 + alen); + size += 4 + alen; + + DEBUG13(printk("%s(%ld): FIRMWAREVER=%s.\n", __func__, ha->host_no, + eiter->a.fw_version)); + + /* Update MS request size. */ + qla2x00_update_ms_fdmi_iocb(ha, size + 16); + + DEBUG13(printk("%s(%ld): RHBA identifier=" + "%02x%02x%02x%02x%02x%02x%02x%02x size=%d.\n", __func__, + ha->host_no, ct_req->req.rhba.hba_identifier[0], + ct_req->req.rhba.hba_identifier[1], + ct_req->req.rhba.hba_identifier[2], + ct_req->req.rhba.hba_identifier[3], + ct_req->req.rhba.hba_identifier[4], + ct_req->req.rhba.hba_identifier[5], + ct_req->req.rhba.hba_identifier[6], + ct_req->req.rhba.hba_identifier[7], size)); + DEBUG13(qla2x00_dump_buffer(entries, size)); + + /* Execute MS IOCB */ + rval = qla2x00_issue_iocb(ha, ha->ms_iocb, ha->ms_iocb_dma, + sizeof(ms_iocb_entry_t)); + if (rval != QLA_SUCCESS) { + /*EMPTY*/ + DEBUG2_3(printk("scsi(%ld): RHBA issue IOCB failed (%d).\n", + ha->host_no, rval)); + } else if (qla2x00_chk_ms_status(ha, 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) { + DEBUG2_13(printk("%s(%ld): HBA already registered.\n", + __func__, ha->host_no)); + rval = QLA_ALREADY_REGISTERED; + } + } else { + DEBUG2(printk("scsi(%ld): RHBA exiting normally.\n", + ha->host_no)); + } + + return rval; +} + +/** + * qla2x00_fdmi_dhba() - + * @ha: HA context + * + * Returns 0 on success. + */ +static int +qla2x00_fdmi_dhba(scsi_qla_host_t *ha) +{ + int rval; + + 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(ha, DHBA_REQ_SIZE, + DHBA_RSP_SIZE); + + /* Prepare CT request */ + ct_req = qla2x00_prep_ct_fdmi_req(&ha->ct_sns->p.req, DHBA_CMD, + DHBA_RSP_SIZE); + ct_rsp = &ha->ct_sns->p.rsp; + + /* Prepare FDMI command arguments -- portname. */ + memcpy(ct_req->req.dhba.port_name, ha->port_name, WWN_SIZE); + + DEBUG13(printk("%s(%ld): DHBA portname=" + "%02x%02x%02x%02x%02x%02x%02x%02x.\n", __func__, ha->host_no, + ct_req->req.dhba.port_name[0], ct_req->req.dhba.port_name[1], + ct_req->req.dhba.port_name[2], ct_req->req.dhba.port_name[3], + ct_req->req.dhba.port_name[4], ct_req->req.dhba.port_name[5], + ct_req->req.dhba.port_name[6], ct_req->req.dhba.port_name[7])); + + /* Execute MS IOCB */ + rval = qla2x00_issue_iocb(ha, ha->ms_iocb, ha->ms_iocb_dma, + sizeof(ms_iocb_entry_t)); + if (rval != QLA_SUCCESS) { + /*EMPTY*/ + DEBUG2_3(printk("scsi(%ld): DHBA issue IOCB failed (%d).\n", + ha->host_no, rval)); + } else if (qla2x00_chk_ms_status(ha, ms_pkt, ct_rsp, "DHBA") != + QLA_SUCCESS) { + rval = QLA_FUNCTION_FAILED; + } else { + DEBUG2(printk("scsi(%ld): DHBA exiting normally.\n", + ha->host_no)); + } + + return rval; +} + +/** + * qla2x00_fdmi_rpa() - + * @ha: HA context + * + * Returns 0 on success. + */ +static int +qla2x00_fdmi_rpa(scsi_qla_host_t *ha) +{ + int rval, alen; + uint32_t size, max_frame_size; + + ms_iocb_entry_t *ms_pkt; + struct ct_sns_req *ct_req; + struct ct_sns_rsp *ct_rsp; + uint8_t *entries; + struct ct_fdmi_port_attr *eiter; + struct init_cb_24xx *icb24 = (struct init_cb_24xx *)ha->init_cb; + + /* Issue RPA */ + /* Prepare common MS IOCB */ + /* Request size adjusted after CT preparation */ + ms_pkt = ha->isp_ops.prep_ms_fdmi_iocb(ha, 0, RPA_RSP_SIZE); + + /* Prepare CT request */ + ct_req = qla2x00_prep_ct_fdmi_req(&ha->ct_sns->p.req, 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, ha->port_name, WWN_SIZE); + size = WWN_SIZE + 4; + + /* Attributes */ + ct_req->req.rpa.attrs.count = + __constant_cpu_to_be32(FDMI_PORT_ATTR_COUNT); + entries = ct_req->req.rpa.port_name; + + /* FC4 types. */ + eiter = (struct ct_fdmi_port_attr *) (entries + size); + eiter->type = __constant_cpu_to_be16(FDMI_PORT_FC4_TYPES); + eiter->len = __constant_cpu_to_be16(4 + 32); + eiter->a.fc4_types[2] = 0x01; + size += 4 + 32; + + DEBUG13(printk("%s(%ld): FC4_TYPES=%02x %02x.\n", __func__, ha->host_no, + eiter->a.fc4_types[2], eiter->a.fc4_types[1])); + + /* Supported speed. */ + eiter = (struct ct_fdmi_port_attr *) (entries + size); + eiter->type = __constant_cpu_to_be16(FDMI_PORT_SUPPORT_SPEED); + eiter->len = __constant_cpu_to_be16(4 + 4); + if (IS_QLA25XX(ha)) + eiter->a.sup_speed = __constant_cpu_to_be32(4); + else if (IS_QLA24XX(ha)) + eiter->a.sup_speed = __constant_cpu_to_be32(8); + else if (IS_QLA23XX(ha)) + eiter->a.sup_speed = __constant_cpu_to_be32(2); + else + eiter->a.sup_speed = __constant_cpu_to_be32(1); + size += 4 + 4; + + DEBUG13(printk("%s(%ld): SUPPORTED_SPEED=%x.\n", __func__, ha->host_no, + eiter->a.sup_speed)); + + /* Current speed. */ + eiter = (struct ct_fdmi_port_attr *) (entries + size); + eiter->type = __constant_cpu_to_be16(FDMI_PORT_CURRENT_SPEED); + eiter->len = __constant_cpu_to_be16(4 + 4); + switch (ha->link_data_rate) { + case 0: + eiter->a.cur_speed = __constant_cpu_to_be32(1); + break; + case 1: + eiter->a.cur_speed = __constant_cpu_to_be32(2); + break; + case 3: + eiter->a.cur_speed = __constant_cpu_to_be32(8); + break; + case 4: + eiter->a.cur_speed = __constant_cpu_to_be32(4); + break; + } + size += 4 + 4; + + DEBUG13(printk("%s(%ld): CURRENT_SPEED=%x.\n", __func__, ha->host_no, + eiter->a.cur_speed)); + + /* Max frame size. */ + eiter = (struct ct_fdmi_port_attr *) (entries + size); + eiter->type = __constant_cpu_to_be16(FDMI_PORT_MAX_FRAME_SIZE); + eiter->len = __constant_cpu_to_be16(4 + 4); + max_frame_size = IS_QLA24XX(ha) || IS_QLA25XX(ha) ? + (uint32_t) icb24->frame_payload_size: + (uint32_t) ha->init_cb->frame_payload_size; + eiter->a.max_frame_size = cpu_to_be32(max_frame_size); + size += 4 + 4; + + DEBUG13(printk("%s(%ld): MAX_FRAME_SIZE=%x.\n", __func__, ha->host_no, + eiter->a.max_frame_size)); + + /* OS device name. */ + eiter = (struct ct_fdmi_port_attr *) (entries + size); + eiter->type = __constant_cpu_to_be16(FDMI_PORT_OS_DEVICE_NAME); + sprintf(eiter->a.os_dev_name, "/proc/scsi/qla2xxx/%ld", ha->host_no); + alen = strlen(eiter->a.os_dev_name); + alen += (alen & 3) ? (4 - (alen & 3)) : 4; + eiter->len = cpu_to_be16(4 + alen); + size += 4 + alen; + + DEBUG13(printk("%s(%ld): OS_DEVICE_NAME=%s.\n", __func__, ha->host_no, + eiter->a.os_dev_name)); + + /* Update MS request size. */ + qla2x00_update_ms_fdmi_iocb(ha, size + 16); + + DEBUG13(printk("%s(%ld): RPA portname=" + "%02x%02x%02x%02x%02x%02x%02x%02x size=%d.\n", __func__, + ha->host_no, ct_req->req.rpa.port_name[0], + ct_req->req.rpa.port_name[1], ct_req->req.rpa.port_name[2], + ct_req->req.rpa.port_name[3], ct_req->req.rpa.port_name[4], + ct_req->req.rpa.port_name[5], ct_req->req.rpa.port_name[6], + ct_req->req.rpa.port_name[7], size)); + DEBUG13(qla2x00_dump_buffer(entries, size)); + + /* Execute MS IOCB */ + rval = qla2x00_issue_iocb(ha, ha->ms_iocb, ha->ms_iocb_dma, + sizeof(ms_iocb_entry_t)); + if (rval != QLA_SUCCESS) { + /*EMPTY*/ + DEBUG2_3(printk("scsi(%ld): RPA issue IOCB failed (%d).\n", + ha->host_no, rval)); + } else if (qla2x00_chk_ms_status(ha, ms_pkt, ct_rsp, "RPA") != + QLA_SUCCESS) { + rval = QLA_FUNCTION_FAILED; + } else { + DEBUG2(printk("scsi(%ld): RPA exiting normally.\n", + ha->host_no)); + } + + return rval; +} + +/** + * qla2x00_fdmi_register() - + * @ha: HA context + * + * Returns 0 on success. + */ +int +qla2x00_fdmi_register(scsi_qla_host_t *ha) +{ + int rval; + + rval = qla2x00_mgmt_svr_login(ha); + if (rval) + return rval; + + rval = qla2x00_fdmi_rhba(ha); + if (rval) { + if (rval != QLA_ALREADY_REGISTERED) + return rval; + + rval = qla2x00_fdmi_dhba(ha); + if (rval) + return rval; + + rval = qla2x00_fdmi_rhba(ha); + if (rval) + return rval; + } + rval = qla2x00_fdmi_rpa(ha); + + return rval; +} diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index a6d2559217cd..c619583e646b 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -88,6 +88,7 @@ qla2x00_initialize_adapter(scsi_qla_host_t *ha) ha->mbx_flags = 0; ha->isp_abort_cnt = 0; ha->beacon_blink_led = 0; + set_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags); qla_printk(KERN_INFO, ha, "Configuring PCI space...\n"); rval = ha->isp_ops.pci_config(ha); @@ -1563,7 +1564,7 @@ qla2x00_nvram_config(scsi_qla_host_t *ha) ha->flags.enable_lip_reset = ((nv->host_p[1] & BIT_1) ? 1 : 0); ha->flags.enable_lip_full_login = ((nv->host_p[1] & BIT_2) ? 1 : 0); ha->flags.enable_target_reset = ((nv->host_p[1] & BIT_3) ? 1 : 0); - ha->flags.enable_led_scheme = ((nv->efi_parameters & BIT_3) ? 1 : 0); + ha->flags.enable_led_scheme = (nv->special_options[1] & BIT_4) ? 1 : 0; ha->operating_mode = (icb->add_firmware_options[0] & (BIT_6 | BIT_5 | BIT_4)) >> 4; @@ -1697,6 +1698,7 @@ qla2x00_alloc_fcport(scsi_qla_host_t *ha, int flags) fcport->iodesc_idx_sent = IODESC_INVALID_INDEX; atomic_set(&fcport->state, FCS_UNCONFIGURED); fcport->flags = FCF_RLC_SUPPORT; + fcport->supported_classes = FC_COS_UNSPECIFIED; return (fcport); } @@ -1898,7 +1900,8 @@ qla2x00_configure_local_loop(scsi_qla_host_t *ha) continue; /* Bypass if not same domain and area of adapter. */ - if (area != ha->d_id.b.area || domain != ha->d_id.b.domain) + if (area && domain && + (area != ha->d_id.b.area || domain != ha->d_id.b.domain)) continue; /* Bypass invalid local loop ID. */ @@ -2075,6 +2078,7 @@ qla2x00_reg_remote_port(scsi_qla_host_t *ha, fc_port_t *fcport) return; } rport->dd_data = fcport; + rport->supported_classes = fcport->supported_classes; rport_ids.roles = FC_RPORT_ROLE_UNKNOWN; if (fcport->port_type == FCT_INITIATOR) @@ -2130,6 +2134,11 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha) return (QLA_SUCCESS); } do { + /* FDMI support. */ + if (ql2xfdmienable && + test_and_clear_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags)) + qla2x00_fdmi_register(ha); + /* Ensure we are logged into the SNS. */ if (IS_QLA24XX(ha) || IS_QLA25XX(ha)) loop_id = NPH_SNS; @@ -2392,6 +2401,12 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports) if (new_fcport->d_id.b24 == ha->d_id.b24) continue; + /* Bypass if same domain and area of adapter. */ + if (((new_fcport->d_id.b24 & 0xffff00) == + (ha->d_id.b24 & 0xffff00)) && ha->current_topology == + ISP_CFG_FL) + continue; + /* Bypass reserved domain fields. */ if ((new_fcport->d_id.b.domain & 0xf0) == 0xf0) continue; @@ -2794,6 +2809,11 @@ qla2x00_fabric_login(scsi_qla_host_t *ha, fc_port_t *fcport, } } + if (mb[10] & BIT_0) + fcport->supported_classes |= FC_COS_CLASS2; + if (mb[10] & BIT_1) + fcport->supported_classes |= FC_COS_CLASS3; + rval = QLA_SUCCESS; break; } else if (mb[0] == MBS_LOOP_ID_USED) { diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index ebdc3c54d155..37f82e2cd7fb 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -810,12 +810,8 @@ qla24xx_start_scsi(srb_t *sp) ha->req_q_cnt = ha->request_q_length - (ha->req_ring_index - cnt); } - if (ha->req_q_cnt < (req_cnt + 2)) { - if (cmd->use_sg) - pci_unmap_sg(ha->pdev, sg, cmd->use_sg, - cmd->sc_data_direction); + if (ha->req_q_cnt < (req_cnt + 2)) goto queuing_error; - } /* Build command packet. */ ha->current_outstanding_cmd = handle; diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index f910de6dd437..c255bb0268a9 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -451,6 +451,8 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) ha->flags.management_server_logged_in = 0; ha->link_data_rate = 0; + if (ql2xfdmienable) + set_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags); /* Update AEN queue. */ qla2x00_enqueue_aen(ha, MBA_LOOP_DOWN, NULL); diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 409ea0ac4032..13e1c9047079 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -19,6 +19,7 @@ #include "qla_def.h" #include <linux/delay.h> +#include <scsi/scsi_transport_fc.h> static void qla2x00_mbx_sem_timeout(unsigned long data) @@ -251,7 +252,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp) mb0 = RD_REG_WORD(®->isp24.mailbox0); ictrl = RD_REG_DWORD(®->isp24.ictrl); } else { - mb0 = RD_MAILBOX_REG(ha, reg->isp, 0); + mb0 = RD_MAILBOX_REG(ha, ®->isp, 0); ictrl = RD_REG_WORD(®->isp.ictrl); } printk("%s(%ld): **** MB Command Timeout for cmd %x ****\n", @@ -983,58 +984,6 @@ qla2x00_abort_target(fc_port_t *fcport) #endif /* - * qla2x00_target_reset - * Issue target reset mailbox command. - * - * Input: - * ha = adapter block pointer. - * TARGET_QUEUE_LOCK must be released. - * ADAPTER_STATE_LOCK must be released. - * - * Returns: - * qla2x00 local function return status code. - * - * Context: - * Kernel context. - */ -int -qla2x00_target_reset(scsi_qla_host_t *ha, struct fc_port *fcport) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - - DEBUG11(printk("qla2x00_target_reset(%ld): entered.\n", ha->host_no);) - - if (atomic_read(&fcport->state) != FCS_ONLINE) - return 0; - - mcp->mb[0] = MBC_TARGET_RESET; - if (HAS_EXTENDED_IDS(ha)) - mcp->mb[1] = fcport->loop_id; - else - mcp->mb[1] = fcport->loop_id << 8; - mcp->mb[2] = ha->loop_reset_delay; - mcp->out_mb = MBX_2|MBX_1|MBX_0; - mcp->in_mb = MBX_0; - mcp->tov = 30; - mcp->flags = 0; - rval = qla2x00_mailbox_command(ha, mcp); - - if (rval != QLA_SUCCESS) { - /*EMPTY*/ - DEBUG2_3_11(printk("qla2x00_target_reset(%ld): failed=%x.\n", - ha->host_no, rval);) - } else { - /*EMPTY*/ - DEBUG11(printk("qla2x00_target_reset(%ld): done.\n", - ha->host_no);) - } - - return rval; -} - -/* * qla2x00_get_adapter_id * Get adapter ID and topology. * @@ -1326,6 +1275,10 @@ qla2x00_get_port_database(scsi_qla_host_t *ha, fc_port_t *fcport, uint8_t opt) fcport->port_type = FCT_INITIATOR; else fcport->port_type = FCT_TARGET; + + /* Passback COS information. */ + fcport->supported_classes = (pd->options & BIT_4) ? + FC_COS_CLASS2: FC_COS_CLASS3; } gpd_error_out: @@ -1661,6 +1614,13 @@ qla24xx_login_fabric(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain, mb[1] |= BIT_1; } else mb[1] = BIT_0; + + /* Passback COS information. */ + mb[10] = 0; + if (lg->io_parameter[7] || lg->io_parameter[8]) + mb[10] |= BIT_0; /* Class 2. */ + if (lg->io_parameter[9] || lg->io_parameter[10]) + mb[10] |= BIT_1; /* Class 3. */ } dma_pool_free(ha->s_dma_pool, lg, lg_dma); @@ -1723,6 +1683,8 @@ qla2x00_login_fabric(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain, mb[2] = mcp->mb[2]; mb[6] = mcp->mb[6]; mb[7] = mcp->mb[7]; + /* COS retrieved from Get-Port-Database mailbox command. */ + mb[10] = 0; } if (rval != QLA_SUCCESS) { @@ -2465,3 +2427,32 @@ qla2x00_set_serdes_params(scsi_qla_host_t *ha, uint16_t sw_em_1g, return rval; } + +int +qla2x00_stop_firmware(scsi_qla_host_t *ha) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + if (!IS_QLA24XX(ha) && !IS_QLA25XX(ha)) + return QLA_FUNCTION_FAILED; + + DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); + + mcp->mb[0] = MBC_STOP_FIRMWARE; + mcp->out_mb = MBX_0; + mcp->in_mb = MBX_0; + mcp->tov = 5; + mcp->flags = 0; + rval = qla2x00_mailbox_command(ha, mcp); + + if (rval != QLA_SUCCESS) { + DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__, + ha->host_no, rval)); + } else { + DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); + } + + return rval; +} diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 9000659bfbcf..8982978c42fd 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -79,7 +79,7 @@ module_param(ql2xloginretrycount, int, S_IRUGO|S_IRUSR); MODULE_PARM_DESC(ql2xloginretrycount, "Specify an alternate value for the NVRAM login retry count."); -int ql2xfwloadbin; +int ql2xfwloadbin=1; module_param(ql2xfwloadbin, int, S_IRUGO|S_IRUSR); MODULE_PARM_DESC(ql2xfwloadbin, "Load ISP2xxx firmware image via hotplug."); @@ -88,6 +88,12 @@ static void qla2x00_free_device(scsi_qla_host_t *); static void qla2x00_config_dma_addressing(scsi_qla_host_t *ha); +int ql2xfdmienable; +module_param(ql2xfdmienable, int, S_IRUGO|S_IRUSR); +MODULE_PARM_DESC(ql2xfdmienable, + "Enables FDMI registratons " + "Default is 0 - no FDMI. 1 - perfom FDMI."); + /* * SCSI host template entry points */ @@ -105,6 +111,9 @@ static int qla2xxx_eh_host_reset(struct scsi_cmnd *); static int qla2x00_loop_reset(scsi_qla_host_t *ha); static int qla2x00_device_reset(scsi_qla_host_t *, fc_port_t *); +static int qla2x00_change_queue_depth(struct scsi_device *, int); +static int qla2x00_change_queue_type(struct scsi_device *, int); + static struct scsi_host_template qla2x00_driver_template = { .module = THIS_MODULE, .name = "qla2xxx", @@ -119,6 +128,8 @@ static struct scsi_host_template qla2x00_driver_template = { .slave_alloc = qla2xxx_slave_alloc, .slave_destroy = qla2xxx_slave_destroy, + .change_queue_depth = qla2x00_change_queue_depth, + .change_queue_type = qla2x00_change_queue_type, .this_id = -1, .cmd_per_lun = 3, .use_clustering = ENABLE_CLUSTERING, @@ -129,6 +140,7 @@ static struct scsi_host_template qla2x00_driver_template = { * which equates to 0x800000 sectors. */ .max_sectors = 0xFFFF, + .shost_attrs = qla2x00_host_attrs, }; static struct scsi_host_template qla24xx_driver_template = { @@ -145,12 +157,15 @@ static struct scsi_host_template qla24xx_driver_template = { .slave_alloc = qla2xxx_slave_alloc, .slave_destroy = qla2xxx_slave_destroy, + .change_queue_depth = qla2x00_change_queue_depth, + .change_queue_type = qla2x00_change_queue_type, .this_id = -1, .cmd_per_lun = 3, .use_clustering = ENABLE_CLUSTERING, .sg_tablesize = SG_ALL, .max_sectors = 0xFFFF, + .shost_attrs = qla2x00_host_attrs, }; static struct scsi_transport_template *qla2xxx_transport_template = NULL; @@ -487,14 +502,13 @@ qc24_fail_command: static int qla2x00_eh_wait_on_command(scsi_qla_host_t *ha, struct scsi_cmnd *cmd) { -#define ABORT_POLLING_PERIOD HZ -#define ABORT_WAIT_ITER ((10 * HZ) / (ABORT_POLLING_PERIOD)) +#define ABORT_POLLING_PERIOD 1000 +#define ABORT_WAIT_ITER ((10 * 1000) / (ABORT_POLLING_PERIOD)) unsigned long wait_iter = ABORT_WAIT_ITER; int ret = QLA_SUCCESS; while (CMD_SP(cmd)) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(ABORT_POLLING_PERIOD); + msleep(ABORT_POLLING_PERIOD); if (--wait_iter) break; @@ -1016,7 +1030,7 @@ qla2x00_loop_reset(scsi_qla_host_t *ha) if (fcport->port_type != FCT_TARGET) continue; - status = qla2x00_target_reset(ha, fcport); + status = qla2x00_device_reset(ha, fcport); if (status != QLA_SUCCESS) break; } @@ -1103,6 +1117,28 @@ qla2xxx_slave_destroy(struct scsi_device *sdev) sdev->hostdata = NULL; } +static int +qla2x00_change_queue_depth(struct scsi_device *sdev, int qdepth) +{ + scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth); + return sdev->queue_depth; +} + +static int +qla2x00_change_queue_type(struct scsi_device *sdev, int tag_type) +{ + if (sdev->tagged_supported) { + scsi_set_tag_type(sdev, tag_type); + if (tag_type) + scsi_activate_tcq(sdev, sdev->queue_depth); + else + scsi_deactivate_tcq(sdev, sdev->queue_depth); + } else + tag_type = 0; + + return tag_type; +} + /** * qla2x00_config_dma_addressing() - Configure OS DMA addressing method. * @ha: HA context @@ -1113,36 +1149,23 @@ qla2xxx_slave_destroy(struct scsi_device *sdev) static void qla2x00_config_dma_addressing(scsi_qla_host_t *ha) { - /* Assume 32bit DMA address */ + /* Assume a 32bit DMA mask. */ ha->flags.enable_64bit_addressing = 0; - /* - * Given the two variants pci_set_dma_mask(), allow the compiler to - * assist in setting the proper dma mask. - */ - if (sizeof(dma_addr_t) > 4) { - if (pci_set_dma_mask(ha->pdev, DMA_64BIT_MASK) == 0) { + if (!dma_set_mask(&ha->pdev->dev, DMA_64BIT_MASK)) { + /* Any upper-dword bits set? */ + if (MSD(dma_get_required_mask(&ha->pdev->dev)) && + !pci_set_consistent_dma_mask(ha->pdev, DMA_64BIT_MASK)) { + /* Ok, a 64bit DMA mask is applicable. */ ha->flags.enable_64bit_addressing = 1; ha->isp_ops.calc_req_entries = qla2x00_calc_iocbs_64; ha->isp_ops.build_iocbs = qla2x00_build_scsi_iocbs_64; - - if (pci_set_consistent_dma_mask(ha->pdev, - DMA_64BIT_MASK)) { - qla_printk(KERN_DEBUG, ha, - "Failed to set 64 bit PCI consistent mask; " - "using 32 bit.\n"); - pci_set_consistent_dma_mask(ha->pdev, - DMA_32BIT_MASK); - } - } else { - qla_printk(KERN_DEBUG, ha, - "Failed to set 64 bit PCI DMA mask, falling back " - "to 32 bit MASK.\n"); - pci_set_dma_mask(ha->pdev, DMA_32BIT_MASK); + return; } - } else { - pci_set_dma_mask(ha->pdev, DMA_32BIT_MASK); } + + dma_set_mask(&ha->pdev->dev, DMA_32BIT_MASK); + pci_set_consistent_dma_mask(ha->pdev, DMA_32BIT_MASK); } static int @@ -1316,6 +1339,7 @@ int qla2x00_probe_one(struct pci_dev *pdev, struct qla_board_info *brd_info) ha->prev_topology = 0; ha->ports = MAX_BUSES; ha->init_cb_size = sizeof(init_cb_t); + ha->mgmt_svr_loop_id = MANAGEMENT_SERVER; /* Assign ISP specific operations. */ ha->isp_ops.pci_config = qla2100_pci_config; @@ -1338,6 +1362,7 @@ int qla2x00_probe_one(struct pci_dev *pdev, struct qla_board_info *brd_info) ha->isp_ops.calc_req_entries = qla2x00_calc_iocbs_32; ha->isp_ops.build_iocbs = qla2x00_build_scsi_iocbs_32; ha->isp_ops.prep_ms_iocb = qla2x00_prep_ms_iocb; + ha->isp_ops.prep_ms_fdmi_iocb = qla2x00_prep_ms_fdmi_iocb; ha->isp_ops.read_nvram = qla2x00_read_nvram_data; ha->isp_ops.write_nvram = qla2x00_write_nvram_data; ha->isp_ops.fw_dump = qla2100_fw_dump; @@ -1375,6 +1400,7 @@ int qla2x00_probe_one(struct pci_dev *pdev, struct qla_board_info *brd_info) ha->response_q_length = RESPONSE_ENTRY_CNT_2300; ha->last_loop_id = SNS_LAST_LOOP_ID_2300; ha->init_cb_size = sizeof(struct init_cb_24xx); + ha->mgmt_svr_loop_id = 10; ha->isp_ops.pci_config = qla24xx_pci_config; ha->isp_ops.reset_chip = qla24xx_reset_chip; ha->isp_ops.chip_diag = qla24xx_chip_diag; @@ -1395,6 +1421,7 @@ int qla2x00_probe_one(struct pci_dev *pdev, struct qla_board_info *brd_info) ha->isp_ops.fabric_login = qla24xx_login_fabric; ha->isp_ops.fabric_logout = qla24xx_fabric_logout; ha->isp_ops.prep_ms_iocb = qla24xx_prep_ms_iocb; + ha->isp_ops.prep_ms_fdmi_iocb = qla24xx_prep_ms_fdmi_iocb; ha->isp_ops.read_nvram = qla24xx_read_nvram_data; ha->isp_ops.write_nvram = qla24xx_write_nvram_data; ha->isp_ops.fw_dump = qla24xx_fw_dump; @@ -1558,8 +1585,6 @@ int qla2x00_probe_one(struct pci_dev *pdev, struct qla_board_info *brd_info) return 0; probe_failed: - fc_remove_host(ha->host); - qla2x00_free_device(ha); scsi_host_put(host); @@ -1601,10 +1626,6 @@ qla2x00_free_device(scsi_qla_host_t *ha) if (!IS_QLA2100(ha) && !IS_QLA2200(ha)) qla2x00_cancel_io_descriptors(ha); - /* turn-off interrupts on the card */ - if (ha->interrupts_on) - ha->isp_ops.disable_intrs(ha); - /* Disable timer */ if (ha->timer_active) qla2x00_stop_timer(ha); @@ -1624,8 +1645,14 @@ qla2x00_free_device(scsi_qla_host_t *ha) } } - qla2x00_mem_free(ha); + /* Stop currently executing firmware. */ + qla2x00_stop_firmware(ha); + + /* turn-off interrupts on the card */ + if (ha->interrupts_on) + ha->isp_ops.disable_intrs(ha); + qla2x00_mem_free(ha); ha->flags.online = 0; @@ -1934,7 +1961,7 @@ qla2x00_mem_free(scsi_qla_host_t *ha) { struct list_head *fcpl, *fcptemp; fc_port_t *fcport; - unsigned long wtime;/* max wait time if mbx cmd is busy. */ + unsigned int wtime;/* max wait time if mbx cmd is busy. */ if (ha == NULL) { /* error */ @@ -1943,11 +1970,9 @@ qla2x00_mem_free(scsi_qla_host_t *ha) } /* Make sure all other threads are stopped. */ - wtime = 60 * HZ; - while (ha->dpc_wait && wtime) { - set_current_state(TASK_INTERRUPTIBLE); - wtime = schedule_timeout(wtime); - } + wtime = 60 * 1000; + while (ha->dpc_wait && wtime) + wtime = msleep_interruptible(wtime); /* free ioctl memory */ qla2x00_free_ioctl_mem(ha); @@ -2478,15 +2503,15 @@ qla2x00_timer(scsi_qla_host_t *ha) int qla2x00_down_timeout(struct semaphore *sema, unsigned long timeout) { - const unsigned int step = HZ/10; + const unsigned int step = 100; /* msecs */ + unsigned int iterations = jiffies_to_msecs(timeout)/100; do { if (!down_trylock(sema)) return 0; - set_current_state(TASK_INTERRUPTIBLE); - if (schedule_timeout(step)) + if (msleep_interruptible(step)) break; - } while ((timeout -= step) > 0); + } while (--iterations >= 0); return -ETIMEDOUT; } diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c index d7f5c608009c..c14abf743b7c 100644 --- a/drivers/scsi/qla2xxx/qla_sup.c +++ b/drivers/scsi/qla2xxx/qla_sup.c @@ -468,21 +468,12 @@ qla24xx_read_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, uint32_t dwords) { uint32_t i; - struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; - - /* Pause RISC. */ - WRT_REG_DWORD(®->hccr, HCCRX_SET_RISC_PAUSE); - RD_REG_DWORD(®->hccr); /* PCI Posting. */ /* Dword reads to flash. */ for (i = 0; i < dwords; i++, faddr++) dwptr[i] = cpu_to_le32(qla24xx_read_flash_dword(ha, flash_data_to_access_addr(faddr))); - /* Release RISC pause. */ - WRT_REG_DWORD(®->hccr, HCCRX_REL_RISC_PAUSE); - RD_REG_DWORD(®->hccr); /* PCI Posting. */ - return dwptr; } @@ -532,10 +523,6 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, ret = QLA_SUCCESS; - /* Pause RISC. */ - WRT_REG_DWORD(®->hccr, HCCRX_SET_RISC_PAUSE); - RD_REG_DWORD(®->hccr); /* PCI Posting. */ - qla24xx_get_flash_manufacturer(ha, &man_id, &flash_id); DEBUG9(printk("%s(%ld): Flash man_id=%d flash_id=%d\n", __func__, ha->host_no, man_id, flash_id)); @@ -599,10 +586,6 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, RD_REG_DWORD(®->ctrl_status) & ~CSRX_FLASH_ENABLE); RD_REG_DWORD(®->ctrl_status); /* PCI Posting. */ - /* Release RISC pause. */ - WRT_REG_DWORD(®->hccr, HCCRX_REL_RISC_PAUSE); - RD_REG_DWORD(®->hccr); /* PCI Posting. */ - return ret; } @@ -630,11 +613,6 @@ qla24xx_read_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr, { uint32_t i; uint32_t *dwptr; - struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; - - /* Pause RISC. */ - WRT_REG_DWORD(®->hccr, HCCRX_SET_RISC_PAUSE); - RD_REG_DWORD(®->hccr); /* PCI Posting. */ /* Dword reads to flash. */ dwptr = (uint32_t *)buf; @@ -642,10 +620,6 @@ qla24xx_read_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr, dwptr[i] = cpu_to_le32(qla24xx_read_flash_dword(ha, nvram_data_to_access_addr(naddr))); - /* Release RISC pause. */ - WRT_REG_DWORD(®->hccr, HCCRX_REL_RISC_PAUSE); - RD_REG_DWORD(®->hccr); /* PCI Posting. */ - return buf; } @@ -690,10 +664,6 @@ qla24xx_write_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr, ret = QLA_SUCCESS; - /* Pause RISC. */ - WRT_REG_DWORD(®->hccr, HCCRX_SET_RISC_PAUSE); - RD_REG_DWORD(®->hccr); /* PCI Posting. */ - /* Enable flash write. */ WRT_REG_DWORD(®->ctrl_status, RD_REG_DWORD(®->ctrl_status) | CSRX_FLASH_ENABLE); @@ -728,9 +698,5 @@ qla24xx_write_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr, RD_REG_DWORD(®->ctrl_status) & ~CSRX_FLASH_ENABLE); RD_REG_DWORD(®->ctrl_status); /* PCI Posting. */ - /* Release RISC pause. */ - WRT_REG_DWORD(®->hccr, HCCRX_REL_RISC_PAUSE); - RD_REG_DWORD(®->hccr); /* PCI Posting. */ - return ret; } diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index e3cd3618bc54..eae7d6edd531 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -19,9 +19,9 @@ /* * Driver version */ -#define QLA2XXX_VERSION "8.01.00b5-k" +#define QLA2XXX_VERSION "8.01.00-k" #define QLA_DRIVER_MAJOR_VER 8 #define QLA_DRIVER_MINOR_VER 1 #define QLA_DRIVER_PATCH_VER 0 -#define QLA_DRIVER_BETA_VER 5 +#define QLA_DRIVER_BETA_VER 0 |