diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-21 07:19:18 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-21 07:19:18 -0700 |
commit | 33cf23b0a535475aead57707cb9f4fe135a93544 (patch) | |
tree | 67e14f77f0eeab847a26a6cbfcb44eecb5fa2fda /drivers/scsi/qla4xxx | |
parent | 7a9b149212f3716c598afe973b6261fd58453b7a (diff) | |
parent | 95bb335c0ebe96afe926387a1ef3a096bd884a82 (diff) | |
download | op-kernel-dev-33cf23b0a535475aead57707cb9f4fe135a93544.zip op-kernel-dev-33cf23b0a535475aead57707cb9f4fe135a93544.tar.gz |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6: (182 commits)
[SCSI] aacraid: add an ifdef'd device delete case instead of taking the device offline
[SCSI] aacraid: prohibit access to array container space
[SCSI] aacraid: add support for handling ATA pass-through commands.
[SCSI] aacraid: expose physical devices for models with newer firmware
[SCSI] aacraid: respond automatically to volumes added by config tool
[SCSI] fcoe: fix fcoe module ref counting
[SCSI] libfcoe: FIP Keep-Alive messages for VPorts are sent with incorrect port_id and wwn
[SCSI] libfcoe: Fix incorrect MAC address clearing
[SCSI] fcoe: fix a circular locking issue with rtnl and sysfs mutex
[SCSI] libfc: Move the port_id into lport
[SCSI] fcoe: move link speed checking into its own routine
[SCSI] libfc: Remove extra pointer check
[SCSI] libfc: Remove unused fc_get_host_port_type
[SCSI] fcoe: fixes wrong error exit in fcoe_create
[SCSI] libfc: set seq_id for incoming sequence
[SCSI] qla2xxx: Updates to ISP82xx support.
[SCSI] qla2xxx: Optionally disable target reset.
[SCSI] qla2xxx: ensure flash operation and host reset via sg_reset are mutually exclusive
[SCSI] qla2xxx: Silence bogus warning by gcc for wrap and did.
[SCSI] qla2xxx: T10 DIF support added.
...
Diffstat (limited to 'drivers/scsi/qla4xxx')
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_def.h | 48 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_fw.h | 46 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_glbl.h | 8 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_init.c | 374 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_iocb.c | 2 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_isr.c | 23 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_mbx.c | 337 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_os.c | 135 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_version.h | 3 |
9 files changed, 756 insertions, 220 deletions
diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h index 81b5f29..4288026 100644 --- a/drivers/scsi/qla4xxx/ql4_def.h +++ b/drivers/scsi/qla4xxx/ql4_def.h @@ -114,6 +114,7 @@ */ #define MAC_ADDR_LEN 6 /* in bytes */ #define IP_ADDR_LEN 4 /* in bytes */ +#define IPv6_ADDR_LEN 16 /* IPv6 address size */ #define DRIVER_NAME "qla4xxx" #define MAX_LINKED_CMDS_PER_LUN 3 @@ -147,6 +148,8 @@ #define MAX_RESET_HA_RETRIES 2 +#define CMD_SP(Cmnd) ((Cmnd)->SCp.ptr) + /* * SCSI Request Block structure (srb) that is placed * on cmd->SCp location of every I/O [We have 22 bytes available] @@ -169,7 +172,7 @@ struct srb { struct scsi_cmnd *cmd; /* (4) SCSI command block */ dma_addr_t dma_handle; /* (4) for unmap of single transfers */ - atomic_t ref_count; /* reference count for this srb */ + struct kref srb_ref; /* reference count for this srb */ uint32_t fw_ddb_index; uint8_t err_id; /* error id */ #define SRB_ERR_PORT 1 /* Request failed because "port down" */ @@ -220,7 +223,7 @@ struct ddb_entry { uint16_t os_target_id; /* Target ID */ uint16_t fw_ddb_index; /* DDB firmware index */ - uint8_t reserved[2]; + uint16_t options; uint32_t fw_ddb_device_state; /* F/W Device State -- see ql4_fw.h */ uint32_t CmdSn; @@ -245,10 +248,18 @@ struct ddb_entry { uint16_t port; uint32_t tpgt; - uint8_t ip_addr[ISCSI_IPADDR_SIZE]; + uint8_t ip_addr[IP_ADDR_LEN]; uint8_t iscsi_name[ISCSI_NAME_SIZE]; /* 72 x48 */ uint8_t iscsi_alias[0x20]; uint8_t isid[6]; + uint16_t iscsi_max_burst_len; + uint16_t iscsi_max_outsnd_r2t; + uint16_t iscsi_first_burst_len; + uint16_t iscsi_max_rcv_data_seg_len; + uint16_t iscsi_max_snd_data_seg_len; + + struct in6_addr remote_ipv6_addr; + struct in6_addr link_local_ipv6_addr; }; /* @@ -301,6 +312,7 @@ struct scsi_qla_host { #define DPC_ISNS_RESTART 7 /* 0x00000080 */ #define DPC_AEN 9 /* 0x00000200 */ #define DPC_GET_DHCP_IP_ADDR 15 /* 0x00008000 */ +#define DPC_LINK_CHANGED 18 /* 0x00040000 */ struct Scsi_Host *host; /* pointer to host data */ uint32_t tot_ddbs; @@ -320,8 +332,7 @@ struct scsi_qla_host { #define MIN_IOBASE_LEN 0x100 uint16_t req_q_count; - uint8_t marker_needed; - uint8_t rsvd1; + uint8_t rsvd1[2]; unsigned long host_no; @@ -441,8 +452,35 @@ struct scsi_qla_host { /* Saved srb for status continuation entry processing */ struct srb *status_srb; + + /* IPv6 support info from InitFW */ + uint8_t acb_version; + uint8_t ipv4_addr_state; + uint16_t ipv4_options; + + uint32_t resvd2; + uint32_t ipv6_options; + uint32_t ipv6_addl_options; + uint8_t ipv6_link_local_state; + uint8_t ipv6_addr0_state; + uint8_t ipv6_addr1_state; + uint8_t ipv6_default_router_state; + struct in6_addr ipv6_link_local_addr; + struct in6_addr ipv6_addr0; + struct in6_addr ipv6_addr1; + struct in6_addr ipv6_default_router_addr; }; +static inline int is_ipv4_enabled(struct scsi_qla_host *ha) +{ + return ((ha->ipv4_options & IPOPT_IPv4_PROTOCOL_ENABLE) != 0); +} + +static inline int is_ipv6_enabled(struct scsi_qla_host *ha) +{ + return ((ha->ipv6_options & IPV6_OPT_IPV6_PROTOCOL_ENABLE) != 0); +} + static inline int is_qla4010(struct scsi_qla_host *ha) { return ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP4010; diff --git a/drivers/scsi/qla4xxx/ql4_fw.h b/drivers/scsi/qla4xxx/ql4_fw.h index 9cd7a60..855226e 100644 --- a/drivers/scsi/qla4xxx/ql4_fw.h +++ b/drivers/scsi/qla4xxx/ql4_fw.h @@ -215,6 +215,7 @@ union external_hw_config_reg { /* Mailbox command definitions */ #define MBOX_CMD_ABOUT_FW 0x0009 #define MBOX_CMD_PING 0x000B +#define MBOX_CMD_ABORT_TASK 0x0015 #define MBOX_CMD_LUN_RESET 0x0016 #define MBOX_CMD_TARGET_WARM_RESET 0x0017 #define MBOX_CMD_GET_MANAGEMENT_DATA 0x001E @@ -258,13 +259,15 @@ union external_hw_config_reg { /* Mailbox 1 */ #define FW_STATE_READY 0x0000 #define FW_STATE_CONFIG_WAIT 0x0001 -#define FW_STATE_WAIT_LOGIN 0x0002 +#define FW_STATE_WAIT_AUTOCONNECT 0x0002 #define FW_STATE_ERROR 0x0004 -#define FW_STATE_DHCP_IN_PROGRESS 0x0008 +#define FW_STATE_CONFIGURING_IP 0x0008 /* Mailbox 3 */ #define FW_ADDSTATE_OPTICAL_MEDIA 0x0001 -#define FW_ADDSTATE_DHCP_ENABLED 0x0002 +#define FW_ADDSTATE_DHCPv4_ENABLED 0x0002 +#define FW_ADDSTATE_DHCPv4_LEASE_ACQUIRED 0x0004 +#define FW_ADDSTATE_DHCPv4_LEASE_EXPIRED 0x0008 #define FW_ADDSTATE_LINK_UP 0x0010 #define FW_ADDSTATE_ISNS_SVC_ENABLED 0x0020 #define MBOX_CMD_GET_DATABASE_ENTRY_DEFAULTS 0x006B @@ -320,6 +323,8 @@ union external_hw_config_reg { /* Host Adapter Initialization Control Block (from host) */ struct addr_ctrl_blk { uint8_t version; /* 00 */ +#define IFCB_VER_MIN 0x01 +#define IFCB_VER_MAX 0x02 uint8_t control; /* 01 */ uint16_t fw_options; /* 02-03 */ @@ -351,11 +356,16 @@ struct addr_ctrl_blk { uint16_t iscsi_opts; /* 30-31 */ uint16_t ipv4_tcp_opts; /* 32-33 */ uint16_t ipv4_ip_opts; /* 34-35 */ +#define IPOPT_IPv4_PROTOCOL_ENABLE 0x8000 uint16_t iscsi_max_pdu_size; /* 36-37 */ uint8_t ipv4_tos; /* 38 */ uint8_t ipv4_ttl; /* 39 */ uint8_t acb_version; /* 3A */ +#define ACB_NOT_SUPPORTED 0x00 +#define ACB_SUPPORTED 0x02 /* Capable of ACB Version 2 + Features */ + uint8_t res2; /* 3B */ uint16_t def_timeout; /* 3C-3D */ uint16_t iscsi_fburst_len; /* 3E-3F */ @@ -397,16 +407,35 @@ struct addr_ctrl_blk { uint32_t cookie; /* 200-203 */ uint16_t ipv6_port; /* 204-205 */ uint16_t ipv6_opts; /* 206-207 */ +#define IPV6_OPT_IPV6_PROTOCOL_ENABLE 0x8000 + uint16_t ipv6_addtl_opts; /* 208-209 */ +#define IPV6_ADDOPT_NEIGHBOR_DISCOVERY_ADDR_ENABLE 0x0002 /* Pri ACB + Only */ +#define IPV6_ADDOPT_AUTOCONFIG_LINK_LOCAL_ADDR 0x0001 + uint16_t ipv6_tcp_opts; /* 20A-20B */ uint8_t ipv6_tcp_wsf; /* 20C */ uint16_t ipv6_flow_lbl; /* 20D-20F */ - uint8_t ipv6_gw_addr[16]; /* 210-21F */ + uint8_t ipv6_dflt_rtr_addr[16]; /* 210-21F */ uint16_t ipv6_vlan_tag; /* 220-221 */ uint8_t ipv6_lnk_lcl_addr_state;/* 222 */ uint8_t ipv6_addr0_state; /* 223 */ uint8_t ipv6_addr1_state; /* 224 */ - uint8_t ipv6_gw_state; /* 225 */ +#define IP_ADDRSTATE_UNCONFIGURED 0 +#define IP_ADDRSTATE_INVALID 1 +#define IP_ADDRSTATE_ACQUIRING 2 +#define IP_ADDRSTATE_TENTATIVE 3 +#define IP_ADDRSTATE_DEPRICATED 4 +#define IP_ADDRSTATE_PREFERRED 5 +#define IP_ADDRSTATE_DISABLING 6 + + uint8_t ipv6_dflt_rtr_state; /* 225 */ +#define IPV6_RTRSTATE_UNKNOWN 0 +#define IPV6_RTRSTATE_MANUAL 1 +#define IPV6_RTRSTATE_ADVERTISED 3 +#define IPV6_RTRSTATE_STALE 4 + uint8_t ipv6_traffic_class; /* 226 */ uint8_t ipv6_hop_limit; /* 227 */ uint8_t ipv6_if_id[8]; /* 228-22F */ @@ -424,7 +453,7 @@ struct addr_ctrl_blk { struct init_fw_ctrl_blk { struct addr_ctrl_blk pri; - struct addr_ctrl_blk sec; +/* struct addr_ctrl_blk sec;*/ }; /*************************************************************************/ @@ -433,6 +462,9 @@ struct dev_db_entry { uint16_t options; /* 00-01 */ #define DDB_OPT_DISC_SESSION 0x10 #define DDB_OPT_TARGET 0x02 /* device is a target */ +#define DDB_OPT_IPV6_DEVICE 0x100 +#define DDB_OPT_IPV6_NULL_LINK_LOCAL 0x800 /* post connection */ +#define DDB_OPT_IPV6_FW_DEFINED_LINK_LOCAL 0x800 /* pre connection */ uint16_t exec_throttle; /* 02-03 */ uint16_t exec_count; /* 04-05 */ @@ -468,7 +500,7 @@ struct dev_db_entry { * pointer to a string so we * don't have to reserve soooo * much RAM */ - uint8_t ipv6_addr[0x10];/* 1A0-1AF */ + uint8_t link_local_ipv6_addr[0x10]; /* 1A0-1AF */ uint8_t res5[0x10]; /* 1B0-1BF */ uint16_t ddb_link; /* 1C0-1C1 */ uint16_t chap_tbl_idx; /* 1C2-1C3 */ diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h index 96ebfb0..c4636f6 100644 --- a/drivers/scsi/qla4xxx/ql4_glbl.h +++ b/drivers/scsi/qla4xxx/ql4_glbl.h @@ -25,6 +25,7 @@ void qla4xxx_process_aen(struct scsi_qla_host * ha, uint8_t process_aen); int qla4xxx_get_dhcp_ip_address(struct scsi_qla_host * ha); int qla4xxx_relogin_device(struct scsi_qla_host * ha, struct ddb_entry * ddb_entry); +int qla4xxx_abort_task(struct scsi_qla_host *ha, struct srb *srb); int qla4xxx_reset_lun(struct scsi_qla_host * ha, struct ddb_entry * ddb_entry, int lun); int qla4xxx_reset_target(struct scsi_qla_host * ha, @@ -65,13 +66,14 @@ void qla4xxx_interrupt_service_routine(struct scsi_qla_host * ha, int qla4xxx_init_rings(struct scsi_qla_host * ha); struct srb * qla4xxx_del_from_active_array(struct scsi_qla_host *ha, uint32_t index); -void qla4xxx_srb_compl(struct scsi_qla_host *ha, struct srb *srb); +void qla4xxx_srb_compl(struct kref *ref); int qla4xxx_reinitialize_ddb_list(struct scsi_qla_host * ha); -int qla4xxx_process_ddb_changed(struct scsi_qla_host * ha, - uint32_t fw_ddb_index, uint32_t state); +int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, uint32_t fw_ddb_index, + uint32_t state, uint32_t conn_error); void qla4xxx_dump_buffer(void *b, uint32_t size); int qla4xxx_send_marker_iocb(struct scsi_qla_host *ha, struct ddb_entry *ddb_entry, int lun, uint16_t mrkr_mod); +int qla4_is_relogin_allowed(struct scsi_qla_host *ha, uint32_t conn_err); extern int ql4xextended_error_logging; extern int ql4xdiscoverywait; diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c index 92329a4..5510df8 100644 --- a/drivers/scsi/qla4xxx/ql4_init.c +++ b/drivers/scsi/qla4xxx/ql4_init.c @@ -189,6 +189,78 @@ static int qla4xxx_init_local_data(struct scsi_qla_host *ha) return qla4xxx_get_firmware_status(ha); } +static uint8_t +qla4xxx_wait_for_ip_config(struct scsi_qla_host *ha) +{ + uint8_t ipv4_wait = 0; + uint8_t ipv6_wait = 0; + int8_t ip_address[IPv6_ADDR_LEN] = {0} ; + + /* If both IPv4 & IPv6 are enabled, possibly only one + * IP address may be acquired, so check to see if we + * need to wait for another */ + if (is_ipv4_enabled(ha) && is_ipv6_enabled(ha)) { + if (((ha->addl_fw_state & FW_ADDSTATE_DHCPv4_ENABLED) != 0) && + ((ha->addl_fw_state & + FW_ADDSTATE_DHCPv4_LEASE_ACQUIRED) == 0)) { + ipv4_wait = 1; + } + if (((ha->ipv6_addl_options & + IPV6_ADDOPT_NEIGHBOR_DISCOVERY_ADDR_ENABLE) != 0) && + ((ha->ipv6_link_local_state == IP_ADDRSTATE_ACQUIRING) || + (ha->ipv6_addr0_state == IP_ADDRSTATE_ACQUIRING) || + (ha->ipv6_addr1_state == IP_ADDRSTATE_ACQUIRING))) { + + ipv6_wait = 1; + + if ((ha->ipv6_link_local_state == + IP_ADDRSTATE_PREFERRED) || + (ha->ipv6_addr0_state == IP_ADDRSTATE_PREFERRED) || + (ha->ipv6_addr1_state == IP_ADDRSTATE_PREFERRED)) { + DEBUG2(printk(KERN_INFO "scsi%ld: %s: " + "Preferred IP configured." + " Don't wait!\n", ha->host_no, + __func__)); + ipv6_wait = 0; + } + if (memcmp(&ha->ipv6_default_router_addr, ip_address, + IPv6_ADDR_LEN) == 0) { + DEBUG2(printk(KERN_INFO "scsi%ld: %s: " + "No Router configured. " + "Don't wait!\n", ha->host_no, + __func__)); + ipv6_wait = 0; + } + if ((ha->ipv6_default_router_state == + IPV6_RTRSTATE_MANUAL) && + (ha->ipv6_link_local_state == + IP_ADDRSTATE_TENTATIVE) && + (memcmp(&ha->ipv6_link_local_addr, + &ha->ipv6_default_router_addr, 4) == 0)) { + DEBUG2(printk("scsi%ld: %s: LinkLocal Router & " + "IP configured. Don't wait!\n", + ha->host_no, __func__)); + ipv6_wait = 0; + } + } + if (ipv4_wait || ipv6_wait) { + DEBUG2(printk("scsi%ld: %s: Wait for additional " + "IP(s) \"", ha->host_no, __func__)); + if (ipv4_wait) + DEBUG2(printk("IPv4 ")); + if (ha->ipv6_link_local_state == IP_ADDRSTATE_ACQUIRING) + DEBUG2(printk("IPv6LinkLocal ")); + if (ha->ipv6_addr0_state == IP_ADDRSTATE_ACQUIRING) + DEBUG2(printk("IPv6Addr0 ")); + if (ha->ipv6_addr1_state == IP_ADDRSTATE_ACQUIRING) + DEBUG2(printk("IPv6Addr1 ")); + DEBUG2(printk("\"\n")); + } + } + + return ipv4_wait|ipv6_wait; +} + static int qla4xxx_fw_ready(struct scsi_qla_host *ha) { uint32_t timeout_count; @@ -226,38 +298,80 @@ static int qla4xxx_fw_ready(struct scsi_qla_host *ha) continue; } + if (ha->firmware_state & FW_STATE_WAIT_AUTOCONNECT) { + DEBUG2(printk(KERN_INFO "scsi%ld: %s: fwstate:" + "AUTOCONNECT in progress\n", + ha->host_no, __func__)); + } + + if (ha->firmware_state & FW_STATE_CONFIGURING_IP) { + DEBUG2(printk(KERN_INFO "scsi%ld: %s: fwstate:" + " CONFIGURING IP\n", + ha->host_no, __func__)); + /* + * Check for link state after 15 secs and if link is + * still DOWN then, cable is unplugged. Ignore "DHCP + * in Progress/CONFIGURING IP" bit to check if firmware + * is in ready state or not after 15 secs. + * This is applicable for both 2.x & 3.x firmware + */ + if (timeout_count <= (ADAPTER_INIT_TOV - 15)) { + if (ha->addl_fw_state & FW_ADDSTATE_LINK_UP) { + DEBUG2(printk(KERN_INFO "scsi%ld: %s:" + " LINK UP (Cable plugged)\n", + ha->host_no, __func__)); + } else if (ha->firmware_state & + (FW_STATE_CONFIGURING_IP | + FW_STATE_READY)) { + DEBUG2(printk(KERN_INFO "scsi%ld: %s: " + "LINK DOWN (Cable unplugged)\n", + ha->host_no, __func__)); + ha->firmware_state = FW_STATE_READY; + } + } + } + if (ha->firmware_state == FW_STATE_READY) { - DEBUG2(dev_info(&ha->pdev->dev, "Firmware Ready..\n")); - /* The firmware is ready to process SCSI commands. */ - DEBUG2(dev_info(&ha->pdev->dev, - "scsi%ld: %s: MEDIA TYPE - %s\n", - ha->host_no, - __func__, (ha->addl_fw_state & - FW_ADDSTATE_OPTICAL_MEDIA) - != 0 ? "OPTICAL" : "COPPER")); - DEBUG2(dev_info(&ha->pdev->dev, - "scsi%ld: %s: DHCP STATE Enabled " - "%s\n", - ha->host_no, __func__, - (ha->addl_fw_state & - FW_ADDSTATE_DHCP_ENABLED) != 0 ? - "YES" : "NO")); - DEBUG2(dev_info(&ha->pdev->dev, - "scsi%ld: %s: LINK %s\n", - ha->host_no, __func__, - (ha->addl_fw_state & - FW_ADDSTATE_LINK_UP) != 0 ? - "UP" : "DOWN")); - DEBUG2(dev_info(&ha->pdev->dev, - "scsi%ld: %s: iSNS Service " - "Started %s\n", - ha->host_no, __func__, - (ha->addl_fw_state & - FW_ADDSTATE_ISNS_SVC_ENABLED) != 0 ? - "YES" : "NO")); - - ready = 1; - break; + /* If DHCP IP Addr is available, retrieve it now. */ + if (test_and_clear_bit(DPC_GET_DHCP_IP_ADDR, + &ha->dpc_flags)) + qla4xxx_get_dhcp_ip_address(ha); + + if (!qla4xxx_wait_for_ip_config(ha) || + timeout_count == 1) { + DEBUG2(dev_info(&ha->pdev->dev, + "Firmware Ready..\n")); + /* The firmware is ready to process SCSI + commands. */ + DEBUG2(dev_info(&ha->pdev->dev, + "scsi%ld: %s: MEDIA TYPE" + " - %s\n", ha->host_no, + __func__, (ha->addl_fw_state & + FW_ADDSTATE_OPTICAL_MEDIA) + != 0 ? "OPTICAL" : "COPPER")); + DEBUG2(dev_info(&ha->pdev->dev, + "scsi%ld: %s: DHCPv4 STATE" + " Enabled %s\n", ha->host_no, + __func__, (ha->addl_fw_state & + FW_ADDSTATE_DHCPv4_ENABLED) != 0 ? + "YES" : "NO")); + DEBUG2(dev_info(&ha->pdev->dev, + "scsi%ld: %s: LINK %s\n", + ha->host_no, __func__, + (ha->addl_fw_state & + FW_ADDSTATE_LINK_UP) != 0 ? + "UP" : "DOWN")); + DEBUG2(dev_info(&ha->pdev->dev, + "scsi%ld: %s: iSNS Service " + "Started %s\n", + ha->host_no, __func__, + (ha->addl_fw_state & + FW_ADDSTATE_ISNS_SVC_ENABLED) != 0 ? + "YES" : "NO")); + + ready = 1; + break; + } } DEBUG2(printk("scsi%ld: %s: waiting on fw, state=%x:%x - " "seconds expired= %d\n", ha->host_no, __func__, @@ -272,15 +386,19 @@ static int qla4xxx_fw_ready(struct scsi_qla_host *ha) msleep(1000); } /* end of for */ - if (timeout_count == 0) + if (timeout_count <= 0) DEBUG2(printk("scsi%ld: %s: FW Initialization timed out!\n", ha->host_no, __func__)); - if (ha->firmware_state & FW_STATE_DHCP_IN_PROGRESS) { - DEBUG2(printk("scsi%ld: %s: FW is reporting its waiting to" - " grab an IP address from DHCP server\n", - ha->host_no, __func__)); + if (ha->firmware_state & FW_STATE_CONFIGURING_IP) { + DEBUG2(printk("scsi%ld: %s: FW initialized, but is reporting " + "it's waiting to configure an IP address\n", + ha->host_no, __func__)); ready = 1; + } else if (ha->firmware_state & FW_STATE_WAIT_AUTOCONNECT) { + DEBUG2(printk("scsi%ld: %s: FW initialized, but " + "auto-discovery still in process\n", + ha->host_no, __func__)); } return ready; @@ -387,6 +505,7 @@ static int qla4xxx_update_ddb_entry(struct scsi_qla_host *ha, struct dev_db_entry *fw_ddb_entry = NULL; dma_addr_t fw_ddb_entry_dma; int status = QLA_ERROR; + uint32_t conn_err; if (ddb_entry == NULL) { DEBUG2(printk("scsi%ld: %s: ddb_entry is NULL\n", ha->host_no, @@ -407,7 +526,7 @@ static int qla4xxx_update_ddb_entry(struct scsi_qla_host *ha, if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index, fw_ddb_entry, fw_ddb_entry_dma, NULL, NULL, - &ddb_entry->fw_ddb_device_state, NULL, + &ddb_entry->fw_ddb_device_state, &conn_err, &ddb_entry->tcp_source_port_num, &ddb_entry->connection_id) == QLA_ERROR) { @@ -419,6 +538,7 @@ static int qla4xxx_update_ddb_entry(struct scsi_qla_host *ha, } status = QLA_SUCCESS; + ddb_entry->options = le16_to_cpu(fw_ddb_entry->options); ddb_entry->target_session_id = le16_to_cpu(fw_ddb_entry->tsid); ddb_entry->task_mgmt_timeout = le16_to_cpu(fw_ddb_entry->def_timeout); @@ -442,11 +562,44 @@ static int qla4xxx_update_ddb_entry(struct scsi_qla_host *ha, memcpy(&ddb_entry->ip_addr[0], &fw_ddb_entry->ip_addr[0], min(sizeof(ddb_entry->ip_addr), sizeof(fw_ddb_entry->ip_addr))); - DEBUG2(printk("scsi%ld: %s: ddb[%d] - State= %x status= %d.\n", - ha->host_no, __func__, fw_ddb_index, - ddb_entry->fw_ddb_device_state, status)); - - exit_update_ddb: + ddb_entry->iscsi_max_burst_len = fw_ddb_entry->iscsi_max_burst_len; + ddb_entry->iscsi_max_outsnd_r2t = fw_ddb_entry->iscsi_max_outsnd_r2t; + ddb_entry->iscsi_first_burst_len = fw_ddb_entry->iscsi_first_burst_len; + ddb_entry->iscsi_max_rcv_data_seg_len = + fw_ddb_entry->iscsi_max_rcv_data_seg_len; + ddb_entry->iscsi_max_snd_data_seg_len = + fw_ddb_entry->iscsi_max_snd_data_seg_len; + + if (ddb_entry->options & DDB_OPT_IPV6_DEVICE) { + memcpy(&ddb_entry->remote_ipv6_addr, + fw_ddb_entry->ip_addr, + min(sizeof(ddb_entry->remote_ipv6_addr), + sizeof(fw_ddb_entry->ip_addr))); + memcpy(&ddb_entry->link_local_ipv6_addr, + fw_ddb_entry->link_local_ipv6_addr, + min(sizeof(ddb_entry->link_local_ipv6_addr), + sizeof(fw_ddb_entry->link_local_ipv6_addr))); + + DEBUG2(dev_info(&ha->pdev->dev, "%s: DDB[%d] osIdx = %d " + "State %04x ConnErr %08x IP %pI6 " + ":%04d \"%s\"\n", + __func__, fw_ddb_index, + ddb_entry->os_target_id, + ddb_entry->fw_ddb_device_state, + conn_err, fw_ddb_entry->ip_addr, + le16_to_cpu(fw_ddb_entry->port), + fw_ddb_entry->iscsi_name)); + } else + DEBUG2(dev_info(&ha->pdev->dev, "%s: DDB[%d] osIdx = %d " + "State %04x ConnErr %08x IP %pI4 " + ":%04d \"%s\"\n", + __func__, fw_ddb_index, + ddb_entry->os_target_id, + ddb_entry->fw_ddb_device_state, + conn_err, fw_ddb_entry->ip_addr, + le16_to_cpu(fw_ddb_entry->port), + fw_ddb_entry->iscsi_name)); +exit_update_ddb: if (fw_ddb_entry) dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), fw_ddb_entry, fw_ddb_entry_dma); @@ -492,6 +645,40 @@ static struct ddb_entry * qla4xxx_alloc_ddb(struct scsi_qla_host *ha, } /** + * qla4_is_relogin_allowed - Are we allowed to login? + * @ha: Pointer to host adapter structure. + * @conn_err: Last connection error associated with the ddb + * + * This routine tests the given connection error to determine if + * we are allowed to login. + **/ +int qla4_is_relogin_allowed(struct scsi_qla_host *ha, uint32_t conn_err) +{ + uint32_t err_code, login_rsp_sts_class; + int relogin = 1; + + err_code = ((conn_err & 0x00ff0000) >> 16); + login_rsp_sts_class = ((conn_err & 0x0000ff00) >> 8); + if (err_code == 0x1c || err_code == 0x06) { + DEBUG2(dev_info(&ha->pdev->dev, + ": conn_err=0x%08x, send target completed" + " or access denied failure\n", conn_err)); + relogin = 0; + } + if ((err_code == 0x08) && (login_rsp_sts_class == 0x02)) { + /* Login Response PDU returned an error. + Login Response Status in Error Code Detail + indicates login should not be retried.*/ + DEBUG2(dev_info(&ha->pdev->dev, + ": conn_err=0x%08x, do not retry relogin\n", + conn_err)); + relogin = 0; + } + + return relogin; +} + +/** * qla4xxx_configure_ddbs - builds driver ddb list * @ha: Pointer to host adapter structure. * @@ -505,18 +692,30 @@ static int qla4xxx_build_ddb_list(struct scsi_qla_host *ha) uint32_t fw_ddb_index = 0; uint32_t next_fw_ddb_index = 0; uint32_t ddb_state; - uint32_t conn_err, err_code; + uint32_t conn_err; struct ddb_entry *ddb_entry; + struct dev_db_entry *fw_ddb_entry = NULL; + dma_addr_t fw_ddb_entry_dma; + uint32_t ipv6_device; uint32_t new_tgt; + fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), + &fw_ddb_entry_dma, GFP_KERNEL); + if (fw_ddb_entry == NULL) { + DEBUG2(dev_info(&ha->pdev->dev, "%s: DMA alloc failed\n", + __func__)); + return QLA_ERROR; + } + dev_info(&ha->pdev->dev, "Initializing DDBs ...\n"); for (fw_ddb_index = 0; fw_ddb_index < MAX_DDB_ENTRIES; fw_ddb_index = next_fw_ddb_index) { /* First, let's see if a device exists here */ - if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index, NULL, 0, NULL, - &next_fw_ddb_index, &ddb_state, - &conn_err, NULL, NULL) == - QLA_ERROR) { + if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index, fw_ddb_entry, + 0, NULL, &next_fw_ddb_index, + &ddb_state, &conn_err, + NULL, NULL) == + QLA_ERROR) { DEBUG2(printk("scsi%ld: %s: get_ddb_entry, " "fw_ddb_index %d failed", ha->host_no, __func__, fw_ddb_index)); @@ -533,18 +732,19 @@ static int qla4xxx_build_ddb_list(struct scsi_qla_host *ha) /* Try and login to device */ DEBUG2(printk("scsi%ld: %s: Login to DDB[%d]\n", ha->host_no, __func__, fw_ddb_index)); - err_code = ((conn_err & 0x00ff0000) >> 16); - if (err_code == 0x1c || err_code == 0x06) { - DEBUG2(printk("scsi%ld: %s send target " - "completed " - "or access denied failure\n", - ha->host_no, __func__)); - } else { + ipv6_device = le16_to_cpu(fw_ddb_entry->options) & + DDB_OPT_IPV6_DEVICE; + if (qla4_is_relogin_allowed(ha, conn_err) && + ((!ipv6_device && + *((uint32_t *)fw_ddb_entry->ip_addr)) + || ipv6_device)) { qla4xxx_set_ddb_entry(ha, fw_ddb_index, 0); if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index, - NULL, 0, NULL, &next_fw_ddb_index, - &ddb_state, &conn_err, NULL, NULL) - == QLA_ERROR) { + NULL, 0, NULL, + &next_fw_ddb_index, + &ddb_state, &conn_err, + NULL, NULL) + == QLA_ERROR) { DEBUG2(printk("scsi%ld: %s:" "get_ddb_entry %d failed\n", ha->host_no, @@ -599,7 +799,6 @@ next_one: struct qla4_relog_scan { int halt_wait; uint32_t conn_err; - uint32_t err_code; uint32_t fw_ddb_index; uint32_t next_fw_ddb_index; uint32_t fw_ddb_device_state; @@ -609,18 +808,7 @@ static int qla4_test_rdy(struct scsi_qla_host *ha, struct qla4_relog_scan *rs) { struct ddb_entry *ddb_entry; - /* - * Don't want to do a relogin if connection - * error is 0x1c. - */ - rs->err_code = ((rs->conn_err & 0x00ff0000) >> 16); - if (rs->err_code == 0x1c || rs->err_code == 0x06) { - DEBUG2(printk( - "scsi%ld: %s send target" - " completed or " - "access denied failure\n", - ha->host_no, __func__)); - } else { + if (qla4_is_relogin_allowed(ha, rs->conn_err)) { /* We either have a device that is in * the process of relogging in or a * device that is waiting to be @@ -908,7 +1096,7 @@ static void qla4x00_pci_config(struct scsi_qla_host *ha) static int qla4xxx_start_firmware_from_flash(struct scsi_qla_host *ha) { int status = QLA_ERROR; - uint32_t max_wait_time; + unsigned long max_wait_time; unsigned long flags; uint32_t mbox_status; @@ -940,7 +1128,10 @@ static int qla4xxx_start_firmware_from_flash(struct scsi_qla_host *ha) spin_unlock_irqrestore(&ha->hardware_lock, flags); /* Wait for firmware to come UP. */ - max_wait_time = FIRMWARE_UP_TOV * 4; + DEBUG2(printk(KERN_INFO "scsi%ld: %s: Wait up to %d seconds for " + "boot firmware to complete...\n", + ha->host_no, __func__, FIRMWARE_UP_TOV)); + max_wait_time = jiffies + (FIRMWARE_UP_TOV * HZ); do { uint32_t ctrl_status; @@ -954,16 +1145,15 @@ static int qla4xxx_start_firmware_from_flash(struct scsi_qla_host *ha) if (mbox_status == MBOX_STS_COMMAND_COMPLETE) break; - DEBUG2(printk("scsi%ld: %s: Waiting for boot firmware to " - "complete... ctrl_sts=0x%x, remaining=%d\n", - ha->host_no, __func__, ctrl_status, - max_wait_time)); + DEBUG2(printk(KERN_INFO "scsi%ld: %s: Waiting for boot " + "firmware to complete... ctrl_sts=0x%x\n", + ha->host_no, __func__, ctrl_status)); - msleep(250); - } while ((max_wait_time--)); + msleep_interruptible(250); + } while (!time_after_eq(jiffies, max_wait_time)); if (mbox_status == MBOX_STS_COMMAND_COMPLETE) { - DEBUG(printk("scsi%ld: %s: Firmware has started\n", + DEBUG(printk(KERN_INFO "scsi%ld: %s: Firmware has started\n", ha->host_no, __func__)); spin_lock_irqsave(&ha->hardware_lock, flags); @@ -1141,6 +1331,7 @@ int qla4xxx_initialize_adapter(struct scsi_qla_host *ha, int status = QLA_ERROR; int8_t ip_address[IP_ADDR_LEN] = {0} ; + clear_bit(AF_ONLINE, &ha->flags); ha->eeprom_cmd_data = 0; qla4x00_pci_config(ha); @@ -1166,7 +1357,7 @@ int qla4xxx_initialize_adapter(struct scsi_qla_host *ha, * the ddb_list and wait for DHCP lease acquired aen to come in * followed by 0x8014 aen" to trigger the tgt discovery process. */ - if (ha->firmware_state & FW_STATE_DHCP_IN_PROGRESS) + if (ha->firmware_state & FW_STATE_CONFIGURING_IP) goto exit_init_online; /* Skip device discovery if ip and subnet is zero */ @@ -1270,8 +1461,8 @@ static void qla4xxx_add_device_dynamically(struct scsi_qla_host *ha, * * This routine processes a Decive Database Changed AEN Event. **/ -int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, - uint32_t fw_ddb_index, uint32_t state) +int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, uint32_t fw_ddb_index, + uint32_t state, uint32_t conn_err) { struct ddb_entry * ddb_entry; uint32_t old_fw_ddb_device_state; @@ -1318,19 +1509,24 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, * the device came back. */ } else { - /* Device went away, try to relogin. */ - /* Mark device missing */ - if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE) + /* Device went away, mark device missing */ + if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE) { + DEBUG2(dev_info(&ha->pdev->dev, "%s mark missing " + "ddb_entry 0x%p sess 0x%p conn 0x%p\n", + __func__, ddb_entry, + ddb_entry->sess, ddb_entry->conn)); qla4xxx_mark_device_missing(ha, ddb_entry); + } + /* * Relogin if device state changed to a not active state. - * However, do not relogin if this aen is a result of an IOCTL - * logout (DF_NO_RELOGIN) or if this is a discovered device. + * However, do not relogin if a RELOGIN is in process, or + * we are not allowed to relogin to this DDB. */ if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_FAILED && !test_bit(DF_RELOGIN, &ddb_entry->flags) && !test_bit(DF_NO_RELOGIN, &ddb_entry->flags) && - !test_bit(DF_ISNS_DISCOVERED, &ddb_entry->flags)) { + qla4_is_relogin_allowed(ha, conn_err)) { /* * This triggers a relogin. After the relogin_timer * expires, the relogin gets scheduled. We must wait a @@ -1338,7 +1534,7 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, * with failed device_state or a logout response before * we can issue another relogin. */ - /* Firmware padds this timeout: (time2wait +1). + /* Firmware pads this timeout: (time2wait +1). * Driver retry to login should be longer than F/W. * Otherwise F/W will fail * set_ddb() mbx cmd with 0x4005 since it still diff --git a/drivers/scsi/qla4xxx/ql4_iocb.c b/drivers/scsi/qla4xxx/ql4_iocb.c index e0c3215..e66f3f2 100644 --- a/drivers/scsi/qla4xxx/ql4_iocb.c +++ b/drivers/scsi/qla4xxx/ql4_iocb.c @@ -299,7 +299,7 @@ int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb) qla4xxx_build_scsi_iocbs(srb, cmd_entry, tot_dsds); wmb(); - srb->cmd->host_scribble = (unsigned char *)srb; + srb->cmd->host_scribble = (unsigned char *)(unsigned long)index; /* update counters */ srb->state = SRB_ACTIVE_STATE; diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c index c196d55..596c303 100644 --- a/drivers/scsi/qla4xxx/ql4_isr.c +++ b/drivers/scsi/qla4xxx/ql4_isr.c @@ -97,7 +97,7 @@ qla4xxx_status_cont_entry(struct scsi_qla_host *ha, /* Place command on done queue. */ if (srb->req_sense_len == 0) { - qla4xxx_srb_compl(ha, srb); + kref_put(&srb->srb_ref, qla4xxx_srb_compl); ha->status_srb = NULL; } } @@ -329,7 +329,7 @@ status_entry_exit: /* complete the request, if not waiting for status_continuation pkt */ srb->cc_stat = sts_entry->completionStatus; if (ha->status_srb == NULL) - qla4xxx_srb_compl(ha, srb); + kref_put(&srb->srb_ref, qla4xxx_srb_compl); } /** @@ -393,7 +393,7 @@ static void qla4xxx_process_response_queue(struct scsi_qla_host * ha) /* ETRY normally by sending it back with * DID_BUS_BUSY */ srb->cmd->result = DID_BUS_BUSY << 16; - qla4xxx_srb_compl(ha, srb); + kref_put(&srb->srb_ref, qla4xxx_srb_compl); break; case ET_CONTINUE: @@ -498,15 +498,22 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha, break; case MBOX_ASTS_LINK_UP: - DEBUG2(printk("scsi%ld: AEN %04x Adapter LINK UP\n", - ha->host_no, mbox_status)); set_bit(AF_LINK_UP, &ha->flags); + if (test_bit(AF_INIT_DONE, &ha->flags)) + set_bit(DPC_LINK_CHANGED, &ha->dpc_flags); + + DEBUG2(printk(KERN_INFO "scsi%ld: AEN %04x Adapter" + " LINK UP\n", ha->host_no, + mbox_status)); break; case MBOX_ASTS_LINK_DOWN: - DEBUG2(printk("scsi%ld: AEN %04x Adapter LINK DOWN\n", - ha->host_no, mbox_status)); clear_bit(AF_LINK_UP, &ha->flags); + set_bit(DPC_LINK_CHANGED, &ha->dpc_flags); + + DEBUG2(printk(KERN_INFO "scsi%ld: AEN %04x Adapter" + " LINK DOWN\n", ha->host_no, + mbox_status)); break; case MBOX_ASTS_HEARTBEAT: @@ -831,7 +838,7 @@ void qla4xxx_process_aen(struct scsi_qla_host * ha, uint8_t process_aen) qla4xxx_reinitialize_ddb_list(ha); } else if (mbox_sts[1] == 1) { /* Specific device. */ qla4xxx_process_ddb_changed(ha, mbox_sts[2], - mbox_sts[3]); + mbox_sts[3], mbox_sts[4]); } break; } diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c index caeb7d1..75496fb 100644 --- a/drivers/scsi/qla4xxx/ql4_mbx.c +++ b/drivers/scsi/qla4xxx/ql4_mbx.c @@ -172,108 +172,207 @@ mbox_exit: return status; } +uint8_t +qla4xxx_set_ifcb(struct scsi_qla_host *ha, uint32_t *mbox_cmd, + uint32_t *mbox_sts, dma_addr_t init_fw_cb_dma) +{ + memset(mbox_cmd, 0, sizeof(mbox_cmd[0]) * MBOX_REG_COUNT); + memset(mbox_sts, 0, sizeof(mbox_sts[0]) * MBOX_REG_COUNT); + mbox_cmd[0] = MBOX_CMD_INITIALIZE_FIRMWARE; + mbox_cmd[1] = 0; + mbox_cmd[2] = LSDW(init_fw_cb_dma); + mbox_cmd[3] = MSDW(init_fw_cb_dma); + mbox_cmd[4] = sizeof(struct addr_ctrl_blk); + mbox_cmd[5] = (IFCB_VER_MAX << 8) | IFCB_VER_MIN; + + if (qla4xxx_mailbox_command(ha, 6, 6, mbox_cmd, mbox_sts) != + QLA_SUCCESS) { + DEBUG2(printk(KERN_WARNING "scsi%ld: %s: " + "MBOX_CMD_INITIALIZE_FIRMWARE" + " failed w/ status %04X\n", + ha->host_no, __func__, mbox_sts[0])); + return QLA_ERROR; + } + return QLA_SUCCESS; +} + +uint8_t +qla4xxx_get_ifcb(struct scsi_qla_host *ha, uint32_t *mbox_cmd, + uint32_t *mbox_sts, dma_addr_t init_fw_cb_dma) +{ + memset(mbox_cmd, 0, sizeof(mbox_cmd[0]) * MBOX_REG_COUNT); + memset(mbox_sts, 0, sizeof(mbox_sts[0]) * MBOX_REG_COUNT); + mbox_cmd[0] = MBOX_CMD_GET_INIT_FW_CTRL_BLOCK; + mbox_cmd[2] = LSDW(init_fw_cb_dma); + mbox_cmd[3] = MSDW(init_fw_cb_dma); + mbox_cmd[4] = sizeof(struct addr_ctrl_blk); + + if (qla4xxx_mailbox_command(ha, 5, 5, mbox_cmd, mbox_sts) != + QLA_SUCCESS) { + DEBUG2(printk(KERN_WARNING "scsi%ld: %s: " + "MBOX_CMD_GET_INIT_FW_CTRL_BLOCK" + " failed w/ status %04X\n", + ha->host_no, __func__, mbox_sts[0])); + return QLA_ERROR; + } + return QLA_SUCCESS; +} + +void +qla4xxx_update_local_ip(struct scsi_qla_host *ha, + struct addr_ctrl_blk *init_fw_cb) +{ + /* Save IPv4 Address Info */ + memcpy(ha->ip_address, init_fw_cb->ipv4_addr, + min(sizeof(ha->ip_address), sizeof(init_fw_cb->ipv4_addr))); + memcpy(ha->subnet_mask, init_fw_cb->ipv4_subnet, + min(sizeof(ha->subnet_mask), sizeof(init_fw_cb->ipv4_subnet))); + memcpy(ha->gateway, init_fw_cb->ipv4_gw_addr, + min(sizeof(ha->gateway), sizeof(init_fw_cb->ipv4_gw_addr))); + + if (is_ipv6_enabled(ha)) { + /* Save IPv6 Address */ + ha->ipv6_link_local_state = init_fw_cb->ipv6_lnk_lcl_addr_state; + ha->ipv6_addr0_state = init_fw_cb->ipv6_addr0_state; + ha->ipv6_addr1_state = init_fw_cb->ipv6_addr1_state; + ha->ipv6_default_router_state = init_fw_cb->ipv6_dflt_rtr_state; + ha->ipv6_link_local_addr.in6_u.u6_addr8[0] = 0xFE; + ha->ipv6_link_local_addr.in6_u.u6_addr8[1] = 0x80; + + memcpy(&ha->ipv6_link_local_addr.in6_u.u6_addr8[8], + init_fw_cb->ipv6_if_id, + min(sizeof(ha->ipv6_link_local_addr)/2, + sizeof(init_fw_cb->ipv6_if_id))); + memcpy(&ha->ipv6_addr0, init_fw_cb->ipv6_addr0, + min(sizeof(ha->ipv6_addr0), + sizeof(init_fw_cb->ipv6_addr0))); + memcpy(&ha->ipv6_addr1, init_fw_cb->ipv6_addr1, + min(sizeof(ha->ipv6_addr1), + sizeof(init_fw_cb->ipv6_addr1))); + memcpy(&ha->ipv6_default_router_addr, + init_fw_cb->ipv6_dflt_rtr_addr, + min(sizeof(ha->ipv6_default_router_addr), + sizeof(init_fw_cb->ipv6_dflt_rtr_addr))); + } +} + +uint8_t +qla4xxx_update_local_ifcb(struct scsi_qla_host *ha, + uint32_t *mbox_cmd, + uint32_t *mbox_sts, + struct addr_ctrl_blk *init_fw_cb, + dma_addr_t init_fw_cb_dma) +{ + if (qla4xxx_get_ifcb(ha, mbox_cmd, mbox_sts, init_fw_cb_dma) + != QLA_SUCCESS) { + DEBUG2(printk(KERN_WARNING + "scsi%ld: %s: Failed to get init_fw_ctrl_blk\n", + ha->host_no, __func__)); + return QLA_ERROR; + } + + DEBUG2(qla4xxx_dump_buffer(init_fw_cb, sizeof(struct addr_ctrl_blk))); + + /* Save some info in adapter structure. */ + ha->acb_version = init_fw_cb->acb_version; + ha->firmware_options = le16_to_cpu(init_fw_cb->fw_options); + ha->tcp_options = le16_to_cpu(init_fw_cb->ipv4_tcp_opts); + ha->ipv4_options = le16_to_cpu(init_fw_cb->ipv4_ip_opts); + ha->ipv4_addr_state = le16_to_cpu(init_fw_cb->ipv4_addr_state); + ha->heartbeat_interval = init_fw_cb->hb_interval; + memcpy(ha->name_string, init_fw_cb->iscsi_name, + min(sizeof(ha->name_string), + sizeof(init_fw_cb->iscsi_name))); + /*memcpy(ha->alias, init_fw_cb->Alias, + min(sizeof(ha->alias), sizeof(init_fw_cb->Alias)));*/ + + /* Save Command Line Paramater info */ + ha->port_down_retry_count = le16_to_cpu(init_fw_cb->conn_ka_timeout); + ha->discovery_wait = ql4xdiscoverywait; + + if (ha->acb_version == ACB_SUPPORTED) { + ha->ipv6_options = init_fw_cb->ipv6_opts; + ha->ipv6_addl_options = init_fw_cb->ipv6_addtl_opts; + } + qla4xxx_update_local_ip(ha, init_fw_cb); + + return QLA_SUCCESS; +} + /** * qla4xxx_initialize_fw_cb - initializes firmware control block. * @ha: Pointer to host adapter structure. **/ int qla4xxx_initialize_fw_cb(struct scsi_qla_host * ha) { - struct init_fw_ctrl_blk *init_fw_cb; + struct addr_ctrl_blk *init_fw_cb; dma_addr_t init_fw_cb_dma; uint32_t mbox_cmd[MBOX_REG_COUNT]; uint32_t mbox_sts[MBOX_REG_COUNT]; int status = QLA_ERROR; init_fw_cb = dma_alloc_coherent(&ha->pdev->dev, - sizeof(struct init_fw_ctrl_blk), + sizeof(struct addr_ctrl_blk), &init_fw_cb_dma, GFP_KERNEL); if (init_fw_cb == NULL) { DEBUG2(printk("scsi%ld: %s: Unable to alloc init_cb\n", ha->host_no, __func__)); return 10; } - memset(init_fw_cb, 0, sizeof(struct init_fw_ctrl_blk)); + memset(init_fw_cb, 0, sizeof(struct addr_ctrl_blk)); /* Get Initialize Firmware Control Block. */ memset(&mbox_cmd, 0, sizeof(mbox_cmd)); memset(&mbox_sts, 0, sizeof(mbox_sts)); - mbox_cmd[0] = MBOX_CMD_GET_INIT_FW_CTRL_BLOCK; - mbox_cmd[2] = LSDW(init_fw_cb_dma); - mbox_cmd[3] = MSDW(init_fw_cb_dma); - mbox_cmd[4] = sizeof(struct init_fw_ctrl_blk); - - if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], &mbox_sts[0]) != + if (qla4xxx_get_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb_dma) != QLA_SUCCESS) { dma_free_coherent(&ha->pdev->dev, - sizeof(struct init_fw_ctrl_blk), + sizeof(struct addr_ctrl_blk), init_fw_cb, init_fw_cb_dma); - return status; + goto exit_init_fw_cb; } /* Initialize request and response queues. */ qla4xxx_init_rings(ha); /* Fill in the request and response queue information. */ - init_fw_cb->pri.rqq_consumer_idx = cpu_to_le16(ha->request_out); - init_fw_cb->pri.compq_producer_idx = cpu_to_le16(ha->response_in); - init_fw_cb->pri.rqq_len = __constant_cpu_to_le16(REQUEST_QUEUE_DEPTH); - init_fw_cb->pri.compq_len = __constant_cpu_to_le16(RESPONSE_QUEUE_DEPTH); - init_fw_cb->pri.rqq_addr_lo = cpu_to_le32(LSDW(ha->request_dma)); - init_fw_cb->pri.rqq_addr_hi = cpu_to_le32(MSDW(ha->request_dma)); - init_fw_cb->pri.compq_addr_lo = cpu_to_le32(LSDW(ha->response_dma)); - init_fw_cb->pri.compq_addr_hi = cpu_to_le32(MSDW(ha->response_dma)); - init_fw_cb->pri.shdwreg_addr_lo = - cpu_to_le32(LSDW(ha->shadow_regs_dma)); - init_fw_cb->pri.shdwreg_addr_hi = - cpu_to_le32(MSDW(ha->shadow_regs_dma)); + init_fw_cb->rqq_consumer_idx = cpu_to_le16(ha->request_out); + init_fw_cb->compq_producer_idx = cpu_to_le16(ha->response_in); + init_fw_cb->rqq_len = __constant_cpu_to_le16(REQUEST_QUEUE_DEPTH); + init_fw_cb->compq_len = __constant_cpu_to_le16(RESPONSE_QUEUE_DEPTH); + init_fw_cb->rqq_addr_lo = cpu_to_le32(LSDW(ha->request_dma)); + init_fw_cb->rqq_addr_hi = cpu_to_le32(MSDW(ha->request_dma)); + init_fw_cb->compq_addr_lo = cpu_to_le32(LSDW(ha->response_dma)); + init_fw_cb->compq_addr_hi = cpu_to_le32(MSDW(ha->response_dma)); + init_fw_cb->shdwreg_addr_lo = cpu_to_le32(LSDW(ha->shadow_regs_dma)); + init_fw_cb->shdwreg_addr_hi = cpu_to_le32(MSDW(ha->shadow_regs_dma)); /* Set up required options. */ - init_fw_cb->pri.fw_options |= + init_fw_cb->fw_options |= __constant_cpu_to_le16(FWOPT_SESSION_MODE | FWOPT_INITIATOR_MODE); - init_fw_cb->pri.fw_options &= __constant_cpu_to_le16(~FWOPT_TARGET_MODE); - - /* Save some info in adapter structure. */ - ha->firmware_options = le16_to_cpu(init_fw_cb->pri.fw_options); - ha->tcp_options = le16_to_cpu(init_fw_cb->pri.ipv4_tcp_opts); - ha->heartbeat_interval = init_fw_cb->pri.hb_interval; - memcpy(ha->ip_address, init_fw_cb->pri.ipv4_addr, - min(sizeof(ha->ip_address), sizeof(init_fw_cb->pri.ipv4_addr))); - memcpy(ha->subnet_mask, init_fw_cb->pri.ipv4_subnet, - min(sizeof(ha->subnet_mask), sizeof(init_fw_cb->pri.ipv4_subnet))); - memcpy(ha->gateway, init_fw_cb->pri.ipv4_gw_addr, - min(sizeof(ha->gateway), sizeof(init_fw_cb->pri.ipv4_gw_addr))); - memcpy(ha->name_string, init_fw_cb->pri.iscsi_name, - min(sizeof(ha->name_string), - sizeof(init_fw_cb->pri.iscsi_name))); - /*memcpy(ha->alias, init_fw_cb->Alias, - min(sizeof(ha->alias), sizeof(init_fw_cb->Alias)));*/ - - /* Save Command Line Paramater info */ - ha->port_down_retry_count = le16_to_cpu(init_fw_cb->pri.conn_ka_timeout); - ha->discovery_wait = ql4xdiscoverywait; + init_fw_cb->fw_options &= __constant_cpu_to_le16(~FWOPT_TARGET_MODE); - /* Send Initialize Firmware Control Block. */ - memset(&mbox_cmd, 0, sizeof(mbox_cmd)); - memset(&mbox_sts, 0, sizeof(mbox_sts)); - - mbox_cmd[0] = MBOX_CMD_INITIALIZE_FIRMWARE; - mbox_cmd[1] = 0; - mbox_cmd[2] = LSDW(init_fw_cb_dma); - mbox_cmd[3] = MSDW(init_fw_cb_dma); - mbox_cmd[4] = sizeof(struct init_fw_ctrl_blk); + if (qla4xxx_set_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb_dma) + != QLA_SUCCESS) { + DEBUG2(printk(KERN_WARNING + "scsi%ld: %s: Failed to set init_fw_ctrl_blk\n", + ha->host_no, __func__)); + goto exit_init_fw_cb; + } - if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], &mbox_sts[0]) == - QLA_SUCCESS) - status = QLA_SUCCESS; - else { - DEBUG2(printk("scsi%ld: %s: MBOX_CMD_INITIALIZE_FIRMWARE " - "failed w/ status %04X\n", ha->host_no, __func__, - mbox_sts[0])); + if (qla4xxx_update_local_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], + init_fw_cb, init_fw_cb_dma) != QLA_SUCCESS) { + DEBUG2(printk("scsi%ld: %s: Failed to update local ifcb\n", + ha->host_no, __func__)); + goto exit_init_fw_cb; } - dma_free_coherent(&ha->pdev->dev, sizeof(struct init_fw_ctrl_blk), - init_fw_cb, init_fw_cb_dma); + status = QLA_SUCCESS; + +exit_init_fw_cb: + dma_free_coherent(&ha->pdev->dev, sizeof(struct addr_ctrl_blk), + init_fw_cb, init_fw_cb_dma); return status; } @@ -284,13 +383,13 @@ int qla4xxx_initialize_fw_cb(struct scsi_qla_host * ha) **/ int qla4xxx_get_dhcp_ip_address(struct scsi_qla_host * ha) { - struct init_fw_ctrl_blk *init_fw_cb; + struct addr_ctrl_blk *init_fw_cb; dma_addr_t init_fw_cb_dma; uint32_t mbox_cmd[MBOX_REG_COUNT]; uint32_t mbox_sts[MBOX_REG_COUNT]; init_fw_cb = dma_alloc_coherent(&ha->pdev->dev, - sizeof(struct init_fw_ctrl_blk), + sizeof(struct addr_ctrl_blk), &init_fw_cb_dma, GFP_KERNEL); if (init_fw_cb == NULL) { printk("scsi%ld: %s: Unable to alloc init_cb\n", ha->host_no, @@ -299,35 +398,21 @@ int qla4xxx_get_dhcp_ip_address(struct scsi_qla_host * ha) } /* Get Initialize Firmware Control Block. */ - memset(&mbox_cmd, 0, sizeof(mbox_cmd)); - memset(&mbox_sts, 0, sizeof(mbox_sts)); - - memset(init_fw_cb, 0, sizeof(struct init_fw_ctrl_blk)); - mbox_cmd[0] = MBOX_CMD_GET_INIT_FW_CTRL_BLOCK; - mbox_cmd[2] = LSDW(init_fw_cb_dma); - mbox_cmd[3] = MSDW(init_fw_cb_dma); - mbox_cmd[4] = sizeof(struct init_fw_ctrl_blk); - - if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], &mbox_sts[0]) != + memset(init_fw_cb, 0, sizeof(struct addr_ctrl_blk)); + if (qla4xxx_get_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb_dma) != QLA_SUCCESS) { DEBUG2(printk("scsi%ld: %s: Failed to get init_fw_ctrl_blk\n", ha->host_no, __func__)); dma_free_coherent(&ha->pdev->dev, - sizeof(struct init_fw_ctrl_blk), + sizeof(struct addr_ctrl_blk), init_fw_cb, init_fw_cb_dma); return QLA_ERROR; } /* Save IP Address. */ - memcpy(ha->ip_address, init_fw_cb->pri.ipv4_addr, - min(sizeof(ha->ip_address), sizeof(init_fw_cb->pri.ipv4_addr))); - memcpy(ha->subnet_mask, init_fw_cb->pri.ipv4_subnet, - min(sizeof(ha->subnet_mask), sizeof(init_fw_cb->pri.ipv4_subnet))); - memcpy(ha->gateway, init_fw_cb->pri.ipv4_gw_addr, - min(sizeof(ha->gateway), sizeof(init_fw_cb->pri.ipv4_gw_addr))); - - dma_free_coherent(&ha->pdev->dev, sizeof(struct init_fw_ctrl_blk), - init_fw_cb, init_fw_cb_dma); + qla4xxx_update_local_ip(ha, init_fw_cb); + dma_free_coherent(&ha->pdev->dev, sizeof(struct addr_ctrl_blk), + init_fw_cb, init_fw_cb_dma); return QLA_SUCCESS; } @@ -409,6 +494,7 @@ int qla4xxx_get_fwddb_entry(struct scsi_qla_host *ha, uint16_t *connection_id) { int status = QLA_ERROR; + uint16_t options; uint32_t mbox_cmd[MBOX_REG_COUNT]; uint32_t mbox_sts[MBOX_REG_COUNT]; @@ -441,14 +527,26 @@ int qla4xxx_get_fwddb_entry(struct scsi_qla_host *ha, goto exit_get_fwddb; } if (fw_ddb_entry) { - dev_info(&ha->pdev->dev, "DDB[%d] MB0 %04x Tot %d Next %d " - "State %04x ConnErr %08x %d.%d.%d.%d:%04d \"%s\"\n", - fw_ddb_index, mbox_sts[0], mbox_sts[2], mbox_sts[3], - mbox_sts[4], mbox_sts[5], fw_ddb_entry->ip_addr[0], - fw_ddb_entry->ip_addr[1], fw_ddb_entry->ip_addr[2], - fw_ddb_entry->ip_addr[3], - le16_to_cpu(fw_ddb_entry->port), - fw_ddb_entry->iscsi_name); + options = le16_to_cpu(fw_ddb_entry->options); + if (options & DDB_OPT_IPV6_DEVICE) { + dev_info(&ha->pdev->dev, "%s: DDB[%d] MB0 %04x Tot %d " + "Next %d State %04x ConnErr %08x %pI6 " + ":%04d \"%s\"\n", __func__, fw_ddb_index, + mbox_sts[0], mbox_sts[2], mbox_sts[3], + mbox_sts[4], mbox_sts[5], + fw_ddb_entry->ip_addr, + le16_to_cpu(fw_ddb_entry->port), + fw_ddb_entry->iscsi_name); + } else { + dev_info(&ha->pdev->dev, "%s: DDB[%d] MB0 %04x Tot %d " + "Next %d State %04x ConnErr %08x %pI4 " + ":%04d \"%s\"\n", __func__, fw_ddb_index, + mbox_sts[0], mbox_sts[2], mbox_sts[3], + mbox_sts[4], mbox_sts[5], + fw_ddb_entry->ip_addr, + le16_to_cpu(fw_ddb_entry->port), + fw_ddb_entry->iscsi_name); + } } if (num_valid_ddb_entries) *num_valid_ddb_entries = mbox_sts[2]; @@ -664,6 +762,59 @@ exit_get_event_log: } /** + * qla4xxx_abort_task - issues Abort Task + * @ha: Pointer to host adapter structure. + * @srb: Pointer to srb entry + * + * This routine performs a LUN RESET on the specified target/lun. + * The caller must ensure that the ddb_entry and lun_entry pointers + * are valid before calling this routine. + **/ +int qla4xxx_abort_task(struct scsi_qla_host *ha, struct srb *srb) +{ + uint32_t mbox_cmd[MBOX_REG_COUNT]; + uint32_t mbox_sts[MBOX_REG_COUNT]; + struct scsi_cmnd *cmd = srb->cmd; + int status = QLA_SUCCESS; + unsigned long flags = 0; + uint32_t index; + + /* + * Send abort task command to ISP, so that the ISP will return + * request with ABORT status + */ + memset(&mbox_cmd, 0, sizeof(mbox_cmd)); + memset(&mbox_sts, 0, sizeof(mbox_sts)); + + spin_lock_irqsave(&ha->hardware_lock, flags); + index = (unsigned long)(unsigned char *)cmd->host_scribble; + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + /* Firmware already posted completion on response queue */ + if (index == MAX_SRBS) + return status; + + mbox_cmd[0] = MBOX_CMD_ABORT_TASK; + mbox_cmd[1] = srb->fw_ddb_index; + mbox_cmd[2] = index; + /* Immediate Command Enable */ + mbox_cmd[5] = 0x01; + + qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 5, &mbox_cmd[0], + &mbox_sts[0]); + if (mbox_sts[0] != MBOX_STS_COMMAND_COMPLETE) { + status = QLA_ERROR; + + DEBUG2(printk(KERN_WARNING "scsi%ld:%d:%d: abort task FAILED: " + "mbx0=%04X, mb1=%04X, mb2=%04X, mb3=%04X, mb4=%04X\n", + ha->host_no, cmd->device->id, cmd->device->lun, mbox_sts[0], + mbox_sts[1], mbox_sts[2], mbox_sts[3], mbox_sts[4])); + } + + return status; +} + +/** * qla4xxx_reset_lun - issues LUN Reset * @ha: Pointer to host adapter structure. * @db_entry: Pointer to device database entry diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 2ccad36..38b1d38 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -74,6 +74,7 @@ static enum blk_eh_timer_return qla4xxx_eh_cmd_timed_out(struct scsi_cmnd *sc); */ static int qla4xxx_queuecommand(struct scsi_cmnd *cmd, void (*done) (struct scsi_cmnd *)); +static int qla4xxx_eh_abort(struct scsi_cmnd *cmd); static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd); static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd); static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd); @@ -88,6 +89,7 @@ static struct scsi_host_template qla4xxx_driver_template = { .proc_name = DRIVER_NAME, .queuecommand = qla4xxx_queuecommand, + .eh_abort_handler = qla4xxx_eh_abort, .eh_device_reset_handler = qla4xxx_eh_device_reset, .eh_target_reset_handler = qla4xxx_eh_target_reset, .eh_host_reset_handler = qla4xxx_eh_host_reset, @@ -384,12 +386,12 @@ static struct srb* qla4xxx_get_new_srb(struct scsi_qla_host *ha, if (!srb) return srb; - atomic_set(&srb->ref_count, 1); + kref_init(&srb->srb_ref); srb->ha = ha; srb->ddb = ddb_entry; srb->cmd = cmd; srb->flags = 0; - cmd->SCp.ptr = (void *)srb; + CMD_SP(cmd) = (void *)srb; cmd->scsi_done = done; return srb; @@ -403,12 +405,14 @@ static void qla4xxx_srb_free_dma(struct scsi_qla_host *ha, struct srb *srb) scsi_dma_unmap(cmd); srb->flags &= ~SRB_DMA_VALID; } - cmd->SCp.ptr = NULL; + CMD_SP(cmd) = NULL; } -void qla4xxx_srb_compl(struct scsi_qla_host *ha, struct srb *srb) +void qla4xxx_srb_compl(struct kref *ref) { + struct srb *srb = container_of(ref, struct srb, srb_ref); struct scsi_cmnd *cmd = srb->cmd; + struct scsi_qla_host *ha = srb->ha; qla4xxx_srb_free_dma(ha, srb); @@ -685,6 +689,7 @@ static void qla4xxx_timer(struct scsi_qla_host *ha) test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags) || test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) || test_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags) || + test_bit(DPC_LINK_CHANGED, &ha->dpc_flags) || test_bit(DPC_AEN, &ha->dpc_flags)) && ha->dpc_thread) { DEBUG2(printk("scsi%ld: %s: scheduling dpc routine" @@ -886,11 +891,10 @@ static void qla4xxx_flush_active_srbs(struct scsi_qla_host *ha) srb = qla4xxx_del_from_active_array(ha, i); if (srb != NULL) { srb->cmd->result = DID_RESET << 16; - qla4xxx_srb_compl(ha, srb); + kref_put(&srb->srb_ref, qla4xxx_srb_compl); } } spin_unlock_irqrestore(&ha->hardware_lock, flags); - } /** @@ -1069,6 +1073,54 @@ static void qla4xxx_do_dpc(struct work_struct *work) if (test_and_clear_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags)) qla4xxx_get_dhcp_ip_address(ha); + /* ---- link change? --- */ + if (test_and_clear_bit(DPC_LINK_CHANGED, &ha->dpc_flags)) { + if (!test_bit(AF_LINK_UP, &ha->flags)) { + /* ---- link down? --- */ + list_for_each_entry_safe(ddb_entry, dtemp, + &ha->ddb_list, list) { + if (atomic_read(&ddb_entry->state) == + DDB_STATE_ONLINE) + qla4xxx_mark_device_missing(ha, + ddb_entry); + } + } else { + /* ---- link up? --- * + * F/W will auto login to all devices ONLY ONCE after + * link up during driver initialization and runtime + * fatal error recovery. Therefore, the driver must + * manually relogin to devices when recovering from + * connection failures, logouts, expired KATO, etc. */ + + list_for_each_entry_safe(ddb_entry, dtemp, + &ha->ddb_list, list) { + if ((atomic_read(&ddb_entry->state) == + DDB_STATE_MISSING) || + (atomic_read(&ddb_entry->state) == + DDB_STATE_DEAD)) { + if (ddb_entry->fw_ddb_device_state == + DDB_DS_SESSION_ACTIVE) { + atomic_set(&ddb_entry->state, + DDB_STATE_ONLINE); + dev_info(&ha->pdev->dev, + "scsi%ld: %s: ddb[%d]" + " os[%d] marked" + " ONLINE\n", + ha->host_no, __func__, + ddb_entry->fw_ddb_index, + ddb_entry->os_target_id); + + iscsi_unblock_session( + ddb_entry->sess); + } else + qla4xxx_relogin_device( + ha, ddb_entry); + } + + } + } + } + /* ---- relogin device? --- */ if (adapter_up(ha) && test_and_clear_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags)) { @@ -1430,12 +1482,14 @@ static void qla4xxx_slave_destroy(struct scsi_device *sdev) struct srb * qla4xxx_del_from_active_array(struct scsi_qla_host *ha, uint32_t index) { struct srb *srb = NULL; - struct scsi_cmnd *cmd; + struct scsi_cmnd *cmd = NULL; - if (!(cmd = scsi_host_find_tag(ha->host, index))) + cmd = scsi_host_find_tag(ha->host, index); + if (!cmd) return srb; - if (!(srb = (struct srb *)cmd->host_scribble)) + srb = (struct srb *)CMD_SP(cmd); + if (!srb) return srb; /* update counters */ @@ -1443,14 +1497,15 @@ struct srb * qla4xxx_del_from_active_array(struct scsi_qla_host *ha, uint32_t in ha->req_q_count += srb->iocb_cnt; ha->iocb_cnt -= srb->iocb_cnt; if (srb->cmd) - srb->cmd->host_scribble = NULL; + srb->cmd->host_scribble = + (unsigned char *)(unsigned long) MAX_SRBS; } return srb; } /** * qla4xxx_eh_wait_on_command - waits for command to be returned by firmware - * @ha: actual ha whose done queue will contain the comd returned by firmware. + * @ha: Pointer to host adapter structure. * @cmd: Scsi Command to wait on. * * This routine waits for the command to be returned by the Firmware @@ -1465,7 +1520,7 @@ static int qla4xxx_eh_wait_on_command(struct scsi_qla_host *ha, do { /* Checking to see if its returned to OS */ - rp = (struct srb *) cmd->SCp.ptr; + rp = (struct srb *) CMD_SP(cmd); if (rp == NULL) { done++; break; @@ -1534,6 +1589,62 @@ static int qla4xxx_eh_wait_for_commands(struct scsi_qla_host *ha, } /** + * qla4xxx_eh_abort - callback for abort task. + * @cmd: Pointer to Linux's SCSI command structure + * + * This routine is called by the Linux OS to abort the specified + * command. + **/ +static int qla4xxx_eh_abort(struct scsi_cmnd *cmd) +{ + struct scsi_qla_host *ha = to_qla_host(cmd->device->host); + unsigned int id = cmd->device->id; + unsigned int lun = cmd->device->lun; + unsigned long serial = cmd->serial_number; + struct srb *srb = NULL; + int ret = SUCCESS; + int wait = 0; + + dev_info(&ha->pdev->dev, + "scsi%ld:%d:%d: Abort command issued cmd=%p, pid=%ld\n", + ha->host_no, id, lun, cmd, serial); + + srb = (struct srb *) CMD_SP(cmd); + + if (!srb) + return SUCCESS; + + kref_get(&srb->srb_ref); + + if (qla4xxx_abort_task(ha, srb) != QLA_SUCCESS) { + DEBUG3(printk("scsi%ld:%d:%d: Abort_task mbx failed.\n", + ha->host_no, id, lun)); + ret = FAILED; + } else { + DEBUG3(printk("scsi%ld:%d:%d: Abort_task mbx success.\n", + ha->host_no, id, lun)); + wait = 1; + } + + kref_put(&srb->srb_ref, qla4xxx_srb_compl); + + /* Wait for command to complete */ + if (wait) { + if (!qla4xxx_eh_wait_on_command(ha, cmd)) { + DEBUG2(printk("scsi%ld:%d:%d: Abort handler timed out\n", + ha->host_no, id, lun)); + ret = FAILED; + } + } + + dev_info(&ha->pdev->dev, + "scsi%ld:%d:%d: Abort command - %s\n", + ha->host_no, id, lun, (ret == SUCCESS) ? "succeded" : "failed"); + + return ret; +} + +/** * qla4xxx_eh_device_reset - callback for target reset. * @cmd: Pointer to Linux's SCSI command structure * diff --git a/drivers/scsi/qla4xxx/ql4_version.h b/drivers/scsi/qla4xxx/ql4_version.h index 6980cb2..28a6c49 100644 --- a/drivers/scsi/qla4xxx/ql4_version.h +++ b/drivers/scsi/qla4xxx/ql4_version.h @@ -5,5 +5,4 @@ * See LICENSE.qla4xxx for copyright and licensing details. */ -#define QLA4XXX_DRIVER_VERSION "5.01.00-k9" - +#define QLA4XXX_DRIVER_VERSION "5.02.00-k1" |