1afaf5a2dSDavid Somayajulu /* 2afaf5a2dSDavid Somayajulu * QLogic iSCSI HBA Driver 37d01d069SVikas Chaudhary * Copyright (c) 2003-2010 QLogic Corporation 4afaf5a2dSDavid Somayajulu * 5afaf5a2dSDavid Somayajulu * See LICENSE.qla4xxx for copyright and licensing details. 6afaf5a2dSDavid Somayajulu */ 7afaf5a2dSDavid Somayajulu #include <linux/moduleparam.h> 85a0e3ad6STejun Heo #include <linux/slab.h> 92a991c21SManish Rangankar #include <linux/blkdev.h> 102a991c21SManish Rangankar #include <linux/iscsi_boot_sysfs.h> 1113483730SMike Christie #include <linux/inet.h> 12afaf5a2dSDavid Somayajulu 13afaf5a2dSDavid Somayajulu #include <scsi/scsi_tcq.h> 14afaf5a2dSDavid Somayajulu #include <scsi/scsicam.h> 15afaf5a2dSDavid Somayajulu 16afaf5a2dSDavid Somayajulu #include "ql4_def.h" 17bee4fe8eSDavid C Somayajulu #include "ql4_version.h" 18bee4fe8eSDavid C Somayajulu #include "ql4_glbl.h" 19bee4fe8eSDavid C Somayajulu #include "ql4_dbg.h" 20bee4fe8eSDavid C Somayajulu #include "ql4_inline.h" 21afaf5a2dSDavid Somayajulu 22afaf5a2dSDavid Somayajulu /* 23afaf5a2dSDavid Somayajulu * Driver version 24afaf5a2dSDavid Somayajulu */ 2547975477SAdrian Bunk static char qla4xxx_version_str[40]; 26afaf5a2dSDavid Somayajulu 27afaf5a2dSDavid Somayajulu /* 28afaf5a2dSDavid Somayajulu * SRB allocation cache 29afaf5a2dSDavid Somayajulu */ 30e18b890bSChristoph Lameter static struct kmem_cache *srb_cachep; 31afaf5a2dSDavid Somayajulu 32afaf5a2dSDavid Somayajulu /* 33afaf5a2dSDavid Somayajulu * Module parameter information and variables 34afaf5a2dSDavid Somayajulu */ 3513483730SMike Christie int ql4xdisablesysfsboot = 1; 3613483730SMike Christie module_param(ql4xdisablesysfsboot, int, S_IRUGO | S_IWUSR); 3713483730SMike Christie MODULE_PARM_DESC(ql4xdisablesysfsboot, 3813483730SMike Christie "Set to disable exporting boot targets to sysfs\n" 3913483730SMike Christie " 0 - Export boot targets\n" 4013483730SMike Christie " 1 - Do not export boot targets (Default)"); 4113483730SMike Christie 42afaf5a2dSDavid Somayajulu int ql4xdontresethba = 0; 43f4f5df23SVikas Chaudhary module_param(ql4xdontresethba, int, S_IRUGO | S_IWUSR); 44afaf5a2dSDavid Somayajulu MODULE_PARM_DESC(ql4xdontresethba, 45f4f5df23SVikas Chaudhary "Don't reset the HBA for driver recovery \n" 46f4f5df23SVikas Chaudhary " 0 - It will reset HBA (Default)\n" 47f4f5df23SVikas Chaudhary " 1 - It will NOT reset HBA"); 48afaf5a2dSDavid Somayajulu 4911010fecSAndrew Vasquez int ql4xextended_error_logging = 0; /* 0 = off, 1 = log errors */ 50f4f5df23SVikas Chaudhary module_param(ql4xextended_error_logging, int, S_IRUGO | S_IWUSR); 5111010fecSAndrew Vasquez MODULE_PARM_DESC(ql4xextended_error_logging, 52afaf5a2dSDavid Somayajulu "Option to enable extended error logging, " 53afaf5a2dSDavid Somayajulu "Default is 0 - no logging, 1 - debug logging"); 54afaf5a2dSDavid Somayajulu 55f4f5df23SVikas Chaudhary int ql4xenablemsix = 1; 56f4f5df23SVikas Chaudhary module_param(ql4xenablemsix, int, S_IRUGO|S_IWUSR); 57f4f5df23SVikas Chaudhary MODULE_PARM_DESC(ql4xenablemsix, 58f4f5df23SVikas Chaudhary "Set to enable MSI or MSI-X interrupt mechanism.\n" 59f4f5df23SVikas Chaudhary " 0 = enable INTx interrupt mechanism.\n" 60f4f5df23SVikas Chaudhary " 1 = enable MSI-X interrupt mechanism (Default).\n" 61f4f5df23SVikas Chaudhary " 2 = enable MSI interrupt mechanism."); 62477ffb9dSDavid C Somayajulu 63d510d965SMike Christie #define QL4_DEF_QDEPTH 32 648bb4033dSVikas Chaudhary static int ql4xmaxqdepth = QL4_DEF_QDEPTH; 658bb4033dSVikas Chaudhary module_param(ql4xmaxqdepth, int, S_IRUGO | S_IWUSR); 668bb4033dSVikas Chaudhary MODULE_PARM_DESC(ql4xmaxqdepth, 678bb4033dSVikas Chaudhary "Maximum queue depth to report for target devices.\n" 688bb4033dSVikas Chaudhary " Default: 32."); 69d510d965SMike Christie 703038727cSVikas Chaudhary static int ql4xsess_recovery_tmo = QL4_SESS_RECOVERY_TMO; 713038727cSVikas Chaudhary module_param(ql4xsess_recovery_tmo, int, S_IRUGO); 723038727cSVikas Chaudhary MODULE_PARM_DESC(ql4xsess_recovery_tmo, 733038727cSVikas Chaudhary "Target Session Recovery Timeout.\n" 7413483730SMike Christie " Default: 120 sec."); 753038727cSVikas Chaudhary 76b3a271a9SManish Rangankar static int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha); 77afaf5a2dSDavid Somayajulu /* 78afaf5a2dSDavid Somayajulu * SCSI host template entry points 79afaf5a2dSDavid Somayajulu */ 8047975477SAdrian Bunk static void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha); 81afaf5a2dSDavid Somayajulu 82afaf5a2dSDavid Somayajulu /* 83afaf5a2dSDavid Somayajulu * iSCSI template entry points 84afaf5a2dSDavid Somayajulu */ 85afaf5a2dSDavid Somayajulu static int qla4xxx_conn_get_param(struct iscsi_cls_conn *conn, 86afaf5a2dSDavid Somayajulu enum iscsi_param param, char *buf); 87aa1e93a2SMike Christie static int qla4xxx_host_get_param(struct Scsi_Host *shost, 88aa1e93a2SMike Christie enum iscsi_host_param param, char *buf); 8900c31889SMike Christie static int qla4xxx_iface_set_param(struct Scsi_Host *shost, void *data, 9000c31889SMike Christie uint32_t len); 91ed1086e0SVikas Chaudhary static int qla4xxx_get_iface_param(struct iscsi_iface *iface, 92ed1086e0SVikas Chaudhary enum iscsi_param_type param_type, 93ed1086e0SVikas Chaudhary int param, char *buf); 945c656af7SMike Christie static enum blk_eh_timer_return qla4xxx_eh_cmd_timed_out(struct scsi_cmnd *sc); 95b3a271a9SManish Rangankar static struct iscsi_endpoint *qla4xxx_ep_connect(struct Scsi_Host *shost, 96b3a271a9SManish Rangankar struct sockaddr *dst_addr, 97b3a271a9SManish Rangankar int non_blocking); 98b3a271a9SManish Rangankar static int qla4xxx_ep_poll(struct iscsi_endpoint *ep, int timeout_ms); 99b3a271a9SManish Rangankar static void qla4xxx_ep_disconnect(struct iscsi_endpoint *ep); 100b3a271a9SManish Rangankar static int qla4xxx_get_ep_param(struct iscsi_endpoint *ep, 101b3a271a9SManish Rangankar enum iscsi_param param, char *buf); 102b3a271a9SManish Rangankar static int qla4xxx_conn_start(struct iscsi_cls_conn *conn); 103b3a271a9SManish Rangankar static struct iscsi_cls_conn * 104b3a271a9SManish Rangankar qla4xxx_conn_create(struct iscsi_cls_session *cls_sess, uint32_t conn_idx); 105b3a271a9SManish Rangankar static int qla4xxx_conn_bind(struct iscsi_cls_session *cls_session, 106b3a271a9SManish Rangankar struct iscsi_cls_conn *cls_conn, 107b3a271a9SManish Rangankar uint64_t transport_fd, int is_leading); 108b3a271a9SManish Rangankar static void qla4xxx_conn_destroy(struct iscsi_cls_conn *conn); 109b3a271a9SManish Rangankar static struct iscsi_cls_session * 110b3a271a9SManish Rangankar qla4xxx_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max, 111b3a271a9SManish Rangankar uint16_t qdepth, uint32_t initial_cmdsn); 112b3a271a9SManish Rangankar static void qla4xxx_session_destroy(struct iscsi_cls_session *sess); 113b3a271a9SManish Rangankar static void qla4xxx_task_work(struct work_struct *wdata); 114b3a271a9SManish Rangankar static int qla4xxx_alloc_pdu(struct iscsi_task *, uint8_t); 115b3a271a9SManish Rangankar static int qla4xxx_task_xmit(struct iscsi_task *); 116b3a271a9SManish Rangankar static void qla4xxx_task_cleanup(struct iscsi_task *); 117b3a271a9SManish Rangankar static void qla4xxx_fail_session(struct iscsi_cls_session *cls_session); 118b3a271a9SManish Rangankar static void qla4xxx_conn_get_stats(struct iscsi_cls_conn *cls_conn, 119b3a271a9SManish Rangankar struct iscsi_stats *stats); 120afaf5a2dSDavid Somayajulu /* 121afaf5a2dSDavid Somayajulu * SCSI host template entry points 122afaf5a2dSDavid Somayajulu */ 123f281233dSJeff Garzik static int qla4xxx_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *cmd); 12409a0f719SVikas Chaudhary static int qla4xxx_eh_abort(struct scsi_cmnd *cmd); 125afaf5a2dSDavid Somayajulu static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd); 126ce545039SMike Christie static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd); 127afaf5a2dSDavid Somayajulu static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd); 128afaf5a2dSDavid Somayajulu static int qla4xxx_slave_alloc(struct scsi_device *device); 129afaf5a2dSDavid Somayajulu static int qla4xxx_slave_configure(struct scsi_device *device); 130afaf5a2dSDavid Somayajulu static void qla4xxx_slave_destroy(struct scsi_device *sdev); 131587a1f16SAl Viro static umode_t ql4_attr_is_visible(int param_type, int param); 13295d31262SVikas Chaudhary static int qla4xxx_host_reset(struct Scsi_Host *shost, int reset_type); 133afaf5a2dSDavid Somayajulu 134f4f5df23SVikas Chaudhary static struct qla4_8xxx_legacy_intr_set legacy_intr[] = 135f4f5df23SVikas Chaudhary QLA82XX_LEGACY_INTR_CONFIG; 136f4f5df23SVikas Chaudhary 137afaf5a2dSDavid Somayajulu static struct scsi_host_template qla4xxx_driver_template = { 138afaf5a2dSDavid Somayajulu .module = THIS_MODULE, 139afaf5a2dSDavid Somayajulu .name = DRIVER_NAME, 140afaf5a2dSDavid Somayajulu .proc_name = DRIVER_NAME, 141afaf5a2dSDavid Somayajulu .queuecommand = qla4xxx_queuecommand, 142afaf5a2dSDavid Somayajulu 14309a0f719SVikas Chaudhary .eh_abort_handler = qla4xxx_eh_abort, 144afaf5a2dSDavid Somayajulu .eh_device_reset_handler = qla4xxx_eh_device_reset, 145ce545039SMike Christie .eh_target_reset_handler = qla4xxx_eh_target_reset, 146afaf5a2dSDavid Somayajulu .eh_host_reset_handler = qla4xxx_eh_host_reset, 1475c656af7SMike Christie .eh_timed_out = qla4xxx_eh_cmd_timed_out, 148afaf5a2dSDavid Somayajulu 149afaf5a2dSDavid Somayajulu .slave_configure = qla4xxx_slave_configure, 150afaf5a2dSDavid Somayajulu .slave_alloc = qla4xxx_slave_alloc, 151afaf5a2dSDavid Somayajulu .slave_destroy = qla4xxx_slave_destroy, 152afaf5a2dSDavid Somayajulu 153afaf5a2dSDavid Somayajulu .this_id = -1, 154afaf5a2dSDavid Somayajulu .cmd_per_lun = 3, 155afaf5a2dSDavid Somayajulu .use_clustering = ENABLE_CLUSTERING, 156afaf5a2dSDavid Somayajulu .sg_tablesize = SG_ALL, 157afaf5a2dSDavid Somayajulu 158afaf5a2dSDavid Somayajulu .max_sectors = 0xFFFF, 1597ad633c0SHarish Zunjarrao .shost_attrs = qla4xxx_host_attrs, 16095d31262SVikas Chaudhary .host_reset = qla4xxx_host_reset, 161a355943cSVikas Chaudhary .vendor_id = SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_QLOGIC, 162afaf5a2dSDavid Somayajulu }; 163afaf5a2dSDavid Somayajulu 164afaf5a2dSDavid Somayajulu static struct iscsi_transport qla4xxx_iscsi_transport = { 165afaf5a2dSDavid Somayajulu .owner = THIS_MODULE, 166afaf5a2dSDavid Somayajulu .name = DRIVER_NAME, 167b3a271a9SManish Rangankar .caps = CAP_TEXT_NEGO | 168b3a271a9SManish Rangankar CAP_DATA_PATH_OFFLOAD | CAP_HDRDGST | 169b3a271a9SManish Rangankar CAP_DATADGST | CAP_LOGIN_OFFLOAD | 170b3a271a9SManish Rangankar CAP_MULTI_R2T, 1713128c6c7SMike Christie .attr_is_visible = ql4_attr_is_visible, 172b3a271a9SManish Rangankar .create_session = qla4xxx_session_create, 173b3a271a9SManish Rangankar .destroy_session = qla4xxx_session_destroy, 174b3a271a9SManish Rangankar .start_conn = qla4xxx_conn_start, 175b3a271a9SManish Rangankar .create_conn = qla4xxx_conn_create, 176b3a271a9SManish Rangankar .bind_conn = qla4xxx_conn_bind, 177b3a271a9SManish Rangankar .stop_conn = iscsi_conn_stop, 178b3a271a9SManish Rangankar .destroy_conn = qla4xxx_conn_destroy, 179b3a271a9SManish Rangankar .set_param = iscsi_set_param, 180afaf5a2dSDavid Somayajulu .get_conn_param = qla4xxx_conn_get_param, 181b3a271a9SManish Rangankar .get_session_param = iscsi_session_get_param, 182b3a271a9SManish Rangankar .get_ep_param = qla4xxx_get_ep_param, 183b3a271a9SManish Rangankar .ep_connect = qla4xxx_ep_connect, 184b3a271a9SManish Rangankar .ep_poll = qla4xxx_ep_poll, 185b3a271a9SManish Rangankar .ep_disconnect = qla4xxx_ep_disconnect, 186b3a271a9SManish Rangankar .get_stats = qla4xxx_conn_get_stats, 187b3a271a9SManish Rangankar .send_pdu = iscsi_conn_send_pdu, 188b3a271a9SManish Rangankar .xmit_task = qla4xxx_task_xmit, 189b3a271a9SManish Rangankar .cleanup_task = qla4xxx_task_cleanup, 190b3a271a9SManish Rangankar .alloc_pdu = qla4xxx_alloc_pdu, 191b3a271a9SManish Rangankar 192aa1e93a2SMike Christie .get_host_param = qla4xxx_host_get_param, 193d00efe3fSMike Christie .set_iface_param = qla4xxx_iface_set_param, 194ed1086e0SVikas Chaudhary .get_iface_param = qla4xxx_get_iface_param, 195a355943cSVikas Chaudhary .bsg_request = qla4xxx_bsg_request, 196afaf5a2dSDavid Somayajulu }; 197afaf5a2dSDavid Somayajulu 198afaf5a2dSDavid Somayajulu static struct scsi_transport_template *qla4xxx_scsi_transport; 199afaf5a2dSDavid Somayajulu 200587a1f16SAl Viro static umode_t ql4_attr_is_visible(int param_type, int param) 2013128c6c7SMike Christie { 2023128c6c7SMike Christie switch (param_type) { 203f27fb2efSMike Christie case ISCSI_HOST_PARAM: 204f27fb2efSMike Christie switch (param) { 205f27fb2efSMike Christie case ISCSI_HOST_PARAM_HWADDRESS: 206f27fb2efSMike Christie case ISCSI_HOST_PARAM_IPADDRESS: 207f27fb2efSMike Christie case ISCSI_HOST_PARAM_INITIATOR_NAME: 208f27fb2efSMike Christie return S_IRUGO; 209f27fb2efSMike Christie default: 210f27fb2efSMike Christie return 0; 211f27fb2efSMike Christie } 2123128c6c7SMike Christie case ISCSI_PARAM: 2133128c6c7SMike Christie switch (param) { 214590134faSMike Christie case ISCSI_PARAM_PERSISTENT_ADDRESS: 215590134faSMike Christie case ISCSI_PARAM_PERSISTENT_PORT: 2163128c6c7SMike Christie case ISCSI_PARAM_CONN_ADDRESS: 2173128c6c7SMike Christie case ISCSI_PARAM_CONN_PORT: 2181d063c17SMike Christie case ISCSI_PARAM_TARGET_NAME: 2191d063c17SMike Christie case ISCSI_PARAM_TPGT: 2201d063c17SMike Christie case ISCSI_PARAM_TARGET_ALIAS: 221b3a271a9SManish Rangankar case ISCSI_PARAM_MAX_BURST: 222b3a271a9SManish Rangankar case ISCSI_PARAM_MAX_R2T: 223b3a271a9SManish Rangankar case ISCSI_PARAM_FIRST_BURST: 224b3a271a9SManish Rangankar case ISCSI_PARAM_MAX_RECV_DLENGTH: 225b3a271a9SManish Rangankar case ISCSI_PARAM_MAX_XMIT_DLENGTH: 226de37920bSMike Christie case ISCSI_PARAM_IFACE_NAME: 2273128c6c7SMike Christie return S_IRUGO; 2283128c6c7SMike Christie default: 2293128c6c7SMike Christie return 0; 2303128c6c7SMike Christie } 231b78dbba0SMike Christie case ISCSI_NET_PARAM: 232b78dbba0SMike Christie switch (param) { 233b78dbba0SMike Christie case ISCSI_NET_PARAM_IPV4_ADDR: 234b78dbba0SMike Christie case ISCSI_NET_PARAM_IPV4_SUBNET: 235b78dbba0SMike Christie case ISCSI_NET_PARAM_IPV4_GW: 236b78dbba0SMike Christie case ISCSI_NET_PARAM_IPV4_BOOTPROTO: 237b78dbba0SMike Christie case ISCSI_NET_PARAM_IFACE_ENABLE: 238b78dbba0SMike Christie case ISCSI_NET_PARAM_IPV6_LINKLOCAL: 239b78dbba0SMike Christie case ISCSI_NET_PARAM_IPV6_ADDR: 240b78dbba0SMike Christie case ISCSI_NET_PARAM_IPV6_ROUTER: 241b78dbba0SMike Christie case ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG: 242b78dbba0SMike Christie case ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG: 2436ac73e8cSVikas Chaudhary case ISCSI_NET_PARAM_VLAN_ID: 2446ac73e8cSVikas Chaudhary case ISCSI_NET_PARAM_VLAN_PRIORITY: 2456ac73e8cSVikas Chaudhary case ISCSI_NET_PARAM_VLAN_ENABLED: 246943c157bSVikas Chaudhary case ISCSI_NET_PARAM_MTU: 2472ada7fc5SVikas Chaudhary case ISCSI_NET_PARAM_PORT: 248b78dbba0SMike Christie return S_IRUGO; 249b78dbba0SMike Christie default: 250b78dbba0SMike Christie return 0; 251b78dbba0SMike Christie } 2523128c6c7SMike Christie } 2533128c6c7SMike Christie 2543128c6c7SMike Christie return 0; 2553128c6c7SMike Christie } 2563128c6c7SMike Christie 257ed1086e0SVikas Chaudhary static int qla4xxx_get_iface_param(struct iscsi_iface *iface, 258ed1086e0SVikas Chaudhary enum iscsi_param_type param_type, 259ed1086e0SVikas Chaudhary int param, char *buf) 260ed1086e0SVikas Chaudhary { 261ed1086e0SVikas Chaudhary struct Scsi_Host *shost = iscsi_iface_to_shost(iface); 262ed1086e0SVikas Chaudhary struct scsi_qla_host *ha = to_qla_host(shost); 263ed1086e0SVikas Chaudhary int len = -ENOSYS; 264ed1086e0SVikas Chaudhary 265ed1086e0SVikas Chaudhary if (param_type != ISCSI_NET_PARAM) 266ed1086e0SVikas Chaudhary return -ENOSYS; 267ed1086e0SVikas Chaudhary 268ed1086e0SVikas Chaudhary switch (param) { 269ed1086e0SVikas Chaudhary case ISCSI_NET_PARAM_IPV4_ADDR: 270ed1086e0SVikas Chaudhary len = sprintf(buf, "%pI4\n", &ha->ip_config.ip_address); 271ed1086e0SVikas Chaudhary break; 272ed1086e0SVikas Chaudhary case ISCSI_NET_PARAM_IPV4_SUBNET: 273ed1086e0SVikas Chaudhary len = sprintf(buf, "%pI4\n", &ha->ip_config.subnet_mask); 274ed1086e0SVikas Chaudhary break; 275ed1086e0SVikas Chaudhary case ISCSI_NET_PARAM_IPV4_GW: 276ed1086e0SVikas Chaudhary len = sprintf(buf, "%pI4\n", &ha->ip_config.gateway); 277ed1086e0SVikas Chaudhary break; 278ed1086e0SVikas Chaudhary case ISCSI_NET_PARAM_IFACE_ENABLE: 279ed1086e0SVikas Chaudhary if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) 280ed1086e0SVikas Chaudhary len = sprintf(buf, "%s\n", 281ed1086e0SVikas Chaudhary (ha->ip_config.ipv4_options & 282ed1086e0SVikas Chaudhary IPOPT_IPV4_PROTOCOL_ENABLE) ? 283ed1086e0SVikas Chaudhary "enabled" : "disabled"); 284ed1086e0SVikas Chaudhary else if (iface->iface_type == ISCSI_IFACE_TYPE_IPV6) 285ed1086e0SVikas Chaudhary len = sprintf(buf, "%s\n", 286ed1086e0SVikas Chaudhary (ha->ip_config.ipv6_options & 287ed1086e0SVikas Chaudhary IPV6_OPT_IPV6_PROTOCOL_ENABLE) ? 288ed1086e0SVikas Chaudhary "enabled" : "disabled"); 289ed1086e0SVikas Chaudhary break; 290ed1086e0SVikas Chaudhary case ISCSI_NET_PARAM_IPV4_BOOTPROTO: 291ed1086e0SVikas Chaudhary len = sprintf(buf, "%s\n", 292ed1086e0SVikas Chaudhary (ha->ip_config.tcp_options & TCPOPT_DHCP_ENABLE) ? 293ed1086e0SVikas Chaudhary "dhcp" : "static"); 294ed1086e0SVikas Chaudhary break; 295ed1086e0SVikas Chaudhary case ISCSI_NET_PARAM_IPV6_ADDR: 296ed1086e0SVikas Chaudhary if (iface->iface_num == 0) 297ed1086e0SVikas Chaudhary len = sprintf(buf, "%pI6\n", &ha->ip_config.ipv6_addr0); 298ed1086e0SVikas Chaudhary if (iface->iface_num == 1) 299ed1086e0SVikas Chaudhary len = sprintf(buf, "%pI6\n", &ha->ip_config.ipv6_addr1); 300ed1086e0SVikas Chaudhary break; 301ed1086e0SVikas Chaudhary case ISCSI_NET_PARAM_IPV6_LINKLOCAL: 302ed1086e0SVikas Chaudhary len = sprintf(buf, "%pI6\n", 303ed1086e0SVikas Chaudhary &ha->ip_config.ipv6_link_local_addr); 304ed1086e0SVikas Chaudhary break; 305ed1086e0SVikas Chaudhary case ISCSI_NET_PARAM_IPV6_ROUTER: 306ed1086e0SVikas Chaudhary len = sprintf(buf, "%pI6\n", 307ed1086e0SVikas Chaudhary &ha->ip_config.ipv6_default_router_addr); 308ed1086e0SVikas Chaudhary break; 309ed1086e0SVikas Chaudhary case ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG: 310ed1086e0SVikas Chaudhary len = sprintf(buf, "%s\n", 311ed1086e0SVikas Chaudhary (ha->ip_config.ipv6_addl_options & 312ed1086e0SVikas Chaudhary IPV6_ADDOPT_NEIGHBOR_DISCOVERY_ADDR_ENABLE) ? 313ed1086e0SVikas Chaudhary "nd" : "static"); 314ed1086e0SVikas Chaudhary break; 315ed1086e0SVikas Chaudhary case ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG: 316ed1086e0SVikas Chaudhary len = sprintf(buf, "%s\n", 317ed1086e0SVikas Chaudhary (ha->ip_config.ipv6_addl_options & 318ed1086e0SVikas Chaudhary IPV6_ADDOPT_AUTOCONFIG_LINK_LOCAL_ADDR) ? 319ed1086e0SVikas Chaudhary "auto" : "static"); 320ed1086e0SVikas Chaudhary break; 3216ac73e8cSVikas Chaudhary case ISCSI_NET_PARAM_VLAN_ID: 3226ac73e8cSVikas Chaudhary if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) 3236ac73e8cSVikas Chaudhary len = sprintf(buf, "%d\n", 3246ac73e8cSVikas Chaudhary (ha->ip_config.ipv4_vlan_tag & 3256ac73e8cSVikas Chaudhary ISCSI_MAX_VLAN_ID)); 3266ac73e8cSVikas Chaudhary else if (iface->iface_type == ISCSI_IFACE_TYPE_IPV6) 3276ac73e8cSVikas Chaudhary len = sprintf(buf, "%d\n", 3286ac73e8cSVikas Chaudhary (ha->ip_config.ipv6_vlan_tag & 3296ac73e8cSVikas Chaudhary ISCSI_MAX_VLAN_ID)); 3306ac73e8cSVikas Chaudhary break; 3316ac73e8cSVikas Chaudhary case ISCSI_NET_PARAM_VLAN_PRIORITY: 3326ac73e8cSVikas Chaudhary if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) 3336ac73e8cSVikas Chaudhary len = sprintf(buf, "%d\n", 3346ac73e8cSVikas Chaudhary ((ha->ip_config.ipv4_vlan_tag >> 13) & 3356ac73e8cSVikas Chaudhary ISCSI_MAX_VLAN_PRIORITY)); 3366ac73e8cSVikas Chaudhary else if (iface->iface_type == ISCSI_IFACE_TYPE_IPV6) 3376ac73e8cSVikas Chaudhary len = sprintf(buf, "%d\n", 3386ac73e8cSVikas Chaudhary ((ha->ip_config.ipv6_vlan_tag >> 13) & 3396ac73e8cSVikas Chaudhary ISCSI_MAX_VLAN_PRIORITY)); 3406ac73e8cSVikas Chaudhary break; 3416ac73e8cSVikas Chaudhary case ISCSI_NET_PARAM_VLAN_ENABLED: 3426ac73e8cSVikas Chaudhary if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) 3436ac73e8cSVikas Chaudhary len = sprintf(buf, "%s\n", 3446ac73e8cSVikas Chaudhary (ha->ip_config.ipv4_options & 3456ac73e8cSVikas Chaudhary IPOPT_VLAN_TAGGING_ENABLE) ? 3466ac73e8cSVikas Chaudhary "enabled" : "disabled"); 3476ac73e8cSVikas Chaudhary else if (iface->iface_type == ISCSI_IFACE_TYPE_IPV6) 3486ac73e8cSVikas Chaudhary len = sprintf(buf, "%s\n", 3496ac73e8cSVikas Chaudhary (ha->ip_config.ipv6_options & 3506ac73e8cSVikas Chaudhary IPV6_OPT_VLAN_TAGGING_ENABLE) ? 3516ac73e8cSVikas Chaudhary "enabled" : "disabled"); 3526ac73e8cSVikas Chaudhary break; 353943c157bSVikas Chaudhary case ISCSI_NET_PARAM_MTU: 354943c157bSVikas Chaudhary len = sprintf(buf, "%d\n", ha->ip_config.eth_mtu_size); 355943c157bSVikas Chaudhary break; 3562ada7fc5SVikas Chaudhary case ISCSI_NET_PARAM_PORT: 3572ada7fc5SVikas Chaudhary if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) 3582ada7fc5SVikas Chaudhary len = sprintf(buf, "%d\n", ha->ip_config.ipv4_port); 3592ada7fc5SVikas Chaudhary else if (iface->iface_type == ISCSI_IFACE_TYPE_IPV6) 3602ada7fc5SVikas Chaudhary len = sprintf(buf, "%d\n", ha->ip_config.ipv6_port); 3612ada7fc5SVikas Chaudhary break; 362ed1086e0SVikas Chaudhary default: 363ed1086e0SVikas Chaudhary len = -ENOSYS; 364ed1086e0SVikas Chaudhary } 365ed1086e0SVikas Chaudhary 366ed1086e0SVikas Chaudhary return len; 367ed1086e0SVikas Chaudhary } 368ed1086e0SVikas Chaudhary 369b3a271a9SManish Rangankar static struct iscsi_endpoint * 370b3a271a9SManish Rangankar qla4xxx_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr, 371b3a271a9SManish Rangankar int non_blocking) 372b3a271a9SManish Rangankar { 373b3a271a9SManish Rangankar int ret; 374b3a271a9SManish Rangankar struct iscsi_endpoint *ep; 375b3a271a9SManish Rangankar struct qla_endpoint *qla_ep; 376b3a271a9SManish Rangankar struct scsi_qla_host *ha; 377b3a271a9SManish Rangankar struct sockaddr_in *addr; 378b3a271a9SManish Rangankar struct sockaddr_in6 *addr6; 379b3a271a9SManish Rangankar 380b3a271a9SManish Rangankar DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); 381b3a271a9SManish Rangankar if (!shost) { 382b3a271a9SManish Rangankar ret = -ENXIO; 383b3a271a9SManish Rangankar printk(KERN_ERR "%s: shost is NULL\n", 384b3a271a9SManish Rangankar __func__); 385b3a271a9SManish Rangankar return ERR_PTR(ret); 386b3a271a9SManish Rangankar } 387b3a271a9SManish Rangankar 388b3a271a9SManish Rangankar ha = iscsi_host_priv(shost); 389b3a271a9SManish Rangankar 390b3a271a9SManish Rangankar ep = iscsi_create_endpoint(sizeof(struct qla_endpoint)); 391b3a271a9SManish Rangankar if (!ep) { 392b3a271a9SManish Rangankar ret = -ENOMEM; 393b3a271a9SManish Rangankar return ERR_PTR(ret); 394b3a271a9SManish Rangankar } 395b3a271a9SManish Rangankar 396b3a271a9SManish Rangankar qla_ep = ep->dd_data; 397b3a271a9SManish Rangankar memset(qla_ep, 0, sizeof(struct qla_endpoint)); 398b3a271a9SManish Rangankar if (dst_addr->sa_family == AF_INET) { 399b3a271a9SManish Rangankar memcpy(&qla_ep->dst_addr, dst_addr, sizeof(struct sockaddr_in)); 400b3a271a9SManish Rangankar addr = (struct sockaddr_in *)&qla_ep->dst_addr; 401b3a271a9SManish Rangankar DEBUG2(ql4_printk(KERN_INFO, ha, "%s: %pI4\n", __func__, 402b3a271a9SManish Rangankar (char *)&addr->sin_addr)); 403b3a271a9SManish Rangankar } else if (dst_addr->sa_family == AF_INET6) { 404b3a271a9SManish Rangankar memcpy(&qla_ep->dst_addr, dst_addr, 405b3a271a9SManish Rangankar sizeof(struct sockaddr_in6)); 406b3a271a9SManish Rangankar addr6 = (struct sockaddr_in6 *)&qla_ep->dst_addr; 407b3a271a9SManish Rangankar DEBUG2(ql4_printk(KERN_INFO, ha, "%s: %pI6\n", __func__, 408b3a271a9SManish Rangankar (char *)&addr6->sin6_addr)); 409b3a271a9SManish Rangankar } 410b3a271a9SManish Rangankar 411b3a271a9SManish Rangankar qla_ep->host = shost; 412b3a271a9SManish Rangankar 413b3a271a9SManish Rangankar return ep; 414b3a271a9SManish Rangankar } 415b3a271a9SManish Rangankar 416b3a271a9SManish Rangankar static int qla4xxx_ep_poll(struct iscsi_endpoint *ep, int timeout_ms) 417b3a271a9SManish Rangankar { 418b3a271a9SManish Rangankar struct qla_endpoint *qla_ep; 419b3a271a9SManish Rangankar struct scsi_qla_host *ha; 420b3a271a9SManish Rangankar int ret = 0; 421b3a271a9SManish Rangankar 422b3a271a9SManish Rangankar DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); 423b3a271a9SManish Rangankar qla_ep = ep->dd_data; 424b3a271a9SManish Rangankar ha = to_qla_host(qla_ep->host); 425b3a271a9SManish Rangankar 42613483730SMike Christie if (adapter_up(ha) && !test_bit(AF_BUILD_DDB_LIST, &ha->flags)) 427b3a271a9SManish Rangankar ret = 1; 428b3a271a9SManish Rangankar 429b3a271a9SManish Rangankar return ret; 430b3a271a9SManish Rangankar } 431b3a271a9SManish Rangankar 432b3a271a9SManish Rangankar static void qla4xxx_ep_disconnect(struct iscsi_endpoint *ep) 433b3a271a9SManish Rangankar { 434b3a271a9SManish Rangankar DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); 435b3a271a9SManish Rangankar iscsi_destroy_endpoint(ep); 436b3a271a9SManish Rangankar } 437b3a271a9SManish Rangankar 438b3a271a9SManish Rangankar static int qla4xxx_get_ep_param(struct iscsi_endpoint *ep, 439b3a271a9SManish Rangankar enum iscsi_param param, 440b3a271a9SManish Rangankar char *buf) 441b3a271a9SManish Rangankar { 442b3a271a9SManish Rangankar struct qla_endpoint *qla_ep = ep->dd_data; 443b3a271a9SManish Rangankar struct sockaddr *dst_addr; 444b3a271a9SManish Rangankar 445b3a271a9SManish Rangankar DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); 446b3a271a9SManish Rangankar 447b3a271a9SManish Rangankar switch (param) { 448b3a271a9SManish Rangankar case ISCSI_PARAM_CONN_PORT: 449b3a271a9SManish Rangankar case ISCSI_PARAM_CONN_ADDRESS: 450b3a271a9SManish Rangankar if (!qla_ep) 451b3a271a9SManish Rangankar return -ENOTCONN; 452b3a271a9SManish Rangankar 453b3a271a9SManish Rangankar dst_addr = (struct sockaddr *)&qla_ep->dst_addr; 454b3a271a9SManish Rangankar if (!dst_addr) 455b3a271a9SManish Rangankar return -ENOTCONN; 456b3a271a9SManish Rangankar 457b3a271a9SManish Rangankar return iscsi_conn_get_addr_param((struct sockaddr_storage *) 458b3a271a9SManish Rangankar &qla_ep->dst_addr, param, buf); 459b3a271a9SManish Rangankar default: 460b3a271a9SManish Rangankar return -ENOSYS; 461b3a271a9SManish Rangankar } 462b3a271a9SManish Rangankar } 463b3a271a9SManish Rangankar 464b3a271a9SManish Rangankar static void qla4xxx_conn_get_stats(struct iscsi_cls_conn *cls_conn, 465b3a271a9SManish Rangankar struct iscsi_stats *stats) 466b3a271a9SManish Rangankar { 467b3a271a9SManish Rangankar struct iscsi_session *sess; 468b3a271a9SManish Rangankar struct iscsi_cls_session *cls_sess; 469b3a271a9SManish Rangankar struct ddb_entry *ddb_entry; 470b3a271a9SManish Rangankar struct scsi_qla_host *ha; 471b3a271a9SManish Rangankar struct ql_iscsi_stats *ql_iscsi_stats; 472b3a271a9SManish Rangankar int stats_size; 473b3a271a9SManish Rangankar int ret; 474b3a271a9SManish Rangankar dma_addr_t iscsi_stats_dma; 475b3a271a9SManish Rangankar 476b3a271a9SManish Rangankar DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); 477b3a271a9SManish Rangankar 478b3a271a9SManish Rangankar cls_sess = iscsi_conn_to_session(cls_conn); 479b3a271a9SManish Rangankar sess = cls_sess->dd_data; 480b3a271a9SManish Rangankar ddb_entry = sess->dd_data; 481b3a271a9SManish Rangankar ha = ddb_entry->ha; 482b3a271a9SManish Rangankar 483b3a271a9SManish Rangankar stats_size = PAGE_ALIGN(sizeof(struct ql_iscsi_stats)); 484b3a271a9SManish Rangankar /* Allocate memory */ 485b3a271a9SManish Rangankar ql_iscsi_stats = dma_alloc_coherent(&ha->pdev->dev, stats_size, 486b3a271a9SManish Rangankar &iscsi_stats_dma, GFP_KERNEL); 487b3a271a9SManish Rangankar if (!ql_iscsi_stats) { 488b3a271a9SManish Rangankar ql4_printk(KERN_ERR, ha, 489b3a271a9SManish Rangankar "Unable to allocate memory for iscsi stats\n"); 490b3a271a9SManish Rangankar goto exit_get_stats; 491b3a271a9SManish Rangankar } 492b3a271a9SManish Rangankar 493b3a271a9SManish Rangankar ret = qla4xxx_get_mgmt_data(ha, ddb_entry->fw_ddb_index, stats_size, 494b3a271a9SManish Rangankar iscsi_stats_dma); 495b3a271a9SManish Rangankar if (ret != QLA_SUCCESS) { 496b3a271a9SManish Rangankar ql4_printk(KERN_ERR, ha, 497b3a271a9SManish Rangankar "Unable to retreive iscsi stats\n"); 498b3a271a9SManish Rangankar goto free_stats; 499b3a271a9SManish Rangankar } 500b3a271a9SManish Rangankar 501b3a271a9SManish Rangankar /* octets */ 502b3a271a9SManish Rangankar stats->txdata_octets = le64_to_cpu(ql_iscsi_stats->tx_data_octets); 503b3a271a9SManish Rangankar stats->rxdata_octets = le64_to_cpu(ql_iscsi_stats->rx_data_octets); 504b3a271a9SManish Rangankar /* xmit pdus */ 505b3a271a9SManish Rangankar stats->noptx_pdus = le32_to_cpu(ql_iscsi_stats->tx_nopout_pdus); 506b3a271a9SManish Rangankar stats->scsicmd_pdus = le32_to_cpu(ql_iscsi_stats->tx_scsi_cmd_pdus); 507b3a271a9SManish Rangankar stats->tmfcmd_pdus = le32_to_cpu(ql_iscsi_stats->tx_tmf_cmd_pdus); 508b3a271a9SManish Rangankar stats->login_pdus = le32_to_cpu(ql_iscsi_stats->tx_login_cmd_pdus); 509b3a271a9SManish Rangankar stats->text_pdus = le32_to_cpu(ql_iscsi_stats->tx_text_cmd_pdus); 510b3a271a9SManish Rangankar stats->dataout_pdus = le32_to_cpu(ql_iscsi_stats->tx_scsi_write_pdus); 511b3a271a9SManish Rangankar stats->logout_pdus = le32_to_cpu(ql_iscsi_stats->tx_logout_cmd_pdus); 512b3a271a9SManish Rangankar stats->snack_pdus = le32_to_cpu(ql_iscsi_stats->tx_snack_req_pdus); 513b3a271a9SManish Rangankar /* recv pdus */ 514b3a271a9SManish Rangankar stats->noprx_pdus = le32_to_cpu(ql_iscsi_stats->rx_nopin_pdus); 515b3a271a9SManish Rangankar stats->scsirsp_pdus = le32_to_cpu(ql_iscsi_stats->rx_scsi_resp_pdus); 516b3a271a9SManish Rangankar stats->tmfrsp_pdus = le32_to_cpu(ql_iscsi_stats->rx_tmf_resp_pdus); 517b3a271a9SManish Rangankar stats->textrsp_pdus = le32_to_cpu(ql_iscsi_stats->rx_text_resp_pdus); 518b3a271a9SManish Rangankar stats->datain_pdus = le32_to_cpu(ql_iscsi_stats->rx_scsi_read_pdus); 519b3a271a9SManish Rangankar stats->logoutrsp_pdus = 520b3a271a9SManish Rangankar le32_to_cpu(ql_iscsi_stats->rx_logout_resp_pdus); 521b3a271a9SManish Rangankar stats->r2t_pdus = le32_to_cpu(ql_iscsi_stats->rx_r2t_pdus); 522b3a271a9SManish Rangankar stats->async_pdus = le32_to_cpu(ql_iscsi_stats->rx_async_pdus); 523b3a271a9SManish Rangankar stats->rjt_pdus = le32_to_cpu(ql_iscsi_stats->rx_reject_pdus); 524b3a271a9SManish Rangankar 525b3a271a9SManish Rangankar free_stats: 526b3a271a9SManish Rangankar dma_free_coherent(&ha->pdev->dev, stats_size, ql_iscsi_stats, 527b3a271a9SManish Rangankar iscsi_stats_dma); 528b3a271a9SManish Rangankar exit_get_stats: 529b3a271a9SManish Rangankar return; 530b3a271a9SManish Rangankar } 531b3a271a9SManish Rangankar 5325c656af7SMike Christie static enum blk_eh_timer_return qla4xxx_eh_cmd_timed_out(struct scsi_cmnd *sc) 5335c656af7SMike Christie { 5345c656af7SMike Christie struct iscsi_cls_session *session; 535b3a271a9SManish Rangankar struct iscsi_session *sess; 536b3a271a9SManish Rangankar unsigned long flags; 537b3a271a9SManish Rangankar enum blk_eh_timer_return ret = BLK_EH_NOT_HANDLED; 5385c656af7SMike Christie 5395c656af7SMike Christie session = starget_to_session(scsi_target(sc->device)); 540b3a271a9SManish Rangankar sess = session->dd_data; 5415c656af7SMike Christie 542b3a271a9SManish Rangankar spin_lock_irqsave(&session->lock, flags); 543b3a271a9SManish Rangankar if (session->state == ISCSI_SESSION_FAILED) 544b3a271a9SManish Rangankar ret = BLK_EH_RESET_TIMER; 545b3a271a9SManish Rangankar spin_unlock_irqrestore(&session->lock, flags); 5465c656af7SMike Christie 547b3a271a9SManish Rangankar return ret; 548568d303bSMike Christie } 549afaf5a2dSDavid Somayajulu 550aa1e93a2SMike Christie static int qla4xxx_host_get_param(struct Scsi_Host *shost, 551aa1e93a2SMike Christie enum iscsi_host_param param, char *buf) 552aa1e93a2SMike Christie { 553aa1e93a2SMike Christie struct scsi_qla_host *ha = to_qla_host(shost); 554aa1e93a2SMike Christie int len; 555aa1e93a2SMike Christie 556aa1e93a2SMike Christie switch (param) { 557aa1e93a2SMike Christie case ISCSI_HOST_PARAM_HWADDRESS: 5587ffc49a6SMichael Chan len = sysfs_format_mac(buf, ha->my_mac, MAC_ADDR_LEN); 559aa1e93a2SMike Christie break; 56022236961SMike Christie case ISCSI_HOST_PARAM_IPADDRESS: 5612bab08fcSVikas Chaudhary len = sprintf(buf, "%pI4\n", &ha->ip_config.ip_address); 56222236961SMike Christie break; 5638ad5781aSMike Christie case ISCSI_HOST_PARAM_INITIATOR_NAME: 56422236961SMike Christie len = sprintf(buf, "%s\n", ha->name_string); 5658ad5781aSMike Christie break; 566aa1e93a2SMike Christie default: 567aa1e93a2SMike Christie return -ENOSYS; 568aa1e93a2SMike Christie } 569aa1e93a2SMike Christie 570aa1e93a2SMike Christie return len; 571aa1e93a2SMike Christie } 572aa1e93a2SMike Christie 573ed1086e0SVikas Chaudhary static void qla4xxx_create_ipv4_iface(struct scsi_qla_host *ha) 574ed1086e0SVikas Chaudhary { 575ed1086e0SVikas Chaudhary if (ha->iface_ipv4) 576ed1086e0SVikas Chaudhary return; 577ed1086e0SVikas Chaudhary 578ed1086e0SVikas Chaudhary /* IPv4 */ 579ed1086e0SVikas Chaudhary ha->iface_ipv4 = iscsi_create_iface(ha->host, 580ed1086e0SVikas Chaudhary &qla4xxx_iscsi_transport, 581ed1086e0SVikas Chaudhary ISCSI_IFACE_TYPE_IPV4, 0, 0); 582ed1086e0SVikas Chaudhary if (!ha->iface_ipv4) 583ed1086e0SVikas Chaudhary ql4_printk(KERN_ERR, ha, "Could not create IPv4 iSCSI " 584ed1086e0SVikas Chaudhary "iface0.\n"); 585ed1086e0SVikas Chaudhary } 586ed1086e0SVikas Chaudhary 587ed1086e0SVikas Chaudhary static void qla4xxx_create_ipv6_iface(struct scsi_qla_host *ha) 588ed1086e0SVikas Chaudhary { 589ed1086e0SVikas Chaudhary if (!ha->iface_ipv6_0) 590ed1086e0SVikas Chaudhary /* IPv6 iface-0 */ 591ed1086e0SVikas Chaudhary ha->iface_ipv6_0 = iscsi_create_iface(ha->host, 592ed1086e0SVikas Chaudhary &qla4xxx_iscsi_transport, 593ed1086e0SVikas Chaudhary ISCSI_IFACE_TYPE_IPV6, 0, 594ed1086e0SVikas Chaudhary 0); 595ed1086e0SVikas Chaudhary if (!ha->iface_ipv6_0) 596ed1086e0SVikas Chaudhary ql4_printk(KERN_ERR, ha, "Could not create IPv6 iSCSI " 597ed1086e0SVikas Chaudhary "iface0.\n"); 598ed1086e0SVikas Chaudhary 599ed1086e0SVikas Chaudhary if (!ha->iface_ipv6_1) 600ed1086e0SVikas Chaudhary /* IPv6 iface-1 */ 601ed1086e0SVikas Chaudhary ha->iface_ipv6_1 = iscsi_create_iface(ha->host, 602ed1086e0SVikas Chaudhary &qla4xxx_iscsi_transport, 603ed1086e0SVikas Chaudhary ISCSI_IFACE_TYPE_IPV6, 1, 604ed1086e0SVikas Chaudhary 0); 605ed1086e0SVikas Chaudhary if (!ha->iface_ipv6_1) 606ed1086e0SVikas Chaudhary ql4_printk(KERN_ERR, ha, "Could not create IPv6 iSCSI " 607ed1086e0SVikas Chaudhary "iface1.\n"); 608ed1086e0SVikas Chaudhary } 609ed1086e0SVikas Chaudhary 610ed1086e0SVikas Chaudhary static void qla4xxx_create_ifaces(struct scsi_qla_host *ha) 611ed1086e0SVikas Chaudhary { 612ed1086e0SVikas Chaudhary if (ha->ip_config.ipv4_options & IPOPT_IPV4_PROTOCOL_ENABLE) 613ed1086e0SVikas Chaudhary qla4xxx_create_ipv4_iface(ha); 614ed1086e0SVikas Chaudhary 615ed1086e0SVikas Chaudhary if (ha->ip_config.ipv6_options & IPV6_OPT_IPV6_PROTOCOL_ENABLE) 616ed1086e0SVikas Chaudhary qla4xxx_create_ipv6_iface(ha); 617ed1086e0SVikas Chaudhary } 618ed1086e0SVikas Chaudhary 619ed1086e0SVikas Chaudhary static void qla4xxx_destroy_ipv4_iface(struct scsi_qla_host *ha) 620ed1086e0SVikas Chaudhary { 621ed1086e0SVikas Chaudhary if (ha->iface_ipv4) { 622ed1086e0SVikas Chaudhary iscsi_destroy_iface(ha->iface_ipv4); 623ed1086e0SVikas Chaudhary ha->iface_ipv4 = NULL; 624ed1086e0SVikas Chaudhary } 625ed1086e0SVikas Chaudhary } 626ed1086e0SVikas Chaudhary 627ed1086e0SVikas Chaudhary static void qla4xxx_destroy_ipv6_iface(struct scsi_qla_host *ha) 628ed1086e0SVikas Chaudhary { 629ed1086e0SVikas Chaudhary if (ha->iface_ipv6_0) { 630ed1086e0SVikas Chaudhary iscsi_destroy_iface(ha->iface_ipv6_0); 631ed1086e0SVikas Chaudhary ha->iface_ipv6_0 = NULL; 632ed1086e0SVikas Chaudhary } 633ed1086e0SVikas Chaudhary if (ha->iface_ipv6_1) { 634ed1086e0SVikas Chaudhary iscsi_destroy_iface(ha->iface_ipv6_1); 635ed1086e0SVikas Chaudhary ha->iface_ipv6_1 = NULL; 636ed1086e0SVikas Chaudhary } 637ed1086e0SVikas Chaudhary } 638ed1086e0SVikas Chaudhary 639ed1086e0SVikas Chaudhary static void qla4xxx_destroy_ifaces(struct scsi_qla_host *ha) 640ed1086e0SVikas Chaudhary { 641ed1086e0SVikas Chaudhary qla4xxx_destroy_ipv4_iface(ha); 642ed1086e0SVikas Chaudhary qla4xxx_destroy_ipv6_iface(ha); 643ed1086e0SVikas Chaudhary } 644ed1086e0SVikas Chaudhary 645d00efe3fSMike Christie static void qla4xxx_set_ipv6(struct scsi_qla_host *ha, 646d00efe3fSMike Christie struct iscsi_iface_param_info *iface_param, 647d00efe3fSMike Christie struct addr_ctrl_blk *init_fw_cb) 648d00efe3fSMike Christie { 649d00efe3fSMike Christie /* 650d00efe3fSMike Christie * iface_num 0 is valid for IPv6 Addr, linklocal, router, autocfg. 651d00efe3fSMike Christie * iface_num 1 is valid only for IPv6 Addr. 652d00efe3fSMike Christie */ 653d00efe3fSMike Christie switch (iface_param->param) { 654d00efe3fSMike Christie case ISCSI_NET_PARAM_IPV6_ADDR: 655d00efe3fSMike Christie if (iface_param->iface_num & 0x1) 656d00efe3fSMike Christie /* IPv6 Addr 1 */ 657d00efe3fSMike Christie memcpy(init_fw_cb->ipv6_addr1, iface_param->value, 658d00efe3fSMike Christie sizeof(init_fw_cb->ipv6_addr1)); 659d00efe3fSMike Christie else 660d00efe3fSMike Christie /* IPv6 Addr 0 */ 661d00efe3fSMike Christie memcpy(init_fw_cb->ipv6_addr0, iface_param->value, 662d00efe3fSMike Christie sizeof(init_fw_cb->ipv6_addr0)); 663d00efe3fSMike Christie break; 664d00efe3fSMike Christie case ISCSI_NET_PARAM_IPV6_LINKLOCAL: 665d00efe3fSMike Christie if (iface_param->iface_num & 0x1) 666d00efe3fSMike Christie break; 667d00efe3fSMike Christie memcpy(init_fw_cb->ipv6_if_id, &iface_param->value[8], 668d00efe3fSMike Christie sizeof(init_fw_cb->ipv6_if_id)); 669d00efe3fSMike Christie break; 670d00efe3fSMike Christie case ISCSI_NET_PARAM_IPV6_ROUTER: 671d00efe3fSMike Christie if (iface_param->iface_num & 0x1) 672d00efe3fSMike Christie break; 673d00efe3fSMike Christie memcpy(init_fw_cb->ipv6_dflt_rtr_addr, iface_param->value, 674d00efe3fSMike Christie sizeof(init_fw_cb->ipv6_dflt_rtr_addr)); 675d00efe3fSMike Christie break; 676d00efe3fSMike Christie case ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG: 677d00efe3fSMike Christie /* Autocfg applies to even interface */ 678d00efe3fSMike Christie if (iface_param->iface_num & 0x1) 679d00efe3fSMike Christie break; 680d00efe3fSMike Christie 681d00efe3fSMike Christie if (iface_param->value[0] == ISCSI_IPV6_AUTOCFG_DISABLE) 682d00efe3fSMike Christie init_fw_cb->ipv6_addtl_opts &= 683d00efe3fSMike Christie cpu_to_le16( 684d00efe3fSMike Christie ~IPV6_ADDOPT_NEIGHBOR_DISCOVERY_ADDR_ENABLE); 685d00efe3fSMike Christie else if (iface_param->value[0] == ISCSI_IPV6_AUTOCFG_ND_ENABLE) 686d00efe3fSMike Christie init_fw_cb->ipv6_addtl_opts |= 687d00efe3fSMike Christie cpu_to_le16( 688d00efe3fSMike Christie IPV6_ADDOPT_NEIGHBOR_DISCOVERY_ADDR_ENABLE); 689d00efe3fSMike Christie else 690d00efe3fSMike Christie ql4_printk(KERN_ERR, ha, "Invalid autocfg setting for " 691d00efe3fSMike Christie "IPv6 addr\n"); 692d00efe3fSMike Christie break; 693d00efe3fSMike Christie case ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG: 694d00efe3fSMike Christie /* Autocfg applies to even interface */ 695d00efe3fSMike Christie if (iface_param->iface_num & 0x1) 696d00efe3fSMike Christie break; 697d00efe3fSMike Christie 698d00efe3fSMike Christie if (iface_param->value[0] == 699d00efe3fSMike Christie ISCSI_IPV6_LINKLOCAL_AUTOCFG_ENABLE) 700d00efe3fSMike Christie init_fw_cb->ipv6_addtl_opts |= cpu_to_le16( 701d00efe3fSMike Christie IPV6_ADDOPT_AUTOCONFIG_LINK_LOCAL_ADDR); 702d00efe3fSMike Christie else if (iface_param->value[0] == 703d00efe3fSMike Christie ISCSI_IPV6_LINKLOCAL_AUTOCFG_DISABLE) 704d00efe3fSMike Christie init_fw_cb->ipv6_addtl_opts &= cpu_to_le16( 705d00efe3fSMike Christie ~IPV6_ADDOPT_AUTOCONFIG_LINK_LOCAL_ADDR); 706d00efe3fSMike Christie else 707d00efe3fSMike Christie ql4_printk(KERN_ERR, ha, "Invalid autocfg setting for " 708d00efe3fSMike Christie "IPv6 linklocal addr\n"); 709d00efe3fSMike Christie break; 710d00efe3fSMike Christie case ISCSI_NET_PARAM_IPV6_ROUTER_AUTOCFG: 711d00efe3fSMike Christie /* Autocfg applies to even interface */ 712d00efe3fSMike Christie if (iface_param->iface_num & 0x1) 713d00efe3fSMike Christie break; 714d00efe3fSMike Christie 715d00efe3fSMike Christie if (iface_param->value[0] == ISCSI_IPV6_ROUTER_AUTOCFG_ENABLE) 716d00efe3fSMike Christie memset(init_fw_cb->ipv6_dflt_rtr_addr, 0, 717d00efe3fSMike Christie sizeof(init_fw_cb->ipv6_dflt_rtr_addr)); 718d00efe3fSMike Christie break; 719d00efe3fSMike Christie case ISCSI_NET_PARAM_IFACE_ENABLE: 720ed1086e0SVikas Chaudhary if (iface_param->value[0] == ISCSI_IFACE_ENABLE) { 721d00efe3fSMike Christie init_fw_cb->ipv6_opts |= 722d00efe3fSMike Christie cpu_to_le16(IPV6_OPT_IPV6_PROTOCOL_ENABLE); 723ed1086e0SVikas Chaudhary qla4xxx_create_ipv6_iface(ha); 724ed1086e0SVikas Chaudhary } else { 725d00efe3fSMike Christie init_fw_cb->ipv6_opts &= 726d00efe3fSMike Christie cpu_to_le16(~IPV6_OPT_IPV6_PROTOCOL_ENABLE & 727d00efe3fSMike Christie 0xFFFF); 728ed1086e0SVikas Chaudhary qla4xxx_destroy_ipv6_iface(ha); 729ed1086e0SVikas Chaudhary } 730d00efe3fSMike Christie break; 7312d63673bSMike Christie case ISCSI_NET_PARAM_VLAN_TAG: 732d00efe3fSMike Christie if (iface_param->len != sizeof(init_fw_cb->ipv6_vlan_tag)) 733d00efe3fSMike Christie break; 7346ac73e8cSVikas Chaudhary init_fw_cb->ipv6_vlan_tag = 7356ac73e8cSVikas Chaudhary cpu_to_be16(*(uint16_t *)iface_param->value); 7366ac73e8cSVikas Chaudhary break; 7376ac73e8cSVikas Chaudhary case ISCSI_NET_PARAM_VLAN_ENABLED: 7386ac73e8cSVikas Chaudhary if (iface_param->value[0] == ISCSI_VLAN_ENABLE) 7396ac73e8cSVikas Chaudhary init_fw_cb->ipv6_opts |= 7406ac73e8cSVikas Chaudhary cpu_to_le16(IPV6_OPT_VLAN_TAGGING_ENABLE); 7416ac73e8cSVikas Chaudhary else 7426ac73e8cSVikas Chaudhary init_fw_cb->ipv6_opts &= 7436ac73e8cSVikas Chaudhary cpu_to_le16(~IPV6_OPT_VLAN_TAGGING_ENABLE); 744d00efe3fSMike Christie break; 745943c157bSVikas Chaudhary case ISCSI_NET_PARAM_MTU: 746943c157bSVikas Chaudhary init_fw_cb->eth_mtu_size = 747943c157bSVikas Chaudhary cpu_to_le16(*(uint16_t *)iface_param->value); 748943c157bSVikas Chaudhary break; 7492ada7fc5SVikas Chaudhary case ISCSI_NET_PARAM_PORT: 7502ada7fc5SVikas Chaudhary /* Autocfg applies to even interface */ 7512ada7fc5SVikas Chaudhary if (iface_param->iface_num & 0x1) 7522ada7fc5SVikas Chaudhary break; 7532ada7fc5SVikas Chaudhary 7542ada7fc5SVikas Chaudhary init_fw_cb->ipv6_port = 7552ada7fc5SVikas Chaudhary cpu_to_le16(*(uint16_t *)iface_param->value); 7562ada7fc5SVikas Chaudhary break; 757d00efe3fSMike Christie default: 758d00efe3fSMike Christie ql4_printk(KERN_ERR, ha, "Unknown IPv6 param = %d\n", 759d00efe3fSMike Christie iface_param->param); 760d00efe3fSMike Christie break; 761d00efe3fSMike Christie } 762d00efe3fSMike Christie } 763d00efe3fSMike Christie 764d00efe3fSMike Christie static void qla4xxx_set_ipv4(struct scsi_qla_host *ha, 765d00efe3fSMike Christie struct iscsi_iface_param_info *iface_param, 766d00efe3fSMike Christie struct addr_ctrl_blk *init_fw_cb) 767d00efe3fSMike Christie { 768d00efe3fSMike Christie switch (iface_param->param) { 769d00efe3fSMike Christie case ISCSI_NET_PARAM_IPV4_ADDR: 770d00efe3fSMike Christie memcpy(init_fw_cb->ipv4_addr, iface_param->value, 771d00efe3fSMike Christie sizeof(init_fw_cb->ipv4_addr)); 772d00efe3fSMike Christie break; 773d00efe3fSMike Christie case ISCSI_NET_PARAM_IPV4_SUBNET: 774d00efe3fSMike Christie memcpy(init_fw_cb->ipv4_subnet, iface_param->value, 775d00efe3fSMike Christie sizeof(init_fw_cb->ipv4_subnet)); 776d00efe3fSMike Christie break; 777d00efe3fSMike Christie case ISCSI_NET_PARAM_IPV4_GW: 778d00efe3fSMike Christie memcpy(init_fw_cb->ipv4_gw_addr, iface_param->value, 779d00efe3fSMike Christie sizeof(init_fw_cb->ipv4_gw_addr)); 780d00efe3fSMike Christie break; 781d00efe3fSMike Christie case ISCSI_NET_PARAM_IPV4_BOOTPROTO: 782d00efe3fSMike Christie if (iface_param->value[0] == ISCSI_BOOTPROTO_DHCP) 783d00efe3fSMike Christie init_fw_cb->ipv4_tcp_opts |= 784d00efe3fSMike Christie cpu_to_le16(TCPOPT_DHCP_ENABLE); 785d00efe3fSMike Christie else if (iface_param->value[0] == ISCSI_BOOTPROTO_STATIC) 786d00efe3fSMike Christie init_fw_cb->ipv4_tcp_opts &= 787d00efe3fSMike Christie cpu_to_le16(~TCPOPT_DHCP_ENABLE); 788d00efe3fSMike Christie else 789d00efe3fSMike Christie ql4_printk(KERN_ERR, ha, "Invalid IPv4 bootproto\n"); 790d00efe3fSMike Christie break; 791d00efe3fSMike Christie case ISCSI_NET_PARAM_IFACE_ENABLE: 792ed1086e0SVikas Chaudhary if (iface_param->value[0] == ISCSI_IFACE_ENABLE) { 793d00efe3fSMike Christie init_fw_cb->ipv4_ip_opts |= 7942bab08fcSVikas Chaudhary cpu_to_le16(IPOPT_IPV4_PROTOCOL_ENABLE); 795ed1086e0SVikas Chaudhary qla4xxx_create_ipv4_iface(ha); 796ed1086e0SVikas Chaudhary } else { 797d00efe3fSMike Christie init_fw_cb->ipv4_ip_opts &= 7982bab08fcSVikas Chaudhary cpu_to_le16(~IPOPT_IPV4_PROTOCOL_ENABLE & 799d00efe3fSMike Christie 0xFFFF); 800ed1086e0SVikas Chaudhary qla4xxx_destroy_ipv4_iface(ha); 801ed1086e0SVikas Chaudhary } 802d00efe3fSMike Christie break; 8032d63673bSMike Christie case ISCSI_NET_PARAM_VLAN_TAG: 804d00efe3fSMike Christie if (iface_param->len != sizeof(init_fw_cb->ipv4_vlan_tag)) 805d00efe3fSMike Christie break; 8066ac73e8cSVikas Chaudhary init_fw_cb->ipv4_vlan_tag = 8076ac73e8cSVikas Chaudhary cpu_to_be16(*(uint16_t *)iface_param->value); 8086ac73e8cSVikas Chaudhary break; 8096ac73e8cSVikas Chaudhary case ISCSI_NET_PARAM_VLAN_ENABLED: 8106ac73e8cSVikas Chaudhary if (iface_param->value[0] == ISCSI_VLAN_ENABLE) 8116ac73e8cSVikas Chaudhary init_fw_cb->ipv4_ip_opts |= 8126ac73e8cSVikas Chaudhary cpu_to_le16(IPOPT_VLAN_TAGGING_ENABLE); 8136ac73e8cSVikas Chaudhary else 8146ac73e8cSVikas Chaudhary init_fw_cb->ipv4_ip_opts &= 8156ac73e8cSVikas Chaudhary cpu_to_le16(~IPOPT_VLAN_TAGGING_ENABLE); 816d00efe3fSMike Christie break; 817943c157bSVikas Chaudhary case ISCSI_NET_PARAM_MTU: 818943c157bSVikas Chaudhary init_fw_cb->eth_mtu_size = 819943c157bSVikas Chaudhary cpu_to_le16(*(uint16_t *)iface_param->value); 820943c157bSVikas Chaudhary break; 8212ada7fc5SVikas Chaudhary case ISCSI_NET_PARAM_PORT: 8222ada7fc5SVikas Chaudhary init_fw_cb->ipv4_port = 8232ada7fc5SVikas Chaudhary cpu_to_le16(*(uint16_t *)iface_param->value); 8242ada7fc5SVikas Chaudhary break; 825d00efe3fSMike Christie default: 826d00efe3fSMike Christie ql4_printk(KERN_ERR, ha, "Unknown IPv4 param = %d\n", 827d00efe3fSMike Christie iface_param->param); 828d00efe3fSMike Christie break; 829d00efe3fSMike Christie } 830d00efe3fSMike Christie } 831d00efe3fSMike Christie 832d00efe3fSMike Christie static void 833d00efe3fSMike Christie qla4xxx_initcb_to_acb(struct addr_ctrl_blk *init_fw_cb) 834d00efe3fSMike Christie { 835d00efe3fSMike Christie struct addr_ctrl_blk_def *acb; 836d00efe3fSMike Christie acb = (struct addr_ctrl_blk_def *)init_fw_cb; 837d00efe3fSMike Christie memset(acb->reserved1, 0, sizeof(acb->reserved1)); 838d00efe3fSMike Christie memset(acb->reserved2, 0, sizeof(acb->reserved2)); 839d00efe3fSMike Christie memset(acb->reserved3, 0, sizeof(acb->reserved3)); 840d00efe3fSMike Christie memset(acb->reserved4, 0, sizeof(acb->reserved4)); 841d00efe3fSMike Christie memset(acb->reserved5, 0, sizeof(acb->reserved5)); 842d00efe3fSMike Christie memset(acb->reserved6, 0, sizeof(acb->reserved6)); 843d00efe3fSMike Christie memset(acb->reserved7, 0, sizeof(acb->reserved7)); 844d00efe3fSMike Christie memset(acb->reserved8, 0, sizeof(acb->reserved8)); 845d00efe3fSMike Christie memset(acb->reserved9, 0, sizeof(acb->reserved9)); 846d00efe3fSMike Christie memset(acb->reserved10, 0, sizeof(acb->reserved10)); 847d00efe3fSMike Christie memset(acb->reserved11, 0, sizeof(acb->reserved11)); 848d00efe3fSMike Christie memset(acb->reserved12, 0, sizeof(acb->reserved12)); 849d00efe3fSMike Christie memset(acb->reserved13, 0, sizeof(acb->reserved13)); 850d00efe3fSMike Christie memset(acb->reserved14, 0, sizeof(acb->reserved14)); 851d00efe3fSMike Christie memset(acb->reserved15, 0, sizeof(acb->reserved15)); 852d00efe3fSMike Christie } 853d00efe3fSMike Christie 854d00efe3fSMike Christie static int 85500c31889SMike Christie qla4xxx_iface_set_param(struct Scsi_Host *shost, void *data, uint32_t len) 856d00efe3fSMike Christie { 857d00efe3fSMike Christie struct scsi_qla_host *ha = to_qla_host(shost); 858d00efe3fSMike Christie int rval = 0; 859d00efe3fSMike Christie struct iscsi_iface_param_info *iface_param = NULL; 860d00efe3fSMike Christie struct addr_ctrl_blk *init_fw_cb = NULL; 861d00efe3fSMike Christie dma_addr_t init_fw_cb_dma; 862d00efe3fSMike Christie uint32_t mbox_cmd[MBOX_REG_COUNT]; 863d00efe3fSMike Christie uint32_t mbox_sts[MBOX_REG_COUNT]; 86400c31889SMike Christie uint32_t rem = len; 86500c31889SMike Christie struct nlattr *attr; 866d00efe3fSMike Christie 867d00efe3fSMike Christie init_fw_cb = dma_alloc_coherent(&ha->pdev->dev, 868d00efe3fSMike Christie sizeof(struct addr_ctrl_blk), 869d00efe3fSMike Christie &init_fw_cb_dma, GFP_KERNEL); 870d00efe3fSMike Christie if (!init_fw_cb) { 871d00efe3fSMike Christie ql4_printk(KERN_ERR, ha, "%s: Unable to alloc init_cb\n", 872d00efe3fSMike Christie __func__); 873d00efe3fSMike Christie return -ENOMEM; 874d00efe3fSMike Christie } 875d00efe3fSMike Christie 876d00efe3fSMike Christie memset(init_fw_cb, 0, sizeof(struct addr_ctrl_blk)); 877d00efe3fSMike Christie memset(&mbox_cmd, 0, sizeof(mbox_cmd)); 878d00efe3fSMike Christie memset(&mbox_sts, 0, sizeof(mbox_sts)); 879d00efe3fSMike Christie 880d00efe3fSMike Christie if (qla4xxx_get_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb_dma)) { 881d00efe3fSMike Christie ql4_printk(KERN_ERR, ha, "%s: get ifcb failed\n", __func__); 882d00efe3fSMike Christie rval = -EIO; 883d00efe3fSMike Christie goto exit_init_fw_cb; 884d00efe3fSMike Christie } 885d00efe3fSMike Christie 88600c31889SMike Christie nla_for_each_attr(attr, data, len, rem) { 88700c31889SMike Christie iface_param = nla_data(attr); 888d00efe3fSMike Christie 889d00efe3fSMike Christie if (iface_param->param_type != ISCSI_NET_PARAM) 890d00efe3fSMike Christie continue; 891d00efe3fSMike Christie 892d00efe3fSMike Christie switch (iface_param->iface_type) { 893d00efe3fSMike Christie case ISCSI_IFACE_TYPE_IPV4: 894d00efe3fSMike Christie switch (iface_param->iface_num) { 895d00efe3fSMike Christie case 0: 896d00efe3fSMike Christie qla4xxx_set_ipv4(ha, iface_param, init_fw_cb); 897d00efe3fSMike Christie break; 898d00efe3fSMike Christie default: 899d00efe3fSMike Christie /* Cannot have more than one IPv4 interface */ 900d00efe3fSMike Christie ql4_printk(KERN_ERR, ha, "Invalid IPv4 iface " 901d00efe3fSMike Christie "number = %d\n", 902d00efe3fSMike Christie iface_param->iface_num); 903d00efe3fSMike Christie break; 904d00efe3fSMike Christie } 905d00efe3fSMike Christie break; 906d00efe3fSMike Christie case ISCSI_IFACE_TYPE_IPV6: 907d00efe3fSMike Christie switch (iface_param->iface_num) { 908d00efe3fSMike Christie case 0: 909d00efe3fSMike Christie case 1: 910d00efe3fSMike Christie qla4xxx_set_ipv6(ha, iface_param, init_fw_cb); 911d00efe3fSMike Christie break; 912d00efe3fSMike Christie default: 913d00efe3fSMike Christie /* Cannot have more than two IPv6 interface */ 914d00efe3fSMike Christie ql4_printk(KERN_ERR, ha, "Invalid IPv6 iface " 915d00efe3fSMike Christie "number = %d\n", 916d00efe3fSMike Christie iface_param->iface_num); 917d00efe3fSMike Christie break; 918d00efe3fSMike Christie } 919d00efe3fSMike Christie break; 920d00efe3fSMike Christie default: 921d00efe3fSMike Christie ql4_printk(KERN_ERR, ha, "Invalid iface type\n"); 922d00efe3fSMike Christie break; 923d00efe3fSMike Christie } 924d00efe3fSMike Christie } 925d00efe3fSMike Christie 926d00efe3fSMike Christie init_fw_cb->cookie = cpu_to_le32(0x11BEAD5A); 927d00efe3fSMike Christie 928d00efe3fSMike Christie rval = qla4xxx_set_flash(ha, init_fw_cb_dma, FLASH_SEGMENT_IFCB, 929d00efe3fSMike Christie sizeof(struct addr_ctrl_blk), 930d00efe3fSMike Christie FLASH_OPT_RMW_COMMIT); 931d00efe3fSMike Christie if (rval != QLA_SUCCESS) { 932d00efe3fSMike Christie ql4_printk(KERN_ERR, ha, "%s: set flash mbx failed\n", 933d00efe3fSMike Christie __func__); 934d00efe3fSMike Christie rval = -EIO; 935d00efe3fSMike Christie goto exit_init_fw_cb; 936d00efe3fSMike Christie } 937d00efe3fSMike Christie 938ce505f9dSVikas Chaudhary rval = qla4xxx_disable_acb(ha); 939ce505f9dSVikas Chaudhary if (rval != QLA_SUCCESS) { 940ce505f9dSVikas Chaudhary ql4_printk(KERN_ERR, ha, "%s: disable acb mbx failed\n", 941ce505f9dSVikas Chaudhary __func__); 942ce505f9dSVikas Chaudhary rval = -EIO; 943ce505f9dSVikas Chaudhary goto exit_init_fw_cb; 944ce505f9dSVikas Chaudhary } 945ce505f9dSVikas Chaudhary 946ce505f9dSVikas Chaudhary wait_for_completion_timeout(&ha->disable_acb_comp, 947ce505f9dSVikas Chaudhary DISABLE_ACB_TOV * HZ); 948d00efe3fSMike Christie 949d00efe3fSMike Christie qla4xxx_initcb_to_acb(init_fw_cb); 950d00efe3fSMike Christie 951d00efe3fSMike Christie rval = qla4xxx_set_acb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb_dma); 952d00efe3fSMike Christie if (rval != QLA_SUCCESS) { 953d00efe3fSMike Christie ql4_printk(KERN_ERR, ha, "%s: set acb mbx failed\n", 954d00efe3fSMike Christie __func__); 955d00efe3fSMike Christie rval = -EIO; 956d00efe3fSMike Christie goto exit_init_fw_cb; 957d00efe3fSMike Christie } 958d00efe3fSMike Christie 959d00efe3fSMike Christie memset(init_fw_cb, 0, sizeof(struct addr_ctrl_blk)); 960d00efe3fSMike Christie qla4xxx_update_local_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb, 961d00efe3fSMike Christie init_fw_cb_dma); 962d00efe3fSMike Christie 963d00efe3fSMike Christie exit_init_fw_cb: 964d00efe3fSMike Christie dma_free_coherent(&ha->pdev->dev, sizeof(struct addr_ctrl_blk), 965d00efe3fSMike Christie init_fw_cb, init_fw_cb_dma); 966d00efe3fSMike Christie 967d00efe3fSMike Christie return rval; 968d00efe3fSMike Christie } 969d00efe3fSMike Christie 970b3a271a9SManish Rangankar static int qla4xxx_conn_get_param(struct iscsi_cls_conn *cls_conn, 971afaf5a2dSDavid Somayajulu enum iscsi_param param, char *buf) 972afaf5a2dSDavid Somayajulu { 973b3a271a9SManish Rangankar struct iscsi_conn *conn; 974b3a271a9SManish Rangankar struct qla_conn *qla_conn; 975b3a271a9SManish Rangankar struct sockaddr *dst_addr; 976b3a271a9SManish Rangankar int len = 0; 977afaf5a2dSDavid Somayajulu 978b3a271a9SManish Rangankar conn = cls_conn->dd_data; 979b3a271a9SManish Rangankar qla_conn = conn->dd_data; 980b3a271a9SManish Rangankar dst_addr = &qla_conn->qla_ep->dst_addr; 981afaf5a2dSDavid Somayajulu 982afaf5a2dSDavid Somayajulu switch (param) { 983afaf5a2dSDavid Somayajulu case ISCSI_PARAM_CONN_PORT: 984afaf5a2dSDavid Somayajulu case ISCSI_PARAM_CONN_ADDRESS: 985b3a271a9SManish Rangankar return iscsi_conn_get_addr_param((struct sockaddr_storage *) 986b3a271a9SManish Rangankar dst_addr, param, buf); 987afaf5a2dSDavid Somayajulu default: 988b3a271a9SManish Rangankar return iscsi_conn_get_param(cls_conn, param, buf); 989afaf5a2dSDavid Somayajulu } 990afaf5a2dSDavid Somayajulu 991afaf5a2dSDavid Somayajulu return len; 992b3a271a9SManish Rangankar 993afaf5a2dSDavid Somayajulu } 994afaf5a2dSDavid Somayajulu 99513483730SMike Christie int qla4xxx_get_ddb_index(struct scsi_qla_host *ha, uint16_t *ddb_index) 99613483730SMike Christie { 99713483730SMike Christie uint32_t mbx_sts = 0; 99813483730SMike Christie uint16_t tmp_ddb_index; 99913483730SMike Christie int ret; 100013483730SMike Christie 100113483730SMike Christie get_ddb_index: 100213483730SMike Christie tmp_ddb_index = find_first_zero_bit(ha->ddb_idx_map, MAX_DDB_ENTRIES); 100313483730SMike Christie 100413483730SMike Christie if (tmp_ddb_index >= MAX_DDB_ENTRIES) { 100513483730SMike Christie DEBUG2(ql4_printk(KERN_INFO, ha, 100613483730SMike Christie "Free DDB index not available\n")); 100713483730SMike Christie ret = QLA_ERROR; 100813483730SMike Christie goto exit_get_ddb_index; 100913483730SMike Christie } 101013483730SMike Christie 101113483730SMike Christie if (test_and_set_bit(tmp_ddb_index, ha->ddb_idx_map)) 101213483730SMike Christie goto get_ddb_index; 101313483730SMike Christie 101413483730SMike Christie DEBUG2(ql4_printk(KERN_INFO, ha, 101513483730SMike Christie "Found a free DDB index at %d\n", tmp_ddb_index)); 101613483730SMike Christie ret = qla4xxx_req_ddb_entry(ha, tmp_ddb_index, &mbx_sts); 101713483730SMike Christie if (ret == QLA_ERROR) { 101813483730SMike Christie if (mbx_sts == MBOX_STS_COMMAND_ERROR) { 101913483730SMike Christie ql4_printk(KERN_INFO, ha, 102013483730SMike Christie "DDB index = %d not available trying next\n", 102113483730SMike Christie tmp_ddb_index); 102213483730SMike Christie goto get_ddb_index; 102313483730SMike Christie } 102413483730SMike Christie DEBUG2(ql4_printk(KERN_INFO, ha, 102513483730SMike Christie "Free FW DDB not available\n")); 102613483730SMike Christie } 102713483730SMike Christie 102813483730SMike Christie *ddb_index = tmp_ddb_index; 102913483730SMike Christie 103013483730SMike Christie exit_get_ddb_index: 103113483730SMike Christie return ret; 103213483730SMike Christie } 103313483730SMike Christie 103413483730SMike Christie static int qla4xxx_match_ipaddress(struct scsi_qla_host *ha, 103513483730SMike Christie struct ddb_entry *ddb_entry, 103613483730SMike Christie char *existing_ipaddr, 103713483730SMike Christie char *user_ipaddr) 103813483730SMike Christie { 103913483730SMike Christie uint8_t dst_ipaddr[IPv6_ADDR_LEN]; 104013483730SMike Christie char formatted_ipaddr[DDB_IPADDR_LEN]; 104113483730SMike Christie int status = QLA_SUCCESS, ret = 0; 104213483730SMike Christie 104313483730SMike Christie if (ddb_entry->fw_ddb_entry.options & DDB_OPT_IPV6_DEVICE) { 104413483730SMike Christie ret = in6_pton(user_ipaddr, strlen(user_ipaddr), dst_ipaddr, 104513483730SMike Christie '\0', NULL); 104613483730SMike Christie if (ret == 0) { 104713483730SMike Christie status = QLA_ERROR; 104813483730SMike Christie goto out_match; 104913483730SMike Christie } 105013483730SMike Christie ret = sprintf(formatted_ipaddr, "%pI6", dst_ipaddr); 105113483730SMike Christie } else { 105213483730SMike Christie ret = in4_pton(user_ipaddr, strlen(user_ipaddr), dst_ipaddr, 105313483730SMike Christie '\0', NULL); 105413483730SMike Christie if (ret == 0) { 105513483730SMike Christie status = QLA_ERROR; 105613483730SMike Christie goto out_match; 105713483730SMike Christie } 105813483730SMike Christie ret = sprintf(formatted_ipaddr, "%pI4", dst_ipaddr); 105913483730SMike Christie } 106013483730SMike Christie 106113483730SMike Christie if (strcmp(existing_ipaddr, formatted_ipaddr)) 106213483730SMike Christie status = QLA_ERROR; 106313483730SMike Christie 106413483730SMike Christie out_match: 106513483730SMike Christie return status; 106613483730SMike Christie } 106713483730SMike Christie 106813483730SMike Christie static int qla4xxx_match_fwdb_session(struct scsi_qla_host *ha, 106913483730SMike Christie struct iscsi_cls_conn *cls_conn) 107013483730SMike Christie { 107113483730SMike Christie int idx = 0, max_ddbs, rval; 107213483730SMike Christie struct iscsi_cls_session *cls_sess = iscsi_conn_to_session(cls_conn); 107313483730SMike Christie struct iscsi_session *sess, *existing_sess; 107413483730SMike Christie struct iscsi_conn *conn, *existing_conn; 107513483730SMike Christie struct ddb_entry *ddb_entry; 107613483730SMike Christie 107713483730SMike Christie sess = cls_sess->dd_data; 107813483730SMike Christie conn = cls_conn->dd_data; 107913483730SMike Christie 108013483730SMike Christie if (sess->targetname == NULL || 108113483730SMike Christie conn->persistent_address == NULL || 108213483730SMike Christie conn->persistent_port == 0) 108313483730SMike Christie return QLA_ERROR; 108413483730SMike Christie 108513483730SMike Christie max_ddbs = is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX : 108613483730SMike Christie MAX_DEV_DB_ENTRIES; 108713483730SMike Christie 108813483730SMike Christie for (idx = 0; idx < max_ddbs; idx++) { 108913483730SMike Christie ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx); 109013483730SMike Christie if (ddb_entry == NULL) 109113483730SMike Christie continue; 109213483730SMike Christie 109313483730SMike Christie if (ddb_entry->ddb_type != FLASH_DDB) 109413483730SMike Christie continue; 109513483730SMike Christie 109613483730SMike Christie existing_sess = ddb_entry->sess->dd_data; 109713483730SMike Christie existing_conn = ddb_entry->conn->dd_data; 109813483730SMike Christie 109913483730SMike Christie if (existing_sess->targetname == NULL || 110013483730SMike Christie existing_conn->persistent_address == NULL || 110113483730SMike Christie existing_conn->persistent_port == 0) 110213483730SMike Christie continue; 110313483730SMike Christie 110413483730SMike Christie DEBUG2(ql4_printk(KERN_INFO, ha, 110513483730SMike Christie "IQN = %s User IQN = %s\n", 110613483730SMike Christie existing_sess->targetname, 110713483730SMike Christie sess->targetname)); 110813483730SMike Christie 110913483730SMike Christie DEBUG2(ql4_printk(KERN_INFO, ha, 111013483730SMike Christie "IP = %s User IP = %s\n", 111113483730SMike Christie existing_conn->persistent_address, 111213483730SMike Christie conn->persistent_address)); 111313483730SMike Christie 111413483730SMike Christie DEBUG2(ql4_printk(KERN_INFO, ha, 111513483730SMike Christie "Port = %d User Port = %d\n", 111613483730SMike Christie existing_conn->persistent_port, 111713483730SMike Christie conn->persistent_port)); 111813483730SMike Christie 111913483730SMike Christie if (strcmp(existing_sess->targetname, sess->targetname)) 112013483730SMike Christie continue; 112113483730SMike Christie rval = qla4xxx_match_ipaddress(ha, ddb_entry, 112213483730SMike Christie existing_conn->persistent_address, 112313483730SMike Christie conn->persistent_address); 112413483730SMike Christie if (rval == QLA_ERROR) 112513483730SMike Christie continue; 112613483730SMike Christie if (existing_conn->persistent_port != conn->persistent_port) 112713483730SMike Christie continue; 112813483730SMike Christie break; 112913483730SMike Christie } 113013483730SMike Christie 113113483730SMike Christie if (idx == max_ddbs) 113213483730SMike Christie return QLA_ERROR; 113313483730SMike Christie 113413483730SMike Christie DEBUG2(ql4_printk(KERN_INFO, ha, 113513483730SMike Christie "Match found in fwdb sessions\n")); 113613483730SMike Christie return QLA_SUCCESS; 113713483730SMike Christie } 113813483730SMike Christie 1139b3a271a9SManish Rangankar static struct iscsi_cls_session * 1140b3a271a9SManish Rangankar qla4xxx_session_create(struct iscsi_endpoint *ep, 1141b3a271a9SManish Rangankar uint16_t cmds_max, uint16_t qdepth, 1142b3a271a9SManish Rangankar uint32_t initial_cmdsn) 1143b3a271a9SManish Rangankar { 1144b3a271a9SManish Rangankar struct iscsi_cls_session *cls_sess; 1145b3a271a9SManish Rangankar struct scsi_qla_host *ha; 1146b3a271a9SManish Rangankar struct qla_endpoint *qla_ep; 1147b3a271a9SManish Rangankar struct ddb_entry *ddb_entry; 114813483730SMike Christie uint16_t ddb_index; 1149b3a271a9SManish Rangankar struct iscsi_session *sess; 1150b3a271a9SManish Rangankar struct sockaddr *dst_addr; 1151b3a271a9SManish Rangankar int ret; 1152b3a271a9SManish Rangankar 1153b3a271a9SManish Rangankar DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); 1154b3a271a9SManish Rangankar if (!ep) { 1155b3a271a9SManish Rangankar printk(KERN_ERR "qla4xxx: missing ep.\n"); 1156b3a271a9SManish Rangankar return NULL; 1157b3a271a9SManish Rangankar } 1158b3a271a9SManish Rangankar 1159b3a271a9SManish Rangankar qla_ep = ep->dd_data; 1160b3a271a9SManish Rangankar dst_addr = (struct sockaddr *)&qla_ep->dst_addr; 1161b3a271a9SManish Rangankar ha = to_qla_host(qla_ep->host); 1162736cf369SManish Rangankar 116313483730SMike Christie ret = qla4xxx_get_ddb_index(ha, &ddb_index); 116413483730SMike Christie if (ret == QLA_ERROR) 1165b3a271a9SManish Rangankar return NULL; 1166b3a271a9SManish Rangankar 1167b3a271a9SManish Rangankar cls_sess = iscsi_session_setup(&qla4xxx_iscsi_transport, qla_ep->host, 1168b3a271a9SManish Rangankar cmds_max, sizeof(struct ddb_entry), 1169b3a271a9SManish Rangankar sizeof(struct ql4_task_data), 1170b3a271a9SManish Rangankar initial_cmdsn, ddb_index); 1171b3a271a9SManish Rangankar if (!cls_sess) 1172b3a271a9SManish Rangankar return NULL; 1173b3a271a9SManish Rangankar 1174b3a271a9SManish Rangankar sess = cls_sess->dd_data; 1175b3a271a9SManish Rangankar ddb_entry = sess->dd_data; 1176b3a271a9SManish Rangankar ddb_entry->fw_ddb_index = ddb_index; 1177b3a271a9SManish Rangankar ddb_entry->fw_ddb_device_state = DDB_DS_NO_CONNECTION_ACTIVE; 1178b3a271a9SManish Rangankar ddb_entry->ha = ha; 1179b3a271a9SManish Rangankar ddb_entry->sess = cls_sess; 118013483730SMike Christie ddb_entry->unblock_sess = qla4xxx_unblock_ddb; 118113483730SMike Christie ddb_entry->ddb_change = qla4xxx_ddb_change; 1182b3a271a9SManish Rangankar cls_sess->recovery_tmo = ql4xsess_recovery_tmo; 1183b3a271a9SManish Rangankar ha->fw_ddb_index_map[ddb_entry->fw_ddb_index] = ddb_entry; 1184b3a271a9SManish Rangankar ha->tot_ddbs++; 1185b3a271a9SManish Rangankar 1186b3a271a9SManish Rangankar return cls_sess; 1187b3a271a9SManish Rangankar } 1188b3a271a9SManish Rangankar 1189b3a271a9SManish Rangankar static void qla4xxx_session_destroy(struct iscsi_cls_session *cls_sess) 1190b3a271a9SManish Rangankar { 1191b3a271a9SManish Rangankar struct iscsi_session *sess; 1192b3a271a9SManish Rangankar struct ddb_entry *ddb_entry; 1193b3a271a9SManish Rangankar struct scsi_qla_host *ha; 1194b3a271a9SManish Rangankar unsigned long flags; 1195b3a271a9SManish Rangankar 1196b3a271a9SManish Rangankar DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); 1197b3a271a9SManish Rangankar sess = cls_sess->dd_data; 1198b3a271a9SManish Rangankar ddb_entry = sess->dd_data; 1199b3a271a9SManish Rangankar ha = ddb_entry->ha; 1200b3a271a9SManish Rangankar 1201736cf369SManish Rangankar qla4xxx_clear_ddb_entry(ha, ddb_entry->fw_ddb_index); 1202736cf369SManish Rangankar 1203b3a271a9SManish Rangankar spin_lock_irqsave(&ha->hardware_lock, flags); 1204b3a271a9SManish Rangankar qla4xxx_free_ddb(ha, ddb_entry); 1205b3a271a9SManish Rangankar spin_unlock_irqrestore(&ha->hardware_lock, flags); 1206b3a271a9SManish Rangankar iscsi_session_teardown(cls_sess); 1207b3a271a9SManish Rangankar } 1208b3a271a9SManish Rangankar 1209b3a271a9SManish Rangankar static struct iscsi_cls_conn * 1210b3a271a9SManish Rangankar qla4xxx_conn_create(struct iscsi_cls_session *cls_sess, uint32_t conn_idx) 1211b3a271a9SManish Rangankar { 1212b3a271a9SManish Rangankar struct iscsi_cls_conn *cls_conn; 1213b3a271a9SManish Rangankar struct iscsi_session *sess; 1214b3a271a9SManish Rangankar struct ddb_entry *ddb_entry; 1215b3a271a9SManish Rangankar 1216b3a271a9SManish Rangankar DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); 1217b3a271a9SManish Rangankar cls_conn = iscsi_conn_setup(cls_sess, sizeof(struct qla_conn), 1218b3a271a9SManish Rangankar conn_idx); 1219ff1d0319SMike Christie if (!cls_conn) 1220ff1d0319SMike Christie return NULL; 1221ff1d0319SMike Christie 1222b3a271a9SManish Rangankar sess = cls_sess->dd_data; 1223b3a271a9SManish Rangankar ddb_entry = sess->dd_data; 1224b3a271a9SManish Rangankar ddb_entry->conn = cls_conn; 1225b3a271a9SManish Rangankar 1226b3a271a9SManish Rangankar return cls_conn; 1227b3a271a9SManish Rangankar } 1228b3a271a9SManish Rangankar 1229b3a271a9SManish Rangankar static int qla4xxx_conn_bind(struct iscsi_cls_session *cls_session, 1230b3a271a9SManish Rangankar struct iscsi_cls_conn *cls_conn, 1231b3a271a9SManish Rangankar uint64_t transport_fd, int is_leading) 1232b3a271a9SManish Rangankar { 1233b3a271a9SManish Rangankar struct iscsi_conn *conn; 1234b3a271a9SManish Rangankar struct qla_conn *qla_conn; 1235b3a271a9SManish Rangankar struct iscsi_endpoint *ep; 1236b3a271a9SManish Rangankar 1237b3a271a9SManish Rangankar DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); 1238b3a271a9SManish Rangankar 1239b3a271a9SManish Rangankar if (iscsi_conn_bind(cls_session, cls_conn, is_leading)) 1240b3a271a9SManish Rangankar return -EINVAL; 1241b3a271a9SManish Rangankar ep = iscsi_lookup_endpoint(transport_fd); 1242b3a271a9SManish Rangankar conn = cls_conn->dd_data; 1243b3a271a9SManish Rangankar qla_conn = conn->dd_data; 1244b3a271a9SManish Rangankar qla_conn->qla_ep = ep->dd_data; 1245b3a271a9SManish Rangankar return 0; 1246b3a271a9SManish Rangankar } 1247b3a271a9SManish Rangankar 1248b3a271a9SManish Rangankar static int qla4xxx_conn_start(struct iscsi_cls_conn *cls_conn) 1249b3a271a9SManish Rangankar { 1250b3a271a9SManish Rangankar struct iscsi_cls_session *cls_sess = iscsi_conn_to_session(cls_conn); 1251b3a271a9SManish Rangankar struct iscsi_session *sess; 1252b3a271a9SManish Rangankar struct ddb_entry *ddb_entry; 1253b3a271a9SManish Rangankar struct scsi_qla_host *ha; 125413483730SMike Christie struct dev_db_entry *fw_ddb_entry = NULL; 1255b3a271a9SManish Rangankar dma_addr_t fw_ddb_entry_dma; 1256b3a271a9SManish Rangankar uint32_t mbx_sts = 0; 1257b3a271a9SManish Rangankar int ret = 0; 1258b3a271a9SManish Rangankar int status = QLA_SUCCESS; 1259b3a271a9SManish Rangankar 1260b3a271a9SManish Rangankar DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); 1261b3a271a9SManish Rangankar sess = cls_sess->dd_data; 1262b3a271a9SManish Rangankar ddb_entry = sess->dd_data; 1263b3a271a9SManish Rangankar ha = ddb_entry->ha; 1264b3a271a9SManish Rangankar 126513483730SMike Christie /* Check if we have matching FW DDB, if yes then do not 126613483730SMike Christie * login to this target. This could cause target to logout previous 126713483730SMike Christie * connection 126813483730SMike Christie */ 126913483730SMike Christie ret = qla4xxx_match_fwdb_session(ha, cls_conn); 127013483730SMike Christie if (ret == QLA_SUCCESS) { 127113483730SMike Christie ql4_printk(KERN_INFO, ha, 127213483730SMike Christie "Session already exist in FW.\n"); 127313483730SMike Christie ret = -EEXIST; 127413483730SMike Christie goto exit_conn_start; 127513483730SMike Christie } 127613483730SMike Christie 1277b3a271a9SManish Rangankar fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), 1278b3a271a9SManish Rangankar &fw_ddb_entry_dma, GFP_KERNEL); 1279b3a271a9SManish Rangankar if (!fw_ddb_entry) { 1280b3a271a9SManish Rangankar ql4_printk(KERN_ERR, ha, 1281b3a271a9SManish Rangankar "%s: Unable to allocate dma buffer\n", __func__); 128213483730SMike Christie ret = -ENOMEM; 128313483730SMike Christie goto exit_conn_start; 1284b3a271a9SManish Rangankar } 1285b3a271a9SManish Rangankar 1286b3a271a9SManish Rangankar ret = qla4xxx_set_param_ddbentry(ha, ddb_entry, cls_conn, &mbx_sts); 1287b3a271a9SManish Rangankar if (ret) { 1288b3a271a9SManish Rangankar /* If iscsid is stopped and started then no need to do 1289b3a271a9SManish Rangankar * set param again since ddb state will be already 1290b3a271a9SManish Rangankar * active and FW does not allow set ddb to an 1291b3a271a9SManish Rangankar * active session. 1292b3a271a9SManish Rangankar */ 1293b3a271a9SManish Rangankar if (mbx_sts) 1294b3a271a9SManish Rangankar if (ddb_entry->fw_ddb_device_state == 1295f922da79SManish Rangankar DDB_DS_SESSION_ACTIVE) { 129613483730SMike Christie ddb_entry->unblock_sess(ddb_entry->sess); 1297b3a271a9SManish Rangankar goto exit_set_param; 1298f922da79SManish Rangankar } 1299b3a271a9SManish Rangankar 1300b3a271a9SManish Rangankar ql4_printk(KERN_ERR, ha, "%s: Failed set param for index[%d]\n", 1301b3a271a9SManish Rangankar __func__, ddb_entry->fw_ddb_index); 1302b3a271a9SManish Rangankar goto exit_conn_start; 1303b3a271a9SManish Rangankar } 1304b3a271a9SManish Rangankar 1305b3a271a9SManish Rangankar status = qla4xxx_conn_open(ha, ddb_entry->fw_ddb_index); 1306b3a271a9SManish Rangankar if (status == QLA_ERROR) { 13070e7e8501SManish Rangankar ql4_printk(KERN_ERR, ha, "%s: Login failed: %s\n", __func__, 13080e7e8501SManish Rangankar sess->targetname); 1309b3a271a9SManish Rangankar ret = -EINVAL; 1310b3a271a9SManish Rangankar goto exit_conn_start; 1311b3a271a9SManish Rangankar } 1312b3a271a9SManish Rangankar 131398270ab4SManish Rangankar if (ddb_entry->fw_ddb_device_state == DDB_DS_NO_CONNECTION_ACTIVE) 1314b3a271a9SManish Rangankar ddb_entry->fw_ddb_device_state = DDB_DS_LOGIN_IN_PROCESS; 1315b3a271a9SManish Rangankar 131698270ab4SManish Rangankar DEBUG2(printk(KERN_INFO "%s: DDB state [%d]\n", __func__, 131798270ab4SManish Rangankar ddb_entry->fw_ddb_device_state)); 131898270ab4SManish Rangankar 1319b3a271a9SManish Rangankar exit_set_param: 1320b3a271a9SManish Rangankar ret = 0; 1321b3a271a9SManish Rangankar 1322b3a271a9SManish Rangankar exit_conn_start: 132313483730SMike Christie if (fw_ddb_entry) 1324b3a271a9SManish Rangankar dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), 1325b3a271a9SManish Rangankar fw_ddb_entry, fw_ddb_entry_dma); 1326b3a271a9SManish Rangankar return ret; 1327b3a271a9SManish Rangankar } 1328b3a271a9SManish Rangankar 1329b3a271a9SManish Rangankar static void qla4xxx_conn_destroy(struct iscsi_cls_conn *cls_conn) 1330b3a271a9SManish Rangankar { 1331b3a271a9SManish Rangankar struct iscsi_cls_session *cls_sess = iscsi_conn_to_session(cls_conn); 1332b3a271a9SManish Rangankar struct iscsi_session *sess; 1333b3a271a9SManish Rangankar struct scsi_qla_host *ha; 1334b3a271a9SManish Rangankar struct ddb_entry *ddb_entry; 1335b3a271a9SManish Rangankar int options; 1336b3a271a9SManish Rangankar 1337b3a271a9SManish Rangankar DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); 1338b3a271a9SManish Rangankar sess = cls_sess->dd_data; 1339b3a271a9SManish Rangankar ddb_entry = sess->dd_data; 1340b3a271a9SManish Rangankar ha = ddb_entry->ha; 1341b3a271a9SManish Rangankar 1342b3a271a9SManish Rangankar options = LOGOUT_OPTION_CLOSE_SESSION; 1343b3a271a9SManish Rangankar if (qla4xxx_session_logout_ddb(ha, ddb_entry, options) == QLA_ERROR) 1344b3a271a9SManish Rangankar ql4_printk(KERN_ERR, ha, "%s: Logout failed\n", __func__); 1345b3a271a9SManish Rangankar } 1346b3a271a9SManish Rangankar 1347b3a271a9SManish Rangankar static void qla4xxx_task_work(struct work_struct *wdata) 1348b3a271a9SManish Rangankar { 1349b3a271a9SManish Rangankar struct ql4_task_data *task_data; 1350b3a271a9SManish Rangankar struct scsi_qla_host *ha; 1351b3a271a9SManish Rangankar struct passthru_status *sts; 1352b3a271a9SManish Rangankar struct iscsi_task *task; 1353b3a271a9SManish Rangankar struct iscsi_hdr *hdr; 1354b3a271a9SManish Rangankar uint8_t *data; 1355b3a271a9SManish Rangankar uint32_t data_len; 1356b3a271a9SManish Rangankar struct iscsi_conn *conn; 1357b3a271a9SManish Rangankar int hdr_len; 1358b3a271a9SManish Rangankar itt_t itt; 1359b3a271a9SManish Rangankar 1360b3a271a9SManish Rangankar task_data = container_of(wdata, struct ql4_task_data, task_work); 1361b3a271a9SManish Rangankar ha = task_data->ha; 1362b3a271a9SManish Rangankar task = task_data->task; 1363b3a271a9SManish Rangankar sts = &task_data->sts; 1364b3a271a9SManish Rangankar hdr_len = sizeof(struct iscsi_hdr); 1365b3a271a9SManish Rangankar 1366b3a271a9SManish Rangankar DEBUG3(printk(KERN_INFO "Status returned\n")); 1367b3a271a9SManish Rangankar DEBUG3(qla4xxx_dump_buffer(sts, 64)); 1368b3a271a9SManish Rangankar DEBUG3(printk(KERN_INFO "Response buffer")); 1369b3a271a9SManish Rangankar DEBUG3(qla4xxx_dump_buffer(task_data->resp_buffer, 64)); 1370b3a271a9SManish Rangankar 1371b3a271a9SManish Rangankar conn = task->conn; 1372b3a271a9SManish Rangankar 1373b3a271a9SManish Rangankar switch (sts->completionStatus) { 1374b3a271a9SManish Rangankar case PASSTHRU_STATUS_COMPLETE: 1375b3a271a9SManish Rangankar hdr = (struct iscsi_hdr *)task_data->resp_buffer; 1376b3a271a9SManish Rangankar /* Assign back the itt in hdr, until we use the PREASSIGN_TAG */ 1377b3a271a9SManish Rangankar itt = sts->handle; 1378b3a271a9SManish Rangankar hdr->itt = itt; 1379b3a271a9SManish Rangankar data = task_data->resp_buffer + hdr_len; 1380b3a271a9SManish Rangankar data_len = task_data->resp_len - hdr_len; 1381b3a271a9SManish Rangankar iscsi_complete_pdu(conn, hdr, data, data_len); 1382b3a271a9SManish Rangankar break; 1383b3a271a9SManish Rangankar default: 1384b3a271a9SManish Rangankar ql4_printk(KERN_ERR, ha, "Passthru failed status = 0x%x\n", 1385b3a271a9SManish Rangankar sts->completionStatus); 1386b3a271a9SManish Rangankar break; 1387b3a271a9SManish Rangankar } 1388b3a271a9SManish Rangankar return; 1389b3a271a9SManish Rangankar } 1390b3a271a9SManish Rangankar 1391b3a271a9SManish Rangankar static int qla4xxx_alloc_pdu(struct iscsi_task *task, uint8_t opcode) 1392b3a271a9SManish Rangankar { 1393b3a271a9SManish Rangankar struct ql4_task_data *task_data; 1394b3a271a9SManish Rangankar struct iscsi_session *sess; 1395b3a271a9SManish Rangankar struct ddb_entry *ddb_entry; 1396b3a271a9SManish Rangankar struct scsi_qla_host *ha; 1397b3a271a9SManish Rangankar int hdr_len; 1398b3a271a9SManish Rangankar 1399b3a271a9SManish Rangankar sess = task->conn->session; 1400b3a271a9SManish Rangankar ddb_entry = sess->dd_data; 1401b3a271a9SManish Rangankar ha = ddb_entry->ha; 1402b3a271a9SManish Rangankar task_data = task->dd_data; 1403b3a271a9SManish Rangankar memset(task_data, 0, sizeof(struct ql4_task_data)); 1404b3a271a9SManish Rangankar 1405b3a271a9SManish Rangankar if (task->sc) { 1406b3a271a9SManish Rangankar ql4_printk(KERN_INFO, ha, 1407b3a271a9SManish Rangankar "%s: SCSI Commands not implemented\n", __func__); 1408b3a271a9SManish Rangankar return -EINVAL; 1409b3a271a9SManish Rangankar } 1410b3a271a9SManish Rangankar 1411b3a271a9SManish Rangankar hdr_len = sizeof(struct iscsi_hdr); 1412b3a271a9SManish Rangankar task_data->ha = ha; 1413b3a271a9SManish Rangankar task_data->task = task; 1414b3a271a9SManish Rangankar 1415b3a271a9SManish Rangankar if (task->data_count) { 1416b3a271a9SManish Rangankar task_data->data_dma = dma_map_single(&ha->pdev->dev, task->data, 1417b3a271a9SManish Rangankar task->data_count, 1418b3a271a9SManish Rangankar PCI_DMA_TODEVICE); 1419b3a271a9SManish Rangankar } 1420b3a271a9SManish Rangankar 1421b3a271a9SManish Rangankar DEBUG2(ql4_printk(KERN_INFO, ha, "%s: MaxRecvLen %u, iscsi hrd %d\n", 1422b3a271a9SManish Rangankar __func__, task->conn->max_recv_dlength, hdr_len)); 1423b3a271a9SManish Rangankar 142469ca216eSManish Rangankar task_data->resp_len = task->conn->max_recv_dlength + hdr_len; 1425b3a271a9SManish Rangankar task_data->resp_buffer = dma_alloc_coherent(&ha->pdev->dev, 1426b3a271a9SManish Rangankar task_data->resp_len, 1427b3a271a9SManish Rangankar &task_data->resp_dma, 1428b3a271a9SManish Rangankar GFP_ATOMIC); 1429b3a271a9SManish Rangankar if (!task_data->resp_buffer) 1430b3a271a9SManish Rangankar goto exit_alloc_pdu; 1431b3a271a9SManish Rangankar 143269ca216eSManish Rangankar task_data->req_len = task->data_count + hdr_len; 1433b3a271a9SManish Rangankar task_data->req_buffer = dma_alloc_coherent(&ha->pdev->dev, 143469ca216eSManish Rangankar task_data->req_len, 1435b3a271a9SManish Rangankar &task_data->req_dma, 1436b3a271a9SManish Rangankar GFP_ATOMIC); 1437b3a271a9SManish Rangankar if (!task_data->req_buffer) 1438b3a271a9SManish Rangankar goto exit_alloc_pdu; 1439b3a271a9SManish Rangankar 1440b3a271a9SManish Rangankar task->hdr = task_data->req_buffer; 1441b3a271a9SManish Rangankar 1442b3a271a9SManish Rangankar INIT_WORK(&task_data->task_work, qla4xxx_task_work); 1443b3a271a9SManish Rangankar 1444b3a271a9SManish Rangankar return 0; 1445b3a271a9SManish Rangankar 1446b3a271a9SManish Rangankar exit_alloc_pdu: 1447b3a271a9SManish Rangankar if (task_data->resp_buffer) 1448b3a271a9SManish Rangankar dma_free_coherent(&ha->pdev->dev, task_data->resp_len, 1449b3a271a9SManish Rangankar task_data->resp_buffer, task_data->resp_dma); 1450b3a271a9SManish Rangankar 1451b3a271a9SManish Rangankar if (task_data->req_buffer) 145269ca216eSManish Rangankar dma_free_coherent(&ha->pdev->dev, task_data->req_len, 1453b3a271a9SManish Rangankar task_data->req_buffer, task_data->req_dma); 1454b3a271a9SManish Rangankar return -ENOMEM; 1455b3a271a9SManish Rangankar } 1456b3a271a9SManish Rangankar 1457b3a271a9SManish Rangankar static void qla4xxx_task_cleanup(struct iscsi_task *task) 1458b3a271a9SManish Rangankar { 1459b3a271a9SManish Rangankar struct ql4_task_data *task_data; 1460b3a271a9SManish Rangankar struct iscsi_session *sess; 1461b3a271a9SManish Rangankar struct ddb_entry *ddb_entry; 1462b3a271a9SManish Rangankar struct scsi_qla_host *ha; 1463b3a271a9SManish Rangankar int hdr_len; 1464b3a271a9SManish Rangankar 1465b3a271a9SManish Rangankar hdr_len = sizeof(struct iscsi_hdr); 1466b3a271a9SManish Rangankar sess = task->conn->session; 1467b3a271a9SManish Rangankar ddb_entry = sess->dd_data; 1468b3a271a9SManish Rangankar ha = ddb_entry->ha; 1469b3a271a9SManish Rangankar task_data = task->dd_data; 1470b3a271a9SManish Rangankar 1471b3a271a9SManish Rangankar if (task->data_count) { 1472b3a271a9SManish Rangankar dma_unmap_single(&ha->pdev->dev, task_data->data_dma, 1473b3a271a9SManish Rangankar task->data_count, PCI_DMA_TODEVICE); 1474b3a271a9SManish Rangankar } 1475b3a271a9SManish Rangankar 1476b3a271a9SManish Rangankar DEBUG2(ql4_printk(KERN_INFO, ha, "%s: MaxRecvLen %u, iscsi hrd %d\n", 1477b3a271a9SManish Rangankar __func__, task->conn->max_recv_dlength, hdr_len)); 1478b3a271a9SManish Rangankar 1479b3a271a9SManish Rangankar dma_free_coherent(&ha->pdev->dev, task_data->resp_len, 1480b3a271a9SManish Rangankar task_data->resp_buffer, task_data->resp_dma); 148169ca216eSManish Rangankar dma_free_coherent(&ha->pdev->dev, task_data->req_len, 1482b3a271a9SManish Rangankar task_data->req_buffer, task_data->req_dma); 1483b3a271a9SManish Rangankar return; 1484b3a271a9SManish Rangankar } 1485b3a271a9SManish Rangankar 1486b3a271a9SManish Rangankar static int qla4xxx_task_xmit(struct iscsi_task *task) 1487b3a271a9SManish Rangankar { 1488b3a271a9SManish Rangankar struct scsi_cmnd *sc = task->sc; 1489b3a271a9SManish Rangankar struct iscsi_session *sess = task->conn->session; 1490b3a271a9SManish Rangankar struct ddb_entry *ddb_entry = sess->dd_data; 1491b3a271a9SManish Rangankar struct scsi_qla_host *ha = ddb_entry->ha; 1492b3a271a9SManish Rangankar 1493b3a271a9SManish Rangankar if (!sc) 1494b3a271a9SManish Rangankar return qla4xxx_send_passthru0(task); 1495b3a271a9SManish Rangankar 1496b3a271a9SManish Rangankar ql4_printk(KERN_INFO, ha, "%s: scsi cmd xmit not implemented\n", 1497b3a271a9SManish Rangankar __func__); 1498b3a271a9SManish Rangankar return -ENOSYS; 1499b3a271a9SManish Rangankar } 1500b3a271a9SManish Rangankar 150113483730SMike Christie static void qla4xxx_copy_fwddb_param(struct scsi_qla_host *ha, 150213483730SMike Christie struct dev_db_entry *fw_ddb_entry, 150313483730SMike Christie struct iscsi_cls_session *cls_sess, 150413483730SMike Christie struct iscsi_cls_conn *cls_conn) 150513483730SMike Christie { 150613483730SMike Christie int buflen = 0; 150713483730SMike Christie struct iscsi_session *sess; 150813483730SMike Christie struct iscsi_conn *conn; 150913483730SMike Christie char ip_addr[DDB_IPADDR_LEN]; 151013483730SMike Christie uint16_t options = 0; 151113483730SMike Christie 151213483730SMike Christie sess = cls_sess->dd_data; 151313483730SMike Christie conn = cls_conn->dd_data; 151413483730SMike Christie 151513483730SMike Christie conn->max_recv_dlength = BYTE_UNITS * 151613483730SMike Christie le16_to_cpu(fw_ddb_entry->iscsi_max_rcv_data_seg_len); 151713483730SMike Christie 151813483730SMike Christie conn->max_xmit_dlength = BYTE_UNITS * 151913483730SMike Christie le16_to_cpu(fw_ddb_entry->iscsi_max_snd_data_seg_len); 152013483730SMike Christie 152113483730SMike Christie sess->initial_r2t_en = 152213483730SMike Christie (BIT_10 & le16_to_cpu(fw_ddb_entry->iscsi_options)); 152313483730SMike Christie 152413483730SMike Christie sess->max_r2t = le16_to_cpu(fw_ddb_entry->iscsi_max_outsnd_r2t); 152513483730SMike Christie 152613483730SMike Christie sess->imm_data_en = (BIT_11 & le16_to_cpu(fw_ddb_entry->iscsi_options)); 152713483730SMike Christie 152813483730SMike Christie sess->first_burst = BYTE_UNITS * 152913483730SMike Christie le16_to_cpu(fw_ddb_entry->iscsi_first_burst_len); 153013483730SMike Christie 153113483730SMike Christie sess->max_burst = BYTE_UNITS * 153213483730SMike Christie le16_to_cpu(fw_ddb_entry->iscsi_max_burst_len); 153313483730SMike Christie 153413483730SMike Christie sess->time2wait = le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait); 153513483730SMike Christie 153613483730SMike Christie sess->time2retain = le16_to_cpu(fw_ddb_entry->iscsi_def_time2retain); 153713483730SMike Christie 153813483730SMike Christie conn->persistent_port = le16_to_cpu(fw_ddb_entry->port); 153913483730SMike Christie 154013483730SMike Christie sess->tpgt = le32_to_cpu(fw_ddb_entry->tgt_portal_grp); 154113483730SMike Christie 154213483730SMike Christie options = le16_to_cpu(fw_ddb_entry->options); 154313483730SMike Christie if (options & DDB_OPT_IPV6_DEVICE) 154413483730SMike Christie sprintf(ip_addr, "%pI6", fw_ddb_entry->ip_addr); 154513483730SMike Christie else 154613483730SMike Christie sprintf(ip_addr, "%pI4", fw_ddb_entry->ip_addr); 154713483730SMike Christie 154813483730SMike Christie iscsi_set_param(cls_conn, ISCSI_PARAM_TARGET_NAME, 154913483730SMike Christie (char *)fw_ddb_entry->iscsi_name, buflen); 155013483730SMike Christie iscsi_set_param(cls_conn, ISCSI_PARAM_INITIATOR_NAME, 155113483730SMike Christie (char *)ha->name_string, buflen); 155213483730SMike Christie iscsi_set_param(cls_conn, ISCSI_PARAM_PERSISTENT_ADDRESS, 155313483730SMike Christie (char *)ip_addr, buflen); 155413483730SMike Christie } 155513483730SMike Christie 155613483730SMike Christie void qla4xxx_update_session_conn_fwddb_param(struct scsi_qla_host *ha, 155713483730SMike Christie struct ddb_entry *ddb_entry) 155813483730SMike Christie { 155913483730SMike Christie struct iscsi_cls_session *cls_sess; 156013483730SMike Christie struct iscsi_cls_conn *cls_conn; 156113483730SMike Christie uint32_t ddb_state; 156213483730SMike Christie dma_addr_t fw_ddb_entry_dma; 156313483730SMike Christie struct dev_db_entry *fw_ddb_entry; 156413483730SMike Christie 156513483730SMike Christie fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), 156613483730SMike Christie &fw_ddb_entry_dma, GFP_KERNEL); 156713483730SMike Christie if (!fw_ddb_entry) { 156813483730SMike Christie ql4_printk(KERN_ERR, ha, 156913483730SMike Christie "%s: Unable to allocate dma buffer\n", __func__); 157013483730SMike Christie goto exit_session_conn_fwddb_param; 157113483730SMike Christie } 157213483730SMike Christie 157313483730SMike Christie if (qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index, fw_ddb_entry, 157413483730SMike Christie fw_ddb_entry_dma, NULL, NULL, &ddb_state, 157513483730SMike Christie NULL, NULL, NULL) == QLA_ERROR) { 157613483730SMike Christie DEBUG2(ql4_printk(KERN_ERR, ha, "scsi%ld: %s: failed " 157713483730SMike Christie "get_ddb_entry for fw_ddb_index %d\n", 157813483730SMike Christie ha->host_no, __func__, 157913483730SMike Christie ddb_entry->fw_ddb_index)); 158013483730SMike Christie goto exit_session_conn_fwddb_param; 158113483730SMike Christie } 158213483730SMike Christie 158313483730SMike Christie cls_sess = ddb_entry->sess; 158413483730SMike Christie 158513483730SMike Christie cls_conn = ddb_entry->conn; 158613483730SMike Christie 158713483730SMike Christie /* Update params */ 158813483730SMike Christie qla4xxx_copy_fwddb_param(ha, fw_ddb_entry, cls_sess, cls_conn); 158913483730SMike Christie 159013483730SMike Christie exit_session_conn_fwddb_param: 159113483730SMike Christie if (fw_ddb_entry) 159213483730SMike Christie dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), 159313483730SMike Christie fw_ddb_entry, fw_ddb_entry_dma); 159413483730SMike Christie } 159513483730SMike Christie 1596b3a271a9SManish Rangankar void qla4xxx_update_session_conn_param(struct scsi_qla_host *ha, 1597b3a271a9SManish Rangankar struct ddb_entry *ddb_entry) 1598b3a271a9SManish Rangankar { 1599b3a271a9SManish Rangankar struct iscsi_cls_session *cls_sess; 1600b3a271a9SManish Rangankar struct iscsi_cls_conn *cls_conn; 1601b3a271a9SManish Rangankar struct iscsi_session *sess; 1602b3a271a9SManish Rangankar struct iscsi_conn *conn; 1603b3a271a9SManish Rangankar uint32_t ddb_state; 1604b3a271a9SManish Rangankar dma_addr_t fw_ddb_entry_dma; 1605b3a271a9SManish Rangankar struct dev_db_entry *fw_ddb_entry; 1606b3a271a9SManish Rangankar 1607b3a271a9SManish Rangankar fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), 1608b3a271a9SManish Rangankar &fw_ddb_entry_dma, GFP_KERNEL); 1609b3a271a9SManish Rangankar if (!fw_ddb_entry) { 1610b3a271a9SManish Rangankar ql4_printk(KERN_ERR, ha, 1611b3a271a9SManish Rangankar "%s: Unable to allocate dma buffer\n", __func__); 161213483730SMike Christie goto exit_session_conn_param; 1613b3a271a9SManish Rangankar } 1614b3a271a9SManish Rangankar 1615b3a271a9SManish Rangankar if (qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index, fw_ddb_entry, 1616b3a271a9SManish Rangankar fw_ddb_entry_dma, NULL, NULL, &ddb_state, 1617b3a271a9SManish Rangankar NULL, NULL, NULL) == QLA_ERROR) { 1618b3a271a9SManish Rangankar DEBUG2(ql4_printk(KERN_ERR, ha, "scsi%ld: %s: failed " 1619b3a271a9SManish Rangankar "get_ddb_entry for fw_ddb_index %d\n", 1620b3a271a9SManish Rangankar ha->host_no, __func__, 1621b3a271a9SManish Rangankar ddb_entry->fw_ddb_index)); 162213483730SMike Christie goto exit_session_conn_param; 1623b3a271a9SManish Rangankar } 1624b3a271a9SManish Rangankar 1625b3a271a9SManish Rangankar cls_sess = ddb_entry->sess; 1626b3a271a9SManish Rangankar sess = cls_sess->dd_data; 1627b3a271a9SManish Rangankar 1628b3a271a9SManish Rangankar cls_conn = ddb_entry->conn; 1629b3a271a9SManish Rangankar conn = cls_conn->dd_data; 1630b3a271a9SManish Rangankar 163113483730SMike Christie /* Update timers after login */ 163213483730SMike Christie ddb_entry->default_relogin_timeout = 163313483730SMike Christie le16_to_cpu(fw_ddb_entry->def_timeout); 163413483730SMike Christie ddb_entry->default_time2wait = 163513483730SMike Christie le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait); 163613483730SMike Christie 1637b3a271a9SManish Rangankar /* Update params */ 1638b3a271a9SManish Rangankar conn->max_recv_dlength = BYTE_UNITS * 1639b3a271a9SManish Rangankar le16_to_cpu(fw_ddb_entry->iscsi_max_rcv_data_seg_len); 1640b3a271a9SManish Rangankar 1641b3a271a9SManish Rangankar conn->max_xmit_dlength = BYTE_UNITS * 1642b3a271a9SManish Rangankar le16_to_cpu(fw_ddb_entry->iscsi_max_snd_data_seg_len); 1643b3a271a9SManish Rangankar 1644b3a271a9SManish Rangankar sess->initial_r2t_en = 1645b3a271a9SManish Rangankar (BIT_10 & le16_to_cpu(fw_ddb_entry->iscsi_options)); 1646b3a271a9SManish Rangankar 1647b3a271a9SManish Rangankar sess->max_r2t = le16_to_cpu(fw_ddb_entry->iscsi_max_outsnd_r2t); 1648b3a271a9SManish Rangankar 1649b3a271a9SManish Rangankar sess->imm_data_en = (BIT_11 & le16_to_cpu(fw_ddb_entry->iscsi_options)); 1650b3a271a9SManish Rangankar 1651b3a271a9SManish Rangankar sess->first_burst = BYTE_UNITS * 1652b3a271a9SManish Rangankar le16_to_cpu(fw_ddb_entry->iscsi_first_burst_len); 1653b3a271a9SManish Rangankar 1654b3a271a9SManish Rangankar sess->max_burst = BYTE_UNITS * 1655b3a271a9SManish Rangankar le16_to_cpu(fw_ddb_entry->iscsi_max_burst_len); 1656b3a271a9SManish Rangankar 1657b3a271a9SManish Rangankar sess->time2wait = le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait); 1658b3a271a9SManish Rangankar 1659b3a271a9SManish Rangankar sess->time2retain = le16_to_cpu(fw_ddb_entry->iscsi_def_time2retain); 1660b3a271a9SManish Rangankar 1661b3a271a9SManish Rangankar sess->tpgt = le32_to_cpu(fw_ddb_entry->tgt_portal_grp); 1662b3a271a9SManish Rangankar 1663b3a271a9SManish Rangankar memcpy(sess->initiatorname, ha->name_string, 1664b3a271a9SManish Rangankar min(sizeof(ha->name_string), sizeof(sess->initiatorname))); 166513483730SMike Christie 166613483730SMike Christie exit_session_conn_param: 166713483730SMike Christie if (fw_ddb_entry) 166813483730SMike Christie dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), 166913483730SMike Christie fw_ddb_entry, fw_ddb_entry_dma); 1670b3a271a9SManish Rangankar } 1671b3a271a9SManish Rangankar 1672afaf5a2dSDavid Somayajulu /* 1673afaf5a2dSDavid Somayajulu * Timer routines 1674afaf5a2dSDavid Somayajulu */ 1675afaf5a2dSDavid Somayajulu 1676afaf5a2dSDavid Somayajulu static void qla4xxx_start_timer(struct scsi_qla_host *ha, void *func, 1677afaf5a2dSDavid Somayajulu unsigned long interval) 1678afaf5a2dSDavid Somayajulu { 1679afaf5a2dSDavid Somayajulu DEBUG(printk("scsi: %s: Starting timer thread for adapter %d\n", 1680afaf5a2dSDavid Somayajulu __func__, ha->host->host_no)); 1681afaf5a2dSDavid Somayajulu init_timer(&ha->timer); 1682afaf5a2dSDavid Somayajulu ha->timer.expires = jiffies + interval * HZ; 1683afaf5a2dSDavid Somayajulu ha->timer.data = (unsigned long)ha; 1684afaf5a2dSDavid Somayajulu ha->timer.function = (void (*)(unsigned long))func; 1685afaf5a2dSDavid Somayajulu add_timer(&ha->timer); 1686afaf5a2dSDavid Somayajulu ha->timer_active = 1; 1687afaf5a2dSDavid Somayajulu } 1688afaf5a2dSDavid Somayajulu 1689afaf5a2dSDavid Somayajulu static void qla4xxx_stop_timer(struct scsi_qla_host *ha) 1690afaf5a2dSDavid Somayajulu { 1691afaf5a2dSDavid Somayajulu del_timer_sync(&ha->timer); 1692afaf5a2dSDavid Somayajulu ha->timer_active = 0; 1693afaf5a2dSDavid Somayajulu } 1694afaf5a2dSDavid Somayajulu 1695afaf5a2dSDavid Somayajulu /*** 1696b3a271a9SManish Rangankar * qla4xxx_mark_device_missing - blocks the session 1697b3a271a9SManish Rangankar * @cls_session: Pointer to the session to be blocked 1698afaf5a2dSDavid Somayajulu * @ddb_entry: Pointer to device database entry 1699afaf5a2dSDavid Somayajulu * 1700f4f5df23SVikas Chaudhary * This routine marks a device missing and close connection. 1701afaf5a2dSDavid Somayajulu **/ 1702b3a271a9SManish Rangankar void qla4xxx_mark_device_missing(struct iscsi_cls_session *cls_session) 1703afaf5a2dSDavid Somayajulu { 1704b3a271a9SManish Rangankar iscsi_block_session(cls_session); 1705afaf5a2dSDavid Somayajulu } 1706afaf5a2dSDavid Somayajulu 1707f4f5df23SVikas Chaudhary /** 1708f4f5df23SVikas Chaudhary * qla4xxx_mark_all_devices_missing - mark all devices as missing. 1709f4f5df23SVikas Chaudhary * @ha: Pointer to host adapter structure. 1710f4f5df23SVikas Chaudhary * 1711f4f5df23SVikas Chaudhary * This routine marks a device missing and resets the relogin retry count. 1712f4f5df23SVikas Chaudhary **/ 1713f4f5df23SVikas Chaudhary void qla4xxx_mark_all_devices_missing(struct scsi_qla_host *ha) 1714f4f5df23SVikas Chaudhary { 1715b3a271a9SManish Rangankar iscsi_host_for_each_session(ha->host, qla4xxx_mark_device_missing); 1716f4f5df23SVikas Chaudhary } 1717f4f5df23SVikas Chaudhary 1718afaf5a2dSDavid Somayajulu static struct srb* qla4xxx_get_new_srb(struct scsi_qla_host *ha, 1719afaf5a2dSDavid Somayajulu struct ddb_entry *ddb_entry, 17208f0722caSVikas Chaudhary struct scsi_cmnd *cmd) 1721afaf5a2dSDavid Somayajulu { 1722afaf5a2dSDavid Somayajulu struct srb *srb; 1723afaf5a2dSDavid Somayajulu 1724afaf5a2dSDavid Somayajulu srb = mempool_alloc(ha->srb_mempool, GFP_ATOMIC); 1725afaf5a2dSDavid Somayajulu if (!srb) 1726afaf5a2dSDavid Somayajulu return srb; 1727afaf5a2dSDavid Somayajulu 172809a0f719SVikas Chaudhary kref_init(&srb->srb_ref); 1729afaf5a2dSDavid Somayajulu srb->ha = ha; 1730afaf5a2dSDavid Somayajulu srb->ddb = ddb_entry; 1731afaf5a2dSDavid Somayajulu srb->cmd = cmd; 1732afaf5a2dSDavid Somayajulu srb->flags = 0; 17335369887aSVikas Chaudhary CMD_SP(cmd) = (void *)srb; 1734afaf5a2dSDavid Somayajulu 1735afaf5a2dSDavid Somayajulu return srb; 1736afaf5a2dSDavid Somayajulu } 1737afaf5a2dSDavid Somayajulu 1738afaf5a2dSDavid Somayajulu static void qla4xxx_srb_free_dma(struct scsi_qla_host *ha, struct srb *srb) 1739afaf5a2dSDavid Somayajulu { 1740afaf5a2dSDavid Somayajulu struct scsi_cmnd *cmd = srb->cmd; 1741afaf5a2dSDavid Somayajulu 1742afaf5a2dSDavid Somayajulu if (srb->flags & SRB_DMA_VALID) { 17435f7186c8SFUJITA Tomonori scsi_dma_unmap(cmd); 1744afaf5a2dSDavid Somayajulu srb->flags &= ~SRB_DMA_VALID; 1745afaf5a2dSDavid Somayajulu } 17465369887aSVikas Chaudhary CMD_SP(cmd) = NULL; 1747afaf5a2dSDavid Somayajulu } 1748afaf5a2dSDavid Somayajulu 174909a0f719SVikas Chaudhary void qla4xxx_srb_compl(struct kref *ref) 1750afaf5a2dSDavid Somayajulu { 175109a0f719SVikas Chaudhary struct srb *srb = container_of(ref, struct srb, srb_ref); 1752afaf5a2dSDavid Somayajulu struct scsi_cmnd *cmd = srb->cmd; 175309a0f719SVikas Chaudhary struct scsi_qla_host *ha = srb->ha; 1754afaf5a2dSDavid Somayajulu 1755afaf5a2dSDavid Somayajulu qla4xxx_srb_free_dma(ha, srb); 1756afaf5a2dSDavid Somayajulu 1757afaf5a2dSDavid Somayajulu mempool_free(srb, ha->srb_mempool); 1758afaf5a2dSDavid Somayajulu 1759afaf5a2dSDavid Somayajulu cmd->scsi_done(cmd); 1760afaf5a2dSDavid Somayajulu } 1761afaf5a2dSDavid Somayajulu 1762afaf5a2dSDavid Somayajulu /** 1763afaf5a2dSDavid Somayajulu * qla4xxx_queuecommand - scsi layer issues scsi command to driver. 17648f0722caSVikas Chaudhary * @host: scsi host 1765afaf5a2dSDavid Somayajulu * @cmd: Pointer to Linux's SCSI command structure 1766afaf5a2dSDavid Somayajulu * 1767afaf5a2dSDavid Somayajulu * Remarks: 1768afaf5a2dSDavid Somayajulu * This routine is invoked by Linux to send a SCSI command to the driver. 1769afaf5a2dSDavid Somayajulu * The mid-level driver tries to ensure that queuecommand never gets 1770afaf5a2dSDavid Somayajulu * invoked concurrently with itself or the interrupt handler (although 1771afaf5a2dSDavid Somayajulu * the interrupt handler may call this routine as part of request- 1772afaf5a2dSDavid Somayajulu * completion handling). Unfortunely, it sometimes calls the scheduler 1773afaf5a2dSDavid Somayajulu * in interrupt context which is a big NO! NO!. 1774afaf5a2dSDavid Somayajulu **/ 17758f0722caSVikas Chaudhary static int qla4xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) 1776afaf5a2dSDavid Somayajulu { 17778f0722caSVikas Chaudhary struct scsi_qla_host *ha = to_qla_host(host); 1778afaf5a2dSDavid Somayajulu struct ddb_entry *ddb_entry = cmd->device->hostdata; 17797fb1921bSMike Christie struct iscsi_cls_session *sess = ddb_entry->sess; 1780afaf5a2dSDavid Somayajulu struct srb *srb; 1781afaf5a2dSDavid Somayajulu int rval; 1782afaf5a2dSDavid Somayajulu 17832232be0dSLalit Chandivade if (test_bit(AF_EEH_BUSY, &ha->flags)) { 17842232be0dSLalit Chandivade if (test_bit(AF_PCI_CHANNEL_IO_PERM_FAILURE, &ha->flags)) 17852232be0dSLalit Chandivade cmd->result = DID_NO_CONNECT << 16; 17862232be0dSLalit Chandivade else 17872232be0dSLalit Chandivade cmd->result = DID_REQUEUE << 16; 17882232be0dSLalit Chandivade goto qc_fail_command; 17892232be0dSLalit Chandivade } 17902232be0dSLalit Chandivade 17917fb1921bSMike Christie if (!sess) { 17927fb1921bSMike Christie cmd->result = DID_IMM_RETRY << 16; 17937fb1921bSMike Christie goto qc_fail_command; 17947fb1921bSMike Christie } 17957fb1921bSMike Christie 17967fb1921bSMike Christie rval = iscsi_session_chkready(sess); 17977fb1921bSMike Christie if (rval) { 17987fb1921bSMike Christie cmd->result = rval; 17997fb1921bSMike Christie goto qc_fail_command; 18007fb1921bSMike Christie } 18017fb1921bSMike Christie 1802f4f5df23SVikas Chaudhary if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) || 1803f4f5df23SVikas Chaudhary test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags) || 1804f4f5df23SVikas Chaudhary test_bit(DPC_RESET_HA, &ha->dpc_flags) || 1805f4f5df23SVikas Chaudhary test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags) || 1806f4f5df23SVikas Chaudhary test_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags) || 1807f4f5df23SVikas Chaudhary !test_bit(AF_ONLINE, &ha->flags) || 1808b3a271a9SManish Rangankar !test_bit(AF_LINK_UP, &ha->flags) || 1809f4f5df23SVikas Chaudhary test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags)) 1810477ffb9dSDavid C Somayajulu goto qc_host_busy; 1811477ffb9dSDavid C Somayajulu 18128f0722caSVikas Chaudhary srb = qla4xxx_get_new_srb(ha, ddb_entry, cmd); 1813afaf5a2dSDavid Somayajulu if (!srb) 18148f0722caSVikas Chaudhary goto qc_host_busy; 1815afaf5a2dSDavid Somayajulu 1816afaf5a2dSDavid Somayajulu rval = qla4xxx_send_command_to_isp(ha, srb); 1817afaf5a2dSDavid Somayajulu if (rval != QLA_SUCCESS) 1818afaf5a2dSDavid Somayajulu goto qc_host_busy_free_sp; 1819afaf5a2dSDavid Somayajulu 1820afaf5a2dSDavid Somayajulu return 0; 1821afaf5a2dSDavid Somayajulu 1822afaf5a2dSDavid Somayajulu qc_host_busy_free_sp: 1823afaf5a2dSDavid Somayajulu qla4xxx_srb_free_dma(ha, srb); 1824afaf5a2dSDavid Somayajulu mempool_free(srb, ha->srb_mempool); 1825afaf5a2dSDavid Somayajulu 1826afaf5a2dSDavid Somayajulu qc_host_busy: 1827afaf5a2dSDavid Somayajulu return SCSI_MLQUEUE_HOST_BUSY; 1828afaf5a2dSDavid Somayajulu 1829afaf5a2dSDavid Somayajulu qc_fail_command: 18308f0722caSVikas Chaudhary cmd->scsi_done(cmd); 1831afaf5a2dSDavid Somayajulu 1832afaf5a2dSDavid Somayajulu return 0; 1833afaf5a2dSDavid Somayajulu } 1834afaf5a2dSDavid Somayajulu 1835afaf5a2dSDavid Somayajulu /** 1836afaf5a2dSDavid Somayajulu * qla4xxx_mem_free - frees memory allocated to adapter 1837afaf5a2dSDavid Somayajulu * @ha: Pointer to host adapter structure. 1838afaf5a2dSDavid Somayajulu * 1839afaf5a2dSDavid Somayajulu * Frees memory previously allocated by qla4xxx_mem_alloc 1840afaf5a2dSDavid Somayajulu **/ 1841afaf5a2dSDavid Somayajulu static void qla4xxx_mem_free(struct scsi_qla_host *ha) 1842afaf5a2dSDavid Somayajulu { 1843afaf5a2dSDavid Somayajulu if (ha->queues) 1844afaf5a2dSDavid Somayajulu dma_free_coherent(&ha->pdev->dev, ha->queues_len, ha->queues, 1845afaf5a2dSDavid Somayajulu ha->queues_dma); 1846afaf5a2dSDavid Somayajulu 1847afaf5a2dSDavid Somayajulu ha->queues_len = 0; 1848afaf5a2dSDavid Somayajulu ha->queues = NULL; 1849afaf5a2dSDavid Somayajulu ha->queues_dma = 0; 1850afaf5a2dSDavid Somayajulu ha->request_ring = NULL; 1851afaf5a2dSDavid Somayajulu ha->request_dma = 0; 1852afaf5a2dSDavid Somayajulu ha->response_ring = NULL; 1853afaf5a2dSDavid Somayajulu ha->response_dma = 0; 1854afaf5a2dSDavid Somayajulu ha->shadow_regs = NULL; 1855afaf5a2dSDavid Somayajulu ha->shadow_regs_dma = 0; 1856afaf5a2dSDavid Somayajulu 1857afaf5a2dSDavid Somayajulu /* Free srb pool. */ 1858afaf5a2dSDavid Somayajulu if (ha->srb_mempool) 1859afaf5a2dSDavid Somayajulu mempool_destroy(ha->srb_mempool); 1860afaf5a2dSDavid Somayajulu 1861afaf5a2dSDavid Somayajulu ha->srb_mempool = NULL; 1862afaf5a2dSDavid Somayajulu 1863b3a271a9SManish Rangankar if (ha->chap_dma_pool) 1864b3a271a9SManish Rangankar dma_pool_destroy(ha->chap_dma_pool); 1865b3a271a9SManish Rangankar 18664549415aSLalit Chandivade if (ha->chap_list) 18674549415aSLalit Chandivade vfree(ha->chap_list); 18684549415aSLalit Chandivade ha->chap_list = NULL; 18694549415aSLalit Chandivade 187013483730SMike Christie if (ha->fw_ddb_dma_pool) 187113483730SMike Christie dma_pool_destroy(ha->fw_ddb_dma_pool); 187213483730SMike Christie 1873afaf5a2dSDavid Somayajulu /* release io space registers */ 1874f4f5df23SVikas Chaudhary if (is_qla8022(ha)) { 1875f4f5df23SVikas Chaudhary if (ha->nx_pcibase) 1876f4f5df23SVikas Chaudhary iounmap( 1877f4f5df23SVikas Chaudhary (struct device_reg_82xx __iomem *)ha->nx_pcibase); 1878f4f5df23SVikas Chaudhary } else if (ha->reg) 1879afaf5a2dSDavid Somayajulu iounmap(ha->reg); 1880afaf5a2dSDavid Somayajulu pci_release_regions(ha->pdev); 1881afaf5a2dSDavid Somayajulu } 1882afaf5a2dSDavid Somayajulu 1883afaf5a2dSDavid Somayajulu /** 1884afaf5a2dSDavid Somayajulu * qla4xxx_mem_alloc - allocates memory for use by adapter. 1885afaf5a2dSDavid Somayajulu * @ha: Pointer to host adapter structure 1886afaf5a2dSDavid Somayajulu * 1887afaf5a2dSDavid Somayajulu * Allocates DMA memory for request and response queues. Also allocates memory 1888afaf5a2dSDavid Somayajulu * for srbs. 1889afaf5a2dSDavid Somayajulu **/ 1890afaf5a2dSDavid Somayajulu static int qla4xxx_mem_alloc(struct scsi_qla_host *ha) 1891afaf5a2dSDavid Somayajulu { 1892afaf5a2dSDavid Somayajulu unsigned long align; 1893afaf5a2dSDavid Somayajulu 1894afaf5a2dSDavid Somayajulu /* Allocate contiguous block of DMA memory for queues. */ 1895afaf5a2dSDavid Somayajulu ha->queues_len = ((REQUEST_QUEUE_DEPTH * QUEUE_SIZE) + 1896afaf5a2dSDavid Somayajulu (RESPONSE_QUEUE_DEPTH * QUEUE_SIZE) + 1897afaf5a2dSDavid Somayajulu sizeof(struct shadow_regs) + 1898afaf5a2dSDavid Somayajulu MEM_ALIGN_VALUE + 1899afaf5a2dSDavid Somayajulu (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1); 1900afaf5a2dSDavid Somayajulu ha->queues = dma_alloc_coherent(&ha->pdev->dev, ha->queues_len, 1901afaf5a2dSDavid Somayajulu &ha->queues_dma, GFP_KERNEL); 1902afaf5a2dSDavid Somayajulu if (ha->queues == NULL) { 1903c2660df3SVikas Chaudhary ql4_printk(KERN_WARNING, ha, 1904afaf5a2dSDavid Somayajulu "Memory Allocation failed - queues.\n"); 1905afaf5a2dSDavid Somayajulu 1906afaf5a2dSDavid Somayajulu goto mem_alloc_error_exit; 1907afaf5a2dSDavid Somayajulu } 1908afaf5a2dSDavid Somayajulu memset(ha->queues, 0, ha->queues_len); 1909afaf5a2dSDavid Somayajulu 1910afaf5a2dSDavid Somayajulu /* 1911afaf5a2dSDavid Somayajulu * As per RISC alignment requirements -- the bus-address must be a 1912afaf5a2dSDavid Somayajulu * multiple of the request-ring size (in bytes). 1913afaf5a2dSDavid Somayajulu */ 1914afaf5a2dSDavid Somayajulu align = 0; 1915afaf5a2dSDavid Somayajulu if ((unsigned long)ha->queues_dma & (MEM_ALIGN_VALUE - 1)) 1916afaf5a2dSDavid Somayajulu align = MEM_ALIGN_VALUE - ((unsigned long)ha->queues_dma & 1917afaf5a2dSDavid Somayajulu (MEM_ALIGN_VALUE - 1)); 1918afaf5a2dSDavid Somayajulu 1919afaf5a2dSDavid Somayajulu /* Update request and response queue pointers. */ 1920afaf5a2dSDavid Somayajulu ha->request_dma = ha->queues_dma + align; 1921afaf5a2dSDavid Somayajulu ha->request_ring = (struct queue_entry *) (ha->queues + align); 1922afaf5a2dSDavid Somayajulu ha->response_dma = ha->queues_dma + align + 1923afaf5a2dSDavid Somayajulu (REQUEST_QUEUE_DEPTH * QUEUE_SIZE); 1924afaf5a2dSDavid Somayajulu ha->response_ring = (struct queue_entry *) (ha->queues + align + 1925afaf5a2dSDavid Somayajulu (REQUEST_QUEUE_DEPTH * 1926afaf5a2dSDavid Somayajulu QUEUE_SIZE)); 1927afaf5a2dSDavid Somayajulu ha->shadow_regs_dma = ha->queues_dma + align + 1928afaf5a2dSDavid Somayajulu (REQUEST_QUEUE_DEPTH * QUEUE_SIZE) + 1929afaf5a2dSDavid Somayajulu (RESPONSE_QUEUE_DEPTH * QUEUE_SIZE); 1930afaf5a2dSDavid Somayajulu ha->shadow_regs = (struct shadow_regs *) (ha->queues + align + 1931afaf5a2dSDavid Somayajulu (REQUEST_QUEUE_DEPTH * 1932afaf5a2dSDavid Somayajulu QUEUE_SIZE) + 1933afaf5a2dSDavid Somayajulu (RESPONSE_QUEUE_DEPTH * 1934afaf5a2dSDavid Somayajulu QUEUE_SIZE)); 1935afaf5a2dSDavid Somayajulu 1936afaf5a2dSDavid Somayajulu /* Allocate memory for srb pool. */ 1937afaf5a2dSDavid Somayajulu ha->srb_mempool = mempool_create(SRB_MIN_REQ, mempool_alloc_slab, 1938afaf5a2dSDavid Somayajulu mempool_free_slab, srb_cachep); 1939afaf5a2dSDavid Somayajulu if (ha->srb_mempool == NULL) { 1940c2660df3SVikas Chaudhary ql4_printk(KERN_WARNING, ha, 1941afaf5a2dSDavid Somayajulu "Memory Allocation failed - SRB Pool.\n"); 1942afaf5a2dSDavid Somayajulu 1943afaf5a2dSDavid Somayajulu goto mem_alloc_error_exit; 1944afaf5a2dSDavid Somayajulu } 1945afaf5a2dSDavid Somayajulu 1946b3a271a9SManish Rangankar ha->chap_dma_pool = dma_pool_create("ql4_chap", &ha->pdev->dev, 1947b3a271a9SManish Rangankar CHAP_DMA_BLOCK_SIZE, 8, 0); 1948b3a271a9SManish Rangankar 1949b3a271a9SManish Rangankar if (ha->chap_dma_pool == NULL) { 1950b3a271a9SManish Rangankar ql4_printk(KERN_WARNING, ha, 1951b3a271a9SManish Rangankar "%s: chap_dma_pool allocation failed..\n", __func__); 1952b3a271a9SManish Rangankar goto mem_alloc_error_exit; 1953b3a271a9SManish Rangankar } 1954b3a271a9SManish Rangankar 195513483730SMike Christie ha->fw_ddb_dma_pool = dma_pool_create("ql4_fw_ddb", &ha->pdev->dev, 195613483730SMike Christie DDB_DMA_BLOCK_SIZE, 8, 0); 195713483730SMike Christie 195813483730SMike Christie if (ha->fw_ddb_dma_pool == NULL) { 195913483730SMike Christie ql4_printk(KERN_WARNING, ha, 196013483730SMike Christie "%s: fw_ddb_dma_pool allocation failed..\n", 196113483730SMike Christie __func__); 196213483730SMike Christie goto mem_alloc_error_exit; 196313483730SMike Christie } 196413483730SMike Christie 1965afaf5a2dSDavid Somayajulu return QLA_SUCCESS; 1966afaf5a2dSDavid Somayajulu 1967afaf5a2dSDavid Somayajulu mem_alloc_error_exit: 1968afaf5a2dSDavid Somayajulu qla4xxx_mem_free(ha); 1969afaf5a2dSDavid Somayajulu return QLA_ERROR; 1970afaf5a2dSDavid Somayajulu } 1971afaf5a2dSDavid Somayajulu 1972afaf5a2dSDavid Somayajulu /** 1973f4f5df23SVikas Chaudhary * qla4_8xxx_check_fw_alive - Check firmware health 1974f4f5df23SVikas Chaudhary * @ha: Pointer to host adapter structure. 1975f4f5df23SVikas Chaudhary * 1976f4f5df23SVikas Chaudhary * Context: Interrupt 1977f4f5df23SVikas Chaudhary **/ 19789ee91a38SShyam Sunder static int qla4_8xxx_check_fw_alive(struct scsi_qla_host *ha) 1979f4f5df23SVikas Chaudhary { 19809ee91a38SShyam Sunder uint32_t fw_heartbeat_counter; 19819ee91a38SShyam Sunder int status = QLA_SUCCESS; 1982f4f5df23SVikas Chaudhary 1983f4f5df23SVikas Chaudhary fw_heartbeat_counter = qla4_8xxx_rd_32(ha, QLA82XX_PEG_ALIVE_COUNTER); 19842232be0dSLalit Chandivade /* If PEG_ALIVE_COUNTER is 0xffffffff, AER/EEH is in progress, ignore */ 19852232be0dSLalit Chandivade if (fw_heartbeat_counter == 0xffffffff) { 19862232be0dSLalit Chandivade DEBUG2(printk(KERN_WARNING "scsi%ld: %s: Device in frozen " 19872232be0dSLalit Chandivade "state, QLA82XX_PEG_ALIVE_COUNTER is 0xffffffff\n", 19882232be0dSLalit Chandivade ha->host_no, __func__)); 19899ee91a38SShyam Sunder return status; 19902232be0dSLalit Chandivade } 1991f4f5df23SVikas Chaudhary 1992f4f5df23SVikas Chaudhary if (ha->fw_heartbeat_counter == fw_heartbeat_counter) { 1993f4f5df23SVikas Chaudhary ha->seconds_since_last_heartbeat++; 1994f4f5df23SVikas Chaudhary /* FW not alive after 2 seconds */ 1995f4f5df23SVikas Chaudhary if (ha->seconds_since_last_heartbeat == 2) { 1996f4f5df23SVikas Chaudhary ha->seconds_since_last_heartbeat = 0; 199768d92ebfSVikas Chaudhary 199868d92ebfSVikas Chaudhary ql4_printk(KERN_INFO, ha, 199968d92ebfSVikas Chaudhary "scsi(%ld): %s, Dumping hw/fw registers:\n " 200068d92ebfSVikas Chaudhary " PEG_HALT_STATUS1: 0x%x, PEG_HALT_STATUS2:" 200168d92ebfSVikas Chaudhary " 0x%x,\n PEG_NET_0_PC: 0x%x, PEG_NET_1_PC:" 200268d92ebfSVikas Chaudhary " 0x%x,\n PEG_NET_2_PC: 0x%x, PEG_NET_3_PC:" 200368d92ebfSVikas Chaudhary " 0x%x,\n PEG_NET_4_PC: 0x%x\n", 20049ee91a38SShyam Sunder ha->host_no, __func__, 20059ee91a38SShyam Sunder qla4_8xxx_rd_32(ha, 20069ee91a38SShyam Sunder QLA82XX_PEG_HALT_STATUS1), 200768d92ebfSVikas Chaudhary qla4_8xxx_rd_32(ha, 200868d92ebfSVikas Chaudhary QLA82XX_PEG_HALT_STATUS2), 200968d92ebfSVikas Chaudhary qla4_8xxx_rd_32(ha, QLA82XX_CRB_PEG_NET_0 + 201068d92ebfSVikas Chaudhary 0x3c), 201168d92ebfSVikas Chaudhary qla4_8xxx_rd_32(ha, QLA82XX_CRB_PEG_NET_1 + 201268d92ebfSVikas Chaudhary 0x3c), 201368d92ebfSVikas Chaudhary qla4_8xxx_rd_32(ha, QLA82XX_CRB_PEG_NET_2 + 201468d92ebfSVikas Chaudhary 0x3c), 201568d92ebfSVikas Chaudhary qla4_8xxx_rd_32(ha, QLA82XX_CRB_PEG_NET_3 + 201668d92ebfSVikas Chaudhary 0x3c), 201768d92ebfSVikas Chaudhary qla4_8xxx_rd_32(ha, QLA82XX_CRB_PEG_NET_4 + 201868d92ebfSVikas Chaudhary 0x3c)); 20199ee91a38SShyam Sunder status = QLA_ERROR; 2020f4f5df23SVikas Chaudhary } 202199457d75SLalit Chandivade } else 202299457d75SLalit Chandivade ha->seconds_since_last_heartbeat = 0; 202399457d75SLalit Chandivade 2024f4f5df23SVikas Chaudhary ha->fw_heartbeat_counter = fw_heartbeat_counter; 20259ee91a38SShyam Sunder return status; 2026f4f5df23SVikas Chaudhary } 2027f4f5df23SVikas Chaudhary 2028f4f5df23SVikas Chaudhary /** 2029f4f5df23SVikas Chaudhary * qla4_8xxx_watchdog - Poll dev state 2030f4f5df23SVikas Chaudhary * @ha: Pointer to host adapter structure. 2031f4f5df23SVikas Chaudhary * 2032f4f5df23SVikas Chaudhary * Context: Interrupt 2033f4f5df23SVikas Chaudhary **/ 2034f4f5df23SVikas Chaudhary void qla4_8xxx_watchdog(struct scsi_qla_host *ha) 2035f4f5df23SVikas Chaudhary { 20369ee91a38SShyam Sunder uint32_t dev_state, halt_status; 2037f4f5df23SVikas Chaudhary 2038f4f5df23SVikas Chaudhary /* don't poll if reset is going on */ 2039d56a1f7bSLalit Chandivade if (!(test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags) || 2040d56a1f7bSLalit Chandivade test_bit(DPC_RESET_HA, &ha->dpc_flags) || 2041977f46a4SVikas Chaudhary test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags))) { 20429ee91a38SShyam Sunder dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE); 2043f4f5df23SVikas Chaudhary if (dev_state == QLA82XX_DEV_NEED_RESET && 2044f4f5df23SVikas Chaudhary !test_bit(DPC_RESET_HA, &ha->dpc_flags)) { 20453930b8c1SVikas Chaudhary if (!ql4xdontresethba) { 20463930b8c1SVikas Chaudhary ql4_printk(KERN_INFO, ha, "%s: HW State: " 20473930b8c1SVikas Chaudhary "NEED RESET!\n", __func__); 2048f4f5df23SVikas Chaudhary set_bit(DPC_RESET_HA, &ha->dpc_flags); 2049f4f5df23SVikas Chaudhary qla4xxx_wake_dpc(ha); 20503930b8c1SVikas Chaudhary } 2051f4f5df23SVikas Chaudhary } else if (dev_state == QLA82XX_DEV_NEED_QUIESCENT && 2052f4f5df23SVikas Chaudhary !test_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags)) { 20533930b8c1SVikas Chaudhary ql4_printk(KERN_INFO, ha, "%s: HW State: NEED QUIES!\n", 20543930b8c1SVikas Chaudhary __func__); 2055f4f5df23SVikas Chaudhary set_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags); 2056f4f5df23SVikas Chaudhary qla4xxx_wake_dpc(ha); 2057f4f5df23SVikas Chaudhary } else { 2058f4f5df23SVikas Chaudhary /* Check firmware health */ 20599ee91a38SShyam Sunder if (qla4_8xxx_check_fw_alive(ha)) { 20609ee91a38SShyam Sunder halt_status = qla4_8xxx_rd_32(ha, 20619ee91a38SShyam Sunder QLA82XX_PEG_HALT_STATUS1); 20629ee91a38SShyam Sunder 20639ee91a38SShyam Sunder /* Since we cannot change dev_state in interrupt 20649ee91a38SShyam Sunder * context, set appropriate DPC flag then wakeup 20659ee91a38SShyam Sunder * DPC */ 20669ee91a38SShyam Sunder if (halt_status & HALT_STATUS_UNRECOVERABLE) 20679ee91a38SShyam Sunder set_bit(DPC_HA_UNRECOVERABLE, 20689ee91a38SShyam Sunder &ha->dpc_flags); 20699ee91a38SShyam Sunder else { 20709ee91a38SShyam Sunder ql4_printk(KERN_INFO, ha, "%s: detect " 20719ee91a38SShyam Sunder "abort needed!\n", __func__); 20729ee91a38SShyam Sunder set_bit(DPC_RESET_HA, &ha->dpc_flags); 20739ee91a38SShyam Sunder } 20749ee91a38SShyam Sunder qla4xxx_mailbox_premature_completion(ha); 20759ee91a38SShyam Sunder qla4xxx_wake_dpc(ha); 20769ee91a38SShyam Sunder } 2077f4f5df23SVikas Chaudhary } 2078f4f5df23SVikas Chaudhary } 2079f4f5df23SVikas Chaudhary } 2080f4f5df23SVikas Chaudhary 20814a4bc2e9SLalit Chandivade static void qla4xxx_check_relogin_flash_ddb(struct iscsi_cls_session *cls_sess) 208213483730SMike Christie { 208313483730SMike Christie struct iscsi_session *sess; 208413483730SMike Christie struct ddb_entry *ddb_entry; 208513483730SMike Christie struct scsi_qla_host *ha; 208613483730SMike Christie 208713483730SMike Christie sess = cls_sess->dd_data; 208813483730SMike Christie ddb_entry = sess->dd_data; 208913483730SMike Christie ha = ddb_entry->ha; 209013483730SMike Christie 209113483730SMike Christie if (!(ddb_entry->ddb_type == FLASH_DDB)) 209213483730SMike Christie return; 209313483730SMike Christie 209413483730SMike Christie if (adapter_up(ha) && !test_bit(DF_RELOGIN, &ddb_entry->flags) && 209513483730SMike Christie !iscsi_is_session_online(cls_sess)) { 209613483730SMike Christie if (atomic_read(&ddb_entry->retry_relogin_timer) != 209713483730SMike Christie INVALID_ENTRY) { 209813483730SMike Christie if (atomic_read(&ddb_entry->retry_relogin_timer) == 209913483730SMike Christie 0) { 210013483730SMike Christie atomic_set(&ddb_entry->retry_relogin_timer, 210113483730SMike Christie INVALID_ENTRY); 210213483730SMike Christie set_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags); 210313483730SMike Christie set_bit(DF_RELOGIN, &ddb_entry->flags); 210413483730SMike Christie DEBUG2(ql4_printk(KERN_INFO, ha, 210513483730SMike Christie "%s: index [%d] login device\n", 210613483730SMike Christie __func__, ddb_entry->fw_ddb_index)); 210713483730SMike Christie } else 210813483730SMike Christie atomic_dec(&ddb_entry->retry_relogin_timer); 210913483730SMike Christie } 211013483730SMike Christie } 211113483730SMike Christie 211213483730SMike Christie /* Wait for relogin to timeout */ 211313483730SMike Christie if (atomic_read(&ddb_entry->relogin_timer) && 211413483730SMike Christie (atomic_dec_and_test(&ddb_entry->relogin_timer) != 0)) { 211513483730SMike Christie /* 211613483730SMike Christie * If the relogin times out and the device is 211713483730SMike Christie * still NOT ONLINE then try and relogin again. 211813483730SMike Christie */ 211913483730SMike Christie if (!iscsi_is_session_online(cls_sess)) { 212013483730SMike Christie /* Reset retry relogin timer */ 212113483730SMike Christie atomic_inc(&ddb_entry->relogin_retry_count); 212213483730SMike Christie DEBUG2(ql4_printk(KERN_INFO, ha, 212313483730SMike Christie "%s: index[%d] relogin timed out-retrying" 212413483730SMike Christie " relogin (%d), retry (%d)\n", __func__, 212513483730SMike Christie ddb_entry->fw_ddb_index, 212613483730SMike Christie atomic_read(&ddb_entry->relogin_retry_count), 212713483730SMike Christie ddb_entry->default_time2wait + 4)); 212813483730SMike Christie set_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags); 212913483730SMike Christie atomic_set(&ddb_entry->retry_relogin_timer, 213013483730SMike Christie ddb_entry->default_time2wait + 4); 213113483730SMike Christie } 213213483730SMike Christie } 213313483730SMike Christie } 213413483730SMike Christie 2135f4f5df23SVikas Chaudhary /** 2136afaf5a2dSDavid Somayajulu * qla4xxx_timer - checks every second for work to do. 2137afaf5a2dSDavid Somayajulu * @ha: Pointer to host adapter structure. 2138afaf5a2dSDavid Somayajulu **/ 2139afaf5a2dSDavid Somayajulu static void qla4xxx_timer(struct scsi_qla_host *ha) 2140afaf5a2dSDavid Somayajulu { 2141afaf5a2dSDavid Somayajulu int start_dpc = 0; 21422232be0dSLalit Chandivade uint16_t w; 21432232be0dSLalit Chandivade 214413483730SMike Christie iscsi_host_for_each_session(ha->host, qla4xxx_check_relogin_flash_ddb); 214513483730SMike Christie 21462232be0dSLalit Chandivade /* If we are in the middle of AER/EEH processing 21472232be0dSLalit Chandivade * skip any processing and reschedule the timer 21482232be0dSLalit Chandivade */ 21492232be0dSLalit Chandivade if (test_bit(AF_EEH_BUSY, &ha->flags)) { 21502232be0dSLalit Chandivade mod_timer(&ha->timer, jiffies + HZ); 21512232be0dSLalit Chandivade return; 21522232be0dSLalit Chandivade } 21532232be0dSLalit Chandivade 21542232be0dSLalit Chandivade /* Hardware read to trigger an EEH error during mailbox waits. */ 21552232be0dSLalit Chandivade if (!pci_channel_offline(ha->pdev)) 21562232be0dSLalit Chandivade pci_read_config_word(ha->pdev, PCI_VENDOR_ID, &w); 2157afaf5a2dSDavid Somayajulu 2158f4f5df23SVikas Chaudhary if (is_qla8022(ha)) { 2159f4f5df23SVikas Chaudhary qla4_8xxx_watchdog(ha); 2160f4f5df23SVikas Chaudhary } 2161f4f5df23SVikas Chaudhary 2162f4f5df23SVikas Chaudhary if (!is_qla8022(ha)) { 2163afaf5a2dSDavid Somayajulu /* Check for heartbeat interval. */ 2164afaf5a2dSDavid Somayajulu if (ha->firmware_options & FWOPT_HEARTBEAT_ENABLE && 2165afaf5a2dSDavid Somayajulu ha->heartbeat_interval != 0) { 2166afaf5a2dSDavid Somayajulu ha->seconds_since_last_heartbeat++; 2167afaf5a2dSDavid Somayajulu if (ha->seconds_since_last_heartbeat > 2168afaf5a2dSDavid Somayajulu ha->heartbeat_interval + 2) 2169afaf5a2dSDavid Somayajulu set_bit(DPC_RESET_HA, &ha->dpc_flags); 2170afaf5a2dSDavid Somayajulu } 2171f4f5df23SVikas Chaudhary } 2172afaf5a2dSDavid Somayajulu 2173afaf5a2dSDavid Somayajulu /* Wakeup the dpc routine for this adapter, if needed. */ 21741b46807eSLalit Chandivade if (start_dpc || 2175afaf5a2dSDavid Somayajulu test_bit(DPC_RESET_HA, &ha->dpc_flags) || 2176afaf5a2dSDavid Somayajulu test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags) || 2177afaf5a2dSDavid Somayajulu test_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags) || 2178f4f5df23SVikas Chaudhary test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags) || 2179afaf5a2dSDavid Somayajulu test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) || 2180afaf5a2dSDavid Somayajulu test_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags) || 2181065aa1b4SVikas Chaudhary test_bit(DPC_LINK_CHANGED, &ha->dpc_flags) || 2182f4f5df23SVikas Chaudhary test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags) || 2183f4f5df23SVikas Chaudhary test_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags) || 21841b46807eSLalit Chandivade test_bit(DPC_AEN, &ha->dpc_flags)) { 2185afaf5a2dSDavid Somayajulu DEBUG2(printk("scsi%ld: %s: scheduling dpc routine" 2186afaf5a2dSDavid Somayajulu " - dpc flags = 0x%lx\n", 2187afaf5a2dSDavid Somayajulu ha->host_no, __func__, ha->dpc_flags)); 2188f4f5df23SVikas Chaudhary qla4xxx_wake_dpc(ha); 2189afaf5a2dSDavid Somayajulu } 2190afaf5a2dSDavid Somayajulu 2191afaf5a2dSDavid Somayajulu /* Reschedule timer thread to call us back in one second */ 2192afaf5a2dSDavid Somayajulu mod_timer(&ha->timer, jiffies + HZ); 2193afaf5a2dSDavid Somayajulu 2194afaf5a2dSDavid Somayajulu DEBUG2(ha->seconds_since_last_intr++); 2195afaf5a2dSDavid Somayajulu } 2196afaf5a2dSDavid Somayajulu 2197afaf5a2dSDavid Somayajulu /** 2198afaf5a2dSDavid Somayajulu * qla4xxx_cmd_wait - waits for all outstanding commands to complete 2199afaf5a2dSDavid Somayajulu * @ha: Pointer to host adapter structure. 2200afaf5a2dSDavid Somayajulu * 2201afaf5a2dSDavid Somayajulu * This routine stalls the driver until all outstanding commands are returned. 2202afaf5a2dSDavid Somayajulu * Caller must release the Hardware Lock prior to calling this routine. 2203afaf5a2dSDavid Somayajulu **/ 2204afaf5a2dSDavid Somayajulu static int qla4xxx_cmd_wait(struct scsi_qla_host *ha) 2205afaf5a2dSDavid Somayajulu { 2206afaf5a2dSDavid Somayajulu uint32_t index = 0; 2207afaf5a2dSDavid Somayajulu unsigned long flags; 2208afaf5a2dSDavid Somayajulu struct scsi_cmnd *cmd; 2209afaf5a2dSDavid Somayajulu 2210f4f5df23SVikas Chaudhary unsigned long wtime = jiffies + (WAIT_CMD_TOV * HZ); 2211f4f5df23SVikas Chaudhary 2212f4f5df23SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, "Wait up to %d seconds for cmds to " 2213f4f5df23SVikas Chaudhary "complete\n", WAIT_CMD_TOV)); 2214f4f5df23SVikas Chaudhary 2215f4f5df23SVikas Chaudhary while (!time_after_eq(jiffies, wtime)) { 2216afaf5a2dSDavid Somayajulu spin_lock_irqsave(&ha->hardware_lock, flags); 2217afaf5a2dSDavid Somayajulu /* Find a command that hasn't completed. */ 2218afaf5a2dSDavid Somayajulu for (index = 0; index < ha->host->can_queue; index++) { 2219afaf5a2dSDavid Somayajulu cmd = scsi_host_find_tag(ha->host, index); 2220a1e0063dSMike Christie /* 2221a1e0063dSMike Christie * We cannot just check if the index is valid, 2222a1e0063dSMike Christie * becase if we are run from the scsi eh, then 2223a1e0063dSMike Christie * the scsi/block layer is going to prevent 2224a1e0063dSMike Christie * the tag from being released. 2225a1e0063dSMike Christie */ 2226a1e0063dSMike Christie if (cmd != NULL && CMD_SP(cmd)) 2227afaf5a2dSDavid Somayajulu break; 2228afaf5a2dSDavid Somayajulu } 2229afaf5a2dSDavid Somayajulu spin_unlock_irqrestore(&ha->hardware_lock, flags); 2230afaf5a2dSDavid Somayajulu 2231afaf5a2dSDavid Somayajulu /* If No Commands are pending, wait is complete */ 2232f4f5df23SVikas Chaudhary if (index == ha->host->can_queue) 2233f4f5df23SVikas Chaudhary return QLA_SUCCESS; 2234afaf5a2dSDavid Somayajulu 2235afaf5a2dSDavid Somayajulu msleep(1000); 2236afaf5a2dSDavid Somayajulu } 2237f4f5df23SVikas Chaudhary /* If we timed out on waiting for commands to come back 2238f4f5df23SVikas Chaudhary * return ERROR. */ 2239f4f5df23SVikas Chaudhary return QLA_ERROR; 2240afaf5a2dSDavid Somayajulu } 2241afaf5a2dSDavid Somayajulu 2242f4f5df23SVikas Chaudhary int qla4xxx_hw_reset(struct scsi_qla_host *ha) 2243afaf5a2dSDavid Somayajulu { 2244afaf5a2dSDavid Somayajulu uint32_t ctrl_status; 2245477ffb9dSDavid C Somayajulu unsigned long flags = 0; 2246477ffb9dSDavid C Somayajulu 2247477ffb9dSDavid C Somayajulu DEBUG2(printk(KERN_ERR "scsi%ld: %s\n", ha->host_no, __func__)); 2248afaf5a2dSDavid Somayajulu 2249f4f5df23SVikas Chaudhary if (ql4xxx_lock_drvr_wait(ha) != QLA_SUCCESS) 2250f4f5df23SVikas Chaudhary return QLA_ERROR; 2251f4f5df23SVikas Chaudhary 2252afaf5a2dSDavid Somayajulu spin_lock_irqsave(&ha->hardware_lock, flags); 2253afaf5a2dSDavid Somayajulu 2254afaf5a2dSDavid Somayajulu /* 2255afaf5a2dSDavid Somayajulu * If the SCSI Reset Interrupt bit is set, clear it. 2256afaf5a2dSDavid Somayajulu * Otherwise, the Soft Reset won't work. 2257afaf5a2dSDavid Somayajulu */ 2258afaf5a2dSDavid Somayajulu ctrl_status = readw(&ha->reg->ctrl_status); 2259afaf5a2dSDavid Somayajulu if ((ctrl_status & CSR_SCSI_RESET_INTR) != 0) 2260afaf5a2dSDavid Somayajulu writel(set_rmask(CSR_SCSI_RESET_INTR), &ha->reg->ctrl_status); 2261afaf5a2dSDavid Somayajulu 2262afaf5a2dSDavid Somayajulu /* Issue Soft Reset */ 2263afaf5a2dSDavid Somayajulu writel(set_rmask(CSR_SOFT_RESET), &ha->reg->ctrl_status); 2264afaf5a2dSDavid Somayajulu readl(&ha->reg->ctrl_status); 2265afaf5a2dSDavid Somayajulu 2266afaf5a2dSDavid Somayajulu spin_unlock_irqrestore(&ha->hardware_lock, flags); 2267f4f5df23SVikas Chaudhary return QLA_SUCCESS; 2268477ffb9dSDavid C Somayajulu } 2269477ffb9dSDavid C Somayajulu 2270477ffb9dSDavid C Somayajulu /** 2271477ffb9dSDavid C Somayajulu * qla4xxx_soft_reset - performs soft reset. 2272477ffb9dSDavid C Somayajulu * @ha: Pointer to host adapter structure. 2273477ffb9dSDavid C Somayajulu **/ 2274477ffb9dSDavid C Somayajulu int qla4xxx_soft_reset(struct scsi_qla_host *ha) 2275477ffb9dSDavid C Somayajulu { 2276477ffb9dSDavid C Somayajulu uint32_t max_wait_time; 2277477ffb9dSDavid C Somayajulu unsigned long flags = 0; 2278f931c534SVikas Chaudhary int status; 2279477ffb9dSDavid C Somayajulu uint32_t ctrl_status; 2280477ffb9dSDavid C Somayajulu 2281f931c534SVikas Chaudhary status = qla4xxx_hw_reset(ha); 2282f931c534SVikas Chaudhary if (status != QLA_SUCCESS) 2283f931c534SVikas Chaudhary return status; 2284afaf5a2dSDavid Somayajulu 2285f931c534SVikas Chaudhary status = QLA_ERROR; 2286afaf5a2dSDavid Somayajulu /* Wait until the Network Reset Intr bit is cleared */ 2287afaf5a2dSDavid Somayajulu max_wait_time = RESET_INTR_TOV; 2288afaf5a2dSDavid Somayajulu do { 2289afaf5a2dSDavid Somayajulu spin_lock_irqsave(&ha->hardware_lock, flags); 2290afaf5a2dSDavid Somayajulu ctrl_status = readw(&ha->reg->ctrl_status); 2291afaf5a2dSDavid Somayajulu spin_unlock_irqrestore(&ha->hardware_lock, flags); 2292afaf5a2dSDavid Somayajulu 2293afaf5a2dSDavid Somayajulu if ((ctrl_status & CSR_NET_RESET_INTR) == 0) 2294afaf5a2dSDavid Somayajulu break; 2295afaf5a2dSDavid Somayajulu 2296afaf5a2dSDavid Somayajulu msleep(1000); 2297afaf5a2dSDavid Somayajulu } while ((--max_wait_time)); 2298afaf5a2dSDavid Somayajulu 2299afaf5a2dSDavid Somayajulu if ((ctrl_status & CSR_NET_RESET_INTR) != 0) { 2300afaf5a2dSDavid Somayajulu DEBUG2(printk(KERN_WARNING 2301afaf5a2dSDavid Somayajulu "scsi%ld: Network Reset Intr not cleared by " 2302afaf5a2dSDavid Somayajulu "Network function, clearing it now!\n", 2303afaf5a2dSDavid Somayajulu ha->host_no)); 2304afaf5a2dSDavid Somayajulu spin_lock_irqsave(&ha->hardware_lock, flags); 2305afaf5a2dSDavid Somayajulu writel(set_rmask(CSR_NET_RESET_INTR), &ha->reg->ctrl_status); 2306afaf5a2dSDavid Somayajulu readl(&ha->reg->ctrl_status); 2307afaf5a2dSDavid Somayajulu spin_unlock_irqrestore(&ha->hardware_lock, flags); 2308afaf5a2dSDavid Somayajulu } 2309afaf5a2dSDavid Somayajulu 2310afaf5a2dSDavid Somayajulu /* Wait until the firmware tells us the Soft Reset is done */ 2311afaf5a2dSDavid Somayajulu max_wait_time = SOFT_RESET_TOV; 2312afaf5a2dSDavid Somayajulu do { 2313afaf5a2dSDavid Somayajulu spin_lock_irqsave(&ha->hardware_lock, flags); 2314afaf5a2dSDavid Somayajulu ctrl_status = readw(&ha->reg->ctrl_status); 2315afaf5a2dSDavid Somayajulu spin_unlock_irqrestore(&ha->hardware_lock, flags); 2316afaf5a2dSDavid Somayajulu 2317afaf5a2dSDavid Somayajulu if ((ctrl_status & CSR_SOFT_RESET) == 0) { 2318afaf5a2dSDavid Somayajulu status = QLA_SUCCESS; 2319afaf5a2dSDavid Somayajulu break; 2320afaf5a2dSDavid Somayajulu } 2321afaf5a2dSDavid Somayajulu 2322afaf5a2dSDavid Somayajulu msleep(1000); 2323afaf5a2dSDavid Somayajulu } while ((--max_wait_time)); 2324afaf5a2dSDavid Somayajulu 2325afaf5a2dSDavid Somayajulu /* 2326afaf5a2dSDavid Somayajulu * Also, make sure that the SCSI Reset Interrupt bit has been cleared 2327afaf5a2dSDavid Somayajulu * after the soft reset has taken place. 2328afaf5a2dSDavid Somayajulu */ 2329afaf5a2dSDavid Somayajulu spin_lock_irqsave(&ha->hardware_lock, flags); 2330afaf5a2dSDavid Somayajulu ctrl_status = readw(&ha->reg->ctrl_status); 2331afaf5a2dSDavid Somayajulu if ((ctrl_status & CSR_SCSI_RESET_INTR) != 0) { 2332afaf5a2dSDavid Somayajulu writel(set_rmask(CSR_SCSI_RESET_INTR), &ha->reg->ctrl_status); 2333afaf5a2dSDavid Somayajulu readl(&ha->reg->ctrl_status); 2334afaf5a2dSDavid Somayajulu } 2335afaf5a2dSDavid Somayajulu spin_unlock_irqrestore(&ha->hardware_lock, flags); 2336afaf5a2dSDavid Somayajulu 2337afaf5a2dSDavid Somayajulu /* If soft reset fails then most probably the bios on other 2338afaf5a2dSDavid Somayajulu * function is also enabled. 2339afaf5a2dSDavid Somayajulu * Since the initialization is sequential the other fn 2340afaf5a2dSDavid Somayajulu * wont be able to acknowledge the soft reset. 2341afaf5a2dSDavid Somayajulu * Issue a force soft reset to workaround this scenario. 2342afaf5a2dSDavid Somayajulu */ 2343afaf5a2dSDavid Somayajulu if (max_wait_time == 0) { 2344afaf5a2dSDavid Somayajulu /* Issue Force Soft Reset */ 2345afaf5a2dSDavid Somayajulu spin_lock_irqsave(&ha->hardware_lock, flags); 2346afaf5a2dSDavid Somayajulu writel(set_rmask(CSR_FORCE_SOFT_RESET), &ha->reg->ctrl_status); 2347afaf5a2dSDavid Somayajulu readl(&ha->reg->ctrl_status); 2348afaf5a2dSDavid Somayajulu spin_unlock_irqrestore(&ha->hardware_lock, flags); 2349afaf5a2dSDavid Somayajulu /* Wait until the firmware tells us the Soft Reset is done */ 2350afaf5a2dSDavid Somayajulu max_wait_time = SOFT_RESET_TOV; 2351afaf5a2dSDavid Somayajulu do { 2352afaf5a2dSDavid Somayajulu spin_lock_irqsave(&ha->hardware_lock, flags); 2353afaf5a2dSDavid Somayajulu ctrl_status = readw(&ha->reg->ctrl_status); 2354afaf5a2dSDavid Somayajulu spin_unlock_irqrestore(&ha->hardware_lock, flags); 2355afaf5a2dSDavid Somayajulu 2356afaf5a2dSDavid Somayajulu if ((ctrl_status & CSR_FORCE_SOFT_RESET) == 0) { 2357afaf5a2dSDavid Somayajulu status = QLA_SUCCESS; 2358afaf5a2dSDavid Somayajulu break; 2359afaf5a2dSDavid Somayajulu } 2360afaf5a2dSDavid Somayajulu 2361afaf5a2dSDavid Somayajulu msleep(1000); 2362afaf5a2dSDavid Somayajulu } while ((--max_wait_time)); 2363afaf5a2dSDavid Somayajulu } 2364afaf5a2dSDavid Somayajulu 2365afaf5a2dSDavid Somayajulu return status; 2366afaf5a2dSDavid Somayajulu } 2367afaf5a2dSDavid Somayajulu 2368afaf5a2dSDavid Somayajulu /** 2369f4f5df23SVikas Chaudhary * qla4xxx_abort_active_cmds - returns all outstanding i/o requests to O.S. 2370afaf5a2dSDavid Somayajulu * @ha: Pointer to host adapter structure. 2371f4f5df23SVikas Chaudhary * @res: returned scsi status 2372afaf5a2dSDavid Somayajulu * 2373afaf5a2dSDavid Somayajulu * This routine is called just prior to a HARD RESET to return all 2374afaf5a2dSDavid Somayajulu * outstanding commands back to the Operating System. 2375afaf5a2dSDavid Somayajulu * Caller should make sure that the following locks are released 2376afaf5a2dSDavid Somayajulu * before this calling routine: Hardware lock, and io_request_lock. 2377afaf5a2dSDavid Somayajulu **/ 2378f4f5df23SVikas Chaudhary static void qla4xxx_abort_active_cmds(struct scsi_qla_host *ha, int res) 2379afaf5a2dSDavid Somayajulu { 2380afaf5a2dSDavid Somayajulu struct srb *srb; 2381afaf5a2dSDavid Somayajulu int i; 2382afaf5a2dSDavid Somayajulu unsigned long flags; 2383afaf5a2dSDavid Somayajulu 2384afaf5a2dSDavid Somayajulu spin_lock_irqsave(&ha->hardware_lock, flags); 2385afaf5a2dSDavid Somayajulu for (i = 0; i < ha->host->can_queue; i++) { 2386afaf5a2dSDavid Somayajulu srb = qla4xxx_del_from_active_array(ha, i); 2387afaf5a2dSDavid Somayajulu if (srb != NULL) { 2388f4f5df23SVikas Chaudhary srb->cmd->result = res; 238909a0f719SVikas Chaudhary kref_put(&srb->srb_ref, qla4xxx_srb_compl); 2390afaf5a2dSDavid Somayajulu } 2391afaf5a2dSDavid Somayajulu } 2392afaf5a2dSDavid Somayajulu spin_unlock_irqrestore(&ha->hardware_lock, flags); 2393afaf5a2dSDavid Somayajulu } 2394afaf5a2dSDavid Somayajulu 2395f4f5df23SVikas Chaudhary void qla4xxx_dead_adapter_cleanup(struct scsi_qla_host *ha) 2396f4f5df23SVikas Chaudhary { 2397f4f5df23SVikas Chaudhary clear_bit(AF_ONLINE, &ha->flags); 2398f4f5df23SVikas Chaudhary 2399f4f5df23SVikas Chaudhary /* Disable the board */ 2400f4f5df23SVikas Chaudhary ql4_printk(KERN_INFO, ha, "Disabling the board\n"); 2401f4f5df23SVikas Chaudhary 2402f4f5df23SVikas Chaudhary qla4xxx_abort_active_cmds(ha, DID_NO_CONNECT << 16); 2403f4f5df23SVikas Chaudhary qla4xxx_mark_all_devices_missing(ha); 2404f4f5df23SVikas Chaudhary clear_bit(AF_INIT_DONE, &ha->flags); 2405f4f5df23SVikas Chaudhary } 2406f4f5df23SVikas Chaudhary 2407b3a271a9SManish Rangankar static void qla4xxx_fail_session(struct iscsi_cls_session *cls_session) 2408b3a271a9SManish Rangankar { 2409b3a271a9SManish Rangankar struct iscsi_session *sess; 2410b3a271a9SManish Rangankar struct ddb_entry *ddb_entry; 2411b3a271a9SManish Rangankar 2412b3a271a9SManish Rangankar sess = cls_session->dd_data; 2413b3a271a9SManish Rangankar ddb_entry = sess->dd_data; 2414b3a271a9SManish Rangankar ddb_entry->fw_ddb_device_state = DDB_DS_SESSION_FAILED; 241513483730SMike Christie 241613483730SMike Christie if (ddb_entry->ddb_type == FLASH_DDB) 241713483730SMike Christie iscsi_block_session(ddb_entry->sess); 241813483730SMike Christie else 241913483730SMike Christie iscsi_session_failure(cls_session->dd_data, 242013483730SMike Christie ISCSI_ERR_CONN_FAILED); 2421b3a271a9SManish Rangankar } 2422b3a271a9SManish Rangankar 2423afaf5a2dSDavid Somayajulu /** 2424afaf5a2dSDavid Somayajulu * qla4xxx_recover_adapter - recovers adapter after a fatal error 2425afaf5a2dSDavid Somayajulu * @ha: Pointer to host adapter structure. 2426afaf5a2dSDavid Somayajulu **/ 2427f4f5df23SVikas Chaudhary static int qla4xxx_recover_adapter(struct scsi_qla_host *ha) 2428afaf5a2dSDavid Somayajulu { 2429f4f5df23SVikas Chaudhary int status = QLA_ERROR; 2430f4f5df23SVikas Chaudhary uint8_t reset_chip = 0; 24318e0f3a66SSarang Radke uint32_t dev_state; 24329ee91a38SShyam Sunder unsigned long wait; 2433afaf5a2dSDavid Somayajulu 2434afaf5a2dSDavid Somayajulu /* Stall incoming I/O until we are done */ 2435f4f5df23SVikas Chaudhary scsi_block_requests(ha->host); 2436afaf5a2dSDavid Somayajulu clear_bit(AF_ONLINE, &ha->flags); 2437b3a271a9SManish Rangankar clear_bit(AF_LINK_UP, &ha->flags); 243850a29aecSMike Christie 2439f4f5df23SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, "%s: adapter OFFLINE\n", __func__)); 2440afaf5a2dSDavid Somayajulu 2441f4f5df23SVikas Chaudhary set_bit(DPC_RESET_ACTIVE, &ha->dpc_flags); 2442afaf5a2dSDavid Somayajulu 2443b3a271a9SManish Rangankar iscsi_host_for_each_session(ha->host, qla4xxx_fail_session); 2444b3a271a9SManish Rangankar 2445f4f5df23SVikas Chaudhary if (test_bit(DPC_RESET_HA, &ha->dpc_flags)) 2446f4f5df23SVikas Chaudhary reset_chip = 1; 2447afaf5a2dSDavid Somayajulu 2448f4f5df23SVikas Chaudhary /* For the DPC_RESET_HA_INTR case (ISP-4xxx specific) 2449f4f5df23SVikas Chaudhary * do not reset adapter, jump to initialize_adapter */ 2450f4f5df23SVikas Chaudhary if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) { 2451f4f5df23SVikas Chaudhary status = QLA_SUCCESS; 2452f4f5df23SVikas Chaudhary goto recover_ha_init_adapter; 2453afaf5a2dSDavid Somayajulu } 2454afaf5a2dSDavid Somayajulu 2455f4f5df23SVikas Chaudhary /* For the ISP-82xx adapter, issue a stop_firmware if invoked 2456f4f5df23SVikas Chaudhary * from eh_host_reset or ioctl module */ 2457f4f5df23SVikas Chaudhary if (is_qla8022(ha) && !reset_chip && 2458f4f5df23SVikas Chaudhary test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags)) { 2459f4f5df23SVikas Chaudhary 2460f4f5df23SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, 2461f4f5df23SVikas Chaudhary "scsi%ld: %s - Performing stop_firmware...\n", 2462f4f5df23SVikas Chaudhary ha->host_no, __func__)); 2463f4f5df23SVikas Chaudhary status = ha->isp_ops->reset_firmware(ha); 2464f4f5df23SVikas Chaudhary if (status == QLA_SUCCESS) { 24652bd1e2beSNilesh Javali if (!test_bit(AF_FW_RECOVERY, &ha->flags)) 2466f4f5df23SVikas Chaudhary qla4xxx_cmd_wait(ha); 2467f4f5df23SVikas Chaudhary ha->isp_ops->disable_intrs(ha); 2468f4f5df23SVikas Chaudhary qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); 2469f4f5df23SVikas Chaudhary qla4xxx_abort_active_cmds(ha, DID_RESET << 16); 2470f4f5df23SVikas Chaudhary } else { 2471f4f5df23SVikas Chaudhary /* If the stop_firmware fails then 2472f4f5df23SVikas Chaudhary * reset the entire chip */ 2473f4f5df23SVikas Chaudhary reset_chip = 1; 2474f4f5df23SVikas Chaudhary clear_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags); 2475f4f5df23SVikas Chaudhary set_bit(DPC_RESET_HA, &ha->dpc_flags); 2476f4f5df23SVikas Chaudhary } 2477f4f5df23SVikas Chaudhary } 2478f4f5df23SVikas Chaudhary 2479f4f5df23SVikas Chaudhary /* Issue full chip reset if recovering from a catastrophic error, 2480f4f5df23SVikas Chaudhary * or if stop_firmware fails for ISP-82xx. 2481f4f5df23SVikas Chaudhary * This is the default case for ISP-4xxx */ 2482f4f5df23SVikas Chaudhary if (!is_qla8022(ha) || reset_chip) { 24839ee91a38SShyam Sunder if (!is_qla8022(ha)) 24849ee91a38SShyam Sunder goto chip_reset; 24859ee91a38SShyam Sunder 24869ee91a38SShyam Sunder /* Check if 82XX firmware is alive or not 24879ee91a38SShyam Sunder * We may have arrived here from NEED_RESET 24889ee91a38SShyam Sunder * detection only */ 24899ee91a38SShyam Sunder if (test_bit(AF_FW_RECOVERY, &ha->flags)) 24909ee91a38SShyam Sunder goto chip_reset; 24919ee91a38SShyam Sunder 24929ee91a38SShyam Sunder wait = jiffies + (FW_ALIVE_WAIT_TOV * HZ); 24939ee91a38SShyam Sunder while (time_before(jiffies, wait)) { 24949ee91a38SShyam Sunder if (qla4_8xxx_check_fw_alive(ha)) { 24959ee91a38SShyam Sunder qla4xxx_mailbox_premature_completion(ha); 24969ee91a38SShyam Sunder break; 24979ee91a38SShyam Sunder } 24989ee91a38SShyam Sunder 24999ee91a38SShyam Sunder set_current_state(TASK_UNINTERRUPTIBLE); 25009ee91a38SShyam Sunder schedule_timeout(HZ); 25019ee91a38SShyam Sunder } 25029ee91a38SShyam Sunder 25032bd1e2beSNilesh Javali if (!test_bit(AF_FW_RECOVERY, &ha->flags)) 2504f4f5df23SVikas Chaudhary qla4xxx_cmd_wait(ha); 25059ee91a38SShyam Sunder chip_reset: 2506f4f5df23SVikas Chaudhary qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); 2507f4f5df23SVikas Chaudhary qla4xxx_abort_active_cmds(ha, DID_RESET << 16); 2508f4f5df23SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, 2509f4f5df23SVikas Chaudhary "scsi%ld: %s - Performing chip reset..\n", 2510f4f5df23SVikas Chaudhary ha->host_no, __func__)); 2511f4f5df23SVikas Chaudhary status = ha->isp_ops->reset_chip(ha); 2512f4f5df23SVikas Chaudhary } 2513f4f5df23SVikas Chaudhary 2514f4f5df23SVikas Chaudhary /* Flush any pending ddb changed AENs */ 2515f4f5df23SVikas Chaudhary qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); 2516f4f5df23SVikas Chaudhary 2517f4f5df23SVikas Chaudhary recover_ha_init_adapter: 2518f4f5df23SVikas Chaudhary /* Upon successful firmware/chip reset, re-initialize the adapter */ 2519f4f5df23SVikas Chaudhary if (status == QLA_SUCCESS) { 2520f4f5df23SVikas Chaudhary /* For ISP-4xxx, force function 1 to always initialize 2521f4f5df23SVikas Chaudhary * before function 3 to prevent both funcions from 2522f4f5df23SVikas Chaudhary * stepping on top of the other */ 2523f4f5df23SVikas Chaudhary if (!is_qla8022(ha) && (ha->mac_index == 3)) 2524f4f5df23SVikas Chaudhary ssleep(6); 2525f4f5df23SVikas Chaudhary 2526f4f5df23SVikas Chaudhary /* NOTE: AF_ONLINE flag set upon successful completion of 2527f4f5df23SVikas Chaudhary * qla4xxx_initialize_adapter */ 252813483730SMike Christie status = qla4xxx_initialize_adapter(ha, RESET_ADAPTER); 2529f4f5df23SVikas Chaudhary } 2530f4f5df23SVikas Chaudhary 2531f4f5df23SVikas Chaudhary /* Retry failed adapter initialization, if necessary 2532f4f5df23SVikas Chaudhary * Do not retry initialize_adapter for RESET_HA_INTR (ISP-4xxx specific) 2533f4f5df23SVikas Chaudhary * case to prevent ping-pong resets between functions */ 2534f4f5df23SVikas Chaudhary if (!test_bit(AF_ONLINE, &ha->flags) && 2535f4f5df23SVikas Chaudhary !test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) { 2536afaf5a2dSDavid Somayajulu /* Adapter initialization failed, see if we can retry 2537f4f5df23SVikas Chaudhary * resetting the ha. 2538f4f5df23SVikas Chaudhary * Since we don't want to block the DPC for too long 2539f4f5df23SVikas Chaudhary * with multiple resets in the same thread, 2540f4f5df23SVikas Chaudhary * utilize DPC to retry */ 25418e0f3a66SSarang Radke if (is_qla8022(ha)) { 25428e0f3a66SSarang Radke qla4_8xxx_idc_lock(ha); 25438e0f3a66SSarang Radke dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE); 25448e0f3a66SSarang Radke qla4_8xxx_idc_unlock(ha); 25458e0f3a66SSarang Radke if (dev_state == QLA82XX_DEV_FAILED) { 25468e0f3a66SSarang Radke ql4_printk(KERN_INFO, ha, "%s: don't retry " 25478e0f3a66SSarang Radke "recover adapter. H/W is in Failed " 25488e0f3a66SSarang Radke "state\n", __func__); 25498e0f3a66SSarang Radke qla4xxx_dead_adapter_cleanup(ha); 25508e0f3a66SSarang Radke clear_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags); 25518e0f3a66SSarang Radke clear_bit(DPC_RESET_HA, &ha->dpc_flags); 25528e0f3a66SSarang Radke clear_bit(DPC_RESET_HA_FW_CONTEXT, 25538e0f3a66SSarang Radke &ha->dpc_flags); 25548e0f3a66SSarang Radke status = QLA_ERROR; 25558e0f3a66SSarang Radke 25568e0f3a66SSarang Radke goto exit_recover; 25578e0f3a66SSarang Radke } 25588e0f3a66SSarang Radke } 25598e0f3a66SSarang Radke 2560afaf5a2dSDavid Somayajulu if (!test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags)) { 2561afaf5a2dSDavid Somayajulu ha->retry_reset_ha_cnt = MAX_RESET_HA_RETRIES; 2562afaf5a2dSDavid Somayajulu DEBUG2(printk("scsi%ld: recover adapter - retrying " 2563afaf5a2dSDavid Somayajulu "(%d) more times\n", ha->host_no, 2564afaf5a2dSDavid Somayajulu ha->retry_reset_ha_cnt)); 2565afaf5a2dSDavid Somayajulu set_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags); 2566afaf5a2dSDavid Somayajulu status = QLA_ERROR; 2567afaf5a2dSDavid Somayajulu } else { 2568afaf5a2dSDavid Somayajulu if (ha->retry_reset_ha_cnt > 0) { 2569afaf5a2dSDavid Somayajulu /* Schedule another Reset HA--DPC will retry */ 2570afaf5a2dSDavid Somayajulu ha->retry_reset_ha_cnt--; 2571afaf5a2dSDavid Somayajulu DEBUG2(printk("scsi%ld: recover adapter - " 2572afaf5a2dSDavid Somayajulu "retry remaining %d\n", 2573afaf5a2dSDavid Somayajulu ha->host_no, 2574afaf5a2dSDavid Somayajulu ha->retry_reset_ha_cnt)); 2575afaf5a2dSDavid Somayajulu status = QLA_ERROR; 2576afaf5a2dSDavid Somayajulu } 2577afaf5a2dSDavid Somayajulu 2578afaf5a2dSDavid Somayajulu if (ha->retry_reset_ha_cnt == 0) { 2579afaf5a2dSDavid Somayajulu /* Recover adapter retries have been exhausted. 2580afaf5a2dSDavid Somayajulu * Adapter DEAD */ 2581afaf5a2dSDavid Somayajulu DEBUG2(printk("scsi%ld: recover adapter " 2582afaf5a2dSDavid Somayajulu "failed - board disabled\n", 2583afaf5a2dSDavid Somayajulu ha->host_no)); 2584f4f5df23SVikas Chaudhary qla4xxx_dead_adapter_cleanup(ha); 2585afaf5a2dSDavid Somayajulu clear_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags); 2586afaf5a2dSDavid Somayajulu clear_bit(DPC_RESET_HA, &ha->dpc_flags); 2587f4f5df23SVikas Chaudhary clear_bit(DPC_RESET_HA_FW_CONTEXT, 2588afaf5a2dSDavid Somayajulu &ha->dpc_flags); 2589afaf5a2dSDavid Somayajulu status = QLA_ERROR; 2590afaf5a2dSDavid Somayajulu } 2591afaf5a2dSDavid Somayajulu } 2592afaf5a2dSDavid Somayajulu } else { 2593afaf5a2dSDavid Somayajulu clear_bit(DPC_RESET_HA, &ha->dpc_flags); 2594f4f5df23SVikas Chaudhary clear_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags); 2595afaf5a2dSDavid Somayajulu clear_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags); 2596afaf5a2dSDavid Somayajulu } 2597afaf5a2dSDavid Somayajulu 25988e0f3a66SSarang Radke exit_recover: 2599afaf5a2dSDavid Somayajulu ha->adapter_error_count++; 2600afaf5a2dSDavid Somayajulu 2601f4f5df23SVikas Chaudhary if (test_bit(AF_ONLINE, &ha->flags)) 2602f4f5df23SVikas Chaudhary ha->isp_ops->enable_intrs(ha); 2603afaf5a2dSDavid Somayajulu 2604f4f5df23SVikas Chaudhary scsi_unblock_requests(ha->host); 2605f4f5df23SVikas Chaudhary 2606f4f5df23SVikas Chaudhary clear_bit(DPC_RESET_ACTIVE, &ha->dpc_flags); 2607f4f5df23SVikas Chaudhary DEBUG2(printk("scsi%ld: recover adapter: %s\n", ha->host_no, 260825985edcSLucas De Marchi status == QLA_ERROR ? "FAILED" : "SUCCEEDED")); 2609f4f5df23SVikas Chaudhary 2610afaf5a2dSDavid Somayajulu return status; 2611afaf5a2dSDavid Somayajulu } 2612afaf5a2dSDavid Somayajulu 2613b3a271a9SManish Rangankar static void qla4xxx_relogin_devices(struct iscsi_cls_session *cls_session) 2614b3a271a9SManish Rangankar { 2615b3a271a9SManish Rangankar struct iscsi_session *sess; 2616b3a271a9SManish Rangankar struct ddb_entry *ddb_entry; 2617b3a271a9SManish Rangankar struct scsi_qla_host *ha; 2618b3a271a9SManish Rangankar 2619b3a271a9SManish Rangankar sess = cls_session->dd_data; 2620b3a271a9SManish Rangankar ddb_entry = sess->dd_data; 2621b3a271a9SManish Rangankar ha = ddb_entry->ha; 2622b3a271a9SManish Rangankar if (!iscsi_is_session_online(cls_session)) { 2623b3a271a9SManish Rangankar if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) { 2624b3a271a9SManish Rangankar ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ddb[%d]" 2625b3a271a9SManish Rangankar " unblock session\n", ha->host_no, __func__, 2626b3a271a9SManish Rangankar ddb_entry->fw_ddb_index); 2627b3a271a9SManish Rangankar iscsi_unblock_session(ddb_entry->sess); 2628b3a271a9SManish Rangankar } else { 2629b3a271a9SManish Rangankar /* Trigger relogin */ 263013483730SMike Christie if (ddb_entry->ddb_type == FLASH_DDB) { 263113483730SMike Christie if (!test_bit(DF_RELOGIN, &ddb_entry->flags)) 263213483730SMike Christie qla4xxx_arm_relogin_timer(ddb_entry); 263313483730SMike Christie } else 2634b3a271a9SManish Rangankar iscsi_session_failure(cls_session->dd_data, 2635b3a271a9SManish Rangankar ISCSI_ERR_CONN_FAILED); 2636b3a271a9SManish Rangankar } 2637b3a271a9SManish Rangankar } 2638b3a271a9SManish Rangankar } 2639b3a271a9SManish Rangankar 264013483730SMike Christie int qla4xxx_unblock_flash_ddb(struct iscsi_cls_session *cls_session) 264113483730SMike Christie { 264213483730SMike Christie struct iscsi_session *sess; 264313483730SMike Christie struct ddb_entry *ddb_entry; 264413483730SMike Christie struct scsi_qla_host *ha; 264513483730SMike Christie 264613483730SMike Christie sess = cls_session->dd_data; 264713483730SMike Christie ddb_entry = sess->dd_data; 264813483730SMike Christie ha = ddb_entry->ha; 264913483730SMike Christie ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ddb[%d]" 265013483730SMike Christie " unblock session\n", ha->host_no, __func__, 265113483730SMike Christie ddb_entry->fw_ddb_index); 265213483730SMike Christie 265313483730SMike Christie iscsi_unblock_session(ddb_entry->sess); 265413483730SMike Christie 265513483730SMike Christie /* Start scan target */ 265613483730SMike Christie if (test_bit(AF_ONLINE, &ha->flags)) { 265713483730SMike Christie ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ddb[%d]" 265813483730SMike Christie " start scan\n", ha->host_no, __func__, 265913483730SMike Christie ddb_entry->fw_ddb_index); 266013483730SMike Christie scsi_queue_work(ha->host, &ddb_entry->sess->scan_work); 266113483730SMike Christie } 266213483730SMike Christie return QLA_SUCCESS; 266313483730SMike Christie } 266413483730SMike Christie 266513483730SMike Christie int qla4xxx_unblock_ddb(struct iscsi_cls_session *cls_session) 266613483730SMike Christie { 266713483730SMike Christie struct iscsi_session *sess; 266813483730SMike Christie struct ddb_entry *ddb_entry; 266913483730SMike Christie struct scsi_qla_host *ha; 267013483730SMike Christie 267113483730SMike Christie sess = cls_session->dd_data; 267213483730SMike Christie ddb_entry = sess->dd_data; 267313483730SMike Christie ha = ddb_entry->ha; 267413483730SMike Christie ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ddb[%d]" 267513483730SMike Christie " unblock user space session\n", ha->host_no, __func__, 267613483730SMike Christie ddb_entry->fw_ddb_index); 267713483730SMike Christie iscsi_conn_start(ddb_entry->conn); 267813483730SMike Christie iscsi_conn_login_event(ddb_entry->conn, 267913483730SMike Christie ISCSI_CONN_STATE_LOGGED_IN); 268013483730SMike Christie 268113483730SMike Christie return QLA_SUCCESS; 268213483730SMike Christie } 268313483730SMike Christie 26842d7924e6SVikas Chaudhary static void qla4xxx_relogin_all_devices(struct scsi_qla_host *ha) 26852d7924e6SVikas Chaudhary { 2686b3a271a9SManish Rangankar iscsi_host_for_each_session(ha->host, qla4xxx_relogin_devices); 26872d7924e6SVikas Chaudhary } 26882d7924e6SVikas Chaudhary 268913483730SMike Christie static void qla4xxx_relogin_flash_ddb(struct iscsi_cls_session *cls_sess) 269013483730SMike Christie { 269113483730SMike Christie uint16_t relogin_timer; 269213483730SMike Christie struct iscsi_session *sess; 269313483730SMike Christie struct ddb_entry *ddb_entry; 269413483730SMike Christie struct scsi_qla_host *ha; 269513483730SMike Christie 269613483730SMike Christie sess = cls_sess->dd_data; 269713483730SMike Christie ddb_entry = sess->dd_data; 269813483730SMike Christie ha = ddb_entry->ha; 269913483730SMike Christie 270013483730SMike Christie relogin_timer = max(ddb_entry->default_relogin_timeout, 270113483730SMike Christie (uint16_t)RELOGIN_TOV); 270213483730SMike Christie atomic_set(&ddb_entry->relogin_timer, relogin_timer); 270313483730SMike Christie 270413483730SMike Christie DEBUG2(ql4_printk(KERN_INFO, ha, 270513483730SMike Christie "scsi%ld: Relogin index [%d]. TOV=%d\n", ha->host_no, 270613483730SMike Christie ddb_entry->fw_ddb_index, relogin_timer)); 270713483730SMike Christie 270813483730SMike Christie qla4xxx_login_flash_ddb(cls_sess); 270913483730SMike Christie } 271013483730SMike Christie 271113483730SMike Christie static void qla4xxx_dpc_relogin(struct iscsi_cls_session *cls_sess) 271213483730SMike Christie { 271313483730SMike Christie struct iscsi_session *sess; 271413483730SMike Christie struct ddb_entry *ddb_entry; 271513483730SMike Christie struct scsi_qla_host *ha; 271613483730SMike Christie 271713483730SMike Christie sess = cls_sess->dd_data; 271813483730SMike Christie ddb_entry = sess->dd_data; 271913483730SMike Christie ha = ddb_entry->ha; 272013483730SMike Christie 272113483730SMike Christie if (!(ddb_entry->ddb_type == FLASH_DDB)) 272213483730SMike Christie return; 272313483730SMike Christie 272413483730SMike Christie if (test_and_clear_bit(DF_RELOGIN, &ddb_entry->flags) && 272513483730SMike Christie !iscsi_is_session_online(cls_sess)) { 272613483730SMike Christie DEBUG2(ql4_printk(KERN_INFO, ha, 272713483730SMike Christie "relogin issued\n")); 272813483730SMike Christie qla4xxx_relogin_flash_ddb(cls_sess); 272913483730SMike Christie } 273013483730SMike Christie } 273113483730SMike Christie 2732f4f5df23SVikas Chaudhary void qla4xxx_wake_dpc(struct scsi_qla_host *ha) 2733f4f5df23SVikas Chaudhary { 27341b46807eSLalit Chandivade if (ha->dpc_thread) 2735f4f5df23SVikas Chaudhary queue_work(ha->dpc_thread, &ha->dpc_work); 2736f4f5df23SVikas Chaudhary } 2737f4f5df23SVikas Chaudhary 2738afaf5a2dSDavid Somayajulu /** 2739afaf5a2dSDavid Somayajulu * qla4xxx_do_dpc - dpc routine 2740afaf5a2dSDavid Somayajulu * @data: in our case pointer to adapter structure 2741afaf5a2dSDavid Somayajulu * 2742afaf5a2dSDavid Somayajulu * This routine is a task that is schedule by the interrupt handler 2743afaf5a2dSDavid Somayajulu * to perform the background processing for interrupts. We put it 2744afaf5a2dSDavid Somayajulu * on a task queue that is consumed whenever the scheduler runs; that's 2745afaf5a2dSDavid Somayajulu * so you can do anything (i.e. put the process to sleep etc). In fact, 2746afaf5a2dSDavid Somayajulu * the mid-level tries to sleep when it reaches the driver threshold 2747afaf5a2dSDavid Somayajulu * "host->can_queue". This can cause a panic if we were in our interrupt code. 2748afaf5a2dSDavid Somayajulu **/ 2749c4028958SDavid Howells static void qla4xxx_do_dpc(struct work_struct *work) 2750afaf5a2dSDavid Somayajulu { 2751c4028958SDavid Howells struct scsi_qla_host *ha = 2752c4028958SDavid Howells container_of(work, struct scsi_qla_host, dpc_work); 2753477ffb9dSDavid C Somayajulu int status = QLA_ERROR; 2754afaf5a2dSDavid Somayajulu 2755f26b9044SDavid C Somayajulu DEBUG2(printk("scsi%ld: %s: DPC handler waking up." 2756f4f5df23SVikas Chaudhary "flags = 0x%08lx, dpc_flags = 0x%08lx\n", 2757f4f5df23SVikas Chaudhary ha->host_no, __func__, ha->flags, ha->dpc_flags)) 2758afaf5a2dSDavid Somayajulu 2759afaf5a2dSDavid Somayajulu /* Initialization not yet finished. Don't do anything yet. */ 2760afaf5a2dSDavid Somayajulu if (!test_bit(AF_INIT_DONE, &ha->flags)) 27611b46807eSLalit Chandivade return; 2762afaf5a2dSDavid Somayajulu 27632232be0dSLalit Chandivade if (test_bit(AF_EEH_BUSY, &ha->flags)) { 27642232be0dSLalit Chandivade DEBUG2(printk(KERN_INFO "scsi%ld: %s: flags = %lx\n", 27652232be0dSLalit Chandivade ha->host_no, __func__, ha->flags)); 27661b46807eSLalit Chandivade return; 27672232be0dSLalit Chandivade } 27682232be0dSLalit Chandivade 2769f4f5df23SVikas Chaudhary if (is_qla8022(ha)) { 2770f4f5df23SVikas Chaudhary if (test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags)) { 2771f4f5df23SVikas Chaudhary qla4_8xxx_idc_lock(ha); 2772f4f5df23SVikas Chaudhary qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, 2773f4f5df23SVikas Chaudhary QLA82XX_DEV_FAILED); 2774f4f5df23SVikas Chaudhary qla4_8xxx_idc_unlock(ha); 2775f4f5df23SVikas Chaudhary ql4_printk(KERN_INFO, ha, "HW State: FAILED\n"); 2776f4f5df23SVikas Chaudhary qla4_8xxx_device_state_handler(ha); 2777f4f5df23SVikas Chaudhary } 2778f4f5df23SVikas Chaudhary if (test_and_clear_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags)) { 2779f4f5df23SVikas Chaudhary qla4_8xxx_need_qsnt_handler(ha); 2780f4f5df23SVikas Chaudhary } 2781f4f5df23SVikas Chaudhary } 2782f4f5df23SVikas Chaudhary 2783f4f5df23SVikas Chaudhary if (!test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags) && 2784f4f5df23SVikas Chaudhary (test_bit(DPC_RESET_HA, &ha->dpc_flags) || 2785afaf5a2dSDavid Somayajulu test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) || 2786f4f5df23SVikas Chaudhary test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags))) { 2787f4f5df23SVikas Chaudhary if (ql4xdontresethba) { 2788f4f5df23SVikas Chaudhary DEBUG2(printk("scsi%ld: %s: Don't Reset HBA\n", 2789f4f5df23SVikas Chaudhary ha->host_no, __func__)); 2790f4f5df23SVikas Chaudhary clear_bit(DPC_RESET_HA, &ha->dpc_flags); 2791f4f5df23SVikas Chaudhary clear_bit(DPC_RESET_HA_INTR, &ha->dpc_flags); 2792f4f5df23SVikas Chaudhary clear_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags); 2793f4f5df23SVikas Chaudhary goto dpc_post_reset_ha; 2794f4f5df23SVikas Chaudhary } 2795f4f5df23SVikas Chaudhary if (test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags) || 2796f26b9044SDavid C Somayajulu test_bit(DPC_RESET_HA, &ha->dpc_flags)) 2797f4f5df23SVikas Chaudhary qla4xxx_recover_adapter(ha); 2798afaf5a2dSDavid Somayajulu 2799477ffb9dSDavid C Somayajulu if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) { 2800afaf5a2dSDavid Somayajulu uint8_t wait_time = RESET_INTR_TOV; 2801afaf5a2dSDavid Somayajulu 2802afaf5a2dSDavid Somayajulu while ((readw(&ha->reg->ctrl_status) & 2803afaf5a2dSDavid Somayajulu (CSR_SOFT_RESET | CSR_FORCE_SOFT_RESET)) != 0) { 2804afaf5a2dSDavid Somayajulu if (--wait_time == 0) 2805afaf5a2dSDavid Somayajulu break; 2806afaf5a2dSDavid Somayajulu msleep(1000); 2807afaf5a2dSDavid Somayajulu } 2808afaf5a2dSDavid Somayajulu if (wait_time == 0) 2809afaf5a2dSDavid Somayajulu DEBUG2(printk("scsi%ld: %s: SR|FSR " 2810afaf5a2dSDavid Somayajulu "bit not cleared-- resetting\n", 2811afaf5a2dSDavid Somayajulu ha->host_no, __func__)); 2812f4f5df23SVikas Chaudhary qla4xxx_abort_active_cmds(ha, DID_RESET << 16); 2813477ffb9dSDavid C Somayajulu if (ql4xxx_lock_drvr_wait(ha) == QLA_SUCCESS) { 2814477ffb9dSDavid C Somayajulu qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); 2815f4f5df23SVikas Chaudhary status = qla4xxx_recover_adapter(ha); 2816477ffb9dSDavid C Somayajulu } 2817477ffb9dSDavid C Somayajulu clear_bit(DPC_RESET_HA_INTR, &ha->dpc_flags); 2818477ffb9dSDavid C Somayajulu if (status == QLA_SUCCESS) 2819f4f5df23SVikas Chaudhary ha->isp_ops->enable_intrs(ha); 2820afaf5a2dSDavid Somayajulu } 2821afaf5a2dSDavid Somayajulu } 2822afaf5a2dSDavid Somayajulu 2823f4f5df23SVikas Chaudhary dpc_post_reset_ha: 2824afaf5a2dSDavid Somayajulu /* ---- process AEN? --- */ 2825afaf5a2dSDavid Somayajulu if (test_and_clear_bit(DPC_AEN, &ha->dpc_flags)) 2826afaf5a2dSDavid Somayajulu qla4xxx_process_aen(ha, PROCESS_ALL_AENS); 2827afaf5a2dSDavid Somayajulu 2828afaf5a2dSDavid Somayajulu /* ---- Get DHCP IP Address? --- */ 2829afaf5a2dSDavid Somayajulu if (test_and_clear_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags)) 2830afaf5a2dSDavid Somayajulu qla4xxx_get_dhcp_ip_address(ha); 2831afaf5a2dSDavid Somayajulu 283213483730SMike Christie /* ---- relogin device? --- */ 283313483730SMike Christie if (adapter_up(ha) && 283413483730SMike Christie test_and_clear_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags)) { 283513483730SMike Christie iscsi_host_for_each_session(ha->host, qla4xxx_dpc_relogin); 283613483730SMike Christie } 283713483730SMike Christie 2838065aa1b4SVikas Chaudhary /* ---- link change? --- */ 2839065aa1b4SVikas Chaudhary if (test_and_clear_bit(DPC_LINK_CHANGED, &ha->dpc_flags)) { 2840065aa1b4SVikas Chaudhary if (!test_bit(AF_LINK_UP, &ha->flags)) { 2841065aa1b4SVikas Chaudhary /* ---- link down? --- */ 28422d7924e6SVikas Chaudhary qla4xxx_mark_all_devices_missing(ha); 2843065aa1b4SVikas Chaudhary } else { 2844065aa1b4SVikas Chaudhary /* ---- link up? --- * 2845065aa1b4SVikas Chaudhary * F/W will auto login to all devices ONLY ONCE after 2846065aa1b4SVikas Chaudhary * link up during driver initialization and runtime 2847065aa1b4SVikas Chaudhary * fatal error recovery. Therefore, the driver must 2848065aa1b4SVikas Chaudhary * manually relogin to devices when recovering from 2849065aa1b4SVikas Chaudhary * connection failures, logouts, expired KATO, etc. */ 285013483730SMike Christie if (test_and_clear_bit(AF_BUILD_DDB_LIST, &ha->flags)) { 285113483730SMike Christie qla4xxx_build_ddb_list(ha, ha->is_reset); 285213483730SMike Christie iscsi_host_for_each_session(ha->host, 285313483730SMike Christie qla4xxx_login_flash_ddb); 285413483730SMike Christie } else 28552d7924e6SVikas Chaudhary qla4xxx_relogin_all_devices(ha); 2856065aa1b4SVikas Chaudhary } 2857065aa1b4SVikas Chaudhary } 2858afaf5a2dSDavid Somayajulu } 2859afaf5a2dSDavid Somayajulu 2860afaf5a2dSDavid Somayajulu /** 2861afaf5a2dSDavid Somayajulu * qla4xxx_free_adapter - release the adapter 2862afaf5a2dSDavid Somayajulu * @ha: pointer to adapter structure 2863afaf5a2dSDavid Somayajulu **/ 2864afaf5a2dSDavid Somayajulu static void qla4xxx_free_adapter(struct scsi_qla_host *ha) 2865afaf5a2dSDavid Somayajulu { 28668a288960SSarang Radke qla4xxx_abort_active_cmds(ha, DID_NO_CONNECT << 16); 2867afaf5a2dSDavid Somayajulu 2868afaf5a2dSDavid Somayajulu if (test_bit(AF_INTERRUPTS_ON, &ha->flags)) { 2869afaf5a2dSDavid Somayajulu /* Turn-off interrupts on the card. */ 2870f4f5df23SVikas Chaudhary ha->isp_ops->disable_intrs(ha); 2871afaf5a2dSDavid Somayajulu } 2872afaf5a2dSDavid Somayajulu 2873afaf5a2dSDavid Somayajulu /* Remove timer thread, if present */ 2874afaf5a2dSDavid Somayajulu if (ha->timer_active) 2875afaf5a2dSDavid Somayajulu qla4xxx_stop_timer(ha); 2876afaf5a2dSDavid Somayajulu 2877f4f5df23SVikas Chaudhary /* Kill the kernel thread for this host */ 2878f4f5df23SVikas Chaudhary if (ha->dpc_thread) 2879f4f5df23SVikas Chaudhary destroy_workqueue(ha->dpc_thread); 2880f4f5df23SVikas Chaudhary 2881b3a271a9SManish Rangankar /* Kill the kernel thread for this host */ 2882b3a271a9SManish Rangankar if (ha->task_wq) 2883b3a271a9SManish Rangankar destroy_workqueue(ha->task_wq); 2884b3a271a9SManish Rangankar 2885f4f5df23SVikas Chaudhary /* Put firmware in known state */ 2886f4f5df23SVikas Chaudhary ha->isp_ops->reset_firmware(ha); 2887f4f5df23SVikas Chaudhary 2888f4f5df23SVikas Chaudhary if (is_qla8022(ha)) { 2889f4f5df23SVikas Chaudhary qla4_8xxx_idc_lock(ha); 2890f4f5df23SVikas Chaudhary qla4_8xxx_clear_drv_active(ha); 2891f4f5df23SVikas Chaudhary qla4_8xxx_idc_unlock(ha); 2892f4f5df23SVikas Chaudhary } 2893f4f5df23SVikas Chaudhary 2894afaf5a2dSDavid Somayajulu /* Detach interrupts */ 2895afaf5a2dSDavid Somayajulu if (test_and_clear_bit(AF_IRQ_ATTACHED, &ha->flags)) 2896f4f5df23SVikas Chaudhary qla4xxx_free_irqs(ha); 2897afaf5a2dSDavid Somayajulu 2898bee4fe8eSDavid C Somayajulu /* free extra memory */ 2899bee4fe8eSDavid C Somayajulu qla4xxx_mem_free(ha); 2900f4f5df23SVikas Chaudhary } 2901bee4fe8eSDavid C Somayajulu 2902f4f5df23SVikas Chaudhary int qla4_8xxx_iospace_config(struct scsi_qla_host *ha) 2903f4f5df23SVikas Chaudhary { 2904f4f5df23SVikas Chaudhary int status = 0; 2905f4f5df23SVikas Chaudhary uint8_t revision_id; 2906f4f5df23SVikas Chaudhary unsigned long mem_base, mem_len, db_base, db_len; 2907f4f5df23SVikas Chaudhary struct pci_dev *pdev = ha->pdev; 2908afaf5a2dSDavid Somayajulu 2909f4f5df23SVikas Chaudhary status = pci_request_regions(pdev, DRIVER_NAME); 2910f4f5df23SVikas Chaudhary if (status) { 2911f4f5df23SVikas Chaudhary printk(KERN_WARNING 2912f4f5df23SVikas Chaudhary "scsi(%ld) Failed to reserve PIO regions (%s) " 2913f4f5df23SVikas Chaudhary "status=%d\n", ha->host_no, pci_name(pdev), status); 2914f4f5df23SVikas Chaudhary goto iospace_error_exit; 2915f4f5df23SVikas Chaudhary } 2916f4f5df23SVikas Chaudhary 2917f4f5df23SVikas Chaudhary pci_read_config_byte(pdev, PCI_REVISION_ID, &revision_id); 2918f4f5df23SVikas Chaudhary DEBUG2(printk(KERN_INFO "%s: revision-id=%d\n", 2919f4f5df23SVikas Chaudhary __func__, revision_id)); 2920f4f5df23SVikas Chaudhary ha->revision_id = revision_id; 2921f4f5df23SVikas Chaudhary 2922f4f5df23SVikas Chaudhary /* remap phys address */ 2923f4f5df23SVikas Chaudhary mem_base = pci_resource_start(pdev, 0); /* 0 is for BAR 0 */ 2924f4f5df23SVikas Chaudhary mem_len = pci_resource_len(pdev, 0); 2925f4f5df23SVikas Chaudhary DEBUG2(printk(KERN_INFO "%s: ioremap from %lx a size of %lx\n", 2926f4f5df23SVikas Chaudhary __func__, mem_base, mem_len)); 2927f4f5df23SVikas Chaudhary 2928f4f5df23SVikas Chaudhary /* mapping of pcibase pointer */ 2929f4f5df23SVikas Chaudhary ha->nx_pcibase = (unsigned long)ioremap(mem_base, mem_len); 2930f4f5df23SVikas Chaudhary if (!ha->nx_pcibase) { 2931f4f5df23SVikas Chaudhary printk(KERN_ERR 2932f4f5df23SVikas Chaudhary "cannot remap MMIO (%s), aborting\n", pci_name(pdev)); 2933f4f5df23SVikas Chaudhary pci_release_regions(ha->pdev); 2934f4f5df23SVikas Chaudhary goto iospace_error_exit; 2935f4f5df23SVikas Chaudhary } 2936f4f5df23SVikas Chaudhary 2937f4f5df23SVikas Chaudhary /* Mapping of IO base pointer, door bell read and write pointer */ 2938f4f5df23SVikas Chaudhary 2939f4f5df23SVikas Chaudhary /* mapping of IO base pointer */ 2940f4f5df23SVikas Chaudhary ha->qla4_8xxx_reg = 2941f4f5df23SVikas Chaudhary (struct device_reg_82xx __iomem *)((uint8_t *)ha->nx_pcibase + 2942f4f5df23SVikas Chaudhary 0xbc000 + (ha->pdev->devfn << 11)); 2943f4f5df23SVikas Chaudhary 2944f4f5df23SVikas Chaudhary db_base = pci_resource_start(pdev, 4); /* doorbell is on bar 4 */ 2945f4f5df23SVikas Chaudhary db_len = pci_resource_len(pdev, 4); 2946f4f5df23SVikas Chaudhary 29472657c800SShyam Sundar ha->nx_db_wr_ptr = (ha->pdev->devfn == 4 ? QLA82XX_CAM_RAM_DB1 : 29482657c800SShyam Sundar QLA82XX_CAM_RAM_DB2); 2949f4f5df23SVikas Chaudhary 29502657c800SShyam Sundar return 0; 2951f4f5df23SVikas Chaudhary iospace_error_exit: 2952f4f5df23SVikas Chaudhary return -ENOMEM; 2953afaf5a2dSDavid Somayajulu } 2954afaf5a2dSDavid Somayajulu 2955afaf5a2dSDavid Somayajulu /*** 2956afaf5a2dSDavid Somayajulu * qla4xxx_iospace_config - maps registers 2957afaf5a2dSDavid Somayajulu * @ha: pointer to adapter structure 2958afaf5a2dSDavid Somayajulu * 2959afaf5a2dSDavid Somayajulu * This routines maps HBA's registers from the pci address space 2960afaf5a2dSDavid Somayajulu * into the kernel virtual address space for memory mapped i/o. 2961afaf5a2dSDavid Somayajulu **/ 2962f4f5df23SVikas Chaudhary int qla4xxx_iospace_config(struct scsi_qla_host *ha) 2963afaf5a2dSDavid Somayajulu { 2964afaf5a2dSDavid Somayajulu unsigned long pio, pio_len, pio_flags; 2965afaf5a2dSDavid Somayajulu unsigned long mmio, mmio_len, mmio_flags; 2966afaf5a2dSDavid Somayajulu 2967afaf5a2dSDavid Somayajulu pio = pci_resource_start(ha->pdev, 0); 2968afaf5a2dSDavid Somayajulu pio_len = pci_resource_len(ha->pdev, 0); 2969afaf5a2dSDavid Somayajulu pio_flags = pci_resource_flags(ha->pdev, 0); 2970afaf5a2dSDavid Somayajulu if (pio_flags & IORESOURCE_IO) { 2971afaf5a2dSDavid Somayajulu if (pio_len < MIN_IOBASE_LEN) { 2972c2660df3SVikas Chaudhary ql4_printk(KERN_WARNING, ha, 2973afaf5a2dSDavid Somayajulu "Invalid PCI I/O region size\n"); 2974afaf5a2dSDavid Somayajulu pio = 0; 2975afaf5a2dSDavid Somayajulu } 2976afaf5a2dSDavid Somayajulu } else { 2977c2660df3SVikas Chaudhary ql4_printk(KERN_WARNING, ha, "region #0 not a PIO resource\n"); 2978afaf5a2dSDavid Somayajulu pio = 0; 2979afaf5a2dSDavid Somayajulu } 2980afaf5a2dSDavid Somayajulu 2981afaf5a2dSDavid Somayajulu /* Use MMIO operations for all accesses. */ 2982afaf5a2dSDavid Somayajulu mmio = pci_resource_start(ha->pdev, 1); 2983afaf5a2dSDavid Somayajulu mmio_len = pci_resource_len(ha->pdev, 1); 2984afaf5a2dSDavid Somayajulu mmio_flags = pci_resource_flags(ha->pdev, 1); 2985afaf5a2dSDavid Somayajulu 2986afaf5a2dSDavid Somayajulu if (!(mmio_flags & IORESOURCE_MEM)) { 2987c2660df3SVikas Chaudhary ql4_printk(KERN_ERR, ha, 2988afaf5a2dSDavid Somayajulu "region #0 not an MMIO resource, aborting\n"); 2989afaf5a2dSDavid Somayajulu 2990afaf5a2dSDavid Somayajulu goto iospace_error_exit; 2991afaf5a2dSDavid Somayajulu } 2992c2660df3SVikas Chaudhary 2993afaf5a2dSDavid Somayajulu if (mmio_len < MIN_IOBASE_LEN) { 2994c2660df3SVikas Chaudhary ql4_printk(KERN_ERR, ha, 2995afaf5a2dSDavid Somayajulu "Invalid PCI mem region size, aborting\n"); 2996afaf5a2dSDavid Somayajulu goto iospace_error_exit; 2997afaf5a2dSDavid Somayajulu } 2998afaf5a2dSDavid Somayajulu 2999afaf5a2dSDavid Somayajulu if (pci_request_regions(ha->pdev, DRIVER_NAME)) { 3000c2660df3SVikas Chaudhary ql4_printk(KERN_WARNING, ha, 3001afaf5a2dSDavid Somayajulu "Failed to reserve PIO/MMIO regions\n"); 3002afaf5a2dSDavid Somayajulu 3003afaf5a2dSDavid Somayajulu goto iospace_error_exit; 3004afaf5a2dSDavid Somayajulu } 3005afaf5a2dSDavid Somayajulu 3006afaf5a2dSDavid Somayajulu ha->pio_address = pio; 3007afaf5a2dSDavid Somayajulu ha->pio_length = pio_len; 3008afaf5a2dSDavid Somayajulu ha->reg = ioremap(mmio, MIN_IOBASE_LEN); 3009afaf5a2dSDavid Somayajulu if (!ha->reg) { 3010c2660df3SVikas Chaudhary ql4_printk(KERN_ERR, ha, 3011afaf5a2dSDavid Somayajulu "cannot remap MMIO, aborting\n"); 3012afaf5a2dSDavid Somayajulu 3013afaf5a2dSDavid Somayajulu goto iospace_error_exit; 3014afaf5a2dSDavid Somayajulu } 3015afaf5a2dSDavid Somayajulu 3016afaf5a2dSDavid Somayajulu return 0; 3017afaf5a2dSDavid Somayajulu 3018afaf5a2dSDavid Somayajulu iospace_error_exit: 3019afaf5a2dSDavid Somayajulu return -ENOMEM; 3020afaf5a2dSDavid Somayajulu } 3021afaf5a2dSDavid Somayajulu 3022f4f5df23SVikas Chaudhary static struct isp_operations qla4xxx_isp_ops = { 3023f4f5df23SVikas Chaudhary .iospace_config = qla4xxx_iospace_config, 3024f4f5df23SVikas Chaudhary .pci_config = qla4xxx_pci_config, 3025f4f5df23SVikas Chaudhary .disable_intrs = qla4xxx_disable_intrs, 3026f4f5df23SVikas Chaudhary .enable_intrs = qla4xxx_enable_intrs, 3027f4f5df23SVikas Chaudhary .start_firmware = qla4xxx_start_firmware, 3028f4f5df23SVikas Chaudhary .intr_handler = qla4xxx_intr_handler, 3029f4f5df23SVikas Chaudhary .interrupt_service_routine = qla4xxx_interrupt_service_routine, 3030f4f5df23SVikas Chaudhary .reset_chip = qla4xxx_soft_reset, 3031f4f5df23SVikas Chaudhary .reset_firmware = qla4xxx_hw_reset, 3032f4f5df23SVikas Chaudhary .queue_iocb = qla4xxx_queue_iocb, 3033f4f5df23SVikas Chaudhary .complete_iocb = qla4xxx_complete_iocb, 3034f4f5df23SVikas Chaudhary .rd_shdw_req_q_out = qla4xxx_rd_shdw_req_q_out, 3035f4f5df23SVikas Chaudhary .rd_shdw_rsp_q_in = qla4xxx_rd_shdw_rsp_q_in, 3036f4f5df23SVikas Chaudhary .get_sys_info = qla4xxx_get_sys_info, 3037f4f5df23SVikas Chaudhary }; 3038f4f5df23SVikas Chaudhary 3039f4f5df23SVikas Chaudhary static struct isp_operations qla4_8xxx_isp_ops = { 3040f4f5df23SVikas Chaudhary .iospace_config = qla4_8xxx_iospace_config, 3041f4f5df23SVikas Chaudhary .pci_config = qla4_8xxx_pci_config, 3042f4f5df23SVikas Chaudhary .disable_intrs = qla4_8xxx_disable_intrs, 3043f4f5df23SVikas Chaudhary .enable_intrs = qla4_8xxx_enable_intrs, 3044f4f5df23SVikas Chaudhary .start_firmware = qla4_8xxx_load_risc, 3045f4f5df23SVikas Chaudhary .intr_handler = qla4_8xxx_intr_handler, 3046f4f5df23SVikas Chaudhary .interrupt_service_routine = qla4_8xxx_interrupt_service_routine, 3047f4f5df23SVikas Chaudhary .reset_chip = qla4_8xxx_isp_reset, 3048f4f5df23SVikas Chaudhary .reset_firmware = qla4_8xxx_stop_firmware, 3049f4f5df23SVikas Chaudhary .queue_iocb = qla4_8xxx_queue_iocb, 3050f4f5df23SVikas Chaudhary .complete_iocb = qla4_8xxx_complete_iocb, 3051f4f5df23SVikas Chaudhary .rd_shdw_req_q_out = qla4_8xxx_rd_shdw_req_q_out, 3052f4f5df23SVikas Chaudhary .rd_shdw_rsp_q_in = qla4_8xxx_rd_shdw_rsp_q_in, 3053f4f5df23SVikas Chaudhary .get_sys_info = qla4_8xxx_get_sys_info, 3054f4f5df23SVikas Chaudhary }; 3055f4f5df23SVikas Chaudhary 3056f4f5df23SVikas Chaudhary uint16_t qla4xxx_rd_shdw_req_q_out(struct scsi_qla_host *ha) 3057f4f5df23SVikas Chaudhary { 3058f4f5df23SVikas Chaudhary return (uint16_t)le32_to_cpu(ha->shadow_regs->req_q_out); 3059f4f5df23SVikas Chaudhary } 3060f4f5df23SVikas Chaudhary 3061f4f5df23SVikas Chaudhary uint16_t qla4_8xxx_rd_shdw_req_q_out(struct scsi_qla_host *ha) 3062f4f5df23SVikas Chaudhary { 3063f4f5df23SVikas Chaudhary return (uint16_t)le32_to_cpu(readl(&ha->qla4_8xxx_reg->req_q_out)); 3064f4f5df23SVikas Chaudhary } 3065f4f5df23SVikas Chaudhary 3066f4f5df23SVikas Chaudhary uint16_t qla4xxx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha) 3067f4f5df23SVikas Chaudhary { 3068f4f5df23SVikas Chaudhary return (uint16_t)le32_to_cpu(ha->shadow_regs->rsp_q_in); 3069f4f5df23SVikas Chaudhary } 3070f4f5df23SVikas Chaudhary 3071f4f5df23SVikas Chaudhary uint16_t qla4_8xxx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha) 3072f4f5df23SVikas Chaudhary { 3073f4f5df23SVikas Chaudhary return (uint16_t)le32_to_cpu(readl(&ha->qla4_8xxx_reg->rsp_q_in)); 3074f4f5df23SVikas Chaudhary } 3075f4f5df23SVikas Chaudhary 30762a991c21SManish Rangankar static ssize_t qla4xxx_show_boot_eth_info(void *data, int type, char *buf) 30772a991c21SManish Rangankar { 30782a991c21SManish Rangankar struct scsi_qla_host *ha = data; 30792a991c21SManish Rangankar char *str = buf; 30802a991c21SManish Rangankar int rc; 30812a991c21SManish Rangankar 30822a991c21SManish Rangankar switch (type) { 30832a991c21SManish Rangankar case ISCSI_BOOT_ETH_FLAGS: 30842a991c21SManish Rangankar rc = sprintf(str, "%d\n", SYSFS_FLAG_FW_SEL_BOOT); 30852a991c21SManish Rangankar break; 30862a991c21SManish Rangankar case ISCSI_BOOT_ETH_INDEX: 30872a991c21SManish Rangankar rc = sprintf(str, "0\n"); 30882a991c21SManish Rangankar break; 30892a991c21SManish Rangankar case ISCSI_BOOT_ETH_MAC: 30902a991c21SManish Rangankar rc = sysfs_format_mac(str, ha->my_mac, 30912a991c21SManish Rangankar MAC_ADDR_LEN); 30922a991c21SManish Rangankar break; 30932a991c21SManish Rangankar default: 30942a991c21SManish Rangankar rc = -ENOSYS; 30952a991c21SManish Rangankar break; 30962a991c21SManish Rangankar } 30972a991c21SManish Rangankar return rc; 30982a991c21SManish Rangankar } 30992a991c21SManish Rangankar 3100587a1f16SAl Viro static umode_t qla4xxx_eth_get_attr_visibility(void *data, int type) 31012a991c21SManish Rangankar { 31022a991c21SManish Rangankar int rc; 31032a991c21SManish Rangankar 31042a991c21SManish Rangankar switch (type) { 31052a991c21SManish Rangankar case ISCSI_BOOT_ETH_FLAGS: 31062a991c21SManish Rangankar case ISCSI_BOOT_ETH_MAC: 31072a991c21SManish Rangankar case ISCSI_BOOT_ETH_INDEX: 31082a991c21SManish Rangankar rc = S_IRUGO; 31092a991c21SManish Rangankar break; 31102a991c21SManish Rangankar default: 31112a991c21SManish Rangankar rc = 0; 31122a991c21SManish Rangankar break; 31132a991c21SManish Rangankar } 31142a991c21SManish Rangankar return rc; 31152a991c21SManish Rangankar } 31162a991c21SManish Rangankar 31172a991c21SManish Rangankar static ssize_t qla4xxx_show_boot_ini_info(void *data, int type, char *buf) 31182a991c21SManish Rangankar { 31192a991c21SManish Rangankar struct scsi_qla_host *ha = data; 31202a991c21SManish Rangankar char *str = buf; 31212a991c21SManish Rangankar int rc; 31222a991c21SManish Rangankar 31232a991c21SManish Rangankar switch (type) { 31242a991c21SManish Rangankar case ISCSI_BOOT_INI_INITIATOR_NAME: 31252a991c21SManish Rangankar rc = sprintf(str, "%s\n", ha->name_string); 31262a991c21SManish Rangankar break; 31272a991c21SManish Rangankar default: 31282a991c21SManish Rangankar rc = -ENOSYS; 31292a991c21SManish Rangankar break; 31302a991c21SManish Rangankar } 31312a991c21SManish Rangankar return rc; 31322a991c21SManish Rangankar } 31332a991c21SManish Rangankar 3134587a1f16SAl Viro static umode_t qla4xxx_ini_get_attr_visibility(void *data, int type) 31352a991c21SManish Rangankar { 31362a991c21SManish Rangankar int rc; 31372a991c21SManish Rangankar 31382a991c21SManish Rangankar switch (type) { 31392a991c21SManish Rangankar case ISCSI_BOOT_INI_INITIATOR_NAME: 31402a991c21SManish Rangankar rc = S_IRUGO; 31412a991c21SManish Rangankar break; 31422a991c21SManish Rangankar default: 31432a991c21SManish Rangankar rc = 0; 31442a991c21SManish Rangankar break; 31452a991c21SManish Rangankar } 31462a991c21SManish Rangankar return rc; 31472a991c21SManish Rangankar } 31482a991c21SManish Rangankar 31492a991c21SManish Rangankar static ssize_t 31502a991c21SManish Rangankar qla4xxx_show_boot_tgt_info(struct ql4_boot_session_info *boot_sess, int type, 31512a991c21SManish Rangankar char *buf) 31522a991c21SManish Rangankar { 31532a991c21SManish Rangankar struct ql4_conn_info *boot_conn = &boot_sess->conn_list[0]; 31542a991c21SManish Rangankar char *str = buf; 31552a991c21SManish Rangankar int rc; 31562a991c21SManish Rangankar 31572a991c21SManish Rangankar switch (type) { 31582a991c21SManish Rangankar case ISCSI_BOOT_TGT_NAME: 31592a991c21SManish Rangankar rc = sprintf(buf, "%s\n", (char *)&boot_sess->target_name); 31602a991c21SManish Rangankar break; 31612a991c21SManish Rangankar case ISCSI_BOOT_TGT_IP_ADDR: 31622a991c21SManish Rangankar if (boot_sess->conn_list[0].dest_ipaddr.ip_type == 0x1) 31632a991c21SManish Rangankar rc = sprintf(buf, "%pI4\n", 31642a991c21SManish Rangankar &boot_conn->dest_ipaddr.ip_address); 31652a991c21SManish Rangankar else 31662a991c21SManish Rangankar rc = sprintf(str, "%pI6\n", 31672a991c21SManish Rangankar &boot_conn->dest_ipaddr.ip_address); 31682a991c21SManish Rangankar break; 31692a991c21SManish Rangankar case ISCSI_BOOT_TGT_PORT: 31702a991c21SManish Rangankar rc = sprintf(str, "%d\n", boot_conn->dest_port); 31712a991c21SManish Rangankar break; 31722a991c21SManish Rangankar case ISCSI_BOOT_TGT_CHAP_NAME: 31732a991c21SManish Rangankar rc = sprintf(str, "%.*s\n", 31742a991c21SManish Rangankar boot_conn->chap.target_chap_name_length, 31752a991c21SManish Rangankar (char *)&boot_conn->chap.target_chap_name); 31762a991c21SManish Rangankar break; 31772a991c21SManish Rangankar case ISCSI_BOOT_TGT_CHAP_SECRET: 31782a991c21SManish Rangankar rc = sprintf(str, "%.*s\n", 31792a991c21SManish Rangankar boot_conn->chap.target_secret_length, 31802a991c21SManish Rangankar (char *)&boot_conn->chap.target_secret); 31812a991c21SManish Rangankar break; 31822a991c21SManish Rangankar case ISCSI_BOOT_TGT_REV_CHAP_NAME: 31832a991c21SManish Rangankar rc = sprintf(str, "%.*s\n", 31842a991c21SManish Rangankar boot_conn->chap.intr_chap_name_length, 31852a991c21SManish Rangankar (char *)&boot_conn->chap.intr_chap_name); 31862a991c21SManish Rangankar break; 31872a991c21SManish Rangankar case ISCSI_BOOT_TGT_REV_CHAP_SECRET: 31882a991c21SManish Rangankar rc = sprintf(str, "%.*s\n", 31892a991c21SManish Rangankar boot_conn->chap.intr_secret_length, 31902a991c21SManish Rangankar (char *)&boot_conn->chap.intr_secret); 31912a991c21SManish Rangankar break; 31922a991c21SManish Rangankar case ISCSI_BOOT_TGT_FLAGS: 31932a991c21SManish Rangankar rc = sprintf(str, "%d\n", SYSFS_FLAG_FW_SEL_BOOT); 31942a991c21SManish Rangankar break; 31952a991c21SManish Rangankar case ISCSI_BOOT_TGT_NIC_ASSOC: 31962a991c21SManish Rangankar rc = sprintf(str, "0\n"); 31972a991c21SManish Rangankar break; 31982a991c21SManish Rangankar default: 31992a991c21SManish Rangankar rc = -ENOSYS; 32002a991c21SManish Rangankar break; 32012a991c21SManish Rangankar } 32022a991c21SManish Rangankar return rc; 32032a991c21SManish Rangankar } 32042a991c21SManish Rangankar 32052a991c21SManish Rangankar static ssize_t qla4xxx_show_boot_tgt_pri_info(void *data, int type, char *buf) 32062a991c21SManish Rangankar { 32072a991c21SManish Rangankar struct scsi_qla_host *ha = data; 32082a991c21SManish Rangankar struct ql4_boot_session_info *boot_sess = &(ha->boot_tgt.boot_pri_sess); 32092a991c21SManish Rangankar 32102a991c21SManish Rangankar return qla4xxx_show_boot_tgt_info(boot_sess, type, buf); 32112a991c21SManish Rangankar } 32122a991c21SManish Rangankar 32132a991c21SManish Rangankar static ssize_t qla4xxx_show_boot_tgt_sec_info(void *data, int type, char *buf) 32142a991c21SManish Rangankar { 32152a991c21SManish Rangankar struct scsi_qla_host *ha = data; 32162a991c21SManish Rangankar struct ql4_boot_session_info *boot_sess = &(ha->boot_tgt.boot_sec_sess); 32172a991c21SManish Rangankar 32182a991c21SManish Rangankar return qla4xxx_show_boot_tgt_info(boot_sess, type, buf); 32192a991c21SManish Rangankar } 32202a991c21SManish Rangankar 3221587a1f16SAl Viro static umode_t qla4xxx_tgt_get_attr_visibility(void *data, int type) 32222a991c21SManish Rangankar { 32232a991c21SManish Rangankar int rc; 32242a991c21SManish Rangankar 32252a991c21SManish Rangankar switch (type) { 32262a991c21SManish Rangankar case ISCSI_BOOT_TGT_NAME: 32272a991c21SManish Rangankar case ISCSI_BOOT_TGT_IP_ADDR: 32282a991c21SManish Rangankar case ISCSI_BOOT_TGT_PORT: 32292a991c21SManish Rangankar case ISCSI_BOOT_TGT_CHAP_NAME: 32302a991c21SManish Rangankar case ISCSI_BOOT_TGT_CHAP_SECRET: 32312a991c21SManish Rangankar case ISCSI_BOOT_TGT_REV_CHAP_NAME: 32322a991c21SManish Rangankar case ISCSI_BOOT_TGT_REV_CHAP_SECRET: 32332a991c21SManish Rangankar case ISCSI_BOOT_TGT_NIC_ASSOC: 32342a991c21SManish Rangankar case ISCSI_BOOT_TGT_FLAGS: 32352a991c21SManish Rangankar rc = S_IRUGO; 32362a991c21SManish Rangankar break; 32372a991c21SManish Rangankar default: 32382a991c21SManish Rangankar rc = 0; 32392a991c21SManish Rangankar break; 32402a991c21SManish Rangankar } 32412a991c21SManish Rangankar return rc; 32422a991c21SManish Rangankar } 32432a991c21SManish Rangankar 32442a991c21SManish Rangankar static void qla4xxx_boot_release(void *data) 32452a991c21SManish Rangankar { 32462a991c21SManish Rangankar struct scsi_qla_host *ha = data; 32472a991c21SManish Rangankar 32482a991c21SManish Rangankar scsi_host_put(ha->host); 32492a991c21SManish Rangankar } 32502a991c21SManish Rangankar 32512a991c21SManish Rangankar static int get_fw_boot_info(struct scsi_qla_host *ha, uint16_t ddb_index[]) 32522a991c21SManish Rangankar { 32532a991c21SManish Rangankar dma_addr_t buf_dma; 32542a991c21SManish Rangankar uint32_t addr, pri_addr, sec_addr; 32552a991c21SManish Rangankar uint32_t offset; 32562a991c21SManish Rangankar uint16_t func_num; 32572a991c21SManish Rangankar uint8_t val; 32582a991c21SManish Rangankar uint8_t *buf = NULL; 32592a991c21SManish Rangankar size_t size = 13 * sizeof(uint8_t); 32602a991c21SManish Rangankar int ret = QLA_SUCCESS; 32612a991c21SManish Rangankar 32622a991c21SManish Rangankar func_num = PCI_FUNC(ha->pdev->devfn); 32632a991c21SManish Rangankar 32640d5b36b8SManish Rangankar ql4_printk(KERN_INFO, ha, "%s: Get FW boot info for 0x%x func %d\n", 32650d5b36b8SManish Rangankar __func__, ha->pdev->device, func_num); 32662a991c21SManish Rangankar 32670d5b36b8SManish Rangankar if (is_qla40XX(ha)) { 32682a991c21SManish Rangankar if (func_num == 1) { 32692a991c21SManish Rangankar addr = NVRAM_PORT0_BOOT_MODE; 32702a991c21SManish Rangankar pri_addr = NVRAM_PORT0_BOOT_PRI_TGT; 32712a991c21SManish Rangankar sec_addr = NVRAM_PORT0_BOOT_SEC_TGT; 32722a991c21SManish Rangankar } else if (func_num == 3) { 32732a991c21SManish Rangankar addr = NVRAM_PORT1_BOOT_MODE; 32742a991c21SManish Rangankar pri_addr = NVRAM_PORT1_BOOT_PRI_TGT; 32752a991c21SManish Rangankar sec_addr = NVRAM_PORT1_BOOT_SEC_TGT; 32762a991c21SManish Rangankar } else { 32772a991c21SManish Rangankar ret = QLA_ERROR; 32782a991c21SManish Rangankar goto exit_boot_info; 32792a991c21SManish Rangankar } 32802a991c21SManish Rangankar 32812a991c21SManish Rangankar /* Check Boot Mode */ 32822a991c21SManish Rangankar val = rd_nvram_byte(ha, addr); 32832a991c21SManish Rangankar if (!(val & 0x07)) { 32842a991c21SManish Rangankar DEBUG2(ql4_printk(KERN_ERR, ha, 32852a991c21SManish Rangankar "%s: Failed Boot options : 0x%x\n", 32862a991c21SManish Rangankar __func__, val)); 32872a991c21SManish Rangankar ret = QLA_ERROR; 32882a991c21SManish Rangankar goto exit_boot_info; 32892a991c21SManish Rangankar } 32902a991c21SManish Rangankar 32912a991c21SManish Rangankar /* get primary valid target index */ 32922a991c21SManish Rangankar val = rd_nvram_byte(ha, pri_addr); 32932a991c21SManish Rangankar if (val & BIT_7) 32942a991c21SManish Rangankar ddb_index[0] = (val & 0x7f); 32952a991c21SManish Rangankar 32962a991c21SManish Rangankar /* get secondary valid target index */ 32972a991c21SManish Rangankar val = rd_nvram_byte(ha, sec_addr); 32982a991c21SManish Rangankar if (val & BIT_7) 32992a991c21SManish Rangankar ddb_index[1] = (val & 0x7f); 33002a991c21SManish Rangankar 33012a991c21SManish Rangankar } else if (is_qla8022(ha)) { 33022a991c21SManish Rangankar buf = dma_alloc_coherent(&ha->pdev->dev, size, 33032a991c21SManish Rangankar &buf_dma, GFP_KERNEL); 33042a991c21SManish Rangankar if (!buf) { 33052a991c21SManish Rangankar DEBUG2(ql4_printk(KERN_ERR, ha, 33062a991c21SManish Rangankar "%s: Unable to allocate dma buffer\n", 33072a991c21SManish Rangankar __func__)); 33082a991c21SManish Rangankar ret = QLA_ERROR; 33092a991c21SManish Rangankar goto exit_boot_info; 33102a991c21SManish Rangankar } 33112a991c21SManish Rangankar 33122a991c21SManish Rangankar if (ha->port_num == 0) 33132a991c21SManish Rangankar offset = BOOT_PARAM_OFFSET_PORT0; 33142a991c21SManish Rangankar else if (ha->port_num == 1) 33152a991c21SManish Rangankar offset = BOOT_PARAM_OFFSET_PORT1; 33162a991c21SManish Rangankar else { 33172a991c21SManish Rangankar ret = QLA_ERROR; 33182a991c21SManish Rangankar goto exit_boot_info_free; 33192a991c21SManish Rangankar } 33202a991c21SManish Rangankar addr = FLASH_RAW_ACCESS_ADDR + (ha->hw.flt_iscsi_param * 4) + 33212a991c21SManish Rangankar offset; 33222a991c21SManish Rangankar if (qla4xxx_get_flash(ha, buf_dma, addr, 33232a991c21SManish Rangankar 13 * sizeof(uint8_t)) != QLA_SUCCESS) { 33242a991c21SManish Rangankar DEBUG2(ql4_printk(KERN_ERR, ha, "scsi%ld: %s: Get Flash" 33252a991c21SManish Rangankar "failed\n", ha->host_no, __func__)); 33262a991c21SManish Rangankar ret = QLA_ERROR; 33272a991c21SManish Rangankar goto exit_boot_info_free; 33282a991c21SManish Rangankar } 33292a991c21SManish Rangankar /* Check Boot Mode */ 33302a991c21SManish Rangankar if (!(buf[1] & 0x07)) { 33312a991c21SManish Rangankar DEBUG2(ql4_printk(KERN_INFO, ha, 33322a991c21SManish Rangankar "Failed: Boot options : 0x%x\n", 33332a991c21SManish Rangankar buf[1])); 33342a991c21SManish Rangankar ret = QLA_ERROR; 33352a991c21SManish Rangankar goto exit_boot_info_free; 33362a991c21SManish Rangankar } 33372a991c21SManish Rangankar 33382a991c21SManish Rangankar /* get primary valid target index */ 33392a991c21SManish Rangankar if (buf[2] & BIT_7) 33402a991c21SManish Rangankar ddb_index[0] = buf[2] & 0x7f; 33412a991c21SManish Rangankar 33422a991c21SManish Rangankar /* get secondary valid target index */ 33432a991c21SManish Rangankar if (buf[11] & BIT_7) 33442a991c21SManish Rangankar ddb_index[1] = buf[11] & 0x7f; 33452a991c21SManish Rangankar } else { 33462a991c21SManish Rangankar ret = QLA_ERROR; 33472a991c21SManish Rangankar goto exit_boot_info; 33482a991c21SManish Rangankar } 33492a991c21SManish Rangankar 33502a991c21SManish Rangankar DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Primary target ID %d, Secondary" 33512a991c21SManish Rangankar " target ID %d\n", __func__, ddb_index[0], 33522a991c21SManish Rangankar ddb_index[1])); 33532a991c21SManish Rangankar 335413483730SMike Christie ha->pri_ddb_idx = ddb_index[0]; 335513483730SMike Christie ha->sec_ddb_idx = ddb_index[1]; 335613483730SMike Christie 33572a991c21SManish Rangankar exit_boot_info_free: 33582a991c21SManish Rangankar dma_free_coherent(&ha->pdev->dev, size, buf, buf_dma); 33592a991c21SManish Rangankar exit_boot_info: 33602a991c21SManish Rangankar return ret; 33612a991c21SManish Rangankar } 33622a991c21SManish Rangankar 336328deb45cSLalit Chandivade /** 336428deb45cSLalit Chandivade * qla4xxx_get_bidi_chap - Get a BIDI CHAP user and password 336528deb45cSLalit Chandivade * @ha: pointer to adapter structure 336628deb45cSLalit Chandivade * @username: CHAP username to be returned 336728deb45cSLalit Chandivade * @password: CHAP password to be returned 336828deb45cSLalit Chandivade * 336928deb45cSLalit Chandivade * If a boot entry has BIDI CHAP enabled then we need to set the BIDI CHAP 337028deb45cSLalit Chandivade * user and password in the sysfs entry in /sys/firmware/iscsi_boot#/. 337128deb45cSLalit Chandivade * So from the CHAP cache find the first BIDI CHAP entry and set it 337228deb45cSLalit Chandivade * to the boot record in sysfs. 337328deb45cSLalit Chandivade **/ 337428deb45cSLalit Chandivade static int qla4xxx_get_bidi_chap(struct scsi_qla_host *ha, char *username, 337528deb45cSLalit Chandivade char *password) 337628deb45cSLalit Chandivade { 337728deb45cSLalit Chandivade int i, ret = -EINVAL; 337828deb45cSLalit Chandivade int max_chap_entries = 0; 337928deb45cSLalit Chandivade struct ql4_chap_table *chap_table; 338028deb45cSLalit Chandivade 338128deb45cSLalit Chandivade if (is_qla8022(ha)) 338228deb45cSLalit Chandivade max_chap_entries = (ha->hw.flt_chap_size / 2) / 338328deb45cSLalit Chandivade sizeof(struct ql4_chap_table); 338428deb45cSLalit Chandivade else 338528deb45cSLalit Chandivade max_chap_entries = MAX_CHAP_ENTRIES_40XX; 338628deb45cSLalit Chandivade 338728deb45cSLalit Chandivade if (!ha->chap_list) { 338828deb45cSLalit Chandivade ql4_printk(KERN_ERR, ha, "Do not have CHAP table cache\n"); 338928deb45cSLalit Chandivade return ret; 339028deb45cSLalit Chandivade } 339128deb45cSLalit Chandivade 339228deb45cSLalit Chandivade mutex_lock(&ha->chap_sem); 339328deb45cSLalit Chandivade for (i = 0; i < max_chap_entries; i++) { 339428deb45cSLalit Chandivade chap_table = (struct ql4_chap_table *)ha->chap_list + i; 339528deb45cSLalit Chandivade if (chap_table->cookie != 339628deb45cSLalit Chandivade __constant_cpu_to_le16(CHAP_VALID_COOKIE)) { 339728deb45cSLalit Chandivade continue; 339828deb45cSLalit Chandivade } 339928deb45cSLalit Chandivade 340028deb45cSLalit Chandivade if (chap_table->flags & BIT_7) /* local */ 340128deb45cSLalit Chandivade continue; 340228deb45cSLalit Chandivade 340328deb45cSLalit Chandivade if (!(chap_table->flags & BIT_6)) /* Not BIDI */ 340428deb45cSLalit Chandivade continue; 340528deb45cSLalit Chandivade 340628deb45cSLalit Chandivade strncpy(password, chap_table->secret, QL4_CHAP_MAX_SECRET_LEN); 340728deb45cSLalit Chandivade strncpy(username, chap_table->name, QL4_CHAP_MAX_NAME_LEN); 340828deb45cSLalit Chandivade ret = 0; 340928deb45cSLalit Chandivade break; 341028deb45cSLalit Chandivade } 341128deb45cSLalit Chandivade mutex_unlock(&ha->chap_sem); 341228deb45cSLalit Chandivade 341328deb45cSLalit Chandivade return ret; 341428deb45cSLalit Chandivade } 341528deb45cSLalit Chandivade 341628deb45cSLalit Chandivade 34172a991c21SManish Rangankar static int qla4xxx_get_boot_target(struct scsi_qla_host *ha, 34182a991c21SManish Rangankar struct ql4_boot_session_info *boot_sess, 34192a991c21SManish Rangankar uint16_t ddb_index) 34202a991c21SManish Rangankar { 34212a991c21SManish Rangankar struct ql4_conn_info *boot_conn = &boot_sess->conn_list[0]; 34222a991c21SManish Rangankar struct dev_db_entry *fw_ddb_entry; 34232a991c21SManish Rangankar dma_addr_t fw_ddb_entry_dma; 34242a991c21SManish Rangankar uint16_t idx; 34252a991c21SManish Rangankar uint16_t options; 34262a991c21SManish Rangankar int ret = QLA_SUCCESS; 34272a991c21SManish Rangankar 34282a991c21SManish Rangankar fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), 34292a991c21SManish Rangankar &fw_ddb_entry_dma, GFP_KERNEL); 34302a991c21SManish Rangankar if (!fw_ddb_entry) { 34312a991c21SManish Rangankar DEBUG2(ql4_printk(KERN_ERR, ha, 34322a991c21SManish Rangankar "%s: Unable to allocate dma buffer.\n", 34332a991c21SManish Rangankar __func__)); 34342a991c21SManish Rangankar ret = QLA_ERROR; 34352a991c21SManish Rangankar return ret; 34362a991c21SManish Rangankar } 34372a991c21SManish Rangankar 34382a991c21SManish Rangankar if (qla4xxx_bootdb_by_index(ha, fw_ddb_entry, 34392a991c21SManish Rangankar fw_ddb_entry_dma, ddb_index)) { 34402a991c21SManish Rangankar DEBUG2(ql4_printk(KERN_ERR, ha, 34412a991c21SManish Rangankar "%s: Flash DDB read Failed\n", __func__)); 34422a991c21SManish Rangankar ret = QLA_ERROR; 34432a991c21SManish Rangankar goto exit_boot_target; 34442a991c21SManish Rangankar } 34452a991c21SManish Rangankar 34462a991c21SManish Rangankar /* Update target name and IP from DDB */ 34472a991c21SManish Rangankar memcpy(boot_sess->target_name, fw_ddb_entry->iscsi_name, 34482a991c21SManish Rangankar min(sizeof(boot_sess->target_name), 34492a991c21SManish Rangankar sizeof(fw_ddb_entry->iscsi_name))); 34502a991c21SManish Rangankar 34512a991c21SManish Rangankar options = le16_to_cpu(fw_ddb_entry->options); 34522a991c21SManish Rangankar if (options & DDB_OPT_IPV6_DEVICE) { 34532a991c21SManish Rangankar memcpy(&boot_conn->dest_ipaddr.ip_address, 34542a991c21SManish Rangankar &fw_ddb_entry->ip_addr[0], IPv6_ADDR_LEN); 34552a991c21SManish Rangankar } else { 34562a991c21SManish Rangankar boot_conn->dest_ipaddr.ip_type = 0x1; 34572a991c21SManish Rangankar memcpy(&boot_conn->dest_ipaddr.ip_address, 34582a991c21SManish Rangankar &fw_ddb_entry->ip_addr[0], IP_ADDR_LEN); 34592a991c21SManish Rangankar } 34602a991c21SManish Rangankar 34612a991c21SManish Rangankar boot_conn->dest_port = le16_to_cpu(fw_ddb_entry->port); 34622a991c21SManish Rangankar 34632a991c21SManish Rangankar /* update chap information */ 34642a991c21SManish Rangankar idx = __le16_to_cpu(fw_ddb_entry->chap_tbl_idx); 34652a991c21SManish Rangankar 34662a991c21SManish Rangankar if (BIT_7 & le16_to_cpu(fw_ddb_entry->iscsi_options)) { 34672a991c21SManish Rangankar 34682a991c21SManish Rangankar DEBUG2(ql4_printk(KERN_INFO, ha, "Setting chap\n")); 34692a991c21SManish Rangankar 34702a991c21SManish Rangankar ret = qla4xxx_get_chap(ha, (char *)&boot_conn->chap. 34712a991c21SManish Rangankar target_chap_name, 34722a991c21SManish Rangankar (char *)&boot_conn->chap.target_secret, 34732a991c21SManish Rangankar idx); 34742a991c21SManish Rangankar if (ret) { 34752a991c21SManish Rangankar ql4_printk(KERN_ERR, ha, "Failed to set chap\n"); 34762a991c21SManish Rangankar ret = QLA_ERROR; 34772a991c21SManish Rangankar goto exit_boot_target; 34782a991c21SManish Rangankar } 34792a991c21SManish Rangankar 34802a991c21SManish Rangankar boot_conn->chap.target_chap_name_length = QL4_CHAP_MAX_NAME_LEN; 34812a991c21SManish Rangankar boot_conn->chap.target_secret_length = QL4_CHAP_MAX_SECRET_LEN; 34822a991c21SManish Rangankar } 34832a991c21SManish Rangankar 34842a991c21SManish Rangankar if (BIT_4 & le16_to_cpu(fw_ddb_entry->iscsi_options)) { 34852a991c21SManish Rangankar 34862a991c21SManish Rangankar DEBUG2(ql4_printk(KERN_INFO, ha, "Setting BIDI chap\n")); 34872a991c21SManish Rangankar 348828deb45cSLalit Chandivade ret = qla4xxx_get_bidi_chap(ha, 348928deb45cSLalit Chandivade (char *)&boot_conn->chap.intr_chap_name, 349028deb45cSLalit Chandivade (char *)&boot_conn->chap.intr_secret); 349128deb45cSLalit Chandivade 34922a991c21SManish Rangankar if (ret) { 34932a991c21SManish Rangankar ql4_printk(KERN_ERR, ha, "Failed to set BIDI chap\n"); 34942a991c21SManish Rangankar ret = QLA_ERROR; 34952a991c21SManish Rangankar goto exit_boot_target; 34962a991c21SManish Rangankar } 34972a991c21SManish Rangankar 34982a991c21SManish Rangankar boot_conn->chap.intr_chap_name_length = QL4_CHAP_MAX_NAME_LEN; 34992a991c21SManish Rangankar boot_conn->chap.intr_secret_length = QL4_CHAP_MAX_SECRET_LEN; 35002a991c21SManish Rangankar } 35012a991c21SManish Rangankar 35022a991c21SManish Rangankar exit_boot_target: 35032a991c21SManish Rangankar dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), 35042a991c21SManish Rangankar fw_ddb_entry, fw_ddb_entry_dma); 35052a991c21SManish Rangankar return ret; 35062a991c21SManish Rangankar } 35072a991c21SManish Rangankar 35082a991c21SManish Rangankar static int qla4xxx_get_boot_info(struct scsi_qla_host *ha) 35092a991c21SManish Rangankar { 35102a991c21SManish Rangankar uint16_t ddb_index[2]; 35118de5b958SLalit Chandivade int ret = QLA_ERROR; 35128de5b958SLalit Chandivade int rval; 35132a991c21SManish Rangankar 35142a991c21SManish Rangankar memset(ddb_index, 0, sizeof(ddb_index)); 35158de5b958SLalit Chandivade ddb_index[0] = 0xffff; 35168de5b958SLalit Chandivade ddb_index[1] = 0xffff; 35172a991c21SManish Rangankar ret = get_fw_boot_info(ha, ddb_index); 35182a991c21SManish Rangankar if (ret != QLA_SUCCESS) { 35192a991c21SManish Rangankar DEBUG2(ql4_printk(KERN_ERR, ha, 35202a991c21SManish Rangankar "%s: Failed to set boot info.\n", __func__)); 35212a991c21SManish Rangankar return ret; 35222a991c21SManish Rangankar } 35232a991c21SManish Rangankar 352413483730SMike Christie if (ql4xdisablesysfsboot) 352513483730SMike Christie return QLA_SUCCESS; 352613483730SMike Christie 35278de5b958SLalit Chandivade if (ddb_index[0] == 0xffff) 35288de5b958SLalit Chandivade goto sec_target; 35298de5b958SLalit Chandivade 35308de5b958SLalit Chandivade rval = qla4xxx_get_boot_target(ha, &(ha->boot_tgt.boot_pri_sess), 35312a991c21SManish Rangankar ddb_index[0]); 35328de5b958SLalit Chandivade if (rval != QLA_SUCCESS) { 35332a991c21SManish Rangankar DEBUG2(ql4_printk(KERN_ERR, ha, "%s: Failed to get " 35342a991c21SManish Rangankar "primary target\n", __func__)); 35358de5b958SLalit Chandivade } else 35368de5b958SLalit Chandivade ret = QLA_SUCCESS; 35372a991c21SManish Rangankar 35388de5b958SLalit Chandivade sec_target: 35398de5b958SLalit Chandivade if (ddb_index[1] == 0xffff) 35408de5b958SLalit Chandivade goto exit_get_boot_info; 35418de5b958SLalit Chandivade 35428de5b958SLalit Chandivade rval = qla4xxx_get_boot_target(ha, &(ha->boot_tgt.boot_sec_sess), 35432a991c21SManish Rangankar ddb_index[1]); 35448de5b958SLalit Chandivade if (rval != QLA_SUCCESS) { 35452a991c21SManish Rangankar DEBUG2(ql4_printk(KERN_ERR, ha, "%s: Failed to get " 35462a991c21SManish Rangankar "secondary target\n", __func__)); 35478de5b958SLalit Chandivade } else 35488de5b958SLalit Chandivade ret = QLA_SUCCESS; 35498de5b958SLalit Chandivade 35508de5b958SLalit Chandivade exit_get_boot_info: 35512a991c21SManish Rangankar return ret; 35522a991c21SManish Rangankar } 35532a991c21SManish Rangankar 35542a991c21SManish Rangankar static int qla4xxx_setup_boot_info(struct scsi_qla_host *ha) 35552a991c21SManish Rangankar { 35562a991c21SManish Rangankar struct iscsi_boot_kobj *boot_kobj; 35572a991c21SManish Rangankar 35582a991c21SManish Rangankar if (qla4xxx_get_boot_info(ha) != QLA_SUCCESS) 355913483730SMike Christie return QLA_ERROR; 356013483730SMike Christie 356113483730SMike Christie if (ql4xdisablesysfsboot) { 356213483730SMike Christie ql4_printk(KERN_INFO, ha, 356313483730SMike Christie "%s: syfsboot disabled - driver will trigger login" 356413483730SMike Christie "and publish session for discovery .\n", __func__); 356513483730SMike Christie return QLA_SUCCESS; 356613483730SMike Christie } 356713483730SMike Christie 35682a991c21SManish Rangankar 35692a991c21SManish Rangankar ha->boot_kset = iscsi_boot_create_host_kset(ha->host->host_no); 35702a991c21SManish Rangankar if (!ha->boot_kset) 35712a991c21SManish Rangankar goto kset_free; 35722a991c21SManish Rangankar 35732a991c21SManish Rangankar if (!scsi_host_get(ha->host)) 35742a991c21SManish Rangankar goto kset_free; 35752a991c21SManish Rangankar boot_kobj = iscsi_boot_create_target(ha->boot_kset, 0, ha, 35762a991c21SManish Rangankar qla4xxx_show_boot_tgt_pri_info, 35772a991c21SManish Rangankar qla4xxx_tgt_get_attr_visibility, 35782a991c21SManish Rangankar qla4xxx_boot_release); 35792a991c21SManish Rangankar if (!boot_kobj) 35802a991c21SManish Rangankar goto put_host; 35812a991c21SManish Rangankar 35822a991c21SManish Rangankar if (!scsi_host_get(ha->host)) 35832a991c21SManish Rangankar goto kset_free; 35842a991c21SManish Rangankar boot_kobj = iscsi_boot_create_target(ha->boot_kset, 1, ha, 35852a991c21SManish Rangankar qla4xxx_show_boot_tgt_sec_info, 35862a991c21SManish Rangankar qla4xxx_tgt_get_attr_visibility, 35872a991c21SManish Rangankar qla4xxx_boot_release); 35882a991c21SManish Rangankar if (!boot_kobj) 35892a991c21SManish Rangankar goto put_host; 35902a991c21SManish Rangankar 35912a991c21SManish Rangankar if (!scsi_host_get(ha->host)) 35922a991c21SManish Rangankar goto kset_free; 35932a991c21SManish Rangankar boot_kobj = iscsi_boot_create_initiator(ha->boot_kset, 0, ha, 35942a991c21SManish Rangankar qla4xxx_show_boot_ini_info, 35952a991c21SManish Rangankar qla4xxx_ini_get_attr_visibility, 35962a991c21SManish Rangankar qla4xxx_boot_release); 35972a991c21SManish Rangankar if (!boot_kobj) 35982a991c21SManish Rangankar goto put_host; 35992a991c21SManish Rangankar 36002a991c21SManish Rangankar if (!scsi_host_get(ha->host)) 36012a991c21SManish Rangankar goto kset_free; 36022a991c21SManish Rangankar boot_kobj = iscsi_boot_create_ethernet(ha->boot_kset, 0, ha, 36032a991c21SManish Rangankar qla4xxx_show_boot_eth_info, 36042a991c21SManish Rangankar qla4xxx_eth_get_attr_visibility, 36052a991c21SManish Rangankar qla4xxx_boot_release); 36062a991c21SManish Rangankar if (!boot_kobj) 36072a991c21SManish Rangankar goto put_host; 36082a991c21SManish Rangankar 360913483730SMike Christie return QLA_SUCCESS; 36102a991c21SManish Rangankar 36112a991c21SManish Rangankar put_host: 36122a991c21SManish Rangankar scsi_host_put(ha->host); 36132a991c21SManish Rangankar kset_free: 36142a991c21SManish Rangankar iscsi_boot_destroy_kset(ha->boot_kset); 36152a991c21SManish Rangankar return -ENOMEM; 36162a991c21SManish Rangankar } 36172a991c21SManish Rangankar 36184549415aSLalit Chandivade 36194549415aSLalit Chandivade /** 36204549415aSLalit Chandivade * qla4xxx_create chap_list - Create CHAP list from FLASH 36214549415aSLalit Chandivade * @ha: pointer to adapter structure 36224549415aSLalit Chandivade * 36234549415aSLalit Chandivade * Read flash and make a list of CHAP entries, during login when a CHAP entry 36244549415aSLalit Chandivade * is received, it will be checked in this list. If entry exist then the CHAP 36254549415aSLalit Chandivade * entry index is set in the DDB. If CHAP entry does not exist in this list 36264549415aSLalit Chandivade * then a new entry is added in FLASH in CHAP table and the index obtained is 36274549415aSLalit Chandivade * used in the DDB. 36284549415aSLalit Chandivade **/ 36294549415aSLalit Chandivade static void qla4xxx_create_chap_list(struct scsi_qla_host *ha) 36304549415aSLalit Chandivade { 36314549415aSLalit Chandivade int rval = 0; 36324549415aSLalit Chandivade uint8_t *chap_flash_data = NULL; 36334549415aSLalit Chandivade uint32_t offset; 36344549415aSLalit Chandivade dma_addr_t chap_dma; 36354549415aSLalit Chandivade uint32_t chap_size = 0; 36364549415aSLalit Chandivade 36374549415aSLalit Chandivade if (is_qla40XX(ha)) 36384549415aSLalit Chandivade chap_size = MAX_CHAP_ENTRIES_40XX * 36394549415aSLalit Chandivade sizeof(struct ql4_chap_table); 36404549415aSLalit Chandivade else /* Single region contains CHAP info for both 36414549415aSLalit Chandivade * ports which is divided into half for each port. 36424549415aSLalit Chandivade */ 36434549415aSLalit Chandivade chap_size = ha->hw.flt_chap_size / 2; 36444549415aSLalit Chandivade 36454549415aSLalit Chandivade chap_flash_data = dma_alloc_coherent(&ha->pdev->dev, chap_size, 36464549415aSLalit Chandivade &chap_dma, GFP_KERNEL); 36474549415aSLalit Chandivade if (!chap_flash_data) { 36484549415aSLalit Chandivade ql4_printk(KERN_ERR, ha, "No memory for chap_flash_data\n"); 36494549415aSLalit Chandivade return; 36504549415aSLalit Chandivade } 36514549415aSLalit Chandivade if (is_qla40XX(ha)) 36524549415aSLalit Chandivade offset = FLASH_CHAP_OFFSET; 36534549415aSLalit Chandivade else { 36544549415aSLalit Chandivade offset = FLASH_RAW_ACCESS_ADDR + (ha->hw.flt_region_chap << 2); 36554549415aSLalit Chandivade if (ha->port_num == 1) 36564549415aSLalit Chandivade offset += chap_size; 36574549415aSLalit Chandivade } 36584549415aSLalit Chandivade 36594549415aSLalit Chandivade rval = qla4xxx_get_flash(ha, chap_dma, offset, chap_size); 36604549415aSLalit Chandivade if (rval != QLA_SUCCESS) 36614549415aSLalit Chandivade goto exit_chap_list; 36624549415aSLalit Chandivade 36634549415aSLalit Chandivade if (ha->chap_list == NULL) 36644549415aSLalit Chandivade ha->chap_list = vmalloc(chap_size); 36654549415aSLalit Chandivade if (ha->chap_list == NULL) { 36664549415aSLalit Chandivade ql4_printk(KERN_ERR, ha, "No memory for ha->chap_list\n"); 36674549415aSLalit Chandivade goto exit_chap_list; 36684549415aSLalit Chandivade } 36694549415aSLalit Chandivade 36704549415aSLalit Chandivade memcpy(ha->chap_list, chap_flash_data, chap_size); 36714549415aSLalit Chandivade 36724549415aSLalit Chandivade exit_chap_list: 36734549415aSLalit Chandivade dma_free_coherent(&ha->pdev->dev, chap_size, 36744549415aSLalit Chandivade chap_flash_data, chap_dma); 367513483730SMike Christie } 367613483730SMike Christie 367713483730SMike Christie static void qla4xxx_get_param_ddb(struct ddb_entry *ddb_entry, 367813483730SMike Christie struct ql4_tuple_ddb *tddb) 367913483730SMike Christie { 368013483730SMike Christie struct scsi_qla_host *ha; 368113483730SMike Christie struct iscsi_cls_session *cls_sess; 368213483730SMike Christie struct iscsi_cls_conn *cls_conn; 368313483730SMike Christie struct iscsi_session *sess; 368413483730SMike Christie struct iscsi_conn *conn; 368513483730SMike Christie 368613483730SMike Christie DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); 368713483730SMike Christie ha = ddb_entry->ha; 368813483730SMike Christie cls_sess = ddb_entry->sess; 368913483730SMike Christie sess = cls_sess->dd_data; 369013483730SMike Christie cls_conn = ddb_entry->conn; 369113483730SMike Christie conn = cls_conn->dd_data; 369213483730SMike Christie 369313483730SMike Christie tddb->tpgt = sess->tpgt; 369413483730SMike Christie tddb->port = conn->persistent_port; 369513483730SMike Christie strncpy(tddb->iscsi_name, sess->targetname, ISCSI_NAME_SIZE); 369613483730SMike Christie strncpy(tddb->ip_addr, conn->persistent_address, DDB_IPADDR_LEN); 369713483730SMike Christie } 369813483730SMike Christie 369913483730SMike Christie static void qla4xxx_convert_param_ddb(struct dev_db_entry *fw_ddb_entry, 370013483730SMike Christie struct ql4_tuple_ddb *tddb) 370113483730SMike Christie { 370213483730SMike Christie uint16_t options = 0; 370313483730SMike Christie 370413483730SMike Christie tddb->tpgt = le32_to_cpu(fw_ddb_entry->tgt_portal_grp); 370513483730SMike Christie memcpy(&tddb->iscsi_name[0], &fw_ddb_entry->iscsi_name[0], 370613483730SMike Christie min(sizeof(tddb->iscsi_name), sizeof(fw_ddb_entry->iscsi_name))); 370713483730SMike Christie 370813483730SMike Christie options = le16_to_cpu(fw_ddb_entry->options); 370913483730SMike Christie if (options & DDB_OPT_IPV6_DEVICE) 371013483730SMike Christie sprintf(tddb->ip_addr, "%pI6", fw_ddb_entry->ip_addr); 371113483730SMike Christie else 371213483730SMike Christie sprintf(tddb->ip_addr, "%pI4", fw_ddb_entry->ip_addr); 371313483730SMike Christie 371413483730SMike Christie tddb->port = le16_to_cpu(fw_ddb_entry->port); 371513483730SMike Christie } 371613483730SMike Christie 371713483730SMike Christie static int qla4xxx_compare_tuple_ddb(struct scsi_qla_host *ha, 371813483730SMike Christie struct ql4_tuple_ddb *old_tddb, 371913483730SMike Christie struct ql4_tuple_ddb *new_tddb) 372013483730SMike Christie { 372113483730SMike Christie if (strcmp(old_tddb->iscsi_name, new_tddb->iscsi_name)) 372213483730SMike Christie return QLA_ERROR; 372313483730SMike Christie 372413483730SMike Christie if (strcmp(old_tddb->ip_addr, new_tddb->ip_addr)) 372513483730SMike Christie return QLA_ERROR; 372613483730SMike Christie 372713483730SMike Christie if (old_tddb->port != new_tddb->port) 372813483730SMike Christie return QLA_ERROR; 372913483730SMike Christie 373013483730SMike Christie DEBUG2(ql4_printk(KERN_INFO, ha, 373113483730SMike Christie "Match Found, fw[%d,%d,%s,%s], [%d,%d,%s,%s]", 373213483730SMike Christie old_tddb->port, old_tddb->tpgt, old_tddb->ip_addr, 373313483730SMike Christie old_tddb->iscsi_name, new_tddb->port, new_tddb->tpgt, 373413483730SMike Christie new_tddb->ip_addr, new_tddb->iscsi_name)); 373513483730SMike Christie 373613483730SMike Christie return QLA_SUCCESS; 373713483730SMike Christie } 373813483730SMike Christie 373913483730SMike Christie static int qla4xxx_is_session_exists(struct scsi_qla_host *ha, 374013483730SMike Christie struct dev_db_entry *fw_ddb_entry) 374113483730SMike Christie { 374213483730SMike Christie struct ddb_entry *ddb_entry; 374313483730SMike Christie struct ql4_tuple_ddb *fw_tddb = NULL; 374413483730SMike Christie struct ql4_tuple_ddb *tmp_tddb = NULL; 374513483730SMike Christie int idx; 374613483730SMike Christie int ret = QLA_ERROR; 374713483730SMike Christie 374813483730SMike Christie fw_tddb = vzalloc(sizeof(*fw_tddb)); 374913483730SMike Christie if (!fw_tddb) { 375013483730SMike Christie DEBUG2(ql4_printk(KERN_WARNING, ha, 375113483730SMike Christie "Memory Allocation failed.\n")); 375213483730SMike Christie ret = QLA_SUCCESS; 375313483730SMike Christie goto exit_check; 375413483730SMike Christie } 375513483730SMike Christie 375613483730SMike Christie tmp_tddb = vzalloc(sizeof(*tmp_tddb)); 375713483730SMike Christie if (!tmp_tddb) { 375813483730SMike Christie DEBUG2(ql4_printk(KERN_WARNING, ha, 375913483730SMike Christie "Memory Allocation failed.\n")); 376013483730SMike Christie ret = QLA_SUCCESS; 376113483730SMike Christie goto exit_check; 376213483730SMike Christie } 376313483730SMike Christie 376413483730SMike Christie qla4xxx_convert_param_ddb(fw_ddb_entry, fw_tddb); 376513483730SMike Christie 376613483730SMike Christie for (idx = 0; idx < MAX_DDB_ENTRIES; idx++) { 376713483730SMike Christie ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx); 376813483730SMike Christie if (ddb_entry == NULL) 376913483730SMike Christie continue; 377013483730SMike Christie 377113483730SMike Christie qla4xxx_get_param_ddb(ddb_entry, tmp_tddb); 377213483730SMike Christie if (!qla4xxx_compare_tuple_ddb(ha, fw_tddb, tmp_tddb)) { 377313483730SMike Christie ret = QLA_SUCCESS; /* found */ 377413483730SMike Christie goto exit_check; 377513483730SMike Christie } 377613483730SMike Christie } 377713483730SMike Christie 377813483730SMike Christie exit_check: 377913483730SMike Christie if (fw_tddb) 378013483730SMike Christie vfree(fw_tddb); 378113483730SMike Christie if (tmp_tddb) 378213483730SMike Christie vfree(tmp_tddb); 378313483730SMike Christie return ret; 378413483730SMike Christie } 378513483730SMike Christie 378613483730SMike Christie static int qla4xxx_is_flash_ddb_exists(struct scsi_qla_host *ha, 378713483730SMike Christie struct list_head *list_nt, 378813483730SMike Christie struct dev_db_entry *fw_ddb_entry) 378913483730SMike Christie { 379013483730SMike Christie struct qla_ddb_index *nt_ddb_idx, *nt_ddb_idx_tmp; 379113483730SMike Christie struct ql4_tuple_ddb *fw_tddb = NULL; 379213483730SMike Christie struct ql4_tuple_ddb *tmp_tddb = NULL; 379313483730SMike Christie int ret = QLA_ERROR; 379413483730SMike Christie 379513483730SMike Christie fw_tddb = vzalloc(sizeof(*fw_tddb)); 379613483730SMike Christie if (!fw_tddb) { 379713483730SMike Christie DEBUG2(ql4_printk(KERN_WARNING, ha, 379813483730SMike Christie "Memory Allocation failed.\n")); 379913483730SMike Christie ret = QLA_SUCCESS; 380013483730SMike Christie goto exit_check; 380113483730SMike Christie } 380213483730SMike Christie 380313483730SMike Christie tmp_tddb = vzalloc(sizeof(*tmp_tddb)); 380413483730SMike Christie if (!tmp_tddb) { 380513483730SMike Christie DEBUG2(ql4_printk(KERN_WARNING, ha, 380613483730SMike Christie "Memory Allocation failed.\n")); 380713483730SMike Christie ret = QLA_SUCCESS; 380813483730SMike Christie goto exit_check; 380913483730SMike Christie } 381013483730SMike Christie 381113483730SMike Christie qla4xxx_convert_param_ddb(fw_ddb_entry, fw_tddb); 381213483730SMike Christie 381313483730SMike Christie list_for_each_entry_safe(nt_ddb_idx, nt_ddb_idx_tmp, list_nt, list) { 381413483730SMike Christie qla4xxx_convert_param_ddb(&nt_ddb_idx->fw_ddb, tmp_tddb); 381513483730SMike Christie if (!qla4xxx_compare_tuple_ddb(ha, fw_tddb, tmp_tddb)) { 381613483730SMike Christie ret = QLA_SUCCESS; /* found */ 381713483730SMike Christie goto exit_check; 381813483730SMike Christie } 381913483730SMike Christie } 382013483730SMike Christie 382113483730SMike Christie exit_check: 382213483730SMike Christie if (fw_tddb) 382313483730SMike Christie vfree(fw_tddb); 382413483730SMike Christie if (tmp_tddb) 382513483730SMike Christie vfree(tmp_tddb); 382613483730SMike Christie return ret; 382713483730SMike Christie } 382813483730SMike Christie 38294a4bc2e9SLalit Chandivade static void qla4xxx_free_ddb_list(struct list_head *list_ddb) 383013483730SMike Christie { 38314a4bc2e9SLalit Chandivade struct qla_ddb_index *ddb_idx, *ddb_idx_tmp; 383213483730SMike Christie 38334a4bc2e9SLalit Chandivade list_for_each_entry_safe(ddb_idx, ddb_idx_tmp, list_ddb, list) { 38344a4bc2e9SLalit Chandivade list_del_init(&ddb_idx->list); 38354a4bc2e9SLalit Chandivade vfree(ddb_idx); 383613483730SMike Christie } 383713483730SMike Christie } 383813483730SMike Christie 383913483730SMike Christie static struct iscsi_endpoint *qla4xxx_get_ep_fwdb(struct scsi_qla_host *ha, 384013483730SMike Christie struct dev_db_entry *fw_ddb_entry) 384113483730SMike Christie { 384213483730SMike Christie struct iscsi_endpoint *ep; 384313483730SMike Christie struct sockaddr_in *addr; 384413483730SMike Christie struct sockaddr_in6 *addr6; 384513483730SMike Christie struct sockaddr *dst_addr; 384613483730SMike Christie char *ip; 384713483730SMike Christie 384813483730SMike Christie /* TODO: need to destroy on unload iscsi_endpoint*/ 384913483730SMike Christie dst_addr = vmalloc(sizeof(*dst_addr)); 385013483730SMike Christie if (!dst_addr) 385113483730SMike Christie return NULL; 385213483730SMike Christie 385313483730SMike Christie if (fw_ddb_entry->options & DDB_OPT_IPV6_DEVICE) { 385413483730SMike Christie dst_addr->sa_family = AF_INET6; 385513483730SMike Christie addr6 = (struct sockaddr_in6 *)dst_addr; 385613483730SMike Christie ip = (char *)&addr6->sin6_addr; 385713483730SMike Christie memcpy(ip, fw_ddb_entry->ip_addr, IPv6_ADDR_LEN); 385813483730SMike Christie addr6->sin6_port = htons(le16_to_cpu(fw_ddb_entry->port)); 385913483730SMike Christie 386013483730SMike Christie } else { 386113483730SMike Christie dst_addr->sa_family = AF_INET; 386213483730SMike Christie addr = (struct sockaddr_in *)dst_addr; 386313483730SMike Christie ip = (char *)&addr->sin_addr; 386413483730SMike Christie memcpy(ip, fw_ddb_entry->ip_addr, IP_ADDR_LEN); 386513483730SMike Christie addr->sin_port = htons(le16_to_cpu(fw_ddb_entry->port)); 386613483730SMike Christie } 386713483730SMike Christie 386813483730SMike Christie ep = qla4xxx_ep_connect(ha->host, dst_addr, 0); 386913483730SMike Christie vfree(dst_addr); 387013483730SMike Christie return ep; 387113483730SMike Christie } 387213483730SMike Christie 387313483730SMike Christie static int qla4xxx_verify_boot_idx(struct scsi_qla_host *ha, uint16_t idx) 387413483730SMike Christie { 387513483730SMike Christie if (ql4xdisablesysfsboot) 387613483730SMike Christie return QLA_SUCCESS; 387713483730SMike Christie if (idx == ha->pri_ddb_idx || idx == ha->sec_ddb_idx) 387813483730SMike Christie return QLA_ERROR; 387913483730SMike Christie return QLA_SUCCESS; 388013483730SMike Christie } 388113483730SMike Christie 388213483730SMike Christie static void qla4xxx_setup_flash_ddb_entry(struct scsi_qla_host *ha, 388313483730SMike Christie struct ddb_entry *ddb_entry) 388413483730SMike Christie { 388513483730SMike Christie ddb_entry->ddb_type = FLASH_DDB; 388613483730SMike Christie ddb_entry->fw_ddb_index = INVALID_ENTRY; 388713483730SMike Christie ddb_entry->fw_ddb_device_state = DDB_DS_NO_CONNECTION_ACTIVE; 388813483730SMike Christie ddb_entry->ha = ha; 388913483730SMike Christie ddb_entry->unblock_sess = qla4xxx_unblock_flash_ddb; 389013483730SMike Christie ddb_entry->ddb_change = qla4xxx_flash_ddb_change; 389113483730SMike Christie 389213483730SMike Christie atomic_set(&ddb_entry->retry_relogin_timer, INVALID_ENTRY); 389313483730SMike Christie atomic_set(&ddb_entry->relogin_timer, 0); 389413483730SMike Christie atomic_set(&ddb_entry->relogin_retry_count, 0); 389513483730SMike Christie 389613483730SMike Christie ddb_entry->default_relogin_timeout = 389713483730SMike Christie le16_to_cpu(ddb_entry->fw_ddb_entry.def_timeout); 389813483730SMike Christie ddb_entry->default_time2wait = 389913483730SMike Christie le16_to_cpu(ddb_entry->fw_ddb_entry.iscsi_def_time2wait); 390013483730SMike Christie } 390113483730SMike Christie 390213483730SMike Christie static void qla4xxx_wait_for_ip_configuration(struct scsi_qla_host *ha) 390313483730SMike Christie { 390413483730SMike Christie uint32_t idx = 0; 390513483730SMike Christie uint32_t ip_idx[IP_ADDR_COUNT] = {0, 1, 2, 3}; /* 4 IP interfaces */ 390613483730SMike Christie uint32_t sts[MBOX_REG_COUNT]; 390713483730SMike Christie uint32_t ip_state; 390813483730SMike Christie unsigned long wtime; 390913483730SMike Christie int ret; 391013483730SMike Christie 391113483730SMike Christie wtime = jiffies + (HZ * IP_CONFIG_TOV); 391213483730SMike Christie do { 391313483730SMike Christie for (idx = 0; idx < IP_ADDR_COUNT; idx++) { 391413483730SMike Christie if (ip_idx[idx] == -1) 391513483730SMike Christie continue; 391613483730SMike Christie 391713483730SMike Christie ret = qla4xxx_get_ip_state(ha, 0, ip_idx[idx], sts); 391813483730SMike Christie 391913483730SMike Christie if (ret == QLA_ERROR) { 392013483730SMike Christie ip_idx[idx] = -1; 392113483730SMike Christie continue; 392213483730SMike Christie } 392313483730SMike Christie 392413483730SMike Christie ip_state = (sts[1] & IP_STATE_MASK) >> IP_STATE_SHIFT; 392513483730SMike Christie 392613483730SMike Christie DEBUG2(ql4_printk(KERN_INFO, ha, 392713483730SMike Christie "Waiting for IP state for idx = %d, state = 0x%x\n", 392813483730SMike Christie ip_idx[idx], ip_state)); 392913483730SMike Christie if (ip_state == IP_ADDRSTATE_UNCONFIGURED || 393013483730SMike Christie ip_state == IP_ADDRSTATE_INVALID || 393113483730SMike Christie ip_state == IP_ADDRSTATE_PREFERRED || 393213483730SMike Christie ip_state == IP_ADDRSTATE_DEPRICATED || 393313483730SMike Christie ip_state == IP_ADDRSTATE_DISABLING) 393413483730SMike Christie ip_idx[idx] = -1; 393513483730SMike Christie } 393613483730SMike Christie 393713483730SMike Christie /* Break if all IP states checked */ 393813483730SMike Christie if ((ip_idx[0] == -1) && 393913483730SMike Christie (ip_idx[1] == -1) && 394013483730SMike Christie (ip_idx[2] == -1) && 394113483730SMike Christie (ip_idx[3] == -1)) 394213483730SMike Christie break; 394313483730SMike Christie schedule_timeout_uninterruptible(HZ); 394413483730SMike Christie } while (time_after(wtime, jiffies)); 394513483730SMike Christie } 394613483730SMike Christie 39474a4bc2e9SLalit Chandivade static void qla4xxx_build_st_list(struct scsi_qla_host *ha, 39484a4bc2e9SLalit Chandivade struct list_head *list_st) 394913483730SMike Christie { 39504a4bc2e9SLalit Chandivade struct qla_ddb_index *st_ddb_idx; 395113483730SMike Christie int max_ddbs; 39524a4bc2e9SLalit Chandivade int fw_idx_size; 39534a4bc2e9SLalit Chandivade struct dev_db_entry *fw_ddb_entry; 39544a4bc2e9SLalit Chandivade dma_addr_t fw_ddb_dma; 395513483730SMike Christie int ret; 395613483730SMike Christie uint32_t idx = 0, next_idx = 0; 395713483730SMike Christie uint32_t state = 0, conn_err = 0; 39584a4bc2e9SLalit Chandivade uint16_t conn_id = 0; 395913483730SMike Christie 396013483730SMike Christie fw_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL, 396113483730SMike Christie &fw_ddb_dma); 396213483730SMike Christie if (fw_ddb_entry == NULL) { 396313483730SMike Christie DEBUG2(ql4_printk(KERN_ERR, ha, "Out of memory\n")); 39644a4bc2e9SLalit Chandivade goto exit_st_list; 396513483730SMike Christie } 396613483730SMike Christie 39674a4bc2e9SLalit Chandivade max_ddbs = is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX : 39684a4bc2e9SLalit Chandivade MAX_DEV_DB_ENTRIES; 396913483730SMike Christie fw_idx_size = sizeof(struct qla_ddb_index); 397013483730SMike Christie 397113483730SMike Christie for (idx = 0; idx < max_ddbs; idx = next_idx) { 39724a4bc2e9SLalit Chandivade ret = qla4xxx_get_fwddb_entry(ha, idx, fw_ddb_entry, fw_ddb_dma, 39734a4bc2e9SLalit Chandivade NULL, &next_idx, &state, 39744a4bc2e9SLalit Chandivade &conn_err, NULL, &conn_id); 397513483730SMike Christie if (ret == QLA_ERROR) 397613483730SMike Christie break; 397713483730SMike Christie 397813483730SMike Christie if (qla4xxx_verify_boot_idx(ha, idx) != QLA_SUCCESS) 397913483730SMike Christie goto continue_next_st; 398013483730SMike Christie 398113483730SMike Christie /* Check if ST, add to the list_st */ 398213483730SMike Christie if (strlen((char *) fw_ddb_entry->iscsi_name) != 0) 398313483730SMike Christie goto continue_next_st; 398413483730SMike Christie 398513483730SMike Christie st_ddb_idx = vzalloc(fw_idx_size); 398613483730SMike Christie if (!st_ddb_idx) 398713483730SMike Christie break; 398813483730SMike Christie 398913483730SMike Christie st_ddb_idx->fw_ddb_idx = idx; 399013483730SMike Christie 39914a4bc2e9SLalit Chandivade list_add_tail(&st_ddb_idx->list, list_st); 399213483730SMike Christie continue_next_st: 399313483730SMike Christie if (next_idx == 0) 399413483730SMike Christie break; 399513483730SMike Christie } 399613483730SMike Christie 39974a4bc2e9SLalit Chandivade exit_st_list: 39984a4bc2e9SLalit Chandivade if (fw_ddb_entry) 39994a4bc2e9SLalit Chandivade dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma); 40004a4bc2e9SLalit Chandivade } 40014a4bc2e9SLalit Chandivade 40024a4bc2e9SLalit Chandivade /** 40034a4bc2e9SLalit Chandivade * qla4xxx_remove_failed_ddb - Remove inactive or failed ddb from list 40044a4bc2e9SLalit Chandivade * @ha: pointer to adapter structure 40054a4bc2e9SLalit Chandivade * @list_ddb: List from which failed ddb to be removed 40064a4bc2e9SLalit Chandivade * 40074a4bc2e9SLalit Chandivade * Iterate over the list of DDBs and find and remove DDBs that are either in 40084a4bc2e9SLalit Chandivade * no connection active state or failed state 40094a4bc2e9SLalit Chandivade **/ 40104a4bc2e9SLalit Chandivade static void qla4xxx_remove_failed_ddb(struct scsi_qla_host *ha, 40114a4bc2e9SLalit Chandivade struct list_head *list_ddb) 40124a4bc2e9SLalit Chandivade { 40134a4bc2e9SLalit Chandivade struct qla_ddb_index *ddb_idx, *ddb_idx_tmp; 40144a4bc2e9SLalit Chandivade uint32_t next_idx = 0; 40154a4bc2e9SLalit Chandivade uint32_t state = 0, conn_err = 0; 40164a4bc2e9SLalit Chandivade int ret; 40174a4bc2e9SLalit Chandivade 40184a4bc2e9SLalit Chandivade list_for_each_entry_safe(ddb_idx, ddb_idx_tmp, list_ddb, list) { 40194a4bc2e9SLalit Chandivade ret = qla4xxx_get_fwddb_entry(ha, ddb_idx->fw_ddb_idx, 40204a4bc2e9SLalit Chandivade NULL, 0, NULL, &next_idx, &state, 40214a4bc2e9SLalit Chandivade &conn_err, NULL, NULL); 40224a4bc2e9SLalit Chandivade if (ret == QLA_ERROR) 40234a4bc2e9SLalit Chandivade continue; 40244a4bc2e9SLalit Chandivade 40254a4bc2e9SLalit Chandivade if (state == DDB_DS_NO_CONNECTION_ACTIVE || 40264a4bc2e9SLalit Chandivade state == DDB_DS_SESSION_FAILED) { 40274a4bc2e9SLalit Chandivade list_del_init(&ddb_idx->list); 40284a4bc2e9SLalit Chandivade vfree(ddb_idx); 40294a4bc2e9SLalit Chandivade } 40304a4bc2e9SLalit Chandivade } 40314a4bc2e9SLalit Chandivade } 40324a4bc2e9SLalit Chandivade 40334a4bc2e9SLalit Chandivade static int qla4xxx_sess_conn_setup(struct scsi_qla_host *ha, 40344a4bc2e9SLalit Chandivade struct dev_db_entry *fw_ddb_entry, 40354a4bc2e9SLalit Chandivade int is_reset) 40364a4bc2e9SLalit Chandivade { 40374a4bc2e9SLalit Chandivade struct iscsi_cls_session *cls_sess; 40384a4bc2e9SLalit Chandivade struct iscsi_session *sess; 40394a4bc2e9SLalit Chandivade struct iscsi_cls_conn *cls_conn; 40404a4bc2e9SLalit Chandivade struct iscsi_endpoint *ep; 40414a4bc2e9SLalit Chandivade uint16_t cmds_max = 32; 40424a4bc2e9SLalit Chandivade uint16_t conn_id = 0; 40434a4bc2e9SLalit Chandivade uint32_t initial_cmdsn = 0; 40444a4bc2e9SLalit Chandivade int ret = QLA_SUCCESS; 40454a4bc2e9SLalit Chandivade 40464a4bc2e9SLalit Chandivade struct ddb_entry *ddb_entry = NULL; 40474a4bc2e9SLalit Chandivade 40484a4bc2e9SLalit Chandivade /* Create session object, with INVALID_ENTRY, 40494a4bc2e9SLalit Chandivade * the targer_id would get set when we issue the login 40504a4bc2e9SLalit Chandivade */ 40514a4bc2e9SLalit Chandivade cls_sess = iscsi_session_setup(&qla4xxx_iscsi_transport, ha->host, 40524a4bc2e9SLalit Chandivade cmds_max, sizeof(struct ddb_entry), 40534a4bc2e9SLalit Chandivade sizeof(struct ql4_task_data), 40544a4bc2e9SLalit Chandivade initial_cmdsn, INVALID_ENTRY); 40554a4bc2e9SLalit Chandivade if (!cls_sess) { 40564a4bc2e9SLalit Chandivade ret = QLA_ERROR; 40574a4bc2e9SLalit Chandivade goto exit_setup; 40584a4bc2e9SLalit Chandivade } 40594a4bc2e9SLalit Chandivade 40604a4bc2e9SLalit Chandivade /* 40614a4bc2e9SLalit Chandivade * so calling module_put function to decrement the 40624a4bc2e9SLalit Chandivade * reference count. 40634a4bc2e9SLalit Chandivade **/ 40644a4bc2e9SLalit Chandivade module_put(qla4xxx_iscsi_transport.owner); 40654a4bc2e9SLalit Chandivade sess = cls_sess->dd_data; 40664a4bc2e9SLalit Chandivade ddb_entry = sess->dd_data; 40674a4bc2e9SLalit Chandivade ddb_entry->sess = cls_sess; 40684a4bc2e9SLalit Chandivade 40694a4bc2e9SLalit Chandivade cls_sess->recovery_tmo = ql4xsess_recovery_tmo; 40704a4bc2e9SLalit Chandivade memcpy(&ddb_entry->fw_ddb_entry, fw_ddb_entry, 40714a4bc2e9SLalit Chandivade sizeof(struct dev_db_entry)); 40724a4bc2e9SLalit Chandivade 40734a4bc2e9SLalit Chandivade qla4xxx_setup_flash_ddb_entry(ha, ddb_entry); 40744a4bc2e9SLalit Chandivade 40754a4bc2e9SLalit Chandivade cls_conn = iscsi_conn_setup(cls_sess, sizeof(struct qla_conn), conn_id); 40764a4bc2e9SLalit Chandivade 40774a4bc2e9SLalit Chandivade if (!cls_conn) { 40784a4bc2e9SLalit Chandivade ret = QLA_ERROR; 40794a4bc2e9SLalit Chandivade goto exit_setup; 40804a4bc2e9SLalit Chandivade } 40814a4bc2e9SLalit Chandivade 40824a4bc2e9SLalit Chandivade ddb_entry->conn = cls_conn; 40834a4bc2e9SLalit Chandivade 40844a4bc2e9SLalit Chandivade /* Setup ep, for displaying attributes in sysfs */ 40854a4bc2e9SLalit Chandivade ep = qla4xxx_get_ep_fwdb(ha, fw_ddb_entry); 40864a4bc2e9SLalit Chandivade if (ep) { 40874a4bc2e9SLalit Chandivade ep->conn = cls_conn; 40884a4bc2e9SLalit Chandivade cls_conn->ep = ep; 40894a4bc2e9SLalit Chandivade } else { 40904a4bc2e9SLalit Chandivade DEBUG2(ql4_printk(KERN_ERR, ha, "Unable to get ep\n")); 40914a4bc2e9SLalit Chandivade ret = QLA_ERROR; 40924a4bc2e9SLalit Chandivade goto exit_setup; 40934a4bc2e9SLalit Chandivade } 40944a4bc2e9SLalit Chandivade 40954a4bc2e9SLalit Chandivade /* Update sess/conn params */ 40964a4bc2e9SLalit Chandivade qla4xxx_copy_fwddb_param(ha, fw_ddb_entry, cls_sess, cls_conn); 40974a4bc2e9SLalit Chandivade 40984a4bc2e9SLalit Chandivade if (is_reset == RESET_ADAPTER) { 40994a4bc2e9SLalit Chandivade iscsi_block_session(cls_sess); 41004a4bc2e9SLalit Chandivade /* Use the relogin path to discover new devices 41014a4bc2e9SLalit Chandivade * by short-circuting the logic of setting 41024a4bc2e9SLalit Chandivade * timer to relogin - instead set the flags 41034a4bc2e9SLalit Chandivade * to initiate login right away. 41044a4bc2e9SLalit Chandivade */ 41054a4bc2e9SLalit Chandivade set_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags); 41064a4bc2e9SLalit Chandivade set_bit(DF_RELOGIN, &ddb_entry->flags); 41074a4bc2e9SLalit Chandivade } 41084a4bc2e9SLalit Chandivade 41094a4bc2e9SLalit Chandivade exit_setup: 41104a4bc2e9SLalit Chandivade return ret; 41114a4bc2e9SLalit Chandivade } 41124a4bc2e9SLalit Chandivade 41134a4bc2e9SLalit Chandivade static void qla4xxx_build_nt_list(struct scsi_qla_host *ha, 41144a4bc2e9SLalit Chandivade struct list_head *list_nt, int is_reset) 41154a4bc2e9SLalit Chandivade { 41164a4bc2e9SLalit Chandivade struct dev_db_entry *fw_ddb_entry; 41174a4bc2e9SLalit Chandivade dma_addr_t fw_ddb_dma; 41184a4bc2e9SLalit Chandivade int max_ddbs; 41194a4bc2e9SLalit Chandivade int fw_idx_size; 41204a4bc2e9SLalit Chandivade int ret; 41214a4bc2e9SLalit Chandivade uint32_t idx = 0, next_idx = 0; 41224a4bc2e9SLalit Chandivade uint32_t state = 0, conn_err = 0; 41234a4bc2e9SLalit Chandivade uint16_t conn_id = 0; 41244a4bc2e9SLalit Chandivade struct qla_ddb_index *nt_ddb_idx; 41254a4bc2e9SLalit Chandivade 41264a4bc2e9SLalit Chandivade fw_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL, 41274a4bc2e9SLalit Chandivade &fw_ddb_dma); 41284a4bc2e9SLalit Chandivade if (fw_ddb_entry == NULL) { 41294a4bc2e9SLalit Chandivade DEBUG2(ql4_printk(KERN_ERR, ha, "Out of memory\n")); 41304a4bc2e9SLalit Chandivade goto exit_nt_list; 41314a4bc2e9SLalit Chandivade } 41324a4bc2e9SLalit Chandivade max_ddbs = is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX : 41334a4bc2e9SLalit Chandivade MAX_DEV_DB_ENTRIES; 41344a4bc2e9SLalit Chandivade fw_idx_size = sizeof(struct qla_ddb_index); 41354a4bc2e9SLalit Chandivade 41364a4bc2e9SLalit Chandivade for (idx = 0; idx < max_ddbs; idx = next_idx) { 41374a4bc2e9SLalit Chandivade ret = qla4xxx_get_fwddb_entry(ha, idx, fw_ddb_entry, fw_ddb_dma, 41384a4bc2e9SLalit Chandivade NULL, &next_idx, &state, 41394a4bc2e9SLalit Chandivade &conn_err, NULL, &conn_id); 41404a4bc2e9SLalit Chandivade if (ret == QLA_ERROR) 41414a4bc2e9SLalit Chandivade break; 41424a4bc2e9SLalit Chandivade 41434a4bc2e9SLalit Chandivade if (qla4xxx_verify_boot_idx(ha, idx) != QLA_SUCCESS) 41444a4bc2e9SLalit Chandivade goto continue_next_nt; 41454a4bc2e9SLalit Chandivade 41464a4bc2e9SLalit Chandivade /* Check if NT, then add to list it */ 41474a4bc2e9SLalit Chandivade if (strlen((char *) fw_ddb_entry->iscsi_name) == 0) 41484a4bc2e9SLalit Chandivade goto continue_next_nt; 41494a4bc2e9SLalit Chandivade 41504a4bc2e9SLalit Chandivade if (!(state == DDB_DS_NO_CONNECTION_ACTIVE || 41514a4bc2e9SLalit Chandivade state == DDB_DS_SESSION_FAILED)) 41524a4bc2e9SLalit Chandivade goto continue_next_nt; 41534a4bc2e9SLalit Chandivade 41544a4bc2e9SLalit Chandivade DEBUG2(ql4_printk(KERN_INFO, ha, 41554a4bc2e9SLalit Chandivade "Adding DDB to session = 0x%x\n", idx)); 41564a4bc2e9SLalit Chandivade if (is_reset == INIT_ADAPTER) { 41574a4bc2e9SLalit Chandivade nt_ddb_idx = vmalloc(fw_idx_size); 41584a4bc2e9SLalit Chandivade if (!nt_ddb_idx) 41594a4bc2e9SLalit Chandivade break; 41604a4bc2e9SLalit Chandivade 41614a4bc2e9SLalit Chandivade nt_ddb_idx->fw_ddb_idx = idx; 41624a4bc2e9SLalit Chandivade 41634a4bc2e9SLalit Chandivade memcpy(&nt_ddb_idx->fw_ddb, fw_ddb_entry, 41644a4bc2e9SLalit Chandivade sizeof(struct dev_db_entry)); 41654a4bc2e9SLalit Chandivade 41664a4bc2e9SLalit Chandivade if (qla4xxx_is_flash_ddb_exists(ha, list_nt, 41674a4bc2e9SLalit Chandivade fw_ddb_entry) == QLA_SUCCESS) { 41684a4bc2e9SLalit Chandivade vfree(nt_ddb_idx); 41694a4bc2e9SLalit Chandivade goto continue_next_nt; 41704a4bc2e9SLalit Chandivade } 41714a4bc2e9SLalit Chandivade list_add_tail(&nt_ddb_idx->list, list_nt); 41724a4bc2e9SLalit Chandivade } else if (is_reset == RESET_ADAPTER) { 41734a4bc2e9SLalit Chandivade if (qla4xxx_is_session_exists(ha, fw_ddb_entry) == 41744a4bc2e9SLalit Chandivade QLA_SUCCESS) 41754a4bc2e9SLalit Chandivade goto continue_next_nt; 41764a4bc2e9SLalit Chandivade } 41774a4bc2e9SLalit Chandivade 41784a4bc2e9SLalit Chandivade ret = qla4xxx_sess_conn_setup(ha, fw_ddb_entry, is_reset); 41794a4bc2e9SLalit Chandivade if (ret == QLA_ERROR) 41804a4bc2e9SLalit Chandivade goto exit_nt_list; 41814a4bc2e9SLalit Chandivade 41824a4bc2e9SLalit Chandivade continue_next_nt: 41834a4bc2e9SLalit Chandivade if (next_idx == 0) 41844a4bc2e9SLalit Chandivade break; 41854a4bc2e9SLalit Chandivade } 41864a4bc2e9SLalit Chandivade 41874a4bc2e9SLalit Chandivade exit_nt_list: 41884a4bc2e9SLalit Chandivade if (fw_ddb_entry) 41894a4bc2e9SLalit Chandivade dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma); 41904a4bc2e9SLalit Chandivade } 41914a4bc2e9SLalit Chandivade 41924a4bc2e9SLalit Chandivade /** 41934a4bc2e9SLalit Chandivade * qla4xxx_build_ddb_list - Build ddb list and setup sessions 41944a4bc2e9SLalit Chandivade * @ha: pointer to adapter structure 41954a4bc2e9SLalit Chandivade * @is_reset: Is this init path or reset path 41964a4bc2e9SLalit Chandivade * 41974a4bc2e9SLalit Chandivade * Create a list of sendtargets (st) from firmware DDBs, issue send targets 41984a4bc2e9SLalit Chandivade * using connection open, then create the list of normal targets (nt) 41994a4bc2e9SLalit Chandivade * from firmware DDBs. Based on the list of nt setup session and connection 42004a4bc2e9SLalit Chandivade * objects. 42014a4bc2e9SLalit Chandivade **/ 42024a4bc2e9SLalit Chandivade void qla4xxx_build_ddb_list(struct scsi_qla_host *ha, int is_reset) 42034a4bc2e9SLalit Chandivade { 42044a4bc2e9SLalit Chandivade uint16_t tmo = 0; 42054a4bc2e9SLalit Chandivade struct list_head list_st, list_nt; 42064a4bc2e9SLalit Chandivade struct qla_ddb_index *st_ddb_idx, *st_ddb_idx_tmp; 42074a4bc2e9SLalit Chandivade unsigned long wtime; 42084a4bc2e9SLalit Chandivade 42094a4bc2e9SLalit Chandivade if (!test_bit(AF_LINK_UP, &ha->flags)) { 42104a4bc2e9SLalit Chandivade set_bit(AF_BUILD_DDB_LIST, &ha->flags); 42114a4bc2e9SLalit Chandivade ha->is_reset = is_reset; 42124a4bc2e9SLalit Chandivade return; 42134a4bc2e9SLalit Chandivade } 42144a4bc2e9SLalit Chandivade 42154a4bc2e9SLalit Chandivade INIT_LIST_HEAD(&list_st); 42164a4bc2e9SLalit Chandivade INIT_LIST_HEAD(&list_nt); 42174a4bc2e9SLalit Chandivade 42184a4bc2e9SLalit Chandivade qla4xxx_build_st_list(ha, &list_st); 42194a4bc2e9SLalit Chandivade 422013483730SMike Christie /* Before issuing conn open mbox, ensure all IPs states are configured 422113483730SMike Christie * Note, conn open fails if IPs are not configured 422213483730SMike Christie */ 422313483730SMike Christie qla4xxx_wait_for_ip_configuration(ha); 422413483730SMike Christie 422513483730SMike Christie /* Go thru the STs and fire the sendtargets by issuing conn open mbx */ 422613483730SMike Christie list_for_each_entry_safe(st_ddb_idx, st_ddb_idx_tmp, &list_st, list) { 422713483730SMike Christie qla4xxx_conn_open(ha, st_ddb_idx->fw_ddb_idx); 422813483730SMike Christie } 422913483730SMike Christie 423013483730SMike Christie /* Wait to ensure all sendtargets are done for min 12 sec wait */ 423113483730SMike Christie tmo = ((ha->def_timeout < LOGIN_TOV) ? LOGIN_TOV : ha->def_timeout); 423213483730SMike Christie DEBUG2(ql4_printk(KERN_INFO, ha, 423313483730SMike Christie "Default time to wait for build ddb %d\n", tmo)); 423413483730SMike Christie 423513483730SMike Christie wtime = jiffies + (HZ * tmo); 423613483730SMike Christie do { 42374a4bc2e9SLalit Chandivade qla4xxx_remove_failed_ddb(ha, &list_st); 423813483730SMike Christie schedule_timeout_uninterruptible(HZ / 10); 423913483730SMike Christie } while (time_after(wtime, jiffies)); 424013483730SMike Christie 424113483730SMike Christie /* Free up the sendtargets list */ 42424a4bc2e9SLalit Chandivade qla4xxx_free_ddb_list(&list_st); 424313483730SMike Christie 42444a4bc2e9SLalit Chandivade qla4xxx_build_nt_list(ha, &list_nt, is_reset); 424513483730SMike Christie 42464a4bc2e9SLalit Chandivade qla4xxx_free_ddb_list(&list_nt); 424713483730SMike Christie 424813483730SMike Christie qla4xxx_free_ddb_index(ha); 424913483730SMike Christie } 425013483730SMike Christie 4251afaf5a2dSDavid Somayajulu /** 4252afaf5a2dSDavid Somayajulu * qla4xxx_probe_adapter - callback function to probe HBA 4253afaf5a2dSDavid Somayajulu * @pdev: pointer to pci_dev structure 4254afaf5a2dSDavid Somayajulu * @pci_device_id: pointer to pci_device entry 4255afaf5a2dSDavid Somayajulu * 4256afaf5a2dSDavid Somayajulu * This routine will probe for Qlogic 4xxx iSCSI host adapters. 4257afaf5a2dSDavid Somayajulu * It returns zero if successful. It also initializes all data necessary for 4258afaf5a2dSDavid Somayajulu * the driver. 4259afaf5a2dSDavid Somayajulu **/ 4260afaf5a2dSDavid Somayajulu static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, 4261afaf5a2dSDavid Somayajulu const struct pci_device_id *ent) 4262afaf5a2dSDavid Somayajulu { 4263afaf5a2dSDavid Somayajulu int ret = -ENODEV, status; 4264afaf5a2dSDavid Somayajulu struct Scsi_Host *host; 4265afaf5a2dSDavid Somayajulu struct scsi_qla_host *ha; 4266afaf5a2dSDavid Somayajulu uint8_t init_retry_count = 0; 4267afaf5a2dSDavid Somayajulu char buf[34]; 4268f4f5df23SVikas Chaudhary struct qla4_8xxx_legacy_intr_set *nx_legacy_intr; 4269f9880e76SPrasanna Mumbai uint32_t dev_state; 4270afaf5a2dSDavid Somayajulu 4271afaf5a2dSDavid Somayajulu if (pci_enable_device(pdev)) 4272afaf5a2dSDavid Somayajulu return -1; 4273afaf5a2dSDavid Somayajulu 4274b3a271a9SManish Rangankar host = iscsi_host_alloc(&qla4xxx_driver_template, sizeof(*ha), 0); 4275afaf5a2dSDavid Somayajulu if (host == NULL) { 4276afaf5a2dSDavid Somayajulu printk(KERN_WARNING 4277afaf5a2dSDavid Somayajulu "qla4xxx: Couldn't allocate host from scsi layer!\n"); 4278afaf5a2dSDavid Somayajulu goto probe_disable_device; 4279afaf5a2dSDavid Somayajulu } 4280afaf5a2dSDavid Somayajulu 4281afaf5a2dSDavid Somayajulu /* Clear our data area */ 4282b3a271a9SManish Rangankar ha = to_qla_host(host); 4283afaf5a2dSDavid Somayajulu memset(ha, 0, sizeof(*ha)); 4284afaf5a2dSDavid Somayajulu 4285afaf5a2dSDavid Somayajulu /* Save the information from PCI BIOS. */ 4286afaf5a2dSDavid Somayajulu ha->pdev = pdev; 4287afaf5a2dSDavid Somayajulu ha->host = host; 4288afaf5a2dSDavid Somayajulu ha->host_no = host->host_no; 4289afaf5a2dSDavid Somayajulu 42902232be0dSLalit Chandivade pci_enable_pcie_error_reporting(pdev); 42912232be0dSLalit Chandivade 4292f4f5df23SVikas Chaudhary /* Setup Runtime configurable options */ 4293f4f5df23SVikas Chaudhary if (is_qla8022(ha)) { 4294f4f5df23SVikas Chaudhary ha->isp_ops = &qla4_8xxx_isp_ops; 4295f4f5df23SVikas Chaudhary rwlock_init(&ha->hw_lock); 4296f4f5df23SVikas Chaudhary ha->qdr_sn_window = -1; 4297f4f5df23SVikas Chaudhary ha->ddr_mn_window = -1; 4298f4f5df23SVikas Chaudhary ha->curr_window = 255; 4299f4f5df23SVikas Chaudhary ha->func_num = PCI_FUNC(ha->pdev->devfn); 4300f4f5df23SVikas Chaudhary nx_legacy_intr = &legacy_intr[ha->func_num]; 4301f4f5df23SVikas Chaudhary ha->nx_legacy_intr.int_vec_bit = nx_legacy_intr->int_vec_bit; 4302f4f5df23SVikas Chaudhary ha->nx_legacy_intr.tgt_status_reg = 4303f4f5df23SVikas Chaudhary nx_legacy_intr->tgt_status_reg; 4304f4f5df23SVikas Chaudhary ha->nx_legacy_intr.tgt_mask_reg = nx_legacy_intr->tgt_mask_reg; 4305f4f5df23SVikas Chaudhary ha->nx_legacy_intr.pci_int_reg = nx_legacy_intr->pci_int_reg; 4306f4f5df23SVikas Chaudhary } else { 4307f4f5df23SVikas Chaudhary ha->isp_ops = &qla4xxx_isp_ops; 4308f4f5df23SVikas Chaudhary } 4309f4f5df23SVikas Chaudhary 43102232be0dSLalit Chandivade /* Set EEH reset type to fundamental if required by hba */ 43112232be0dSLalit Chandivade if (is_qla8022(ha)) 43122232be0dSLalit Chandivade pdev->needs_freset = 1; 43132232be0dSLalit Chandivade 4314afaf5a2dSDavid Somayajulu /* Configure PCI I/O space. */ 4315f4f5df23SVikas Chaudhary ret = ha->isp_ops->iospace_config(ha); 4316afaf5a2dSDavid Somayajulu if (ret) 4317f4f5df23SVikas Chaudhary goto probe_failed_ioconfig; 4318afaf5a2dSDavid Somayajulu 4319c2660df3SVikas Chaudhary ql4_printk(KERN_INFO, ha, "Found an ISP%04x, irq %d, iobase 0x%p\n", 4320afaf5a2dSDavid Somayajulu pdev->device, pdev->irq, ha->reg); 4321afaf5a2dSDavid Somayajulu 4322afaf5a2dSDavid Somayajulu qla4xxx_config_dma_addressing(ha); 4323afaf5a2dSDavid Somayajulu 4324afaf5a2dSDavid Somayajulu /* Initialize lists and spinlocks. */ 4325afaf5a2dSDavid Somayajulu INIT_LIST_HEAD(&ha->free_srb_q); 4326afaf5a2dSDavid Somayajulu 4327afaf5a2dSDavid Somayajulu mutex_init(&ha->mbox_sem); 43284549415aSLalit Chandivade mutex_init(&ha->chap_sem); 4329f4f5df23SVikas Chaudhary init_completion(&ha->mbx_intr_comp); 433095d31262SVikas Chaudhary init_completion(&ha->disable_acb_comp); 4331afaf5a2dSDavid Somayajulu 4332afaf5a2dSDavid Somayajulu spin_lock_init(&ha->hardware_lock); 4333afaf5a2dSDavid Somayajulu 4334afaf5a2dSDavid Somayajulu /* Allocate dma buffers */ 4335afaf5a2dSDavid Somayajulu if (qla4xxx_mem_alloc(ha)) { 4336c2660df3SVikas Chaudhary ql4_printk(KERN_WARNING, ha, 4337afaf5a2dSDavid Somayajulu "[ERROR] Failed to allocate memory for adapter\n"); 4338afaf5a2dSDavid Somayajulu 4339afaf5a2dSDavid Somayajulu ret = -ENOMEM; 4340afaf5a2dSDavid Somayajulu goto probe_failed; 4341afaf5a2dSDavid Somayajulu } 4342afaf5a2dSDavid Somayajulu 4343b3a271a9SManish Rangankar host->cmd_per_lun = 3; 4344b3a271a9SManish Rangankar host->max_channel = 0; 4345b3a271a9SManish Rangankar host->max_lun = MAX_LUNS - 1; 4346b3a271a9SManish Rangankar host->max_id = MAX_TARGETS; 4347b3a271a9SManish Rangankar host->max_cmd_len = IOCB_MAX_CDB_LEN; 4348b3a271a9SManish Rangankar host->can_queue = MAX_SRBS ; 4349b3a271a9SManish Rangankar host->transportt = qla4xxx_scsi_transport; 4350b3a271a9SManish Rangankar 4351b3a271a9SManish Rangankar ret = scsi_init_shared_tag_map(host, MAX_SRBS); 4352b3a271a9SManish Rangankar if (ret) { 4353b3a271a9SManish Rangankar ql4_printk(KERN_WARNING, ha, 4354b3a271a9SManish Rangankar "%s: scsi_init_shared_tag_map failed\n", __func__); 4355b3a271a9SManish Rangankar goto probe_failed; 4356b3a271a9SManish Rangankar } 4357b3a271a9SManish Rangankar 4358b3a271a9SManish Rangankar pci_set_drvdata(pdev, ha); 4359b3a271a9SManish Rangankar 4360b3a271a9SManish Rangankar ret = scsi_add_host(host, &pdev->dev); 4361b3a271a9SManish Rangankar if (ret) 4362b3a271a9SManish Rangankar goto probe_failed; 4363b3a271a9SManish Rangankar 4364f4f5df23SVikas Chaudhary if (is_qla8022(ha)) 4365f4f5df23SVikas Chaudhary (void) qla4_8xxx_get_flash_info(ha); 4366f4f5df23SVikas Chaudhary 4367afaf5a2dSDavid Somayajulu /* 4368afaf5a2dSDavid Somayajulu * Initialize the Host adapter request/response queues and 4369afaf5a2dSDavid Somayajulu * firmware 4370afaf5a2dSDavid Somayajulu * NOTE: interrupts enabled upon successful completion 4371afaf5a2dSDavid Somayajulu */ 437213483730SMike Christie status = qla4xxx_initialize_adapter(ha, INIT_ADAPTER); 4373f4f5df23SVikas Chaudhary while ((!test_bit(AF_ONLINE, &ha->flags)) && 4374f4f5df23SVikas Chaudhary init_retry_count++ < MAX_INIT_RETRIES) { 4375f9880e76SPrasanna Mumbai 4376f9880e76SPrasanna Mumbai if (is_qla8022(ha)) { 4377f9880e76SPrasanna Mumbai qla4_8xxx_idc_lock(ha); 4378f9880e76SPrasanna Mumbai dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE); 4379f9880e76SPrasanna Mumbai qla4_8xxx_idc_unlock(ha); 4380f9880e76SPrasanna Mumbai if (dev_state == QLA82XX_DEV_FAILED) { 4381f9880e76SPrasanna Mumbai ql4_printk(KERN_WARNING, ha, "%s: don't retry " 4382f9880e76SPrasanna Mumbai "initialize adapter. H/W is in failed state\n", 4383f9880e76SPrasanna Mumbai __func__); 4384f9880e76SPrasanna Mumbai break; 4385f9880e76SPrasanna Mumbai } 4386f9880e76SPrasanna Mumbai } 4387afaf5a2dSDavid Somayajulu DEBUG2(printk("scsi: %s: retrying adapter initialization " 4388afaf5a2dSDavid Somayajulu "(%d)\n", __func__, init_retry_count)); 4389f4f5df23SVikas Chaudhary 4390f4f5df23SVikas Chaudhary if (ha->isp_ops->reset_chip(ha) == QLA_ERROR) 4391f4f5df23SVikas Chaudhary continue; 4392f4f5df23SVikas Chaudhary 439313483730SMike Christie status = qla4xxx_initialize_adapter(ha, INIT_ADAPTER); 4394afaf5a2dSDavid Somayajulu } 4395f4f5df23SVikas Chaudhary 4396f4f5df23SVikas Chaudhary if (!test_bit(AF_ONLINE, &ha->flags)) { 4397c2660df3SVikas Chaudhary ql4_printk(KERN_WARNING, ha, "Failed to initialize adapter\n"); 4398afaf5a2dSDavid Somayajulu 4399fe998527SLalit Chandivade if (is_qla8022(ha) && ql4xdontresethba) { 4400fe998527SLalit Chandivade /* Put the device in failed state. */ 4401fe998527SLalit Chandivade DEBUG2(printk(KERN_ERR "HW STATE: FAILED\n")); 4402fe998527SLalit Chandivade qla4_8xxx_idc_lock(ha); 4403fe998527SLalit Chandivade qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, 4404fe998527SLalit Chandivade QLA82XX_DEV_FAILED); 4405fe998527SLalit Chandivade qla4_8xxx_idc_unlock(ha); 4406fe998527SLalit Chandivade } 4407afaf5a2dSDavid Somayajulu ret = -ENODEV; 4408b3a271a9SManish Rangankar goto remove_host; 4409afaf5a2dSDavid Somayajulu } 4410afaf5a2dSDavid Somayajulu 4411afaf5a2dSDavid Somayajulu /* Startup the kernel thread for this host adapter. */ 4412afaf5a2dSDavid Somayajulu DEBUG2(printk("scsi: %s: Starting kernel thread for " 4413afaf5a2dSDavid Somayajulu "qla4xxx_dpc\n", __func__)); 4414afaf5a2dSDavid Somayajulu sprintf(buf, "qla4xxx_%lu_dpc", ha->host_no); 4415afaf5a2dSDavid Somayajulu ha->dpc_thread = create_singlethread_workqueue(buf); 4416afaf5a2dSDavid Somayajulu if (!ha->dpc_thread) { 4417c2660df3SVikas Chaudhary ql4_printk(KERN_WARNING, ha, "Unable to start DPC thread!\n"); 4418afaf5a2dSDavid Somayajulu ret = -ENODEV; 4419b3a271a9SManish Rangankar goto remove_host; 4420afaf5a2dSDavid Somayajulu } 4421c4028958SDavid Howells INIT_WORK(&ha->dpc_work, qla4xxx_do_dpc); 4422afaf5a2dSDavid Somayajulu 4423b3a271a9SManish Rangankar sprintf(buf, "qla4xxx_%lu_task", ha->host_no); 4424b3a271a9SManish Rangankar ha->task_wq = alloc_workqueue(buf, WQ_MEM_RECLAIM, 1); 4425b3a271a9SManish Rangankar if (!ha->task_wq) { 4426b3a271a9SManish Rangankar ql4_printk(KERN_WARNING, ha, "Unable to start task thread!\n"); 4427b3a271a9SManish Rangankar ret = -ENODEV; 4428b3a271a9SManish Rangankar goto remove_host; 4429b3a271a9SManish Rangankar } 4430b3a271a9SManish Rangankar 4431f4f5df23SVikas Chaudhary /* For ISP-82XX, request_irqs is called in qla4_8xxx_load_risc 4432f4f5df23SVikas Chaudhary * (which is called indirectly by qla4xxx_initialize_adapter), 4433f4f5df23SVikas Chaudhary * so that irqs will be registered after crbinit but before 4434f4f5df23SVikas Chaudhary * mbx_intr_enable. 4435f4f5df23SVikas Chaudhary */ 4436f4f5df23SVikas Chaudhary if (!is_qla8022(ha)) { 4437f4f5df23SVikas Chaudhary ret = qla4xxx_request_irqs(ha); 4438afaf5a2dSDavid Somayajulu if (ret) { 4439f4f5df23SVikas Chaudhary ql4_printk(KERN_WARNING, ha, "Failed to reserve " 4440f4f5df23SVikas Chaudhary "interrupt %d already in use.\n", pdev->irq); 4441b3a271a9SManish Rangankar goto remove_host; 4442afaf5a2dSDavid Somayajulu } 4443f4f5df23SVikas Chaudhary } 4444afaf5a2dSDavid Somayajulu 44452232be0dSLalit Chandivade pci_save_state(ha->pdev); 4446f4f5df23SVikas Chaudhary ha->isp_ops->enable_intrs(ha); 4447afaf5a2dSDavid Somayajulu 4448afaf5a2dSDavid Somayajulu /* Start timer thread. */ 4449afaf5a2dSDavid Somayajulu qla4xxx_start_timer(ha, qla4xxx_timer, 1); 4450afaf5a2dSDavid Somayajulu 4451afaf5a2dSDavid Somayajulu set_bit(AF_INIT_DONE, &ha->flags); 4452afaf5a2dSDavid Somayajulu 4453afaf5a2dSDavid Somayajulu printk(KERN_INFO 4454afaf5a2dSDavid Somayajulu " QLogic iSCSI HBA Driver version: %s\n" 4455afaf5a2dSDavid Somayajulu " QLogic ISP%04x @ %s, host#=%ld, fw=%02d.%02d.%02d.%02d\n", 4456afaf5a2dSDavid Somayajulu qla4xxx_version_str, ha->pdev->device, pci_name(ha->pdev), 4457afaf5a2dSDavid Somayajulu ha->host_no, ha->firmware_version[0], ha->firmware_version[1], 4458afaf5a2dSDavid Somayajulu ha->patch_number, ha->build_number); 4459ed1086e0SVikas Chaudhary 44602a991c21SManish Rangankar if (qla4xxx_setup_boot_info(ha)) 44612a991c21SManish Rangankar ql4_printk(KERN_ERR, ha, "%s:ISCSI boot info setup failed\n", 44622a991c21SManish Rangankar __func__); 44632a991c21SManish Rangankar 446413483730SMike Christie /* Perform the build ddb list and login to each */ 446513483730SMike Christie qla4xxx_build_ddb_list(ha, INIT_ADAPTER); 446613483730SMike Christie iscsi_host_for_each_session(ha->host, qla4xxx_login_flash_ddb); 446713483730SMike Christie 446813483730SMike Christie qla4xxx_create_chap_list(ha); 446913483730SMike Christie 4470ed1086e0SVikas Chaudhary qla4xxx_create_ifaces(ha); 4471afaf5a2dSDavid Somayajulu return 0; 4472afaf5a2dSDavid Somayajulu 4473b3a271a9SManish Rangankar remove_host: 4474b3a271a9SManish Rangankar scsi_remove_host(ha->host); 4475b3a271a9SManish Rangankar 4476afaf5a2dSDavid Somayajulu probe_failed: 4477afaf5a2dSDavid Somayajulu qla4xxx_free_adapter(ha); 4478f4f5df23SVikas Chaudhary 4479f4f5df23SVikas Chaudhary probe_failed_ioconfig: 44802232be0dSLalit Chandivade pci_disable_pcie_error_reporting(pdev); 4481afaf5a2dSDavid Somayajulu scsi_host_put(ha->host); 4482afaf5a2dSDavid Somayajulu 4483afaf5a2dSDavid Somayajulu probe_disable_device: 4484afaf5a2dSDavid Somayajulu pci_disable_device(pdev); 4485afaf5a2dSDavid Somayajulu 4486afaf5a2dSDavid Somayajulu return ret; 4487afaf5a2dSDavid Somayajulu } 4488afaf5a2dSDavid Somayajulu 4489afaf5a2dSDavid Somayajulu /** 44907eece5a0SKaren Higgins * qla4xxx_prevent_other_port_reinit - prevent other port from re-initialize 44917eece5a0SKaren Higgins * @ha: pointer to adapter structure 44927eece5a0SKaren Higgins * 44937eece5a0SKaren Higgins * Mark the other ISP-4xxx port to indicate that the driver is being removed, 44947eece5a0SKaren Higgins * so that the other port will not re-initialize while in the process of 44957eece5a0SKaren Higgins * removing the ha due to driver unload or hba hotplug. 44967eece5a0SKaren Higgins **/ 44977eece5a0SKaren Higgins static void qla4xxx_prevent_other_port_reinit(struct scsi_qla_host *ha) 44987eece5a0SKaren Higgins { 44997eece5a0SKaren Higgins struct scsi_qla_host *other_ha = NULL; 45007eece5a0SKaren Higgins struct pci_dev *other_pdev = NULL; 45017eece5a0SKaren Higgins int fn = ISP4XXX_PCI_FN_2; 45027eece5a0SKaren Higgins 45037eece5a0SKaren Higgins /*iscsi function numbers for ISP4xxx is 1 and 3*/ 45047eece5a0SKaren Higgins if (PCI_FUNC(ha->pdev->devfn) & BIT_1) 45057eece5a0SKaren Higgins fn = ISP4XXX_PCI_FN_1; 45067eece5a0SKaren Higgins 45077eece5a0SKaren Higgins other_pdev = 45087eece5a0SKaren Higgins pci_get_domain_bus_and_slot(pci_domain_nr(ha->pdev->bus), 45097eece5a0SKaren Higgins ha->pdev->bus->number, PCI_DEVFN(PCI_SLOT(ha->pdev->devfn), 45107eece5a0SKaren Higgins fn)); 45117eece5a0SKaren Higgins 45127eece5a0SKaren Higgins /* Get other_ha if other_pdev is valid and state is enable*/ 45137eece5a0SKaren Higgins if (other_pdev) { 45147eece5a0SKaren Higgins if (atomic_read(&other_pdev->enable_cnt)) { 45157eece5a0SKaren Higgins other_ha = pci_get_drvdata(other_pdev); 45167eece5a0SKaren Higgins if (other_ha) { 45177eece5a0SKaren Higgins set_bit(AF_HA_REMOVAL, &other_ha->flags); 45187eece5a0SKaren Higgins DEBUG2(ql4_printk(KERN_INFO, ha, "%s: " 45197eece5a0SKaren Higgins "Prevent %s reinit\n", __func__, 45207eece5a0SKaren Higgins dev_name(&other_ha->pdev->dev))); 45217eece5a0SKaren Higgins } 45227eece5a0SKaren Higgins } 45237eece5a0SKaren Higgins pci_dev_put(other_pdev); 45247eece5a0SKaren Higgins } 45257eece5a0SKaren Higgins } 45267eece5a0SKaren Higgins 452713483730SMike Christie static void qla4xxx_destroy_fw_ddb_session(struct scsi_qla_host *ha) 452813483730SMike Christie { 452913483730SMike Christie struct ddb_entry *ddb_entry; 453013483730SMike Christie int options; 453113483730SMike Christie int idx; 453213483730SMike Christie 453313483730SMike Christie for (idx = 0; idx < MAX_DDB_ENTRIES; idx++) { 453413483730SMike Christie 453513483730SMike Christie ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx); 453613483730SMike Christie if ((ddb_entry != NULL) && 453713483730SMike Christie (ddb_entry->ddb_type == FLASH_DDB)) { 453813483730SMike Christie 453913483730SMike Christie options = LOGOUT_OPTION_CLOSE_SESSION; 454013483730SMike Christie if (qla4xxx_session_logout_ddb(ha, ddb_entry, options) 454113483730SMike Christie == QLA_ERROR) 454213483730SMike Christie ql4_printk(KERN_ERR, ha, "%s: Logout failed\n", 454313483730SMike Christie __func__); 454413483730SMike Christie 454513483730SMike Christie qla4xxx_clear_ddb_entry(ha, ddb_entry->fw_ddb_index); 454613483730SMike Christie /* 454713483730SMike Christie * we have decremented the reference count of the driver 454813483730SMike Christie * when we setup the session to have the driver unload 454913483730SMike Christie * to be seamless without actually destroying the 455013483730SMike Christie * session 455113483730SMike Christie **/ 455213483730SMike Christie try_module_get(qla4xxx_iscsi_transport.owner); 455313483730SMike Christie iscsi_destroy_endpoint(ddb_entry->conn->ep); 455413483730SMike Christie qla4xxx_free_ddb(ha, ddb_entry); 455513483730SMike Christie iscsi_session_teardown(ddb_entry->sess); 455613483730SMike Christie } 455713483730SMike Christie } 455813483730SMike Christie } 45597eece5a0SKaren Higgins /** 4560afaf5a2dSDavid Somayajulu * qla4xxx_remove_adapter - calback function to remove adapter. 4561afaf5a2dSDavid Somayajulu * @pci_dev: PCI device pointer 4562afaf5a2dSDavid Somayajulu **/ 4563afaf5a2dSDavid Somayajulu static void __devexit qla4xxx_remove_adapter(struct pci_dev *pdev) 4564afaf5a2dSDavid Somayajulu { 4565afaf5a2dSDavid Somayajulu struct scsi_qla_host *ha; 4566afaf5a2dSDavid Somayajulu 4567afaf5a2dSDavid Somayajulu ha = pci_get_drvdata(pdev); 4568afaf5a2dSDavid Somayajulu 45697eece5a0SKaren Higgins if (!is_qla8022(ha)) 45707eece5a0SKaren Higgins qla4xxx_prevent_other_port_reinit(ha); 4571bee4fe8eSDavid C Somayajulu 4572ed1086e0SVikas Chaudhary /* destroy iface from sysfs */ 4573ed1086e0SVikas Chaudhary qla4xxx_destroy_ifaces(ha); 4574ed1086e0SVikas Chaudhary 457513483730SMike Christie if ((!ql4xdisablesysfsboot) && ha->boot_kset) 45762a991c21SManish Rangankar iscsi_boot_destroy_kset(ha->boot_kset); 45772a991c21SManish Rangankar 457813483730SMike Christie qla4xxx_destroy_fw_ddb_session(ha); 457913483730SMike Christie 4580afaf5a2dSDavid Somayajulu scsi_remove_host(ha->host); 4581afaf5a2dSDavid Somayajulu 4582afaf5a2dSDavid Somayajulu qla4xxx_free_adapter(ha); 4583afaf5a2dSDavid Somayajulu 4584afaf5a2dSDavid Somayajulu scsi_host_put(ha->host); 4585afaf5a2dSDavid Somayajulu 45862232be0dSLalit Chandivade pci_disable_pcie_error_reporting(pdev); 4587f4f5df23SVikas Chaudhary pci_disable_device(pdev); 4588afaf5a2dSDavid Somayajulu pci_set_drvdata(pdev, NULL); 4589afaf5a2dSDavid Somayajulu } 4590afaf5a2dSDavid Somayajulu 4591afaf5a2dSDavid Somayajulu /** 4592afaf5a2dSDavid Somayajulu * qla4xxx_config_dma_addressing() - Configure OS DMA addressing method. 4593afaf5a2dSDavid Somayajulu * @ha: HA context 4594afaf5a2dSDavid Somayajulu * 4595afaf5a2dSDavid Somayajulu * At exit, the @ha's flags.enable_64bit_addressing set to indicated 4596afaf5a2dSDavid Somayajulu * supported addressing method. 4597afaf5a2dSDavid Somayajulu */ 459847975477SAdrian Bunk static void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha) 4599afaf5a2dSDavid Somayajulu { 4600afaf5a2dSDavid Somayajulu int retval; 4601afaf5a2dSDavid Somayajulu 4602afaf5a2dSDavid Somayajulu /* Update our PCI device dma_mask for full 64 bit mask */ 46036a35528aSYang Hongyang if (pci_set_dma_mask(ha->pdev, DMA_BIT_MASK(64)) == 0) { 46046a35528aSYang Hongyang if (pci_set_consistent_dma_mask(ha->pdev, DMA_BIT_MASK(64))) { 4605afaf5a2dSDavid Somayajulu dev_dbg(&ha->pdev->dev, 4606afaf5a2dSDavid Somayajulu "Failed to set 64 bit PCI consistent mask; " 4607afaf5a2dSDavid Somayajulu "using 32 bit.\n"); 4608afaf5a2dSDavid Somayajulu retval = pci_set_consistent_dma_mask(ha->pdev, 4609284901a9SYang Hongyang DMA_BIT_MASK(32)); 4610afaf5a2dSDavid Somayajulu } 4611afaf5a2dSDavid Somayajulu } else 4612284901a9SYang Hongyang retval = pci_set_dma_mask(ha->pdev, DMA_BIT_MASK(32)); 4613afaf5a2dSDavid Somayajulu } 4614afaf5a2dSDavid Somayajulu 4615afaf5a2dSDavid Somayajulu static int qla4xxx_slave_alloc(struct scsi_device *sdev) 4616afaf5a2dSDavid Somayajulu { 4617b3a271a9SManish Rangankar struct iscsi_cls_session *cls_sess; 4618b3a271a9SManish Rangankar struct iscsi_session *sess; 4619b3a271a9SManish Rangankar struct ddb_entry *ddb; 46208bb4033dSVikas Chaudhary int queue_depth = QL4_DEF_QDEPTH; 4621afaf5a2dSDavid Somayajulu 4622b3a271a9SManish Rangankar cls_sess = starget_to_session(sdev->sdev_target); 4623b3a271a9SManish Rangankar sess = cls_sess->dd_data; 4624b3a271a9SManish Rangankar ddb = sess->dd_data; 4625b3a271a9SManish Rangankar 4626afaf5a2dSDavid Somayajulu sdev->hostdata = ddb; 4627afaf5a2dSDavid Somayajulu sdev->tagged_supported = 1; 46288bb4033dSVikas Chaudhary 46298bb4033dSVikas Chaudhary if (ql4xmaxqdepth != 0 && ql4xmaxqdepth <= 0xffffU) 46308bb4033dSVikas Chaudhary queue_depth = ql4xmaxqdepth; 46318bb4033dSVikas Chaudhary 46328bb4033dSVikas Chaudhary scsi_activate_tcq(sdev, queue_depth); 4633afaf5a2dSDavid Somayajulu return 0; 4634afaf5a2dSDavid Somayajulu } 4635afaf5a2dSDavid Somayajulu 4636afaf5a2dSDavid Somayajulu static int qla4xxx_slave_configure(struct scsi_device *sdev) 4637afaf5a2dSDavid Somayajulu { 4638afaf5a2dSDavid Somayajulu sdev->tagged_supported = 1; 4639afaf5a2dSDavid Somayajulu return 0; 4640afaf5a2dSDavid Somayajulu } 4641afaf5a2dSDavid Somayajulu 4642afaf5a2dSDavid Somayajulu static void qla4xxx_slave_destroy(struct scsi_device *sdev) 4643afaf5a2dSDavid Somayajulu { 4644afaf5a2dSDavid Somayajulu scsi_deactivate_tcq(sdev, 1); 4645afaf5a2dSDavid Somayajulu } 4646afaf5a2dSDavid Somayajulu 4647afaf5a2dSDavid Somayajulu /** 4648afaf5a2dSDavid Somayajulu * qla4xxx_del_from_active_array - returns an active srb 4649afaf5a2dSDavid Somayajulu * @ha: Pointer to host adapter structure. 4650fd589a8fSAnand Gadiyar * @index: index into the active_array 4651afaf5a2dSDavid Somayajulu * 4652afaf5a2dSDavid Somayajulu * This routine removes and returns the srb at the specified index 4653afaf5a2dSDavid Somayajulu **/ 4654f4f5df23SVikas Chaudhary struct srb *qla4xxx_del_from_active_array(struct scsi_qla_host *ha, 4655f4f5df23SVikas Chaudhary uint32_t index) 4656afaf5a2dSDavid Somayajulu { 4657afaf5a2dSDavid Somayajulu struct srb *srb = NULL; 46585369887aSVikas Chaudhary struct scsi_cmnd *cmd = NULL; 4659afaf5a2dSDavid Somayajulu 46605369887aSVikas Chaudhary cmd = scsi_host_find_tag(ha->host, index); 46615369887aSVikas Chaudhary if (!cmd) 4662afaf5a2dSDavid Somayajulu return srb; 4663afaf5a2dSDavid Somayajulu 46645369887aSVikas Chaudhary srb = (struct srb *)CMD_SP(cmd); 46655369887aSVikas Chaudhary if (!srb) 4666afaf5a2dSDavid Somayajulu return srb; 4667afaf5a2dSDavid Somayajulu 4668afaf5a2dSDavid Somayajulu /* update counters */ 4669afaf5a2dSDavid Somayajulu if (srb->flags & SRB_DMA_VALID) { 4670afaf5a2dSDavid Somayajulu ha->req_q_count += srb->iocb_cnt; 4671afaf5a2dSDavid Somayajulu ha->iocb_cnt -= srb->iocb_cnt; 4672afaf5a2dSDavid Somayajulu if (srb->cmd) 46735369887aSVikas Chaudhary srb->cmd->host_scribble = 46745369887aSVikas Chaudhary (unsigned char *)(unsigned long) MAX_SRBS; 4675afaf5a2dSDavid Somayajulu } 4676afaf5a2dSDavid Somayajulu return srb; 4677afaf5a2dSDavid Somayajulu } 4678afaf5a2dSDavid Somayajulu 4679afaf5a2dSDavid Somayajulu /** 4680afaf5a2dSDavid Somayajulu * qla4xxx_eh_wait_on_command - waits for command to be returned by firmware 468109a0f719SVikas Chaudhary * @ha: Pointer to host adapter structure. 4682afaf5a2dSDavid Somayajulu * @cmd: Scsi Command to wait on. 4683afaf5a2dSDavid Somayajulu * 4684afaf5a2dSDavid Somayajulu * This routine waits for the command to be returned by the Firmware 4685afaf5a2dSDavid Somayajulu * for some max time. 4686afaf5a2dSDavid Somayajulu **/ 4687afaf5a2dSDavid Somayajulu static int qla4xxx_eh_wait_on_command(struct scsi_qla_host *ha, 4688afaf5a2dSDavid Somayajulu struct scsi_cmnd *cmd) 4689afaf5a2dSDavid Somayajulu { 4690afaf5a2dSDavid Somayajulu int done = 0; 4691afaf5a2dSDavid Somayajulu struct srb *rp; 4692afaf5a2dSDavid Somayajulu uint32_t max_wait_time = EH_WAIT_CMD_TOV; 46932232be0dSLalit Chandivade int ret = SUCCESS; 46942232be0dSLalit Chandivade 46952232be0dSLalit Chandivade /* Dont wait on command if PCI error is being handled 46962232be0dSLalit Chandivade * by PCI AER driver 46972232be0dSLalit Chandivade */ 46982232be0dSLalit Chandivade if (unlikely(pci_channel_offline(ha->pdev)) || 46992232be0dSLalit Chandivade (test_bit(AF_EEH_BUSY, &ha->flags))) { 47002232be0dSLalit Chandivade ql4_printk(KERN_WARNING, ha, "scsi%ld: Return from %s\n", 47012232be0dSLalit Chandivade ha->host_no, __func__); 47022232be0dSLalit Chandivade return ret; 47032232be0dSLalit Chandivade } 4704afaf5a2dSDavid Somayajulu 4705afaf5a2dSDavid Somayajulu do { 4706afaf5a2dSDavid Somayajulu /* Checking to see if its returned to OS */ 47075369887aSVikas Chaudhary rp = (struct srb *) CMD_SP(cmd); 4708afaf5a2dSDavid Somayajulu if (rp == NULL) { 4709afaf5a2dSDavid Somayajulu done++; 4710afaf5a2dSDavid Somayajulu break; 4711afaf5a2dSDavid Somayajulu } 4712afaf5a2dSDavid Somayajulu 4713afaf5a2dSDavid Somayajulu msleep(2000); 4714afaf5a2dSDavid Somayajulu } while (max_wait_time--); 4715afaf5a2dSDavid Somayajulu 4716afaf5a2dSDavid Somayajulu return done; 4717afaf5a2dSDavid Somayajulu } 4718afaf5a2dSDavid Somayajulu 4719afaf5a2dSDavid Somayajulu /** 4720afaf5a2dSDavid Somayajulu * qla4xxx_wait_for_hba_online - waits for HBA to come online 4721afaf5a2dSDavid Somayajulu * @ha: Pointer to host adapter structure 4722afaf5a2dSDavid Somayajulu **/ 4723afaf5a2dSDavid Somayajulu static int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha) 4724afaf5a2dSDavid Somayajulu { 4725afaf5a2dSDavid Somayajulu unsigned long wait_online; 4726afaf5a2dSDavid Somayajulu 4727f581a3f7SVikas Chaudhary wait_online = jiffies + (HBA_ONLINE_TOV * HZ); 4728afaf5a2dSDavid Somayajulu while (time_before(jiffies, wait_online)) { 4729afaf5a2dSDavid Somayajulu 4730afaf5a2dSDavid Somayajulu if (adapter_up(ha)) 4731afaf5a2dSDavid Somayajulu return QLA_SUCCESS; 4732afaf5a2dSDavid Somayajulu 4733afaf5a2dSDavid Somayajulu msleep(2000); 4734afaf5a2dSDavid Somayajulu } 4735afaf5a2dSDavid Somayajulu 4736afaf5a2dSDavid Somayajulu return QLA_ERROR; 4737afaf5a2dSDavid Somayajulu } 4738afaf5a2dSDavid Somayajulu 4739afaf5a2dSDavid Somayajulu /** 4740ce545039SMike Christie * qla4xxx_eh_wait_for_commands - wait for active cmds to finish. 4741fd589a8fSAnand Gadiyar * @ha: pointer to HBA 4742afaf5a2dSDavid Somayajulu * @t: target id 4743afaf5a2dSDavid Somayajulu * @l: lun id 4744afaf5a2dSDavid Somayajulu * 4745afaf5a2dSDavid Somayajulu * This function waits for all outstanding commands to a lun to complete. It 4746afaf5a2dSDavid Somayajulu * returns 0 if all pending commands are returned and 1 otherwise. 4747afaf5a2dSDavid Somayajulu **/ 4748ce545039SMike Christie static int qla4xxx_eh_wait_for_commands(struct scsi_qla_host *ha, 4749ce545039SMike Christie struct scsi_target *stgt, 4750ce545039SMike Christie struct scsi_device *sdev) 4751afaf5a2dSDavid Somayajulu { 4752afaf5a2dSDavid Somayajulu int cnt; 4753afaf5a2dSDavid Somayajulu int status = 0; 4754afaf5a2dSDavid Somayajulu struct scsi_cmnd *cmd; 4755afaf5a2dSDavid Somayajulu 4756afaf5a2dSDavid Somayajulu /* 4757ce545039SMike Christie * Waiting for all commands for the designated target or dev 4758ce545039SMike Christie * in the active array 4759afaf5a2dSDavid Somayajulu */ 4760afaf5a2dSDavid Somayajulu for (cnt = 0; cnt < ha->host->can_queue; cnt++) { 4761afaf5a2dSDavid Somayajulu cmd = scsi_host_find_tag(ha->host, cnt); 4762ce545039SMike Christie if (cmd && stgt == scsi_target(cmd->device) && 4763ce545039SMike Christie (!sdev || sdev == cmd->device)) { 4764afaf5a2dSDavid Somayajulu if (!qla4xxx_eh_wait_on_command(ha, cmd)) { 4765afaf5a2dSDavid Somayajulu status++; 4766afaf5a2dSDavid Somayajulu break; 4767afaf5a2dSDavid Somayajulu } 4768afaf5a2dSDavid Somayajulu } 4769afaf5a2dSDavid Somayajulu } 4770afaf5a2dSDavid Somayajulu return status; 4771afaf5a2dSDavid Somayajulu } 4772afaf5a2dSDavid Somayajulu 4773afaf5a2dSDavid Somayajulu /** 477409a0f719SVikas Chaudhary * qla4xxx_eh_abort - callback for abort task. 477509a0f719SVikas Chaudhary * @cmd: Pointer to Linux's SCSI command structure 477609a0f719SVikas Chaudhary * 477709a0f719SVikas Chaudhary * This routine is called by the Linux OS to abort the specified 477809a0f719SVikas Chaudhary * command. 477909a0f719SVikas Chaudhary **/ 478009a0f719SVikas Chaudhary static int qla4xxx_eh_abort(struct scsi_cmnd *cmd) 478109a0f719SVikas Chaudhary { 478209a0f719SVikas Chaudhary struct scsi_qla_host *ha = to_qla_host(cmd->device->host); 478309a0f719SVikas Chaudhary unsigned int id = cmd->device->id; 478409a0f719SVikas Chaudhary unsigned int lun = cmd->device->lun; 478592b3e5bbSMike Christie unsigned long flags; 478609a0f719SVikas Chaudhary struct srb *srb = NULL; 478709a0f719SVikas Chaudhary int ret = SUCCESS; 478809a0f719SVikas Chaudhary int wait = 0; 478909a0f719SVikas Chaudhary 4790c2660df3SVikas Chaudhary ql4_printk(KERN_INFO, ha, 47915cd049a5SChristoph Hellwig "scsi%ld:%d:%d: Abort command issued cmd=%p\n", 47925cd049a5SChristoph Hellwig ha->host_no, id, lun, cmd); 479309a0f719SVikas Chaudhary 479492b3e5bbSMike Christie spin_lock_irqsave(&ha->hardware_lock, flags); 479509a0f719SVikas Chaudhary srb = (struct srb *) CMD_SP(cmd); 479692b3e5bbSMike Christie if (!srb) { 479792b3e5bbSMike Christie spin_unlock_irqrestore(&ha->hardware_lock, flags); 479809a0f719SVikas Chaudhary return SUCCESS; 479992b3e5bbSMike Christie } 480009a0f719SVikas Chaudhary kref_get(&srb->srb_ref); 480192b3e5bbSMike Christie spin_unlock_irqrestore(&ha->hardware_lock, flags); 480209a0f719SVikas Chaudhary 480309a0f719SVikas Chaudhary if (qla4xxx_abort_task(ha, srb) != QLA_SUCCESS) { 480409a0f719SVikas Chaudhary DEBUG3(printk("scsi%ld:%d:%d: Abort_task mbx failed.\n", 480509a0f719SVikas Chaudhary ha->host_no, id, lun)); 480609a0f719SVikas Chaudhary ret = FAILED; 480709a0f719SVikas Chaudhary } else { 480809a0f719SVikas Chaudhary DEBUG3(printk("scsi%ld:%d:%d: Abort_task mbx success.\n", 480909a0f719SVikas Chaudhary ha->host_no, id, lun)); 481009a0f719SVikas Chaudhary wait = 1; 481109a0f719SVikas Chaudhary } 481209a0f719SVikas Chaudhary 481309a0f719SVikas Chaudhary kref_put(&srb->srb_ref, qla4xxx_srb_compl); 481409a0f719SVikas Chaudhary 481509a0f719SVikas Chaudhary /* Wait for command to complete */ 481609a0f719SVikas Chaudhary if (wait) { 481709a0f719SVikas Chaudhary if (!qla4xxx_eh_wait_on_command(ha, cmd)) { 481809a0f719SVikas Chaudhary DEBUG2(printk("scsi%ld:%d:%d: Abort handler timed out\n", 481909a0f719SVikas Chaudhary ha->host_no, id, lun)); 482009a0f719SVikas Chaudhary ret = FAILED; 482109a0f719SVikas Chaudhary } 482209a0f719SVikas Chaudhary } 482309a0f719SVikas Chaudhary 4824c2660df3SVikas Chaudhary ql4_printk(KERN_INFO, ha, 482509a0f719SVikas Chaudhary "scsi%ld:%d:%d: Abort command - %s\n", 482625985edcSLucas De Marchi ha->host_no, id, lun, (ret == SUCCESS) ? "succeeded" : "failed"); 482709a0f719SVikas Chaudhary 482809a0f719SVikas Chaudhary return ret; 482909a0f719SVikas Chaudhary } 483009a0f719SVikas Chaudhary 483109a0f719SVikas Chaudhary /** 4832afaf5a2dSDavid Somayajulu * qla4xxx_eh_device_reset - callback for target reset. 4833afaf5a2dSDavid Somayajulu * @cmd: Pointer to Linux's SCSI command structure 4834afaf5a2dSDavid Somayajulu * 4835afaf5a2dSDavid Somayajulu * This routine is called by the Linux OS to reset all luns on the 4836afaf5a2dSDavid Somayajulu * specified target. 4837afaf5a2dSDavid Somayajulu **/ 4838afaf5a2dSDavid Somayajulu static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd) 4839afaf5a2dSDavid Somayajulu { 4840afaf5a2dSDavid Somayajulu struct scsi_qla_host *ha = to_qla_host(cmd->device->host); 4841afaf5a2dSDavid Somayajulu struct ddb_entry *ddb_entry = cmd->device->hostdata; 4842afaf5a2dSDavid Somayajulu int ret = FAILED, stat; 4843afaf5a2dSDavid Somayajulu 4844612f7348SKaren Higgins if (!ddb_entry) 4845afaf5a2dSDavid Somayajulu return ret; 4846afaf5a2dSDavid Somayajulu 4847c01be6dcSMike Christie ret = iscsi_block_scsi_eh(cmd); 4848c01be6dcSMike Christie if (ret) 4849c01be6dcSMike Christie return ret; 4850c01be6dcSMike Christie ret = FAILED; 4851c01be6dcSMike Christie 4852c2660df3SVikas Chaudhary ql4_printk(KERN_INFO, ha, 4853afaf5a2dSDavid Somayajulu "scsi%ld:%d:%d:%d: DEVICE RESET ISSUED.\n", ha->host_no, 4854afaf5a2dSDavid Somayajulu cmd->device->channel, cmd->device->id, cmd->device->lun); 4855afaf5a2dSDavid Somayajulu 4856afaf5a2dSDavid Somayajulu DEBUG2(printk(KERN_INFO 4857afaf5a2dSDavid Somayajulu "scsi%ld: DEVICE_RESET cmd=%p jiffies = 0x%lx, to=%x," 4858afaf5a2dSDavid Somayajulu "dpc_flags=%lx, status=%x allowed=%d\n", ha->host_no, 4859242f9dcbSJens Axboe cmd, jiffies, cmd->request->timeout / HZ, 4860afaf5a2dSDavid Somayajulu ha->dpc_flags, cmd->result, cmd->allowed)); 4861afaf5a2dSDavid Somayajulu 4862afaf5a2dSDavid Somayajulu /* FIXME: wait for hba to go online */ 4863afaf5a2dSDavid Somayajulu stat = qla4xxx_reset_lun(ha, ddb_entry, cmd->device->lun); 4864afaf5a2dSDavid Somayajulu if (stat != QLA_SUCCESS) { 4865c2660df3SVikas Chaudhary ql4_printk(KERN_INFO, ha, "DEVICE RESET FAILED. %d\n", stat); 4866afaf5a2dSDavid Somayajulu goto eh_dev_reset_done; 4867afaf5a2dSDavid Somayajulu } 4868afaf5a2dSDavid Somayajulu 4869ce545039SMike Christie if (qla4xxx_eh_wait_for_commands(ha, scsi_target(cmd->device), 4870ce545039SMike Christie cmd->device)) { 4871c2660df3SVikas Chaudhary ql4_printk(KERN_INFO, ha, 4872afaf5a2dSDavid Somayajulu "DEVICE RESET FAILED - waiting for " 4873afaf5a2dSDavid Somayajulu "commands.\n"); 4874afaf5a2dSDavid Somayajulu goto eh_dev_reset_done; 4875afaf5a2dSDavid Somayajulu } 4876afaf5a2dSDavid Somayajulu 48779d562913SDavid C Somayajulu /* Send marker. */ 48789d562913SDavid C Somayajulu if (qla4xxx_send_marker_iocb(ha, ddb_entry, cmd->device->lun, 48799d562913SDavid C Somayajulu MM_LUN_RESET) != QLA_SUCCESS) 48809d562913SDavid C Somayajulu goto eh_dev_reset_done; 48819d562913SDavid C Somayajulu 4882c2660df3SVikas Chaudhary ql4_printk(KERN_INFO, ha, 4883afaf5a2dSDavid Somayajulu "scsi(%ld:%d:%d:%d): DEVICE RESET SUCCEEDED.\n", 4884afaf5a2dSDavid Somayajulu ha->host_no, cmd->device->channel, cmd->device->id, 4885afaf5a2dSDavid Somayajulu cmd->device->lun); 4886afaf5a2dSDavid Somayajulu 4887afaf5a2dSDavid Somayajulu ret = SUCCESS; 4888afaf5a2dSDavid Somayajulu 4889afaf5a2dSDavid Somayajulu eh_dev_reset_done: 4890afaf5a2dSDavid Somayajulu 4891afaf5a2dSDavid Somayajulu return ret; 4892afaf5a2dSDavid Somayajulu } 4893afaf5a2dSDavid Somayajulu 4894afaf5a2dSDavid Somayajulu /** 4895ce545039SMike Christie * qla4xxx_eh_target_reset - callback for target reset. 4896ce545039SMike Christie * @cmd: Pointer to Linux's SCSI command structure 4897ce545039SMike Christie * 4898ce545039SMike Christie * This routine is called by the Linux OS to reset the target. 4899ce545039SMike Christie **/ 4900ce545039SMike Christie static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd) 4901ce545039SMike Christie { 4902ce545039SMike Christie struct scsi_qla_host *ha = to_qla_host(cmd->device->host); 4903ce545039SMike Christie struct ddb_entry *ddb_entry = cmd->device->hostdata; 4904c01be6dcSMike Christie int stat, ret; 4905ce545039SMike Christie 4906ce545039SMike Christie if (!ddb_entry) 4907ce545039SMike Christie return FAILED; 4908ce545039SMike Christie 4909c01be6dcSMike Christie ret = iscsi_block_scsi_eh(cmd); 4910c01be6dcSMike Christie if (ret) 4911c01be6dcSMike Christie return ret; 4912c01be6dcSMike Christie 4913ce545039SMike Christie starget_printk(KERN_INFO, scsi_target(cmd->device), 4914ce545039SMike Christie "WARM TARGET RESET ISSUED.\n"); 4915ce545039SMike Christie 4916ce545039SMike Christie DEBUG2(printk(KERN_INFO 4917ce545039SMike Christie "scsi%ld: TARGET_DEVICE_RESET cmd=%p jiffies = 0x%lx, " 4918ce545039SMike Christie "to=%x,dpc_flags=%lx, status=%x allowed=%d\n", 4919242f9dcbSJens Axboe ha->host_no, cmd, jiffies, cmd->request->timeout / HZ, 4920ce545039SMike Christie ha->dpc_flags, cmd->result, cmd->allowed)); 4921ce545039SMike Christie 4922ce545039SMike Christie stat = qla4xxx_reset_target(ha, ddb_entry); 4923ce545039SMike Christie if (stat != QLA_SUCCESS) { 4924ce545039SMike Christie starget_printk(KERN_INFO, scsi_target(cmd->device), 4925ce545039SMike Christie "WARM TARGET RESET FAILED.\n"); 4926ce545039SMike Christie return FAILED; 4927ce545039SMike Christie } 4928ce545039SMike Christie 4929ce545039SMike Christie if (qla4xxx_eh_wait_for_commands(ha, scsi_target(cmd->device), 4930ce545039SMike Christie NULL)) { 4931ce545039SMike Christie starget_printk(KERN_INFO, scsi_target(cmd->device), 4932ce545039SMike Christie "WARM TARGET DEVICE RESET FAILED - " 4933ce545039SMike Christie "waiting for commands.\n"); 4934ce545039SMike Christie return FAILED; 4935ce545039SMike Christie } 4936ce545039SMike Christie 49379d562913SDavid C Somayajulu /* Send marker. */ 49389d562913SDavid C Somayajulu if (qla4xxx_send_marker_iocb(ha, ddb_entry, cmd->device->lun, 49399d562913SDavid C Somayajulu MM_TGT_WARM_RESET) != QLA_SUCCESS) { 49409d562913SDavid C Somayajulu starget_printk(KERN_INFO, scsi_target(cmd->device), 49419d562913SDavid C Somayajulu "WARM TARGET DEVICE RESET FAILED - " 49429d562913SDavid C Somayajulu "marker iocb failed.\n"); 49439d562913SDavid C Somayajulu return FAILED; 49449d562913SDavid C Somayajulu } 49459d562913SDavid C Somayajulu 4946ce545039SMike Christie starget_printk(KERN_INFO, scsi_target(cmd->device), 4947ce545039SMike Christie "WARM TARGET RESET SUCCEEDED.\n"); 4948ce545039SMike Christie return SUCCESS; 4949ce545039SMike Christie } 4950ce545039SMike Christie 4951ce545039SMike Christie /** 49528a288960SSarang Radke * qla4xxx_is_eh_active - check if error handler is running 49538a288960SSarang Radke * @shost: Pointer to SCSI Host struct 49548a288960SSarang Radke * 49558a288960SSarang Radke * This routine finds that if reset host is called in EH 49568a288960SSarang Radke * scenario or from some application like sg_reset 49578a288960SSarang Radke **/ 49588a288960SSarang Radke static int qla4xxx_is_eh_active(struct Scsi_Host *shost) 49598a288960SSarang Radke { 49608a288960SSarang Radke if (shost->shost_state == SHOST_RECOVERY) 49618a288960SSarang Radke return 1; 49628a288960SSarang Radke return 0; 49638a288960SSarang Radke } 49648a288960SSarang Radke 49658a288960SSarang Radke /** 4966afaf5a2dSDavid Somayajulu * qla4xxx_eh_host_reset - kernel callback 4967afaf5a2dSDavid Somayajulu * @cmd: Pointer to Linux's SCSI command structure 4968afaf5a2dSDavid Somayajulu * 4969afaf5a2dSDavid Somayajulu * This routine is invoked by the Linux kernel to perform fatal error 4970afaf5a2dSDavid Somayajulu * recovery on the specified adapter. 4971afaf5a2dSDavid Somayajulu **/ 4972afaf5a2dSDavid Somayajulu static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd) 4973afaf5a2dSDavid Somayajulu { 4974afaf5a2dSDavid Somayajulu int return_status = FAILED; 4975afaf5a2dSDavid Somayajulu struct scsi_qla_host *ha; 4976afaf5a2dSDavid Somayajulu 4977b3a271a9SManish Rangankar ha = to_qla_host(cmd->device->host); 4978afaf5a2dSDavid Somayajulu 4979f4f5df23SVikas Chaudhary if (ql4xdontresethba) { 4980f4f5df23SVikas Chaudhary DEBUG2(printk("scsi%ld: %s: Don't Reset HBA\n", 4981f4f5df23SVikas Chaudhary ha->host_no, __func__)); 49828a288960SSarang Radke 49838a288960SSarang Radke /* Clear outstanding srb in queues */ 49848a288960SSarang Radke if (qla4xxx_is_eh_active(cmd->device->host)) 49858a288960SSarang Radke qla4xxx_abort_active_cmds(ha, DID_ABORT << 16); 49868a288960SSarang Radke 4987f4f5df23SVikas Chaudhary return FAILED; 4988f4f5df23SVikas Chaudhary } 4989f4f5df23SVikas Chaudhary 4990c2660df3SVikas Chaudhary ql4_printk(KERN_INFO, ha, 4991dca05c4cSKaren Higgins "scsi(%ld:%d:%d:%d): HOST RESET ISSUED.\n", ha->host_no, 4992afaf5a2dSDavid Somayajulu cmd->device->channel, cmd->device->id, cmd->device->lun); 4993afaf5a2dSDavid Somayajulu 4994afaf5a2dSDavid Somayajulu if (qla4xxx_wait_for_hba_online(ha) != QLA_SUCCESS) { 4995afaf5a2dSDavid Somayajulu DEBUG2(printk("scsi%ld:%d: %s: Unable to reset host. Adapter " 4996afaf5a2dSDavid Somayajulu "DEAD.\n", ha->host_no, cmd->device->channel, 4997afaf5a2dSDavid Somayajulu __func__)); 4998afaf5a2dSDavid Somayajulu 4999afaf5a2dSDavid Somayajulu return FAILED; 5000afaf5a2dSDavid Somayajulu } 5001afaf5a2dSDavid Somayajulu 5002f4f5df23SVikas Chaudhary if (!test_bit(DPC_RESET_HA, &ha->dpc_flags)) { 5003f4f5df23SVikas Chaudhary if (is_qla8022(ha)) 5004f4f5df23SVikas Chaudhary set_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags); 5005f4f5df23SVikas Chaudhary else 5006f4f5df23SVikas Chaudhary set_bit(DPC_RESET_HA, &ha->dpc_flags); 5007f4f5df23SVikas Chaudhary } 500850a29aecSMike Christie 5009f4f5df23SVikas Chaudhary if (qla4xxx_recover_adapter(ha) == QLA_SUCCESS) 5010afaf5a2dSDavid Somayajulu return_status = SUCCESS; 5011afaf5a2dSDavid Somayajulu 5012c2660df3SVikas Chaudhary ql4_printk(KERN_INFO, ha, "HOST RESET %s.\n", 501325985edcSLucas De Marchi return_status == FAILED ? "FAILED" : "SUCCEEDED"); 5014afaf5a2dSDavid Somayajulu 5015afaf5a2dSDavid Somayajulu return return_status; 5016afaf5a2dSDavid Somayajulu } 5017afaf5a2dSDavid Somayajulu 501895d31262SVikas Chaudhary static int qla4xxx_context_reset(struct scsi_qla_host *ha) 501995d31262SVikas Chaudhary { 502095d31262SVikas Chaudhary uint32_t mbox_cmd[MBOX_REG_COUNT]; 502195d31262SVikas Chaudhary uint32_t mbox_sts[MBOX_REG_COUNT]; 502295d31262SVikas Chaudhary struct addr_ctrl_blk_def *acb = NULL; 502395d31262SVikas Chaudhary uint32_t acb_len = sizeof(struct addr_ctrl_blk_def); 502495d31262SVikas Chaudhary int rval = QLA_SUCCESS; 502595d31262SVikas Chaudhary dma_addr_t acb_dma; 502695d31262SVikas Chaudhary 502795d31262SVikas Chaudhary acb = dma_alloc_coherent(&ha->pdev->dev, 502895d31262SVikas Chaudhary sizeof(struct addr_ctrl_blk_def), 502995d31262SVikas Chaudhary &acb_dma, GFP_KERNEL); 503095d31262SVikas Chaudhary if (!acb) { 503195d31262SVikas Chaudhary ql4_printk(KERN_ERR, ha, "%s: Unable to alloc acb\n", 503295d31262SVikas Chaudhary __func__); 503395d31262SVikas Chaudhary rval = -ENOMEM; 503495d31262SVikas Chaudhary goto exit_port_reset; 503595d31262SVikas Chaudhary } 503695d31262SVikas Chaudhary 503795d31262SVikas Chaudhary memset(acb, 0, acb_len); 503895d31262SVikas Chaudhary 503995d31262SVikas Chaudhary rval = qla4xxx_get_acb(ha, acb_dma, PRIMARI_ACB, acb_len); 504095d31262SVikas Chaudhary if (rval != QLA_SUCCESS) { 504195d31262SVikas Chaudhary rval = -EIO; 504295d31262SVikas Chaudhary goto exit_free_acb; 504395d31262SVikas Chaudhary } 504495d31262SVikas Chaudhary 504595d31262SVikas Chaudhary rval = qla4xxx_disable_acb(ha); 504695d31262SVikas Chaudhary if (rval != QLA_SUCCESS) { 504795d31262SVikas Chaudhary rval = -EIO; 504895d31262SVikas Chaudhary goto exit_free_acb; 504995d31262SVikas Chaudhary } 505095d31262SVikas Chaudhary 505195d31262SVikas Chaudhary wait_for_completion_timeout(&ha->disable_acb_comp, 505295d31262SVikas Chaudhary DISABLE_ACB_TOV * HZ); 505395d31262SVikas Chaudhary 505495d31262SVikas Chaudhary rval = qla4xxx_set_acb(ha, &mbox_cmd[0], &mbox_sts[0], acb_dma); 505595d31262SVikas Chaudhary if (rval != QLA_SUCCESS) { 505695d31262SVikas Chaudhary rval = -EIO; 505795d31262SVikas Chaudhary goto exit_free_acb; 505895d31262SVikas Chaudhary } 505995d31262SVikas Chaudhary 506095d31262SVikas Chaudhary exit_free_acb: 506195d31262SVikas Chaudhary dma_free_coherent(&ha->pdev->dev, sizeof(struct addr_ctrl_blk_def), 506295d31262SVikas Chaudhary acb, acb_dma); 506395d31262SVikas Chaudhary exit_port_reset: 506495d31262SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, "%s %s\n", __func__, 506595d31262SVikas Chaudhary rval == QLA_SUCCESS ? "SUCCEEDED" : "FAILED")); 506695d31262SVikas Chaudhary return rval; 506795d31262SVikas Chaudhary } 506895d31262SVikas Chaudhary 506995d31262SVikas Chaudhary static int qla4xxx_host_reset(struct Scsi_Host *shost, int reset_type) 507095d31262SVikas Chaudhary { 507195d31262SVikas Chaudhary struct scsi_qla_host *ha = to_qla_host(shost); 507295d31262SVikas Chaudhary int rval = QLA_SUCCESS; 507395d31262SVikas Chaudhary 507495d31262SVikas Chaudhary if (ql4xdontresethba) { 507595d31262SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Don't Reset HBA\n", 507695d31262SVikas Chaudhary __func__)); 507795d31262SVikas Chaudhary rval = -EPERM; 507895d31262SVikas Chaudhary goto exit_host_reset; 507995d31262SVikas Chaudhary } 508095d31262SVikas Chaudhary 508195d31262SVikas Chaudhary rval = qla4xxx_wait_for_hba_online(ha); 508295d31262SVikas Chaudhary if (rval != QLA_SUCCESS) { 508395d31262SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Unable to reset host " 508495d31262SVikas Chaudhary "adapter\n", __func__)); 508595d31262SVikas Chaudhary rval = -EIO; 508695d31262SVikas Chaudhary goto exit_host_reset; 508795d31262SVikas Chaudhary } 508895d31262SVikas Chaudhary 508995d31262SVikas Chaudhary if (test_bit(DPC_RESET_HA, &ha->dpc_flags)) 509095d31262SVikas Chaudhary goto recover_adapter; 509195d31262SVikas Chaudhary 509295d31262SVikas Chaudhary switch (reset_type) { 509395d31262SVikas Chaudhary case SCSI_ADAPTER_RESET: 509495d31262SVikas Chaudhary set_bit(DPC_RESET_HA, &ha->dpc_flags); 509595d31262SVikas Chaudhary break; 509695d31262SVikas Chaudhary case SCSI_FIRMWARE_RESET: 509795d31262SVikas Chaudhary if (!test_bit(DPC_RESET_HA, &ha->dpc_flags)) { 509895d31262SVikas Chaudhary if (is_qla8022(ha)) 509995d31262SVikas Chaudhary /* set firmware context reset */ 510095d31262SVikas Chaudhary set_bit(DPC_RESET_HA_FW_CONTEXT, 510195d31262SVikas Chaudhary &ha->dpc_flags); 510295d31262SVikas Chaudhary else { 510395d31262SVikas Chaudhary rval = qla4xxx_context_reset(ha); 510495d31262SVikas Chaudhary goto exit_host_reset; 510595d31262SVikas Chaudhary } 510695d31262SVikas Chaudhary } 510795d31262SVikas Chaudhary break; 510895d31262SVikas Chaudhary } 510995d31262SVikas Chaudhary 511095d31262SVikas Chaudhary recover_adapter: 511195d31262SVikas Chaudhary rval = qla4xxx_recover_adapter(ha); 511295d31262SVikas Chaudhary if (rval != QLA_SUCCESS) { 511395d31262SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, "%s: recover adapter fail\n", 511495d31262SVikas Chaudhary __func__)); 511595d31262SVikas Chaudhary rval = -EIO; 511695d31262SVikas Chaudhary } 511795d31262SVikas Chaudhary 511895d31262SVikas Chaudhary exit_host_reset: 511995d31262SVikas Chaudhary return rval; 512095d31262SVikas Chaudhary } 512195d31262SVikas Chaudhary 51222232be0dSLalit Chandivade /* PCI AER driver recovers from all correctable errors w/o 51232232be0dSLalit Chandivade * driver intervention. For uncorrectable errors PCI AER 51242232be0dSLalit Chandivade * driver calls the following device driver's callbacks 51252232be0dSLalit Chandivade * 51262232be0dSLalit Chandivade * - Fatal Errors - link_reset 51272232be0dSLalit Chandivade * - Non-Fatal Errors - driver's pci_error_detected() which 51282232be0dSLalit Chandivade * returns CAN_RECOVER, NEED_RESET or DISCONNECT. 51292232be0dSLalit Chandivade * 51302232be0dSLalit Chandivade * PCI AER driver calls 51312232be0dSLalit Chandivade * CAN_RECOVER - driver's pci_mmio_enabled(), mmio_enabled 51322232be0dSLalit Chandivade * returns RECOVERED or NEED_RESET if fw_hung 51332232be0dSLalit Chandivade * NEED_RESET - driver's slot_reset() 51342232be0dSLalit Chandivade * DISCONNECT - device is dead & cannot recover 51352232be0dSLalit Chandivade * RECOVERED - driver's pci_resume() 51362232be0dSLalit Chandivade */ 51372232be0dSLalit Chandivade static pci_ers_result_t 51382232be0dSLalit Chandivade qla4xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) 51392232be0dSLalit Chandivade { 51402232be0dSLalit Chandivade struct scsi_qla_host *ha = pci_get_drvdata(pdev); 51412232be0dSLalit Chandivade 51422232be0dSLalit Chandivade ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: error detected:state %x\n", 51432232be0dSLalit Chandivade ha->host_no, __func__, state); 51442232be0dSLalit Chandivade 51452232be0dSLalit Chandivade if (!is_aer_supported(ha)) 51462232be0dSLalit Chandivade return PCI_ERS_RESULT_NONE; 51472232be0dSLalit Chandivade 51482232be0dSLalit Chandivade switch (state) { 51492232be0dSLalit Chandivade case pci_channel_io_normal: 51502232be0dSLalit Chandivade clear_bit(AF_EEH_BUSY, &ha->flags); 51512232be0dSLalit Chandivade return PCI_ERS_RESULT_CAN_RECOVER; 51522232be0dSLalit Chandivade case pci_channel_io_frozen: 51532232be0dSLalit Chandivade set_bit(AF_EEH_BUSY, &ha->flags); 51542232be0dSLalit Chandivade qla4xxx_mailbox_premature_completion(ha); 51552232be0dSLalit Chandivade qla4xxx_free_irqs(ha); 51562232be0dSLalit Chandivade pci_disable_device(pdev); 51577b3595dfSVikas Chaudhary /* Return back all IOs */ 51587b3595dfSVikas Chaudhary qla4xxx_abort_active_cmds(ha, DID_RESET << 16); 51592232be0dSLalit Chandivade return PCI_ERS_RESULT_NEED_RESET; 51602232be0dSLalit Chandivade case pci_channel_io_perm_failure: 51612232be0dSLalit Chandivade set_bit(AF_EEH_BUSY, &ha->flags); 51622232be0dSLalit Chandivade set_bit(AF_PCI_CHANNEL_IO_PERM_FAILURE, &ha->flags); 51632232be0dSLalit Chandivade qla4xxx_abort_active_cmds(ha, DID_NO_CONNECT << 16); 51642232be0dSLalit Chandivade return PCI_ERS_RESULT_DISCONNECT; 51652232be0dSLalit Chandivade } 51662232be0dSLalit Chandivade return PCI_ERS_RESULT_NEED_RESET; 51672232be0dSLalit Chandivade } 51682232be0dSLalit Chandivade 51692232be0dSLalit Chandivade /** 51702232be0dSLalit Chandivade * qla4xxx_pci_mmio_enabled() gets called if 51712232be0dSLalit Chandivade * qla4xxx_pci_error_detected() returns PCI_ERS_RESULT_CAN_RECOVER 51722232be0dSLalit Chandivade * and read/write to the device still works. 51732232be0dSLalit Chandivade **/ 51742232be0dSLalit Chandivade static pci_ers_result_t 51752232be0dSLalit Chandivade qla4xxx_pci_mmio_enabled(struct pci_dev *pdev) 51762232be0dSLalit Chandivade { 51772232be0dSLalit Chandivade struct scsi_qla_host *ha = pci_get_drvdata(pdev); 51782232be0dSLalit Chandivade 51792232be0dSLalit Chandivade if (!is_aer_supported(ha)) 51802232be0dSLalit Chandivade return PCI_ERS_RESULT_NONE; 51812232be0dSLalit Chandivade 51822232be0dSLalit Chandivade return PCI_ERS_RESULT_RECOVERED; 51832232be0dSLalit Chandivade } 51842232be0dSLalit Chandivade 51857b3595dfSVikas Chaudhary static uint32_t qla4_8xxx_error_recovery(struct scsi_qla_host *ha) 51862232be0dSLalit Chandivade { 51872232be0dSLalit Chandivade uint32_t rval = QLA_ERROR; 51887b3595dfSVikas Chaudhary uint32_t ret = 0; 51892232be0dSLalit Chandivade int fn; 51902232be0dSLalit Chandivade struct pci_dev *other_pdev = NULL; 51912232be0dSLalit Chandivade 51922232be0dSLalit Chandivade ql4_printk(KERN_WARNING, ha, "scsi%ld: In %s\n", ha->host_no, __func__); 51932232be0dSLalit Chandivade 51942232be0dSLalit Chandivade set_bit(DPC_RESET_ACTIVE, &ha->dpc_flags); 51952232be0dSLalit Chandivade 51962232be0dSLalit Chandivade if (test_bit(AF_ONLINE, &ha->flags)) { 51972232be0dSLalit Chandivade clear_bit(AF_ONLINE, &ha->flags); 5198b3a271a9SManish Rangankar clear_bit(AF_LINK_UP, &ha->flags); 5199b3a271a9SManish Rangankar iscsi_host_for_each_session(ha->host, qla4xxx_fail_session); 52002232be0dSLalit Chandivade qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); 52012232be0dSLalit Chandivade } 52022232be0dSLalit Chandivade 52032232be0dSLalit Chandivade fn = PCI_FUNC(ha->pdev->devfn); 52042232be0dSLalit Chandivade while (fn > 0) { 52052232be0dSLalit Chandivade fn--; 52062232be0dSLalit Chandivade ql4_printk(KERN_INFO, ha, "scsi%ld: %s: Finding PCI device at " 52072232be0dSLalit Chandivade "func %x\n", ha->host_no, __func__, fn); 52082232be0dSLalit Chandivade /* Get the pci device given the domain, bus, 52092232be0dSLalit Chandivade * slot/function number */ 52102232be0dSLalit Chandivade other_pdev = 52112232be0dSLalit Chandivade pci_get_domain_bus_and_slot(pci_domain_nr(ha->pdev->bus), 52122232be0dSLalit Chandivade ha->pdev->bus->number, PCI_DEVFN(PCI_SLOT(ha->pdev->devfn), 52132232be0dSLalit Chandivade fn)); 52142232be0dSLalit Chandivade 52152232be0dSLalit Chandivade if (!other_pdev) 52162232be0dSLalit Chandivade continue; 52172232be0dSLalit Chandivade 52182232be0dSLalit Chandivade if (atomic_read(&other_pdev->enable_cnt)) { 52192232be0dSLalit Chandivade ql4_printk(KERN_INFO, ha, "scsi%ld: %s: Found PCI " 52202232be0dSLalit Chandivade "func in enabled state%x\n", ha->host_no, 52212232be0dSLalit Chandivade __func__, fn); 52222232be0dSLalit Chandivade pci_dev_put(other_pdev); 52232232be0dSLalit Chandivade break; 52242232be0dSLalit Chandivade } 52252232be0dSLalit Chandivade pci_dev_put(other_pdev); 52262232be0dSLalit Chandivade } 52272232be0dSLalit Chandivade 52282232be0dSLalit Chandivade /* The first function on the card, the reset owner will 52292232be0dSLalit Chandivade * start & initialize the firmware. The other functions 52302232be0dSLalit Chandivade * on the card will reset the firmware context 52312232be0dSLalit Chandivade */ 52322232be0dSLalit Chandivade if (!fn) { 52332232be0dSLalit Chandivade ql4_printk(KERN_INFO, ha, "scsi%ld: %s: devfn being reset " 52342232be0dSLalit Chandivade "0x%x is the owner\n", ha->host_no, __func__, 52352232be0dSLalit Chandivade ha->pdev->devfn); 52362232be0dSLalit Chandivade 52372232be0dSLalit Chandivade qla4_8xxx_idc_lock(ha); 52382232be0dSLalit Chandivade qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, 52392232be0dSLalit Chandivade QLA82XX_DEV_COLD); 52402232be0dSLalit Chandivade 52412232be0dSLalit Chandivade qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_IDC_VERSION, 52422232be0dSLalit Chandivade QLA82XX_IDC_VERSION); 52432232be0dSLalit Chandivade 52442232be0dSLalit Chandivade qla4_8xxx_idc_unlock(ha); 52452232be0dSLalit Chandivade clear_bit(AF_FW_RECOVERY, &ha->flags); 524613483730SMike Christie rval = qla4xxx_initialize_adapter(ha, RESET_ADAPTER); 52472232be0dSLalit Chandivade qla4_8xxx_idc_lock(ha); 52482232be0dSLalit Chandivade 52492232be0dSLalit Chandivade if (rval != QLA_SUCCESS) { 52502232be0dSLalit Chandivade ql4_printk(KERN_INFO, ha, "scsi%ld: %s: HW State: " 52512232be0dSLalit Chandivade "FAILED\n", ha->host_no, __func__); 52522232be0dSLalit Chandivade qla4_8xxx_clear_drv_active(ha); 52532232be0dSLalit Chandivade qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, 52542232be0dSLalit Chandivade QLA82XX_DEV_FAILED); 52552232be0dSLalit Chandivade } else { 52562232be0dSLalit Chandivade ql4_printk(KERN_INFO, ha, "scsi%ld: %s: HW State: " 52572232be0dSLalit Chandivade "READY\n", ha->host_no, __func__); 52582232be0dSLalit Chandivade qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, 52592232be0dSLalit Chandivade QLA82XX_DEV_READY); 52602232be0dSLalit Chandivade /* Clear driver state register */ 52612232be0dSLalit Chandivade qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_STATE, 0); 52622232be0dSLalit Chandivade qla4_8xxx_set_drv_active(ha); 52637b3595dfSVikas Chaudhary ret = qla4xxx_request_irqs(ha); 52647b3595dfSVikas Chaudhary if (ret) { 52657b3595dfSVikas Chaudhary ql4_printk(KERN_WARNING, ha, "Failed to " 52667b3595dfSVikas Chaudhary "reserve interrupt %d already in use.\n", 52677b3595dfSVikas Chaudhary ha->pdev->irq); 52687b3595dfSVikas Chaudhary rval = QLA_ERROR; 52697b3595dfSVikas Chaudhary } else { 52702232be0dSLalit Chandivade ha->isp_ops->enable_intrs(ha); 52717b3595dfSVikas Chaudhary rval = QLA_SUCCESS; 52727b3595dfSVikas Chaudhary } 52732232be0dSLalit Chandivade } 52742232be0dSLalit Chandivade qla4_8xxx_idc_unlock(ha); 52752232be0dSLalit Chandivade } else { 52762232be0dSLalit Chandivade ql4_printk(KERN_INFO, ha, "scsi%ld: %s: devfn 0x%x is not " 52772232be0dSLalit Chandivade "the reset owner\n", ha->host_no, __func__, 52782232be0dSLalit Chandivade ha->pdev->devfn); 52792232be0dSLalit Chandivade if ((qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE) == 52802232be0dSLalit Chandivade QLA82XX_DEV_READY)) { 52812232be0dSLalit Chandivade clear_bit(AF_FW_RECOVERY, &ha->flags); 528213483730SMike Christie rval = qla4xxx_initialize_adapter(ha, RESET_ADAPTER); 52837b3595dfSVikas Chaudhary if (rval == QLA_SUCCESS) { 52847b3595dfSVikas Chaudhary ret = qla4xxx_request_irqs(ha); 52857b3595dfSVikas Chaudhary if (ret) { 52867b3595dfSVikas Chaudhary ql4_printk(KERN_WARNING, ha, "Failed to" 52877b3595dfSVikas Chaudhary " reserve interrupt %d already in" 52887b3595dfSVikas Chaudhary " use.\n", ha->pdev->irq); 52897b3595dfSVikas Chaudhary rval = QLA_ERROR; 52907b3595dfSVikas Chaudhary } else { 52912232be0dSLalit Chandivade ha->isp_ops->enable_intrs(ha); 52927b3595dfSVikas Chaudhary rval = QLA_SUCCESS; 52937b3595dfSVikas Chaudhary } 52947b3595dfSVikas Chaudhary } 52952232be0dSLalit Chandivade qla4_8xxx_idc_lock(ha); 52962232be0dSLalit Chandivade qla4_8xxx_set_drv_active(ha); 52972232be0dSLalit Chandivade qla4_8xxx_idc_unlock(ha); 52982232be0dSLalit Chandivade } 52992232be0dSLalit Chandivade } 53002232be0dSLalit Chandivade clear_bit(DPC_RESET_ACTIVE, &ha->dpc_flags); 53012232be0dSLalit Chandivade return rval; 53022232be0dSLalit Chandivade } 53032232be0dSLalit Chandivade 53042232be0dSLalit Chandivade static pci_ers_result_t 53052232be0dSLalit Chandivade qla4xxx_pci_slot_reset(struct pci_dev *pdev) 53062232be0dSLalit Chandivade { 53072232be0dSLalit Chandivade pci_ers_result_t ret = PCI_ERS_RESULT_DISCONNECT; 53082232be0dSLalit Chandivade struct scsi_qla_host *ha = pci_get_drvdata(pdev); 53092232be0dSLalit Chandivade int rc; 53102232be0dSLalit Chandivade 53112232be0dSLalit Chandivade ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: slot_reset\n", 53122232be0dSLalit Chandivade ha->host_no, __func__); 53132232be0dSLalit Chandivade 53142232be0dSLalit Chandivade if (!is_aer_supported(ha)) 53152232be0dSLalit Chandivade return PCI_ERS_RESULT_NONE; 53162232be0dSLalit Chandivade 53172232be0dSLalit Chandivade /* Restore the saved state of PCIe device - 53182232be0dSLalit Chandivade * BAR registers, PCI Config space, PCIX, MSI, 53192232be0dSLalit Chandivade * IOV states 53202232be0dSLalit Chandivade */ 53212232be0dSLalit Chandivade pci_restore_state(pdev); 53222232be0dSLalit Chandivade 53232232be0dSLalit Chandivade /* pci_restore_state() clears the saved_state flag of the device 53242232be0dSLalit Chandivade * save restored state which resets saved_state flag 53252232be0dSLalit Chandivade */ 53262232be0dSLalit Chandivade pci_save_state(pdev); 53272232be0dSLalit Chandivade 53282232be0dSLalit Chandivade /* Initialize device or resume if in suspended state */ 53292232be0dSLalit Chandivade rc = pci_enable_device(pdev); 53302232be0dSLalit Chandivade if (rc) { 533125985edcSLucas De Marchi ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: Can't re-enable " 53322232be0dSLalit Chandivade "device after reset\n", ha->host_no, __func__); 53332232be0dSLalit Chandivade goto exit_slot_reset; 53342232be0dSLalit Chandivade } 53352232be0dSLalit Chandivade 53367b3595dfSVikas Chaudhary ha->isp_ops->disable_intrs(ha); 53372232be0dSLalit Chandivade 53382232be0dSLalit Chandivade if (is_qla8022(ha)) { 53392232be0dSLalit Chandivade if (qla4_8xxx_error_recovery(ha) == QLA_SUCCESS) { 53402232be0dSLalit Chandivade ret = PCI_ERS_RESULT_RECOVERED; 53412232be0dSLalit Chandivade goto exit_slot_reset; 53422232be0dSLalit Chandivade } else 53432232be0dSLalit Chandivade goto exit_slot_reset; 53442232be0dSLalit Chandivade } 53452232be0dSLalit Chandivade 53462232be0dSLalit Chandivade exit_slot_reset: 53472232be0dSLalit Chandivade ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: Return=%x\n" 53482232be0dSLalit Chandivade "device after reset\n", ha->host_no, __func__, ret); 53492232be0dSLalit Chandivade return ret; 53502232be0dSLalit Chandivade } 53512232be0dSLalit Chandivade 53522232be0dSLalit Chandivade static void 53532232be0dSLalit Chandivade qla4xxx_pci_resume(struct pci_dev *pdev) 53542232be0dSLalit Chandivade { 53552232be0dSLalit Chandivade struct scsi_qla_host *ha = pci_get_drvdata(pdev); 53562232be0dSLalit Chandivade int ret; 53572232be0dSLalit Chandivade 53582232be0dSLalit Chandivade ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: pci_resume\n", 53592232be0dSLalit Chandivade ha->host_no, __func__); 53602232be0dSLalit Chandivade 53612232be0dSLalit Chandivade ret = qla4xxx_wait_for_hba_online(ha); 53622232be0dSLalit Chandivade if (ret != QLA_SUCCESS) { 53632232be0dSLalit Chandivade ql4_printk(KERN_ERR, ha, "scsi%ld: %s: the device failed to " 53642232be0dSLalit Chandivade "resume I/O from slot/link_reset\n", ha->host_no, 53652232be0dSLalit Chandivade __func__); 53662232be0dSLalit Chandivade } 53672232be0dSLalit Chandivade 53682232be0dSLalit Chandivade pci_cleanup_aer_uncorrect_error_status(pdev); 53692232be0dSLalit Chandivade clear_bit(AF_EEH_BUSY, &ha->flags); 53702232be0dSLalit Chandivade } 53712232be0dSLalit Chandivade 53722232be0dSLalit Chandivade static struct pci_error_handlers qla4xxx_err_handler = { 53732232be0dSLalit Chandivade .error_detected = qla4xxx_pci_error_detected, 53742232be0dSLalit Chandivade .mmio_enabled = qla4xxx_pci_mmio_enabled, 53752232be0dSLalit Chandivade .slot_reset = qla4xxx_pci_slot_reset, 53762232be0dSLalit Chandivade .resume = qla4xxx_pci_resume, 53772232be0dSLalit Chandivade }; 53782232be0dSLalit Chandivade 5379afaf5a2dSDavid Somayajulu static struct pci_device_id qla4xxx_pci_tbl[] = { 5380afaf5a2dSDavid Somayajulu { 5381afaf5a2dSDavid Somayajulu .vendor = PCI_VENDOR_ID_QLOGIC, 5382afaf5a2dSDavid Somayajulu .device = PCI_DEVICE_ID_QLOGIC_ISP4010, 5383afaf5a2dSDavid Somayajulu .subvendor = PCI_ANY_ID, 5384afaf5a2dSDavid Somayajulu .subdevice = PCI_ANY_ID, 5385afaf5a2dSDavid Somayajulu }, 5386afaf5a2dSDavid Somayajulu { 5387afaf5a2dSDavid Somayajulu .vendor = PCI_VENDOR_ID_QLOGIC, 5388afaf5a2dSDavid Somayajulu .device = PCI_DEVICE_ID_QLOGIC_ISP4022, 5389afaf5a2dSDavid Somayajulu .subvendor = PCI_ANY_ID, 5390afaf5a2dSDavid Somayajulu .subdevice = PCI_ANY_ID, 5391afaf5a2dSDavid Somayajulu }, 5392d915058fSDavid C Somayajulu { 5393d915058fSDavid C Somayajulu .vendor = PCI_VENDOR_ID_QLOGIC, 5394d915058fSDavid C Somayajulu .device = PCI_DEVICE_ID_QLOGIC_ISP4032, 5395d915058fSDavid C Somayajulu .subvendor = PCI_ANY_ID, 5396d915058fSDavid C Somayajulu .subdevice = PCI_ANY_ID, 5397d915058fSDavid C Somayajulu }, 5398f4f5df23SVikas Chaudhary { 5399f4f5df23SVikas Chaudhary .vendor = PCI_VENDOR_ID_QLOGIC, 5400f4f5df23SVikas Chaudhary .device = PCI_DEVICE_ID_QLOGIC_ISP8022, 5401f4f5df23SVikas Chaudhary .subvendor = PCI_ANY_ID, 5402f4f5df23SVikas Chaudhary .subdevice = PCI_ANY_ID, 5403f4f5df23SVikas Chaudhary }, 5404afaf5a2dSDavid Somayajulu {0, 0}, 5405afaf5a2dSDavid Somayajulu }; 5406afaf5a2dSDavid Somayajulu MODULE_DEVICE_TABLE(pci, qla4xxx_pci_tbl); 5407afaf5a2dSDavid Somayajulu 540847975477SAdrian Bunk static struct pci_driver qla4xxx_pci_driver = { 5409afaf5a2dSDavid Somayajulu .name = DRIVER_NAME, 5410afaf5a2dSDavid Somayajulu .id_table = qla4xxx_pci_tbl, 5411afaf5a2dSDavid Somayajulu .probe = qla4xxx_probe_adapter, 5412afaf5a2dSDavid Somayajulu .remove = qla4xxx_remove_adapter, 54132232be0dSLalit Chandivade .err_handler = &qla4xxx_err_handler, 5414afaf5a2dSDavid Somayajulu }; 5415afaf5a2dSDavid Somayajulu 5416afaf5a2dSDavid Somayajulu static int __init qla4xxx_module_init(void) 5417afaf5a2dSDavid Somayajulu { 5418afaf5a2dSDavid Somayajulu int ret; 5419afaf5a2dSDavid Somayajulu 5420afaf5a2dSDavid Somayajulu /* Allocate cache for SRBs. */ 5421afaf5a2dSDavid Somayajulu srb_cachep = kmem_cache_create("qla4xxx_srbs", sizeof(struct srb), 0, 542220c2df83SPaul Mundt SLAB_HWCACHE_ALIGN, NULL); 5423afaf5a2dSDavid Somayajulu if (srb_cachep == NULL) { 5424afaf5a2dSDavid Somayajulu printk(KERN_ERR 5425afaf5a2dSDavid Somayajulu "%s: Unable to allocate SRB cache..." 5426afaf5a2dSDavid Somayajulu "Failing load!\n", DRIVER_NAME); 5427afaf5a2dSDavid Somayajulu ret = -ENOMEM; 5428afaf5a2dSDavid Somayajulu goto no_srp_cache; 5429afaf5a2dSDavid Somayajulu } 5430afaf5a2dSDavid Somayajulu 5431afaf5a2dSDavid Somayajulu /* Derive version string. */ 5432afaf5a2dSDavid Somayajulu strcpy(qla4xxx_version_str, QLA4XXX_DRIVER_VERSION); 543311010fecSAndrew Vasquez if (ql4xextended_error_logging) 5434afaf5a2dSDavid Somayajulu strcat(qla4xxx_version_str, "-debug"); 5435afaf5a2dSDavid Somayajulu 5436afaf5a2dSDavid Somayajulu qla4xxx_scsi_transport = 5437afaf5a2dSDavid Somayajulu iscsi_register_transport(&qla4xxx_iscsi_transport); 5438afaf5a2dSDavid Somayajulu if (!qla4xxx_scsi_transport){ 5439afaf5a2dSDavid Somayajulu ret = -ENODEV; 5440afaf5a2dSDavid Somayajulu goto release_srb_cache; 5441afaf5a2dSDavid Somayajulu } 5442afaf5a2dSDavid Somayajulu 5443afaf5a2dSDavid Somayajulu ret = pci_register_driver(&qla4xxx_pci_driver); 5444afaf5a2dSDavid Somayajulu if (ret) 5445afaf5a2dSDavid Somayajulu goto unregister_transport; 5446afaf5a2dSDavid Somayajulu 5447afaf5a2dSDavid Somayajulu printk(KERN_INFO "QLogic iSCSI HBA Driver\n"); 5448afaf5a2dSDavid Somayajulu return 0; 54495ae16db3SDoug Maxey 5450afaf5a2dSDavid Somayajulu unregister_transport: 5451afaf5a2dSDavid Somayajulu iscsi_unregister_transport(&qla4xxx_iscsi_transport); 5452afaf5a2dSDavid Somayajulu release_srb_cache: 5453afaf5a2dSDavid Somayajulu kmem_cache_destroy(srb_cachep); 5454afaf5a2dSDavid Somayajulu no_srp_cache: 5455afaf5a2dSDavid Somayajulu return ret; 5456afaf5a2dSDavid Somayajulu } 5457afaf5a2dSDavid Somayajulu 5458afaf5a2dSDavid Somayajulu static void __exit qla4xxx_module_exit(void) 5459afaf5a2dSDavid Somayajulu { 5460afaf5a2dSDavid Somayajulu pci_unregister_driver(&qla4xxx_pci_driver); 5461afaf5a2dSDavid Somayajulu iscsi_unregister_transport(&qla4xxx_iscsi_transport); 5462afaf5a2dSDavid Somayajulu kmem_cache_destroy(srb_cachep); 5463afaf5a2dSDavid Somayajulu } 5464afaf5a2dSDavid Somayajulu 5465afaf5a2dSDavid Somayajulu module_init(qla4xxx_module_init); 5466afaf5a2dSDavid Somayajulu module_exit(qla4xxx_module_exit); 5467afaf5a2dSDavid Somayajulu 5468afaf5a2dSDavid Somayajulu MODULE_AUTHOR("QLogic Corporation"); 5469afaf5a2dSDavid Somayajulu MODULE_DESCRIPTION("QLogic iSCSI HBA Driver"); 5470afaf5a2dSDavid Somayajulu MODULE_LICENSE("GPL"); 5471afaf5a2dSDavid Somayajulu MODULE_VERSION(QLA4XXX_DRIVER_VERSION); 5472