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> 9afaf5a2dSDavid Somayajulu 10afaf5a2dSDavid Somayajulu #include <scsi/scsi_tcq.h> 11afaf5a2dSDavid Somayajulu #include <scsi/scsicam.h> 12afaf5a2dSDavid Somayajulu 13afaf5a2dSDavid Somayajulu #include "ql4_def.h" 14bee4fe8eSDavid C Somayajulu #include "ql4_version.h" 15bee4fe8eSDavid C Somayajulu #include "ql4_glbl.h" 16bee4fe8eSDavid C Somayajulu #include "ql4_dbg.h" 17bee4fe8eSDavid C Somayajulu #include "ql4_inline.h" 18afaf5a2dSDavid Somayajulu 19afaf5a2dSDavid Somayajulu /* 20afaf5a2dSDavid Somayajulu * Driver version 21afaf5a2dSDavid Somayajulu */ 2247975477SAdrian Bunk static char qla4xxx_version_str[40]; 23afaf5a2dSDavid Somayajulu 24afaf5a2dSDavid Somayajulu /* 25afaf5a2dSDavid Somayajulu * SRB allocation cache 26afaf5a2dSDavid Somayajulu */ 27e18b890bSChristoph Lameter static struct kmem_cache *srb_cachep; 28afaf5a2dSDavid Somayajulu 29afaf5a2dSDavid Somayajulu /* 30afaf5a2dSDavid Somayajulu * Module parameter information and variables 31afaf5a2dSDavid Somayajulu */ 32afaf5a2dSDavid Somayajulu int ql4xdontresethba = 0; 33f4f5df23SVikas Chaudhary module_param(ql4xdontresethba, int, S_IRUGO | S_IWUSR); 34afaf5a2dSDavid Somayajulu MODULE_PARM_DESC(ql4xdontresethba, 35f4f5df23SVikas Chaudhary "Don't reset the HBA for driver recovery \n" 36f4f5df23SVikas Chaudhary " 0 - It will reset HBA (Default)\n" 37f4f5df23SVikas Chaudhary " 1 - It will NOT reset HBA"); 38afaf5a2dSDavid Somayajulu 3911010fecSAndrew Vasquez int ql4xextended_error_logging = 0; /* 0 = off, 1 = log errors */ 40f4f5df23SVikas Chaudhary module_param(ql4xextended_error_logging, int, S_IRUGO | S_IWUSR); 4111010fecSAndrew Vasquez MODULE_PARM_DESC(ql4xextended_error_logging, 42afaf5a2dSDavid Somayajulu "Option to enable extended error logging, " 43afaf5a2dSDavid Somayajulu "Default is 0 - no logging, 1 - debug logging"); 44afaf5a2dSDavid Somayajulu 45f4f5df23SVikas Chaudhary int ql4xenablemsix = 1; 46f4f5df23SVikas Chaudhary module_param(ql4xenablemsix, int, S_IRUGO|S_IWUSR); 47f4f5df23SVikas Chaudhary MODULE_PARM_DESC(ql4xenablemsix, 48f4f5df23SVikas Chaudhary "Set to enable MSI or MSI-X interrupt mechanism.\n" 49f4f5df23SVikas Chaudhary " 0 = enable INTx interrupt mechanism.\n" 50f4f5df23SVikas Chaudhary " 1 = enable MSI-X interrupt mechanism (Default).\n" 51f4f5df23SVikas Chaudhary " 2 = enable MSI interrupt mechanism."); 52477ffb9dSDavid C Somayajulu 53d510d965SMike Christie #define QL4_DEF_QDEPTH 32 548bb4033dSVikas Chaudhary static int ql4xmaxqdepth = QL4_DEF_QDEPTH; 558bb4033dSVikas Chaudhary module_param(ql4xmaxqdepth, int, S_IRUGO | S_IWUSR); 568bb4033dSVikas Chaudhary MODULE_PARM_DESC(ql4xmaxqdepth, 578bb4033dSVikas Chaudhary "Maximum queue depth to report for target devices.\n" 588bb4033dSVikas Chaudhary " Default: 32."); 59d510d965SMike Christie 603038727cSVikas Chaudhary static int ql4xsess_recovery_tmo = QL4_SESS_RECOVERY_TMO; 613038727cSVikas Chaudhary module_param(ql4xsess_recovery_tmo, int, S_IRUGO); 623038727cSVikas Chaudhary MODULE_PARM_DESC(ql4xsess_recovery_tmo, 633038727cSVikas Chaudhary "Target Session Recovery Timeout.\n" 643038727cSVikas Chaudhary " Default: 30 sec."); 653038727cSVikas Chaudhary 66b3a271a9SManish Rangankar static int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha); 67afaf5a2dSDavid Somayajulu /* 68afaf5a2dSDavid Somayajulu * SCSI host template entry points 69afaf5a2dSDavid Somayajulu */ 7047975477SAdrian Bunk static void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha); 71afaf5a2dSDavid Somayajulu 72afaf5a2dSDavid Somayajulu /* 73afaf5a2dSDavid Somayajulu * iSCSI template entry points 74afaf5a2dSDavid Somayajulu */ 75afaf5a2dSDavid Somayajulu static int qla4xxx_conn_get_param(struct iscsi_cls_conn *conn, 76afaf5a2dSDavid Somayajulu enum iscsi_param param, char *buf); 77aa1e93a2SMike Christie static int qla4xxx_host_get_param(struct Scsi_Host *shost, 78aa1e93a2SMike Christie enum iscsi_host_param param, char *buf); 79d00efe3fSMike Christie static int qla4xxx_iface_set_param(struct Scsi_Host *shost, char *data, 80d00efe3fSMike Christie int count); 81ed1086e0SVikas Chaudhary static int qla4xxx_get_iface_param(struct iscsi_iface *iface, 82ed1086e0SVikas Chaudhary enum iscsi_param_type param_type, 83ed1086e0SVikas Chaudhary int param, char *buf); 845c656af7SMike Christie static enum blk_eh_timer_return qla4xxx_eh_cmd_timed_out(struct scsi_cmnd *sc); 85b3a271a9SManish Rangankar static struct iscsi_endpoint *qla4xxx_ep_connect(struct Scsi_Host *shost, 86b3a271a9SManish Rangankar struct sockaddr *dst_addr, 87b3a271a9SManish Rangankar int non_blocking); 88b3a271a9SManish Rangankar static int qla4xxx_ep_poll(struct iscsi_endpoint *ep, int timeout_ms); 89b3a271a9SManish Rangankar static void qla4xxx_ep_disconnect(struct iscsi_endpoint *ep); 90b3a271a9SManish Rangankar static int qla4xxx_get_ep_param(struct iscsi_endpoint *ep, 91b3a271a9SManish Rangankar enum iscsi_param param, char *buf); 92b3a271a9SManish Rangankar static int qla4xxx_conn_start(struct iscsi_cls_conn *conn); 93b3a271a9SManish Rangankar static struct iscsi_cls_conn * 94b3a271a9SManish Rangankar qla4xxx_conn_create(struct iscsi_cls_session *cls_sess, uint32_t conn_idx); 95b3a271a9SManish Rangankar static int qla4xxx_conn_bind(struct iscsi_cls_session *cls_session, 96b3a271a9SManish Rangankar struct iscsi_cls_conn *cls_conn, 97b3a271a9SManish Rangankar uint64_t transport_fd, int is_leading); 98b3a271a9SManish Rangankar static void qla4xxx_conn_destroy(struct iscsi_cls_conn *conn); 99b3a271a9SManish Rangankar static struct iscsi_cls_session * 100b3a271a9SManish Rangankar qla4xxx_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max, 101b3a271a9SManish Rangankar uint16_t qdepth, uint32_t initial_cmdsn); 102b3a271a9SManish Rangankar static void qla4xxx_session_destroy(struct iscsi_cls_session *sess); 103b3a271a9SManish Rangankar static void qla4xxx_task_work(struct work_struct *wdata); 104b3a271a9SManish Rangankar static int qla4xxx_alloc_pdu(struct iscsi_task *, uint8_t); 105b3a271a9SManish Rangankar static int qla4xxx_task_xmit(struct iscsi_task *); 106b3a271a9SManish Rangankar static void qla4xxx_task_cleanup(struct iscsi_task *); 107b3a271a9SManish Rangankar static void qla4xxx_fail_session(struct iscsi_cls_session *cls_session); 108b3a271a9SManish Rangankar static void qla4xxx_conn_get_stats(struct iscsi_cls_conn *cls_conn, 109b3a271a9SManish Rangankar struct iscsi_stats *stats); 110afaf5a2dSDavid Somayajulu /* 111afaf5a2dSDavid Somayajulu * SCSI host template entry points 112afaf5a2dSDavid Somayajulu */ 113f281233dSJeff Garzik static int qla4xxx_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *cmd); 11409a0f719SVikas Chaudhary static int qla4xxx_eh_abort(struct scsi_cmnd *cmd); 115afaf5a2dSDavid Somayajulu static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd); 116ce545039SMike Christie static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd); 117afaf5a2dSDavid Somayajulu static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd); 118afaf5a2dSDavid Somayajulu static int qla4xxx_slave_alloc(struct scsi_device *device); 119afaf5a2dSDavid Somayajulu static int qla4xxx_slave_configure(struct scsi_device *device); 120afaf5a2dSDavid Somayajulu static void qla4xxx_slave_destroy(struct scsi_device *sdev); 1213128c6c7SMike Christie static mode_t ql4_attr_is_visible(int param_type, int param); 122afaf5a2dSDavid Somayajulu 123f4f5df23SVikas Chaudhary static struct qla4_8xxx_legacy_intr_set legacy_intr[] = 124f4f5df23SVikas Chaudhary QLA82XX_LEGACY_INTR_CONFIG; 125f4f5df23SVikas Chaudhary 126afaf5a2dSDavid Somayajulu static struct scsi_host_template qla4xxx_driver_template = { 127afaf5a2dSDavid Somayajulu .module = THIS_MODULE, 128afaf5a2dSDavid Somayajulu .name = DRIVER_NAME, 129afaf5a2dSDavid Somayajulu .proc_name = DRIVER_NAME, 130afaf5a2dSDavid Somayajulu .queuecommand = qla4xxx_queuecommand, 131afaf5a2dSDavid Somayajulu 13209a0f719SVikas Chaudhary .eh_abort_handler = qla4xxx_eh_abort, 133afaf5a2dSDavid Somayajulu .eh_device_reset_handler = qla4xxx_eh_device_reset, 134ce545039SMike Christie .eh_target_reset_handler = qla4xxx_eh_target_reset, 135afaf5a2dSDavid Somayajulu .eh_host_reset_handler = qla4xxx_eh_host_reset, 1365c656af7SMike Christie .eh_timed_out = qla4xxx_eh_cmd_timed_out, 137afaf5a2dSDavid Somayajulu 138afaf5a2dSDavid Somayajulu .slave_configure = qla4xxx_slave_configure, 139afaf5a2dSDavid Somayajulu .slave_alloc = qla4xxx_slave_alloc, 140afaf5a2dSDavid Somayajulu .slave_destroy = qla4xxx_slave_destroy, 141afaf5a2dSDavid Somayajulu 142afaf5a2dSDavid Somayajulu .this_id = -1, 143afaf5a2dSDavid Somayajulu .cmd_per_lun = 3, 144afaf5a2dSDavid Somayajulu .use_clustering = ENABLE_CLUSTERING, 145afaf5a2dSDavid Somayajulu .sg_tablesize = SG_ALL, 146afaf5a2dSDavid Somayajulu 147afaf5a2dSDavid Somayajulu .max_sectors = 0xFFFF, 1487ad633c0SHarish Zunjarrao .shost_attrs = qla4xxx_host_attrs, 149a355943cSVikas Chaudhary .vendor_id = SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_QLOGIC, 150afaf5a2dSDavid Somayajulu }; 151afaf5a2dSDavid Somayajulu 152afaf5a2dSDavid Somayajulu static struct iscsi_transport qla4xxx_iscsi_transport = { 153afaf5a2dSDavid Somayajulu .owner = THIS_MODULE, 154afaf5a2dSDavid Somayajulu .name = DRIVER_NAME, 155b3a271a9SManish Rangankar .caps = CAP_TEXT_NEGO | 156b3a271a9SManish Rangankar CAP_DATA_PATH_OFFLOAD | CAP_HDRDGST | 157b3a271a9SManish Rangankar CAP_DATADGST | CAP_LOGIN_OFFLOAD | 158b3a271a9SManish Rangankar CAP_MULTI_R2T, 1593128c6c7SMike Christie .attr_is_visible = ql4_attr_is_visible, 160b3a271a9SManish Rangankar .create_session = qla4xxx_session_create, 161b3a271a9SManish Rangankar .destroy_session = qla4xxx_session_destroy, 162b3a271a9SManish Rangankar .start_conn = qla4xxx_conn_start, 163b3a271a9SManish Rangankar .create_conn = qla4xxx_conn_create, 164b3a271a9SManish Rangankar .bind_conn = qla4xxx_conn_bind, 165b3a271a9SManish Rangankar .stop_conn = iscsi_conn_stop, 166b3a271a9SManish Rangankar .destroy_conn = qla4xxx_conn_destroy, 167b3a271a9SManish Rangankar .set_param = iscsi_set_param, 168afaf5a2dSDavid Somayajulu .get_conn_param = qla4xxx_conn_get_param, 169b3a271a9SManish Rangankar .get_session_param = iscsi_session_get_param, 170b3a271a9SManish Rangankar .get_ep_param = qla4xxx_get_ep_param, 171b3a271a9SManish Rangankar .ep_connect = qla4xxx_ep_connect, 172b3a271a9SManish Rangankar .ep_poll = qla4xxx_ep_poll, 173b3a271a9SManish Rangankar .ep_disconnect = qla4xxx_ep_disconnect, 174b3a271a9SManish Rangankar .get_stats = qla4xxx_conn_get_stats, 175b3a271a9SManish Rangankar .send_pdu = iscsi_conn_send_pdu, 176b3a271a9SManish Rangankar .xmit_task = qla4xxx_task_xmit, 177b3a271a9SManish Rangankar .cleanup_task = qla4xxx_task_cleanup, 178b3a271a9SManish Rangankar .alloc_pdu = qla4xxx_alloc_pdu, 179b3a271a9SManish Rangankar 180aa1e93a2SMike Christie .get_host_param = qla4xxx_host_get_param, 181d00efe3fSMike Christie .set_iface_param = qla4xxx_iface_set_param, 182ed1086e0SVikas Chaudhary .get_iface_param = qla4xxx_get_iface_param, 183a355943cSVikas Chaudhary .bsg_request = qla4xxx_bsg_request, 184afaf5a2dSDavid Somayajulu }; 185afaf5a2dSDavid Somayajulu 186afaf5a2dSDavid Somayajulu static struct scsi_transport_template *qla4xxx_scsi_transport; 187afaf5a2dSDavid Somayajulu 1883128c6c7SMike Christie static mode_t ql4_attr_is_visible(int param_type, int param) 1893128c6c7SMike Christie { 1903128c6c7SMike Christie switch (param_type) { 191f27fb2efSMike Christie case ISCSI_HOST_PARAM: 192f27fb2efSMike Christie switch (param) { 193f27fb2efSMike Christie case ISCSI_HOST_PARAM_HWADDRESS: 194f27fb2efSMike Christie case ISCSI_HOST_PARAM_IPADDRESS: 195f27fb2efSMike Christie case ISCSI_HOST_PARAM_INITIATOR_NAME: 196f27fb2efSMike Christie return S_IRUGO; 197f27fb2efSMike Christie default: 198f27fb2efSMike Christie return 0; 199f27fb2efSMike Christie } 2003128c6c7SMike Christie case ISCSI_PARAM: 2013128c6c7SMike Christie switch (param) { 2023128c6c7SMike Christie case ISCSI_PARAM_CONN_ADDRESS: 2033128c6c7SMike Christie case ISCSI_PARAM_CONN_PORT: 2041d063c17SMike Christie case ISCSI_PARAM_TARGET_NAME: 2051d063c17SMike Christie case ISCSI_PARAM_TPGT: 2061d063c17SMike Christie case ISCSI_PARAM_TARGET_ALIAS: 207b3a271a9SManish Rangankar case ISCSI_PARAM_MAX_BURST: 208b3a271a9SManish Rangankar case ISCSI_PARAM_MAX_R2T: 209b3a271a9SManish Rangankar case ISCSI_PARAM_FIRST_BURST: 210b3a271a9SManish Rangankar case ISCSI_PARAM_MAX_RECV_DLENGTH: 211b3a271a9SManish Rangankar case ISCSI_PARAM_MAX_XMIT_DLENGTH: 2123128c6c7SMike Christie return S_IRUGO; 2133128c6c7SMike Christie default: 2143128c6c7SMike Christie return 0; 2153128c6c7SMike Christie } 216b78dbba0SMike Christie case ISCSI_NET_PARAM: 217b78dbba0SMike Christie switch (param) { 218b78dbba0SMike Christie case ISCSI_NET_PARAM_IPV4_ADDR: 219b78dbba0SMike Christie case ISCSI_NET_PARAM_IPV4_SUBNET: 220b78dbba0SMike Christie case ISCSI_NET_PARAM_IPV4_GW: 221b78dbba0SMike Christie case ISCSI_NET_PARAM_IPV4_BOOTPROTO: 222b78dbba0SMike Christie case ISCSI_NET_PARAM_IFACE_ENABLE: 223b78dbba0SMike Christie case ISCSI_NET_PARAM_IPV6_LINKLOCAL: 224b78dbba0SMike Christie case ISCSI_NET_PARAM_IPV6_ADDR: 225b78dbba0SMike Christie case ISCSI_NET_PARAM_IPV6_ROUTER: 226b78dbba0SMike Christie case ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG: 227b78dbba0SMike Christie case ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG: 2286ac73e8cSVikas Chaudhary case ISCSI_NET_PARAM_VLAN_ID: 2296ac73e8cSVikas Chaudhary case ISCSI_NET_PARAM_VLAN_PRIORITY: 2306ac73e8cSVikas Chaudhary case ISCSI_NET_PARAM_VLAN_ENABLED: 231b78dbba0SMike Christie return S_IRUGO; 232b78dbba0SMike Christie default: 233b78dbba0SMike Christie return 0; 234b78dbba0SMike Christie } 2353128c6c7SMike Christie } 2363128c6c7SMike Christie 2373128c6c7SMike Christie return 0; 2383128c6c7SMike Christie } 2393128c6c7SMike Christie 240ed1086e0SVikas Chaudhary static int qla4xxx_get_iface_param(struct iscsi_iface *iface, 241ed1086e0SVikas Chaudhary enum iscsi_param_type param_type, 242ed1086e0SVikas Chaudhary int param, char *buf) 243ed1086e0SVikas Chaudhary { 244ed1086e0SVikas Chaudhary struct Scsi_Host *shost = iscsi_iface_to_shost(iface); 245ed1086e0SVikas Chaudhary struct scsi_qla_host *ha = to_qla_host(shost); 246ed1086e0SVikas Chaudhary int len = -ENOSYS; 247ed1086e0SVikas Chaudhary 248ed1086e0SVikas Chaudhary if (param_type != ISCSI_NET_PARAM) 249ed1086e0SVikas Chaudhary return -ENOSYS; 250ed1086e0SVikas Chaudhary 251ed1086e0SVikas Chaudhary switch (param) { 252ed1086e0SVikas Chaudhary case ISCSI_NET_PARAM_IPV4_ADDR: 253ed1086e0SVikas Chaudhary len = sprintf(buf, "%pI4\n", &ha->ip_config.ip_address); 254ed1086e0SVikas Chaudhary break; 255ed1086e0SVikas Chaudhary case ISCSI_NET_PARAM_IPV4_SUBNET: 256ed1086e0SVikas Chaudhary len = sprintf(buf, "%pI4\n", &ha->ip_config.subnet_mask); 257ed1086e0SVikas Chaudhary break; 258ed1086e0SVikas Chaudhary case ISCSI_NET_PARAM_IPV4_GW: 259ed1086e0SVikas Chaudhary len = sprintf(buf, "%pI4\n", &ha->ip_config.gateway); 260ed1086e0SVikas Chaudhary break; 261ed1086e0SVikas Chaudhary case ISCSI_NET_PARAM_IFACE_ENABLE: 262ed1086e0SVikas Chaudhary if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) 263ed1086e0SVikas Chaudhary len = sprintf(buf, "%s\n", 264ed1086e0SVikas Chaudhary (ha->ip_config.ipv4_options & 265ed1086e0SVikas Chaudhary IPOPT_IPV4_PROTOCOL_ENABLE) ? 266ed1086e0SVikas Chaudhary "enabled" : "disabled"); 267ed1086e0SVikas Chaudhary else if (iface->iface_type == ISCSI_IFACE_TYPE_IPV6) 268ed1086e0SVikas Chaudhary len = sprintf(buf, "%s\n", 269ed1086e0SVikas Chaudhary (ha->ip_config.ipv6_options & 270ed1086e0SVikas Chaudhary IPV6_OPT_IPV6_PROTOCOL_ENABLE) ? 271ed1086e0SVikas Chaudhary "enabled" : "disabled"); 272ed1086e0SVikas Chaudhary break; 273ed1086e0SVikas Chaudhary case ISCSI_NET_PARAM_IPV4_BOOTPROTO: 274ed1086e0SVikas Chaudhary len = sprintf(buf, "%s\n", 275ed1086e0SVikas Chaudhary (ha->ip_config.tcp_options & TCPOPT_DHCP_ENABLE) ? 276ed1086e0SVikas Chaudhary "dhcp" : "static"); 277ed1086e0SVikas Chaudhary break; 278ed1086e0SVikas Chaudhary case ISCSI_NET_PARAM_IPV6_ADDR: 279ed1086e0SVikas Chaudhary if (iface->iface_num == 0) 280ed1086e0SVikas Chaudhary len = sprintf(buf, "%pI6\n", &ha->ip_config.ipv6_addr0); 281ed1086e0SVikas Chaudhary if (iface->iface_num == 1) 282ed1086e0SVikas Chaudhary len = sprintf(buf, "%pI6\n", &ha->ip_config.ipv6_addr1); 283ed1086e0SVikas Chaudhary break; 284ed1086e0SVikas Chaudhary case ISCSI_NET_PARAM_IPV6_LINKLOCAL: 285ed1086e0SVikas Chaudhary len = sprintf(buf, "%pI6\n", 286ed1086e0SVikas Chaudhary &ha->ip_config.ipv6_link_local_addr); 287ed1086e0SVikas Chaudhary break; 288ed1086e0SVikas Chaudhary case ISCSI_NET_PARAM_IPV6_ROUTER: 289ed1086e0SVikas Chaudhary len = sprintf(buf, "%pI6\n", 290ed1086e0SVikas Chaudhary &ha->ip_config.ipv6_default_router_addr); 291ed1086e0SVikas Chaudhary break; 292ed1086e0SVikas Chaudhary case ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG: 293ed1086e0SVikas Chaudhary len = sprintf(buf, "%s\n", 294ed1086e0SVikas Chaudhary (ha->ip_config.ipv6_addl_options & 295ed1086e0SVikas Chaudhary IPV6_ADDOPT_NEIGHBOR_DISCOVERY_ADDR_ENABLE) ? 296ed1086e0SVikas Chaudhary "nd" : "static"); 297ed1086e0SVikas Chaudhary break; 298ed1086e0SVikas Chaudhary case ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG: 299ed1086e0SVikas Chaudhary len = sprintf(buf, "%s\n", 300ed1086e0SVikas Chaudhary (ha->ip_config.ipv6_addl_options & 301ed1086e0SVikas Chaudhary IPV6_ADDOPT_AUTOCONFIG_LINK_LOCAL_ADDR) ? 302ed1086e0SVikas Chaudhary "auto" : "static"); 303ed1086e0SVikas Chaudhary break; 3046ac73e8cSVikas Chaudhary case ISCSI_NET_PARAM_VLAN_ID: 3056ac73e8cSVikas Chaudhary if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) 3066ac73e8cSVikas Chaudhary len = sprintf(buf, "%d\n", 3076ac73e8cSVikas Chaudhary (ha->ip_config.ipv4_vlan_tag & 3086ac73e8cSVikas Chaudhary ISCSI_MAX_VLAN_ID)); 3096ac73e8cSVikas Chaudhary else if (iface->iface_type == ISCSI_IFACE_TYPE_IPV6) 3106ac73e8cSVikas Chaudhary len = sprintf(buf, "%d\n", 3116ac73e8cSVikas Chaudhary (ha->ip_config.ipv6_vlan_tag & 3126ac73e8cSVikas Chaudhary ISCSI_MAX_VLAN_ID)); 3136ac73e8cSVikas Chaudhary break; 3146ac73e8cSVikas Chaudhary case ISCSI_NET_PARAM_VLAN_PRIORITY: 3156ac73e8cSVikas Chaudhary if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) 3166ac73e8cSVikas Chaudhary len = sprintf(buf, "%d\n", 3176ac73e8cSVikas Chaudhary ((ha->ip_config.ipv4_vlan_tag >> 13) & 3186ac73e8cSVikas Chaudhary ISCSI_MAX_VLAN_PRIORITY)); 3196ac73e8cSVikas Chaudhary else if (iface->iface_type == ISCSI_IFACE_TYPE_IPV6) 3206ac73e8cSVikas Chaudhary len = sprintf(buf, "%d\n", 3216ac73e8cSVikas Chaudhary ((ha->ip_config.ipv6_vlan_tag >> 13) & 3226ac73e8cSVikas Chaudhary ISCSI_MAX_VLAN_PRIORITY)); 3236ac73e8cSVikas Chaudhary break; 3246ac73e8cSVikas Chaudhary case ISCSI_NET_PARAM_VLAN_ENABLED: 3256ac73e8cSVikas Chaudhary if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) 3266ac73e8cSVikas Chaudhary len = sprintf(buf, "%s\n", 3276ac73e8cSVikas Chaudhary (ha->ip_config.ipv4_options & 3286ac73e8cSVikas Chaudhary IPOPT_VLAN_TAGGING_ENABLE) ? 3296ac73e8cSVikas Chaudhary "enabled" : "disabled"); 3306ac73e8cSVikas Chaudhary else if (iface->iface_type == ISCSI_IFACE_TYPE_IPV6) 3316ac73e8cSVikas Chaudhary len = sprintf(buf, "%s\n", 3326ac73e8cSVikas Chaudhary (ha->ip_config.ipv6_options & 3336ac73e8cSVikas Chaudhary IPV6_OPT_VLAN_TAGGING_ENABLE) ? 3346ac73e8cSVikas Chaudhary "enabled" : "disabled"); 3356ac73e8cSVikas Chaudhary break; 336ed1086e0SVikas Chaudhary default: 337ed1086e0SVikas Chaudhary len = -ENOSYS; 338ed1086e0SVikas Chaudhary } 339ed1086e0SVikas Chaudhary 340ed1086e0SVikas Chaudhary return len; 341ed1086e0SVikas Chaudhary } 342ed1086e0SVikas Chaudhary 343b3a271a9SManish Rangankar static struct iscsi_endpoint * 344b3a271a9SManish Rangankar qla4xxx_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr, 345b3a271a9SManish Rangankar int non_blocking) 346b3a271a9SManish Rangankar { 347b3a271a9SManish Rangankar int ret; 348b3a271a9SManish Rangankar struct iscsi_endpoint *ep; 349b3a271a9SManish Rangankar struct qla_endpoint *qla_ep; 350b3a271a9SManish Rangankar struct scsi_qla_host *ha; 351b3a271a9SManish Rangankar struct sockaddr_in *addr; 352b3a271a9SManish Rangankar struct sockaddr_in6 *addr6; 353b3a271a9SManish Rangankar 354b3a271a9SManish Rangankar DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); 355b3a271a9SManish Rangankar if (!shost) { 356b3a271a9SManish Rangankar ret = -ENXIO; 357b3a271a9SManish Rangankar printk(KERN_ERR "%s: shost is NULL\n", 358b3a271a9SManish Rangankar __func__); 359b3a271a9SManish Rangankar return ERR_PTR(ret); 360b3a271a9SManish Rangankar } 361b3a271a9SManish Rangankar 362b3a271a9SManish Rangankar ha = iscsi_host_priv(shost); 363b3a271a9SManish Rangankar 364b3a271a9SManish Rangankar ep = iscsi_create_endpoint(sizeof(struct qla_endpoint)); 365b3a271a9SManish Rangankar if (!ep) { 366b3a271a9SManish Rangankar ret = -ENOMEM; 367b3a271a9SManish Rangankar return ERR_PTR(ret); 368b3a271a9SManish Rangankar } 369b3a271a9SManish Rangankar 370b3a271a9SManish Rangankar qla_ep = ep->dd_data; 371b3a271a9SManish Rangankar memset(qla_ep, 0, sizeof(struct qla_endpoint)); 372b3a271a9SManish Rangankar if (dst_addr->sa_family == AF_INET) { 373b3a271a9SManish Rangankar memcpy(&qla_ep->dst_addr, dst_addr, sizeof(struct sockaddr_in)); 374b3a271a9SManish Rangankar addr = (struct sockaddr_in *)&qla_ep->dst_addr; 375b3a271a9SManish Rangankar DEBUG2(ql4_printk(KERN_INFO, ha, "%s: %pI4\n", __func__, 376b3a271a9SManish Rangankar (char *)&addr->sin_addr)); 377b3a271a9SManish Rangankar } else if (dst_addr->sa_family == AF_INET6) { 378b3a271a9SManish Rangankar memcpy(&qla_ep->dst_addr, dst_addr, 379b3a271a9SManish Rangankar sizeof(struct sockaddr_in6)); 380b3a271a9SManish Rangankar addr6 = (struct sockaddr_in6 *)&qla_ep->dst_addr; 381b3a271a9SManish Rangankar DEBUG2(ql4_printk(KERN_INFO, ha, "%s: %pI6\n", __func__, 382b3a271a9SManish Rangankar (char *)&addr6->sin6_addr)); 383b3a271a9SManish Rangankar } 384b3a271a9SManish Rangankar 385b3a271a9SManish Rangankar qla_ep->host = shost; 386b3a271a9SManish Rangankar 387b3a271a9SManish Rangankar return ep; 388b3a271a9SManish Rangankar } 389b3a271a9SManish Rangankar 390b3a271a9SManish Rangankar static int qla4xxx_ep_poll(struct iscsi_endpoint *ep, int timeout_ms) 391b3a271a9SManish Rangankar { 392b3a271a9SManish Rangankar struct qla_endpoint *qla_ep; 393b3a271a9SManish Rangankar struct scsi_qla_host *ha; 394b3a271a9SManish Rangankar int ret = 0; 395b3a271a9SManish Rangankar 396b3a271a9SManish Rangankar DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); 397b3a271a9SManish Rangankar qla_ep = ep->dd_data; 398b3a271a9SManish Rangankar ha = to_qla_host(qla_ep->host); 399b3a271a9SManish Rangankar 400b3a271a9SManish Rangankar if (adapter_up(ha)) 401b3a271a9SManish Rangankar ret = 1; 402b3a271a9SManish Rangankar 403b3a271a9SManish Rangankar return ret; 404b3a271a9SManish Rangankar } 405b3a271a9SManish Rangankar 406b3a271a9SManish Rangankar static void qla4xxx_ep_disconnect(struct iscsi_endpoint *ep) 407b3a271a9SManish Rangankar { 408b3a271a9SManish Rangankar DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); 409b3a271a9SManish Rangankar iscsi_destroy_endpoint(ep); 410b3a271a9SManish Rangankar } 411b3a271a9SManish Rangankar 412b3a271a9SManish Rangankar static int qla4xxx_get_ep_param(struct iscsi_endpoint *ep, 413b3a271a9SManish Rangankar enum iscsi_param param, 414b3a271a9SManish Rangankar char *buf) 415b3a271a9SManish Rangankar { 416b3a271a9SManish Rangankar struct qla_endpoint *qla_ep = ep->dd_data; 417b3a271a9SManish Rangankar struct sockaddr *dst_addr; 418b3a271a9SManish Rangankar 419b3a271a9SManish Rangankar DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); 420b3a271a9SManish Rangankar 421b3a271a9SManish Rangankar switch (param) { 422b3a271a9SManish Rangankar case ISCSI_PARAM_CONN_PORT: 423b3a271a9SManish Rangankar case ISCSI_PARAM_CONN_ADDRESS: 424b3a271a9SManish Rangankar if (!qla_ep) 425b3a271a9SManish Rangankar return -ENOTCONN; 426b3a271a9SManish Rangankar 427b3a271a9SManish Rangankar dst_addr = (struct sockaddr *)&qla_ep->dst_addr; 428b3a271a9SManish Rangankar if (!dst_addr) 429b3a271a9SManish Rangankar return -ENOTCONN; 430b3a271a9SManish Rangankar 431b3a271a9SManish Rangankar return iscsi_conn_get_addr_param((struct sockaddr_storage *) 432b3a271a9SManish Rangankar &qla_ep->dst_addr, param, buf); 433b3a271a9SManish Rangankar default: 434b3a271a9SManish Rangankar return -ENOSYS; 435b3a271a9SManish Rangankar } 436b3a271a9SManish Rangankar } 437b3a271a9SManish Rangankar 438b3a271a9SManish Rangankar static void qla4xxx_conn_get_stats(struct iscsi_cls_conn *cls_conn, 439b3a271a9SManish Rangankar struct iscsi_stats *stats) 440b3a271a9SManish Rangankar { 441b3a271a9SManish Rangankar struct iscsi_session *sess; 442b3a271a9SManish Rangankar struct iscsi_cls_session *cls_sess; 443b3a271a9SManish Rangankar struct ddb_entry *ddb_entry; 444b3a271a9SManish Rangankar struct scsi_qla_host *ha; 445b3a271a9SManish Rangankar struct ql_iscsi_stats *ql_iscsi_stats; 446b3a271a9SManish Rangankar int stats_size; 447b3a271a9SManish Rangankar int ret; 448b3a271a9SManish Rangankar dma_addr_t iscsi_stats_dma; 449b3a271a9SManish Rangankar 450b3a271a9SManish Rangankar DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); 451b3a271a9SManish Rangankar 452b3a271a9SManish Rangankar cls_sess = iscsi_conn_to_session(cls_conn); 453b3a271a9SManish Rangankar sess = cls_sess->dd_data; 454b3a271a9SManish Rangankar ddb_entry = sess->dd_data; 455b3a271a9SManish Rangankar ha = ddb_entry->ha; 456b3a271a9SManish Rangankar 457b3a271a9SManish Rangankar stats_size = PAGE_ALIGN(sizeof(struct ql_iscsi_stats)); 458b3a271a9SManish Rangankar /* Allocate memory */ 459b3a271a9SManish Rangankar ql_iscsi_stats = dma_alloc_coherent(&ha->pdev->dev, stats_size, 460b3a271a9SManish Rangankar &iscsi_stats_dma, GFP_KERNEL); 461b3a271a9SManish Rangankar if (!ql_iscsi_stats) { 462b3a271a9SManish Rangankar ql4_printk(KERN_ERR, ha, 463b3a271a9SManish Rangankar "Unable to allocate memory for iscsi stats\n"); 464b3a271a9SManish Rangankar goto exit_get_stats; 465b3a271a9SManish Rangankar } 466b3a271a9SManish Rangankar 467b3a271a9SManish Rangankar ret = qla4xxx_get_mgmt_data(ha, ddb_entry->fw_ddb_index, stats_size, 468b3a271a9SManish Rangankar iscsi_stats_dma); 469b3a271a9SManish Rangankar if (ret != QLA_SUCCESS) { 470b3a271a9SManish Rangankar ql4_printk(KERN_ERR, ha, 471b3a271a9SManish Rangankar "Unable to retreive iscsi stats\n"); 472b3a271a9SManish Rangankar goto free_stats; 473b3a271a9SManish Rangankar } 474b3a271a9SManish Rangankar 475b3a271a9SManish Rangankar /* octets */ 476b3a271a9SManish Rangankar stats->txdata_octets = le64_to_cpu(ql_iscsi_stats->tx_data_octets); 477b3a271a9SManish Rangankar stats->rxdata_octets = le64_to_cpu(ql_iscsi_stats->rx_data_octets); 478b3a271a9SManish Rangankar /* xmit pdus */ 479b3a271a9SManish Rangankar stats->noptx_pdus = le32_to_cpu(ql_iscsi_stats->tx_nopout_pdus); 480b3a271a9SManish Rangankar stats->scsicmd_pdus = le32_to_cpu(ql_iscsi_stats->tx_scsi_cmd_pdus); 481b3a271a9SManish Rangankar stats->tmfcmd_pdus = le32_to_cpu(ql_iscsi_stats->tx_tmf_cmd_pdus); 482b3a271a9SManish Rangankar stats->login_pdus = le32_to_cpu(ql_iscsi_stats->tx_login_cmd_pdus); 483b3a271a9SManish Rangankar stats->text_pdus = le32_to_cpu(ql_iscsi_stats->tx_text_cmd_pdus); 484b3a271a9SManish Rangankar stats->dataout_pdus = le32_to_cpu(ql_iscsi_stats->tx_scsi_write_pdus); 485b3a271a9SManish Rangankar stats->logout_pdus = le32_to_cpu(ql_iscsi_stats->tx_logout_cmd_pdus); 486b3a271a9SManish Rangankar stats->snack_pdus = le32_to_cpu(ql_iscsi_stats->tx_snack_req_pdus); 487b3a271a9SManish Rangankar /* recv pdus */ 488b3a271a9SManish Rangankar stats->noprx_pdus = le32_to_cpu(ql_iscsi_stats->rx_nopin_pdus); 489b3a271a9SManish Rangankar stats->scsirsp_pdus = le32_to_cpu(ql_iscsi_stats->rx_scsi_resp_pdus); 490b3a271a9SManish Rangankar stats->tmfrsp_pdus = le32_to_cpu(ql_iscsi_stats->rx_tmf_resp_pdus); 491b3a271a9SManish Rangankar stats->textrsp_pdus = le32_to_cpu(ql_iscsi_stats->rx_text_resp_pdus); 492b3a271a9SManish Rangankar stats->datain_pdus = le32_to_cpu(ql_iscsi_stats->rx_scsi_read_pdus); 493b3a271a9SManish Rangankar stats->logoutrsp_pdus = 494b3a271a9SManish Rangankar le32_to_cpu(ql_iscsi_stats->rx_logout_resp_pdus); 495b3a271a9SManish Rangankar stats->r2t_pdus = le32_to_cpu(ql_iscsi_stats->rx_r2t_pdus); 496b3a271a9SManish Rangankar stats->async_pdus = le32_to_cpu(ql_iscsi_stats->rx_async_pdus); 497b3a271a9SManish Rangankar stats->rjt_pdus = le32_to_cpu(ql_iscsi_stats->rx_reject_pdus); 498b3a271a9SManish Rangankar 499b3a271a9SManish Rangankar free_stats: 500b3a271a9SManish Rangankar dma_free_coherent(&ha->pdev->dev, stats_size, ql_iscsi_stats, 501b3a271a9SManish Rangankar iscsi_stats_dma); 502b3a271a9SManish Rangankar exit_get_stats: 503b3a271a9SManish Rangankar return; 504b3a271a9SManish Rangankar } 505b3a271a9SManish Rangankar 5065c656af7SMike Christie static enum blk_eh_timer_return qla4xxx_eh_cmd_timed_out(struct scsi_cmnd *sc) 5075c656af7SMike Christie { 5085c656af7SMike Christie struct iscsi_cls_session *session; 509b3a271a9SManish Rangankar struct iscsi_session *sess; 510b3a271a9SManish Rangankar unsigned long flags; 511b3a271a9SManish Rangankar enum blk_eh_timer_return ret = BLK_EH_NOT_HANDLED; 5125c656af7SMike Christie 5135c656af7SMike Christie session = starget_to_session(scsi_target(sc->device)); 514b3a271a9SManish Rangankar sess = session->dd_data; 5155c656af7SMike Christie 516b3a271a9SManish Rangankar spin_lock_irqsave(&session->lock, flags); 517b3a271a9SManish Rangankar if (session->state == ISCSI_SESSION_FAILED) 518b3a271a9SManish Rangankar ret = BLK_EH_RESET_TIMER; 519b3a271a9SManish Rangankar spin_unlock_irqrestore(&session->lock, flags); 5205c656af7SMike Christie 521b3a271a9SManish Rangankar return ret; 522568d303bSMike Christie } 523afaf5a2dSDavid Somayajulu 524aa1e93a2SMike Christie static int qla4xxx_host_get_param(struct Scsi_Host *shost, 525aa1e93a2SMike Christie enum iscsi_host_param param, char *buf) 526aa1e93a2SMike Christie { 527aa1e93a2SMike Christie struct scsi_qla_host *ha = to_qla_host(shost); 528aa1e93a2SMike Christie int len; 529aa1e93a2SMike Christie 530aa1e93a2SMike Christie switch (param) { 531aa1e93a2SMike Christie case ISCSI_HOST_PARAM_HWADDRESS: 5327ffc49a6SMichael Chan len = sysfs_format_mac(buf, ha->my_mac, MAC_ADDR_LEN); 533aa1e93a2SMike Christie break; 53422236961SMike Christie case ISCSI_HOST_PARAM_IPADDRESS: 5352bab08fcSVikas Chaudhary len = sprintf(buf, "%pI4\n", &ha->ip_config.ip_address); 53622236961SMike Christie break; 5378ad5781aSMike Christie case ISCSI_HOST_PARAM_INITIATOR_NAME: 53822236961SMike Christie len = sprintf(buf, "%s\n", ha->name_string); 5398ad5781aSMike Christie break; 540aa1e93a2SMike Christie default: 541aa1e93a2SMike Christie return -ENOSYS; 542aa1e93a2SMike Christie } 543aa1e93a2SMike Christie 544aa1e93a2SMike Christie return len; 545aa1e93a2SMike Christie } 546aa1e93a2SMike Christie 547ed1086e0SVikas Chaudhary static void qla4xxx_create_ipv4_iface(struct scsi_qla_host *ha) 548ed1086e0SVikas Chaudhary { 549ed1086e0SVikas Chaudhary if (ha->iface_ipv4) 550ed1086e0SVikas Chaudhary return; 551ed1086e0SVikas Chaudhary 552ed1086e0SVikas Chaudhary /* IPv4 */ 553ed1086e0SVikas Chaudhary ha->iface_ipv4 = iscsi_create_iface(ha->host, 554ed1086e0SVikas Chaudhary &qla4xxx_iscsi_transport, 555ed1086e0SVikas Chaudhary ISCSI_IFACE_TYPE_IPV4, 0, 0); 556ed1086e0SVikas Chaudhary if (!ha->iface_ipv4) 557ed1086e0SVikas Chaudhary ql4_printk(KERN_ERR, ha, "Could not create IPv4 iSCSI " 558ed1086e0SVikas Chaudhary "iface0.\n"); 559ed1086e0SVikas Chaudhary } 560ed1086e0SVikas Chaudhary 561ed1086e0SVikas Chaudhary static void qla4xxx_create_ipv6_iface(struct scsi_qla_host *ha) 562ed1086e0SVikas Chaudhary { 563ed1086e0SVikas Chaudhary if (!ha->iface_ipv6_0) 564ed1086e0SVikas Chaudhary /* IPv6 iface-0 */ 565ed1086e0SVikas Chaudhary ha->iface_ipv6_0 = iscsi_create_iface(ha->host, 566ed1086e0SVikas Chaudhary &qla4xxx_iscsi_transport, 567ed1086e0SVikas Chaudhary ISCSI_IFACE_TYPE_IPV6, 0, 568ed1086e0SVikas Chaudhary 0); 569ed1086e0SVikas Chaudhary if (!ha->iface_ipv6_0) 570ed1086e0SVikas Chaudhary ql4_printk(KERN_ERR, ha, "Could not create IPv6 iSCSI " 571ed1086e0SVikas Chaudhary "iface0.\n"); 572ed1086e0SVikas Chaudhary 573ed1086e0SVikas Chaudhary if (!ha->iface_ipv6_1) 574ed1086e0SVikas Chaudhary /* IPv6 iface-1 */ 575ed1086e0SVikas Chaudhary ha->iface_ipv6_1 = iscsi_create_iface(ha->host, 576ed1086e0SVikas Chaudhary &qla4xxx_iscsi_transport, 577ed1086e0SVikas Chaudhary ISCSI_IFACE_TYPE_IPV6, 1, 578ed1086e0SVikas Chaudhary 0); 579ed1086e0SVikas Chaudhary if (!ha->iface_ipv6_1) 580ed1086e0SVikas Chaudhary ql4_printk(KERN_ERR, ha, "Could not create IPv6 iSCSI " 581ed1086e0SVikas Chaudhary "iface1.\n"); 582ed1086e0SVikas Chaudhary } 583ed1086e0SVikas Chaudhary 584ed1086e0SVikas Chaudhary static void qla4xxx_create_ifaces(struct scsi_qla_host *ha) 585ed1086e0SVikas Chaudhary { 586ed1086e0SVikas Chaudhary if (ha->ip_config.ipv4_options & IPOPT_IPV4_PROTOCOL_ENABLE) 587ed1086e0SVikas Chaudhary qla4xxx_create_ipv4_iface(ha); 588ed1086e0SVikas Chaudhary 589ed1086e0SVikas Chaudhary if (ha->ip_config.ipv6_options & IPV6_OPT_IPV6_PROTOCOL_ENABLE) 590ed1086e0SVikas Chaudhary qla4xxx_create_ipv6_iface(ha); 591ed1086e0SVikas Chaudhary } 592ed1086e0SVikas Chaudhary 593ed1086e0SVikas Chaudhary static void qla4xxx_destroy_ipv4_iface(struct scsi_qla_host *ha) 594ed1086e0SVikas Chaudhary { 595ed1086e0SVikas Chaudhary if (ha->iface_ipv4) { 596ed1086e0SVikas Chaudhary iscsi_destroy_iface(ha->iface_ipv4); 597ed1086e0SVikas Chaudhary ha->iface_ipv4 = NULL; 598ed1086e0SVikas Chaudhary } 599ed1086e0SVikas Chaudhary } 600ed1086e0SVikas Chaudhary 601ed1086e0SVikas Chaudhary static void qla4xxx_destroy_ipv6_iface(struct scsi_qla_host *ha) 602ed1086e0SVikas Chaudhary { 603ed1086e0SVikas Chaudhary if (ha->iface_ipv6_0) { 604ed1086e0SVikas Chaudhary iscsi_destroy_iface(ha->iface_ipv6_0); 605ed1086e0SVikas Chaudhary ha->iface_ipv6_0 = NULL; 606ed1086e0SVikas Chaudhary } 607ed1086e0SVikas Chaudhary if (ha->iface_ipv6_1) { 608ed1086e0SVikas Chaudhary iscsi_destroy_iface(ha->iface_ipv6_1); 609ed1086e0SVikas Chaudhary ha->iface_ipv6_1 = NULL; 610ed1086e0SVikas Chaudhary } 611ed1086e0SVikas Chaudhary } 612ed1086e0SVikas Chaudhary 613ed1086e0SVikas Chaudhary static void qla4xxx_destroy_ifaces(struct scsi_qla_host *ha) 614ed1086e0SVikas Chaudhary { 615ed1086e0SVikas Chaudhary qla4xxx_destroy_ipv4_iface(ha); 616ed1086e0SVikas Chaudhary qla4xxx_destroy_ipv6_iface(ha); 617ed1086e0SVikas Chaudhary } 618ed1086e0SVikas Chaudhary 619d00efe3fSMike Christie static void qla4xxx_set_ipv6(struct scsi_qla_host *ha, 620d00efe3fSMike Christie struct iscsi_iface_param_info *iface_param, 621d00efe3fSMike Christie struct addr_ctrl_blk *init_fw_cb) 622d00efe3fSMike Christie { 623d00efe3fSMike Christie /* 624d00efe3fSMike Christie * iface_num 0 is valid for IPv6 Addr, linklocal, router, autocfg. 625d00efe3fSMike Christie * iface_num 1 is valid only for IPv6 Addr. 626d00efe3fSMike Christie */ 627d00efe3fSMike Christie switch (iface_param->param) { 628d00efe3fSMike Christie case ISCSI_NET_PARAM_IPV6_ADDR: 629d00efe3fSMike Christie if (iface_param->iface_num & 0x1) 630d00efe3fSMike Christie /* IPv6 Addr 1 */ 631d00efe3fSMike Christie memcpy(init_fw_cb->ipv6_addr1, iface_param->value, 632d00efe3fSMike Christie sizeof(init_fw_cb->ipv6_addr1)); 633d00efe3fSMike Christie else 634d00efe3fSMike Christie /* IPv6 Addr 0 */ 635d00efe3fSMike Christie memcpy(init_fw_cb->ipv6_addr0, iface_param->value, 636d00efe3fSMike Christie sizeof(init_fw_cb->ipv6_addr0)); 637d00efe3fSMike Christie break; 638d00efe3fSMike Christie case ISCSI_NET_PARAM_IPV6_LINKLOCAL: 639d00efe3fSMike Christie if (iface_param->iface_num & 0x1) 640d00efe3fSMike Christie break; 641d00efe3fSMike Christie memcpy(init_fw_cb->ipv6_if_id, &iface_param->value[8], 642d00efe3fSMike Christie sizeof(init_fw_cb->ipv6_if_id)); 643d00efe3fSMike Christie break; 644d00efe3fSMike Christie case ISCSI_NET_PARAM_IPV6_ROUTER: 645d00efe3fSMike Christie if (iface_param->iface_num & 0x1) 646d00efe3fSMike Christie break; 647d00efe3fSMike Christie memcpy(init_fw_cb->ipv6_dflt_rtr_addr, iface_param->value, 648d00efe3fSMike Christie sizeof(init_fw_cb->ipv6_dflt_rtr_addr)); 649d00efe3fSMike Christie break; 650d00efe3fSMike Christie case ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG: 651d00efe3fSMike Christie /* Autocfg applies to even interface */ 652d00efe3fSMike Christie if (iface_param->iface_num & 0x1) 653d00efe3fSMike Christie break; 654d00efe3fSMike Christie 655d00efe3fSMike Christie if (iface_param->value[0] == ISCSI_IPV6_AUTOCFG_DISABLE) 656d00efe3fSMike Christie init_fw_cb->ipv6_addtl_opts &= 657d00efe3fSMike Christie cpu_to_le16( 658d00efe3fSMike Christie ~IPV6_ADDOPT_NEIGHBOR_DISCOVERY_ADDR_ENABLE); 659d00efe3fSMike Christie else if (iface_param->value[0] == ISCSI_IPV6_AUTOCFG_ND_ENABLE) 660d00efe3fSMike Christie init_fw_cb->ipv6_addtl_opts |= 661d00efe3fSMike Christie cpu_to_le16( 662d00efe3fSMike Christie IPV6_ADDOPT_NEIGHBOR_DISCOVERY_ADDR_ENABLE); 663d00efe3fSMike Christie else 664d00efe3fSMike Christie ql4_printk(KERN_ERR, ha, "Invalid autocfg setting for " 665d00efe3fSMike Christie "IPv6 addr\n"); 666d00efe3fSMike Christie break; 667d00efe3fSMike Christie case ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG: 668d00efe3fSMike Christie /* Autocfg applies to even interface */ 669d00efe3fSMike Christie if (iface_param->iface_num & 0x1) 670d00efe3fSMike Christie break; 671d00efe3fSMike Christie 672d00efe3fSMike Christie if (iface_param->value[0] == 673d00efe3fSMike Christie ISCSI_IPV6_LINKLOCAL_AUTOCFG_ENABLE) 674d00efe3fSMike Christie init_fw_cb->ipv6_addtl_opts |= cpu_to_le16( 675d00efe3fSMike Christie IPV6_ADDOPT_AUTOCONFIG_LINK_LOCAL_ADDR); 676d00efe3fSMike Christie else if (iface_param->value[0] == 677d00efe3fSMike Christie ISCSI_IPV6_LINKLOCAL_AUTOCFG_DISABLE) 678d00efe3fSMike Christie init_fw_cb->ipv6_addtl_opts &= cpu_to_le16( 679d00efe3fSMike Christie ~IPV6_ADDOPT_AUTOCONFIG_LINK_LOCAL_ADDR); 680d00efe3fSMike Christie else 681d00efe3fSMike Christie ql4_printk(KERN_ERR, ha, "Invalid autocfg setting for " 682d00efe3fSMike Christie "IPv6 linklocal addr\n"); 683d00efe3fSMike Christie break; 684d00efe3fSMike Christie case ISCSI_NET_PARAM_IPV6_ROUTER_AUTOCFG: 685d00efe3fSMike Christie /* Autocfg applies to even interface */ 686d00efe3fSMike Christie if (iface_param->iface_num & 0x1) 687d00efe3fSMike Christie break; 688d00efe3fSMike Christie 689d00efe3fSMike Christie if (iface_param->value[0] == ISCSI_IPV6_ROUTER_AUTOCFG_ENABLE) 690d00efe3fSMike Christie memset(init_fw_cb->ipv6_dflt_rtr_addr, 0, 691d00efe3fSMike Christie sizeof(init_fw_cb->ipv6_dflt_rtr_addr)); 692d00efe3fSMike Christie break; 693d00efe3fSMike Christie case ISCSI_NET_PARAM_IFACE_ENABLE: 694ed1086e0SVikas Chaudhary if (iface_param->value[0] == ISCSI_IFACE_ENABLE) { 695d00efe3fSMike Christie init_fw_cb->ipv6_opts |= 696d00efe3fSMike Christie cpu_to_le16(IPV6_OPT_IPV6_PROTOCOL_ENABLE); 697ed1086e0SVikas Chaudhary qla4xxx_create_ipv6_iface(ha); 698ed1086e0SVikas Chaudhary } else { 699d00efe3fSMike Christie init_fw_cb->ipv6_opts &= 700d00efe3fSMike Christie cpu_to_le16(~IPV6_OPT_IPV6_PROTOCOL_ENABLE & 701d00efe3fSMike Christie 0xFFFF); 702ed1086e0SVikas Chaudhary qla4xxx_destroy_ipv6_iface(ha); 703ed1086e0SVikas Chaudhary } 704d00efe3fSMike Christie break; 705d00efe3fSMike Christie case ISCSI_NET_PARAM_VLAN_ID: 706d00efe3fSMike Christie if (iface_param->len != sizeof(init_fw_cb->ipv6_vlan_tag)) 707d00efe3fSMike Christie break; 7086ac73e8cSVikas Chaudhary init_fw_cb->ipv6_vlan_tag = 7096ac73e8cSVikas Chaudhary cpu_to_be16(*(uint16_t *)iface_param->value); 7106ac73e8cSVikas Chaudhary break; 7116ac73e8cSVikas Chaudhary case ISCSI_NET_PARAM_VLAN_ENABLED: 7126ac73e8cSVikas Chaudhary if (iface_param->value[0] == ISCSI_VLAN_ENABLE) 7136ac73e8cSVikas Chaudhary init_fw_cb->ipv6_opts |= 7146ac73e8cSVikas Chaudhary cpu_to_le16(IPV6_OPT_VLAN_TAGGING_ENABLE); 7156ac73e8cSVikas Chaudhary else 7166ac73e8cSVikas Chaudhary init_fw_cb->ipv6_opts &= 7176ac73e8cSVikas Chaudhary cpu_to_le16(~IPV6_OPT_VLAN_TAGGING_ENABLE); 718d00efe3fSMike Christie break; 719d00efe3fSMike Christie default: 720d00efe3fSMike Christie ql4_printk(KERN_ERR, ha, "Unknown IPv6 param = %d\n", 721d00efe3fSMike Christie iface_param->param); 722d00efe3fSMike Christie break; 723d00efe3fSMike Christie } 724d00efe3fSMike Christie } 725d00efe3fSMike Christie 726d00efe3fSMike Christie static void qla4xxx_set_ipv4(struct scsi_qla_host *ha, 727d00efe3fSMike Christie struct iscsi_iface_param_info *iface_param, 728d00efe3fSMike Christie struct addr_ctrl_blk *init_fw_cb) 729d00efe3fSMike Christie { 730d00efe3fSMike Christie switch (iface_param->param) { 731d00efe3fSMike Christie case ISCSI_NET_PARAM_IPV4_ADDR: 732d00efe3fSMike Christie memcpy(init_fw_cb->ipv4_addr, iface_param->value, 733d00efe3fSMike Christie sizeof(init_fw_cb->ipv4_addr)); 734d00efe3fSMike Christie break; 735d00efe3fSMike Christie case ISCSI_NET_PARAM_IPV4_SUBNET: 736d00efe3fSMike Christie memcpy(init_fw_cb->ipv4_subnet, iface_param->value, 737d00efe3fSMike Christie sizeof(init_fw_cb->ipv4_subnet)); 738d00efe3fSMike Christie break; 739d00efe3fSMike Christie case ISCSI_NET_PARAM_IPV4_GW: 740d00efe3fSMike Christie memcpy(init_fw_cb->ipv4_gw_addr, iface_param->value, 741d00efe3fSMike Christie sizeof(init_fw_cb->ipv4_gw_addr)); 742d00efe3fSMike Christie break; 743d00efe3fSMike Christie case ISCSI_NET_PARAM_IPV4_BOOTPROTO: 744d00efe3fSMike Christie if (iface_param->value[0] == ISCSI_BOOTPROTO_DHCP) 745d00efe3fSMike Christie init_fw_cb->ipv4_tcp_opts |= 746d00efe3fSMike Christie cpu_to_le16(TCPOPT_DHCP_ENABLE); 747d00efe3fSMike Christie else if (iface_param->value[0] == ISCSI_BOOTPROTO_STATIC) 748d00efe3fSMike Christie init_fw_cb->ipv4_tcp_opts &= 749d00efe3fSMike Christie cpu_to_le16(~TCPOPT_DHCP_ENABLE); 750d00efe3fSMike Christie else 751d00efe3fSMike Christie ql4_printk(KERN_ERR, ha, "Invalid IPv4 bootproto\n"); 752d00efe3fSMike Christie break; 753d00efe3fSMike Christie case ISCSI_NET_PARAM_IFACE_ENABLE: 754ed1086e0SVikas Chaudhary if (iface_param->value[0] == ISCSI_IFACE_ENABLE) { 755d00efe3fSMike Christie init_fw_cb->ipv4_ip_opts |= 7562bab08fcSVikas Chaudhary cpu_to_le16(IPOPT_IPV4_PROTOCOL_ENABLE); 757ed1086e0SVikas Chaudhary qla4xxx_create_ipv4_iface(ha); 758ed1086e0SVikas Chaudhary } else { 759d00efe3fSMike Christie init_fw_cb->ipv4_ip_opts &= 7602bab08fcSVikas Chaudhary cpu_to_le16(~IPOPT_IPV4_PROTOCOL_ENABLE & 761d00efe3fSMike Christie 0xFFFF); 762ed1086e0SVikas Chaudhary qla4xxx_destroy_ipv4_iface(ha); 763ed1086e0SVikas Chaudhary } 764d00efe3fSMike Christie break; 765d00efe3fSMike Christie case ISCSI_NET_PARAM_VLAN_ID: 766d00efe3fSMike Christie if (iface_param->len != sizeof(init_fw_cb->ipv4_vlan_tag)) 767d00efe3fSMike Christie break; 7686ac73e8cSVikas Chaudhary init_fw_cb->ipv4_vlan_tag = 7696ac73e8cSVikas Chaudhary cpu_to_be16(*(uint16_t *)iface_param->value); 7706ac73e8cSVikas Chaudhary break; 7716ac73e8cSVikas Chaudhary case ISCSI_NET_PARAM_VLAN_ENABLED: 7726ac73e8cSVikas Chaudhary if (iface_param->value[0] == ISCSI_VLAN_ENABLE) 7736ac73e8cSVikas Chaudhary init_fw_cb->ipv4_ip_opts |= 7746ac73e8cSVikas Chaudhary cpu_to_le16(IPOPT_VLAN_TAGGING_ENABLE); 7756ac73e8cSVikas Chaudhary else 7766ac73e8cSVikas Chaudhary init_fw_cb->ipv4_ip_opts &= 7776ac73e8cSVikas Chaudhary cpu_to_le16(~IPOPT_VLAN_TAGGING_ENABLE); 778d00efe3fSMike Christie break; 779d00efe3fSMike Christie default: 780d00efe3fSMike Christie ql4_printk(KERN_ERR, ha, "Unknown IPv4 param = %d\n", 781d00efe3fSMike Christie iface_param->param); 782d00efe3fSMike Christie break; 783d00efe3fSMike Christie } 784d00efe3fSMike Christie } 785d00efe3fSMike Christie 786d00efe3fSMike Christie static void 787d00efe3fSMike Christie qla4xxx_initcb_to_acb(struct addr_ctrl_blk *init_fw_cb) 788d00efe3fSMike Christie { 789d00efe3fSMike Christie struct addr_ctrl_blk_def *acb; 790d00efe3fSMike Christie acb = (struct addr_ctrl_blk_def *)init_fw_cb; 791d00efe3fSMike Christie memset(acb->reserved1, 0, sizeof(acb->reserved1)); 792d00efe3fSMike Christie memset(acb->reserved2, 0, sizeof(acb->reserved2)); 793d00efe3fSMike Christie memset(acb->reserved3, 0, sizeof(acb->reserved3)); 794d00efe3fSMike Christie memset(acb->reserved4, 0, sizeof(acb->reserved4)); 795d00efe3fSMike Christie memset(acb->reserved5, 0, sizeof(acb->reserved5)); 796d00efe3fSMike Christie memset(acb->reserved6, 0, sizeof(acb->reserved6)); 797d00efe3fSMike Christie memset(acb->reserved7, 0, sizeof(acb->reserved7)); 798d00efe3fSMike Christie memset(acb->reserved8, 0, sizeof(acb->reserved8)); 799d00efe3fSMike Christie memset(acb->reserved9, 0, sizeof(acb->reserved9)); 800d00efe3fSMike Christie memset(acb->reserved10, 0, sizeof(acb->reserved10)); 801d00efe3fSMike Christie memset(acb->reserved11, 0, sizeof(acb->reserved11)); 802d00efe3fSMike Christie memset(acb->reserved12, 0, sizeof(acb->reserved12)); 803d00efe3fSMike Christie memset(acb->reserved13, 0, sizeof(acb->reserved13)); 804d00efe3fSMike Christie memset(acb->reserved14, 0, sizeof(acb->reserved14)); 805d00efe3fSMike Christie memset(acb->reserved15, 0, sizeof(acb->reserved15)); 806d00efe3fSMike Christie } 807d00efe3fSMike Christie 808d00efe3fSMike Christie static int 809d00efe3fSMike Christie qla4xxx_iface_set_param(struct Scsi_Host *shost, char *data, int count) 810d00efe3fSMike Christie { 811d00efe3fSMike Christie struct scsi_qla_host *ha = to_qla_host(shost); 812d00efe3fSMike Christie int rval = 0; 813d00efe3fSMike Christie struct iscsi_iface_param_info *iface_param = NULL; 814d00efe3fSMike Christie struct addr_ctrl_blk *init_fw_cb = NULL; 815d00efe3fSMike Christie dma_addr_t init_fw_cb_dma; 816d00efe3fSMike Christie uint32_t mbox_cmd[MBOX_REG_COUNT]; 817d00efe3fSMike Christie uint32_t mbox_sts[MBOX_REG_COUNT]; 818d00efe3fSMike Christie uint32_t total_param_count; 819d00efe3fSMike Christie uint32_t length; 820d00efe3fSMike Christie 821d00efe3fSMike Christie init_fw_cb = dma_alloc_coherent(&ha->pdev->dev, 822d00efe3fSMike Christie sizeof(struct addr_ctrl_blk), 823d00efe3fSMike Christie &init_fw_cb_dma, GFP_KERNEL); 824d00efe3fSMike Christie if (!init_fw_cb) { 825d00efe3fSMike Christie ql4_printk(KERN_ERR, ha, "%s: Unable to alloc init_cb\n", 826d00efe3fSMike Christie __func__); 827d00efe3fSMike Christie return -ENOMEM; 828d00efe3fSMike Christie } 829d00efe3fSMike Christie 830d00efe3fSMike Christie memset(init_fw_cb, 0, sizeof(struct addr_ctrl_blk)); 831d00efe3fSMike Christie memset(&mbox_cmd, 0, sizeof(mbox_cmd)); 832d00efe3fSMike Christie memset(&mbox_sts, 0, sizeof(mbox_sts)); 833d00efe3fSMike Christie 834d00efe3fSMike Christie if (qla4xxx_get_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb_dma)) { 835d00efe3fSMike Christie ql4_printk(KERN_ERR, ha, "%s: get ifcb failed\n", __func__); 836d00efe3fSMike Christie rval = -EIO; 837d00efe3fSMike Christie goto exit_init_fw_cb; 838d00efe3fSMike Christie } 839d00efe3fSMike Christie 840d00efe3fSMike Christie total_param_count = count; 841d00efe3fSMike Christie iface_param = (struct iscsi_iface_param_info *)data; 842d00efe3fSMike Christie 843d00efe3fSMike Christie for ( ; total_param_count != 0; total_param_count--) { 844d00efe3fSMike Christie length = iface_param->len; 845d00efe3fSMike Christie 846d00efe3fSMike Christie if (iface_param->param_type != ISCSI_NET_PARAM) 847d00efe3fSMike Christie continue; 848d00efe3fSMike Christie 849d00efe3fSMike Christie switch (iface_param->iface_type) { 850d00efe3fSMike Christie case ISCSI_IFACE_TYPE_IPV4: 851d00efe3fSMike Christie switch (iface_param->iface_num) { 852d00efe3fSMike Christie case 0: 853d00efe3fSMike Christie qla4xxx_set_ipv4(ha, iface_param, init_fw_cb); 854d00efe3fSMike Christie break; 855d00efe3fSMike Christie default: 856d00efe3fSMike Christie /* Cannot have more than one IPv4 interface */ 857d00efe3fSMike Christie ql4_printk(KERN_ERR, ha, "Invalid IPv4 iface " 858d00efe3fSMike Christie "number = %d\n", 859d00efe3fSMike Christie iface_param->iface_num); 860d00efe3fSMike Christie break; 861d00efe3fSMike Christie } 862d00efe3fSMike Christie break; 863d00efe3fSMike Christie case ISCSI_IFACE_TYPE_IPV6: 864d00efe3fSMike Christie switch (iface_param->iface_num) { 865d00efe3fSMike Christie case 0: 866d00efe3fSMike Christie case 1: 867d00efe3fSMike Christie qla4xxx_set_ipv6(ha, iface_param, init_fw_cb); 868d00efe3fSMike Christie break; 869d00efe3fSMike Christie default: 870d00efe3fSMike Christie /* Cannot have more than two IPv6 interface */ 871d00efe3fSMike Christie ql4_printk(KERN_ERR, ha, "Invalid IPv6 iface " 872d00efe3fSMike Christie "number = %d\n", 873d00efe3fSMike Christie iface_param->iface_num); 874d00efe3fSMike Christie break; 875d00efe3fSMike Christie } 876d00efe3fSMike Christie break; 877d00efe3fSMike Christie default: 878d00efe3fSMike Christie ql4_printk(KERN_ERR, ha, "Invalid iface type\n"); 879d00efe3fSMike Christie break; 880d00efe3fSMike Christie } 881d00efe3fSMike Christie 882d00efe3fSMike Christie iface_param = (struct iscsi_iface_param_info *) 883d00efe3fSMike Christie ((uint8_t *)iface_param + 884d00efe3fSMike Christie sizeof(struct iscsi_iface_param_info) + length); 885d00efe3fSMike Christie } 886d00efe3fSMike Christie 887d00efe3fSMike Christie init_fw_cb->cookie = cpu_to_le32(0x11BEAD5A); 888d00efe3fSMike Christie 889d00efe3fSMike Christie rval = qla4xxx_set_flash(ha, init_fw_cb_dma, FLASH_SEGMENT_IFCB, 890d00efe3fSMike Christie sizeof(struct addr_ctrl_blk), 891d00efe3fSMike Christie FLASH_OPT_RMW_COMMIT); 892d00efe3fSMike Christie if (rval != QLA_SUCCESS) { 893d00efe3fSMike Christie ql4_printk(KERN_ERR, ha, "%s: set flash mbx failed\n", 894d00efe3fSMike Christie __func__); 895d00efe3fSMike Christie rval = -EIO; 896d00efe3fSMike Christie goto exit_init_fw_cb; 897d00efe3fSMike Christie } 898d00efe3fSMike Christie 899d00efe3fSMike Christie qla4xxx_disable_acb(ha); 900d00efe3fSMike Christie 901d00efe3fSMike Christie qla4xxx_initcb_to_acb(init_fw_cb); 902d00efe3fSMike Christie 903d00efe3fSMike Christie rval = qla4xxx_set_acb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb_dma); 904d00efe3fSMike Christie if (rval != QLA_SUCCESS) { 905d00efe3fSMike Christie ql4_printk(KERN_ERR, ha, "%s: set acb mbx failed\n", 906d00efe3fSMike Christie __func__); 907d00efe3fSMike Christie rval = -EIO; 908d00efe3fSMike Christie goto exit_init_fw_cb; 909d00efe3fSMike Christie } 910d00efe3fSMike Christie 911d00efe3fSMike Christie memset(init_fw_cb, 0, sizeof(struct addr_ctrl_blk)); 912d00efe3fSMike Christie qla4xxx_update_local_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb, 913d00efe3fSMike Christie init_fw_cb_dma); 914d00efe3fSMike Christie 915d00efe3fSMike Christie exit_init_fw_cb: 916d00efe3fSMike Christie dma_free_coherent(&ha->pdev->dev, sizeof(struct addr_ctrl_blk), 917d00efe3fSMike Christie init_fw_cb, init_fw_cb_dma); 918d00efe3fSMike Christie 919d00efe3fSMike Christie return rval; 920d00efe3fSMike Christie } 921d00efe3fSMike Christie 922b3a271a9SManish Rangankar static int qla4xxx_conn_get_param(struct iscsi_cls_conn *cls_conn, 923afaf5a2dSDavid Somayajulu enum iscsi_param param, char *buf) 924afaf5a2dSDavid Somayajulu { 925b3a271a9SManish Rangankar struct iscsi_conn *conn; 926b3a271a9SManish Rangankar struct qla_conn *qla_conn; 927b3a271a9SManish Rangankar struct sockaddr *dst_addr; 928b3a271a9SManish Rangankar int len = 0; 929afaf5a2dSDavid Somayajulu 930b3a271a9SManish Rangankar conn = cls_conn->dd_data; 931b3a271a9SManish Rangankar qla_conn = conn->dd_data; 932b3a271a9SManish Rangankar dst_addr = &qla_conn->qla_ep->dst_addr; 933afaf5a2dSDavid Somayajulu 934afaf5a2dSDavid Somayajulu switch (param) { 935afaf5a2dSDavid Somayajulu case ISCSI_PARAM_CONN_PORT: 936afaf5a2dSDavid Somayajulu case ISCSI_PARAM_CONN_ADDRESS: 937b3a271a9SManish Rangankar return iscsi_conn_get_addr_param((struct sockaddr_storage *) 938b3a271a9SManish Rangankar dst_addr, param, buf); 939afaf5a2dSDavid Somayajulu default: 940b3a271a9SManish Rangankar return iscsi_conn_get_param(cls_conn, param, buf); 941afaf5a2dSDavid Somayajulu } 942afaf5a2dSDavid Somayajulu 943afaf5a2dSDavid Somayajulu return len; 944b3a271a9SManish Rangankar 945afaf5a2dSDavid Somayajulu } 946afaf5a2dSDavid Somayajulu 947b3a271a9SManish Rangankar static struct iscsi_cls_session * 948b3a271a9SManish Rangankar qla4xxx_session_create(struct iscsi_endpoint *ep, 949b3a271a9SManish Rangankar uint16_t cmds_max, uint16_t qdepth, 950b3a271a9SManish Rangankar uint32_t initial_cmdsn) 951b3a271a9SManish Rangankar { 952b3a271a9SManish Rangankar struct iscsi_cls_session *cls_sess; 953b3a271a9SManish Rangankar struct scsi_qla_host *ha; 954b3a271a9SManish Rangankar struct qla_endpoint *qla_ep; 955b3a271a9SManish Rangankar struct ddb_entry *ddb_entry; 956b3a271a9SManish Rangankar uint32_t ddb_index; 957b3a271a9SManish Rangankar uint32_t mbx_sts = 0; 958b3a271a9SManish Rangankar struct iscsi_session *sess; 959b3a271a9SManish Rangankar struct sockaddr *dst_addr; 960b3a271a9SManish Rangankar int ret; 961b3a271a9SManish Rangankar 962b3a271a9SManish Rangankar DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); 963b3a271a9SManish Rangankar if (!ep) { 964b3a271a9SManish Rangankar printk(KERN_ERR "qla4xxx: missing ep.\n"); 965b3a271a9SManish Rangankar return NULL; 966b3a271a9SManish Rangankar } 967b3a271a9SManish Rangankar 968b3a271a9SManish Rangankar qla_ep = ep->dd_data; 969b3a271a9SManish Rangankar dst_addr = (struct sockaddr *)&qla_ep->dst_addr; 970b3a271a9SManish Rangankar ha = to_qla_host(qla_ep->host); 971b3a271a9SManish Rangankar get_ddb_index: 972b3a271a9SManish Rangankar ddb_index = find_first_zero_bit(ha->ddb_idx_map, MAX_DDB_ENTRIES); 973b3a271a9SManish Rangankar 974b3a271a9SManish Rangankar if (ddb_index >= MAX_DDB_ENTRIES) { 975b3a271a9SManish Rangankar DEBUG2(ql4_printk(KERN_INFO, ha, 976b3a271a9SManish Rangankar "Free DDB index not available\n")); 977b3a271a9SManish Rangankar return NULL; 978b3a271a9SManish Rangankar } 979b3a271a9SManish Rangankar 980b3a271a9SManish Rangankar if (test_and_set_bit(ddb_index, ha->ddb_idx_map)) 981b3a271a9SManish Rangankar goto get_ddb_index; 982b3a271a9SManish Rangankar 983b3a271a9SManish Rangankar DEBUG2(ql4_printk(KERN_INFO, ha, 984b3a271a9SManish Rangankar "Found a free DDB index at %d\n", ddb_index)); 985b3a271a9SManish Rangankar ret = qla4xxx_req_ddb_entry(ha, ddb_index, &mbx_sts); 986b3a271a9SManish Rangankar if (ret == QLA_ERROR) { 987b3a271a9SManish Rangankar if (mbx_sts == MBOX_STS_COMMAND_ERROR) { 988b3a271a9SManish Rangankar ql4_printk(KERN_INFO, ha, 989b3a271a9SManish Rangankar "DDB index = %d not available trying next\n", 990b3a271a9SManish Rangankar ddb_index); 991b3a271a9SManish Rangankar goto get_ddb_index; 992b3a271a9SManish Rangankar } 993b3a271a9SManish Rangankar DEBUG2(ql4_printk(KERN_INFO, ha, 994b3a271a9SManish Rangankar "Free FW DDB not available\n")); 995b3a271a9SManish Rangankar return NULL; 996b3a271a9SManish Rangankar } 997b3a271a9SManish Rangankar 998b3a271a9SManish Rangankar cls_sess = iscsi_session_setup(&qla4xxx_iscsi_transport, qla_ep->host, 999b3a271a9SManish Rangankar cmds_max, sizeof(struct ddb_entry), 1000b3a271a9SManish Rangankar sizeof(struct ql4_task_data), 1001b3a271a9SManish Rangankar initial_cmdsn, ddb_index); 1002b3a271a9SManish Rangankar if (!cls_sess) 1003b3a271a9SManish Rangankar return NULL; 1004b3a271a9SManish Rangankar 1005b3a271a9SManish Rangankar sess = cls_sess->dd_data; 1006b3a271a9SManish Rangankar ddb_entry = sess->dd_data; 1007b3a271a9SManish Rangankar ddb_entry->fw_ddb_index = ddb_index; 1008b3a271a9SManish Rangankar ddb_entry->fw_ddb_device_state = DDB_DS_NO_CONNECTION_ACTIVE; 1009b3a271a9SManish Rangankar ddb_entry->ha = ha; 1010b3a271a9SManish Rangankar ddb_entry->sess = cls_sess; 1011b3a271a9SManish Rangankar cls_sess->recovery_tmo = ql4xsess_recovery_tmo; 1012b3a271a9SManish Rangankar ha->fw_ddb_index_map[ddb_entry->fw_ddb_index] = ddb_entry; 1013b3a271a9SManish Rangankar ha->tot_ddbs++; 1014b3a271a9SManish Rangankar 1015b3a271a9SManish Rangankar return cls_sess; 1016b3a271a9SManish Rangankar } 1017b3a271a9SManish Rangankar 1018b3a271a9SManish Rangankar static void qla4xxx_session_destroy(struct iscsi_cls_session *cls_sess) 1019b3a271a9SManish Rangankar { 1020b3a271a9SManish Rangankar struct iscsi_session *sess; 1021b3a271a9SManish Rangankar struct ddb_entry *ddb_entry; 1022b3a271a9SManish Rangankar struct scsi_qla_host *ha; 1023b3a271a9SManish Rangankar unsigned long flags; 1024b3a271a9SManish Rangankar 1025b3a271a9SManish Rangankar DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); 1026b3a271a9SManish Rangankar sess = cls_sess->dd_data; 1027b3a271a9SManish Rangankar ddb_entry = sess->dd_data; 1028b3a271a9SManish Rangankar ha = ddb_entry->ha; 1029b3a271a9SManish Rangankar 1030b3a271a9SManish Rangankar spin_lock_irqsave(&ha->hardware_lock, flags); 1031b3a271a9SManish Rangankar qla4xxx_free_ddb(ha, ddb_entry); 1032b3a271a9SManish Rangankar spin_unlock_irqrestore(&ha->hardware_lock, flags); 1033b3a271a9SManish Rangankar iscsi_session_teardown(cls_sess); 1034b3a271a9SManish Rangankar } 1035b3a271a9SManish Rangankar 1036b3a271a9SManish Rangankar static struct iscsi_cls_conn * 1037b3a271a9SManish Rangankar qla4xxx_conn_create(struct iscsi_cls_session *cls_sess, uint32_t conn_idx) 1038b3a271a9SManish Rangankar { 1039b3a271a9SManish Rangankar struct iscsi_cls_conn *cls_conn; 1040b3a271a9SManish Rangankar struct iscsi_session *sess; 1041b3a271a9SManish Rangankar struct ddb_entry *ddb_entry; 1042b3a271a9SManish Rangankar 1043b3a271a9SManish Rangankar DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); 1044b3a271a9SManish Rangankar cls_conn = iscsi_conn_setup(cls_sess, sizeof(struct qla_conn), 1045b3a271a9SManish Rangankar conn_idx); 1046b3a271a9SManish Rangankar sess = cls_sess->dd_data; 1047b3a271a9SManish Rangankar ddb_entry = sess->dd_data; 1048b3a271a9SManish Rangankar ddb_entry->conn = cls_conn; 1049b3a271a9SManish Rangankar 1050b3a271a9SManish Rangankar return cls_conn; 1051b3a271a9SManish Rangankar } 1052b3a271a9SManish Rangankar 1053b3a271a9SManish Rangankar static int qla4xxx_conn_bind(struct iscsi_cls_session *cls_session, 1054b3a271a9SManish Rangankar struct iscsi_cls_conn *cls_conn, 1055b3a271a9SManish Rangankar uint64_t transport_fd, int is_leading) 1056b3a271a9SManish Rangankar { 1057b3a271a9SManish Rangankar struct iscsi_conn *conn; 1058b3a271a9SManish Rangankar struct qla_conn *qla_conn; 1059b3a271a9SManish Rangankar struct iscsi_endpoint *ep; 1060b3a271a9SManish Rangankar 1061b3a271a9SManish Rangankar DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); 1062b3a271a9SManish Rangankar 1063b3a271a9SManish Rangankar if (iscsi_conn_bind(cls_session, cls_conn, is_leading)) 1064b3a271a9SManish Rangankar return -EINVAL; 1065b3a271a9SManish Rangankar ep = iscsi_lookup_endpoint(transport_fd); 1066b3a271a9SManish Rangankar conn = cls_conn->dd_data; 1067b3a271a9SManish Rangankar qla_conn = conn->dd_data; 1068b3a271a9SManish Rangankar qla_conn->qla_ep = ep->dd_data; 1069b3a271a9SManish Rangankar return 0; 1070b3a271a9SManish Rangankar } 1071b3a271a9SManish Rangankar 1072b3a271a9SManish Rangankar static int qla4xxx_conn_start(struct iscsi_cls_conn *cls_conn) 1073b3a271a9SManish Rangankar { 1074b3a271a9SManish Rangankar struct iscsi_cls_session *cls_sess = iscsi_conn_to_session(cls_conn); 1075b3a271a9SManish Rangankar struct iscsi_session *sess; 1076b3a271a9SManish Rangankar struct ddb_entry *ddb_entry; 1077b3a271a9SManish Rangankar struct scsi_qla_host *ha; 1078b3a271a9SManish Rangankar struct dev_db_entry *fw_ddb_entry; 1079b3a271a9SManish Rangankar dma_addr_t fw_ddb_entry_dma; 1080b3a271a9SManish Rangankar uint32_t mbx_sts = 0; 1081b3a271a9SManish Rangankar int ret = 0; 1082b3a271a9SManish Rangankar int status = QLA_SUCCESS; 1083b3a271a9SManish Rangankar 1084b3a271a9SManish Rangankar DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); 1085b3a271a9SManish Rangankar sess = cls_sess->dd_data; 1086b3a271a9SManish Rangankar ddb_entry = sess->dd_data; 1087b3a271a9SManish Rangankar ha = ddb_entry->ha; 1088b3a271a9SManish Rangankar 1089b3a271a9SManish Rangankar fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), 1090b3a271a9SManish Rangankar &fw_ddb_entry_dma, GFP_KERNEL); 1091b3a271a9SManish Rangankar if (!fw_ddb_entry) { 1092b3a271a9SManish Rangankar ql4_printk(KERN_ERR, ha, 1093b3a271a9SManish Rangankar "%s: Unable to allocate dma buffer\n", __func__); 1094b3a271a9SManish Rangankar return -ENOMEM; 1095b3a271a9SManish Rangankar } 1096b3a271a9SManish Rangankar 1097b3a271a9SManish Rangankar ret = qla4xxx_set_param_ddbentry(ha, ddb_entry, cls_conn, &mbx_sts); 1098b3a271a9SManish Rangankar if (ret) { 1099b3a271a9SManish Rangankar /* If iscsid is stopped and started then no need to do 1100b3a271a9SManish Rangankar * set param again since ddb state will be already 1101b3a271a9SManish Rangankar * active and FW does not allow set ddb to an 1102b3a271a9SManish Rangankar * active session. 1103b3a271a9SManish Rangankar */ 1104b3a271a9SManish Rangankar if (mbx_sts) 1105b3a271a9SManish Rangankar if (ddb_entry->fw_ddb_device_state == 1106b3a271a9SManish Rangankar DDB_DS_SESSION_ACTIVE) 1107b3a271a9SManish Rangankar goto exit_set_param; 1108b3a271a9SManish Rangankar 1109b3a271a9SManish Rangankar ql4_printk(KERN_ERR, ha, "%s: Failed set param for index[%d]\n", 1110b3a271a9SManish Rangankar __func__, ddb_entry->fw_ddb_index); 1111b3a271a9SManish Rangankar goto exit_conn_start; 1112b3a271a9SManish Rangankar } 1113b3a271a9SManish Rangankar 1114b3a271a9SManish Rangankar status = qla4xxx_conn_open(ha, ddb_entry->fw_ddb_index); 1115b3a271a9SManish Rangankar if (status == QLA_ERROR) { 11160e7e8501SManish Rangankar ql4_printk(KERN_ERR, ha, "%s: Login failed: %s\n", __func__, 11170e7e8501SManish Rangankar sess->targetname); 1118b3a271a9SManish Rangankar ret = -EINVAL; 1119b3a271a9SManish Rangankar goto exit_conn_start; 1120b3a271a9SManish Rangankar } 1121b3a271a9SManish Rangankar 1122b3a271a9SManish Rangankar ddb_entry->fw_ddb_device_state = DDB_DS_LOGIN_IN_PROCESS; 1123b3a271a9SManish Rangankar 1124b3a271a9SManish Rangankar exit_set_param: 1125b3a271a9SManish Rangankar iscsi_conn_start(cls_conn); 1126b3a271a9SManish Rangankar ret = 0; 1127b3a271a9SManish Rangankar 1128b3a271a9SManish Rangankar exit_conn_start: 1129b3a271a9SManish Rangankar dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), 1130b3a271a9SManish Rangankar fw_ddb_entry, fw_ddb_entry_dma); 1131b3a271a9SManish Rangankar return ret; 1132b3a271a9SManish Rangankar } 1133b3a271a9SManish Rangankar 1134b3a271a9SManish Rangankar static void qla4xxx_conn_destroy(struct iscsi_cls_conn *cls_conn) 1135b3a271a9SManish Rangankar { 1136b3a271a9SManish Rangankar struct iscsi_cls_session *cls_sess = iscsi_conn_to_session(cls_conn); 1137b3a271a9SManish Rangankar struct iscsi_session *sess; 1138b3a271a9SManish Rangankar struct scsi_qla_host *ha; 1139b3a271a9SManish Rangankar struct ddb_entry *ddb_entry; 1140b3a271a9SManish Rangankar int options; 1141b3a271a9SManish Rangankar 1142b3a271a9SManish Rangankar DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); 1143b3a271a9SManish Rangankar sess = cls_sess->dd_data; 1144b3a271a9SManish Rangankar ddb_entry = sess->dd_data; 1145b3a271a9SManish Rangankar ha = ddb_entry->ha; 1146b3a271a9SManish Rangankar 1147b3a271a9SManish Rangankar options = LOGOUT_OPTION_CLOSE_SESSION; 1148b3a271a9SManish Rangankar if (qla4xxx_session_logout_ddb(ha, ddb_entry, options) == QLA_ERROR) 1149b3a271a9SManish Rangankar ql4_printk(KERN_ERR, ha, "%s: Logout failed\n", __func__); 1150b3a271a9SManish Rangankar else 1151b3a271a9SManish Rangankar qla4xxx_clear_ddb_entry(ha, ddb_entry->fw_ddb_index); 1152b3a271a9SManish Rangankar 1153b3a271a9SManish Rangankar /* 1154b3a271a9SManish Rangankar * Clear the DDB bit so that next login can use the bit 1155b3a271a9SManish Rangankar * if FW is not clearing the DDB entry then set DDB will fail anyways 1156b3a271a9SManish Rangankar */ 1157b3a271a9SManish Rangankar clear_bit(ddb_entry->fw_ddb_index, ha->ddb_idx_map); 1158b3a271a9SManish Rangankar } 1159b3a271a9SManish Rangankar 1160b3a271a9SManish Rangankar static void qla4xxx_task_work(struct work_struct *wdata) 1161b3a271a9SManish Rangankar { 1162b3a271a9SManish Rangankar struct ql4_task_data *task_data; 1163b3a271a9SManish Rangankar struct scsi_qla_host *ha; 1164b3a271a9SManish Rangankar struct passthru_status *sts; 1165b3a271a9SManish Rangankar struct iscsi_task *task; 1166b3a271a9SManish Rangankar struct iscsi_hdr *hdr; 1167b3a271a9SManish Rangankar uint8_t *data; 1168b3a271a9SManish Rangankar uint32_t data_len; 1169b3a271a9SManish Rangankar struct iscsi_conn *conn; 1170b3a271a9SManish Rangankar int hdr_len; 1171b3a271a9SManish Rangankar itt_t itt; 1172b3a271a9SManish Rangankar 1173b3a271a9SManish Rangankar task_data = container_of(wdata, struct ql4_task_data, task_work); 1174b3a271a9SManish Rangankar ha = task_data->ha; 1175b3a271a9SManish Rangankar task = task_data->task; 1176b3a271a9SManish Rangankar sts = &task_data->sts; 1177b3a271a9SManish Rangankar hdr_len = sizeof(struct iscsi_hdr); 1178b3a271a9SManish Rangankar 1179b3a271a9SManish Rangankar DEBUG3(printk(KERN_INFO "Status returned\n")); 1180b3a271a9SManish Rangankar DEBUG3(qla4xxx_dump_buffer(sts, 64)); 1181b3a271a9SManish Rangankar DEBUG3(printk(KERN_INFO "Response buffer")); 1182b3a271a9SManish Rangankar DEBUG3(qla4xxx_dump_buffer(task_data->resp_buffer, 64)); 1183b3a271a9SManish Rangankar 1184b3a271a9SManish Rangankar conn = task->conn; 1185b3a271a9SManish Rangankar 1186b3a271a9SManish Rangankar switch (sts->completionStatus) { 1187b3a271a9SManish Rangankar case PASSTHRU_STATUS_COMPLETE: 1188b3a271a9SManish Rangankar hdr = (struct iscsi_hdr *)task_data->resp_buffer; 1189b3a271a9SManish Rangankar /* Assign back the itt in hdr, until we use the PREASSIGN_TAG */ 1190b3a271a9SManish Rangankar itt = sts->handle; 1191b3a271a9SManish Rangankar hdr->itt = itt; 1192b3a271a9SManish Rangankar data = task_data->resp_buffer + hdr_len; 1193b3a271a9SManish Rangankar data_len = task_data->resp_len - hdr_len; 1194b3a271a9SManish Rangankar iscsi_complete_pdu(conn, hdr, data, data_len); 1195b3a271a9SManish Rangankar break; 1196b3a271a9SManish Rangankar default: 1197b3a271a9SManish Rangankar ql4_printk(KERN_ERR, ha, "Passthru failed status = 0x%x\n", 1198b3a271a9SManish Rangankar sts->completionStatus); 1199b3a271a9SManish Rangankar break; 1200b3a271a9SManish Rangankar } 1201b3a271a9SManish Rangankar return; 1202b3a271a9SManish Rangankar } 1203b3a271a9SManish Rangankar 1204b3a271a9SManish Rangankar static int qla4xxx_alloc_pdu(struct iscsi_task *task, uint8_t opcode) 1205b3a271a9SManish Rangankar { 1206b3a271a9SManish Rangankar struct ql4_task_data *task_data; 1207b3a271a9SManish Rangankar struct iscsi_session *sess; 1208b3a271a9SManish Rangankar struct ddb_entry *ddb_entry; 1209b3a271a9SManish Rangankar struct scsi_qla_host *ha; 1210b3a271a9SManish Rangankar int hdr_len; 1211b3a271a9SManish Rangankar 1212b3a271a9SManish Rangankar sess = task->conn->session; 1213b3a271a9SManish Rangankar ddb_entry = sess->dd_data; 1214b3a271a9SManish Rangankar ha = ddb_entry->ha; 1215b3a271a9SManish Rangankar task_data = task->dd_data; 1216b3a271a9SManish Rangankar memset(task_data, 0, sizeof(struct ql4_task_data)); 1217b3a271a9SManish Rangankar 1218b3a271a9SManish Rangankar if (task->sc) { 1219b3a271a9SManish Rangankar ql4_printk(KERN_INFO, ha, 1220b3a271a9SManish Rangankar "%s: SCSI Commands not implemented\n", __func__); 1221b3a271a9SManish Rangankar return -EINVAL; 1222b3a271a9SManish Rangankar } 1223b3a271a9SManish Rangankar 1224b3a271a9SManish Rangankar hdr_len = sizeof(struct iscsi_hdr); 1225b3a271a9SManish Rangankar task_data->ha = ha; 1226b3a271a9SManish Rangankar task_data->task = task; 1227b3a271a9SManish Rangankar 1228b3a271a9SManish Rangankar if (task->data_count) { 1229b3a271a9SManish Rangankar task_data->data_dma = dma_map_single(&ha->pdev->dev, task->data, 1230b3a271a9SManish Rangankar task->data_count, 1231b3a271a9SManish Rangankar PCI_DMA_TODEVICE); 1232b3a271a9SManish Rangankar } 1233b3a271a9SManish Rangankar 1234b3a271a9SManish Rangankar DEBUG2(ql4_printk(KERN_INFO, ha, "%s: MaxRecvLen %u, iscsi hrd %d\n", 1235b3a271a9SManish Rangankar __func__, task->conn->max_recv_dlength, hdr_len)); 1236b3a271a9SManish Rangankar 1237b3a271a9SManish Rangankar task_data->resp_len = task->conn->max_recv_dlength; 1238b3a271a9SManish Rangankar task_data->resp_buffer = dma_alloc_coherent(&ha->pdev->dev, 1239b3a271a9SManish Rangankar task_data->resp_len, 1240b3a271a9SManish Rangankar &task_data->resp_dma, 1241b3a271a9SManish Rangankar GFP_ATOMIC); 1242b3a271a9SManish Rangankar if (!task_data->resp_buffer) 1243b3a271a9SManish Rangankar goto exit_alloc_pdu; 1244b3a271a9SManish Rangankar 1245b3a271a9SManish Rangankar task_data->req_buffer = dma_alloc_coherent(&ha->pdev->dev, 1246b3a271a9SManish Rangankar task->data_count + hdr_len, 1247b3a271a9SManish Rangankar &task_data->req_dma, 1248b3a271a9SManish Rangankar GFP_ATOMIC); 1249b3a271a9SManish Rangankar if (!task_data->req_buffer) 1250b3a271a9SManish Rangankar goto exit_alloc_pdu; 1251b3a271a9SManish Rangankar 1252b3a271a9SManish Rangankar task->hdr = task_data->req_buffer; 1253b3a271a9SManish Rangankar 1254b3a271a9SManish Rangankar INIT_WORK(&task_data->task_work, qla4xxx_task_work); 1255b3a271a9SManish Rangankar 1256b3a271a9SManish Rangankar return 0; 1257b3a271a9SManish Rangankar 1258b3a271a9SManish Rangankar exit_alloc_pdu: 1259b3a271a9SManish Rangankar if (task_data->resp_buffer) 1260b3a271a9SManish Rangankar dma_free_coherent(&ha->pdev->dev, task_data->resp_len, 1261b3a271a9SManish Rangankar task_data->resp_buffer, task_data->resp_dma); 1262b3a271a9SManish Rangankar 1263b3a271a9SManish Rangankar if (task_data->req_buffer) 1264b3a271a9SManish Rangankar dma_free_coherent(&ha->pdev->dev, task->data_count + hdr_len, 1265b3a271a9SManish Rangankar task_data->req_buffer, task_data->req_dma); 1266b3a271a9SManish Rangankar return -ENOMEM; 1267b3a271a9SManish Rangankar } 1268b3a271a9SManish Rangankar 1269b3a271a9SManish Rangankar static void qla4xxx_task_cleanup(struct iscsi_task *task) 1270b3a271a9SManish Rangankar { 1271b3a271a9SManish Rangankar struct ql4_task_data *task_data; 1272b3a271a9SManish Rangankar struct iscsi_session *sess; 1273b3a271a9SManish Rangankar struct ddb_entry *ddb_entry; 1274b3a271a9SManish Rangankar struct scsi_qla_host *ha; 1275b3a271a9SManish Rangankar int hdr_len; 1276b3a271a9SManish Rangankar 1277b3a271a9SManish Rangankar hdr_len = sizeof(struct iscsi_hdr); 1278b3a271a9SManish Rangankar sess = task->conn->session; 1279b3a271a9SManish Rangankar ddb_entry = sess->dd_data; 1280b3a271a9SManish Rangankar ha = ddb_entry->ha; 1281b3a271a9SManish Rangankar task_data = task->dd_data; 1282b3a271a9SManish Rangankar 1283b3a271a9SManish Rangankar if (task->data_count) { 1284b3a271a9SManish Rangankar dma_unmap_single(&ha->pdev->dev, task_data->data_dma, 1285b3a271a9SManish Rangankar task->data_count, PCI_DMA_TODEVICE); 1286b3a271a9SManish Rangankar } 1287b3a271a9SManish Rangankar 1288b3a271a9SManish Rangankar DEBUG2(ql4_printk(KERN_INFO, ha, "%s: MaxRecvLen %u, iscsi hrd %d\n", 1289b3a271a9SManish Rangankar __func__, task->conn->max_recv_dlength, hdr_len)); 1290b3a271a9SManish Rangankar 1291b3a271a9SManish Rangankar dma_free_coherent(&ha->pdev->dev, task_data->resp_len, 1292b3a271a9SManish Rangankar task_data->resp_buffer, task_data->resp_dma); 1293b3a271a9SManish Rangankar dma_free_coherent(&ha->pdev->dev, task->data_count + hdr_len, 1294b3a271a9SManish Rangankar task_data->req_buffer, task_data->req_dma); 1295b3a271a9SManish Rangankar return; 1296b3a271a9SManish Rangankar } 1297b3a271a9SManish Rangankar 1298b3a271a9SManish Rangankar static int qla4xxx_task_xmit(struct iscsi_task *task) 1299b3a271a9SManish Rangankar { 1300b3a271a9SManish Rangankar struct scsi_cmnd *sc = task->sc; 1301b3a271a9SManish Rangankar struct iscsi_session *sess = task->conn->session; 1302b3a271a9SManish Rangankar struct ddb_entry *ddb_entry = sess->dd_data; 1303b3a271a9SManish Rangankar struct scsi_qla_host *ha = ddb_entry->ha; 1304b3a271a9SManish Rangankar 1305b3a271a9SManish Rangankar if (!sc) 1306b3a271a9SManish Rangankar return qla4xxx_send_passthru0(task); 1307b3a271a9SManish Rangankar 1308b3a271a9SManish Rangankar ql4_printk(KERN_INFO, ha, "%s: scsi cmd xmit not implemented\n", 1309b3a271a9SManish Rangankar __func__); 1310b3a271a9SManish Rangankar return -ENOSYS; 1311b3a271a9SManish Rangankar } 1312b3a271a9SManish Rangankar 1313b3a271a9SManish Rangankar void qla4xxx_update_session_conn_param(struct scsi_qla_host *ha, 1314b3a271a9SManish Rangankar struct ddb_entry *ddb_entry) 1315b3a271a9SManish Rangankar { 1316b3a271a9SManish Rangankar struct iscsi_cls_session *cls_sess; 1317b3a271a9SManish Rangankar struct iscsi_cls_conn *cls_conn; 1318b3a271a9SManish Rangankar struct iscsi_session *sess; 1319b3a271a9SManish Rangankar struct iscsi_conn *conn; 1320b3a271a9SManish Rangankar uint32_t ddb_state; 1321b3a271a9SManish Rangankar dma_addr_t fw_ddb_entry_dma; 1322b3a271a9SManish Rangankar struct dev_db_entry *fw_ddb_entry; 1323b3a271a9SManish Rangankar 1324b3a271a9SManish Rangankar fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), 1325b3a271a9SManish Rangankar &fw_ddb_entry_dma, GFP_KERNEL); 1326b3a271a9SManish Rangankar if (!fw_ddb_entry) { 1327b3a271a9SManish Rangankar ql4_printk(KERN_ERR, ha, 1328b3a271a9SManish Rangankar "%s: Unable to allocate dma buffer\n", __func__); 1329b3a271a9SManish Rangankar return; 1330b3a271a9SManish Rangankar } 1331b3a271a9SManish Rangankar 1332b3a271a9SManish Rangankar if (qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index, fw_ddb_entry, 1333b3a271a9SManish Rangankar fw_ddb_entry_dma, NULL, NULL, &ddb_state, 1334b3a271a9SManish Rangankar NULL, NULL, NULL) == QLA_ERROR) { 1335b3a271a9SManish Rangankar DEBUG2(ql4_printk(KERN_ERR, ha, "scsi%ld: %s: failed " 1336b3a271a9SManish Rangankar "get_ddb_entry for fw_ddb_index %d\n", 1337b3a271a9SManish Rangankar ha->host_no, __func__, 1338b3a271a9SManish Rangankar ddb_entry->fw_ddb_index)); 1339b3a271a9SManish Rangankar return; 1340b3a271a9SManish Rangankar } 1341b3a271a9SManish Rangankar 1342b3a271a9SManish Rangankar cls_sess = ddb_entry->sess; 1343b3a271a9SManish Rangankar sess = cls_sess->dd_data; 1344b3a271a9SManish Rangankar 1345b3a271a9SManish Rangankar cls_conn = ddb_entry->conn; 1346b3a271a9SManish Rangankar conn = cls_conn->dd_data; 1347b3a271a9SManish Rangankar 1348b3a271a9SManish Rangankar /* Update params */ 1349b3a271a9SManish Rangankar conn->max_recv_dlength = BYTE_UNITS * 1350b3a271a9SManish Rangankar le16_to_cpu(fw_ddb_entry->iscsi_max_rcv_data_seg_len); 1351b3a271a9SManish Rangankar 1352b3a271a9SManish Rangankar conn->max_xmit_dlength = BYTE_UNITS * 1353b3a271a9SManish Rangankar le16_to_cpu(fw_ddb_entry->iscsi_max_snd_data_seg_len); 1354b3a271a9SManish Rangankar 1355b3a271a9SManish Rangankar sess->initial_r2t_en = 1356b3a271a9SManish Rangankar (BIT_10 & le16_to_cpu(fw_ddb_entry->iscsi_options)); 1357b3a271a9SManish Rangankar 1358b3a271a9SManish Rangankar sess->max_r2t = le16_to_cpu(fw_ddb_entry->iscsi_max_outsnd_r2t); 1359b3a271a9SManish Rangankar 1360b3a271a9SManish Rangankar sess->imm_data_en = (BIT_11 & le16_to_cpu(fw_ddb_entry->iscsi_options)); 1361b3a271a9SManish Rangankar 1362b3a271a9SManish Rangankar sess->first_burst = BYTE_UNITS * 1363b3a271a9SManish Rangankar le16_to_cpu(fw_ddb_entry->iscsi_first_burst_len); 1364b3a271a9SManish Rangankar 1365b3a271a9SManish Rangankar sess->max_burst = BYTE_UNITS * 1366b3a271a9SManish Rangankar le16_to_cpu(fw_ddb_entry->iscsi_max_burst_len); 1367b3a271a9SManish Rangankar 1368b3a271a9SManish Rangankar sess->time2wait = le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait); 1369b3a271a9SManish Rangankar 1370b3a271a9SManish Rangankar sess->time2retain = le16_to_cpu(fw_ddb_entry->iscsi_def_time2retain); 1371b3a271a9SManish Rangankar 1372b3a271a9SManish Rangankar sess->tpgt = le32_to_cpu(fw_ddb_entry->tgt_portal_grp); 1373b3a271a9SManish Rangankar 1374b3a271a9SManish Rangankar memcpy(sess->initiatorname, ha->name_string, 1375b3a271a9SManish Rangankar min(sizeof(ha->name_string), sizeof(sess->initiatorname))); 1376b3a271a9SManish Rangankar } 1377b3a271a9SManish Rangankar 1378afaf5a2dSDavid Somayajulu /* 1379afaf5a2dSDavid Somayajulu * Timer routines 1380afaf5a2dSDavid Somayajulu */ 1381afaf5a2dSDavid Somayajulu 1382afaf5a2dSDavid Somayajulu static void qla4xxx_start_timer(struct scsi_qla_host *ha, void *func, 1383afaf5a2dSDavid Somayajulu unsigned long interval) 1384afaf5a2dSDavid Somayajulu { 1385afaf5a2dSDavid Somayajulu DEBUG(printk("scsi: %s: Starting timer thread for adapter %d\n", 1386afaf5a2dSDavid Somayajulu __func__, ha->host->host_no)); 1387afaf5a2dSDavid Somayajulu init_timer(&ha->timer); 1388afaf5a2dSDavid Somayajulu ha->timer.expires = jiffies + interval * HZ; 1389afaf5a2dSDavid Somayajulu ha->timer.data = (unsigned long)ha; 1390afaf5a2dSDavid Somayajulu ha->timer.function = (void (*)(unsigned long))func; 1391afaf5a2dSDavid Somayajulu add_timer(&ha->timer); 1392afaf5a2dSDavid Somayajulu ha->timer_active = 1; 1393afaf5a2dSDavid Somayajulu } 1394afaf5a2dSDavid Somayajulu 1395afaf5a2dSDavid Somayajulu static void qla4xxx_stop_timer(struct scsi_qla_host *ha) 1396afaf5a2dSDavid Somayajulu { 1397afaf5a2dSDavid Somayajulu del_timer_sync(&ha->timer); 1398afaf5a2dSDavid Somayajulu ha->timer_active = 0; 1399afaf5a2dSDavid Somayajulu } 1400afaf5a2dSDavid Somayajulu 1401afaf5a2dSDavid Somayajulu /*** 1402b3a271a9SManish Rangankar * qla4xxx_mark_device_missing - blocks the session 1403b3a271a9SManish Rangankar * @cls_session: Pointer to the session to be blocked 1404afaf5a2dSDavid Somayajulu * @ddb_entry: Pointer to device database entry 1405afaf5a2dSDavid Somayajulu * 1406f4f5df23SVikas Chaudhary * This routine marks a device missing and close connection. 1407afaf5a2dSDavid Somayajulu **/ 1408b3a271a9SManish Rangankar void qla4xxx_mark_device_missing(struct iscsi_cls_session *cls_session) 1409afaf5a2dSDavid Somayajulu { 1410b3a271a9SManish Rangankar iscsi_block_session(cls_session); 1411afaf5a2dSDavid Somayajulu } 1412afaf5a2dSDavid Somayajulu 1413f4f5df23SVikas Chaudhary /** 1414f4f5df23SVikas Chaudhary * qla4xxx_mark_all_devices_missing - mark all devices as missing. 1415f4f5df23SVikas Chaudhary * @ha: Pointer to host adapter structure. 1416f4f5df23SVikas Chaudhary * 1417f4f5df23SVikas Chaudhary * This routine marks a device missing and resets the relogin retry count. 1418f4f5df23SVikas Chaudhary **/ 1419f4f5df23SVikas Chaudhary void qla4xxx_mark_all_devices_missing(struct scsi_qla_host *ha) 1420f4f5df23SVikas Chaudhary { 1421b3a271a9SManish Rangankar iscsi_host_for_each_session(ha->host, qla4xxx_mark_device_missing); 1422f4f5df23SVikas Chaudhary } 1423f4f5df23SVikas Chaudhary 1424afaf5a2dSDavid Somayajulu static struct srb* qla4xxx_get_new_srb(struct scsi_qla_host *ha, 1425afaf5a2dSDavid Somayajulu struct ddb_entry *ddb_entry, 14268f0722caSVikas Chaudhary struct scsi_cmnd *cmd) 1427afaf5a2dSDavid Somayajulu { 1428afaf5a2dSDavid Somayajulu struct srb *srb; 1429afaf5a2dSDavid Somayajulu 1430afaf5a2dSDavid Somayajulu srb = mempool_alloc(ha->srb_mempool, GFP_ATOMIC); 1431afaf5a2dSDavid Somayajulu if (!srb) 1432afaf5a2dSDavid Somayajulu return srb; 1433afaf5a2dSDavid Somayajulu 143409a0f719SVikas Chaudhary kref_init(&srb->srb_ref); 1435afaf5a2dSDavid Somayajulu srb->ha = ha; 1436afaf5a2dSDavid Somayajulu srb->ddb = ddb_entry; 1437afaf5a2dSDavid Somayajulu srb->cmd = cmd; 1438afaf5a2dSDavid Somayajulu srb->flags = 0; 14395369887aSVikas Chaudhary CMD_SP(cmd) = (void *)srb; 1440afaf5a2dSDavid Somayajulu 1441afaf5a2dSDavid Somayajulu return srb; 1442afaf5a2dSDavid Somayajulu } 1443afaf5a2dSDavid Somayajulu 1444afaf5a2dSDavid Somayajulu static void qla4xxx_srb_free_dma(struct scsi_qla_host *ha, struct srb *srb) 1445afaf5a2dSDavid Somayajulu { 1446afaf5a2dSDavid Somayajulu struct scsi_cmnd *cmd = srb->cmd; 1447afaf5a2dSDavid Somayajulu 1448afaf5a2dSDavid Somayajulu if (srb->flags & SRB_DMA_VALID) { 14495f7186c8SFUJITA Tomonori scsi_dma_unmap(cmd); 1450afaf5a2dSDavid Somayajulu srb->flags &= ~SRB_DMA_VALID; 1451afaf5a2dSDavid Somayajulu } 14525369887aSVikas Chaudhary CMD_SP(cmd) = NULL; 1453afaf5a2dSDavid Somayajulu } 1454afaf5a2dSDavid Somayajulu 145509a0f719SVikas Chaudhary void qla4xxx_srb_compl(struct kref *ref) 1456afaf5a2dSDavid Somayajulu { 145709a0f719SVikas Chaudhary struct srb *srb = container_of(ref, struct srb, srb_ref); 1458afaf5a2dSDavid Somayajulu struct scsi_cmnd *cmd = srb->cmd; 145909a0f719SVikas Chaudhary struct scsi_qla_host *ha = srb->ha; 1460afaf5a2dSDavid Somayajulu 1461afaf5a2dSDavid Somayajulu qla4xxx_srb_free_dma(ha, srb); 1462afaf5a2dSDavid Somayajulu 1463afaf5a2dSDavid Somayajulu mempool_free(srb, ha->srb_mempool); 1464afaf5a2dSDavid Somayajulu 1465afaf5a2dSDavid Somayajulu cmd->scsi_done(cmd); 1466afaf5a2dSDavid Somayajulu } 1467afaf5a2dSDavid Somayajulu 1468afaf5a2dSDavid Somayajulu /** 1469afaf5a2dSDavid Somayajulu * qla4xxx_queuecommand - scsi layer issues scsi command to driver. 14708f0722caSVikas Chaudhary * @host: scsi host 1471afaf5a2dSDavid Somayajulu * @cmd: Pointer to Linux's SCSI command structure 1472afaf5a2dSDavid Somayajulu * 1473afaf5a2dSDavid Somayajulu * Remarks: 1474afaf5a2dSDavid Somayajulu * This routine is invoked by Linux to send a SCSI command to the driver. 1475afaf5a2dSDavid Somayajulu * The mid-level driver tries to ensure that queuecommand never gets 1476afaf5a2dSDavid Somayajulu * invoked concurrently with itself or the interrupt handler (although 1477afaf5a2dSDavid Somayajulu * the interrupt handler may call this routine as part of request- 1478afaf5a2dSDavid Somayajulu * completion handling). Unfortunely, it sometimes calls the scheduler 1479afaf5a2dSDavid Somayajulu * in interrupt context which is a big NO! NO!. 1480afaf5a2dSDavid Somayajulu **/ 14818f0722caSVikas Chaudhary static int qla4xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) 1482afaf5a2dSDavid Somayajulu { 14838f0722caSVikas Chaudhary struct scsi_qla_host *ha = to_qla_host(host); 1484afaf5a2dSDavid Somayajulu struct ddb_entry *ddb_entry = cmd->device->hostdata; 14857fb1921bSMike Christie struct iscsi_cls_session *sess = ddb_entry->sess; 1486afaf5a2dSDavid Somayajulu struct srb *srb; 1487afaf5a2dSDavid Somayajulu int rval; 1488afaf5a2dSDavid Somayajulu 14892232be0dSLalit Chandivade if (test_bit(AF_EEH_BUSY, &ha->flags)) { 14902232be0dSLalit Chandivade if (test_bit(AF_PCI_CHANNEL_IO_PERM_FAILURE, &ha->flags)) 14912232be0dSLalit Chandivade cmd->result = DID_NO_CONNECT << 16; 14922232be0dSLalit Chandivade else 14932232be0dSLalit Chandivade cmd->result = DID_REQUEUE << 16; 14942232be0dSLalit Chandivade goto qc_fail_command; 14952232be0dSLalit Chandivade } 14962232be0dSLalit Chandivade 14977fb1921bSMike Christie if (!sess) { 14987fb1921bSMike Christie cmd->result = DID_IMM_RETRY << 16; 14997fb1921bSMike Christie goto qc_fail_command; 15007fb1921bSMike Christie } 15017fb1921bSMike Christie 15027fb1921bSMike Christie rval = iscsi_session_chkready(sess); 15037fb1921bSMike Christie if (rval) { 15047fb1921bSMike Christie cmd->result = rval; 15057fb1921bSMike Christie goto qc_fail_command; 15067fb1921bSMike Christie } 15077fb1921bSMike Christie 1508f4f5df23SVikas Chaudhary if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) || 1509f4f5df23SVikas Chaudhary test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags) || 1510f4f5df23SVikas Chaudhary test_bit(DPC_RESET_HA, &ha->dpc_flags) || 1511f4f5df23SVikas Chaudhary test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags) || 1512f4f5df23SVikas Chaudhary test_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags) || 1513f4f5df23SVikas Chaudhary !test_bit(AF_ONLINE, &ha->flags) || 1514b3a271a9SManish Rangankar !test_bit(AF_LINK_UP, &ha->flags) || 1515f4f5df23SVikas Chaudhary test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags)) 1516477ffb9dSDavid C Somayajulu goto qc_host_busy; 1517477ffb9dSDavid C Somayajulu 15188f0722caSVikas Chaudhary srb = qla4xxx_get_new_srb(ha, ddb_entry, cmd); 1519afaf5a2dSDavid Somayajulu if (!srb) 15208f0722caSVikas Chaudhary goto qc_host_busy; 1521afaf5a2dSDavid Somayajulu 1522afaf5a2dSDavid Somayajulu rval = qla4xxx_send_command_to_isp(ha, srb); 1523afaf5a2dSDavid Somayajulu if (rval != QLA_SUCCESS) 1524afaf5a2dSDavid Somayajulu goto qc_host_busy_free_sp; 1525afaf5a2dSDavid Somayajulu 1526afaf5a2dSDavid Somayajulu return 0; 1527afaf5a2dSDavid Somayajulu 1528afaf5a2dSDavid Somayajulu qc_host_busy_free_sp: 1529afaf5a2dSDavid Somayajulu qla4xxx_srb_free_dma(ha, srb); 1530afaf5a2dSDavid Somayajulu mempool_free(srb, ha->srb_mempool); 1531afaf5a2dSDavid Somayajulu 1532afaf5a2dSDavid Somayajulu qc_host_busy: 1533afaf5a2dSDavid Somayajulu return SCSI_MLQUEUE_HOST_BUSY; 1534afaf5a2dSDavid Somayajulu 1535afaf5a2dSDavid Somayajulu qc_fail_command: 15368f0722caSVikas Chaudhary cmd->scsi_done(cmd); 1537afaf5a2dSDavid Somayajulu 1538afaf5a2dSDavid Somayajulu return 0; 1539afaf5a2dSDavid Somayajulu } 1540afaf5a2dSDavid Somayajulu 1541afaf5a2dSDavid Somayajulu /** 1542afaf5a2dSDavid Somayajulu * qla4xxx_mem_free - frees memory allocated to adapter 1543afaf5a2dSDavid Somayajulu * @ha: Pointer to host adapter structure. 1544afaf5a2dSDavid Somayajulu * 1545afaf5a2dSDavid Somayajulu * Frees memory previously allocated by qla4xxx_mem_alloc 1546afaf5a2dSDavid Somayajulu **/ 1547afaf5a2dSDavid Somayajulu static void qla4xxx_mem_free(struct scsi_qla_host *ha) 1548afaf5a2dSDavid Somayajulu { 1549afaf5a2dSDavid Somayajulu if (ha->queues) 1550afaf5a2dSDavid Somayajulu dma_free_coherent(&ha->pdev->dev, ha->queues_len, ha->queues, 1551afaf5a2dSDavid Somayajulu ha->queues_dma); 1552afaf5a2dSDavid Somayajulu 1553afaf5a2dSDavid Somayajulu ha->queues_len = 0; 1554afaf5a2dSDavid Somayajulu ha->queues = NULL; 1555afaf5a2dSDavid Somayajulu ha->queues_dma = 0; 1556afaf5a2dSDavid Somayajulu ha->request_ring = NULL; 1557afaf5a2dSDavid Somayajulu ha->request_dma = 0; 1558afaf5a2dSDavid Somayajulu ha->response_ring = NULL; 1559afaf5a2dSDavid Somayajulu ha->response_dma = 0; 1560afaf5a2dSDavid Somayajulu ha->shadow_regs = NULL; 1561afaf5a2dSDavid Somayajulu ha->shadow_regs_dma = 0; 1562afaf5a2dSDavid Somayajulu 1563afaf5a2dSDavid Somayajulu /* Free srb pool. */ 1564afaf5a2dSDavid Somayajulu if (ha->srb_mempool) 1565afaf5a2dSDavid Somayajulu mempool_destroy(ha->srb_mempool); 1566afaf5a2dSDavid Somayajulu 1567afaf5a2dSDavid Somayajulu ha->srb_mempool = NULL; 1568afaf5a2dSDavid Somayajulu 1569b3a271a9SManish Rangankar if (ha->chap_dma_pool) 1570b3a271a9SManish Rangankar dma_pool_destroy(ha->chap_dma_pool); 1571b3a271a9SManish Rangankar 1572afaf5a2dSDavid Somayajulu /* release io space registers */ 1573f4f5df23SVikas Chaudhary if (is_qla8022(ha)) { 1574f4f5df23SVikas Chaudhary if (ha->nx_pcibase) 1575f4f5df23SVikas Chaudhary iounmap( 1576f4f5df23SVikas Chaudhary (struct device_reg_82xx __iomem *)ha->nx_pcibase); 1577f4f5df23SVikas Chaudhary } else if (ha->reg) 1578afaf5a2dSDavid Somayajulu iounmap(ha->reg); 1579afaf5a2dSDavid Somayajulu pci_release_regions(ha->pdev); 1580afaf5a2dSDavid Somayajulu } 1581afaf5a2dSDavid Somayajulu 1582afaf5a2dSDavid Somayajulu /** 1583afaf5a2dSDavid Somayajulu * qla4xxx_mem_alloc - allocates memory for use by adapter. 1584afaf5a2dSDavid Somayajulu * @ha: Pointer to host adapter structure 1585afaf5a2dSDavid Somayajulu * 1586afaf5a2dSDavid Somayajulu * Allocates DMA memory for request and response queues. Also allocates memory 1587afaf5a2dSDavid Somayajulu * for srbs. 1588afaf5a2dSDavid Somayajulu **/ 1589afaf5a2dSDavid Somayajulu static int qla4xxx_mem_alloc(struct scsi_qla_host *ha) 1590afaf5a2dSDavid Somayajulu { 1591afaf5a2dSDavid Somayajulu unsigned long align; 1592afaf5a2dSDavid Somayajulu 1593afaf5a2dSDavid Somayajulu /* Allocate contiguous block of DMA memory for queues. */ 1594afaf5a2dSDavid Somayajulu ha->queues_len = ((REQUEST_QUEUE_DEPTH * QUEUE_SIZE) + 1595afaf5a2dSDavid Somayajulu (RESPONSE_QUEUE_DEPTH * QUEUE_SIZE) + 1596afaf5a2dSDavid Somayajulu sizeof(struct shadow_regs) + 1597afaf5a2dSDavid Somayajulu MEM_ALIGN_VALUE + 1598afaf5a2dSDavid Somayajulu (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1); 1599afaf5a2dSDavid Somayajulu ha->queues = dma_alloc_coherent(&ha->pdev->dev, ha->queues_len, 1600afaf5a2dSDavid Somayajulu &ha->queues_dma, GFP_KERNEL); 1601afaf5a2dSDavid Somayajulu if (ha->queues == NULL) { 1602c2660df3SVikas Chaudhary ql4_printk(KERN_WARNING, ha, 1603afaf5a2dSDavid Somayajulu "Memory Allocation failed - queues.\n"); 1604afaf5a2dSDavid Somayajulu 1605afaf5a2dSDavid Somayajulu goto mem_alloc_error_exit; 1606afaf5a2dSDavid Somayajulu } 1607afaf5a2dSDavid Somayajulu memset(ha->queues, 0, ha->queues_len); 1608afaf5a2dSDavid Somayajulu 1609afaf5a2dSDavid Somayajulu /* 1610afaf5a2dSDavid Somayajulu * As per RISC alignment requirements -- the bus-address must be a 1611afaf5a2dSDavid Somayajulu * multiple of the request-ring size (in bytes). 1612afaf5a2dSDavid Somayajulu */ 1613afaf5a2dSDavid Somayajulu align = 0; 1614afaf5a2dSDavid Somayajulu if ((unsigned long)ha->queues_dma & (MEM_ALIGN_VALUE - 1)) 1615afaf5a2dSDavid Somayajulu align = MEM_ALIGN_VALUE - ((unsigned long)ha->queues_dma & 1616afaf5a2dSDavid Somayajulu (MEM_ALIGN_VALUE - 1)); 1617afaf5a2dSDavid Somayajulu 1618afaf5a2dSDavid Somayajulu /* Update request and response queue pointers. */ 1619afaf5a2dSDavid Somayajulu ha->request_dma = ha->queues_dma + align; 1620afaf5a2dSDavid Somayajulu ha->request_ring = (struct queue_entry *) (ha->queues + align); 1621afaf5a2dSDavid Somayajulu ha->response_dma = ha->queues_dma + align + 1622afaf5a2dSDavid Somayajulu (REQUEST_QUEUE_DEPTH * QUEUE_SIZE); 1623afaf5a2dSDavid Somayajulu ha->response_ring = (struct queue_entry *) (ha->queues + align + 1624afaf5a2dSDavid Somayajulu (REQUEST_QUEUE_DEPTH * 1625afaf5a2dSDavid Somayajulu QUEUE_SIZE)); 1626afaf5a2dSDavid Somayajulu ha->shadow_regs_dma = ha->queues_dma + align + 1627afaf5a2dSDavid Somayajulu (REQUEST_QUEUE_DEPTH * QUEUE_SIZE) + 1628afaf5a2dSDavid Somayajulu (RESPONSE_QUEUE_DEPTH * QUEUE_SIZE); 1629afaf5a2dSDavid Somayajulu ha->shadow_regs = (struct shadow_regs *) (ha->queues + align + 1630afaf5a2dSDavid Somayajulu (REQUEST_QUEUE_DEPTH * 1631afaf5a2dSDavid Somayajulu QUEUE_SIZE) + 1632afaf5a2dSDavid Somayajulu (RESPONSE_QUEUE_DEPTH * 1633afaf5a2dSDavid Somayajulu QUEUE_SIZE)); 1634afaf5a2dSDavid Somayajulu 1635afaf5a2dSDavid Somayajulu /* Allocate memory for srb pool. */ 1636afaf5a2dSDavid Somayajulu ha->srb_mempool = mempool_create(SRB_MIN_REQ, mempool_alloc_slab, 1637afaf5a2dSDavid Somayajulu mempool_free_slab, srb_cachep); 1638afaf5a2dSDavid Somayajulu if (ha->srb_mempool == NULL) { 1639c2660df3SVikas Chaudhary ql4_printk(KERN_WARNING, ha, 1640afaf5a2dSDavid Somayajulu "Memory Allocation failed - SRB Pool.\n"); 1641afaf5a2dSDavid Somayajulu 1642afaf5a2dSDavid Somayajulu goto mem_alloc_error_exit; 1643afaf5a2dSDavid Somayajulu } 1644afaf5a2dSDavid Somayajulu 1645b3a271a9SManish Rangankar ha->chap_dma_pool = dma_pool_create("ql4_chap", &ha->pdev->dev, 1646b3a271a9SManish Rangankar CHAP_DMA_BLOCK_SIZE, 8, 0); 1647b3a271a9SManish Rangankar 1648b3a271a9SManish Rangankar if (ha->chap_dma_pool == NULL) { 1649b3a271a9SManish Rangankar ql4_printk(KERN_WARNING, ha, 1650b3a271a9SManish Rangankar "%s: chap_dma_pool allocation failed..\n", __func__); 1651b3a271a9SManish Rangankar goto mem_alloc_error_exit; 1652b3a271a9SManish Rangankar } 1653b3a271a9SManish Rangankar 1654afaf5a2dSDavid Somayajulu return QLA_SUCCESS; 1655afaf5a2dSDavid Somayajulu 1656afaf5a2dSDavid Somayajulu mem_alloc_error_exit: 1657afaf5a2dSDavid Somayajulu qla4xxx_mem_free(ha); 1658afaf5a2dSDavid Somayajulu return QLA_ERROR; 1659afaf5a2dSDavid Somayajulu } 1660afaf5a2dSDavid Somayajulu 1661afaf5a2dSDavid Somayajulu /** 1662f4f5df23SVikas Chaudhary * qla4_8xxx_check_fw_alive - Check firmware health 1663f4f5df23SVikas Chaudhary * @ha: Pointer to host adapter structure. 1664f4f5df23SVikas Chaudhary * 1665f4f5df23SVikas Chaudhary * Context: Interrupt 1666f4f5df23SVikas Chaudhary **/ 1667f4f5df23SVikas Chaudhary static void qla4_8xxx_check_fw_alive(struct scsi_qla_host *ha) 1668f4f5df23SVikas Chaudhary { 1669f4f5df23SVikas Chaudhary uint32_t fw_heartbeat_counter, halt_status; 1670f4f5df23SVikas Chaudhary 1671f4f5df23SVikas Chaudhary fw_heartbeat_counter = qla4_8xxx_rd_32(ha, QLA82XX_PEG_ALIVE_COUNTER); 16722232be0dSLalit Chandivade /* If PEG_ALIVE_COUNTER is 0xffffffff, AER/EEH is in progress, ignore */ 16732232be0dSLalit Chandivade if (fw_heartbeat_counter == 0xffffffff) { 16742232be0dSLalit Chandivade DEBUG2(printk(KERN_WARNING "scsi%ld: %s: Device in frozen " 16752232be0dSLalit Chandivade "state, QLA82XX_PEG_ALIVE_COUNTER is 0xffffffff\n", 16762232be0dSLalit Chandivade ha->host_no, __func__)); 16772232be0dSLalit Chandivade return; 16782232be0dSLalit Chandivade } 1679f4f5df23SVikas Chaudhary 1680f4f5df23SVikas Chaudhary if (ha->fw_heartbeat_counter == fw_heartbeat_counter) { 1681f4f5df23SVikas Chaudhary ha->seconds_since_last_heartbeat++; 1682f4f5df23SVikas Chaudhary /* FW not alive after 2 seconds */ 1683f4f5df23SVikas Chaudhary if (ha->seconds_since_last_heartbeat == 2) { 1684f4f5df23SVikas Chaudhary ha->seconds_since_last_heartbeat = 0; 1685f4f5df23SVikas Chaudhary halt_status = qla4_8xxx_rd_32(ha, 1686f4f5df23SVikas Chaudhary QLA82XX_PEG_HALT_STATUS1); 168768d92ebfSVikas Chaudhary 168868d92ebfSVikas Chaudhary ql4_printk(KERN_INFO, ha, 168968d92ebfSVikas Chaudhary "scsi(%ld): %s, Dumping hw/fw registers:\n " 169068d92ebfSVikas Chaudhary " PEG_HALT_STATUS1: 0x%x, PEG_HALT_STATUS2:" 169168d92ebfSVikas Chaudhary " 0x%x,\n PEG_NET_0_PC: 0x%x, PEG_NET_1_PC:" 169268d92ebfSVikas Chaudhary " 0x%x,\n PEG_NET_2_PC: 0x%x, PEG_NET_3_PC:" 169368d92ebfSVikas Chaudhary " 0x%x,\n PEG_NET_4_PC: 0x%x\n", 169468d92ebfSVikas Chaudhary ha->host_no, __func__, halt_status, 169568d92ebfSVikas Chaudhary qla4_8xxx_rd_32(ha, 169668d92ebfSVikas Chaudhary QLA82XX_PEG_HALT_STATUS2), 169768d92ebfSVikas Chaudhary qla4_8xxx_rd_32(ha, QLA82XX_CRB_PEG_NET_0 + 169868d92ebfSVikas Chaudhary 0x3c), 169968d92ebfSVikas Chaudhary qla4_8xxx_rd_32(ha, QLA82XX_CRB_PEG_NET_1 + 170068d92ebfSVikas Chaudhary 0x3c), 170168d92ebfSVikas Chaudhary qla4_8xxx_rd_32(ha, QLA82XX_CRB_PEG_NET_2 + 170268d92ebfSVikas Chaudhary 0x3c), 170368d92ebfSVikas Chaudhary qla4_8xxx_rd_32(ha, QLA82XX_CRB_PEG_NET_3 + 170468d92ebfSVikas Chaudhary 0x3c), 170568d92ebfSVikas Chaudhary qla4_8xxx_rd_32(ha, QLA82XX_CRB_PEG_NET_4 + 170668d92ebfSVikas Chaudhary 0x3c)); 170721033639SNilesh Javali 1708f4f5df23SVikas Chaudhary /* Since we cannot change dev_state in interrupt 1709f4f5df23SVikas Chaudhary * context, set appropriate DPC flag then wakeup 1710f4f5df23SVikas Chaudhary * DPC */ 1711f4f5df23SVikas Chaudhary if (halt_status & HALT_STATUS_UNRECOVERABLE) 1712f4f5df23SVikas Chaudhary set_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags); 1713f4f5df23SVikas Chaudhary else { 1714f4f5df23SVikas Chaudhary printk("scsi%ld: %s: detect abort needed!\n", 1715f4f5df23SVikas Chaudhary ha->host_no, __func__); 1716f4f5df23SVikas Chaudhary set_bit(DPC_RESET_HA, &ha->dpc_flags); 1717f4f5df23SVikas Chaudhary } 1718f4f5df23SVikas Chaudhary qla4xxx_wake_dpc(ha); 171921033639SNilesh Javali qla4xxx_mailbox_premature_completion(ha); 1720f4f5df23SVikas Chaudhary } 172199457d75SLalit Chandivade } else 172299457d75SLalit Chandivade ha->seconds_since_last_heartbeat = 0; 172399457d75SLalit Chandivade 1724f4f5df23SVikas Chaudhary ha->fw_heartbeat_counter = fw_heartbeat_counter; 1725f4f5df23SVikas Chaudhary } 1726f4f5df23SVikas Chaudhary 1727f4f5df23SVikas Chaudhary /** 1728f4f5df23SVikas Chaudhary * qla4_8xxx_watchdog - Poll dev state 1729f4f5df23SVikas Chaudhary * @ha: Pointer to host adapter structure. 1730f4f5df23SVikas Chaudhary * 1731f4f5df23SVikas Chaudhary * Context: Interrupt 1732f4f5df23SVikas Chaudhary **/ 1733f4f5df23SVikas Chaudhary void qla4_8xxx_watchdog(struct scsi_qla_host *ha) 1734f4f5df23SVikas Chaudhary { 1735f4f5df23SVikas Chaudhary uint32_t dev_state; 1736f4f5df23SVikas Chaudhary 1737f4f5df23SVikas Chaudhary dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE); 1738f4f5df23SVikas Chaudhary 1739f4f5df23SVikas Chaudhary /* don't poll if reset is going on */ 1740d56a1f7bSLalit Chandivade if (!(test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags) || 1741d56a1f7bSLalit Chandivade test_bit(DPC_RESET_HA, &ha->dpc_flags) || 1742977f46a4SVikas Chaudhary test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags))) { 1743f4f5df23SVikas Chaudhary if (dev_state == QLA82XX_DEV_NEED_RESET && 1744f4f5df23SVikas Chaudhary !test_bit(DPC_RESET_HA, &ha->dpc_flags)) { 17453930b8c1SVikas Chaudhary if (!ql4xdontresethba) { 17463930b8c1SVikas Chaudhary ql4_printk(KERN_INFO, ha, "%s: HW State: " 17473930b8c1SVikas Chaudhary "NEED RESET!\n", __func__); 1748f4f5df23SVikas Chaudhary set_bit(DPC_RESET_HA, &ha->dpc_flags); 1749f4f5df23SVikas Chaudhary qla4xxx_wake_dpc(ha); 175021033639SNilesh Javali qla4xxx_mailbox_premature_completion(ha); 17513930b8c1SVikas Chaudhary } 1752f4f5df23SVikas Chaudhary } else if (dev_state == QLA82XX_DEV_NEED_QUIESCENT && 1753f4f5df23SVikas Chaudhary !test_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags)) { 17543930b8c1SVikas Chaudhary ql4_printk(KERN_INFO, ha, "%s: HW State: NEED QUIES!\n", 17553930b8c1SVikas Chaudhary __func__); 1756f4f5df23SVikas Chaudhary set_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags); 1757f4f5df23SVikas Chaudhary qla4xxx_wake_dpc(ha); 1758f4f5df23SVikas Chaudhary } else { 1759f4f5df23SVikas Chaudhary /* Check firmware health */ 1760f4f5df23SVikas Chaudhary qla4_8xxx_check_fw_alive(ha); 1761f4f5df23SVikas Chaudhary } 1762f4f5df23SVikas Chaudhary } 1763f4f5df23SVikas Chaudhary } 1764f4f5df23SVikas Chaudhary 1765f4f5df23SVikas Chaudhary /** 1766afaf5a2dSDavid Somayajulu * qla4xxx_timer - checks every second for work to do. 1767afaf5a2dSDavid Somayajulu * @ha: Pointer to host adapter structure. 1768afaf5a2dSDavid Somayajulu **/ 1769afaf5a2dSDavid Somayajulu static void qla4xxx_timer(struct scsi_qla_host *ha) 1770afaf5a2dSDavid Somayajulu { 1771afaf5a2dSDavid Somayajulu int start_dpc = 0; 17722232be0dSLalit Chandivade uint16_t w; 17732232be0dSLalit Chandivade 17742232be0dSLalit Chandivade /* If we are in the middle of AER/EEH processing 17752232be0dSLalit Chandivade * skip any processing and reschedule the timer 17762232be0dSLalit Chandivade */ 17772232be0dSLalit Chandivade if (test_bit(AF_EEH_BUSY, &ha->flags)) { 17782232be0dSLalit Chandivade mod_timer(&ha->timer, jiffies + HZ); 17792232be0dSLalit Chandivade return; 17802232be0dSLalit Chandivade } 17812232be0dSLalit Chandivade 17822232be0dSLalit Chandivade /* Hardware read to trigger an EEH error during mailbox waits. */ 17832232be0dSLalit Chandivade if (!pci_channel_offline(ha->pdev)) 17842232be0dSLalit Chandivade pci_read_config_word(ha->pdev, PCI_VENDOR_ID, &w); 1785afaf5a2dSDavid Somayajulu 1786f4f5df23SVikas Chaudhary if (is_qla8022(ha)) { 1787f4f5df23SVikas Chaudhary qla4_8xxx_watchdog(ha); 1788f4f5df23SVikas Chaudhary } 1789f4f5df23SVikas Chaudhary 1790f4f5df23SVikas Chaudhary if (!is_qla8022(ha)) { 1791afaf5a2dSDavid Somayajulu /* Check for heartbeat interval. */ 1792afaf5a2dSDavid Somayajulu if (ha->firmware_options & FWOPT_HEARTBEAT_ENABLE && 1793afaf5a2dSDavid Somayajulu ha->heartbeat_interval != 0) { 1794afaf5a2dSDavid Somayajulu ha->seconds_since_last_heartbeat++; 1795afaf5a2dSDavid Somayajulu if (ha->seconds_since_last_heartbeat > 1796afaf5a2dSDavid Somayajulu ha->heartbeat_interval + 2) 1797afaf5a2dSDavid Somayajulu set_bit(DPC_RESET_HA, &ha->dpc_flags); 1798afaf5a2dSDavid Somayajulu } 1799f4f5df23SVikas Chaudhary } 1800afaf5a2dSDavid Somayajulu 1801afaf5a2dSDavid Somayajulu /* Wakeup the dpc routine for this adapter, if needed. */ 18021b46807eSLalit Chandivade if (start_dpc || 1803afaf5a2dSDavid Somayajulu test_bit(DPC_RESET_HA, &ha->dpc_flags) || 1804afaf5a2dSDavid Somayajulu test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags) || 1805afaf5a2dSDavid Somayajulu test_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags) || 1806f4f5df23SVikas Chaudhary test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags) || 1807afaf5a2dSDavid Somayajulu test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) || 1808afaf5a2dSDavid Somayajulu test_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags) || 1809065aa1b4SVikas Chaudhary test_bit(DPC_LINK_CHANGED, &ha->dpc_flags) || 1810f4f5df23SVikas Chaudhary test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags) || 1811f4f5df23SVikas Chaudhary test_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags) || 18121b46807eSLalit Chandivade test_bit(DPC_AEN, &ha->dpc_flags)) { 1813afaf5a2dSDavid Somayajulu DEBUG2(printk("scsi%ld: %s: scheduling dpc routine" 1814afaf5a2dSDavid Somayajulu " - dpc flags = 0x%lx\n", 1815afaf5a2dSDavid Somayajulu ha->host_no, __func__, ha->dpc_flags)); 1816f4f5df23SVikas Chaudhary qla4xxx_wake_dpc(ha); 1817afaf5a2dSDavid Somayajulu } 1818afaf5a2dSDavid Somayajulu 1819afaf5a2dSDavid Somayajulu /* Reschedule timer thread to call us back in one second */ 1820afaf5a2dSDavid Somayajulu mod_timer(&ha->timer, jiffies + HZ); 1821afaf5a2dSDavid Somayajulu 1822afaf5a2dSDavid Somayajulu DEBUG2(ha->seconds_since_last_intr++); 1823afaf5a2dSDavid Somayajulu } 1824afaf5a2dSDavid Somayajulu 1825afaf5a2dSDavid Somayajulu /** 1826afaf5a2dSDavid Somayajulu * qla4xxx_cmd_wait - waits for all outstanding commands to complete 1827afaf5a2dSDavid Somayajulu * @ha: Pointer to host adapter structure. 1828afaf5a2dSDavid Somayajulu * 1829afaf5a2dSDavid Somayajulu * This routine stalls the driver until all outstanding commands are returned. 1830afaf5a2dSDavid Somayajulu * Caller must release the Hardware Lock prior to calling this routine. 1831afaf5a2dSDavid Somayajulu **/ 1832afaf5a2dSDavid Somayajulu static int qla4xxx_cmd_wait(struct scsi_qla_host *ha) 1833afaf5a2dSDavid Somayajulu { 1834afaf5a2dSDavid Somayajulu uint32_t index = 0; 1835afaf5a2dSDavid Somayajulu unsigned long flags; 1836afaf5a2dSDavid Somayajulu struct scsi_cmnd *cmd; 1837afaf5a2dSDavid Somayajulu 1838f4f5df23SVikas Chaudhary unsigned long wtime = jiffies + (WAIT_CMD_TOV * HZ); 1839f4f5df23SVikas Chaudhary 1840f4f5df23SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, "Wait up to %d seconds for cmds to " 1841f4f5df23SVikas Chaudhary "complete\n", WAIT_CMD_TOV)); 1842f4f5df23SVikas Chaudhary 1843f4f5df23SVikas Chaudhary while (!time_after_eq(jiffies, wtime)) { 1844afaf5a2dSDavid Somayajulu spin_lock_irqsave(&ha->hardware_lock, flags); 1845afaf5a2dSDavid Somayajulu /* Find a command that hasn't completed. */ 1846afaf5a2dSDavid Somayajulu for (index = 0; index < ha->host->can_queue; index++) { 1847afaf5a2dSDavid Somayajulu cmd = scsi_host_find_tag(ha->host, index); 1848a1e0063dSMike Christie /* 1849a1e0063dSMike Christie * We cannot just check if the index is valid, 1850a1e0063dSMike Christie * becase if we are run from the scsi eh, then 1851a1e0063dSMike Christie * the scsi/block layer is going to prevent 1852a1e0063dSMike Christie * the tag from being released. 1853a1e0063dSMike Christie */ 1854a1e0063dSMike Christie if (cmd != NULL && CMD_SP(cmd)) 1855afaf5a2dSDavid Somayajulu break; 1856afaf5a2dSDavid Somayajulu } 1857afaf5a2dSDavid Somayajulu spin_unlock_irqrestore(&ha->hardware_lock, flags); 1858afaf5a2dSDavid Somayajulu 1859afaf5a2dSDavid Somayajulu /* If No Commands are pending, wait is complete */ 1860f4f5df23SVikas Chaudhary if (index == ha->host->can_queue) 1861f4f5df23SVikas Chaudhary return QLA_SUCCESS; 1862afaf5a2dSDavid Somayajulu 1863afaf5a2dSDavid Somayajulu msleep(1000); 1864afaf5a2dSDavid Somayajulu } 1865f4f5df23SVikas Chaudhary /* If we timed out on waiting for commands to come back 1866f4f5df23SVikas Chaudhary * return ERROR. */ 1867f4f5df23SVikas Chaudhary return QLA_ERROR; 1868afaf5a2dSDavid Somayajulu } 1869afaf5a2dSDavid Somayajulu 1870f4f5df23SVikas Chaudhary int qla4xxx_hw_reset(struct scsi_qla_host *ha) 1871afaf5a2dSDavid Somayajulu { 1872afaf5a2dSDavid Somayajulu uint32_t ctrl_status; 1873477ffb9dSDavid C Somayajulu unsigned long flags = 0; 1874477ffb9dSDavid C Somayajulu 1875477ffb9dSDavid C Somayajulu DEBUG2(printk(KERN_ERR "scsi%ld: %s\n", ha->host_no, __func__)); 1876afaf5a2dSDavid Somayajulu 1877f4f5df23SVikas Chaudhary if (ql4xxx_lock_drvr_wait(ha) != QLA_SUCCESS) 1878f4f5df23SVikas Chaudhary return QLA_ERROR; 1879f4f5df23SVikas Chaudhary 1880afaf5a2dSDavid Somayajulu spin_lock_irqsave(&ha->hardware_lock, flags); 1881afaf5a2dSDavid Somayajulu 1882afaf5a2dSDavid Somayajulu /* 1883afaf5a2dSDavid Somayajulu * If the SCSI Reset Interrupt bit is set, clear it. 1884afaf5a2dSDavid Somayajulu * Otherwise, the Soft Reset won't work. 1885afaf5a2dSDavid Somayajulu */ 1886afaf5a2dSDavid Somayajulu ctrl_status = readw(&ha->reg->ctrl_status); 1887afaf5a2dSDavid Somayajulu if ((ctrl_status & CSR_SCSI_RESET_INTR) != 0) 1888afaf5a2dSDavid Somayajulu writel(set_rmask(CSR_SCSI_RESET_INTR), &ha->reg->ctrl_status); 1889afaf5a2dSDavid Somayajulu 1890afaf5a2dSDavid Somayajulu /* Issue Soft Reset */ 1891afaf5a2dSDavid Somayajulu writel(set_rmask(CSR_SOFT_RESET), &ha->reg->ctrl_status); 1892afaf5a2dSDavid Somayajulu readl(&ha->reg->ctrl_status); 1893afaf5a2dSDavid Somayajulu 1894afaf5a2dSDavid Somayajulu spin_unlock_irqrestore(&ha->hardware_lock, flags); 1895f4f5df23SVikas Chaudhary return QLA_SUCCESS; 1896477ffb9dSDavid C Somayajulu } 1897477ffb9dSDavid C Somayajulu 1898477ffb9dSDavid C Somayajulu /** 1899477ffb9dSDavid C Somayajulu * qla4xxx_soft_reset - performs soft reset. 1900477ffb9dSDavid C Somayajulu * @ha: Pointer to host adapter structure. 1901477ffb9dSDavid C Somayajulu **/ 1902477ffb9dSDavid C Somayajulu int qla4xxx_soft_reset(struct scsi_qla_host *ha) 1903477ffb9dSDavid C Somayajulu { 1904477ffb9dSDavid C Somayajulu uint32_t max_wait_time; 1905477ffb9dSDavid C Somayajulu unsigned long flags = 0; 1906f931c534SVikas Chaudhary int status; 1907477ffb9dSDavid C Somayajulu uint32_t ctrl_status; 1908477ffb9dSDavid C Somayajulu 1909f931c534SVikas Chaudhary status = qla4xxx_hw_reset(ha); 1910f931c534SVikas Chaudhary if (status != QLA_SUCCESS) 1911f931c534SVikas Chaudhary return status; 1912afaf5a2dSDavid Somayajulu 1913f931c534SVikas Chaudhary status = QLA_ERROR; 1914afaf5a2dSDavid Somayajulu /* Wait until the Network Reset Intr bit is cleared */ 1915afaf5a2dSDavid Somayajulu max_wait_time = RESET_INTR_TOV; 1916afaf5a2dSDavid Somayajulu do { 1917afaf5a2dSDavid Somayajulu spin_lock_irqsave(&ha->hardware_lock, flags); 1918afaf5a2dSDavid Somayajulu ctrl_status = readw(&ha->reg->ctrl_status); 1919afaf5a2dSDavid Somayajulu spin_unlock_irqrestore(&ha->hardware_lock, flags); 1920afaf5a2dSDavid Somayajulu 1921afaf5a2dSDavid Somayajulu if ((ctrl_status & CSR_NET_RESET_INTR) == 0) 1922afaf5a2dSDavid Somayajulu break; 1923afaf5a2dSDavid Somayajulu 1924afaf5a2dSDavid Somayajulu msleep(1000); 1925afaf5a2dSDavid Somayajulu } while ((--max_wait_time)); 1926afaf5a2dSDavid Somayajulu 1927afaf5a2dSDavid Somayajulu if ((ctrl_status & CSR_NET_RESET_INTR) != 0) { 1928afaf5a2dSDavid Somayajulu DEBUG2(printk(KERN_WARNING 1929afaf5a2dSDavid Somayajulu "scsi%ld: Network Reset Intr not cleared by " 1930afaf5a2dSDavid Somayajulu "Network function, clearing it now!\n", 1931afaf5a2dSDavid Somayajulu ha->host_no)); 1932afaf5a2dSDavid Somayajulu spin_lock_irqsave(&ha->hardware_lock, flags); 1933afaf5a2dSDavid Somayajulu writel(set_rmask(CSR_NET_RESET_INTR), &ha->reg->ctrl_status); 1934afaf5a2dSDavid Somayajulu readl(&ha->reg->ctrl_status); 1935afaf5a2dSDavid Somayajulu spin_unlock_irqrestore(&ha->hardware_lock, flags); 1936afaf5a2dSDavid Somayajulu } 1937afaf5a2dSDavid Somayajulu 1938afaf5a2dSDavid Somayajulu /* Wait until the firmware tells us the Soft Reset is done */ 1939afaf5a2dSDavid Somayajulu max_wait_time = SOFT_RESET_TOV; 1940afaf5a2dSDavid Somayajulu do { 1941afaf5a2dSDavid Somayajulu spin_lock_irqsave(&ha->hardware_lock, flags); 1942afaf5a2dSDavid Somayajulu ctrl_status = readw(&ha->reg->ctrl_status); 1943afaf5a2dSDavid Somayajulu spin_unlock_irqrestore(&ha->hardware_lock, flags); 1944afaf5a2dSDavid Somayajulu 1945afaf5a2dSDavid Somayajulu if ((ctrl_status & CSR_SOFT_RESET) == 0) { 1946afaf5a2dSDavid Somayajulu status = QLA_SUCCESS; 1947afaf5a2dSDavid Somayajulu break; 1948afaf5a2dSDavid Somayajulu } 1949afaf5a2dSDavid Somayajulu 1950afaf5a2dSDavid Somayajulu msleep(1000); 1951afaf5a2dSDavid Somayajulu } while ((--max_wait_time)); 1952afaf5a2dSDavid Somayajulu 1953afaf5a2dSDavid Somayajulu /* 1954afaf5a2dSDavid Somayajulu * Also, make sure that the SCSI Reset Interrupt bit has been cleared 1955afaf5a2dSDavid Somayajulu * after the soft reset has taken place. 1956afaf5a2dSDavid Somayajulu */ 1957afaf5a2dSDavid Somayajulu spin_lock_irqsave(&ha->hardware_lock, flags); 1958afaf5a2dSDavid Somayajulu ctrl_status = readw(&ha->reg->ctrl_status); 1959afaf5a2dSDavid Somayajulu if ((ctrl_status & CSR_SCSI_RESET_INTR) != 0) { 1960afaf5a2dSDavid Somayajulu writel(set_rmask(CSR_SCSI_RESET_INTR), &ha->reg->ctrl_status); 1961afaf5a2dSDavid Somayajulu readl(&ha->reg->ctrl_status); 1962afaf5a2dSDavid Somayajulu } 1963afaf5a2dSDavid Somayajulu spin_unlock_irqrestore(&ha->hardware_lock, flags); 1964afaf5a2dSDavid Somayajulu 1965afaf5a2dSDavid Somayajulu /* If soft reset fails then most probably the bios on other 1966afaf5a2dSDavid Somayajulu * function is also enabled. 1967afaf5a2dSDavid Somayajulu * Since the initialization is sequential the other fn 1968afaf5a2dSDavid Somayajulu * wont be able to acknowledge the soft reset. 1969afaf5a2dSDavid Somayajulu * Issue a force soft reset to workaround this scenario. 1970afaf5a2dSDavid Somayajulu */ 1971afaf5a2dSDavid Somayajulu if (max_wait_time == 0) { 1972afaf5a2dSDavid Somayajulu /* Issue Force Soft Reset */ 1973afaf5a2dSDavid Somayajulu spin_lock_irqsave(&ha->hardware_lock, flags); 1974afaf5a2dSDavid Somayajulu writel(set_rmask(CSR_FORCE_SOFT_RESET), &ha->reg->ctrl_status); 1975afaf5a2dSDavid Somayajulu readl(&ha->reg->ctrl_status); 1976afaf5a2dSDavid Somayajulu spin_unlock_irqrestore(&ha->hardware_lock, flags); 1977afaf5a2dSDavid Somayajulu /* Wait until the firmware tells us the Soft Reset is done */ 1978afaf5a2dSDavid Somayajulu max_wait_time = SOFT_RESET_TOV; 1979afaf5a2dSDavid Somayajulu do { 1980afaf5a2dSDavid Somayajulu spin_lock_irqsave(&ha->hardware_lock, flags); 1981afaf5a2dSDavid Somayajulu ctrl_status = readw(&ha->reg->ctrl_status); 1982afaf5a2dSDavid Somayajulu spin_unlock_irqrestore(&ha->hardware_lock, flags); 1983afaf5a2dSDavid Somayajulu 1984afaf5a2dSDavid Somayajulu if ((ctrl_status & CSR_FORCE_SOFT_RESET) == 0) { 1985afaf5a2dSDavid Somayajulu status = QLA_SUCCESS; 1986afaf5a2dSDavid Somayajulu break; 1987afaf5a2dSDavid Somayajulu } 1988afaf5a2dSDavid Somayajulu 1989afaf5a2dSDavid Somayajulu msleep(1000); 1990afaf5a2dSDavid Somayajulu } while ((--max_wait_time)); 1991afaf5a2dSDavid Somayajulu } 1992afaf5a2dSDavid Somayajulu 1993afaf5a2dSDavid Somayajulu return status; 1994afaf5a2dSDavid Somayajulu } 1995afaf5a2dSDavid Somayajulu 1996afaf5a2dSDavid Somayajulu /** 1997f4f5df23SVikas Chaudhary * qla4xxx_abort_active_cmds - returns all outstanding i/o requests to O.S. 1998afaf5a2dSDavid Somayajulu * @ha: Pointer to host adapter structure. 1999f4f5df23SVikas Chaudhary * @res: returned scsi status 2000afaf5a2dSDavid Somayajulu * 2001afaf5a2dSDavid Somayajulu * This routine is called just prior to a HARD RESET to return all 2002afaf5a2dSDavid Somayajulu * outstanding commands back to the Operating System. 2003afaf5a2dSDavid Somayajulu * Caller should make sure that the following locks are released 2004afaf5a2dSDavid Somayajulu * before this calling routine: Hardware lock, and io_request_lock. 2005afaf5a2dSDavid Somayajulu **/ 2006f4f5df23SVikas Chaudhary static void qla4xxx_abort_active_cmds(struct scsi_qla_host *ha, int res) 2007afaf5a2dSDavid Somayajulu { 2008afaf5a2dSDavid Somayajulu struct srb *srb; 2009afaf5a2dSDavid Somayajulu int i; 2010afaf5a2dSDavid Somayajulu unsigned long flags; 2011afaf5a2dSDavid Somayajulu 2012afaf5a2dSDavid Somayajulu spin_lock_irqsave(&ha->hardware_lock, flags); 2013afaf5a2dSDavid Somayajulu for (i = 0; i < ha->host->can_queue; i++) { 2014afaf5a2dSDavid Somayajulu srb = qla4xxx_del_from_active_array(ha, i); 2015afaf5a2dSDavid Somayajulu if (srb != NULL) { 2016f4f5df23SVikas Chaudhary srb->cmd->result = res; 201709a0f719SVikas Chaudhary kref_put(&srb->srb_ref, qla4xxx_srb_compl); 2018afaf5a2dSDavid Somayajulu } 2019afaf5a2dSDavid Somayajulu } 2020afaf5a2dSDavid Somayajulu spin_unlock_irqrestore(&ha->hardware_lock, flags); 2021afaf5a2dSDavid Somayajulu } 2022afaf5a2dSDavid Somayajulu 2023f4f5df23SVikas Chaudhary void qla4xxx_dead_adapter_cleanup(struct scsi_qla_host *ha) 2024f4f5df23SVikas Chaudhary { 2025f4f5df23SVikas Chaudhary clear_bit(AF_ONLINE, &ha->flags); 2026f4f5df23SVikas Chaudhary 2027f4f5df23SVikas Chaudhary /* Disable the board */ 2028f4f5df23SVikas Chaudhary ql4_printk(KERN_INFO, ha, "Disabling the board\n"); 2029f4f5df23SVikas Chaudhary 2030f4f5df23SVikas Chaudhary qla4xxx_abort_active_cmds(ha, DID_NO_CONNECT << 16); 2031f4f5df23SVikas Chaudhary qla4xxx_mark_all_devices_missing(ha); 2032f4f5df23SVikas Chaudhary clear_bit(AF_INIT_DONE, &ha->flags); 2033f4f5df23SVikas Chaudhary } 2034f4f5df23SVikas Chaudhary 2035b3a271a9SManish Rangankar static void qla4xxx_fail_session(struct iscsi_cls_session *cls_session) 2036b3a271a9SManish Rangankar { 2037b3a271a9SManish Rangankar struct iscsi_session *sess; 2038b3a271a9SManish Rangankar struct ddb_entry *ddb_entry; 2039b3a271a9SManish Rangankar 2040b3a271a9SManish Rangankar sess = cls_session->dd_data; 2041b3a271a9SManish Rangankar ddb_entry = sess->dd_data; 2042b3a271a9SManish Rangankar ddb_entry->fw_ddb_device_state = DDB_DS_SESSION_FAILED; 2043b3a271a9SManish Rangankar iscsi_session_failure(cls_session->dd_data, ISCSI_ERR_CONN_FAILED); 2044b3a271a9SManish Rangankar } 2045b3a271a9SManish Rangankar 2046afaf5a2dSDavid Somayajulu /** 2047afaf5a2dSDavid Somayajulu * qla4xxx_recover_adapter - recovers adapter after a fatal error 2048afaf5a2dSDavid Somayajulu * @ha: Pointer to host adapter structure. 2049afaf5a2dSDavid Somayajulu **/ 2050f4f5df23SVikas Chaudhary static int qla4xxx_recover_adapter(struct scsi_qla_host *ha) 2051afaf5a2dSDavid Somayajulu { 2052f4f5df23SVikas Chaudhary int status = QLA_ERROR; 2053f4f5df23SVikas Chaudhary uint8_t reset_chip = 0; 2054afaf5a2dSDavid Somayajulu 2055afaf5a2dSDavid Somayajulu /* Stall incoming I/O until we are done */ 2056f4f5df23SVikas Chaudhary scsi_block_requests(ha->host); 2057afaf5a2dSDavid Somayajulu clear_bit(AF_ONLINE, &ha->flags); 2058b3a271a9SManish Rangankar clear_bit(AF_LINK_UP, &ha->flags); 205950a29aecSMike Christie 2060f4f5df23SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, "%s: adapter OFFLINE\n", __func__)); 2061afaf5a2dSDavid Somayajulu 2062f4f5df23SVikas Chaudhary set_bit(DPC_RESET_ACTIVE, &ha->dpc_flags); 2063afaf5a2dSDavid Somayajulu 2064b3a271a9SManish Rangankar iscsi_host_for_each_session(ha->host, qla4xxx_fail_session); 2065b3a271a9SManish Rangankar 2066f4f5df23SVikas Chaudhary if (test_bit(DPC_RESET_HA, &ha->dpc_flags)) 2067f4f5df23SVikas Chaudhary reset_chip = 1; 2068afaf5a2dSDavid Somayajulu 2069f4f5df23SVikas Chaudhary /* For the DPC_RESET_HA_INTR case (ISP-4xxx specific) 2070f4f5df23SVikas Chaudhary * do not reset adapter, jump to initialize_adapter */ 2071f4f5df23SVikas Chaudhary if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) { 2072f4f5df23SVikas Chaudhary status = QLA_SUCCESS; 2073f4f5df23SVikas Chaudhary goto recover_ha_init_adapter; 2074afaf5a2dSDavid Somayajulu } 2075afaf5a2dSDavid Somayajulu 2076f4f5df23SVikas Chaudhary /* For the ISP-82xx adapter, issue a stop_firmware if invoked 2077f4f5df23SVikas Chaudhary * from eh_host_reset or ioctl module */ 2078f4f5df23SVikas Chaudhary if (is_qla8022(ha) && !reset_chip && 2079f4f5df23SVikas Chaudhary test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags)) { 2080f4f5df23SVikas Chaudhary 2081f4f5df23SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, 2082f4f5df23SVikas Chaudhary "scsi%ld: %s - Performing stop_firmware...\n", 2083f4f5df23SVikas Chaudhary ha->host_no, __func__)); 2084f4f5df23SVikas Chaudhary status = ha->isp_ops->reset_firmware(ha); 2085f4f5df23SVikas Chaudhary if (status == QLA_SUCCESS) { 20862bd1e2beSNilesh Javali if (!test_bit(AF_FW_RECOVERY, &ha->flags)) 2087f4f5df23SVikas Chaudhary qla4xxx_cmd_wait(ha); 2088f4f5df23SVikas Chaudhary ha->isp_ops->disable_intrs(ha); 2089f4f5df23SVikas Chaudhary qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); 2090f4f5df23SVikas Chaudhary qla4xxx_abort_active_cmds(ha, DID_RESET << 16); 2091f4f5df23SVikas Chaudhary } else { 2092f4f5df23SVikas Chaudhary /* If the stop_firmware fails then 2093f4f5df23SVikas Chaudhary * reset the entire chip */ 2094f4f5df23SVikas Chaudhary reset_chip = 1; 2095f4f5df23SVikas Chaudhary clear_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags); 2096f4f5df23SVikas Chaudhary set_bit(DPC_RESET_HA, &ha->dpc_flags); 2097f4f5df23SVikas Chaudhary } 2098f4f5df23SVikas Chaudhary } 2099f4f5df23SVikas Chaudhary 2100f4f5df23SVikas Chaudhary /* Issue full chip reset if recovering from a catastrophic error, 2101f4f5df23SVikas Chaudhary * or if stop_firmware fails for ISP-82xx. 2102f4f5df23SVikas Chaudhary * This is the default case for ISP-4xxx */ 2103f4f5df23SVikas Chaudhary if (!is_qla8022(ha) || reset_chip) { 21042bd1e2beSNilesh Javali if (!test_bit(AF_FW_RECOVERY, &ha->flags)) 2105f4f5df23SVikas Chaudhary qla4xxx_cmd_wait(ha); 2106f4f5df23SVikas Chaudhary qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); 2107f4f5df23SVikas Chaudhary qla4xxx_abort_active_cmds(ha, DID_RESET << 16); 2108f4f5df23SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, 2109f4f5df23SVikas Chaudhary "scsi%ld: %s - Performing chip reset..\n", 2110f4f5df23SVikas Chaudhary ha->host_no, __func__)); 2111f4f5df23SVikas Chaudhary status = ha->isp_ops->reset_chip(ha); 2112f4f5df23SVikas Chaudhary } 2113f4f5df23SVikas Chaudhary 2114f4f5df23SVikas Chaudhary /* Flush any pending ddb changed AENs */ 2115f4f5df23SVikas Chaudhary qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); 2116f4f5df23SVikas Chaudhary 2117f4f5df23SVikas Chaudhary recover_ha_init_adapter: 2118f4f5df23SVikas Chaudhary /* Upon successful firmware/chip reset, re-initialize the adapter */ 2119f4f5df23SVikas Chaudhary if (status == QLA_SUCCESS) { 2120f4f5df23SVikas Chaudhary /* For ISP-4xxx, force function 1 to always initialize 2121f4f5df23SVikas Chaudhary * before function 3 to prevent both funcions from 2122f4f5df23SVikas Chaudhary * stepping on top of the other */ 2123f4f5df23SVikas Chaudhary if (!is_qla8022(ha) && (ha->mac_index == 3)) 2124f4f5df23SVikas Chaudhary ssleep(6); 2125f4f5df23SVikas Chaudhary 2126f4f5df23SVikas Chaudhary /* NOTE: AF_ONLINE flag set upon successful completion of 2127f4f5df23SVikas Chaudhary * qla4xxx_initialize_adapter */ 21280e7e8501SManish Rangankar status = qla4xxx_initialize_adapter(ha); 2129f4f5df23SVikas Chaudhary } 2130f4f5df23SVikas Chaudhary 2131f4f5df23SVikas Chaudhary /* Retry failed adapter initialization, if necessary 2132f4f5df23SVikas Chaudhary * Do not retry initialize_adapter for RESET_HA_INTR (ISP-4xxx specific) 2133f4f5df23SVikas Chaudhary * case to prevent ping-pong resets between functions */ 2134f4f5df23SVikas Chaudhary if (!test_bit(AF_ONLINE, &ha->flags) && 2135f4f5df23SVikas Chaudhary !test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) { 2136afaf5a2dSDavid Somayajulu /* Adapter initialization failed, see if we can retry 2137f4f5df23SVikas Chaudhary * resetting the ha. 2138f4f5df23SVikas Chaudhary * Since we don't want to block the DPC for too long 2139f4f5df23SVikas Chaudhary * with multiple resets in the same thread, 2140f4f5df23SVikas Chaudhary * utilize DPC to retry */ 2141afaf5a2dSDavid Somayajulu if (!test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags)) { 2142afaf5a2dSDavid Somayajulu ha->retry_reset_ha_cnt = MAX_RESET_HA_RETRIES; 2143afaf5a2dSDavid Somayajulu DEBUG2(printk("scsi%ld: recover adapter - retrying " 2144afaf5a2dSDavid Somayajulu "(%d) more times\n", ha->host_no, 2145afaf5a2dSDavid Somayajulu ha->retry_reset_ha_cnt)); 2146afaf5a2dSDavid Somayajulu set_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags); 2147afaf5a2dSDavid Somayajulu status = QLA_ERROR; 2148afaf5a2dSDavid Somayajulu } else { 2149afaf5a2dSDavid Somayajulu if (ha->retry_reset_ha_cnt > 0) { 2150afaf5a2dSDavid Somayajulu /* Schedule another Reset HA--DPC will retry */ 2151afaf5a2dSDavid Somayajulu ha->retry_reset_ha_cnt--; 2152afaf5a2dSDavid Somayajulu DEBUG2(printk("scsi%ld: recover adapter - " 2153afaf5a2dSDavid Somayajulu "retry remaining %d\n", 2154afaf5a2dSDavid Somayajulu ha->host_no, 2155afaf5a2dSDavid Somayajulu ha->retry_reset_ha_cnt)); 2156afaf5a2dSDavid Somayajulu status = QLA_ERROR; 2157afaf5a2dSDavid Somayajulu } 2158afaf5a2dSDavid Somayajulu 2159afaf5a2dSDavid Somayajulu if (ha->retry_reset_ha_cnt == 0) { 2160afaf5a2dSDavid Somayajulu /* Recover adapter retries have been exhausted. 2161afaf5a2dSDavid Somayajulu * Adapter DEAD */ 2162afaf5a2dSDavid Somayajulu DEBUG2(printk("scsi%ld: recover adapter " 2163afaf5a2dSDavid Somayajulu "failed - board disabled\n", 2164afaf5a2dSDavid Somayajulu ha->host_no)); 2165f4f5df23SVikas Chaudhary qla4xxx_dead_adapter_cleanup(ha); 2166afaf5a2dSDavid Somayajulu clear_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags); 2167afaf5a2dSDavid Somayajulu clear_bit(DPC_RESET_HA, &ha->dpc_flags); 2168f4f5df23SVikas Chaudhary clear_bit(DPC_RESET_HA_FW_CONTEXT, 2169afaf5a2dSDavid Somayajulu &ha->dpc_flags); 2170afaf5a2dSDavid Somayajulu status = QLA_ERROR; 2171afaf5a2dSDavid Somayajulu } 2172afaf5a2dSDavid Somayajulu } 2173afaf5a2dSDavid Somayajulu } else { 2174afaf5a2dSDavid Somayajulu clear_bit(DPC_RESET_HA, &ha->dpc_flags); 2175f4f5df23SVikas Chaudhary clear_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags); 2176afaf5a2dSDavid Somayajulu clear_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags); 2177afaf5a2dSDavid Somayajulu } 2178afaf5a2dSDavid Somayajulu 2179afaf5a2dSDavid Somayajulu ha->adapter_error_count++; 2180afaf5a2dSDavid Somayajulu 2181f4f5df23SVikas Chaudhary if (test_bit(AF_ONLINE, &ha->flags)) 2182f4f5df23SVikas Chaudhary ha->isp_ops->enable_intrs(ha); 2183afaf5a2dSDavid Somayajulu 2184f4f5df23SVikas Chaudhary scsi_unblock_requests(ha->host); 2185f4f5df23SVikas Chaudhary 2186f4f5df23SVikas Chaudhary clear_bit(DPC_RESET_ACTIVE, &ha->dpc_flags); 2187f4f5df23SVikas Chaudhary DEBUG2(printk("scsi%ld: recover adapter: %s\n", ha->host_no, 218825985edcSLucas De Marchi status == QLA_ERROR ? "FAILED" : "SUCCEEDED")); 2189f4f5df23SVikas Chaudhary 2190afaf5a2dSDavid Somayajulu return status; 2191afaf5a2dSDavid Somayajulu } 2192afaf5a2dSDavid Somayajulu 2193b3a271a9SManish Rangankar static void qla4xxx_relogin_devices(struct iscsi_cls_session *cls_session) 2194b3a271a9SManish Rangankar { 2195b3a271a9SManish Rangankar struct iscsi_session *sess; 2196b3a271a9SManish Rangankar struct ddb_entry *ddb_entry; 2197b3a271a9SManish Rangankar struct scsi_qla_host *ha; 2198b3a271a9SManish Rangankar 2199b3a271a9SManish Rangankar sess = cls_session->dd_data; 2200b3a271a9SManish Rangankar ddb_entry = sess->dd_data; 2201b3a271a9SManish Rangankar ha = ddb_entry->ha; 2202b3a271a9SManish Rangankar if (!iscsi_is_session_online(cls_session)) { 2203b3a271a9SManish Rangankar if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) { 2204b3a271a9SManish Rangankar ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ddb[%d]" 2205b3a271a9SManish Rangankar " unblock session\n", ha->host_no, __func__, 2206b3a271a9SManish Rangankar ddb_entry->fw_ddb_index); 2207b3a271a9SManish Rangankar iscsi_unblock_session(ddb_entry->sess); 2208b3a271a9SManish Rangankar } else { 2209b3a271a9SManish Rangankar /* Trigger relogin */ 2210b3a271a9SManish Rangankar iscsi_session_failure(cls_session->dd_data, 2211b3a271a9SManish Rangankar ISCSI_ERR_CONN_FAILED); 2212b3a271a9SManish Rangankar } 2213b3a271a9SManish Rangankar } 2214b3a271a9SManish Rangankar } 2215b3a271a9SManish Rangankar 22162d7924e6SVikas Chaudhary static void qla4xxx_relogin_all_devices(struct scsi_qla_host *ha) 22172d7924e6SVikas Chaudhary { 2218b3a271a9SManish Rangankar iscsi_host_for_each_session(ha->host, qla4xxx_relogin_devices); 22192d7924e6SVikas Chaudhary } 22202d7924e6SVikas Chaudhary 2221f4f5df23SVikas Chaudhary void qla4xxx_wake_dpc(struct scsi_qla_host *ha) 2222f4f5df23SVikas Chaudhary { 22231b46807eSLalit Chandivade if (ha->dpc_thread) 2224f4f5df23SVikas Chaudhary queue_work(ha->dpc_thread, &ha->dpc_work); 2225f4f5df23SVikas Chaudhary } 2226f4f5df23SVikas Chaudhary 2227afaf5a2dSDavid Somayajulu /** 2228afaf5a2dSDavid Somayajulu * qla4xxx_do_dpc - dpc routine 2229afaf5a2dSDavid Somayajulu * @data: in our case pointer to adapter structure 2230afaf5a2dSDavid Somayajulu * 2231afaf5a2dSDavid Somayajulu * This routine is a task that is schedule by the interrupt handler 2232afaf5a2dSDavid Somayajulu * to perform the background processing for interrupts. We put it 2233afaf5a2dSDavid Somayajulu * on a task queue that is consumed whenever the scheduler runs; that's 2234afaf5a2dSDavid Somayajulu * so you can do anything (i.e. put the process to sleep etc). In fact, 2235afaf5a2dSDavid Somayajulu * the mid-level tries to sleep when it reaches the driver threshold 2236afaf5a2dSDavid Somayajulu * "host->can_queue". This can cause a panic if we were in our interrupt code. 2237afaf5a2dSDavid Somayajulu **/ 2238c4028958SDavid Howells static void qla4xxx_do_dpc(struct work_struct *work) 2239afaf5a2dSDavid Somayajulu { 2240c4028958SDavid Howells struct scsi_qla_host *ha = 2241c4028958SDavid Howells container_of(work, struct scsi_qla_host, dpc_work); 2242477ffb9dSDavid C Somayajulu int status = QLA_ERROR; 2243afaf5a2dSDavid Somayajulu 2244f26b9044SDavid C Somayajulu DEBUG2(printk("scsi%ld: %s: DPC handler waking up." 2245f4f5df23SVikas Chaudhary "flags = 0x%08lx, dpc_flags = 0x%08lx\n", 2246f4f5df23SVikas Chaudhary ha->host_no, __func__, ha->flags, ha->dpc_flags)) 2247afaf5a2dSDavid Somayajulu 2248afaf5a2dSDavid Somayajulu /* Initialization not yet finished. Don't do anything yet. */ 2249afaf5a2dSDavid Somayajulu if (!test_bit(AF_INIT_DONE, &ha->flags)) 22501b46807eSLalit Chandivade return; 2251afaf5a2dSDavid Somayajulu 22522232be0dSLalit Chandivade if (test_bit(AF_EEH_BUSY, &ha->flags)) { 22532232be0dSLalit Chandivade DEBUG2(printk(KERN_INFO "scsi%ld: %s: flags = %lx\n", 22542232be0dSLalit Chandivade ha->host_no, __func__, ha->flags)); 22551b46807eSLalit Chandivade return; 22562232be0dSLalit Chandivade } 22572232be0dSLalit Chandivade 2258f4f5df23SVikas Chaudhary if (is_qla8022(ha)) { 2259f4f5df23SVikas Chaudhary if (test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags)) { 2260f4f5df23SVikas Chaudhary qla4_8xxx_idc_lock(ha); 2261f4f5df23SVikas Chaudhary qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, 2262f4f5df23SVikas Chaudhary QLA82XX_DEV_FAILED); 2263f4f5df23SVikas Chaudhary qla4_8xxx_idc_unlock(ha); 2264f4f5df23SVikas Chaudhary ql4_printk(KERN_INFO, ha, "HW State: FAILED\n"); 2265f4f5df23SVikas Chaudhary qla4_8xxx_device_state_handler(ha); 2266f4f5df23SVikas Chaudhary } 2267f4f5df23SVikas Chaudhary if (test_and_clear_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags)) { 2268f4f5df23SVikas Chaudhary qla4_8xxx_need_qsnt_handler(ha); 2269f4f5df23SVikas Chaudhary } 2270f4f5df23SVikas Chaudhary } 2271f4f5df23SVikas Chaudhary 2272f4f5df23SVikas Chaudhary if (!test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags) && 2273f4f5df23SVikas Chaudhary (test_bit(DPC_RESET_HA, &ha->dpc_flags) || 2274afaf5a2dSDavid Somayajulu test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) || 2275f4f5df23SVikas Chaudhary test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags))) { 2276f4f5df23SVikas Chaudhary if (ql4xdontresethba) { 2277f4f5df23SVikas Chaudhary DEBUG2(printk("scsi%ld: %s: Don't Reset HBA\n", 2278f4f5df23SVikas Chaudhary ha->host_no, __func__)); 2279f4f5df23SVikas Chaudhary clear_bit(DPC_RESET_HA, &ha->dpc_flags); 2280f4f5df23SVikas Chaudhary clear_bit(DPC_RESET_HA_INTR, &ha->dpc_flags); 2281f4f5df23SVikas Chaudhary clear_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags); 2282f4f5df23SVikas Chaudhary goto dpc_post_reset_ha; 2283f4f5df23SVikas Chaudhary } 2284f4f5df23SVikas Chaudhary if (test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags) || 2285f26b9044SDavid C Somayajulu test_bit(DPC_RESET_HA, &ha->dpc_flags)) 2286f4f5df23SVikas Chaudhary qla4xxx_recover_adapter(ha); 2287afaf5a2dSDavid Somayajulu 2288477ffb9dSDavid C Somayajulu if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) { 2289afaf5a2dSDavid Somayajulu uint8_t wait_time = RESET_INTR_TOV; 2290afaf5a2dSDavid Somayajulu 2291afaf5a2dSDavid Somayajulu while ((readw(&ha->reg->ctrl_status) & 2292afaf5a2dSDavid Somayajulu (CSR_SOFT_RESET | CSR_FORCE_SOFT_RESET)) != 0) { 2293afaf5a2dSDavid Somayajulu if (--wait_time == 0) 2294afaf5a2dSDavid Somayajulu break; 2295afaf5a2dSDavid Somayajulu msleep(1000); 2296afaf5a2dSDavid Somayajulu } 2297afaf5a2dSDavid Somayajulu if (wait_time == 0) 2298afaf5a2dSDavid Somayajulu DEBUG2(printk("scsi%ld: %s: SR|FSR " 2299afaf5a2dSDavid Somayajulu "bit not cleared-- resetting\n", 2300afaf5a2dSDavid Somayajulu ha->host_no, __func__)); 2301f4f5df23SVikas Chaudhary qla4xxx_abort_active_cmds(ha, DID_RESET << 16); 2302477ffb9dSDavid C Somayajulu if (ql4xxx_lock_drvr_wait(ha) == QLA_SUCCESS) { 2303477ffb9dSDavid C Somayajulu qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); 2304f4f5df23SVikas Chaudhary status = qla4xxx_recover_adapter(ha); 2305477ffb9dSDavid C Somayajulu } 2306477ffb9dSDavid C Somayajulu clear_bit(DPC_RESET_HA_INTR, &ha->dpc_flags); 2307477ffb9dSDavid C Somayajulu if (status == QLA_SUCCESS) 2308f4f5df23SVikas Chaudhary ha->isp_ops->enable_intrs(ha); 2309afaf5a2dSDavid Somayajulu } 2310afaf5a2dSDavid Somayajulu } 2311afaf5a2dSDavid Somayajulu 2312f4f5df23SVikas Chaudhary dpc_post_reset_ha: 2313afaf5a2dSDavid Somayajulu /* ---- process AEN? --- */ 2314afaf5a2dSDavid Somayajulu if (test_and_clear_bit(DPC_AEN, &ha->dpc_flags)) 2315afaf5a2dSDavid Somayajulu qla4xxx_process_aen(ha, PROCESS_ALL_AENS); 2316afaf5a2dSDavid Somayajulu 2317afaf5a2dSDavid Somayajulu /* ---- Get DHCP IP Address? --- */ 2318afaf5a2dSDavid Somayajulu if (test_and_clear_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags)) 2319afaf5a2dSDavid Somayajulu qla4xxx_get_dhcp_ip_address(ha); 2320afaf5a2dSDavid Somayajulu 2321065aa1b4SVikas Chaudhary /* ---- link change? --- */ 2322065aa1b4SVikas Chaudhary if (test_and_clear_bit(DPC_LINK_CHANGED, &ha->dpc_flags)) { 2323065aa1b4SVikas Chaudhary if (!test_bit(AF_LINK_UP, &ha->flags)) { 2324065aa1b4SVikas Chaudhary /* ---- link down? --- */ 23252d7924e6SVikas Chaudhary qla4xxx_mark_all_devices_missing(ha); 2326065aa1b4SVikas Chaudhary } else { 2327065aa1b4SVikas Chaudhary /* ---- link up? --- * 2328065aa1b4SVikas Chaudhary * F/W will auto login to all devices ONLY ONCE after 2329065aa1b4SVikas Chaudhary * link up during driver initialization and runtime 2330065aa1b4SVikas Chaudhary * fatal error recovery. Therefore, the driver must 2331065aa1b4SVikas Chaudhary * manually relogin to devices when recovering from 2332065aa1b4SVikas Chaudhary * connection failures, logouts, expired KATO, etc. */ 2333065aa1b4SVikas Chaudhary 23342d7924e6SVikas Chaudhary qla4xxx_relogin_all_devices(ha); 2335065aa1b4SVikas Chaudhary } 2336065aa1b4SVikas Chaudhary } 2337afaf5a2dSDavid Somayajulu } 2338afaf5a2dSDavid Somayajulu 2339afaf5a2dSDavid Somayajulu /** 2340afaf5a2dSDavid Somayajulu * qla4xxx_free_adapter - release the adapter 2341afaf5a2dSDavid Somayajulu * @ha: pointer to adapter structure 2342afaf5a2dSDavid Somayajulu **/ 2343afaf5a2dSDavid Somayajulu static void qla4xxx_free_adapter(struct scsi_qla_host *ha) 2344afaf5a2dSDavid Somayajulu { 2345afaf5a2dSDavid Somayajulu 2346afaf5a2dSDavid Somayajulu if (test_bit(AF_INTERRUPTS_ON, &ha->flags)) { 2347afaf5a2dSDavid Somayajulu /* Turn-off interrupts on the card. */ 2348f4f5df23SVikas Chaudhary ha->isp_ops->disable_intrs(ha); 2349afaf5a2dSDavid Somayajulu } 2350afaf5a2dSDavid Somayajulu 2351afaf5a2dSDavid Somayajulu /* Remove timer thread, if present */ 2352afaf5a2dSDavid Somayajulu if (ha->timer_active) 2353afaf5a2dSDavid Somayajulu qla4xxx_stop_timer(ha); 2354afaf5a2dSDavid Somayajulu 2355f4f5df23SVikas Chaudhary /* Kill the kernel thread for this host */ 2356f4f5df23SVikas Chaudhary if (ha->dpc_thread) 2357f4f5df23SVikas Chaudhary destroy_workqueue(ha->dpc_thread); 2358f4f5df23SVikas Chaudhary 2359b3a271a9SManish Rangankar /* Kill the kernel thread for this host */ 2360b3a271a9SManish Rangankar if (ha->task_wq) 2361b3a271a9SManish Rangankar destroy_workqueue(ha->task_wq); 2362b3a271a9SManish Rangankar 2363f4f5df23SVikas Chaudhary /* Put firmware in known state */ 2364f4f5df23SVikas Chaudhary ha->isp_ops->reset_firmware(ha); 2365f4f5df23SVikas Chaudhary 2366f4f5df23SVikas Chaudhary if (is_qla8022(ha)) { 2367f4f5df23SVikas Chaudhary qla4_8xxx_idc_lock(ha); 2368f4f5df23SVikas Chaudhary qla4_8xxx_clear_drv_active(ha); 2369f4f5df23SVikas Chaudhary qla4_8xxx_idc_unlock(ha); 2370f4f5df23SVikas Chaudhary } 2371f4f5df23SVikas Chaudhary 2372afaf5a2dSDavid Somayajulu /* Detach interrupts */ 2373afaf5a2dSDavid Somayajulu if (test_and_clear_bit(AF_IRQ_ATTACHED, &ha->flags)) 2374f4f5df23SVikas Chaudhary qla4xxx_free_irqs(ha); 2375afaf5a2dSDavid Somayajulu 2376bee4fe8eSDavid C Somayajulu /* free extra memory */ 2377bee4fe8eSDavid C Somayajulu qla4xxx_mem_free(ha); 2378f4f5df23SVikas Chaudhary } 2379bee4fe8eSDavid C Somayajulu 2380f4f5df23SVikas Chaudhary int qla4_8xxx_iospace_config(struct scsi_qla_host *ha) 2381f4f5df23SVikas Chaudhary { 2382f4f5df23SVikas Chaudhary int status = 0; 2383f4f5df23SVikas Chaudhary uint8_t revision_id; 2384f4f5df23SVikas Chaudhary unsigned long mem_base, mem_len, db_base, db_len; 2385f4f5df23SVikas Chaudhary struct pci_dev *pdev = ha->pdev; 2386afaf5a2dSDavid Somayajulu 2387f4f5df23SVikas Chaudhary status = pci_request_regions(pdev, DRIVER_NAME); 2388f4f5df23SVikas Chaudhary if (status) { 2389f4f5df23SVikas Chaudhary printk(KERN_WARNING 2390f4f5df23SVikas Chaudhary "scsi(%ld) Failed to reserve PIO regions (%s) " 2391f4f5df23SVikas Chaudhary "status=%d\n", ha->host_no, pci_name(pdev), status); 2392f4f5df23SVikas Chaudhary goto iospace_error_exit; 2393f4f5df23SVikas Chaudhary } 2394f4f5df23SVikas Chaudhary 2395f4f5df23SVikas Chaudhary pci_read_config_byte(pdev, PCI_REVISION_ID, &revision_id); 2396f4f5df23SVikas Chaudhary DEBUG2(printk(KERN_INFO "%s: revision-id=%d\n", 2397f4f5df23SVikas Chaudhary __func__, revision_id)); 2398f4f5df23SVikas Chaudhary ha->revision_id = revision_id; 2399f4f5df23SVikas Chaudhary 2400f4f5df23SVikas Chaudhary /* remap phys address */ 2401f4f5df23SVikas Chaudhary mem_base = pci_resource_start(pdev, 0); /* 0 is for BAR 0 */ 2402f4f5df23SVikas Chaudhary mem_len = pci_resource_len(pdev, 0); 2403f4f5df23SVikas Chaudhary DEBUG2(printk(KERN_INFO "%s: ioremap from %lx a size of %lx\n", 2404f4f5df23SVikas Chaudhary __func__, mem_base, mem_len)); 2405f4f5df23SVikas Chaudhary 2406f4f5df23SVikas Chaudhary /* mapping of pcibase pointer */ 2407f4f5df23SVikas Chaudhary ha->nx_pcibase = (unsigned long)ioremap(mem_base, mem_len); 2408f4f5df23SVikas Chaudhary if (!ha->nx_pcibase) { 2409f4f5df23SVikas Chaudhary printk(KERN_ERR 2410f4f5df23SVikas Chaudhary "cannot remap MMIO (%s), aborting\n", pci_name(pdev)); 2411f4f5df23SVikas Chaudhary pci_release_regions(ha->pdev); 2412f4f5df23SVikas Chaudhary goto iospace_error_exit; 2413f4f5df23SVikas Chaudhary } 2414f4f5df23SVikas Chaudhary 2415f4f5df23SVikas Chaudhary /* Mapping of IO base pointer, door bell read and write pointer */ 2416f4f5df23SVikas Chaudhary 2417f4f5df23SVikas Chaudhary /* mapping of IO base pointer */ 2418f4f5df23SVikas Chaudhary ha->qla4_8xxx_reg = 2419f4f5df23SVikas Chaudhary (struct device_reg_82xx __iomem *)((uint8_t *)ha->nx_pcibase + 2420f4f5df23SVikas Chaudhary 0xbc000 + (ha->pdev->devfn << 11)); 2421f4f5df23SVikas Chaudhary 2422f4f5df23SVikas Chaudhary db_base = pci_resource_start(pdev, 4); /* doorbell is on bar 4 */ 2423f4f5df23SVikas Chaudhary db_len = pci_resource_len(pdev, 4); 2424f4f5df23SVikas Chaudhary 24252657c800SShyam Sundar ha->nx_db_wr_ptr = (ha->pdev->devfn == 4 ? QLA82XX_CAM_RAM_DB1 : 24262657c800SShyam Sundar QLA82XX_CAM_RAM_DB2); 2427f4f5df23SVikas Chaudhary 24282657c800SShyam Sundar return 0; 2429f4f5df23SVikas Chaudhary iospace_error_exit: 2430f4f5df23SVikas Chaudhary return -ENOMEM; 2431afaf5a2dSDavid Somayajulu } 2432afaf5a2dSDavid Somayajulu 2433afaf5a2dSDavid Somayajulu /*** 2434afaf5a2dSDavid Somayajulu * qla4xxx_iospace_config - maps registers 2435afaf5a2dSDavid Somayajulu * @ha: pointer to adapter structure 2436afaf5a2dSDavid Somayajulu * 2437afaf5a2dSDavid Somayajulu * This routines maps HBA's registers from the pci address space 2438afaf5a2dSDavid Somayajulu * into the kernel virtual address space for memory mapped i/o. 2439afaf5a2dSDavid Somayajulu **/ 2440f4f5df23SVikas Chaudhary int qla4xxx_iospace_config(struct scsi_qla_host *ha) 2441afaf5a2dSDavid Somayajulu { 2442afaf5a2dSDavid Somayajulu unsigned long pio, pio_len, pio_flags; 2443afaf5a2dSDavid Somayajulu unsigned long mmio, mmio_len, mmio_flags; 2444afaf5a2dSDavid Somayajulu 2445afaf5a2dSDavid Somayajulu pio = pci_resource_start(ha->pdev, 0); 2446afaf5a2dSDavid Somayajulu pio_len = pci_resource_len(ha->pdev, 0); 2447afaf5a2dSDavid Somayajulu pio_flags = pci_resource_flags(ha->pdev, 0); 2448afaf5a2dSDavid Somayajulu if (pio_flags & IORESOURCE_IO) { 2449afaf5a2dSDavid Somayajulu if (pio_len < MIN_IOBASE_LEN) { 2450c2660df3SVikas Chaudhary ql4_printk(KERN_WARNING, ha, 2451afaf5a2dSDavid Somayajulu "Invalid PCI I/O region size\n"); 2452afaf5a2dSDavid Somayajulu pio = 0; 2453afaf5a2dSDavid Somayajulu } 2454afaf5a2dSDavid Somayajulu } else { 2455c2660df3SVikas Chaudhary ql4_printk(KERN_WARNING, ha, "region #0 not a PIO resource\n"); 2456afaf5a2dSDavid Somayajulu pio = 0; 2457afaf5a2dSDavid Somayajulu } 2458afaf5a2dSDavid Somayajulu 2459afaf5a2dSDavid Somayajulu /* Use MMIO operations for all accesses. */ 2460afaf5a2dSDavid Somayajulu mmio = pci_resource_start(ha->pdev, 1); 2461afaf5a2dSDavid Somayajulu mmio_len = pci_resource_len(ha->pdev, 1); 2462afaf5a2dSDavid Somayajulu mmio_flags = pci_resource_flags(ha->pdev, 1); 2463afaf5a2dSDavid Somayajulu 2464afaf5a2dSDavid Somayajulu if (!(mmio_flags & IORESOURCE_MEM)) { 2465c2660df3SVikas Chaudhary ql4_printk(KERN_ERR, ha, 2466afaf5a2dSDavid Somayajulu "region #0 not an MMIO resource, aborting\n"); 2467afaf5a2dSDavid Somayajulu 2468afaf5a2dSDavid Somayajulu goto iospace_error_exit; 2469afaf5a2dSDavid Somayajulu } 2470c2660df3SVikas Chaudhary 2471afaf5a2dSDavid Somayajulu if (mmio_len < MIN_IOBASE_LEN) { 2472c2660df3SVikas Chaudhary ql4_printk(KERN_ERR, ha, 2473afaf5a2dSDavid Somayajulu "Invalid PCI mem region size, aborting\n"); 2474afaf5a2dSDavid Somayajulu goto iospace_error_exit; 2475afaf5a2dSDavid Somayajulu } 2476afaf5a2dSDavid Somayajulu 2477afaf5a2dSDavid Somayajulu if (pci_request_regions(ha->pdev, DRIVER_NAME)) { 2478c2660df3SVikas Chaudhary ql4_printk(KERN_WARNING, ha, 2479afaf5a2dSDavid Somayajulu "Failed to reserve PIO/MMIO regions\n"); 2480afaf5a2dSDavid Somayajulu 2481afaf5a2dSDavid Somayajulu goto iospace_error_exit; 2482afaf5a2dSDavid Somayajulu } 2483afaf5a2dSDavid Somayajulu 2484afaf5a2dSDavid Somayajulu ha->pio_address = pio; 2485afaf5a2dSDavid Somayajulu ha->pio_length = pio_len; 2486afaf5a2dSDavid Somayajulu ha->reg = ioremap(mmio, MIN_IOBASE_LEN); 2487afaf5a2dSDavid Somayajulu if (!ha->reg) { 2488c2660df3SVikas Chaudhary ql4_printk(KERN_ERR, ha, 2489afaf5a2dSDavid Somayajulu "cannot remap MMIO, aborting\n"); 2490afaf5a2dSDavid Somayajulu 2491afaf5a2dSDavid Somayajulu goto iospace_error_exit; 2492afaf5a2dSDavid Somayajulu } 2493afaf5a2dSDavid Somayajulu 2494afaf5a2dSDavid Somayajulu return 0; 2495afaf5a2dSDavid Somayajulu 2496afaf5a2dSDavid Somayajulu iospace_error_exit: 2497afaf5a2dSDavid Somayajulu return -ENOMEM; 2498afaf5a2dSDavid Somayajulu } 2499afaf5a2dSDavid Somayajulu 2500f4f5df23SVikas Chaudhary static struct isp_operations qla4xxx_isp_ops = { 2501f4f5df23SVikas Chaudhary .iospace_config = qla4xxx_iospace_config, 2502f4f5df23SVikas Chaudhary .pci_config = qla4xxx_pci_config, 2503f4f5df23SVikas Chaudhary .disable_intrs = qla4xxx_disable_intrs, 2504f4f5df23SVikas Chaudhary .enable_intrs = qla4xxx_enable_intrs, 2505f4f5df23SVikas Chaudhary .start_firmware = qla4xxx_start_firmware, 2506f4f5df23SVikas Chaudhary .intr_handler = qla4xxx_intr_handler, 2507f4f5df23SVikas Chaudhary .interrupt_service_routine = qla4xxx_interrupt_service_routine, 2508f4f5df23SVikas Chaudhary .reset_chip = qla4xxx_soft_reset, 2509f4f5df23SVikas Chaudhary .reset_firmware = qla4xxx_hw_reset, 2510f4f5df23SVikas Chaudhary .queue_iocb = qla4xxx_queue_iocb, 2511f4f5df23SVikas Chaudhary .complete_iocb = qla4xxx_complete_iocb, 2512f4f5df23SVikas Chaudhary .rd_shdw_req_q_out = qla4xxx_rd_shdw_req_q_out, 2513f4f5df23SVikas Chaudhary .rd_shdw_rsp_q_in = qla4xxx_rd_shdw_rsp_q_in, 2514f4f5df23SVikas Chaudhary .get_sys_info = qla4xxx_get_sys_info, 2515f4f5df23SVikas Chaudhary }; 2516f4f5df23SVikas Chaudhary 2517f4f5df23SVikas Chaudhary static struct isp_operations qla4_8xxx_isp_ops = { 2518f4f5df23SVikas Chaudhary .iospace_config = qla4_8xxx_iospace_config, 2519f4f5df23SVikas Chaudhary .pci_config = qla4_8xxx_pci_config, 2520f4f5df23SVikas Chaudhary .disable_intrs = qla4_8xxx_disable_intrs, 2521f4f5df23SVikas Chaudhary .enable_intrs = qla4_8xxx_enable_intrs, 2522f4f5df23SVikas Chaudhary .start_firmware = qla4_8xxx_load_risc, 2523f4f5df23SVikas Chaudhary .intr_handler = qla4_8xxx_intr_handler, 2524f4f5df23SVikas Chaudhary .interrupt_service_routine = qla4_8xxx_interrupt_service_routine, 2525f4f5df23SVikas Chaudhary .reset_chip = qla4_8xxx_isp_reset, 2526f4f5df23SVikas Chaudhary .reset_firmware = qla4_8xxx_stop_firmware, 2527f4f5df23SVikas Chaudhary .queue_iocb = qla4_8xxx_queue_iocb, 2528f4f5df23SVikas Chaudhary .complete_iocb = qla4_8xxx_complete_iocb, 2529f4f5df23SVikas Chaudhary .rd_shdw_req_q_out = qla4_8xxx_rd_shdw_req_q_out, 2530f4f5df23SVikas Chaudhary .rd_shdw_rsp_q_in = qla4_8xxx_rd_shdw_rsp_q_in, 2531f4f5df23SVikas Chaudhary .get_sys_info = qla4_8xxx_get_sys_info, 2532f4f5df23SVikas Chaudhary }; 2533f4f5df23SVikas Chaudhary 2534f4f5df23SVikas Chaudhary uint16_t qla4xxx_rd_shdw_req_q_out(struct scsi_qla_host *ha) 2535f4f5df23SVikas Chaudhary { 2536f4f5df23SVikas Chaudhary return (uint16_t)le32_to_cpu(ha->shadow_regs->req_q_out); 2537f4f5df23SVikas Chaudhary } 2538f4f5df23SVikas Chaudhary 2539f4f5df23SVikas Chaudhary uint16_t qla4_8xxx_rd_shdw_req_q_out(struct scsi_qla_host *ha) 2540f4f5df23SVikas Chaudhary { 2541f4f5df23SVikas Chaudhary return (uint16_t)le32_to_cpu(readl(&ha->qla4_8xxx_reg->req_q_out)); 2542f4f5df23SVikas Chaudhary } 2543f4f5df23SVikas Chaudhary 2544f4f5df23SVikas Chaudhary uint16_t qla4xxx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha) 2545f4f5df23SVikas Chaudhary { 2546f4f5df23SVikas Chaudhary return (uint16_t)le32_to_cpu(ha->shadow_regs->rsp_q_in); 2547f4f5df23SVikas Chaudhary } 2548f4f5df23SVikas Chaudhary 2549f4f5df23SVikas Chaudhary uint16_t qla4_8xxx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha) 2550f4f5df23SVikas Chaudhary { 2551f4f5df23SVikas Chaudhary return (uint16_t)le32_to_cpu(readl(&ha->qla4_8xxx_reg->rsp_q_in)); 2552f4f5df23SVikas Chaudhary } 2553f4f5df23SVikas Chaudhary 2554afaf5a2dSDavid Somayajulu /** 2555afaf5a2dSDavid Somayajulu * qla4xxx_probe_adapter - callback function to probe HBA 2556afaf5a2dSDavid Somayajulu * @pdev: pointer to pci_dev structure 2557afaf5a2dSDavid Somayajulu * @pci_device_id: pointer to pci_device entry 2558afaf5a2dSDavid Somayajulu * 2559afaf5a2dSDavid Somayajulu * This routine will probe for Qlogic 4xxx iSCSI host adapters. 2560afaf5a2dSDavid Somayajulu * It returns zero if successful. It also initializes all data necessary for 2561afaf5a2dSDavid Somayajulu * the driver. 2562afaf5a2dSDavid Somayajulu **/ 2563afaf5a2dSDavid Somayajulu static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, 2564afaf5a2dSDavid Somayajulu const struct pci_device_id *ent) 2565afaf5a2dSDavid Somayajulu { 2566afaf5a2dSDavid Somayajulu int ret = -ENODEV, status; 2567afaf5a2dSDavid Somayajulu struct Scsi_Host *host; 2568afaf5a2dSDavid Somayajulu struct scsi_qla_host *ha; 2569afaf5a2dSDavid Somayajulu uint8_t init_retry_count = 0; 2570afaf5a2dSDavid Somayajulu char buf[34]; 2571f4f5df23SVikas Chaudhary struct qla4_8xxx_legacy_intr_set *nx_legacy_intr; 2572f9880e76SPrasanna Mumbai uint32_t dev_state; 2573afaf5a2dSDavid Somayajulu 2574afaf5a2dSDavid Somayajulu if (pci_enable_device(pdev)) 2575afaf5a2dSDavid Somayajulu return -1; 2576afaf5a2dSDavid Somayajulu 2577b3a271a9SManish Rangankar host = iscsi_host_alloc(&qla4xxx_driver_template, sizeof(*ha), 0); 2578afaf5a2dSDavid Somayajulu if (host == NULL) { 2579afaf5a2dSDavid Somayajulu printk(KERN_WARNING 2580afaf5a2dSDavid Somayajulu "qla4xxx: Couldn't allocate host from scsi layer!\n"); 2581afaf5a2dSDavid Somayajulu goto probe_disable_device; 2582afaf5a2dSDavid Somayajulu } 2583afaf5a2dSDavid Somayajulu 2584afaf5a2dSDavid Somayajulu /* Clear our data area */ 2585b3a271a9SManish Rangankar ha = to_qla_host(host); 2586afaf5a2dSDavid Somayajulu memset(ha, 0, sizeof(*ha)); 2587afaf5a2dSDavid Somayajulu 2588afaf5a2dSDavid Somayajulu /* Save the information from PCI BIOS. */ 2589afaf5a2dSDavid Somayajulu ha->pdev = pdev; 2590afaf5a2dSDavid Somayajulu ha->host = host; 2591afaf5a2dSDavid Somayajulu ha->host_no = host->host_no; 2592afaf5a2dSDavid Somayajulu 25932232be0dSLalit Chandivade pci_enable_pcie_error_reporting(pdev); 25942232be0dSLalit Chandivade 2595f4f5df23SVikas Chaudhary /* Setup Runtime configurable options */ 2596f4f5df23SVikas Chaudhary if (is_qla8022(ha)) { 2597f4f5df23SVikas Chaudhary ha->isp_ops = &qla4_8xxx_isp_ops; 2598f4f5df23SVikas Chaudhary rwlock_init(&ha->hw_lock); 2599f4f5df23SVikas Chaudhary ha->qdr_sn_window = -1; 2600f4f5df23SVikas Chaudhary ha->ddr_mn_window = -1; 2601f4f5df23SVikas Chaudhary ha->curr_window = 255; 2602f4f5df23SVikas Chaudhary ha->func_num = PCI_FUNC(ha->pdev->devfn); 2603f4f5df23SVikas Chaudhary nx_legacy_intr = &legacy_intr[ha->func_num]; 2604f4f5df23SVikas Chaudhary ha->nx_legacy_intr.int_vec_bit = nx_legacy_intr->int_vec_bit; 2605f4f5df23SVikas Chaudhary ha->nx_legacy_intr.tgt_status_reg = 2606f4f5df23SVikas Chaudhary nx_legacy_intr->tgt_status_reg; 2607f4f5df23SVikas Chaudhary ha->nx_legacy_intr.tgt_mask_reg = nx_legacy_intr->tgt_mask_reg; 2608f4f5df23SVikas Chaudhary ha->nx_legacy_intr.pci_int_reg = nx_legacy_intr->pci_int_reg; 2609f4f5df23SVikas Chaudhary } else { 2610f4f5df23SVikas Chaudhary ha->isp_ops = &qla4xxx_isp_ops; 2611f4f5df23SVikas Chaudhary } 2612f4f5df23SVikas Chaudhary 26132232be0dSLalit Chandivade /* Set EEH reset type to fundamental if required by hba */ 26142232be0dSLalit Chandivade if (is_qla8022(ha)) 26152232be0dSLalit Chandivade pdev->needs_freset = 1; 26162232be0dSLalit Chandivade 2617afaf5a2dSDavid Somayajulu /* Configure PCI I/O space. */ 2618f4f5df23SVikas Chaudhary ret = ha->isp_ops->iospace_config(ha); 2619afaf5a2dSDavid Somayajulu if (ret) 2620f4f5df23SVikas Chaudhary goto probe_failed_ioconfig; 2621afaf5a2dSDavid Somayajulu 2622c2660df3SVikas Chaudhary ql4_printk(KERN_INFO, ha, "Found an ISP%04x, irq %d, iobase 0x%p\n", 2623afaf5a2dSDavid Somayajulu pdev->device, pdev->irq, ha->reg); 2624afaf5a2dSDavid Somayajulu 2625afaf5a2dSDavid Somayajulu qla4xxx_config_dma_addressing(ha); 2626afaf5a2dSDavid Somayajulu 2627afaf5a2dSDavid Somayajulu /* Initialize lists and spinlocks. */ 2628afaf5a2dSDavid Somayajulu INIT_LIST_HEAD(&ha->free_srb_q); 2629afaf5a2dSDavid Somayajulu 2630afaf5a2dSDavid Somayajulu mutex_init(&ha->mbox_sem); 2631f4f5df23SVikas Chaudhary init_completion(&ha->mbx_intr_comp); 2632afaf5a2dSDavid Somayajulu 2633afaf5a2dSDavid Somayajulu spin_lock_init(&ha->hardware_lock); 2634afaf5a2dSDavid Somayajulu 2635afaf5a2dSDavid Somayajulu /* Allocate dma buffers */ 2636afaf5a2dSDavid Somayajulu if (qla4xxx_mem_alloc(ha)) { 2637c2660df3SVikas Chaudhary ql4_printk(KERN_WARNING, ha, 2638afaf5a2dSDavid Somayajulu "[ERROR] Failed to allocate memory for adapter\n"); 2639afaf5a2dSDavid Somayajulu 2640afaf5a2dSDavid Somayajulu ret = -ENOMEM; 2641afaf5a2dSDavid Somayajulu goto probe_failed; 2642afaf5a2dSDavid Somayajulu } 2643afaf5a2dSDavid Somayajulu 2644b3a271a9SManish Rangankar host->cmd_per_lun = 3; 2645b3a271a9SManish Rangankar host->max_channel = 0; 2646b3a271a9SManish Rangankar host->max_lun = MAX_LUNS - 1; 2647b3a271a9SManish Rangankar host->max_id = MAX_TARGETS; 2648b3a271a9SManish Rangankar host->max_cmd_len = IOCB_MAX_CDB_LEN; 2649b3a271a9SManish Rangankar host->can_queue = MAX_SRBS ; 2650b3a271a9SManish Rangankar host->transportt = qla4xxx_scsi_transport; 2651b3a271a9SManish Rangankar 2652b3a271a9SManish Rangankar ret = scsi_init_shared_tag_map(host, MAX_SRBS); 2653b3a271a9SManish Rangankar if (ret) { 2654b3a271a9SManish Rangankar ql4_printk(KERN_WARNING, ha, 2655b3a271a9SManish Rangankar "%s: scsi_init_shared_tag_map failed\n", __func__); 2656b3a271a9SManish Rangankar goto probe_failed; 2657b3a271a9SManish Rangankar } 2658b3a271a9SManish Rangankar 2659b3a271a9SManish Rangankar pci_set_drvdata(pdev, ha); 2660b3a271a9SManish Rangankar 2661b3a271a9SManish Rangankar ret = scsi_add_host(host, &pdev->dev); 2662b3a271a9SManish Rangankar if (ret) 2663b3a271a9SManish Rangankar goto probe_failed; 2664b3a271a9SManish Rangankar 2665f4f5df23SVikas Chaudhary if (is_qla8022(ha)) 2666f4f5df23SVikas Chaudhary (void) qla4_8xxx_get_flash_info(ha); 2667f4f5df23SVikas Chaudhary 2668afaf5a2dSDavid Somayajulu /* 2669afaf5a2dSDavid Somayajulu * Initialize the Host adapter request/response queues and 2670afaf5a2dSDavid Somayajulu * firmware 2671afaf5a2dSDavid Somayajulu * NOTE: interrupts enabled upon successful completion 2672afaf5a2dSDavid Somayajulu */ 26730e7e8501SManish Rangankar status = qla4xxx_initialize_adapter(ha); 2674f4f5df23SVikas Chaudhary while ((!test_bit(AF_ONLINE, &ha->flags)) && 2675f4f5df23SVikas Chaudhary init_retry_count++ < MAX_INIT_RETRIES) { 2676f9880e76SPrasanna Mumbai 2677f9880e76SPrasanna Mumbai if (is_qla8022(ha)) { 2678f9880e76SPrasanna Mumbai qla4_8xxx_idc_lock(ha); 2679f9880e76SPrasanna Mumbai dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE); 2680f9880e76SPrasanna Mumbai qla4_8xxx_idc_unlock(ha); 2681f9880e76SPrasanna Mumbai if (dev_state == QLA82XX_DEV_FAILED) { 2682f9880e76SPrasanna Mumbai ql4_printk(KERN_WARNING, ha, "%s: don't retry " 2683f9880e76SPrasanna Mumbai "initialize adapter. H/W is in failed state\n", 2684f9880e76SPrasanna Mumbai __func__); 2685f9880e76SPrasanna Mumbai break; 2686f9880e76SPrasanna Mumbai } 2687f9880e76SPrasanna Mumbai } 2688afaf5a2dSDavid Somayajulu DEBUG2(printk("scsi: %s: retrying adapter initialization " 2689afaf5a2dSDavid Somayajulu "(%d)\n", __func__, init_retry_count)); 2690f4f5df23SVikas Chaudhary 2691f4f5df23SVikas Chaudhary if (ha->isp_ops->reset_chip(ha) == QLA_ERROR) 2692f4f5df23SVikas Chaudhary continue; 2693f4f5df23SVikas Chaudhary 26940e7e8501SManish Rangankar status = qla4xxx_initialize_adapter(ha); 2695afaf5a2dSDavid Somayajulu } 2696f4f5df23SVikas Chaudhary 2697f4f5df23SVikas Chaudhary if (!test_bit(AF_ONLINE, &ha->flags)) { 2698c2660df3SVikas Chaudhary ql4_printk(KERN_WARNING, ha, "Failed to initialize adapter\n"); 2699afaf5a2dSDavid Somayajulu 2700fe998527SLalit Chandivade if (is_qla8022(ha) && ql4xdontresethba) { 2701fe998527SLalit Chandivade /* Put the device in failed state. */ 2702fe998527SLalit Chandivade DEBUG2(printk(KERN_ERR "HW STATE: FAILED\n")); 2703fe998527SLalit Chandivade qla4_8xxx_idc_lock(ha); 2704fe998527SLalit Chandivade qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, 2705fe998527SLalit Chandivade QLA82XX_DEV_FAILED); 2706fe998527SLalit Chandivade qla4_8xxx_idc_unlock(ha); 2707fe998527SLalit Chandivade } 2708afaf5a2dSDavid Somayajulu ret = -ENODEV; 2709b3a271a9SManish Rangankar goto remove_host; 2710afaf5a2dSDavid Somayajulu } 2711afaf5a2dSDavid Somayajulu 2712afaf5a2dSDavid Somayajulu /* Startup the kernel thread for this host adapter. */ 2713afaf5a2dSDavid Somayajulu DEBUG2(printk("scsi: %s: Starting kernel thread for " 2714afaf5a2dSDavid Somayajulu "qla4xxx_dpc\n", __func__)); 2715afaf5a2dSDavid Somayajulu sprintf(buf, "qla4xxx_%lu_dpc", ha->host_no); 2716afaf5a2dSDavid Somayajulu ha->dpc_thread = create_singlethread_workqueue(buf); 2717afaf5a2dSDavid Somayajulu if (!ha->dpc_thread) { 2718c2660df3SVikas Chaudhary ql4_printk(KERN_WARNING, ha, "Unable to start DPC thread!\n"); 2719afaf5a2dSDavid Somayajulu ret = -ENODEV; 2720b3a271a9SManish Rangankar goto remove_host; 2721afaf5a2dSDavid Somayajulu } 2722c4028958SDavid Howells INIT_WORK(&ha->dpc_work, qla4xxx_do_dpc); 2723afaf5a2dSDavid Somayajulu 2724b3a271a9SManish Rangankar sprintf(buf, "qla4xxx_%lu_task", ha->host_no); 2725b3a271a9SManish Rangankar ha->task_wq = alloc_workqueue(buf, WQ_MEM_RECLAIM, 1); 2726b3a271a9SManish Rangankar if (!ha->task_wq) { 2727b3a271a9SManish Rangankar ql4_printk(KERN_WARNING, ha, "Unable to start task thread!\n"); 2728b3a271a9SManish Rangankar ret = -ENODEV; 2729b3a271a9SManish Rangankar goto remove_host; 2730b3a271a9SManish Rangankar } 2731b3a271a9SManish Rangankar 2732f4f5df23SVikas Chaudhary /* For ISP-82XX, request_irqs is called in qla4_8xxx_load_risc 2733f4f5df23SVikas Chaudhary * (which is called indirectly by qla4xxx_initialize_adapter), 2734f4f5df23SVikas Chaudhary * so that irqs will be registered after crbinit but before 2735f4f5df23SVikas Chaudhary * mbx_intr_enable. 2736f4f5df23SVikas Chaudhary */ 2737f4f5df23SVikas Chaudhary if (!is_qla8022(ha)) { 2738f4f5df23SVikas Chaudhary ret = qla4xxx_request_irqs(ha); 2739afaf5a2dSDavid Somayajulu if (ret) { 2740f4f5df23SVikas Chaudhary ql4_printk(KERN_WARNING, ha, "Failed to reserve " 2741f4f5df23SVikas Chaudhary "interrupt %d already in use.\n", pdev->irq); 2742b3a271a9SManish Rangankar goto remove_host; 2743afaf5a2dSDavid Somayajulu } 2744f4f5df23SVikas Chaudhary } 2745afaf5a2dSDavid Somayajulu 27462232be0dSLalit Chandivade pci_save_state(ha->pdev); 2747f4f5df23SVikas Chaudhary ha->isp_ops->enable_intrs(ha); 2748afaf5a2dSDavid Somayajulu 2749afaf5a2dSDavid Somayajulu /* Start timer thread. */ 2750afaf5a2dSDavid Somayajulu qla4xxx_start_timer(ha, qla4xxx_timer, 1); 2751afaf5a2dSDavid Somayajulu 2752afaf5a2dSDavid Somayajulu set_bit(AF_INIT_DONE, &ha->flags); 2753afaf5a2dSDavid Somayajulu 2754afaf5a2dSDavid Somayajulu printk(KERN_INFO 2755afaf5a2dSDavid Somayajulu " QLogic iSCSI HBA Driver version: %s\n" 2756afaf5a2dSDavid Somayajulu " QLogic ISP%04x @ %s, host#=%ld, fw=%02d.%02d.%02d.%02d\n", 2757afaf5a2dSDavid Somayajulu qla4xxx_version_str, ha->pdev->device, pci_name(ha->pdev), 2758afaf5a2dSDavid Somayajulu ha->host_no, ha->firmware_version[0], ha->firmware_version[1], 2759afaf5a2dSDavid Somayajulu ha->patch_number, ha->build_number); 2760ed1086e0SVikas Chaudhary 2761ed1086e0SVikas Chaudhary qla4xxx_create_ifaces(ha); 2762afaf5a2dSDavid Somayajulu return 0; 2763afaf5a2dSDavid Somayajulu 2764b3a271a9SManish Rangankar remove_host: 2765b3a271a9SManish Rangankar scsi_remove_host(ha->host); 2766b3a271a9SManish Rangankar 2767afaf5a2dSDavid Somayajulu probe_failed: 2768afaf5a2dSDavid Somayajulu qla4xxx_free_adapter(ha); 2769f4f5df23SVikas Chaudhary 2770f4f5df23SVikas Chaudhary probe_failed_ioconfig: 27712232be0dSLalit Chandivade pci_disable_pcie_error_reporting(pdev); 2772afaf5a2dSDavid Somayajulu scsi_host_put(ha->host); 2773afaf5a2dSDavid Somayajulu 2774afaf5a2dSDavid Somayajulu probe_disable_device: 2775afaf5a2dSDavid Somayajulu pci_disable_device(pdev); 2776afaf5a2dSDavid Somayajulu 2777afaf5a2dSDavid Somayajulu return ret; 2778afaf5a2dSDavid Somayajulu } 2779afaf5a2dSDavid Somayajulu 2780afaf5a2dSDavid Somayajulu /** 27817eece5a0SKaren Higgins * qla4xxx_prevent_other_port_reinit - prevent other port from re-initialize 27827eece5a0SKaren Higgins * @ha: pointer to adapter structure 27837eece5a0SKaren Higgins * 27847eece5a0SKaren Higgins * Mark the other ISP-4xxx port to indicate that the driver is being removed, 27857eece5a0SKaren Higgins * so that the other port will not re-initialize while in the process of 27867eece5a0SKaren Higgins * removing the ha due to driver unload or hba hotplug. 27877eece5a0SKaren Higgins **/ 27887eece5a0SKaren Higgins static void qla4xxx_prevent_other_port_reinit(struct scsi_qla_host *ha) 27897eece5a0SKaren Higgins { 27907eece5a0SKaren Higgins struct scsi_qla_host *other_ha = NULL; 27917eece5a0SKaren Higgins struct pci_dev *other_pdev = NULL; 27927eece5a0SKaren Higgins int fn = ISP4XXX_PCI_FN_2; 27937eece5a0SKaren Higgins 27947eece5a0SKaren Higgins /*iscsi function numbers for ISP4xxx is 1 and 3*/ 27957eece5a0SKaren Higgins if (PCI_FUNC(ha->pdev->devfn) & BIT_1) 27967eece5a0SKaren Higgins fn = ISP4XXX_PCI_FN_1; 27977eece5a0SKaren Higgins 27987eece5a0SKaren Higgins other_pdev = 27997eece5a0SKaren Higgins pci_get_domain_bus_and_slot(pci_domain_nr(ha->pdev->bus), 28007eece5a0SKaren Higgins ha->pdev->bus->number, PCI_DEVFN(PCI_SLOT(ha->pdev->devfn), 28017eece5a0SKaren Higgins fn)); 28027eece5a0SKaren Higgins 28037eece5a0SKaren Higgins /* Get other_ha if other_pdev is valid and state is enable*/ 28047eece5a0SKaren Higgins if (other_pdev) { 28057eece5a0SKaren Higgins if (atomic_read(&other_pdev->enable_cnt)) { 28067eece5a0SKaren Higgins other_ha = pci_get_drvdata(other_pdev); 28077eece5a0SKaren Higgins if (other_ha) { 28087eece5a0SKaren Higgins set_bit(AF_HA_REMOVAL, &other_ha->flags); 28097eece5a0SKaren Higgins DEBUG2(ql4_printk(KERN_INFO, ha, "%s: " 28107eece5a0SKaren Higgins "Prevent %s reinit\n", __func__, 28117eece5a0SKaren Higgins dev_name(&other_ha->pdev->dev))); 28127eece5a0SKaren Higgins } 28137eece5a0SKaren Higgins } 28147eece5a0SKaren Higgins pci_dev_put(other_pdev); 28157eece5a0SKaren Higgins } 28167eece5a0SKaren Higgins } 28177eece5a0SKaren Higgins 28187eece5a0SKaren Higgins /** 2819afaf5a2dSDavid Somayajulu * qla4xxx_remove_adapter - calback function to remove adapter. 2820afaf5a2dSDavid Somayajulu * @pci_dev: PCI device pointer 2821afaf5a2dSDavid Somayajulu **/ 2822afaf5a2dSDavid Somayajulu static void __devexit qla4xxx_remove_adapter(struct pci_dev *pdev) 2823afaf5a2dSDavid Somayajulu { 2824afaf5a2dSDavid Somayajulu struct scsi_qla_host *ha; 2825afaf5a2dSDavid Somayajulu 2826afaf5a2dSDavid Somayajulu ha = pci_get_drvdata(pdev); 2827afaf5a2dSDavid Somayajulu 28287eece5a0SKaren Higgins if (!is_qla8022(ha)) 28297eece5a0SKaren Higgins qla4xxx_prevent_other_port_reinit(ha); 2830bee4fe8eSDavid C Somayajulu 2831ed1086e0SVikas Chaudhary /* destroy iface from sysfs */ 2832ed1086e0SVikas Chaudhary qla4xxx_destroy_ifaces(ha); 2833ed1086e0SVikas Chaudhary 2834afaf5a2dSDavid Somayajulu scsi_remove_host(ha->host); 2835afaf5a2dSDavid Somayajulu 2836afaf5a2dSDavid Somayajulu qla4xxx_free_adapter(ha); 2837afaf5a2dSDavid Somayajulu 2838afaf5a2dSDavid Somayajulu scsi_host_put(ha->host); 2839afaf5a2dSDavid Somayajulu 28402232be0dSLalit Chandivade pci_disable_pcie_error_reporting(pdev); 2841f4f5df23SVikas Chaudhary pci_disable_device(pdev); 2842afaf5a2dSDavid Somayajulu pci_set_drvdata(pdev, NULL); 2843afaf5a2dSDavid Somayajulu } 2844afaf5a2dSDavid Somayajulu 2845afaf5a2dSDavid Somayajulu /** 2846afaf5a2dSDavid Somayajulu * qla4xxx_config_dma_addressing() - Configure OS DMA addressing method. 2847afaf5a2dSDavid Somayajulu * @ha: HA context 2848afaf5a2dSDavid Somayajulu * 2849afaf5a2dSDavid Somayajulu * At exit, the @ha's flags.enable_64bit_addressing set to indicated 2850afaf5a2dSDavid Somayajulu * supported addressing method. 2851afaf5a2dSDavid Somayajulu */ 285247975477SAdrian Bunk static void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha) 2853afaf5a2dSDavid Somayajulu { 2854afaf5a2dSDavid Somayajulu int retval; 2855afaf5a2dSDavid Somayajulu 2856afaf5a2dSDavid Somayajulu /* Update our PCI device dma_mask for full 64 bit mask */ 28576a35528aSYang Hongyang if (pci_set_dma_mask(ha->pdev, DMA_BIT_MASK(64)) == 0) { 28586a35528aSYang Hongyang if (pci_set_consistent_dma_mask(ha->pdev, DMA_BIT_MASK(64))) { 2859afaf5a2dSDavid Somayajulu dev_dbg(&ha->pdev->dev, 2860afaf5a2dSDavid Somayajulu "Failed to set 64 bit PCI consistent mask; " 2861afaf5a2dSDavid Somayajulu "using 32 bit.\n"); 2862afaf5a2dSDavid Somayajulu retval = pci_set_consistent_dma_mask(ha->pdev, 2863284901a9SYang Hongyang DMA_BIT_MASK(32)); 2864afaf5a2dSDavid Somayajulu } 2865afaf5a2dSDavid Somayajulu } else 2866284901a9SYang Hongyang retval = pci_set_dma_mask(ha->pdev, DMA_BIT_MASK(32)); 2867afaf5a2dSDavid Somayajulu } 2868afaf5a2dSDavid Somayajulu 2869afaf5a2dSDavid Somayajulu static int qla4xxx_slave_alloc(struct scsi_device *sdev) 2870afaf5a2dSDavid Somayajulu { 2871b3a271a9SManish Rangankar struct iscsi_cls_session *cls_sess; 2872b3a271a9SManish Rangankar struct iscsi_session *sess; 2873b3a271a9SManish Rangankar struct ddb_entry *ddb; 28748bb4033dSVikas Chaudhary int queue_depth = QL4_DEF_QDEPTH; 2875afaf5a2dSDavid Somayajulu 2876b3a271a9SManish Rangankar cls_sess = starget_to_session(sdev->sdev_target); 2877b3a271a9SManish Rangankar sess = cls_sess->dd_data; 2878b3a271a9SManish Rangankar ddb = sess->dd_data; 2879b3a271a9SManish Rangankar 2880afaf5a2dSDavid Somayajulu sdev->hostdata = ddb; 2881afaf5a2dSDavid Somayajulu sdev->tagged_supported = 1; 28828bb4033dSVikas Chaudhary 28838bb4033dSVikas Chaudhary if (ql4xmaxqdepth != 0 && ql4xmaxqdepth <= 0xffffU) 28848bb4033dSVikas Chaudhary queue_depth = ql4xmaxqdepth; 28858bb4033dSVikas Chaudhary 28868bb4033dSVikas Chaudhary scsi_activate_tcq(sdev, queue_depth); 2887afaf5a2dSDavid Somayajulu return 0; 2888afaf5a2dSDavid Somayajulu } 2889afaf5a2dSDavid Somayajulu 2890afaf5a2dSDavid Somayajulu static int qla4xxx_slave_configure(struct scsi_device *sdev) 2891afaf5a2dSDavid Somayajulu { 2892afaf5a2dSDavid Somayajulu sdev->tagged_supported = 1; 2893afaf5a2dSDavid Somayajulu return 0; 2894afaf5a2dSDavid Somayajulu } 2895afaf5a2dSDavid Somayajulu 2896afaf5a2dSDavid Somayajulu static void qla4xxx_slave_destroy(struct scsi_device *sdev) 2897afaf5a2dSDavid Somayajulu { 2898afaf5a2dSDavid Somayajulu scsi_deactivate_tcq(sdev, 1); 2899afaf5a2dSDavid Somayajulu } 2900afaf5a2dSDavid Somayajulu 2901afaf5a2dSDavid Somayajulu /** 2902afaf5a2dSDavid Somayajulu * qla4xxx_del_from_active_array - returns an active srb 2903afaf5a2dSDavid Somayajulu * @ha: Pointer to host adapter structure. 2904fd589a8fSAnand Gadiyar * @index: index into the active_array 2905afaf5a2dSDavid Somayajulu * 2906afaf5a2dSDavid Somayajulu * This routine removes and returns the srb at the specified index 2907afaf5a2dSDavid Somayajulu **/ 2908f4f5df23SVikas Chaudhary struct srb *qla4xxx_del_from_active_array(struct scsi_qla_host *ha, 2909f4f5df23SVikas Chaudhary uint32_t index) 2910afaf5a2dSDavid Somayajulu { 2911afaf5a2dSDavid Somayajulu struct srb *srb = NULL; 29125369887aSVikas Chaudhary struct scsi_cmnd *cmd = NULL; 2913afaf5a2dSDavid Somayajulu 29145369887aSVikas Chaudhary cmd = scsi_host_find_tag(ha->host, index); 29155369887aSVikas Chaudhary if (!cmd) 2916afaf5a2dSDavid Somayajulu return srb; 2917afaf5a2dSDavid Somayajulu 29185369887aSVikas Chaudhary srb = (struct srb *)CMD_SP(cmd); 29195369887aSVikas Chaudhary if (!srb) 2920afaf5a2dSDavid Somayajulu return srb; 2921afaf5a2dSDavid Somayajulu 2922afaf5a2dSDavid Somayajulu /* update counters */ 2923afaf5a2dSDavid Somayajulu if (srb->flags & SRB_DMA_VALID) { 2924afaf5a2dSDavid Somayajulu ha->req_q_count += srb->iocb_cnt; 2925afaf5a2dSDavid Somayajulu ha->iocb_cnt -= srb->iocb_cnt; 2926afaf5a2dSDavid Somayajulu if (srb->cmd) 29275369887aSVikas Chaudhary srb->cmd->host_scribble = 29285369887aSVikas Chaudhary (unsigned char *)(unsigned long) MAX_SRBS; 2929afaf5a2dSDavid Somayajulu } 2930afaf5a2dSDavid Somayajulu return srb; 2931afaf5a2dSDavid Somayajulu } 2932afaf5a2dSDavid Somayajulu 2933afaf5a2dSDavid Somayajulu /** 2934afaf5a2dSDavid Somayajulu * qla4xxx_eh_wait_on_command - waits for command to be returned by firmware 293509a0f719SVikas Chaudhary * @ha: Pointer to host adapter structure. 2936afaf5a2dSDavid Somayajulu * @cmd: Scsi Command to wait on. 2937afaf5a2dSDavid Somayajulu * 2938afaf5a2dSDavid Somayajulu * This routine waits for the command to be returned by the Firmware 2939afaf5a2dSDavid Somayajulu * for some max time. 2940afaf5a2dSDavid Somayajulu **/ 2941afaf5a2dSDavid Somayajulu static int qla4xxx_eh_wait_on_command(struct scsi_qla_host *ha, 2942afaf5a2dSDavid Somayajulu struct scsi_cmnd *cmd) 2943afaf5a2dSDavid Somayajulu { 2944afaf5a2dSDavid Somayajulu int done = 0; 2945afaf5a2dSDavid Somayajulu struct srb *rp; 2946afaf5a2dSDavid Somayajulu uint32_t max_wait_time = EH_WAIT_CMD_TOV; 29472232be0dSLalit Chandivade int ret = SUCCESS; 29482232be0dSLalit Chandivade 29492232be0dSLalit Chandivade /* Dont wait on command if PCI error is being handled 29502232be0dSLalit Chandivade * by PCI AER driver 29512232be0dSLalit Chandivade */ 29522232be0dSLalit Chandivade if (unlikely(pci_channel_offline(ha->pdev)) || 29532232be0dSLalit Chandivade (test_bit(AF_EEH_BUSY, &ha->flags))) { 29542232be0dSLalit Chandivade ql4_printk(KERN_WARNING, ha, "scsi%ld: Return from %s\n", 29552232be0dSLalit Chandivade ha->host_no, __func__); 29562232be0dSLalit Chandivade return ret; 29572232be0dSLalit Chandivade } 2958afaf5a2dSDavid Somayajulu 2959afaf5a2dSDavid Somayajulu do { 2960afaf5a2dSDavid Somayajulu /* Checking to see if its returned to OS */ 29615369887aSVikas Chaudhary rp = (struct srb *) CMD_SP(cmd); 2962afaf5a2dSDavid Somayajulu if (rp == NULL) { 2963afaf5a2dSDavid Somayajulu done++; 2964afaf5a2dSDavid Somayajulu break; 2965afaf5a2dSDavid Somayajulu } 2966afaf5a2dSDavid Somayajulu 2967afaf5a2dSDavid Somayajulu msleep(2000); 2968afaf5a2dSDavid Somayajulu } while (max_wait_time--); 2969afaf5a2dSDavid Somayajulu 2970afaf5a2dSDavid Somayajulu return done; 2971afaf5a2dSDavid Somayajulu } 2972afaf5a2dSDavid Somayajulu 2973afaf5a2dSDavid Somayajulu /** 2974afaf5a2dSDavid Somayajulu * qla4xxx_wait_for_hba_online - waits for HBA to come online 2975afaf5a2dSDavid Somayajulu * @ha: Pointer to host adapter structure 2976afaf5a2dSDavid Somayajulu **/ 2977afaf5a2dSDavid Somayajulu static int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha) 2978afaf5a2dSDavid Somayajulu { 2979afaf5a2dSDavid Somayajulu unsigned long wait_online; 2980afaf5a2dSDavid Somayajulu 2981f581a3f7SVikas Chaudhary wait_online = jiffies + (HBA_ONLINE_TOV * HZ); 2982afaf5a2dSDavid Somayajulu while (time_before(jiffies, wait_online)) { 2983afaf5a2dSDavid Somayajulu 2984afaf5a2dSDavid Somayajulu if (adapter_up(ha)) 2985afaf5a2dSDavid Somayajulu return QLA_SUCCESS; 2986afaf5a2dSDavid Somayajulu 2987afaf5a2dSDavid Somayajulu msleep(2000); 2988afaf5a2dSDavid Somayajulu } 2989afaf5a2dSDavid Somayajulu 2990afaf5a2dSDavid Somayajulu return QLA_ERROR; 2991afaf5a2dSDavid Somayajulu } 2992afaf5a2dSDavid Somayajulu 2993afaf5a2dSDavid Somayajulu /** 2994ce545039SMike Christie * qla4xxx_eh_wait_for_commands - wait for active cmds to finish. 2995fd589a8fSAnand Gadiyar * @ha: pointer to HBA 2996afaf5a2dSDavid Somayajulu * @t: target id 2997afaf5a2dSDavid Somayajulu * @l: lun id 2998afaf5a2dSDavid Somayajulu * 2999afaf5a2dSDavid Somayajulu * This function waits for all outstanding commands to a lun to complete. It 3000afaf5a2dSDavid Somayajulu * returns 0 if all pending commands are returned and 1 otherwise. 3001afaf5a2dSDavid Somayajulu **/ 3002ce545039SMike Christie static int qla4xxx_eh_wait_for_commands(struct scsi_qla_host *ha, 3003ce545039SMike Christie struct scsi_target *stgt, 3004ce545039SMike Christie struct scsi_device *sdev) 3005afaf5a2dSDavid Somayajulu { 3006afaf5a2dSDavid Somayajulu int cnt; 3007afaf5a2dSDavid Somayajulu int status = 0; 3008afaf5a2dSDavid Somayajulu struct scsi_cmnd *cmd; 3009afaf5a2dSDavid Somayajulu 3010afaf5a2dSDavid Somayajulu /* 3011ce545039SMike Christie * Waiting for all commands for the designated target or dev 3012ce545039SMike Christie * in the active array 3013afaf5a2dSDavid Somayajulu */ 3014afaf5a2dSDavid Somayajulu for (cnt = 0; cnt < ha->host->can_queue; cnt++) { 3015afaf5a2dSDavid Somayajulu cmd = scsi_host_find_tag(ha->host, cnt); 3016ce545039SMike Christie if (cmd && stgt == scsi_target(cmd->device) && 3017ce545039SMike Christie (!sdev || sdev == cmd->device)) { 3018afaf5a2dSDavid Somayajulu if (!qla4xxx_eh_wait_on_command(ha, cmd)) { 3019afaf5a2dSDavid Somayajulu status++; 3020afaf5a2dSDavid Somayajulu break; 3021afaf5a2dSDavid Somayajulu } 3022afaf5a2dSDavid Somayajulu } 3023afaf5a2dSDavid Somayajulu } 3024afaf5a2dSDavid Somayajulu return status; 3025afaf5a2dSDavid Somayajulu } 3026afaf5a2dSDavid Somayajulu 3027afaf5a2dSDavid Somayajulu /** 302809a0f719SVikas Chaudhary * qla4xxx_eh_abort - callback for abort task. 302909a0f719SVikas Chaudhary * @cmd: Pointer to Linux's SCSI command structure 303009a0f719SVikas Chaudhary * 303109a0f719SVikas Chaudhary * This routine is called by the Linux OS to abort the specified 303209a0f719SVikas Chaudhary * command. 303309a0f719SVikas Chaudhary **/ 303409a0f719SVikas Chaudhary static int qla4xxx_eh_abort(struct scsi_cmnd *cmd) 303509a0f719SVikas Chaudhary { 303609a0f719SVikas Chaudhary struct scsi_qla_host *ha = to_qla_host(cmd->device->host); 303709a0f719SVikas Chaudhary unsigned int id = cmd->device->id; 303809a0f719SVikas Chaudhary unsigned int lun = cmd->device->lun; 303992b3e5bbSMike Christie unsigned long flags; 304009a0f719SVikas Chaudhary struct srb *srb = NULL; 304109a0f719SVikas Chaudhary int ret = SUCCESS; 304209a0f719SVikas Chaudhary int wait = 0; 304309a0f719SVikas Chaudhary 3044c2660df3SVikas Chaudhary ql4_printk(KERN_INFO, ha, 30455cd049a5SChristoph Hellwig "scsi%ld:%d:%d: Abort command issued cmd=%p\n", 30465cd049a5SChristoph Hellwig ha->host_no, id, lun, cmd); 304709a0f719SVikas Chaudhary 304892b3e5bbSMike Christie spin_lock_irqsave(&ha->hardware_lock, flags); 304909a0f719SVikas Chaudhary srb = (struct srb *) CMD_SP(cmd); 305092b3e5bbSMike Christie if (!srb) { 305192b3e5bbSMike Christie spin_unlock_irqrestore(&ha->hardware_lock, flags); 305209a0f719SVikas Chaudhary return SUCCESS; 305392b3e5bbSMike Christie } 305409a0f719SVikas Chaudhary kref_get(&srb->srb_ref); 305592b3e5bbSMike Christie spin_unlock_irqrestore(&ha->hardware_lock, flags); 305609a0f719SVikas Chaudhary 305709a0f719SVikas Chaudhary if (qla4xxx_abort_task(ha, srb) != QLA_SUCCESS) { 305809a0f719SVikas Chaudhary DEBUG3(printk("scsi%ld:%d:%d: Abort_task mbx failed.\n", 305909a0f719SVikas Chaudhary ha->host_no, id, lun)); 306009a0f719SVikas Chaudhary ret = FAILED; 306109a0f719SVikas Chaudhary } else { 306209a0f719SVikas Chaudhary DEBUG3(printk("scsi%ld:%d:%d: Abort_task mbx success.\n", 306309a0f719SVikas Chaudhary ha->host_no, id, lun)); 306409a0f719SVikas Chaudhary wait = 1; 306509a0f719SVikas Chaudhary } 306609a0f719SVikas Chaudhary 306709a0f719SVikas Chaudhary kref_put(&srb->srb_ref, qla4xxx_srb_compl); 306809a0f719SVikas Chaudhary 306909a0f719SVikas Chaudhary /* Wait for command to complete */ 307009a0f719SVikas Chaudhary if (wait) { 307109a0f719SVikas Chaudhary if (!qla4xxx_eh_wait_on_command(ha, cmd)) { 307209a0f719SVikas Chaudhary DEBUG2(printk("scsi%ld:%d:%d: Abort handler timed out\n", 307309a0f719SVikas Chaudhary ha->host_no, id, lun)); 307409a0f719SVikas Chaudhary ret = FAILED; 307509a0f719SVikas Chaudhary } 307609a0f719SVikas Chaudhary } 307709a0f719SVikas Chaudhary 3078c2660df3SVikas Chaudhary ql4_printk(KERN_INFO, ha, 307909a0f719SVikas Chaudhary "scsi%ld:%d:%d: Abort command - %s\n", 308025985edcSLucas De Marchi ha->host_no, id, lun, (ret == SUCCESS) ? "succeeded" : "failed"); 308109a0f719SVikas Chaudhary 308209a0f719SVikas Chaudhary return ret; 308309a0f719SVikas Chaudhary } 308409a0f719SVikas Chaudhary 308509a0f719SVikas Chaudhary /** 3086afaf5a2dSDavid Somayajulu * qla4xxx_eh_device_reset - callback for target reset. 3087afaf5a2dSDavid Somayajulu * @cmd: Pointer to Linux's SCSI command structure 3088afaf5a2dSDavid Somayajulu * 3089afaf5a2dSDavid Somayajulu * This routine is called by the Linux OS to reset all luns on the 3090afaf5a2dSDavid Somayajulu * specified target. 3091afaf5a2dSDavid Somayajulu **/ 3092afaf5a2dSDavid Somayajulu static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd) 3093afaf5a2dSDavid Somayajulu { 3094afaf5a2dSDavid Somayajulu struct scsi_qla_host *ha = to_qla_host(cmd->device->host); 3095afaf5a2dSDavid Somayajulu struct ddb_entry *ddb_entry = cmd->device->hostdata; 3096afaf5a2dSDavid Somayajulu int ret = FAILED, stat; 3097afaf5a2dSDavid Somayajulu 3098612f7348SKaren Higgins if (!ddb_entry) 3099afaf5a2dSDavid Somayajulu return ret; 3100afaf5a2dSDavid Somayajulu 3101c01be6dcSMike Christie ret = iscsi_block_scsi_eh(cmd); 3102c01be6dcSMike Christie if (ret) 3103c01be6dcSMike Christie return ret; 3104c01be6dcSMike Christie ret = FAILED; 3105c01be6dcSMike Christie 3106c2660df3SVikas Chaudhary ql4_printk(KERN_INFO, ha, 3107afaf5a2dSDavid Somayajulu "scsi%ld:%d:%d:%d: DEVICE RESET ISSUED.\n", ha->host_no, 3108afaf5a2dSDavid Somayajulu cmd->device->channel, cmd->device->id, cmd->device->lun); 3109afaf5a2dSDavid Somayajulu 3110afaf5a2dSDavid Somayajulu DEBUG2(printk(KERN_INFO 3111afaf5a2dSDavid Somayajulu "scsi%ld: DEVICE_RESET cmd=%p jiffies = 0x%lx, to=%x," 3112afaf5a2dSDavid Somayajulu "dpc_flags=%lx, status=%x allowed=%d\n", ha->host_no, 3113242f9dcbSJens Axboe cmd, jiffies, cmd->request->timeout / HZ, 3114afaf5a2dSDavid Somayajulu ha->dpc_flags, cmd->result, cmd->allowed)); 3115afaf5a2dSDavid Somayajulu 3116afaf5a2dSDavid Somayajulu /* FIXME: wait for hba to go online */ 3117afaf5a2dSDavid Somayajulu stat = qla4xxx_reset_lun(ha, ddb_entry, cmd->device->lun); 3118afaf5a2dSDavid Somayajulu if (stat != QLA_SUCCESS) { 3119c2660df3SVikas Chaudhary ql4_printk(KERN_INFO, ha, "DEVICE RESET FAILED. %d\n", stat); 3120afaf5a2dSDavid Somayajulu goto eh_dev_reset_done; 3121afaf5a2dSDavid Somayajulu } 3122afaf5a2dSDavid Somayajulu 3123ce545039SMike Christie if (qla4xxx_eh_wait_for_commands(ha, scsi_target(cmd->device), 3124ce545039SMike Christie cmd->device)) { 3125c2660df3SVikas Chaudhary ql4_printk(KERN_INFO, ha, 3126afaf5a2dSDavid Somayajulu "DEVICE RESET FAILED - waiting for " 3127afaf5a2dSDavid Somayajulu "commands.\n"); 3128afaf5a2dSDavid Somayajulu goto eh_dev_reset_done; 3129afaf5a2dSDavid Somayajulu } 3130afaf5a2dSDavid Somayajulu 31319d562913SDavid C Somayajulu /* Send marker. */ 31329d562913SDavid C Somayajulu if (qla4xxx_send_marker_iocb(ha, ddb_entry, cmd->device->lun, 31339d562913SDavid C Somayajulu MM_LUN_RESET) != QLA_SUCCESS) 31349d562913SDavid C Somayajulu goto eh_dev_reset_done; 31359d562913SDavid C Somayajulu 3136c2660df3SVikas Chaudhary ql4_printk(KERN_INFO, ha, 3137afaf5a2dSDavid Somayajulu "scsi(%ld:%d:%d:%d): DEVICE RESET SUCCEEDED.\n", 3138afaf5a2dSDavid Somayajulu ha->host_no, cmd->device->channel, cmd->device->id, 3139afaf5a2dSDavid Somayajulu cmd->device->lun); 3140afaf5a2dSDavid Somayajulu 3141afaf5a2dSDavid Somayajulu ret = SUCCESS; 3142afaf5a2dSDavid Somayajulu 3143afaf5a2dSDavid Somayajulu eh_dev_reset_done: 3144afaf5a2dSDavid Somayajulu 3145afaf5a2dSDavid Somayajulu return ret; 3146afaf5a2dSDavid Somayajulu } 3147afaf5a2dSDavid Somayajulu 3148afaf5a2dSDavid Somayajulu /** 3149ce545039SMike Christie * qla4xxx_eh_target_reset - callback for target reset. 3150ce545039SMike Christie * @cmd: Pointer to Linux's SCSI command structure 3151ce545039SMike Christie * 3152ce545039SMike Christie * This routine is called by the Linux OS to reset the target. 3153ce545039SMike Christie **/ 3154ce545039SMike Christie static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd) 3155ce545039SMike Christie { 3156ce545039SMike Christie struct scsi_qla_host *ha = to_qla_host(cmd->device->host); 3157ce545039SMike Christie struct ddb_entry *ddb_entry = cmd->device->hostdata; 3158c01be6dcSMike Christie int stat, ret; 3159ce545039SMike Christie 3160ce545039SMike Christie if (!ddb_entry) 3161ce545039SMike Christie return FAILED; 3162ce545039SMike Christie 3163c01be6dcSMike Christie ret = iscsi_block_scsi_eh(cmd); 3164c01be6dcSMike Christie if (ret) 3165c01be6dcSMike Christie return ret; 3166c01be6dcSMike Christie 3167ce545039SMike Christie starget_printk(KERN_INFO, scsi_target(cmd->device), 3168ce545039SMike Christie "WARM TARGET RESET ISSUED.\n"); 3169ce545039SMike Christie 3170ce545039SMike Christie DEBUG2(printk(KERN_INFO 3171ce545039SMike Christie "scsi%ld: TARGET_DEVICE_RESET cmd=%p jiffies = 0x%lx, " 3172ce545039SMike Christie "to=%x,dpc_flags=%lx, status=%x allowed=%d\n", 3173242f9dcbSJens Axboe ha->host_no, cmd, jiffies, cmd->request->timeout / HZ, 3174ce545039SMike Christie ha->dpc_flags, cmd->result, cmd->allowed)); 3175ce545039SMike Christie 3176ce545039SMike Christie stat = qla4xxx_reset_target(ha, ddb_entry); 3177ce545039SMike Christie if (stat != QLA_SUCCESS) { 3178ce545039SMike Christie starget_printk(KERN_INFO, scsi_target(cmd->device), 3179ce545039SMike Christie "WARM TARGET RESET FAILED.\n"); 3180ce545039SMike Christie return FAILED; 3181ce545039SMike Christie } 3182ce545039SMike Christie 3183ce545039SMike Christie if (qla4xxx_eh_wait_for_commands(ha, scsi_target(cmd->device), 3184ce545039SMike Christie NULL)) { 3185ce545039SMike Christie starget_printk(KERN_INFO, scsi_target(cmd->device), 3186ce545039SMike Christie "WARM TARGET DEVICE RESET FAILED - " 3187ce545039SMike Christie "waiting for commands.\n"); 3188ce545039SMike Christie return FAILED; 3189ce545039SMike Christie } 3190ce545039SMike Christie 31919d562913SDavid C Somayajulu /* Send marker. */ 31929d562913SDavid C Somayajulu if (qla4xxx_send_marker_iocb(ha, ddb_entry, cmd->device->lun, 31939d562913SDavid C Somayajulu MM_TGT_WARM_RESET) != QLA_SUCCESS) { 31949d562913SDavid C Somayajulu starget_printk(KERN_INFO, scsi_target(cmd->device), 31959d562913SDavid C Somayajulu "WARM TARGET DEVICE RESET FAILED - " 31969d562913SDavid C Somayajulu "marker iocb failed.\n"); 31979d562913SDavid C Somayajulu return FAILED; 31989d562913SDavid C Somayajulu } 31999d562913SDavid C Somayajulu 3200ce545039SMike Christie starget_printk(KERN_INFO, scsi_target(cmd->device), 3201ce545039SMike Christie "WARM TARGET RESET SUCCEEDED.\n"); 3202ce545039SMike Christie return SUCCESS; 3203ce545039SMike Christie } 3204ce545039SMike Christie 3205ce545039SMike Christie /** 3206afaf5a2dSDavid Somayajulu * qla4xxx_eh_host_reset - kernel callback 3207afaf5a2dSDavid Somayajulu * @cmd: Pointer to Linux's SCSI command structure 3208afaf5a2dSDavid Somayajulu * 3209afaf5a2dSDavid Somayajulu * This routine is invoked by the Linux kernel to perform fatal error 3210afaf5a2dSDavid Somayajulu * recovery on the specified adapter. 3211afaf5a2dSDavid Somayajulu **/ 3212afaf5a2dSDavid Somayajulu static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd) 3213afaf5a2dSDavid Somayajulu { 3214afaf5a2dSDavid Somayajulu int return_status = FAILED; 3215afaf5a2dSDavid Somayajulu struct scsi_qla_host *ha; 3216afaf5a2dSDavid Somayajulu 3217b3a271a9SManish Rangankar ha = to_qla_host(cmd->device->host); 3218afaf5a2dSDavid Somayajulu 3219f4f5df23SVikas Chaudhary if (ql4xdontresethba) { 3220f4f5df23SVikas Chaudhary DEBUG2(printk("scsi%ld: %s: Don't Reset HBA\n", 3221f4f5df23SVikas Chaudhary ha->host_no, __func__)); 3222f4f5df23SVikas Chaudhary return FAILED; 3223f4f5df23SVikas Chaudhary } 3224f4f5df23SVikas Chaudhary 3225c2660df3SVikas Chaudhary ql4_printk(KERN_INFO, ha, 3226dca05c4cSKaren Higgins "scsi(%ld:%d:%d:%d): HOST RESET ISSUED.\n", ha->host_no, 3227afaf5a2dSDavid Somayajulu cmd->device->channel, cmd->device->id, cmd->device->lun); 3228afaf5a2dSDavid Somayajulu 3229afaf5a2dSDavid Somayajulu if (qla4xxx_wait_for_hba_online(ha) != QLA_SUCCESS) { 3230afaf5a2dSDavid Somayajulu DEBUG2(printk("scsi%ld:%d: %s: Unable to reset host. Adapter " 3231afaf5a2dSDavid Somayajulu "DEAD.\n", ha->host_no, cmd->device->channel, 3232afaf5a2dSDavid Somayajulu __func__)); 3233afaf5a2dSDavid Somayajulu 3234afaf5a2dSDavid Somayajulu return FAILED; 3235afaf5a2dSDavid Somayajulu } 3236afaf5a2dSDavid Somayajulu 3237f4f5df23SVikas Chaudhary if (!test_bit(DPC_RESET_HA, &ha->dpc_flags)) { 3238f4f5df23SVikas Chaudhary if (is_qla8022(ha)) 3239f4f5df23SVikas Chaudhary set_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags); 3240f4f5df23SVikas Chaudhary else 3241f4f5df23SVikas Chaudhary set_bit(DPC_RESET_HA, &ha->dpc_flags); 3242f4f5df23SVikas Chaudhary } 324350a29aecSMike Christie 3244f4f5df23SVikas Chaudhary if (qla4xxx_recover_adapter(ha) == QLA_SUCCESS) 3245afaf5a2dSDavid Somayajulu return_status = SUCCESS; 3246afaf5a2dSDavid Somayajulu 3247c2660df3SVikas Chaudhary ql4_printk(KERN_INFO, ha, "HOST RESET %s.\n", 324825985edcSLucas De Marchi return_status == FAILED ? "FAILED" : "SUCCEEDED"); 3249afaf5a2dSDavid Somayajulu 3250afaf5a2dSDavid Somayajulu return return_status; 3251afaf5a2dSDavid Somayajulu } 3252afaf5a2dSDavid Somayajulu 32532232be0dSLalit Chandivade /* PCI AER driver recovers from all correctable errors w/o 32542232be0dSLalit Chandivade * driver intervention. For uncorrectable errors PCI AER 32552232be0dSLalit Chandivade * driver calls the following device driver's callbacks 32562232be0dSLalit Chandivade * 32572232be0dSLalit Chandivade * - Fatal Errors - link_reset 32582232be0dSLalit Chandivade * - Non-Fatal Errors - driver's pci_error_detected() which 32592232be0dSLalit Chandivade * returns CAN_RECOVER, NEED_RESET or DISCONNECT. 32602232be0dSLalit Chandivade * 32612232be0dSLalit Chandivade * PCI AER driver calls 32622232be0dSLalit Chandivade * CAN_RECOVER - driver's pci_mmio_enabled(), mmio_enabled 32632232be0dSLalit Chandivade * returns RECOVERED or NEED_RESET if fw_hung 32642232be0dSLalit Chandivade * NEED_RESET - driver's slot_reset() 32652232be0dSLalit Chandivade * DISCONNECT - device is dead & cannot recover 32662232be0dSLalit Chandivade * RECOVERED - driver's pci_resume() 32672232be0dSLalit Chandivade */ 32682232be0dSLalit Chandivade static pci_ers_result_t 32692232be0dSLalit Chandivade qla4xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) 32702232be0dSLalit Chandivade { 32712232be0dSLalit Chandivade struct scsi_qla_host *ha = pci_get_drvdata(pdev); 32722232be0dSLalit Chandivade 32732232be0dSLalit Chandivade ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: error detected:state %x\n", 32742232be0dSLalit Chandivade ha->host_no, __func__, state); 32752232be0dSLalit Chandivade 32762232be0dSLalit Chandivade if (!is_aer_supported(ha)) 32772232be0dSLalit Chandivade return PCI_ERS_RESULT_NONE; 32782232be0dSLalit Chandivade 32792232be0dSLalit Chandivade switch (state) { 32802232be0dSLalit Chandivade case pci_channel_io_normal: 32812232be0dSLalit Chandivade clear_bit(AF_EEH_BUSY, &ha->flags); 32822232be0dSLalit Chandivade return PCI_ERS_RESULT_CAN_RECOVER; 32832232be0dSLalit Chandivade case pci_channel_io_frozen: 32842232be0dSLalit Chandivade set_bit(AF_EEH_BUSY, &ha->flags); 32852232be0dSLalit Chandivade qla4xxx_mailbox_premature_completion(ha); 32862232be0dSLalit Chandivade qla4xxx_free_irqs(ha); 32872232be0dSLalit Chandivade pci_disable_device(pdev); 32887b3595dfSVikas Chaudhary /* Return back all IOs */ 32897b3595dfSVikas Chaudhary qla4xxx_abort_active_cmds(ha, DID_RESET << 16); 32902232be0dSLalit Chandivade return PCI_ERS_RESULT_NEED_RESET; 32912232be0dSLalit Chandivade case pci_channel_io_perm_failure: 32922232be0dSLalit Chandivade set_bit(AF_EEH_BUSY, &ha->flags); 32932232be0dSLalit Chandivade set_bit(AF_PCI_CHANNEL_IO_PERM_FAILURE, &ha->flags); 32942232be0dSLalit Chandivade qla4xxx_abort_active_cmds(ha, DID_NO_CONNECT << 16); 32952232be0dSLalit Chandivade return PCI_ERS_RESULT_DISCONNECT; 32962232be0dSLalit Chandivade } 32972232be0dSLalit Chandivade return PCI_ERS_RESULT_NEED_RESET; 32982232be0dSLalit Chandivade } 32992232be0dSLalit Chandivade 33002232be0dSLalit Chandivade /** 33012232be0dSLalit Chandivade * qla4xxx_pci_mmio_enabled() gets called if 33022232be0dSLalit Chandivade * qla4xxx_pci_error_detected() returns PCI_ERS_RESULT_CAN_RECOVER 33032232be0dSLalit Chandivade * and read/write to the device still works. 33042232be0dSLalit Chandivade **/ 33052232be0dSLalit Chandivade static pci_ers_result_t 33062232be0dSLalit Chandivade qla4xxx_pci_mmio_enabled(struct pci_dev *pdev) 33072232be0dSLalit Chandivade { 33082232be0dSLalit Chandivade struct scsi_qla_host *ha = pci_get_drvdata(pdev); 33092232be0dSLalit Chandivade 33102232be0dSLalit Chandivade if (!is_aer_supported(ha)) 33112232be0dSLalit Chandivade return PCI_ERS_RESULT_NONE; 33122232be0dSLalit Chandivade 33132232be0dSLalit Chandivade return PCI_ERS_RESULT_RECOVERED; 33142232be0dSLalit Chandivade } 33152232be0dSLalit Chandivade 33167b3595dfSVikas Chaudhary static uint32_t qla4_8xxx_error_recovery(struct scsi_qla_host *ha) 33172232be0dSLalit Chandivade { 33182232be0dSLalit Chandivade uint32_t rval = QLA_ERROR; 33197b3595dfSVikas Chaudhary uint32_t ret = 0; 33202232be0dSLalit Chandivade int fn; 33212232be0dSLalit Chandivade struct pci_dev *other_pdev = NULL; 33222232be0dSLalit Chandivade 33232232be0dSLalit Chandivade ql4_printk(KERN_WARNING, ha, "scsi%ld: In %s\n", ha->host_no, __func__); 33242232be0dSLalit Chandivade 33252232be0dSLalit Chandivade set_bit(DPC_RESET_ACTIVE, &ha->dpc_flags); 33262232be0dSLalit Chandivade 33272232be0dSLalit Chandivade if (test_bit(AF_ONLINE, &ha->flags)) { 33282232be0dSLalit Chandivade clear_bit(AF_ONLINE, &ha->flags); 3329b3a271a9SManish Rangankar clear_bit(AF_LINK_UP, &ha->flags); 3330b3a271a9SManish Rangankar iscsi_host_for_each_session(ha->host, qla4xxx_fail_session); 33312232be0dSLalit Chandivade qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); 33322232be0dSLalit Chandivade } 33332232be0dSLalit Chandivade 33342232be0dSLalit Chandivade fn = PCI_FUNC(ha->pdev->devfn); 33352232be0dSLalit Chandivade while (fn > 0) { 33362232be0dSLalit Chandivade fn--; 33372232be0dSLalit Chandivade ql4_printk(KERN_INFO, ha, "scsi%ld: %s: Finding PCI device at " 33382232be0dSLalit Chandivade "func %x\n", ha->host_no, __func__, fn); 33392232be0dSLalit Chandivade /* Get the pci device given the domain, bus, 33402232be0dSLalit Chandivade * slot/function number */ 33412232be0dSLalit Chandivade other_pdev = 33422232be0dSLalit Chandivade pci_get_domain_bus_and_slot(pci_domain_nr(ha->pdev->bus), 33432232be0dSLalit Chandivade ha->pdev->bus->number, PCI_DEVFN(PCI_SLOT(ha->pdev->devfn), 33442232be0dSLalit Chandivade fn)); 33452232be0dSLalit Chandivade 33462232be0dSLalit Chandivade if (!other_pdev) 33472232be0dSLalit Chandivade continue; 33482232be0dSLalit Chandivade 33492232be0dSLalit Chandivade if (atomic_read(&other_pdev->enable_cnt)) { 33502232be0dSLalit Chandivade ql4_printk(KERN_INFO, ha, "scsi%ld: %s: Found PCI " 33512232be0dSLalit Chandivade "func in enabled state%x\n", ha->host_no, 33522232be0dSLalit Chandivade __func__, fn); 33532232be0dSLalit Chandivade pci_dev_put(other_pdev); 33542232be0dSLalit Chandivade break; 33552232be0dSLalit Chandivade } 33562232be0dSLalit Chandivade pci_dev_put(other_pdev); 33572232be0dSLalit Chandivade } 33582232be0dSLalit Chandivade 33592232be0dSLalit Chandivade /* The first function on the card, the reset owner will 33602232be0dSLalit Chandivade * start & initialize the firmware. The other functions 33612232be0dSLalit Chandivade * on the card will reset the firmware context 33622232be0dSLalit Chandivade */ 33632232be0dSLalit Chandivade if (!fn) { 33642232be0dSLalit Chandivade ql4_printk(KERN_INFO, ha, "scsi%ld: %s: devfn being reset " 33652232be0dSLalit Chandivade "0x%x is the owner\n", ha->host_no, __func__, 33662232be0dSLalit Chandivade ha->pdev->devfn); 33672232be0dSLalit Chandivade 33682232be0dSLalit Chandivade qla4_8xxx_idc_lock(ha); 33692232be0dSLalit Chandivade qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, 33702232be0dSLalit Chandivade QLA82XX_DEV_COLD); 33712232be0dSLalit Chandivade 33722232be0dSLalit Chandivade qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_IDC_VERSION, 33732232be0dSLalit Chandivade QLA82XX_IDC_VERSION); 33742232be0dSLalit Chandivade 33752232be0dSLalit Chandivade qla4_8xxx_idc_unlock(ha); 33762232be0dSLalit Chandivade clear_bit(AF_FW_RECOVERY, &ha->flags); 33770e7e8501SManish Rangankar rval = qla4xxx_initialize_adapter(ha); 33782232be0dSLalit Chandivade qla4_8xxx_idc_lock(ha); 33792232be0dSLalit Chandivade 33802232be0dSLalit Chandivade if (rval != QLA_SUCCESS) { 33812232be0dSLalit Chandivade ql4_printk(KERN_INFO, ha, "scsi%ld: %s: HW State: " 33822232be0dSLalit Chandivade "FAILED\n", ha->host_no, __func__); 33832232be0dSLalit Chandivade qla4_8xxx_clear_drv_active(ha); 33842232be0dSLalit Chandivade qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, 33852232be0dSLalit Chandivade QLA82XX_DEV_FAILED); 33862232be0dSLalit Chandivade } else { 33872232be0dSLalit Chandivade ql4_printk(KERN_INFO, ha, "scsi%ld: %s: HW State: " 33882232be0dSLalit Chandivade "READY\n", ha->host_no, __func__); 33892232be0dSLalit Chandivade qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, 33902232be0dSLalit Chandivade QLA82XX_DEV_READY); 33912232be0dSLalit Chandivade /* Clear driver state register */ 33922232be0dSLalit Chandivade qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_STATE, 0); 33932232be0dSLalit Chandivade qla4_8xxx_set_drv_active(ha); 33947b3595dfSVikas Chaudhary ret = qla4xxx_request_irqs(ha); 33957b3595dfSVikas Chaudhary if (ret) { 33967b3595dfSVikas Chaudhary ql4_printk(KERN_WARNING, ha, "Failed to " 33977b3595dfSVikas Chaudhary "reserve interrupt %d already in use.\n", 33987b3595dfSVikas Chaudhary ha->pdev->irq); 33997b3595dfSVikas Chaudhary rval = QLA_ERROR; 34007b3595dfSVikas Chaudhary } else { 34012232be0dSLalit Chandivade ha->isp_ops->enable_intrs(ha); 34027b3595dfSVikas Chaudhary rval = QLA_SUCCESS; 34037b3595dfSVikas Chaudhary } 34042232be0dSLalit Chandivade } 34052232be0dSLalit Chandivade qla4_8xxx_idc_unlock(ha); 34062232be0dSLalit Chandivade } else { 34072232be0dSLalit Chandivade ql4_printk(KERN_INFO, ha, "scsi%ld: %s: devfn 0x%x is not " 34082232be0dSLalit Chandivade "the reset owner\n", ha->host_no, __func__, 34092232be0dSLalit Chandivade ha->pdev->devfn); 34102232be0dSLalit Chandivade if ((qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE) == 34112232be0dSLalit Chandivade QLA82XX_DEV_READY)) { 34122232be0dSLalit Chandivade clear_bit(AF_FW_RECOVERY, &ha->flags); 34130e7e8501SManish Rangankar rval = qla4xxx_initialize_adapter(ha); 34147b3595dfSVikas Chaudhary if (rval == QLA_SUCCESS) { 34157b3595dfSVikas Chaudhary ret = qla4xxx_request_irqs(ha); 34167b3595dfSVikas Chaudhary if (ret) { 34177b3595dfSVikas Chaudhary ql4_printk(KERN_WARNING, ha, "Failed to" 34187b3595dfSVikas Chaudhary " reserve interrupt %d already in" 34197b3595dfSVikas Chaudhary " use.\n", ha->pdev->irq); 34207b3595dfSVikas Chaudhary rval = QLA_ERROR; 34217b3595dfSVikas Chaudhary } else { 34222232be0dSLalit Chandivade ha->isp_ops->enable_intrs(ha); 34237b3595dfSVikas Chaudhary rval = QLA_SUCCESS; 34247b3595dfSVikas Chaudhary } 34257b3595dfSVikas Chaudhary } 34262232be0dSLalit Chandivade qla4_8xxx_idc_lock(ha); 34272232be0dSLalit Chandivade qla4_8xxx_set_drv_active(ha); 34282232be0dSLalit Chandivade qla4_8xxx_idc_unlock(ha); 34292232be0dSLalit Chandivade } 34302232be0dSLalit Chandivade } 34312232be0dSLalit Chandivade clear_bit(DPC_RESET_ACTIVE, &ha->dpc_flags); 34322232be0dSLalit Chandivade return rval; 34332232be0dSLalit Chandivade } 34342232be0dSLalit Chandivade 34352232be0dSLalit Chandivade static pci_ers_result_t 34362232be0dSLalit Chandivade qla4xxx_pci_slot_reset(struct pci_dev *pdev) 34372232be0dSLalit Chandivade { 34382232be0dSLalit Chandivade pci_ers_result_t ret = PCI_ERS_RESULT_DISCONNECT; 34392232be0dSLalit Chandivade struct scsi_qla_host *ha = pci_get_drvdata(pdev); 34402232be0dSLalit Chandivade int rc; 34412232be0dSLalit Chandivade 34422232be0dSLalit Chandivade ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: slot_reset\n", 34432232be0dSLalit Chandivade ha->host_no, __func__); 34442232be0dSLalit Chandivade 34452232be0dSLalit Chandivade if (!is_aer_supported(ha)) 34462232be0dSLalit Chandivade return PCI_ERS_RESULT_NONE; 34472232be0dSLalit Chandivade 34482232be0dSLalit Chandivade /* Restore the saved state of PCIe device - 34492232be0dSLalit Chandivade * BAR registers, PCI Config space, PCIX, MSI, 34502232be0dSLalit Chandivade * IOV states 34512232be0dSLalit Chandivade */ 34522232be0dSLalit Chandivade pci_restore_state(pdev); 34532232be0dSLalit Chandivade 34542232be0dSLalit Chandivade /* pci_restore_state() clears the saved_state flag of the device 34552232be0dSLalit Chandivade * save restored state which resets saved_state flag 34562232be0dSLalit Chandivade */ 34572232be0dSLalit Chandivade pci_save_state(pdev); 34582232be0dSLalit Chandivade 34592232be0dSLalit Chandivade /* Initialize device or resume if in suspended state */ 34602232be0dSLalit Chandivade rc = pci_enable_device(pdev); 34612232be0dSLalit Chandivade if (rc) { 346225985edcSLucas De Marchi ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: Can't re-enable " 34632232be0dSLalit Chandivade "device after reset\n", ha->host_no, __func__); 34642232be0dSLalit Chandivade goto exit_slot_reset; 34652232be0dSLalit Chandivade } 34662232be0dSLalit Chandivade 34677b3595dfSVikas Chaudhary ha->isp_ops->disable_intrs(ha); 34682232be0dSLalit Chandivade 34692232be0dSLalit Chandivade if (is_qla8022(ha)) { 34702232be0dSLalit Chandivade if (qla4_8xxx_error_recovery(ha) == QLA_SUCCESS) { 34712232be0dSLalit Chandivade ret = PCI_ERS_RESULT_RECOVERED; 34722232be0dSLalit Chandivade goto exit_slot_reset; 34732232be0dSLalit Chandivade } else 34742232be0dSLalit Chandivade goto exit_slot_reset; 34752232be0dSLalit Chandivade } 34762232be0dSLalit Chandivade 34772232be0dSLalit Chandivade exit_slot_reset: 34782232be0dSLalit Chandivade ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: Return=%x\n" 34792232be0dSLalit Chandivade "device after reset\n", ha->host_no, __func__, ret); 34802232be0dSLalit Chandivade return ret; 34812232be0dSLalit Chandivade } 34822232be0dSLalit Chandivade 34832232be0dSLalit Chandivade static void 34842232be0dSLalit Chandivade qla4xxx_pci_resume(struct pci_dev *pdev) 34852232be0dSLalit Chandivade { 34862232be0dSLalit Chandivade struct scsi_qla_host *ha = pci_get_drvdata(pdev); 34872232be0dSLalit Chandivade int ret; 34882232be0dSLalit Chandivade 34892232be0dSLalit Chandivade ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: pci_resume\n", 34902232be0dSLalit Chandivade ha->host_no, __func__); 34912232be0dSLalit Chandivade 34922232be0dSLalit Chandivade ret = qla4xxx_wait_for_hba_online(ha); 34932232be0dSLalit Chandivade if (ret != QLA_SUCCESS) { 34942232be0dSLalit Chandivade ql4_printk(KERN_ERR, ha, "scsi%ld: %s: the device failed to " 34952232be0dSLalit Chandivade "resume I/O from slot/link_reset\n", ha->host_no, 34962232be0dSLalit Chandivade __func__); 34972232be0dSLalit Chandivade } 34982232be0dSLalit Chandivade 34992232be0dSLalit Chandivade pci_cleanup_aer_uncorrect_error_status(pdev); 35002232be0dSLalit Chandivade clear_bit(AF_EEH_BUSY, &ha->flags); 35012232be0dSLalit Chandivade } 35022232be0dSLalit Chandivade 35032232be0dSLalit Chandivade static struct pci_error_handlers qla4xxx_err_handler = { 35042232be0dSLalit Chandivade .error_detected = qla4xxx_pci_error_detected, 35052232be0dSLalit Chandivade .mmio_enabled = qla4xxx_pci_mmio_enabled, 35062232be0dSLalit Chandivade .slot_reset = qla4xxx_pci_slot_reset, 35072232be0dSLalit Chandivade .resume = qla4xxx_pci_resume, 35082232be0dSLalit Chandivade }; 35092232be0dSLalit Chandivade 3510afaf5a2dSDavid Somayajulu static struct pci_device_id qla4xxx_pci_tbl[] = { 3511afaf5a2dSDavid Somayajulu { 3512afaf5a2dSDavid Somayajulu .vendor = PCI_VENDOR_ID_QLOGIC, 3513afaf5a2dSDavid Somayajulu .device = PCI_DEVICE_ID_QLOGIC_ISP4010, 3514afaf5a2dSDavid Somayajulu .subvendor = PCI_ANY_ID, 3515afaf5a2dSDavid Somayajulu .subdevice = PCI_ANY_ID, 3516afaf5a2dSDavid Somayajulu }, 3517afaf5a2dSDavid Somayajulu { 3518afaf5a2dSDavid Somayajulu .vendor = PCI_VENDOR_ID_QLOGIC, 3519afaf5a2dSDavid Somayajulu .device = PCI_DEVICE_ID_QLOGIC_ISP4022, 3520afaf5a2dSDavid Somayajulu .subvendor = PCI_ANY_ID, 3521afaf5a2dSDavid Somayajulu .subdevice = PCI_ANY_ID, 3522afaf5a2dSDavid Somayajulu }, 3523d915058fSDavid C Somayajulu { 3524d915058fSDavid C Somayajulu .vendor = PCI_VENDOR_ID_QLOGIC, 3525d915058fSDavid C Somayajulu .device = PCI_DEVICE_ID_QLOGIC_ISP4032, 3526d915058fSDavid C Somayajulu .subvendor = PCI_ANY_ID, 3527d915058fSDavid C Somayajulu .subdevice = PCI_ANY_ID, 3528d915058fSDavid C Somayajulu }, 3529f4f5df23SVikas Chaudhary { 3530f4f5df23SVikas Chaudhary .vendor = PCI_VENDOR_ID_QLOGIC, 3531f4f5df23SVikas Chaudhary .device = PCI_DEVICE_ID_QLOGIC_ISP8022, 3532f4f5df23SVikas Chaudhary .subvendor = PCI_ANY_ID, 3533f4f5df23SVikas Chaudhary .subdevice = PCI_ANY_ID, 3534f4f5df23SVikas Chaudhary }, 3535afaf5a2dSDavid Somayajulu {0, 0}, 3536afaf5a2dSDavid Somayajulu }; 3537afaf5a2dSDavid Somayajulu MODULE_DEVICE_TABLE(pci, qla4xxx_pci_tbl); 3538afaf5a2dSDavid Somayajulu 353947975477SAdrian Bunk static struct pci_driver qla4xxx_pci_driver = { 3540afaf5a2dSDavid Somayajulu .name = DRIVER_NAME, 3541afaf5a2dSDavid Somayajulu .id_table = qla4xxx_pci_tbl, 3542afaf5a2dSDavid Somayajulu .probe = qla4xxx_probe_adapter, 3543afaf5a2dSDavid Somayajulu .remove = qla4xxx_remove_adapter, 35442232be0dSLalit Chandivade .err_handler = &qla4xxx_err_handler, 3545afaf5a2dSDavid Somayajulu }; 3546afaf5a2dSDavid Somayajulu 3547afaf5a2dSDavid Somayajulu static int __init qla4xxx_module_init(void) 3548afaf5a2dSDavid Somayajulu { 3549afaf5a2dSDavid Somayajulu int ret; 3550afaf5a2dSDavid Somayajulu 3551afaf5a2dSDavid Somayajulu /* Allocate cache for SRBs. */ 3552afaf5a2dSDavid Somayajulu srb_cachep = kmem_cache_create("qla4xxx_srbs", sizeof(struct srb), 0, 355320c2df83SPaul Mundt SLAB_HWCACHE_ALIGN, NULL); 3554afaf5a2dSDavid Somayajulu if (srb_cachep == NULL) { 3555afaf5a2dSDavid Somayajulu printk(KERN_ERR 3556afaf5a2dSDavid Somayajulu "%s: Unable to allocate SRB cache..." 3557afaf5a2dSDavid Somayajulu "Failing load!\n", DRIVER_NAME); 3558afaf5a2dSDavid Somayajulu ret = -ENOMEM; 3559afaf5a2dSDavid Somayajulu goto no_srp_cache; 3560afaf5a2dSDavid Somayajulu } 3561afaf5a2dSDavid Somayajulu 3562afaf5a2dSDavid Somayajulu /* Derive version string. */ 3563afaf5a2dSDavid Somayajulu strcpy(qla4xxx_version_str, QLA4XXX_DRIVER_VERSION); 356411010fecSAndrew Vasquez if (ql4xextended_error_logging) 3565afaf5a2dSDavid Somayajulu strcat(qla4xxx_version_str, "-debug"); 3566afaf5a2dSDavid Somayajulu 3567afaf5a2dSDavid Somayajulu qla4xxx_scsi_transport = 3568afaf5a2dSDavid Somayajulu iscsi_register_transport(&qla4xxx_iscsi_transport); 3569afaf5a2dSDavid Somayajulu if (!qla4xxx_scsi_transport){ 3570afaf5a2dSDavid Somayajulu ret = -ENODEV; 3571afaf5a2dSDavid Somayajulu goto release_srb_cache; 3572afaf5a2dSDavid Somayajulu } 3573afaf5a2dSDavid Somayajulu 3574afaf5a2dSDavid Somayajulu ret = pci_register_driver(&qla4xxx_pci_driver); 3575afaf5a2dSDavid Somayajulu if (ret) 3576afaf5a2dSDavid Somayajulu goto unregister_transport; 3577afaf5a2dSDavid Somayajulu 3578afaf5a2dSDavid Somayajulu printk(KERN_INFO "QLogic iSCSI HBA Driver\n"); 3579afaf5a2dSDavid Somayajulu return 0; 35805ae16db3SDoug Maxey 3581afaf5a2dSDavid Somayajulu unregister_transport: 3582afaf5a2dSDavid Somayajulu iscsi_unregister_transport(&qla4xxx_iscsi_transport); 3583afaf5a2dSDavid Somayajulu release_srb_cache: 3584afaf5a2dSDavid Somayajulu kmem_cache_destroy(srb_cachep); 3585afaf5a2dSDavid Somayajulu no_srp_cache: 3586afaf5a2dSDavid Somayajulu return ret; 3587afaf5a2dSDavid Somayajulu } 3588afaf5a2dSDavid Somayajulu 3589afaf5a2dSDavid Somayajulu static void __exit qla4xxx_module_exit(void) 3590afaf5a2dSDavid Somayajulu { 3591afaf5a2dSDavid Somayajulu pci_unregister_driver(&qla4xxx_pci_driver); 3592afaf5a2dSDavid Somayajulu iscsi_unregister_transport(&qla4xxx_iscsi_transport); 3593afaf5a2dSDavid Somayajulu kmem_cache_destroy(srb_cachep); 3594afaf5a2dSDavid Somayajulu } 3595afaf5a2dSDavid Somayajulu 3596afaf5a2dSDavid Somayajulu module_init(qla4xxx_module_init); 3597afaf5a2dSDavid Somayajulu module_exit(qla4xxx_module_exit); 3598afaf5a2dSDavid Somayajulu 3599afaf5a2dSDavid Somayajulu MODULE_AUTHOR("QLogic Corporation"); 3600afaf5a2dSDavid Somayajulu MODULE_DESCRIPTION("QLogic iSCSI HBA Driver"); 3601afaf5a2dSDavid Somayajulu MODULE_LICENSE("GPL"); 3602afaf5a2dSDavid Somayajulu MODULE_VERSION(QLA4XXX_DRIVER_VERSION); 3603