1afaf5a2dSDavid Somayajulu /* 2afaf5a2dSDavid Somayajulu * QLogic iSCSI HBA Driver 37d01d069SVikas Chaudhary * Copyright (c) 2003-2010 QLogic Corporation 4afaf5a2dSDavid Somayajulu * 5afaf5a2dSDavid Somayajulu * See LICENSE.qla4xxx for copyright and licensing details. 6afaf5a2dSDavid Somayajulu */ 7afaf5a2dSDavid Somayajulu #include <linux/moduleparam.h> 85a0e3ad6STejun Heo #include <linux/slab.h> 92a991c21SManish Rangankar #include <linux/blkdev.h> 102a991c21SManish Rangankar #include <linux/iscsi_boot_sysfs.h> 11afaf5a2dSDavid Somayajulu 12afaf5a2dSDavid Somayajulu #include <scsi/scsi_tcq.h> 13afaf5a2dSDavid Somayajulu #include <scsi/scsicam.h> 14afaf5a2dSDavid Somayajulu 15afaf5a2dSDavid Somayajulu #include "ql4_def.h" 16bee4fe8eSDavid C Somayajulu #include "ql4_version.h" 17bee4fe8eSDavid C Somayajulu #include "ql4_glbl.h" 18bee4fe8eSDavid C Somayajulu #include "ql4_dbg.h" 19bee4fe8eSDavid C Somayajulu #include "ql4_inline.h" 20afaf5a2dSDavid Somayajulu 21afaf5a2dSDavid Somayajulu /* 22afaf5a2dSDavid Somayajulu * Driver version 23afaf5a2dSDavid Somayajulu */ 2447975477SAdrian Bunk static char qla4xxx_version_str[40]; 25afaf5a2dSDavid Somayajulu 26afaf5a2dSDavid Somayajulu /* 27afaf5a2dSDavid Somayajulu * SRB allocation cache 28afaf5a2dSDavid Somayajulu */ 29e18b890bSChristoph Lameter static struct kmem_cache *srb_cachep; 30afaf5a2dSDavid Somayajulu 31afaf5a2dSDavid Somayajulu /* 32afaf5a2dSDavid Somayajulu * Module parameter information and variables 33afaf5a2dSDavid Somayajulu */ 34afaf5a2dSDavid Somayajulu int ql4xdontresethba = 0; 35f4f5df23SVikas Chaudhary module_param(ql4xdontresethba, int, S_IRUGO | S_IWUSR); 36afaf5a2dSDavid Somayajulu MODULE_PARM_DESC(ql4xdontresethba, 37f4f5df23SVikas Chaudhary "Don't reset the HBA for driver recovery \n" 38f4f5df23SVikas Chaudhary " 0 - It will reset HBA (Default)\n" 39f4f5df23SVikas Chaudhary " 1 - It will NOT reset HBA"); 40afaf5a2dSDavid Somayajulu 4111010fecSAndrew Vasquez int ql4xextended_error_logging = 0; /* 0 = off, 1 = log errors */ 42f4f5df23SVikas Chaudhary module_param(ql4xextended_error_logging, int, S_IRUGO | S_IWUSR); 4311010fecSAndrew Vasquez MODULE_PARM_DESC(ql4xextended_error_logging, 44afaf5a2dSDavid Somayajulu "Option to enable extended error logging, " 45afaf5a2dSDavid Somayajulu "Default is 0 - no logging, 1 - debug logging"); 46afaf5a2dSDavid Somayajulu 47f4f5df23SVikas Chaudhary int ql4xenablemsix = 1; 48f4f5df23SVikas Chaudhary module_param(ql4xenablemsix, int, S_IRUGO|S_IWUSR); 49f4f5df23SVikas Chaudhary MODULE_PARM_DESC(ql4xenablemsix, 50f4f5df23SVikas Chaudhary "Set to enable MSI or MSI-X interrupt mechanism.\n" 51f4f5df23SVikas Chaudhary " 0 = enable INTx interrupt mechanism.\n" 52f4f5df23SVikas Chaudhary " 1 = enable MSI-X interrupt mechanism (Default).\n" 53f4f5df23SVikas Chaudhary " 2 = enable MSI interrupt mechanism."); 54477ffb9dSDavid C Somayajulu 55d510d965SMike Christie #define QL4_DEF_QDEPTH 32 568bb4033dSVikas Chaudhary static int ql4xmaxqdepth = QL4_DEF_QDEPTH; 578bb4033dSVikas Chaudhary module_param(ql4xmaxqdepth, int, S_IRUGO | S_IWUSR); 588bb4033dSVikas Chaudhary MODULE_PARM_DESC(ql4xmaxqdepth, 598bb4033dSVikas Chaudhary "Maximum queue depth to report for target devices.\n" 608bb4033dSVikas Chaudhary " Default: 32."); 61d510d965SMike Christie 623038727cSVikas Chaudhary static int ql4xsess_recovery_tmo = QL4_SESS_RECOVERY_TMO; 633038727cSVikas Chaudhary module_param(ql4xsess_recovery_tmo, int, S_IRUGO); 643038727cSVikas Chaudhary MODULE_PARM_DESC(ql4xsess_recovery_tmo, 653038727cSVikas Chaudhary "Target Session Recovery Timeout.\n" 663038727cSVikas Chaudhary " Default: 30 sec."); 673038727cSVikas Chaudhary 68b3a271a9SManish Rangankar static int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha); 69afaf5a2dSDavid Somayajulu /* 70afaf5a2dSDavid Somayajulu * SCSI host template entry points 71afaf5a2dSDavid Somayajulu */ 7247975477SAdrian Bunk static void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha); 73afaf5a2dSDavid Somayajulu 74afaf5a2dSDavid Somayajulu /* 75afaf5a2dSDavid Somayajulu * iSCSI template entry points 76afaf5a2dSDavid Somayajulu */ 77afaf5a2dSDavid Somayajulu static int qla4xxx_conn_get_param(struct iscsi_cls_conn *conn, 78afaf5a2dSDavid Somayajulu enum iscsi_param param, char *buf); 79aa1e93a2SMike Christie static int qla4xxx_host_get_param(struct Scsi_Host *shost, 80aa1e93a2SMike Christie enum iscsi_host_param param, char *buf); 81d00efe3fSMike Christie static int qla4xxx_iface_set_param(struct Scsi_Host *shost, char *data, 82d00efe3fSMike Christie int count); 83ed1086e0SVikas Chaudhary static int qla4xxx_get_iface_param(struct iscsi_iface *iface, 84ed1086e0SVikas Chaudhary enum iscsi_param_type param_type, 85ed1086e0SVikas Chaudhary int param, char *buf); 865c656af7SMike Christie static enum blk_eh_timer_return qla4xxx_eh_cmd_timed_out(struct scsi_cmnd *sc); 87b3a271a9SManish Rangankar static struct iscsi_endpoint *qla4xxx_ep_connect(struct Scsi_Host *shost, 88b3a271a9SManish Rangankar struct sockaddr *dst_addr, 89b3a271a9SManish Rangankar int non_blocking); 90b3a271a9SManish Rangankar static int qla4xxx_ep_poll(struct iscsi_endpoint *ep, int timeout_ms); 91b3a271a9SManish Rangankar static void qla4xxx_ep_disconnect(struct iscsi_endpoint *ep); 92b3a271a9SManish Rangankar static int qla4xxx_get_ep_param(struct iscsi_endpoint *ep, 93b3a271a9SManish Rangankar enum iscsi_param param, char *buf); 94b3a271a9SManish Rangankar static int qla4xxx_conn_start(struct iscsi_cls_conn *conn); 95b3a271a9SManish Rangankar static struct iscsi_cls_conn * 96b3a271a9SManish Rangankar qla4xxx_conn_create(struct iscsi_cls_session *cls_sess, uint32_t conn_idx); 97b3a271a9SManish Rangankar static int qla4xxx_conn_bind(struct iscsi_cls_session *cls_session, 98b3a271a9SManish Rangankar struct iscsi_cls_conn *cls_conn, 99b3a271a9SManish Rangankar uint64_t transport_fd, int is_leading); 100b3a271a9SManish Rangankar static void qla4xxx_conn_destroy(struct iscsi_cls_conn *conn); 101b3a271a9SManish Rangankar static struct iscsi_cls_session * 102b3a271a9SManish Rangankar qla4xxx_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max, 103b3a271a9SManish Rangankar uint16_t qdepth, uint32_t initial_cmdsn); 104b3a271a9SManish Rangankar static void qla4xxx_session_destroy(struct iscsi_cls_session *sess); 105b3a271a9SManish Rangankar static void qla4xxx_task_work(struct work_struct *wdata); 106b3a271a9SManish Rangankar static int qla4xxx_alloc_pdu(struct iscsi_task *, uint8_t); 107b3a271a9SManish Rangankar static int qla4xxx_task_xmit(struct iscsi_task *); 108b3a271a9SManish Rangankar static void qla4xxx_task_cleanup(struct iscsi_task *); 109b3a271a9SManish Rangankar static void qla4xxx_fail_session(struct iscsi_cls_session *cls_session); 110b3a271a9SManish Rangankar static void qla4xxx_conn_get_stats(struct iscsi_cls_conn *cls_conn, 111b3a271a9SManish Rangankar struct iscsi_stats *stats); 112afaf5a2dSDavid Somayajulu /* 113afaf5a2dSDavid Somayajulu * SCSI host template entry points 114afaf5a2dSDavid Somayajulu */ 115f281233dSJeff Garzik static int qla4xxx_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *cmd); 11609a0f719SVikas Chaudhary static int qla4xxx_eh_abort(struct scsi_cmnd *cmd); 117afaf5a2dSDavid Somayajulu static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd); 118ce545039SMike Christie static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd); 119afaf5a2dSDavid Somayajulu static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd); 120afaf5a2dSDavid Somayajulu static int qla4xxx_slave_alloc(struct scsi_device *device); 121afaf5a2dSDavid Somayajulu static int qla4xxx_slave_configure(struct scsi_device *device); 122afaf5a2dSDavid Somayajulu static void qla4xxx_slave_destroy(struct scsi_device *sdev); 1233128c6c7SMike Christie static mode_t ql4_attr_is_visible(int param_type, int param); 12495d31262SVikas Chaudhary static int qla4xxx_host_reset(struct Scsi_Host *shost, int reset_type); 125afaf5a2dSDavid Somayajulu 126f4f5df23SVikas Chaudhary static struct qla4_8xxx_legacy_intr_set legacy_intr[] = 127f4f5df23SVikas Chaudhary QLA82XX_LEGACY_INTR_CONFIG; 128f4f5df23SVikas Chaudhary 129afaf5a2dSDavid Somayajulu static struct scsi_host_template qla4xxx_driver_template = { 130afaf5a2dSDavid Somayajulu .module = THIS_MODULE, 131afaf5a2dSDavid Somayajulu .name = DRIVER_NAME, 132afaf5a2dSDavid Somayajulu .proc_name = DRIVER_NAME, 133afaf5a2dSDavid Somayajulu .queuecommand = qla4xxx_queuecommand, 134afaf5a2dSDavid Somayajulu 13509a0f719SVikas Chaudhary .eh_abort_handler = qla4xxx_eh_abort, 136afaf5a2dSDavid Somayajulu .eh_device_reset_handler = qla4xxx_eh_device_reset, 137ce545039SMike Christie .eh_target_reset_handler = qla4xxx_eh_target_reset, 138afaf5a2dSDavid Somayajulu .eh_host_reset_handler = qla4xxx_eh_host_reset, 1395c656af7SMike Christie .eh_timed_out = qla4xxx_eh_cmd_timed_out, 140afaf5a2dSDavid Somayajulu 141afaf5a2dSDavid Somayajulu .slave_configure = qla4xxx_slave_configure, 142afaf5a2dSDavid Somayajulu .slave_alloc = qla4xxx_slave_alloc, 143afaf5a2dSDavid Somayajulu .slave_destroy = qla4xxx_slave_destroy, 144afaf5a2dSDavid Somayajulu 145afaf5a2dSDavid Somayajulu .this_id = -1, 146afaf5a2dSDavid Somayajulu .cmd_per_lun = 3, 147afaf5a2dSDavid Somayajulu .use_clustering = ENABLE_CLUSTERING, 148afaf5a2dSDavid Somayajulu .sg_tablesize = SG_ALL, 149afaf5a2dSDavid Somayajulu 150afaf5a2dSDavid Somayajulu .max_sectors = 0xFFFF, 1517ad633c0SHarish Zunjarrao .shost_attrs = qla4xxx_host_attrs, 15295d31262SVikas Chaudhary .host_reset = qla4xxx_host_reset, 153a355943cSVikas Chaudhary .vendor_id = SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_QLOGIC, 154afaf5a2dSDavid Somayajulu }; 155afaf5a2dSDavid Somayajulu 156afaf5a2dSDavid Somayajulu static struct iscsi_transport qla4xxx_iscsi_transport = { 157afaf5a2dSDavid Somayajulu .owner = THIS_MODULE, 158afaf5a2dSDavid Somayajulu .name = DRIVER_NAME, 159b3a271a9SManish Rangankar .caps = CAP_TEXT_NEGO | 160b3a271a9SManish Rangankar CAP_DATA_PATH_OFFLOAD | CAP_HDRDGST | 161b3a271a9SManish Rangankar CAP_DATADGST | CAP_LOGIN_OFFLOAD | 162b3a271a9SManish Rangankar CAP_MULTI_R2T, 1633128c6c7SMike Christie .attr_is_visible = ql4_attr_is_visible, 164b3a271a9SManish Rangankar .create_session = qla4xxx_session_create, 165b3a271a9SManish Rangankar .destroy_session = qla4xxx_session_destroy, 166b3a271a9SManish Rangankar .start_conn = qla4xxx_conn_start, 167b3a271a9SManish Rangankar .create_conn = qla4xxx_conn_create, 168b3a271a9SManish Rangankar .bind_conn = qla4xxx_conn_bind, 169b3a271a9SManish Rangankar .stop_conn = iscsi_conn_stop, 170b3a271a9SManish Rangankar .destroy_conn = qla4xxx_conn_destroy, 171b3a271a9SManish Rangankar .set_param = iscsi_set_param, 172afaf5a2dSDavid Somayajulu .get_conn_param = qla4xxx_conn_get_param, 173b3a271a9SManish Rangankar .get_session_param = iscsi_session_get_param, 174b3a271a9SManish Rangankar .get_ep_param = qla4xxx_get_ep_param, 175b3a271a9SManish Rangankar .ep_connect = qla4xxx_ep_connect, 176b3a271a9SManish Rangankar .ep_poll = qla4xxx_ep_poll, 177b3a271a9SManish Rangankar .ep_disconnect = qla4xxx_ep_disconnect, 178b3a271a9SManish Rangankar .get_stats = qla4xxx_conn_get_stats, 179b3a271a9SManish Rangankar .send_pdu = iscsi_conn_send_pdu, 180b3a271a9SManish Rangankar .xmit_task = qla4xxx_task_xmit, 181b3a271a9SManish Rangankar .cleanup_task = qla4xxx_task_cleanup, 182b3a271a9SManish Rangankar .alloc_pdu = qla4xxx_alloc_pdu, 183b3a271a9SManish Rangankar 184aa1e93a2SMike Christie .get_host_param = qla4xxx_host_get_param, 185d00efe3fSMike Christie .set_iface_param = qla4xxx_iface_set_param, 186ed1086e0SVikas Chaudhary .get_iface_param = qla4xxx_get_iface_param, 187a355943cSVikas Chaudhary .bsg_request = qla4xxx_bsg_request, 188afaf5a2dSDavid Somayajulu }; 189afaf5a2dSDavid Somayajulu 190afaf5a2dSDavid Somayajulu static struct scsi_transport_template *qla4xxx_scsi_transport; 191afaf5a2dSDavid Somayajulu 1923128c6c7SMike Christie static mode_t ql4_attr_is_visible(int param_type, int param) 1933128c6c7SMike Christie { 1943128c6c7SMike Christie switch (param_type) { 195f27fb2efSMike Christie case ISCSI_HOST_PARAM: 196f27fb2efSMike Christie switch (param) { 197f27fb2efSMike Christie case ISCSI_HOST_PARAM_HWADDRESS: 198f27fb2efSMike Christie case ISCSI_HOST_PARAM_IPADDRESS: 199f27fb2efSMike Christie case ISCSI_HOST_PARAM_INITIATOR_NAME: 200f27fb2efSMike Christie return S_IRUGO; 201f27fb2efSMike Christie default: 202f27fb2efSMike Christie return 0; 203f27fb2efSMike Christie } 2043128c6c7SMike Christie case ISCSI_PARAM: 2053128c6c7SMike Christie switch (param) { 2063128c6c7SMike Christie case ISCSI_PARAM_CONN_ADDRESS: 2073128c6c7SMike Christie case ISCSI_PARAM_CONN_PORT: 2081d063c17SMike Christie case ISCSI_PARAM_TARGET_NAME: 2091d063c17SMike Christie case ISCSI_PARAM_TPGT: 2101d063c17SMike Christie case ISCSI_PARAM_TARGET_ALIAS: 211b3a271a9SManish Rangankar case ISCSI_PARAM_MAX_BURST: 212b3a271a9SManish Rangankar case ISCSI_PARAM_MAX_R2T: 213b3a271a9SManish Rangankar case ISCSI_PARAM_FIRST_BURST: 214b3a271a9SManish Rangankar case ISCSI_PARAM_MAX_RECV_DLENGTH: 215b3a271a9SManish Rangankar case ISCSI_PARAM_MAX_XMIT_DLENGTH: 216de37920bSMike Christie case ISCSI_PARAM_IFACE_NAME: 2173128c6c7SMike Christie return S_IRUGO; 2183128c6c7SMike Christie default: 2193128c6c7SMike Christie return 0; 2203128c6c7SMike Christie } 221b78dbba0SMike Christie case ISCSI_NET_PARAM: 222b78dbba0SMike Christie switch (param) { 223b78dbba0SMike Christie case ISCSI_NET_PARAM_IPV4_ADDR: 224b78dbba0SMike Christie case ISCSI_NET_PARAM_IPV4_SUBNET: 225b78dbba0SMike Christie case ISCSI_NET_PARAM_IPV4_GW: 226b78dbba0SMike Christie case ISCSI_NET_PARAM_IPV4_BOOTPROTO: 227b78dbba0SMike Christie case ISCSI_NET_PARAM_IFACE_ENABLE: 228b78dbba0SMike Christie case ISCSI_NET_PARAM_IPV6_LINKLOCAL: 229b78dbba0SMike Christie case ISCSI_NET_PARAM_IPV6_ADDR: 230b78dbba0SMike Christie case ISCSI_NET_PARAM_IPV6_ROUTER: 231b78dbba0SMike Christie case ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG: 232b78dbba0SMike Christie case ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG: 2336ac73e8cSVikas Chaudhary case ISCSI_NET_PARAM_VLAN_ID: 2346ac73e8cSVikas Chaudhary case ISCSI_NET_PARAM_VLAN_PRIORITY: 2356ac73e8cSVikas Chaudhary case ISCSI_NET_PARAM_VLAN_ENABLED: 236943c157bSVikas Chaudhary case ISCSI_NET_PARAM_MTU: 2372ada7fc5SVikas Chaudhary case ISCSI_NET_PARAM_PORT: 238b78dbba0SMike Christie return S_IRUGO; 239b78dbba0SMike Christie default: 240b78dbba0SMike Christie return 0; 241b78dbba0SMike Christie } 2423128c6c7SMike Christie } 2433128c6c7SMike Christie 2443128c6c7SMike Christie return 0; 2453128c6c7SMike Christie } 2463128c6c7SMike Christie 247ed1086e0SVikas Chaudhary static int qla4xxx_get_iface_param(struct iscsi_iface *iface, 248ed1086e0SVikas Chaudhary enum iscsi_param_type param_type, 249ed1086e0SVikas Chaudhary int param, char *buf) 250ed1086e0SVikas Chaudhary { 251ed1086e0SVikas Chaudhary struct Scsi_Host *shost = iscsi_iface_to_shost(iface); 252ed1086e0SVikas Chaudhary struct scsi_qla_host *ha = to_qla_host(shost); 253ed1086e0SVikas Chaudhary int len = -ENOSYS; 254ed1086e0SVikas Chaudhary 255ed1086e0SVikas Chaudhary if (param_type != ISCSI_NET_PARAM) 256ed1086e0SVikas Chaudhary return -ENOSYS; 257ed1086e0SVikas Chaudhary 258ed1086e0SVikas Chaudhary switch (param) { 259ed1086e0SVikas Chaudhary case ISCSI_NET_PARAM_IPV4_ADDR: 260ed1086e0SVikas Chaudhary len = sprintf(buf, "%pI4\n", &ha->ip_config.ip_address); 261ed1086e0SVikas Chaudhary break; 262ed1086e0SVikas Chaudhary case ISCSI_NET_PARAM_IPV4_SUBNET: 263ed1086e0SVikas Chaudhary len = sprintf(buf, "%pI4\n", &ha->ip_config.subnet_mask); 264ed1086e0SVikas Chaudhary break; 265ed1086e0SVikas Chaudhary case ISCSI_NET_PARAM_IPV4_GW: 266ed1086e0SVikas Chaudhary len = sprintf(buf, "%pI4\n", &ha->ip_config.gateway); 267ed1086e0SVikas Chaudhary break; 268ed1086e0SVikas Chaudhary case ISCSI_NET_PARAM_IFACE_ENABLE: 269ed1086e0SVikas Chaudhary if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) 270ed1086e0SVikas Chaudhary len = sprintf(buf, "%s\n", 271ed1086e0SVikas Chaudhary (ha->ip_config.ipv4_options & 272ed1086e0SVikas Chaudhary IPOPT_IPV4_PROTOCOL_ENABLE) ? 273ed1086e0SVikas Chaudhary "enabled" : "disabled"); 274ed1086e0SVikas Chaudhary else if (iface->iface_type == ISCSI_IFACE_TYPE_IPV6) 275ed1086e0SVikas Chaudhary len = sprintf(buf, "%s\n", 276ed1086e0SVikas Chaudhary (ha->ip_config.ipv6_options & 277ed1086e0SVikas Chaudhary IPV6_OPT_IPV6_PROTOCOL_ENABLE) ? 278ed1086e0SVikas Chaudhary "enabled" : "disabled"); 279ed1086e0SVikas Chaudhary break; 280ed1086e0SVikas Chaudhary case ISCSI_NET_PARAM_IPV4_BOOTPROTO: 281ed1086e0SVikas Chaudhary len = sprintf(buf, "%s\n", 282ed1086e0SVikas Chaudhary (ha->ip_config.tcp_options & TCPOPT_DHCP_ENABLE) ? 283ed1086e0SVikas Chaudhary "dhcp" : "static"); 284ed1086e0SVikas Chaudhary break; 285ed1086e0SVikas Chaudhary case ISCSI_NET_PARAM_IPV6_ADDR: 286ed1086e0SVikas Chaudhary if (iface->iface_num == 0) 287ed1086e0SVikas Chaudhary len = sprintf(buf, "%pI6\n", &ha->ip_config.ipv6_addr0); 288ed1086e0SVikas Chaudhary if (iface->iface_num == 1) 289ed1086e0SVikas Chaudhary len = sprintf(buf, "%pI6\n", &ha->ip_config.ipv6_addr1); 290ed1086e0SVikas Chaudhary break; 291ed1086e0SVikas Chaudhary case ISCSI_NET_PARAM_IPV6_LINKLOCAL: 292ed1086e0SVikas Chaudhary len = sprintf(buf, "%pI6\n", 293ed1086e0SVikas Chaudhary &ha->ip_config.ipv6_link_local_addr); 294ed1086e0SVikas Chaudhary break; 295ed1086e0SVikas Chaudhary case ISCSI_NET_PARAM_IPV6_ROUTER: 296ed1086e0SVikas Chaudhary len = sprintf(buf, "%pI6\n", 297ed1086e0SVikas Chaudhary &ha->ip_config.ipv6_default_router_addr); 298ed1086e0SVikas Chaudhary break; 299ed1086e0SVikas Chaudhary case ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG: 300ed1086e0SVikas Chaudhary len = sprintf(buf, "%s\n", 301ed1086e0SVikas Chaudhary (ha->ip_config.ipv6_addl_options & 302ed1086e0SVikas Chaudhary IPV6_ADDOPT_NEIGHBOR_DISCOVERY_ADDR_ENABLE) ? 303ed1086e0SVikas Chaudhary "nd" : "static"); 304ed1086e0SVikas Chaudhary break; 305ed1086e0SVikas Chaudhary case ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG: 306ed1086e0SVikas Chaudhary len = sprintf(buf, "%s\n", 307ed1086e0SVikas Chaudhary (ha->ip_config.ipv6_addl_options & 308ed1086e0SVikas Chaudhary IPV6_ADDOPT_AUTOCONFIG_LINK_LOCAL_ADDR) ? 309ed1086e0SVikas Chaudhary "auto" : "static"); 310ed1086e0SVikas Chaudhary break; 3116ac73e8cSVikas Chaudhary case ISCSI_NET_PARAM_VLAN_ID: 3126ac73e8cSVikas Chaudhary if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) 3136ac73e8cSVikas Chaudhary len = sprintf(buf, "%d\n", 3146ac73e8cSVikas Chaudhary (ha->ip_config.ipv4_vlan_tag & 3156ac73e8cSVikas Chaudhary ISCSI_MAX_VLAN_ID)); 3166ac73e8cSVikas Chaudhary else if (iface->iface_type == ISCSI_IFACE_TYPE_IPV6) 3176ac73e8cSVikas Chaudhary len = sprintf(buf, "%d\n", 3186ac73e8cSVikas Chaudhary (ha->ip_config.ipv6_vlan_tag & 3196ac73e8cSVikas Chaudhary ISCSI_MAX_VLAN_ID)); 3206ac73e8cSVikas Chaudhary break; 3216ac73e8cSVikas Chaudhary case ISCSI_NET_PARAM_VLAN_PRIORITY: 3226ac73e8cSVikas Chaudhary if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) 3236ac73e8cSVikas Chaudhary len = sprintf(buf, "%d\n", 3246ac73e8cSVikas Chaudhary ((ha->ip_config.ipv4_vlan_tag >> 13) & 3256ac73e8cSVikas Chaudhary ISCSI_MAX_VLAN_PRIORITY)); 3266ac73e8cSVikas Chaudhary else if (iface->iface_type == ISCSI_IFACE_TYPE_IPV6) 3276ac73e8cSVikas Chaudhary len = sprintf(buf, "%d\n", 3286ac73e8cSVikas Chaudhary ((ha->ip_config.ipv6_vlan_tag >> 13) & 3296ac73e8cSVikas Chaudhary ISCSI_MAX_VLAN_PRIORITY)); 3306ac73e8cSVikas Chaudhary break; 3316ac73e8cSVikas Chaudhary case ISCSI_NET_PARAM_VLAN_ENABLED: 3326ac73e8cSVikas Chaudhary if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) 3336ac73e8cSVikas Chaudhary len = sprintf(buf, "%s\n", 3346ac73e8cSVikas Chaudhary (ha->ip_config.ipv4_options & 3356ac73e8cSVikas Chaudhary IPOPT_VLAN_TAGGING_ENABLE) ? 3366ac73e8cSVikas Chaudhary "enabled" : "disabled"); 3376ac73e8cSVikas Chaudhary else if (iface->iface_type == ISCSI_IFACE_TYPE_IPV6) 3386ac73e8cSVikas Chaudhary len = sprintf(buf, "%s\n", 3396ac73e8cSVikas Chaudhary (ha->ip_config.ipv6_options & 3406ac73e8cSVikas Chaudhary IPV6_OPT_VLAN_TAGGING_ENABLE) ? 3416ac73e8cSVikas Chaudhary "enabled" : "disabled"); 3426ac73e8cSVikas Chaudhary break; 343943c157bSVikas Chaudhary case ISCSI_NET_PARAM_MTU: 344943c157bSVikas Chaudhary len = sprintf(buf, "%d\n", ha->ip_config.eth_mtu_size); 345943c157bSVikas Chaudhary break; 3462ada7fc5SVikas Chaudhary case ISCSI_NET_PARAM_PORT: 3472ada7fc5SVikas Chaudhary if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) 3482ada7fc5SVikas Chaudhary len = sprintf(buf, "%d\n", ha->ip_config.ipv4_port); 3492ada7fc5SVikas Chaudhary else if (iface->iface_type == ISCSI_IFACE_TYPE_IPV6) 3502ada7fc5SVikas Chaudhary len = sprintf(buf, "%d\n", ha->ip_config.ipv6_port); 3512ada7fc5SVikas Chaudhary break; 352ed1086e0SVikas Chaudhary default: 353ed1086e0SVikas Chaudhary len = -ENOSYS; 354ed1086e0SVikas Chaudhary } 355ed1086e0SVikas Chaudhary 356ed1086e0SVikas Chaudhary return len; 357ed1086e0SVikas Chaudhary } 358ed1086e0SVikas Chaudhary 359b3a271a9SManish Rangankar static struct iscsi_endpoint * 360b3a271a9SManish Rangankar qla4xxx_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr, 361b3a271a9SManish Rangankar int non_blocking) 362b3a271a9SManish Rangankar { 363b3a271a9SManish Rangankar int ret; 364b3a271a9SManish Rangankar struct iscsi_endpoint *ep; 365b3a271a9SManish Rangankar struct qla_endpoint *qla_ep; 366b3a271a9SManish Rangankar struct scsi_qla_host *ha; 367b3a271a9SManish Rangankar struct sockaddr_in *addr; 368b3a271a9SManish Rangankar struct sockaddr_in6 *addr6; 369b3a271a9SManish Rangankar 370b3a271a9SManish Rangankar DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); 371b3a271a9SManish Rangankar if (!shost) { 372b3a271a9SManish Rangankar ret = -ENXIO; 373b3a271a9SManish Rangankar printk(KERN_ERR "%s: shost is NULL\n", 374b3a271a9SManish Rangankar __func__); 375b3a271a9SManish Rangankar return ERR_PTR(ret); 376b3a271a9SManish Rangankar } 377b3a271a9SManish Rangankar 378b3a271a9SManish Rangankar ha = iscsi_host_priv(shost); 379b3a271a9SManish Rangankar 380b3a271a9SManish Rangankar ep = iscsi_create_endpoint(sizeof(struct qla_endpoint)); 381b3a271a9SManish Rangankar if (!ep) { 382b3a271a9SManish Rangankar ret = -ENOMEM; 383b3a271a9SManish Rangankar return ERR_PTR(ret); 384b3a271a9SManish Rangankar } 385b3a271a9SManish Rangankar 386b3a271a9SManish Rangankar qla_ep = ep->dd_data; 387b3a271a9SManish Rangankar memset(qla_ep, 0, sizeof(struct qla_endpoint)); 388b3a271a9SManish Rangankar if (dst_addr->sa_family == AF_INET) { 389b3a271a9SManish Rangankar memcpy(&qla_ep->dst_addr, dst_addr, sizeof(struct sockaddr_in)); 390b3a271a9SManish Rangankar addr = (struct sockaddr_in *)&qla_ep->dst_addr; 391b3a271a9SManish Rangankar DEBUG2(ql4_printk(KERN_INFO, ha, "%s: %pI4\n", __func__, 392b3a271a9SManish Rangankar (char *)&addr->sin_addr)); 393b3a271a9SManish Rangankar } else if (dst_addr->sa_family == AF_INET6) { 394b3a271a9SManish Rangankar memcpy(&qla_ep->dst_addr, dst_addr, 395b3a271a9SManish Rangankar sizeof(struct sockaddr_in6)); 396b3a271a9SManish Rangankar addr6 = (struct sockaddr_in6 *)&qla_ep->dst_addr; 397b3a271a9SManish Rangankar DEBUG2(ql4_printk(KERN_INFO, ha, "%s: %pI6\n", __func__, 398b3a271a9SManish Rangankar (char *)&addr6->sin6_addr)); 399b3a271a9SManish Rangankar } 400b3a271a9SManish Rangankar 401b3a271a9SManish Rangankar qla_ep->host = shost; 402b3a271a9SManish Rangankar 403b3a271a9SManish Rangankar return ep; 404b3a271a9SManish Rangankar } 405b3a271a9SManish Rangankar 406b3a271a9SManish Rangankar static int qla4xxx_ep_poll(struct iscsi_endpoint *ep, int timeout_ms) 407b3a271a9SManish Rangankar { 408b3a271a9SManish Rangankar struct qla_endpoint *qla_ep; 409b3a271a9SManish Rangankar struct scsi_qla_host *ha; 410b3a271a9SManish Rangankar int ret = 0; 411b3a271a9SManish Rangankar 412b3a271a9SManish Rangankar DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); 413b3a271a9SManish Rangankar qla_ep = ep->dd_data; 414b3a271a9SManish Rangankar ha = to_qla_host(qla_ep->host); 415b3a271a9SManish Rangankar 416b3a271a9SManish Rangankar if (adapter_up(ha)) 417b3a271a9SManish Rangankar ret = 1; 418b3a271a9SManish Rangankar 419b3a271a9SManish Rangankar return ret; 420b3a271a9SManish Rangankar } 421b3a271a9SManish Rangankar 422b3a271a9SManish Rangankar static void qla4xxx_ep_disconnect(struct iscsi_endpoint *ep) 423b3a271a9SManish Rangankar { 424b3a271a9SManish Rangankar DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); 425b3a271a9SManish Rangankar iscsi_destroy_endpoint(ep); 426b3a271a9SManish Rangankar } 427b3a271a9SManish Rangankar 428b3a271a9SManish Rangankar static int qla4xxx_get_ep_param(struct iscsi_endpoint *ep, 429b3a271a9SManish Rangankar enum iscsi_param param, 430b3a271a9SManish Rangankar char *buf) 431b3a271a9SManish Rangankar { 432b3a271a9SManish Rangankar struct qla_endpoint *qla_ep = ep->dd_data; 433b3a271a9SManish Rangankar struct sockaddr *dst_addr; 434b3a271a9SManish Rangankar 435b3a271a9SManish Rangankar DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); 436b3a271a9SManish Rangankar 437b3a271a9SManish Rangankar switch (param) { 438b3a271a9SManish Rangankar case ISCSI_PARAM_CONN_PORT: 439b3a271a9SManish Rangankar case ISCSI_PARAM_CONN_ADDRESS: 440b3a271a9SManish Rangankar if (!qla_ep) 441b3a271a9SManish Rangankar return -ENOTCONN; 442b3a271a9SManish Rangankar 443b3a271a9SManish Rangankar dst_addr = (struct sockaddr *)&qla_ep->dst_addr; 444b3a271a9SManish Rangankar if (!dst_addr) 445b3a271a9SManish Rangankar return -ENOTCONN; 446b3a271a9SManish Rangankar 447b3a271a9SManish Rangankar return iscsi_conn_get_addr_param((struct sockaddr_storage *) 448b3a271a9SManish Rangankar &qla_ep->dst_addr, param, buf); 449b3a271a9SManish Rangankar default: 450b3a271a9SManish Rangankar return -ENOSYS; 451b3a271a9SManish Rangankar } 452b3a271a9SManish Rangankar } 453b3a271a9SManish Rangankar 454b3a271a9SManish Rangankar static void qla4xxx_conn_get_stats(struct iscsi_cls_conn *cls_conn, 455b3a271a9SManish Rangankar struct iscsi_stats *stats) 456b3a271a9SManish Rangankar { 457b3a271a9SManish Rangankar struct iscsi_session *sess; 458b3a271a9SManish Rangankar struct iscsi_cls_session *cls_sess; 459b3a271a9SManish Rangankar struct ddb_entry *ddb_entry; 460b3a271a9SManish Rangankar struct scsi_qla_host *ha; 461b3a271a9SManish Rangankar struct ql_iscsi_stats *ql_iscsi_stats; 462b3a271a9SManish Rangankar int stats_size; 463b3a271a9SManish Rangankar int ret; 464b3a271a9SManish Rangankar dma_addr_t iscsi_stats_dma; 465b3a271a9SManish Rangankar 466b3a271a9SManish Rangankar DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); 467b3a271a9SManish Rangankar 468b3a271a9SManish Rangankar cls_sess = iscsi_conn_to_session(cls_conn); 469b3a271a9SManish Rangankar sess = cls_sess->dd_data; 470b3a271a9SManish Rangankar ddb_entry = sess->dd_data; 471b3a271a9SManish Rangankar ha = ddb_entry->ha; 472b3a271a9SManish Rangankar 473b3a271a9SManish Rangankar stats_size = PAGE_ALIGN(sizeof(struct ql_iscsi_stats)); 474b3a271a9SManish Rangankar /* Allocate memory */ 475b3a271a9SManish Rangankar ql_iscsi_stats = dma_alloc_coherent(&ha->pdev->dev, stats_size, 476b3a271a9SManish Rangankar &iscsi_stats_dma, GFP_KERNEL); 477b3a271a9SManish Rangankar if (!ql_iscsi_stats) { 478b3a271a9SManish Rangankar ql4_printk(KERN_ERR, ha, 479b3a271a9SManish Rangankar "Unable to allocate memory for iscsi stats\n"); 480b3a271a9SManish Rangankar goto exit_get_stats; 481b3a271a9SManish Rangankar } 482b3a271a9SManish Rangankar 483b3a271a9SManish Rangankar ret = qla4xxx_get_mgmt_data(ha, ddb_entry->fw_ddb_index, stats_size, 484b3a271a9SManish Rangankar iscsi_stats_dma); 485b3a271a9SManish Rangankar if (ret != QLA_SUCCESS) { 486b3a271a9SManish Rangankar ql4_printk(KERN_ERR, ha, 487b3a271a9SManish Rangankar "Unable to retreive iscsi stats\n"); 488b3a271a9SManish Rangankar goto free_stats; 489b3a271a9SManish Rangankar } 490b3a271a9SManish Rangankar 491b3a271a9SManish Rangankar /* octets */ 492b3a271a9SManish Rangankar stats->txdata_octets = le64_to_cpu(ql_iscsi_stats->tx_data_octets); 493b3a271a9SManish Rangankar stats->rxdata_octets = le64_to_cpu(ql_iscsi_stats->rx_data_octets); 494b3a271a9SManish Rangankar /* xmit pdus */ 495b3a271a9SManish Rangankar stats->noptx_pdus = le32_to_cpu(ql_iscsi_stats->tx_nopout_pdus); 496b3a271a9SManish Rangankar stats->scsicmd_pdus = le32_to_cpu(ql_iscsi_stats->tx_scsi_cmd_pdus); 497b3a271a9SManish Rangankar stats->tmfcmd_pdus = le32_to_cpu(ql_iscsi_stats->tx_tmf_cmd_pdus); 498b3a271a9SManish Rangankar stats->login_pdus = le32_to_cpu(ql_iscsi_stats->tx_login_cmd_pdus); 499b3a271a9SManish Rangankar stats->text_pdus = le32_to_cpu(ql_iscsi_stats->tx_text_cmd_pdus); 500b3a271a9SManish Rangankar stats->dataout_pdus = le32_to_cpu(ql_iscsi_stats->tx_scsi_write_pdus); 501b3a271a9SManish Rangankar stats->logout_pdus = le32_to_cpu(ql_iscsi_stats->tx_logout_cmd_pdus); 502b3a271a9SManish Rangankar stats->snack_pdus = le32_to_cpu(ql_iscsi_stats->tx_snack_req_pdus); 503b3a271a9SManish Rangankar /* recv pdus */ 504b3a271a9SManish Rangankar stats->noprx_pdus = le32_to_cpu(ql_iscsi_stats->rx_nopin_pdus); 505b3a271a9SManish Rangankar stats->scsirsp_pdus = le32_to_cpu(ql_iscsi_stats->rx_scsi_resp_pdus); 506b3a271a9SManish Rangankar stats->tmfrsp_pdus = le32_to_cpu(ql_iscsi_stats->rx_tmf_resp_pdus); 507b3a271a9SManish Rangankar stats->textrsp_pdus = le32_to_cpu(ql_iscsi_stats->rx_text_resp_pdus); 508b3a271a9SManish Rangankar stats->datain_pdus = le32_to_cpu(ql_iscsi_stats->rx_scsi_read_pdus); 509b3a271a9SManish Rangankar stats->logoutrsp_pdus = 510b3a271a9SManish Rangankar le32_to_cpu(ql_iscsi_stats->rx_logout_resp_pdus); 511b3a271a9SManish Rangankar stats->r2t_pdus = le32_to_cpu(ql_iscsi_stats->rx_r2t_pdus); 512b3a271a9SManish Rangankar stats->async_pdus = le32_to_cpu(ql_iscsi_stats->rx_async_pdus); 513b3a271a9SManish Rangankar stats->rjt_pdus = le32_to_cpu(ql_iscsi_stats->rx_reject_pdus); 514b3a271a9SManish Rangankar 515b3a271a9SManish Rangankar free_stats: 516b3a271a9SManish Rangankar dma_free_coherent(&ha->pdev->dev, stats_size, ql_iscsi_stats, 517b3a271a9SManish Rangankar iscsi_stats_dma); 518b3a271a9SManish Rangankar exit_get_stats: 519b3a271a9SManish Rangankar return; 520b3a271a9SManish Rangankar } 521b3a271a9SManish Rangankar 5225c656af7SMike Christie static enum blk_eh_timer_return qla4xxx_eh_cmd_timed_out(struct scsi_cmnd *sc) 5235c656af7SMike Christie { 5245c656af7SMike Christie struct iscsi_cls_session *session; 525b3a271a9SManish Rangankar struct iscsi_session *sess; 526b3a271a9SManish Rangankar unsigned long flags; 527b3a271a9SManish Rangankar enum blk_eh_timer_return ret = BLK_EH_NOT_HANDLED; 5285c656af7SMike Christie 5295c656af7SMike Christie session = starget_to_session(scsi_target(sc->device)); 530b3a271a9SManish Rangankar sess = session->dd_data; 5315c656af7SMike Christie 532b3a271a9SManish Rangankar spin_lock_irqsave(&session->lock, flags); 533b3a271a9SManish Rangankar if (session->state == ISCSI_SESSION_FAILED) 534b3a271a9SManish Rangankar ret = BLK_EH_RESET_TIMER; 535b3a271a9SManish Rangankar spin_unlock_irqrestore(&session->lock, flags); 5365c656af7SMike Christie 537b3a271a9SManish Rangankar return ret; 538568d303bSMike Christie } 539afaf5a2dSDavid Somayajulu 540aa1e93a2SMike Christie static int qla4xxx_host_get_param(struct Scsi_Host *shost, 541aa1e93a2SMike Christie enum iscsi_host_param param, char *buf) 542aa1e93a2SMike Christie { 543aa1e93a2SMike Christie struct scsi_qla_host *ha = to_qla_host(shost); 544aa1e93a2SMike Christie int len; 545aa1e93a2SMike Christie 546aa1e93a2SMike Christie switch (param) { 547aa1e93a2SMike Christie case ISCSI_HOST_PARAM_HWADDRESS: 5487ffc49a6SMichael Chan len = sysfs_format_mac(buf, ha->my_mac, MAC_ADDR_LEN); 549aa1e93a2SMike Christie break; 55022236961SMike Christie case ISCSI_HOST_PARAM_IPADDRESS: 5512bab08fcSVikas Chaudhary len = sprintf(buf, "%pI4\n", &ha->ip_config.ip_address); 55222236961SMike Christie break; 5538ad5781aSMike Christie case ISCSI_HOST_PARAM_INITIATOR_NAME: 55422236961SMike Christie len = sprintf(buf, "%s\n", ha->name_string); 5558ad5781aSMike Christie break; 556aa1e93a2SMike Christie default: 557aa1e93a2SMike Christie return -ENOSYS; 558aa1e93a2SMike Christie } 559aa1e93a2SMike Christie 560aa1e93a2SMike Christie return len; 561aa1e93a2SMike Christie } 562aa1e93a2SMike Christie 563ed1086e0SVikas Chaudhary static void qla4xxx_create_ipv4_iface(struct scsi_qla_host *ha) 564ed1086e0SVikas Chaudhary { 565ed1086e0SVikas Chaudhary if (ha->iface_ipv4) 566ed1086e0SVikas Chaudhary return; 567ed1086e0SVikas Chaudhary 568ed1086e0SVikas Chaudhary /* IPv4 */ 569ed1086e0SVikas Chaudhary ha->iface_ipv4 = iscsi_create_iface(ha->host, 570ed1086e0SVikas Chaudhary &qla4xxx_iscsi_transport, 571ed1086e0SVikas Chaudhary ISCSI_IFACE_TYPE_IPV4, 0, 0); 572ed1086e0SVikas Chaudhary if (!ha->iface_ipv4) 573ed1086e0SVikas Chaudhary ql4_printk(KERN_ERR, ha, "Could not create IPv4 iSCSI " 574ed1086e0SVikas Chaudhary "iface0.\n"); 575ed1086e0SVikas Chaudhary } 576ed1086e0SVikas Chaudhary 577ed1086e0SVikas Chaudhary static void qla4xxx_create_ipv6_iface(struct scsi_qla_host *ha) 578ed1086e0SVikas Chaudhary { 579ed1086e0SVikas Chaudhary if (!ha->iface_ipv6_0) 580ed1086e0SVikas Chaudhary /* IPv6 iface-0 */ 581ed1086e0SVikas Chaudhary ha->iface_ipv6_0 = iscsi_create_iface(ha->host, 582ed1086e0SVikas Chaudhary &qla4xxx_iscsi_transport, 583ed1086e0SVikas Chaudhary ISCSI_IFACE_TYPE_IPV6, 0, 584ed1086e0SVikas Chaudhary 0); 585ed1086e0SVikas Chaudhary if (!ha->iface_ipv6_0) 586ed1086e0SVikas Chaudhary ql4_printk(KERN_ERR, ha, "Could not create IPv6 iSCSI " 587ed1086e0SVikas Chaudhary "iface0.\n"); 588ed1086e0SVikas Chaudhary 589ed1086e0SVikas Chaudhary if (!ha->iface_ipv6_1) 590ed1086e0SVikas Chaudhary /* IPv6 iface-1 */ 591ed1086e0SVikas Chaudhary ha->iface_ipv6_1 = iscsi_create_iface(ha->host, 592ed1086e0SVikas Chaudhary &qla4xxx_iscsi_transport, 593ed1086e0SVikas Chaudhary ISCSI_IFACE_TYPE_IPV6, 1, 594ed1086e0SVikas Chaudhary 0); 595ed1086e0SVikas Chaudhary if (!ha->iface_ipv6_1) 596ed1086e0SVikas Chaudhary ql4_printk(KERN_ERR, ha, "Could not create IPv6 iSCSI " 597ed1086e0SVikas Chaudhary "iface1.\n"); 598ed1086e0SVikas Chaudhary } 599ed1086e0SVikas Chaudhary 600ed1086e0SVikas Chaudhary static void qla4xxx_create_ifaces(struct scsi_qla_host *ha) 601ed1086e0SVikas Chaudhary { 602ed1086e0SVikas Chaudhary if (ha->ip_config.ipv4_options & IPOPT_IPV4_PROTOCOL_ENABLE) 603ed1086e0SVikas Chaudhary qla4xxx_create_ipv4_iface(ha); 604ed1086e0SVikas Chaudhary 605ed1086e0SVikas Chaudhary if (ha->ip_config.ipv6_options & IPV6_OPT_IPV6_PROTOCOL_ENABLE) 606ed1086e0SVikas Chaudhary qla4xxx_create_ipv6_iface(ha); 607ed1086e0SVikas Chaudhary } 608ed1086e0SVikas Chaudhary 609ed1086e0SVikas Chaudhary static void qla4xxx_destroy_ipv4_iface(struct scsi_qla_host *ha) 610ed1086e0SVikas Chaudhary { 611ed1086e0SVikas Chaudhary if (ha->iface_ipv4) { 612ed1086e0SVikas Chaudhary iscsi_destroy_iface(ha->iface_ipv4); 613ed1086e0SVikas Chaudhary ha->iface_ipv4 = NULL; 614ed1086e0SVikas Chaudhary } 615ed1086e0SVikas Chaudhary } 616ed1086e0SVikas Chaudhary 617ed1086e0SVikas Chaudhary static void qla4xxx_destroy_ipv6_iface(struct scsi_qla_host *ha) 618ed1086e0SVikas Chaudhary { 619ed1086e0SVikas Chaudhary if (ha->iface_ipv6_0) { 620ed1086e0SVikas Chaudhary iscsi_destroy_iface(ha->iface_ipv6_0); 621ed1086e0SVikas Chaudhary ha->iface_ipv6_0 = NULL; 622ed1086e0SVikas Chaudhary } 623ed1086e0SVikas Chaudhary if (ha->iface_ipv6_1) { 624ed1086e0SVikas Chaudhary iscsi_destroy_iface(ha->iface_ipv6_1); 625ed1086e0SVikas Chaudhary ha->iface_ipv6_1 = NULL; 626ed1086e0SVikas Chaudhary } 627ed1086e0SVikas Chaudhary } 628ed1086e0SVikas Chaudhary 629ed1086e0SVikas Chaudhary static void qla4xxx_destroy_ifaces(struct scsi_qla_host *ha) 630ed1086e0SVikas Chaudhary { 631ed1086e0SVikas Chaudhary qla4xxx_destroy_ipv4_iface(ha); 632ed1086e0SVikas Chaudhary qla4xxx_destroy_ipv6_iface(ha); 633ed1086e0SVikas Chaudhary } 634ed1086e0SVikas Chaudhary 635d00efe3fSMike Christie static void qla4xxx_set_ipv6(struct scsi_qla_host *ha, 636d00efe3fSMike Christie struct iscsi_iface_param_info *iface_param, 637d00efe3fSMike Christie struct addr_ctrl_blk *init_fw_cb) 638d00efe3fSMike Christie { 639d00efe3fSMike Christie /* 640d00efe3fSMike Christie * iface_num 0 is valid for IPv6 Addr, linklocal, router, autocfg. 641d00efe3fSMike Christie * iface_num 1 is valid only for IPv6 Addr. 642d00efe3fSMike Christie */ 643d00efe3fSMike Christie switch (iface_param->param) { 644d00efe3fSMike Christie case ISCSI_NET_PARAM_IPV6_ADDR: 645d00efe3fSMike Christie if (iface_param->iface_num & 0x1) 646d00efe3fSMike Christie /* IPv6 Addr 1 */ 647d00efe3fSMike Christie memcpy(init_fw_cb->ipv6_addr1, iface_param->value, 648d00efe3fSMike Christie sizeof(init_fw_cb->ipv6_addr1)); 649d00efe3fSMike Christie else 650d00efe3fSMike Christie /* IPv6 Addr 0 */ 651d00efe3fSMike Christie memcpy(init_fw_cb->ipv6_addr0, iface_param->value, 652d00efe3fSMike Christie sizeof(init_fw_cb->ipv6_addr0)); 653d00efe3fSMike Christie break; 654d00efe3fSMike Christie case ISCSI_NET_PARAM_IPV6_LINKLOCAL: 655d00efe3fSMike Christie if (iface_param->iface_num & 0x1) 656d00efe3fSMike Christie break; 657d00efe3fSMike Christie memcpy(init_fw_cb->ipv6_if_id, &iface_param->value[8], 658d00efe3fSMike Christie sizeof(init_fw_cb->ipv6_if_id)); 659d00efe3fSMike Christie break; 660d00efe3fSMike Christie case ISCSI_NET_PARAM_IPV6_ROUTER: 661d00efe3fSMike Christie if (iface_param->iface_num & 0x1) 662d00efe3fSMike Christie break; 663d00efe3fSMike Christie memcpy(init_fw_cb->ipv6_dflt_rtr_addr, iface_param->value, 664d00efe3fSMike Christie sizeof(init_fw_cb->ipv6_dflt_rtr_addr)); 665d00efe3fSMike Christie break; 666d00efe3fSMike Christie case ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG: 667d00efe3fSMike Christie /* Autocfg applies to even interface */ 668d00efe3fSMike Christie if (iface_param->iface_num & 0x1) 669d00efe3fSMike Christie break; 670d00efe3fSMike Christie 671d00efe3fSMike Christie if (iface_param->value[0] == ISCSI_IPV6_AUTOCFG_DISABLE) 672d00efe3fSMike Christie init_fw_cb->ipv6_addtl_opts &= 673d00efe3fSMike Christie cpu_to_le16( 674d00efe3fSMike Christie ~IPV6_ADDOPT_NEIGHBOR_DISCOVERY_ADDR_ENABLE); 675d00efe3fSMike Christie else if (iface_param->value[0] == ISCSI_IPV6_AUTOCFG_ND_ENABLE) 676d00efe3fSMike Christie init_fw_cb->ipv6_addtl_opts |= 677d00efe3fSMike Christie cpu_to_le16( 678d00efe3fSMike Christie IPV6_ADDOPT_NEIGHBOR_DISCOVERY_ADDR_ENABLE); 679d00efe3fSMike Christie else 680d00efe3fSMike Christie ql4_printk(KERN_ERR, ha, "Invalid autocfg setting for " 681d00efe3fSMike Christie "IPv6 addr\n"); 682d00efe3fSMike Christie break; 683d00efe3fSMike Christie case ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG: 684d00efe3fSMike Christie /* Autocfg applies to even interface */ 685d00efe3fSMike Christie if (iface_param->iface_num & 0x1) 686d00efe3fSMike Christie break; 687d00efe3fSMike Christie 688d00efe3fSMike Christie if (iface_param->value[0] == 689d00efe3fSMike Christie ISCSI_IPV6_LINKLOCAL_AUTOCFG_ENABLE) 690d00efe3fSMike Christie init_fw_cb->ipv6_addtl_opts |= cpu_to_le16( 691d00efe3fSMike Christie IPV6_ADDOPT_AUTOCONFIG_LINK_LOCAL_ADDR); 692d00efe3fSMike Christie else if (iface_param->value[0] == 693d00efe3fSMike Christie ISCSI_IPV6_LINKLOCAL_AUTOCFG_DISABLE) 694d00efe3fSMike Christie init_fw_cb->ipv6_addtl_opts &= cpu_to_le16( 695d00efe3fSMike Christie ~IPV6_ADDOPT_AUTOCONFIG_LINK_LOCAL_ADDR); 696d00efe3fSMike Christie else 697d00efe3fSMike Christie ql4_printk(KERN_ERR, ha, "Invalid autocfg setting for " 698d00efe3fSMike Christie "IPv6 linklocal addr\n"); 699d00efe3fSMike Christie break; 700d00efe3fSMike Christie case ISCSI_NET_PARAM_IPV6_ROUTER_AUTOCFG: 701d00efe3fSMike Christie /* Autocfg applies to even interface */ 702d00efe3fSMike Christie if (iface_param->iface_num & 0x1) 703d00efe3fSMike Christie break; 704d00efe3fSMike Christie 705d00efe3fSMike Christie if (iface_param->value[0] == ISCSI_IPV6_ROUTER_AUTOCFG_ENABLE) 706d00efe3fSMike Christie memset(init_fw_cb->ipv6_dflt_rtr_addr, 0, 707d00efe3fSMike Christie sizeof(init_fw_cb->ipv6_dflt_rtr_addr)); 708d00efe3fSMike Christie break; 709d00efe3fSMike Christie case ISCSI_NET_PARAM_IFACE_ENABLE: 710ed1086e0SVikas Chaudhary if (iface_param->value[0] == ISCSI_IFACE_ENABLE) { 711d00efe3fSMike Christie init_fw_cb->ipv6_opts |= 712d00efe3fSMike Christie cpu_to_le16(IPV6_OPT_IPV6_PROTOCOL_ENABLE); 713ed1086e0SVikas Chaudhary qla4xxx_create_ipv6_iface(ha); 714ed1086e0SVikas Chaudhary } else { 715d00efe3fSMike Christie init_fw_cb->ipv6_opts &= 716d00efe3fSMike Christie cpu_to_le16(~IPV6_OPT_IPV6_PROTOCOL_ENABLE & 717d00efe3fSMike Christie 0xFFFF); 718ed1086e0SVikas Chaudhary qla4xxx_destroy_ipv6_iface(ha); 719ed1086e0SVikas Chaudhary } 720d00efe3fSMike Christie break; 721d00efe3fSMike Christie case ISCSI_NET_PARAM_VLAN_ID: 722d00efe3fSMike Christie if (iface_param->len != sizeof(init_fw_cb->ipv6_vlan_tag)) 723d00efe3fSMike Christie break; 7246ac73e8cSVikas Chaudhary init_fw_cb->ipv6_vlan_tag = 7256ac73e8cSVikas Chaudhary cpu_to_be16(*(uint16_t *)iface_param->value); 7266ac73e8cSVikas Chaudhary break; 7276ac73e8cSVikas Chaudhary case ISCSI_NET_PARAM_VLAN_ENABLED: 7286ac73e8cSVikas Chaudhary if (iface_param->value[0] == ISCSI_VLAN_ENABLE) 7296ac73e8cSVikas Chaudhary init_fw_cb->ipv6_opts |= 7306ac73e8cSVikas Chaudhary cpu_to_le16(IPV6_OPT_VLAN_TAGGING_ENABLE); 7316ac73e8cSVikas Chaudhary else 7326ac73e8cSVikas Chaudhary init_fw_cb->ipv6_opts &= 7336ac73e8cSVikas Chaudhary cpu_to_le16(~IPV6_OPT_VLAN_TAGGING_ENABLE); 734d00efe3fSMike Christie break; 735943c157bSVikas Chaudhary case ISCSI_NET_PARAM_MTU: 736943c157bSVikas Chaudhary init_fw_cb->eth_mtu_size = 737943c157bSVikas Chaudhary cpu_to_le16(*(uint16_t *)iface_param->value); 738943c157bSVikas Chaudhary break; 7392ada7fc5SVikas Chaudhary case ISCSI_NET_PARAM_PORT: 7402ada7fc5SVikas Chaudhary /* Autocfg applies to even interface */ 7412ada7fc5SVikas Chaudhary if (iface_param->iface_num & 0x1) 7422ada7fc5SVikas Chaudhary break; 7432ada7fc5SVikas Chaudhary 7442ada7fc5SVikas Chaudhary init_fw_cb->ipv6_port = 7452ada7fc5SVikas Chaudhary cpu_to_le16(*(uint16_t *)iface_param->value); 7462ada7fc5SVikas Chaudhary break; 747d00efe3fSMike Christie default: 748d00efe3fSMike Christie ql4_printk(KERN_ERR, ha, "Unknown IPv6 param = %d\n", 749d00efe3fSMike Christie iface_param->param); 750d00efe3fSMike Christie break; 751d00efe3fSMike Christie } 752d00efe3fSMike Christie } 753d00efe3fSMike Christie 754d00efe3fSMike Christie static void qla4xxx_set_ipv4(struct scsi_qla_host *ha, 755d00efe3fSMike Christie struct iscsi_iface_param_info *iface_param, 756d00efe3fSMike Christie struct addr_ctrl_blk *init_fw_cb) 757d00efe3fSMike Christie { 758d00efe3fSMike Christie switch (iface_param->param) { 759d00efe3fSMike Christie case ISCSI_NET_PARAM_IPV4_ADDR: 760d00efe3fSMike Christie memcpy(init_fw_cb->ipv4_addr, iface_param->value, 761d00efe3fSMike Christie sizeof(init_fw_cb->ipv4_addr)); 762d00efe3fSMike Christie break; 763d00efe3fSMike Christie case ISCSI_NET_PARAM_IPV4_SUBNET: 764d00efe3fSMike Christie memcpy(init_fw_cb->ipv4_subnet, iface_param->value, 765d00efe3fSMike Christie sizeof(init_fw_cb->ipv4_subnet)); 766d00efe3fSMike Christie break; 767d00efe3fSMike Christie case ISCSI_NET_PARAM_IPV4_GW: 768d00efe3fSMike Christie memcpy(init_fw_cb->ipv4_gw_addr, iface_param->value, 769d00efe3fSMike Christie sizeof(init_fw_cb->ipv4_gw_addr)); 770d00efe3fSMike Christie break; 771d00efe3fSMike Christie case ISCSI_NET_PARAM_IPV4_BOOTPROTO: 772d00efe3fSMike Christie if (iface_param->value[0] == ISCSI_BOOTPROTO_DHCP) 773d00efe3fSMike Christie init_fw_cb->ipv4_tcp_opts |= 774d00efe3fSMike Christie cpu_to_le16(TCPOPT_DHCP_ENABLE); 775d00efe3fSMike Christie else if (iface_param->value[0] == ISCSI_BOOTPROTO_STATIC) 776d00efe3fSMike Christie init_fw_cb->ipv4_tcp_opts &= 777d00efe3fSMike Christie cpu_to_le16(~TCPOPT_DHCP_ENABLE); 778d00efe3fSMike Christie else 779d00efe3fSMike Christie ql4_printk(KERN_ERR, ha, "Invalid IPv4 bootproto\n"); 780d00efe3fSMike Christie break; 781d00efe3fSMike Christie case ISCSI_NET_PARAM_IFACE_ENABLE: 782ed1086e0SVikas Chaudhary if (iface_param->value[0] == ISCSI_IFACE_ENABLE) { 783d00efe3fSMike Christie init_fw_cb->ipv4_ip_opts |= 7842bab08fcSVikas Chaudhary cpu_to_le16(IPOPT_IPV4_PROTOCOL_ENABLE); 785ed1086e0SVikas Chaudhary qla4xxx_create_ipv4_iface(ha); 786ed1086e0SVikas Chaudhary } else { 787d00efe3fSMike Christie init_fw_cb->ipv4_ip_opts &= 7882bab08fcSVikas Chaudhary cpu_to_le16(~IPOPT_IPV4_PROTOCOL_ENABLE & 789d00efe3fSMike Christie 0xFFFF); 790ed1086e0SVikas Chaudhary qla4xxx_destroy_ipv4_iface(ha); 791ed1086e0SVikas Chaudhary } 792d00efe3fSMike Christie break; 793d00efe3fSMike Christie case ISCSI_NET_PARAM_VLAN_ID: 794d00efe3fSMike Christie if (iface_param->len != sizeof(init_fw_cb->ipv4_vlan_tag)) 795d00efe3fSMike Christie break; 7966ac73e8cSVikas Chaudhary init_fw_cb->ipv4_vlan_tag = 7976ac73e8cSVikas Chaudhary cpu_to_be16(*(uint16_t *)iface_param->value); 7986ac73e8cSVikas Chaudhary break; 7996ac73e8cSVikas Chaudhary case ISCSI_NET_PARAM_VLAN_ENABLED: 8006ac73e8cSVikas Chaudhary if (iface_param->value[0] == ISCSI_VLAN_ENABLE) 8016ac73e8cSVikas Chaudhary init_fw_cb->ipv4_ip_opts |= 8026ac73e8cSVikas Chaudhary cpu_to_le16(IPOPT_VLAN_TAGGING_ENABLE); 8036ac73e8cSVikas Chaudhary else 8046ac73e8cSVikas Chaudhary init_fw_cb->ipv4_ip_opts &= 8056ac73e8cSVikas Chaudhary cpu_to_le16(~IPOPT_VLAN_TAGGING_ENABLE); 806d00efe3fSMike Christie break; 807943c157bSVikas Chaudhary case ISCSI_NET_PARAM_MTU: 808943c157bSVikas Chaudhary init_fw_cb->eth_mtu_size = 809943c157bSVikas Chaudhary cpu_to_le16(*(uint16_t *)iface_param->value); 810943c157bSVikas Chaudhary break; 8112ada7fc5SVikas Chaudhary case ISCSI_NET_PARAM_PORT: 8122ada7fc5SVikas Chaudhary init_fw_cb->ipv4_port = 8132ada7fc5SVikas Chaudhary cpu_to_le16(*(uint16_t *)iface_param->value); 8142ada7fc5SVikas Chaudhary break; 815d00efe3fSMike Christie default: 816d00efe3fSMike Christie ql4_printk(KERN_ERR, ha, "Unknown IPv4 param = %d\n", 817d00efe3fSMike Christie iface_param->param); 818d00efe3fSMike Christie break; 819d00efe3fSMike Christie } 820d00efe3fSMike Christie } 821d00efe3fSMike Christie 822d00efe3fSMike Christie static void 823d00efe3fSMike Christie qla4xxx_initcb_to_acb(struct addr_ctrl_blk *init_fw_cb) 824d00efe3fSMike Christie { 825d00efe3fSMike Christie struct addr_ctrl_blk_def *acb; 826d00efe3fSMike Christie acb = (struct addr_ctrl_blk_def *)init_fw_cb; 827d00efe3fSMike Christie memset(acb->reserved1, 0, sizeof(acb->reserved1)); 828d00efe3fSMike Christie memset(acb->reserved2, 0, sizeof(acb->reserved2)); 829d00efe3fSMike Christie memset(acb->reserved3, 0, sizeof(acb->reserved3)); 830d00efe3fSMike Christie memset(acb->reserved4, 0, sizeof(acb->reserved4)); 831d00efe3fSMike Christie memset(acb->reserved5, 0, sizeof(acb->reserved5)); 832d00efe3fSMike Christie memset(acb->reserved6, 0, sizeof(acb->reserved6)); 833d00efe3fSMike Christie memset(acb->reserved7, 0, sizeof(acb->reserved7)); 834d00efe3fSMike Christie memset(acb->reserved8, 0, sizeof(acb->reserved8)); 835d00efe3fSMike Christie memset(acb->reserved9, 0, sizeof(acb->reserved9)); 836d00efe3fSMike Christie memset(acb->reserved10, 0, sizeof(acb->reserved10)); 837d00efe3fSMike Christie memset(acb->reserved11, 0, sizeof(acb->reserved11)); 838d00efe3fSMike Christie memset(acb->reserved12, 0, sizeof(acb->reserved12)); 839d00efe3fSMike Christie memset(acb->reserved13, 0, sizeof(acb->reserved13)); 840d00efe3fSMike Christie memset(acb->reserved14, 0, sizeof(acb->reserved14)); 841d00efe3fSMike Christie memset(acb->reserved15, 0, sizeof(acb->reserved15)); 842d00efe3fSMike Christie } 843d00efe3fSMike Christie 844d00efe3fSMike Christie static int 845d00efe3fSMike Christie qla4xxx_iface_set_param(struct Scsi_Host *shost, char *data, int count) 846d00efe3fSMike Christie { 847d00efe3fSMike Christie struct scsi_qla_host *ha = to_qla_host(shost); 848d00efe3fSMike Christie int rval = 0; 849d00efe3fSMike Christie struct iscsi_iface_param_info *iface_param = NULL; 850d00efe3fSMike Christie struct addr_ctrl_blk *init_fw_cb = NULL; 851d00efe3fSMike Christie dma_addr_t init_fw_cb_dma; 852d00efe3fSMike Christie uint32_t mbox_cmd[MBOX_REG_COUNT]; 853d00efe3fSMike Christie uint32_t mbox_sts[MBOX_REG_COUNT]; 854d00efe3fSMike Christie uint32_t total_param_count; 855d00efe3fSMike Christie uint32_t length; 856d00efe3fSMike Christie 857d00efe3fSMike Christie init_fw_cb = dma_alloc_coherent(&ha->pdev->dev, 858d00efe3fSMike Christie sizeof(struct addr_ctrl_blk), 859d00efe3fSMike Christie &init_fw_cb_dma, GFP_KERNEL); 860d00efe3fSMike Christie if (!init_fw_cb) { 861d00efe3fSMike Christie ql4_printk(KERN_ERR, ha, "%s: Unable to alloc init_cb\n", 862d00efe3fSMike Christie __func__); 863d00efe3fSMike Christie return -ENOMEM; 864d00efe3fSMike Christie } 865d00efe3fSMike Christie 866d00efe3fSMike Christie memset(init_fw_cb, 0, sizeof(struct addr_ctrl_blk)); 867d00efe3fSMike Christie memset(&mbox_cmd, 0, sizeof(mbox_cmd)); 868d00efe3fSMike Christie memset(&mbox_sts, 0, sizeof(mbox_sts)); 869d00efe3fSMike Christie 870d00efe3fSMike Christie if (qla4xxx_get_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb_dma)) { 871d00efe3fSMike Christie ql4_printk(KERN_ERR, ha, "%s: get ifcb failed\n", __func__); 872d00efe3fSMike Christie rval = -EIO; 873d00efe3fSMike Christie goto exit_init_fw_cb; 874d00efe3fSMike Christie } 875d00efe3fSMike Christie 876d00efe3fSMike Christie total_param_count = count; 877d00efe3fSMike Christie iface_param = (struct iscsi_iface_param_info *)data; 878d00efe3fSMike Christie 879d00efe3fSMike Christie for ( ; total_param_count != 0; total_param_count--) { 880d00efe3fSMike Christie length = iface_param->len; 881d00efe3fSMike Christie 882d00efe3fSMike Christie if (iface_param->param_type != ISCSI_NET_PARAM) 883d00efe3fSMike Christie continue; 884d00efe3fSMike Christie 885d00efe3fSMike Christie switch (iface_param->iface_type) { 886d00efe3fSMike Christie case ISCSI_IFACE_TYPE_IPV4: 887d00efe3fSMike Christie switch (iface_param->iface_num) { 888d00efe3fSMike Christie case 0: 889d00efe3fSMike Christie qla4xxx_set_ipv4(ha, iface_param, init_fw_cb); 890d00efe3fSMike Christie break; 891d00efe3fSMike Christie default: 892d00efe3fSMike Christie /* Cannot have more than one IPv4 interface */ 893d00efe3fSMike Christie ql4_printk(KERN_ERR, ha, "Invalid IPv4 iface " 894d00efe3fSMike Christie "number = %d\n", 895d00efe3fSMike Christie iface_param->iface_num); 896d00efe3fSMike Christie break; 897d00efe3fSMike Christie } 898d00efe3fSMike Christie break; 899d00efe3fSMike Christie case ISCSI_IFACE_TYPE_IPV6: 900d00efe3fSMike Christie switch (iface_param->iface_num) { 901d00efe3fSMike Christie case 0: 902d00efe3fSMike Christie case 1: 903d00efe3fSMike Christie qla4xxx_set_ipv6(ha, iface_param, init_fw_cb); 904d00efe3fSMike Christie break; 905d00efe3fSMike Christie default: 906d00efe3fSMike Christie /* Cannot have more than two IPv6 interface */ 907d00efe3fSMike Christie ql4_printk(KERN_ERR, ha, "Invalid IPv6 iface " 908d00efe3fSMike Christie "number = %d\n", 909d00efe3fSMike Christie iface_param->iface_num); 910d00efe3fSMike Christie break; 911d00efe3fSMike Christie } 912d00efe3fSMike Christie break; 913d00efe3fSMike Christie default: 914d00efe3fSMike Christie ql4_printk(KERN_ERR, ha, "Invalid iface type\n"); 915d00efe3fSMike Christie break; 916d00efe3fSMike Christie } 917d00efe3fSMike Christie 918d00efe3fSMike Christie iface_param = (struct iscsi_iface_param_info *) 919d00efe3fSMike Christie ((uint8_t *)iface_param + 920d00efe3fSMike Christie sizeof(struct iscsi_iface_param_info) + length); 921d00efe3fSMike Christie } 922d00efe3fSMike Christie 923d00efe3fSMike Christie init_fw_cb->cookie = cpu_to_le32(0x11BEAD5A); 924d00efe3fSMike Christie 925d00efe3fSMike Christie rval = qla4xxx_set_flash(ha, init_fw_cb_dma, FLASH_SEGMENT_IFCB, 926d00efe3fSMike Christie sizeof(struct addr_ctrl_blk), 927d00efe3fSMike Christie FLASH_OPT_RMW_COMMIT); 928d00efe3fSMike Christie if (rval != QLA_SUCCESS) { 929d00efe3fSMike Christie ql4_printk(KERN_ERR, ha, "%s: set flash mbx failed\n", 930d00efe3fSMike Christie __func__); 931d00efe3fSMike Christie rval = -EIO; 932d00efe3fSMike Christie goto exit_init_fw_cb; 933d00efe3fSMike Christie } 934d00efe3fSMike Christie 935d00efe3fSMike Christie qla4xxx_disable_acb(ha); 936d00efe3fSMike Christie 937d00efe3fSMike Christie qla4xxx_initcb_to_acb(init_fw_cb); 938d00efe3fSMike Christie 939d00efe3fSMike Christie rval = qla4xxx_set_acb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb_dma); 940d00efe3fSMike Christie if (rval != QLA_SUCCESS) { 941d00efe3fSMike Christie ql4_printk(KERN_ERR, ha, "%s: set acb mbx failed\n", 942d00efe3fSMike Christie __func__); 943d00efe3fSMike Christie rval = -EIO; 944d00efe3fSMike Christie goto exit_init_fw_cb; 945d00efe3fSMike Christie } 946d00efe3fSMike Christie 947d00efe3fSMike Christie memset(init_fw_cb, 0, sizeof(struct addr_ctrl_blk)); 948d00efe3fSMike Christie qla4xxx_update_local_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb, 949d00efe3fSMike Christie init_fw_cb_dma); 950d00efe3fSMike Christie 951d00efe3fSMike Christie exit_init_fw_cb: 952d00efe3fSMike Christie dma_free_coherent(&ha->pdev->dev, sizeof(struct addr_ctrl_blk), 953d00efe3fSMike Christie init_fw_cb, init_fw_cb_dma); 954d00efe3fSMike Christie 955d00efe3fSMike Christie return rval; 956d00efe3fSMike Christie } 957d00efe3fSMike Christie 958b3a271a9SManish Rangankar static int qla4xxx_conn_get_param(struct iscsi_cls_conn *cls_conn, 959afaf5a2dSDavid Somayajulu enum iscsi_param param, char *buf) 960afaf5a2dSDavid Somayajulu { 961b3a271a9SManish Rangankar struct iscsi_conn *conn; 962b3a271a9SManish Rangankar struct qla_conn *qla_conn; 963b3a271a9SManish Rangankar struct sockaddr *dst_addr; 964b3a271a9SManish Rangankar int len = 0; 965afaf5a2dSDavid Somayajulu 966b3a271a9SManish Rangankar conn = cls_conn->dd_data; 967b3a271a9SManish Rangankar qla_conn = conn->dd_data; 968b3a271a9SManish Rangankar dst_addr = &qla_conn->qla_ep->dst_addr; 969afaf5a2dSDavid Somayajulu 970afaf5a2dSDavid Somayajulu switch (param) { 971afaf5a2dSDavid Somayajulu case ISCSI_PARAM_CONN_PORT: 972afaf5a2dSDavid Somayajulu case ISCSI_PARAM_CONN_ADDRESS: 973b3a271a9SManish Rangankar return iscsi_conn_get_addr_param((struct sockaddr_storage *) 974b3a271a9SManish Rangankar dst_addr, param, buf); 975afaf5a2dSDavid Somayajulu default: 976b3a271a9SManish Rangankar return iscsi_conn_get_param(cls_conn, param, buf); 977afaf5a2dSDavid Somayajulu } 978afaf5a2dSDavid Somayajulu 979afaf5a2dSDavid Somayajulu return len; 980b3a271a9SManish Rangankar 981afaf5a2dSDavid Somayajulu } 982afaf5a2dSDavid Somayajulu 983b3a271a9SManish Rangankar static struct iscsi_cls_session * 984b3a271a9SManish Rangankar qla4xxx_session_create(struct iscsi_endpoint *ep, 985b3a271a9SManish Rangankar uint16_t cmds_max, uint16_t qdepth, 986b3a271a9SManish Rangankar uint32_t initial_cmdsn) 987b3a271a9SManish Rangankar { 988b3a271a9SManish Rangankar struct iscsi_cls_session *cls_sess; 989b3a271a9SManish Rangankar struct scsi_qla_host *ha; 990b3a271a9SManish Rangankar struct qla_endpoint *qla_ep; 991b3a271a9SManish Rangankar struct ddb_entry *ddb_entry; 992b3a271a9SManish Rangankar uint32_t ddb_index; 993b3a271a9SManish Rangankar uint32_t mbx_sts = 0; 994b3a271a9SManish Rangankar struct iscsi_session *sess; 995b3a271a9SManish Rangankar struct sockaddr *dst_addr; 996b3a271a9SManish Rangankar int ret; 997b3a271a9SManish Rangankar 998b3a271a9SManish Rangankar DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); 999b3a271a9SManish Rangankar if (!ep) { 1000b3a271a9SManish Rangankar printk(KERN_ERR "qla4xxx: missing ep.\n"); 1001b3a271a9SManish Rangankar return NULL; 1002b3a271a9SManish Rangankar } 1003b3a271a9SManish Rangankar 1004b3a271a9SManish Rangankar qla_ep = ep->dd_data; 1005b3a271a9SManish Rangankar dst_addr = (struct sockaddr *)&qla_ep->dst_addr; 1006b3a271a9SManish Rangankar ha = to_qla_host(qla_ep->host); 1007736cf369SManish Rangankar 1008b3a271a9SManish Rangankar get_ddb_index: 1009b3a271a9SManish Rangankar ddb_index = find_first_zero_bit(ha->ddb_idx_map, MAX_DDB_ENTRIES); 1010b3a271a9SManish Rangankar 1011b3a271a9SManish Rangankar if (ddb_index >= MAX_DDB_ENTRIES) { 1012b3a271a9SManish Rangankar DEBUG2(ql4_printk(KERN_INFO, ha, 1013b3a271a9SManish Rangankar "Free DDB index not available\n")); 1014b3a271a9SManish Rangankar return NULL; 1015b3a271a9SManish Rangankar } 1016b3a271a9SManish Rangankar 1017b3a271a9SManish Rangankar if (test_and_set_bit(ddb_index, ha->ddb_idx_map)) 1018b3a271a9SManish Rangankar goto get_ddb_index; 1019b3a271a9SManish Rangankar 1020b3a271a9SManish Rangankar DEBUG2(ql4_printk(KERN_INFO, ha, 1021b3a271a9SManish Rangankar "Found a free DDB index at %d\n", ddb_index)); 1022b3a271a9SManish Rangankar ret = qla4xxx_req_ddb_entry(ha, ddb_index, &mbx_sts); 1023b3a271a9SManish Rangankar if (ret == QLA_ERROR) { 1024b3a271a9SManish Rangankar if (mbx_sts == MBOX_STS_COMMAND_ERROR) { 1025b3a271a9SManish Rangankar ql4_printk(KERN_INFO, ha, 1026b3a271a9SManish Rangankar "DDB index = %d not available trying next\n", 1027b3a271a9SManish Rangankar ddb_index); 1028b3a271a9SManish Rangankar goto get_ddb_index; 1029b3a271a9SManish Rangankar } 1030b3a271a9SManish Rangankar DEBUG2(ql4_printk(KERN_INFO, ha, 1031b3a271a9SManish Rangankar "Free FW DDB not available\n")); 1032b3a271a9SManish Rangankar return NULL; 1033b3a271a9SManish Rangankar } 1034b3a271a9SManish Rangankar 1035b3a271a9SManish Rangankar cls_sess = iscsi_session_setup(&qla4xxx_iscsi_transport, qla_ep->host, 1036b3a271a9SManish Rangankar cmds_max, sizeof(struct ddb_entry), 1037b3a271a9SManish Rangankar sizeof(struct ql4_task_data), 1038b3a271a9SManish Rangankar initial_cmdsn, ddb_index); 1039b3a271a9SManish Rangankar if (!cls_sess) 1040b3a271a9SManish Rangankar return NULL; 1041b3a271a9SManish Rangankar 1042b3a271a9SManish Rangankar sess = cls_sess->dd_data; 1043b3a271a9SManish Rangankar ddb_entry = sess->dd_data; 1044b3a271a9SManish Rangankar ddb_entry->fw_ddb_index = ddb_index; 1045b3a271a9SManish Rangankar ddb_entry->fw_ddb_device_state = DDB_DS_NO_CONNECTION_ACTIVE; 1046b3a271a9SManish Rangankar ddb_entry->ha = ha; 1047b3a271a9SManish Rangankar ddb_entry->sess = cls_sess; 1048b3a271a9SManish Rangankar cls_sess->recovery_tmo = ql4xsess_recovery_tmo; 1049b3a271a9SManish Rangankar ha->fw_ddb_index_map[ddb_entry->fw_ddb_index] = ddb_entry; 1050b3a271a9SManish Rangankar ha->tot_ddbs++; 1051b3a271a9SManish Rangankar 1052b3a271a9SManish Rangankar return cls_sess; 1053b3a271a9SManish Rangankar } 1054b3a271a9SManish Rangankar 1055b3a271a9SManish Rangankar static void qla4xxx_session_destroy(struct iscsi_cls_session *cls_sess) 1056b3a271a9SManish Rangankar { 1057b3a271a9SManish Rangankar struct iscsi_session *sess; 1058b3a271a9SManish Rangankar struct ddb_entry *ddb_entry; 1059b3a271a9SManish Rangankar struct scsi_qla_host *ha; 1060b3a271a9SManish Rangankar unsigned long flags; 1061b3a271a9SManish Rangankar 1062b3a271a9SManish Rangankar DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); 1063b3a271a9SManish Rangankar sess = cls_sess->dd_data; 1064b3a271a9SManish Rangankar ddb_entry = sess->dd_data; 1065b3a271a9SManish Rangankar ha = ddb_entry->ha; 1066b3a271a9SManish Rangankar 1067736cf369SManish Rangankar qla4xxx_clear_ddb_entry(ha, ddb_entry->fw_ddb_index); 1068736cf369SManish Rangankar 1069b3a271a9SManish Rangankar spin_lock_irqsave(&ha->hardware_lock, flags); 1070b3a271a9SManish Rangankar qla4xxx_free_ddb(ha, ddb_entry); 1071b3a271a9SManish Rangankar spin_unlock_irqrestore(&ha->hardware_lock, flags); 1072b3a271a9SManish Rangankar iscsi_session_teardown(cls_sess); 1073b3a271a9SManish Rangankar } 1074b3a271a9SManish Rangankar 1075b3a271a9SManish Rangankar static struct iscsi_cls_conn * 1076b3a271a9SManish Rangankar qla4xxx_conn_create(struct iscsi_cls_session *cls_sess, uint32_t conn_idx) 1077b3a271a9SManish Rangankar { 1078b3a271a9SManish Rangankar struct iscsi_cls_conn *cls_conn; 1079b3a271a9SManish Rangankar struct iscsi_session *sess; 1080b3a271a9SManish Rangankar struct ddb_entry *ddb_entry; 1081b3a271a9SManish Rangankar 1082b3a271a9SManish Rangankar DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); 1083b3a271a9SManish Rangankar cls_conn = iscsi_conn_setup(cls_sess, sizeof(struct qla_conn), 1084b3a271a9SManish Rangankar conn_idx); 1085b3a271a9SManish Rangankar sess = cls_sess->dd_data; 1086b3a271a9SManish Rangankar ddb_entry = sess->dd_data; 1087b3a271a9SManish Rangankar ddb_entry->conn = cls_conn; 1088b3a271a9SManish Rangankar 1089b3a271a9SManish Rangankar return cls_conn; 1090b3a271a9SManish Rangankar } 1091b3a271a9SManish Rangankar 1092b3a271a9SManish Rangankar static int qla4xxx_conn_bind(struct iscsi_cls_session *cls_session, 1093b3a271a9SManish Rangankar struct iscsi_cls_conn *cls_conn, 1094b3a271a9SManish Rangankar uint64_t transport_fd, int is_leading) 1095b3a271a9SManish Rangankar { 1096b3a271a9SManish Rangankar struct iscsi_conn *conn; 1097b3a271a9SManish Rangankar struct qla_conn *qla_conn; 1098b3a271a9SManish Rangankar struct iscsi_endpoint *ep; 1099b3a271a9SManish Rangankar 1100b3a271a9SManish Rangankar DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); 1101b3a271a9SManish Rangankar 1102b3a271a9SManish Rangankar if (iscsi_conn_bind(cls_session, cls_conn, is_leading)) 1103b3a271a9SManish Rangankar return -EINVAL; 1104b3a271a9SManish Rangankar ep = iscsi_lookup_endpoint(transport_fd); 1105b3a271a9SManish Rangankar conn = cls_conn->dd_data; 1106b3a271a9SManish Rangankar qla_conn = conn->dd_data; 1107b3a271a9SManish Rangankar qla_conn->qla_ep = ep->dd_data; 1108b3a271a9SManish Rangankar return 0; 1109b3a271a9SManish Rangankar } 1110b3a271a9SManish Rangankar 1111b3a271a9SManish Rangankar static int qla4xxx_conn_start(struct iscsi_cls_conn *cls_conn) 1112b3a271a9SManish Rangankar { 1113b3a271a9SManish Rangankar struct iscsi_cls_session *cls_sess = iscsi_conn_to_session(cls_conn); 1114b3a271a9SManish Rangankar struct iscsi_session *sess; 1115b3a271a9SManish Rangankar struct ddb_entry *ddb_entry; 1116b3a271a9SManish Rangankar struct scsi_qla_host *ha; 1117b3a271a9SManish Rangankar struct dev_db_entry *fw_ddb_entry; 1118b3a271a9SManish Rangankar dma_addr_t fw_ddb_entry_dma; 1119b3a271a9SManish Rangankar uint32_t mbx_sts = 0; 1120b3a271a9SManish Rangankar int ret = 0; 1121b3a271a9SManish Rangankar int status = QLA_SUCCESS; 1122b3a271a9SManish Rangankar 1123b3a271a9SManish Rangankar DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); 1124b3a271a9SManish Rangankar sess = cls_sess->dd_data; 1125b3a271a9SManish Rangankar ddb_entry = sess->dd_data; 1126b3a271a9SManish Rangankar ha = ddb_entry->ha; 1127b3a271a9SManish Rangankar 1128b3a271a9SManish Rangankar fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), 1129b3a271a9SManish Rangankar &fw_ddb_entry_dma, GFP_KERNEL); 1130b3a271a9SManish Rangankar if (!fw_ddb_entry) { 1131b3a271a9SManish Rangankar ql4_printk(KERN_ERR, ha, 1132b3a271a9SManish Rangankar "%s: Unable to allocate dma buffer\n", __func__); 1133b3a271a9SManish Rangankar return -ENOMEM; 1134b3a271a9SManish Rangankar } 1135b3a271a9SManish Rangankar 1136b3a271a9SManish Rangankar ret = qla4xxx_set_param_ddbentry(ha, ddb_entry, cls_conn, &mbx_sts); 1137b3a271a9SManish Rangankar if (ret) { 1138b3a271a9SManish Rangankar /* If iscsid is stopped and started then no need to do 1139b3a271a9SManish Rangankar * set param again since ddb state will be already 1140b3a271a9SManish Rangankar * active and FW does not allow set ddb to an 1141b3a271a9SManish Rangankar * active session. 1142b3a271a9SManish Rangankar */ 1143b3a271a9SManish Rangankar if (mbx_sts) 1144b3a271a9SManish Rangankar if (ddb_entry->fw_ddb_device_state == 1145f922da79SManish Rangankar DDB_DS_SESSION_ACTIVE) { 1146f922da79SManish Rangankar iscsi_conn_start(ddb_entry->conn); 1147f922da79SManish Rangankar iscsi_conn_login_event(ddb_entry->conn, 1148f922da79SManish Rangankar ISCSI_CONN_STATE_LOGGED_IN); 1149b3a271a9SManish Rangankar goto exit_set_param; 1150f922da79SManish Rangankar } 1151b3a271a9SManish Rangankar 1152b3a271a9SManish Rangankar ql4_printk(KERN_ERR, ha, "%s: Failed set param for index[%d]\n", 1153b3a271a9SManish Rangankar __func__, ddb_entry->fw_ddb_index); 1154b3a271a9SManish Rangankar goto exit_conn_start; 1155b3a271a9SManish Rangankar } 1156b3a271a9SManish Rangankar 1157b3a271a9SManish Rangankar status = qla4xxx_conn_open(ha, ddb_entry->fw_ddb_index); 1158b3a271a9SManish Rangankar if (status == QLA_ERROR) { 11590e7e8501SManish Rangankar ql4_printk(KERN_ERR, ha, "%s: Login failed: %s\n", __func__, 11600e7e8501SManish Rangankar sess->targetname); 1161b3a271a9SManish Rangankar ret = -EINVAL; 1162b3a271a9SManish Rangankar goto exit_conn_start; 1163b3a271a9SManish Rangankar } 1164b3a271a9SManish Rangankar 116598270ab4SManish Rangankar if (ddb_entry->fw_ddb_device_state == DDB_DS_NO_CONNECTION_ACTIVE) 1166b3a271a9SManish Rangankar ddb_entry->fw_ddb_device_state = DDB_DS_LOGIN_IN_PROCESS; 1167b3a271a9SManish Rangankar 116898270ab4SManish Rangankar DEBUG2(printk(KERN_INFO "%s: DDB state [%d]\n", __func__, 116998270ab4SManish Rangankar ddb_entry->fw_ddb_device_state)); 117098270ab4SManish Rangankar 1171b3a271a9SManish Rangankar exit_set_param: 1172b3a271a9SManish Rangankar ret = 0; 1173b3a271a9SManish Rangankar 1174b3a271a9SManish Rangankar exit_conn_start: 1175b3a271a9SManish Rangankar dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), 1176b3a271a9SManish Rangankar fw_ddb_entry, fw_ddb_entry_dma); 1177b3a271a9SManish Rangankar return ret; 1178b3a271a9SManish Rangankar } 1179b3a271a9SManish Rangankar 1180b3a271a9SManish Rangankar static void qla4xxx_conn_destroy(struct iscsi_cls_conn *cls_conn) 1181b3a271a9SManish Rangankar { 1182b3a271a9SManish Rangankar struct iscsi_cls_session *cls_sess = iscsi_conn_to_session(cls_conn); 1183b3a271a9SManish Rangankar struct iscsi_session *sess; 1184b3a271a9SManish Rangankar struct scsi_qla_host *ha; 1185b3a271a9SManish Rangankar struct ddb_entry *ddb_entry; 1186b3a271a9SManish Rangankar int options; 1187b3a271a9SManish Rangankar 1188b3a271a9SManish Rangankar DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); 1189b3a271a9SManish Rangankar sess = cls_sess->dd_data; 1190b3a271a9SManish Rangankar ddb_entry = sess->dd_data; 1191b3a271a9SManish Rangankar ha = ddb_entry->ha; 1192b3a271a9SManish Rangankar 1193b3a271a9SManish Rangankar options = LOGOUT_OPTION_CLOSE_SESSION; 1194b3a271a9SManish Rangankar if (qla4xxx_session_logout_ddb(ha, ddb_entry, options) == QLA_ERROR) 1195b3a271a9SManish Rangankar ql4_printk(KERN_ERR, ha, "%s: Logout failed\n", __func__); 1196b3a271a9SManish Rangankar } 1197b3a271a9SManish Rangankar 1198b3a271a9SManish Rangankar static void qla4xxx_task_work(struct work_struct *wdata) 1199b3a271a9SManish Rangankar { 1200b3a271a9SManish Rangankar struct ql4_task_data *task_data; 1201b3a271a9SManish Rangankar struct scsi_qla_host *ha; 1202b3a271a9SManish Rangankar struct passthru_status *sts; 1203b3a271a9SManish Rangankar struct iscsi_task *task; 1204b3a271a9SManish Rangankar struct iscsi_hdr *hdr; 1205b3a271a9SManish Rangankar uint8_t *data; 1206b3a271a9SManish Rangankar uint32_t data_len; 1207b3a271a9SManish Rangankar struct iscsi_conn *conn; 1208b3a271a9SManish Rangankar int hdr_len; 1209b3a271a9SManish Rangankar itt_t itt; 1210b3a271a9SManish Rangankar 1211b3a271a9SManish Rangankar task_data = container_of(wdata, struct ql4_task_data, task_work); 1212b3a271a9SManish Rangankar ha = task_data->ha; 1213b3a271a9SManish Rangankar task = task_data->task; 1214b3a271a9SManish Rangankar sts = &task_data->sts; 1215b3a271a9SManish Rangankar hdr_len = sizeof(struct iscsi_hdr); 1216b3a271a9SManish Rangankar 1217b3a271a9SManish Rangankar DEBUG3(printk(KERN_INFO "Status returned\n")); 1218b3a271a9SManish Rangankar DEBUG3(qla4xxx_dump_buffer(sts, 64)); 1219b3a271a9SManish Rangankar DEBUG3(printk(KERN_INFO "Response buffer")); 1220b3a271a9SManish Rangankar DEBUG3(qla4xxx_dump_buffer(task_data->resp_buffer, 64)); 1221b3a271a9SManish Rangankar 1222b3a271a9SManish Rangankar conn = task->conn; 1223b3a271a9SManish Rangankar 1224b3a271a9SManish Rangankar switch (sts->completionStatus) { 1225b3a271a9SManish Rangankar case PASSTHRU_STATUS_COMPLETE: 1226b3a271a9SManish Rangankar hdr = (struct iscsi_hdr *)task_data->resp_buffer; 1227b3a271a9SManish Rangankar /* Assign back the itt in hdr, until we use the PREASSIGN_TAG */ 1228b3a271a9SManish Rangankar itt = sts->handle; 1229b3a271a9SManish Rangankar hdr->itt = itt; 1230b3a271a9SManish Rangankar data = task_data->resp_buffer + hdr_len; 1231b3a271a9SManish Rangankar data_len = task_data->resp_len - hdr_len; 1232b3a271a9SManish Rangankar iscsi_complete_pdu(conn, hdr, data, data_len); 1233b3a271a9SManish Rangankar break; 1234b3a271a9SManish Rangankar default: 1235b3a271a9SManish Rangankar ql4_printk(KERN_ERR, ha, "Passthru failed status = 0x%x\n", 1236b3a271a9SManish Rangankar sts->completionStatus); 1237b3a271a9SManish Rangankar break; 1238b3a271a9SManish Rangankar } 1239b3a271a9SManish Rangankar return; 1240b3a271a9SManish Rangankar } 1241b3a271a9SManish Rangankar 1242b3a271a9SManish Rangankar static int qla4xxx_alloc_pdu(struct iscsi_task *task, uint8_t opcode) 1243b3a271a9SManish Rangankar { 1244b3a271a9SManish Rangankar struct ql4_task_data *task_data; 1245b3a271a9SManish Rangankar struct iscsi_session *sess; 1246b3a271a9SManish Rangankar struct ddb_entry *ddb_entry; 1247b3a271a9SManish Rangankar struct scsi_qla_host *ha; 1248b3a271a9SManish Rangankar int hdr_len; 1249b3a271a9SManish Rangankar 1250b3a271a9SManish Rangankar sess = task->conn->session; 1251b3a271a9SManish Rangankar ddb_entry = sess->dd_data; 1252b3a271a9SManish Rangankar ha = ddb_entry->ha; 1253b3a271a9SManish Rangankar task_data = task->dd_data; 1254b3a271a9SManish Rangankar memset(task_data, 0, sizeof(struct ql4_task_data)); 1255b3a271a9SManish Rangankar 1256b3a271a9SManish Rangankar if (task->sc) { 1257b3a271a9SManish Rangankar ql4_printk(KERN_INFO, ha, 1258b3a271a9SManish Rangankar "%s: SCSI Commands not implemented\n", __func__); 1259b3a271a9SManish Rangankar return -EINVAL; 1260b3a271a9SManish Rangankar } 1261b3a271a9SManish Rangankar 1262b3a271a9SManish Rangankar hdr_len = sizeof(struct iscsi_hdr); 1263b3a271a9SManish Rangankar task_data->ha = ha; 1264b3a271a9SManish Rangankar task_data->task = task; 1265b3a271a9SManish Rangankar 1266b3a271a9SManish Rangankar if (task->data_count) { 1267b3a271a9SManish Rangankar task_data->data_dma = dma_map_single(&ha->pdev->dev, task->data, 1268b3a271a9SManish Rangankar task->data_count, 1269b3a271a9SManish Rangankar PCI_DMA_TODEVICE); 1270b3a271a9SManish Rangankar } 1271b3a271a9SManish Rangankar 1272b3a271a9SManish Rangankar DEBUG2(ql4_printk(KERN_INFO, ha, "%s: MaxRecvLen %u, iscsi hrd %d\n", 1273b3a271a9SManish Rangankar __func__, task->conn->max_recv_dlength, hdr_len)); 1274b3a271a9SManish Rangankar 127569ca216eSManish Rangankar task_data->resp_len = task->conn->max_recv_dlength + hdr_len; 1276b3a271a9SManish Rangankar task_data->resp_buffer = dma_alloc_coherent(&ha->pdev->dev, 1277b3a271a9SManish Rangankar task_data->resp_len, 1278b3a271a9SManish Rangankar &task_data->resp_dma, 1279b3a271a9SManish Rangankar GFP_ATOMIC); 1280b3a271a9SManish Rangankar if (!task_data->resp_buffer) 1281b3a271a9SManish Rangankar goto exit_alloc_pdu; 1282b3a271a9SManish Rangankar 128369ca216eSManish Rangankar task_data->req_len = task->data_count + hdr_len; 1284b3a271a9SManish Rangankar task_data->req_buffer = dma_alloc_coherent(&ha->pdev->dev, 128569ca216eSManish Rangankar task_data->req_len, 1286b3a271a9SManish Rangankar &task_data->req_dma, 1287b3a271a9SManish Rangankar GFP_ATOMIC); 1288b3a271a9SManish Rangankar if (!task_data->req_buffer) 1289b3a271a9SManish Rangankar goto exit_alloc_pdu; 1290b3a271a9SManish Rangankar 1291b3a271a9SManish Rangankar task->hdr = task_data->req_buffer; 1292b3a271a9SManish Rangankar 1293b3a271a9SManish Rangankar INIT_WORK(&task_data->task_work, qla4xxx_task_work); 1294b3a271a9SManish Rangankar 1295b3a271a9SManish Rangankar return 0; 1296b3a271a9SManish Rangankar 1297b3a271a9SManish Rangankar exit_alloc_pdu: 1298b3a271a9SManish Rangankar if (task_data->resp_buffer) 1299b3a271a9SManish Rangankar dma_free_coherent(&ha->pdev->dev, task_data->resp_len, 1300b3a271a9SManish Rangankar task_data->resp_buffer, task_data->resp_dma); 1301b3a271a9SManish Rangankar 1302b3a271a9SManish Rangankar if (task_data->req_buffer) 130369ca216eSManish Rangankar dma_free_coherent(&ha->pdev->dev, task_data->req_len, 1304b3a271a9SManish Rangankar task_data->req_buffer, task_data->req_dma); 1305b3a271a9SManish Rangankar return -ENOMEM; 1306b3a271a9SManish Rangankar } 1307b3a271a9SManish Rangankar 1308b3a271a9SManish Rangankar static void qla4xxx_task_cleanup(struct iscsi_task *task) 1309b3a271a9SManish Rangankar { 1310b3a271a9SManish Rangankar struct ql4_task_data *task_data; 1311b3a271a9SManish Rangankar struct iscsi_session *sess; 1312b3a271a9SManish Rangankar struct ddb_entry *ddb_entry; 1313b3a271a9SManish Rangankar struct scsi_qla_host *ha; 1314b3a271a9SManish Rangankar int hdr_len; 1315b3a271a9SManish Rangankar 1316b3a271a9SManish Rangankar hdr_len = sizeof(struct iscsi_hdr); 1317b3a271a9SManish Rangankar sess = task->conn->session; 1318b3a271a9SManish Rangankar ddb_entry = sess->dd_data; 1319b3a271a9SManish Rangankar ha = ddb_entry->ha; 1320b3a271a9SManish Rangankar task_data = task->dd_data; 1321b3a271a9SManish Rangankar 1322b3a271a9SManish Rangankar if (task->data_count) { 1323b3a271a9SManish Rangankar dma_unmap_single(&ha->pdev->dev, task_data->data_dma, 1324b3a271a9SManish Rangankar task->data_count, PCI_DMA_TODEVICE); 1325b3a271a9SManish Rangankar } 1326b3a271a9SManish Rangankar 1327b3a271a9SManish Rangankar DEBUG2(ql4_printk(KERN_INFO, ha, "%s: MaxRecvLen %u, iscsi hrd %d\n", 1328b3a271a9SManish Rangankar __func__, task->conn->max_recv_dlength, hdr_len)); 1329b3a271a9SManish Rangankar 1330b3a271a9SManish Rangankar dma_free_coherent(&ha->pdev->dev, task_data->resp_len, 1331b3a271a9SManish Rangankar task_data->resp_buffer, task_data->resp_dma); 133269ca216eSManish Rangankar dma_free_coherent(&ha->pdev->dev, task_data->req_len, 1333b3a271a9SManish Rangankar task_data->req_buffer, task_data->req_dma); 1334b3a271a9SManish Rangankar return; 1335b3a271a9SManish Rangankar } 1336b3a271a9SManish Rangankar 1337b3a271a9SManish Rangankar static int qla4xxx_task_xmit(struct iscsi_task *task) 1338b3a271a9SManish Rangankar { 1339b3a271a9SManish Rangankar struct scsi_cmnd *sc = task->sc; 1340b3a271a9SManish Rangankar struct iscsi_session *sess = task->conn->session; 1341b3a271a9SManish Rangankar struct ddb_entry *ddb_entry = sess->dd_data; 1342b3a271a9SManish Rangankar struct scsi_qla_host *ha = ddb_entry->ha; 1343b3a271a9SManish Rangankar 1344b3a271a9SManish Rangankar if (!sc) 1345b3a271a9SManish Rangankar return qla4xxx_send_passthru0(task); 1346b3a271a9SManish Rangankar 1347b3a271a9SManish Rangankar ql4_printk(KERN_INFO, ha, "%s: scsi cmd xmit not implemented\n", 1348b3a271a9SManish Rangankar __func__); 1349b3a271a9SManish Rangankar return -ENOSYS; 1350b3a271a9SManish Rangankar } 1351b3a271a9SManish Rangankar 1352b3a271a9SManish Rangankar void qla4xxx_update_session_conn_param(struct scsi_qla_host *ha, 1353b3a271a9SManish Rangankar struct ddb_entry *ddb_entry) 1354b3a271a9SManish Rangankar { 1355b3a271a9SManish Rangankar struct iscsi_cls_session *cls_sess; 1356b3a271a9SManish Rangankar struct iscsi_cls_conn *cls_conn; 1357b3a271a9SManish Rangankar struct iscsi_session *sess; 1358b3a271a9SManish Rangankar struct iscsi_conn *conn; 1359b3a271a9SManish Rangankar uint32_t ddb_state; 1360b3a271a9SManish Rangankar dma_addr_t fw_ddb_entry_dma; 1361b3a271a9SManish Rangankar struct dev_db_entry *fw_ddb_entry; 1362b3a271a9SManish Rangankar 1363b3a271a9SManish Rangankar fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), 1364b3a271a9SManish Rangankar &fw_ddb_entry_dma, GFP_KERNEL); 1365b3a271a9SManish Rangankar if (!fw_ddb_entry) { 1366b3a271a9SManish Rangankar ql4_printk(KERN_ERR, ha, 1367b3a271a9SManish Rangankar "%s: Unable to allocate dma buffer\n", __func__); 1368b3a271a9SManish Rangankar return; 1369b3a271a9SManish Rangankar } 1370b3a271a9SManish Rangankar 1371b3a271a9SManish Rangankar if (qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index, fw_ddb_entry, 1372b3a271a9SManish Rangankar fw_ddb_entry_dma, NULL, NULL, &ddb_state, 1373b3a271a9SManish Rangankar NULL, NULL, NULL) == QLA_ERROR) { 1374b3a271a9SManish Rangankar DEBUG2(ql4_printk(KERN_ERR, ha, "scsi%ld: %s: failed " 1375b3a271a9SManish Rangankar "get_ddb_entry for fw_ddb_index %d\n", 1376b3a271a9SManish Rangankar ha->host_no, __func__, 1377b3a271a9SManish Rangankar ddb_entry->fw_ddb_index)); 1378b3a271a9SManish Rangankar return; 1379b3a271a9SManish Rangankar } 1380b3a271a9SManish Rangankar 1381b3a271a9SManish Rangankar cls_sess = ddb_entry->sess; 1382b3a271a9SManish Rangankar sess = cls_sess->dd_data; 1383b3a271a9SManish Rangankar 1384b3a271a9SManish Rangankar cls_conn = ddb_entry->conn; 1385b3a271a9SManish Rangankar conn = cls_conn->dd_data; 1386b3a271a9SManish Rangankar 1387b3a271a9SManish Rangankar /* Update params */ 1388b3a271a9SManish Rangankar conn->max_recv_dlength = BYTE_UNITS * 1389b3a271a9SManish Rangankar le16_to_cpu(fw_ddb_entry->iscsi_max_rcv_data_seg_len); 1390b3a271a9SManish Rangankar 1391b3a271a9SManish Rangankar conn->max_xmit_dlength = BYTE_UNITS * 1392b3a271a9SManish Rangankar le16_to_cpu(fw_ddb_entry->iscsi_max_snd_data_seg_len); 1393b3a271a9SManish Rangankar 1394b3a271a9SManish Rangankar sess->initial_r2t_en = 1395b3a271a9SManish Rangankar (BIT_10 & le16_to_cpu(fw_ddb_entry->iscsi_options)); 1396b3a271a9SManish Rangankar 1397b3a271a9SManish Rangankar sess->max_r2t = le16_to_cpu(fw_ddb_entry->iscsi_max_outsnd_r2t); 1398b3a271a9SManish Rangankar 1399b3a271a9SManish Rangankar sess->imm_data_en = (BIT_11 & le16_to_cpu(fw_ddb_entry->iscsi_options)); 1400b3a271a9SManish Rangankar 1401b3a271a9SManish Rangankar sess->first_burst = BYTE_UNITS * 1402b3a271a9SManish Rangankar le16_to_cpu(fw_ddb_entry->iscsi_first_burst_len); 1403b3a271a9SManish Rangankar 1404b3a271a9SManish Rangankar sess->max_burst = BYTE_UNITS * 1405b3a271a9SManish Rangankar le16_to_cpu(fw_ddb_entry->iscsi_max_burst_len); 1406b3a271a9SManish Rangankar 1407b3a271a9SManish Rangankar sess->time2wait = le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait); 1408b3a271a9SManish Rangankar 1409b3a271a9SManish Rangankar sess->time2retain = le16_to_cpu(fw_ddb_entry->iscsi_def_time2retain); 1410b3a271a9SManish Rangankar 1411b3a271a9SManish Rangankar sess->tpgt = le32_to_cpu(fw_ddb_entry->tgt_portal_grp); 1412b3a271a9SManish Rangankar 1413b3a271a9SManish Rangankar memcpy(sess->initiatorname, ha->name_string, 1414b3a271a9SManish Rangankar min(sizeof(ha->name_string), sizeof(sess->initiatorname))); 1415b3a271a9SManish Rangankar } 1416b3a271a9SManish Rangankar 1417afaf5a2dSDavid Somayajulu /* 1418afaf5a2dSDavid Somayajulu * Timer routines 1419afaf5a2dSDavid Somayajulu */ 1420afaf5a2dSDavid Somayajulu 1421afaf5a2dSDavid Somayajulu static void qla4xxx_start_timer(struct scsi_qla_host *ha, void *func, 1422afaf5a2dSDavid Somayajulu unsigned long interval) 1423afaf5a2dSDavid Somayajulu { 1424afaf5a2dSDavid Somayajulu DEBUG(printk("scsi: %s: Starting timer thread for adapter %d\n", 1425afaf5a2dSDavid Somayajulu __func__, ha->host->host_no)); 1426afaf5a2dSDavid Somayajulu init_timer(&ha->timer); 1427afaf5a2dSDavid Somayajulu ha->timer.expires = jiffies + interval * HZ; 1428afaf5a2dSDavid Somayajulu ha->timer.data = (unsigned long)ha; 1429afaf5a2dSDavid Somayajulu ha->timer.function = (void (*)(unsigned long))func; 1430afaf5a2dSDavid Somayajulu add_timer(&ha->timer); 1431afaf5a2dSDavid Somayajulu ha->timer_active = 1; 1432afaf5a2dSDavid Somayajulu } 1433afaf5a2dSDavid Somayajulu 1434afaf5a2dSDavid Somayajulu static void qla4xxx_stop_timer(struct scsi_qla_host *ha) 1435afaf5a2dSDavid Somayajulu { 1436afaf5a2dSDavid Somayajulu del_timer_sync(&ha->timer); 1437afaf5a2dSDavid Somayajulu ha->timer_active = 0; 1438afaf5a2dSDavid Somayajulu } 1439afaf5a2dSDavid Somayajulu 1440afaf5a2dSDavid Somayajulu /*** 1441b3a271a9SManish Rangankar * qla4xxx_mark_device_missing - blocks the session 1442b3a271a9SManish Rangankar * @cls_session: Pointer to the session to be blocked 1443afaf5a2dSDavid Somayajulu * @ddb_entry: Pointer to device database entry 1444afaf5a2dSDavid Somayajulu * 1445f4f5df23SVikas Chaudhary * This routine marks a device missing and close connection. 1446afaf5a2dSDavid Somayajulu **/ 1447b3a271a9SManish Rangankar void qla4xxx_mark_device_missing(struct iscsi_cls_session *cls_session) 1448afaf5a2dSDavid Somayajulu { 1449b3a271a9SManish Rangankar iscsi_block_session(cls_session); 1450afaf5a2dSDavid Somayajulu } 1451afaf5a2dSDavid Somayajulu 1452f4f5df23SVikas Chaudhary /** 1453f4f5df23SVikas Chaudhary * qla4xxx_mark_all_devices_missing - mark all devices as missing. 1454f4f5df23SVikas Chaudhary * @ha: Pointer to host adapter structure. 1455f4f5df23SVikas Chaudhary * 1456f4f5df23SVikas Chaudhary * This routine marks a device missing and resets the relogin retry count. 1457f4f5df23SVikas Chaudhary **/ 1458f4f5df23SVikas Chaudhary void qla4xxx_mark_all_devices_missing(struct scsi_qla_host *ha) 1459f4f5df23SVikas Chaudhary { 1460b3a271a9SManish Rangankar iscsi_host_for_each_session(ha->host, qla4xxx_mark_device_missing); 1461f4f5df23SVikas Chaudhary } 1462f4f5df23SVikas Chaudhary 1463afaf5a2dSDavid Somayajulu static struct srb* qla4xxx_get_new_srb(struct scsi_qla_host *ha, 1464afaf5a2dSDavid Somayajulu struct ddb_entry *ddb_entry, 14658f0722caSVikas Chaudhary struct scsi_cmnd *cmd) 1466afaf5a2dSDavid Somayajulu { 1467afaf5a2dSDavid Somayajulu struct srb *srb; 1468afaf5a2dSDavid Somayajulu 1469afaf5a2dSDavid Somayajulu srb = mempool_alloc(ha->srb_mempool, GFP_ATOMIC); 1470afaf5a2dSDavid Somayajulu if (!srb) 1471afaf5a2dSDavid Somayajulu return srb; 1472afaf5a2dSDavid Somayajulu 147309a0f719SVikas Chaudhary kref_init(&srb->srb_ref); 1474afaf5a2dSDavid Somayajulu srb->ha = ha; 1475afaf5a2dSDavid Somayajulu srb->ddb = ddb_entry; 1476afaf5a2dSDavid Somayajulu srb->cmd = cmd; 1477afaf5a2dSDavid Somayajulu srb->flags = 0; 14785369887aSVikas Chaudhary CMD_SP(cmd) = (void *)srb; 1479afaf5a2dSDavid Somayajulu 1480afaf5a2dSDavid Somayajulu return srb; 1481afaf5a2dSDavid Somayajulu } 1482afaf5a2dSDavid Somayajulu 1483afaf5a2dSDavid Somayajulu static void qla4xxx_srb_free_dma(struct scsi_qla_host *ha, struct srb *srb) 1484afaf5a2dSDavid Somayajulu { 1485afaf5a2dSDavid Somayajulu struct scsi_cmnd *cmd = srb->cmd; 1486afaf5a2dSDavid Somayajulu 1487afaf5a2dSDavid Somayajulu if (srb->flags & SRB_DMA_VALID) { 14885f7186c8SFUJITA Tomonori scsi_dma_unmap(cmd); 1489afaf5a2dSDavid Somayajulu srb->flags &= ~SRB_DMA_VALID; 1490afaf5a2dSDavid Somayajulu } 14915369887aSVikas Chaudhary CMD_SP(cmd) = NULL; 1492afaf5a2dSDavid Somayajulu } 1493afaf5a2dSDavid Somayajulu 149409a0f719SVikas Chaudhary void qla4xxx_srb_compl(struct kref *ref) 1495afaf5a2dSDavid Somayajulu { 149609a0f719SVikas Chaudhary struct srb *srb = container_of(ref, struct srb, srb_ref); 1497afaf5a2dSDavid Somayajulu struct scsi_cmnd *cmd = srb->cmd; 149809a0f719SVikas Chaudhary struct scsi_qla_host *ha = srb->ha; 1499afaf5a2dSDavid Somayajulu 1500afaf5a2dSDavid Somayajulu qla4xxx_srb_free_dma(ha, srb); 1501afaf5a2dSDavid Somayajulu 1502afaf5a2dSDavid Somayajulu mempool_free(srb, ha->srb_mempool); 1503afaf5a2dSDavid Somayajulu 1504afaf5a2dSDavid Somayajulu cmd->scsi_done(cmd); 1505afaf5a2dSDavid Somayajulu } 1506afaf5a2dSDavid Somayajulu 1507afaf5a2dSDavid Somayajulu /** 1508afaf5a2dSDavid Somayajulu * qla4xxx_queuecommand - scsi layer issues scsi command to driver. 15098f0722caSVikas Chaudhary * @host: scsi host 1510afaf5a2dSDavid Somayajulu * @cmd: Pointer to Linux's SCSI command structure 1511afaf5a2dSDavid Somayajulu * 1512afaf5a2dSDavid Somayajulu * Remarks: 1513afaf5a2dSDavid Somayajulu * This routine is invoked by Linux to send a SCSI command to the driver. 1514afaf5a2dSDavid Somayajulu * The mid-level driver tries to ensure that queuecommand never gets 1515afaf5a2dSDavid Somayajulu * invoked concurrently with itself or the interrupt handler (although 1516afaf5a2dSDavid Somayajulu * the interrupt handler may call this routine as part of request- 1517afaf5a2dSDavid Somayajulu * completion handling). Unfortunely, it sometimes calls the scheduler 1518afaf5a2dSDavid Somayajulu * in interrupt context which is a big NO! NO!. 1519afaf5a2dSDavid Somayajulu **/ 15208f0722caSVikas Chaudhary static int qla4xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) 1521afaf5a2dSDavid Somayajulu { 15228f0722caSVikas Chaudhary struct scsi_qla_host *ha = to_qla_host(host); 1523afaf5a2dSDavid Somayajulu struct ddb_entry *ddb_entry = cmd->device->hostdata; 15247fb1921bSMike Christie struct iscsi_cls_session *sess = ddb_entry->sess; 1525afaf5a2dSDavid Somayajulu struct srb *srb; 1526afaf5a2dSDavid Somayajulu int rval; 1527afaf5a2dSDavid Somayajulu 15282232be0dSLalit Chandivade if (test_bit(AF_EEH_BUSY, &ha->flags)) { 15292232be0dSLalit Chandivade if (test_bit(AF_PCI_CHANNEL_IO_PERM_FAILURE, &ha->flags)) 15302232be0dSLalit Chandivade cmd->result = DID_NO_CONNECT << 16; 15312232be0dSLalit Chandivade else 15322232be0dSLalit Chandivade cmd->result = DID_REQUEUE << 16; 15332232be0dSLalit Chandivade goto qc_fail_command; 15342232be0dSLalit Chandivade } 15352232be0dSLalit Chandivade 15367fb1921bSMike Christie if (!sess) { 15377fb1921bSMike Christie cmd->result = DID_IMM_RETRY << 16; 15387fb1921bSMike Christie goto qc_fail_command; 15397fb1921bSMike Christie } 15407fb1921bSMike Christie 15417fb1921bSMike Christie rval = iscsi_session_chkready(sess); 15427fb1921bSMike Christie if (rval) { 15437fb1921bSMike Christie cmd->result = rval; 15447fb1921bSMike Christie goto qc_fail_command; 15457fb1921bSMike Christie } 15467fb1921bSMike Christie 1547f4f5df23SVikas Chaudhary if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) || 1548f4f5df23SVikas Chaudhary test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags) || 1549f4f5df23SVikas Chaudhary test_bit(DPC_RESET_HA, &ha->dpc_flags) || 1550f4f5df23SVikas Chaudhary test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags) || 1551f4f5df23SVikas Chaudhary test_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags) || 1552f4f5df23SVikas Chaudhary !test_bit(AF_ONLINE, &ha->flags) || 1553b3a271a9SManish Rangankar !test_bit(AF_LINK_UP, &ha->flags) || 1554f4f5df23SVikas Chaudhary test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags)) 1555477ffb9dSDavid C Somayajulu goto qc_host_busy; 1556477ffb9dSDavid C Somayajulu 15578f0722caSVikas Chaudhary srb = qla4xxx_get_new_srb(ha, ddb_entry, cmd); 1558afaf5a2dSDavid Somayajulu if (!srb) 15598f0722caSVikas Chaudhary goto qc_host_busy; 1560afaf5a2dSDavid Somayajulu 1561afaf5a2dSDavid Somayajulu rval = qla4xxx_send_command_to_isp(ha, srb); 1562afaf5a2dSDavid Somayajulu if (rval != QLA_SUCCESS) 1563afaf5a2dSDavid Somayajulu goto qc_host_busy_free_sp; 1564afaf5a2dSDavid Somayajulu 1565afaf5a2dSDavid Somayajulu return 0; 1566afaf5a2dSDavid Somayajulu 1567afaf5a2dSDavid Somayajulu qc_host_busy_free_sp: 1568afaf5a2dSDavid Somayajulu qla4xxx_srb_free_dma(ha, srb); 1569afaf5a2dSDavid Somayajulu mempool_free(srb, ha->srb_mempool); 1570afaf5a2dSDavid Somayajulu 1571afaf5a2dSDavid Somayajulu qc_host_busy: 1572afaf5a2dSDavid Somayajulu return SCSI_MLQUEUE_HOST_BUSY; 1573afaf5a2dSDavid Somayajulu 1574afaf5a2dSDavid Somayajulu qc_fail_command: 15758f0722caSVikas Chaudhary cmd->scsi_done(cmd); 1576afaf5a2dSDavid Somayajulu 1577afaf5a2dSDavid Somayajulu return 0; 1578afaf5a2dSDavid Somayajulu } 1579afaf5a2dSDavid Somayajulu 1580afaf5a2dSDavid Somayajulu /** 1581afaf5a2dSDavid Somayajulu * qla4xxx_mem_free - frees memory allocated to adapter 1582afaf5a2dSDavid Somayajulu * @ha: Pointer to host adapter structure. 1583afaf5a2dSDavid Somayajulu * 1584afaf5a2dSDavid Somayajulu * Frees memory previously allocated by qla4xxx_mem_alloc 1585afaf5a2dSDavid Somayajulu **/ 1586afaf5a2dSDavid Somayajulu static void qla4xxx_mem_free(struct scsi_qla_host *ha) 1587afaf5a2dSDavid Somayajulu { 1588afaf5a2dSDavid Somayajulu if (ha->queues) 1589afaf5a2dSDavid Somayajulu dma_free_coherent(&ha->pdev->dev, ha->queues_len, ha->queues, 1590afaf5a2dSDavid Somayajulu ha->queues_dma); 1591afaf5a2dSDavid Somayajulu 1592afaf5a2dSDavid Somayajulu ha->queues_len = 0; 1593afaf5a2dSDavid Somayajulu ha->queues = NULL; 1594afaf5a2dSDavid Somayajulu ha->queues_dma = 0; 1595afaf5a2dSDavid Somayajulu ha->request_ring = NULL; 1596afaf5a2dSDavid Somayajulu ha->request_dma = 0; 1597afaf5a2dSDavid Somayajulu ha->response_ring = NULL; 1598afaf5a2dSDavid Somayajulu ha->response_dma = 0; 1599afaf5a2dSDavid Somayajulu ha->shadow_regs = NULL; 1600afaf5a2dSDavid Somayajulu ha->shadow_regs_dma = 0; 1601afaf5a2dSDavid Somayajulu 1602afaf5a2dSDavid Somayajulu /* Free srb pool. */ 1603afaf5a2dSDavid Somayajulu if (ha->srb_mempool) 1604afaf5a2dSDavid Somayajulu mempool_destroy(ha->srb_mempool); 1605afaf5a2dSDavid Somayajulu 1606afaf5a2dSDavid Somayajulu ha->srb_mempool = NULL; 1607afaf5a2dSDavid Somayajulu 1608b3a271a9SManish Rangankar if (ha->chap_dma_pool) 1609b3a271a9SManish Rangankar dma_pool_destroy(ha->chap_dma_pool); 1610b3a271a9SManish Rangankar 16114549415aSLalit Chandivade if (ha->chap_list) 16124549415aSLalit Chandivade vfree(ha->chap_list); 16134549415aSLalit Chandivade ha->chap_list = NULL; 16144549415aSLalit Chandivade 1615afaf5a2dSDavid Somayajulu /* release io space registers */ 1616f4f5df23SVikas Chaudhary if (is_qla8022(ha)) { 1617f4f5df23SVikas Chaudhary if (ha->nx_pcibase) 1618f4f5df23SVikas Chaudhary iounmap( 1619f4f5df23SVikas Chaudhary (struct device_reg_82xx __iomem *)ha->nx_pcibase); 1620f4f5df23SVikas Chaudhary } else if (ha->reg) 1621afaf5a2dSDavid Somayajulu iounmap(ha->reg); 1622afaf5a2dSDavid Somayajulu pci_release_regions(ha->pdev); 1623afaf5a2dSDavid Somayajulu } 1624afaf5a2dSDavid Somayajulu 1625afaf5a2dSDavid Somayajulu /** 1626afaf5a2dSDavid Somayajulu * qla4xxx_mem_alloc - allocates memory for use by adapter. 1627afaf5a2dSDavid Somayajulu * @ha: Pointer to host adapter structure 1628afaf5a2dSDavid Somayajulu * 1629afaf5a2dSDavid Somayajulu * Allocates DMA memory for request and response queues. Also allocates memory 1630afaf5a2dSDavid Somayajulu * for srbs. 1631afaf5a2dSDavid Somayajulu **/ 1632afaf5a2dSDavid Somayajulu static int qla4xxx_mem_alloc(struct scsi_qla_host *ha) 1633afaf5a2dSDavid Somayajulu { 1634afaf5a2dSDavid Somayajulu unsigned long align; 1635afaf5a2dSDavid Somayajulu 1636afaf5a2dSDavid Somayajulu /* Allocate contiguous block of DMA memory for queues. */ 1637afaf5a2dSDavid Somayajulu ha->queues_len = ((REQUEST_QUEUE_DEPTH * QUEUE_SIZE) + 1638afaf5a2dSDavid Somayajulu (RESPONSE_QUEUE_DEPTH * QUEUE_SIZE) + 1639afaf5a2dSDavid Somayajulu sizeof(struct shadow_regs) + 1640afaf5a2dSDavid Somayajulu MEM_ALIGN_VALUE + 1641afaf5a2dSDavid Somayajulu (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1); 1642afaf5a2dSDavid Somayajulu ha->queues = dma_alloc_coherent(&ha->pdev->dev, ha->queues_len, 1643afaf5a2dSDavid Somayajulu &ha->queues_dma, GFP_KERNEL); 1644afaf5a2dSDavid Somayajulu if (ha->queues == NULL) { 1645c2660df3SVikas Chaudhary ql4_printk(KERN_WARNING, ha, 1646afaf5a2dSDavid Somayajulu "Memory Allocation failed - queues.\n"); 1647afaf5a2dSDavid Somayajulu 1648afaf5a2dSDavid Somayajulu goto mem_alloc_error_exit; 1649afaf5a2dSDavid Somayajulu } 1650afaf5a2dSDavid Somayajulu memset(ha->queues, 0, ha->queues_len); 1651afaf5a2dSDavid Somayajulu 1652afaf5a2dSDavid Somayajulu /* 1653afaf5a2dSDavid Somayajulu * As per RISC alignment requirements -- the bus-address must be a 1654afaf5a2dSDavid Somayajulu * multiple of the request-ring size (in bytes). 1655afaf5a2dSDavid Somayajulu */ 1656afaf5a2dSDavid Somayajulu align = 0; 1657afaf5a2dSDavid Somayajulu if ((unsigned long)ha->queues_dma & (MEM_ALIGN_VALUE - 1)) 1658afaf5a2dSDavid Somayajulu align = MEM_ALIGN_VALUE - ((unsigned long)ha->queues_dma & 1659afaf5a2dSDavid Somayajulu (MEM_ALIGN_VALUE - 1)); 1660afaf5a2dSDavid Somayajulu 1661afaf5a2dSDavid Somayajulu /* Update request and response queue pointers. */ 1662afaf5a2dSDavid Somayajulu ha->request_dma = ha->queues_dma + align; 1663afaf5a2dSDavid Somayajulu ha->request_ring = (struct queue_entry *) (ha->queues + align); 1664afaf5a2dSDavid Somayajulu ha->response_dma = ha->queues_dma + align + 1665afaf5a2dSDavid Somayajulu (REQUEST_QUEUE_DEPTH * QUEUE_SIZE); 1666afaf5a2dSDavid Somayajulu ha->response_ring = (struct queue_entry *) (ha->queues + align + 1667afaf5a2dSDavid Somayajulu (REQUEST_QUEUE_DEPTH * 1668afaf5a2dSDavid Somayajulu QUEUE_SIZE)); 1669afaf5a2dSDavid Somayajulu ha->shadow_regs_dma = ha->queues_dma + align + 1670afaf5a2dSDavid Somayajulu (REQUEST_QUEUE_DEPTH * QUEUE_SIZE) + 1671afaf5a2dSDavid Somayajulu (RESPONSE_QUEUE_DEPTH * QUEUE_SIZE); 1672afaf5a2dSDavid Somayajulu ha->shadow_regs = (struct shadow_regs *) (ha->queues + align + 1673afaf5a2dSDavid Somayajulu (REQUEST_QUEUE_DEPTH * 1674afaf5a2dSDavid Somayajulu QUEUE_SIZE) + 1675afaf5a2dSDavid Somayajulu (RESPONSE_QUEUE_DEPTH * 1676afaf5a2dSDavid Somayajulu QUEUE_SIZE)); 1677afaf5a2dSDavid Somayajulu 1678afaf5a2dSDavid Somayajulu /* Allocate memory for srb pool. */ 1679afaf5a2dSDavid Somayajulu ha->srb_mempool = mempool_create(SRB_MIN_REQ, mempool_alloc_slab, 1680afaf5a2dSDavid Somayajulu mempool_free_slab, srb_cachep); 1681afaf5a2dSDavid Somayajulu if (ha->srb_mempool == NULL) { 1682c2660df3SVikas Chaudhary ql4_printk(KERN_WARNING, ha, 1683afaf5a2dSDavid Somayajulu "Memory Allocation failed - SRB Pool.\n"); 1684afaf5a2dSDavid Somayajulu 1685afaf5a2dSDavid Somayajulu goto mem_alloc_error_exit; 1686afaf5a2dSDavid Somayajulu } 1687afaf5a2dSDavid Somayajulu 1688b3a271a9SManish Rangankar ha->chap_dma_pool = dma_pool_create("ql4_chap", &ha->pdev->dev, 1689b3a271a9SManish Rangankar CHAP_DMA_BLOCK_SIZE, 8, 0); 1690b3a271a9SManish Rangankar 1691b3a271a9SManish Rangankar if (ha->chap_dma_pool == NULL) { 1692b3a271a9SManish Rangankar ql4_printk(KERN_WARNING, ha, 1693b3a271a9SManish Rangankar "%s: chap_dma_pool allocation failed..\n", __func__); 1694b3a271a9SManish Rangankar goto mem_alloc_error_exit; 1695b3a271a9SManish Rangankar } 1696b3a271a9SManish Rangankar 1697afaf5a2dSDavid Somayajulu return QLA_SUCCESS; 1698afaf5a2dSDavid Somayajulu 1699afaf5a2dSDavid Somayajulu mem_alloc_error_exit: 1700afaf5a2dSDavid Somayajulu qla4xxx_mem_free(ha); 1701afaf5a2dSDavid Somayajulu return QLA_ERROR; 1702afaf5a2dSDavid Somayajulu } 1703afaf5a2dSDavid Somayajulu 1704afaf5a2dSDavid Somayajulu /** 1705f4f5df23SVikas Chaudhary * qla4_8xxx_check_fw_alive - Check firmware health 1706f4f5df23SVikas Chaudhary * @ha: Pointer to host adapter structure. 1707f4f5df23SVikas Chaudhary * 1708f4f5df23SVikas Chaudhary * Context: Interrupt 1709f4f5df23SVikas Chaudhary **/ 1710f4f5df23SVikas Chaudhary static void qla4_8xxx_check_fw_alive(struct scsi_qla_host *ha) 1711f4f5df23SVikas Chaudhary { 1712f4f5df23SVikas Chaudhary uint32_t fw_heartbeat_counter, halt_status; 1713f4f5df23SVikas Chaudhary 1714f4f5df23SVikas Chaudhary fw_heartbeat_counter = qla4_8xxx_rd_32(ha, QLA82XX_PEG_ALIVE_COUNTER); 17152232be0dSLalit Chandivade /* If PEG_ALIVE_COUNTER is 0xffffffff, AER/EEH is in progress, ignore */ 17162232be0dSLalit Chandivade if (fw_heartbeat_counter == 0xffffffff) { 17172232be0dSLalit Chandivade DEBUG2(printk(KERN_WARNING "scsi%ld: %s: Device in frozen " 17182232be0dSLalit Chandivade "state, QLA82XX_PEG_ALIVE_COUNTER is 0xffffffff\n", 17192232be0dSLalit Chandivade ha->host_no, __func__)); 17202232be0dSLalit Chandivade return; 17212232be0dSLalit Chandivade } 1722f4f5df23SVikas Chaudhary 1723f4f5df23SVikas Chaudhary if (ha->fw_heartbeat_counter == fw_heartbeat_counter) { 1724f4f5df23SVikas Chaudhary ha->seconds_since_last_heartbeat++; 1725f4f5df23SVikas Chaudhary /* FW not alive after 2 seconds */ 1726f4f5df23SVikas Chaudhary if (ha->seconds_since_last_heartbeat == 2) { 1727f4f5df23SVikas Chaudhary ha->seconds_since_last_heartbeat = 0; 1728f4f5df23SVikas Chaudhary halt_status = qla4_8xxx_rd_32(ha, 1729f4f5df23SVikas Chaudhary QLA82XX_PEG_HALT_STATUS1); 173068d92ebfSVikas Chaudhary 173168d92ebfSVikas Chaudhary ql4_printk(KERN_INFO, ha, 173268d92ebfSVikas Chaudhary "scsi(%ld): %s, Dumping hw/fw registers:\n " 173368d92ebfSVikas Chaudhary " PEG_HALT_STATUS1: 0x%x, PEG_HALT_STATUS2:" 173468d92ebfSVikas Chaudhary " 0x%x,\n PEG_NET_0_PC: 0x%x, PEG_NET_1_PC:" 173568d92ebfSVikas Chaudhary " 0x%x,\n PEG_NET_2_PC: 0x%x, PEG_NET_3_PC:" 173668d92ebfSVikas Chaudhary " 0x%x,\n PEG_NET_4_PC: 0x%x\n", 173768d92ebfSVikas Chaudhary ha->host_no, __func__, halt_status, 173868d92ebfSVikas Chaudhary qla4_8xxx_rd_32(ha, 173968d92ebfSVikas Chaudhary QLA82XX_PEG_HALT_STATUS2), 174068d92ebfSVikas Chaudhary qla4_8xxx_rd_32(ha, QLA82XX_CRB_PEG_NET_0 + 174168d92ebfSVikas Chaudhary 0x3c), 174268d92ebfSVikas Chaudhary qla4_8xxx_rd_32(ha, QLA82XX_CRB_PEG_NET_1 + 174368d92ebfSVikas Chaudhary 0x3c), 174468d92ebfSVikas Chaudhary qla4_8xxx_rd_32(ha, QLA82XX_CRB_PEG_NET_2 + 174568d92ebfSVikas Chaudhary 0x3c), 174668d92ebfSVikas Chaudhary qla4_8xxx_rd_32(ha, QLA82XX_CRB_PEG_NET_3 + 174768d92ebfSVikas Chaudhary 0x3c), 174868d92ebfSVikas Chaudhary qla4_8xxx_rd_32(ha, QLA82XX_CRB_PEG_NET_4 + 174968d92ebfSVikas Chaudhary 0x3c)); 175021033639SNilesh Javali 1751f4f5df23SVikas Chaudhary /* Since we cannot change dev_state in interrupt 1752f4f5df23SVikas Chaudhary * context, set appropriate DPC flag then wakeup 1753f4f5df23SVikas Chaudhary * DPC */ 1754f4f5df23SVikas Chaudhary if (halt_status & HALT_STATUS_UNRECOVERABLE) 1755f4f5df23SVikas Chaudhary set_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags); 1756f4f5df23SVikas Chaudhary else { 1757f4f5df23SVikas Chaudhary printk("scsi%ld: %s: detect abort needed!\n", 1758f4f5df23SVikas Chaudhary ha->host_no, __func__); 1759f4f5df23SVikas Chaudhary set_bit(DPC_RESET_HA, &ha->dpc_flags); 1760f4f5df23SVikas Chaudhary } 1761f4f5df23SVikas Chaudhary qla4xxx_wake_dpc(ha); 176221033639SNilesh Javali qla4xxx_mailbox_premature_completion(ha); 1763f4f5df23SVikas Chaudhary } 176499457d75SLalit Chandivade } else 176599457d75SLalit Chandivade ha->seconds_since_last_heartbeat = 0; 176699457d75SLalit Chandivade 1767f4f5df23SVikas Chaudhary ha->fw_heartbeat_counter = fw_heartbeat_counter; 1768f4f5df23SVikas Chaudhary } 1769f4f5df23SVikas Chaudhary 1770f4f5df23SVikas Chaudhary /** 1771f4f5df23SVikas Chaudhary * qla4_8xxx_watchdog - Poll dev state 1772f4f5df23SVikas Chaudhary * @ha: Pointer to host adapter structure. 1773f4f5df23SVikas Chaudhary * 1774f4f5df23SVikas Chaudhary * Context: Interrupt 1775f4f5df23SVikas Chaudhary **/ 1776f4f5df23SVikas Chaudhary void qla4_8xxx_watchdog(struct scsi_qla_host *ha) 1777f4f5df23SVikas Chaudhary { 1778f4f5df23SVikas Chaudhary uint32_t dev_state; 1779f4f5df23SVikas Chaudhary 1780f4f5df23SVikas Chaudhary dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE); 1781f4f5df23SVikas Chaudhary 1782f4f5df23SVikas Chaudhary /* don't poll if reset is going on */ 1783d56a1f7bSLalit Chandivade if (!(test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags) || 1784d56a1f7bSLalit Chandivade test_bit(DPC_RESET_HA, &ha->dpc_flags) || 1785977f46a4SVikas Chaudhary test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags))) { 1786f4f5df23SVikas Chaudhary if (dev_state == QLA82XX_DEV_NEED_RESET && 1787f4f5df23SVikas Chaudhary !test_bit(DPC_RESET_HA, &ha->dpc_flags)) { 17883930b8c1SVikas Chaudhary if (!ql4xdontresethba) { 17893930b8c1SVikas Chaudhary ql4_printk(KERN_INFO, ha, "%s: HW State: " 17903930b8c1SVikas Chaudhary "NEED RESET!\n", __func__); 1791f4f5df23SVikas Chaudhary set_bit(DPC_RESET_HA, &ha->dpc_flags); 1792f4f5df23SVikas Chaudhary qla4xxx_wake_dpc(ha); 179321033639SNilesh Javali qla4xxx_mailbox_premature_completion(ha); 17943930b8c1SVikas Chaudhary } 1795f4f5df23SVikas Chaudhary } else if (dev_state == QLA82XX_DEV_NEED_QUIESCENT && 1796f4f5df23SVikas Chaudhary !test_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags)) { 17973930b8c1SVikas Chaudhary ql4_printk(KERN_INFO, ha, "%s: HW State: NEED QUIES!\n", 17983930b8c1SVikas Chaudhary __func__); 1799f4f5df23SVikas Chaudhary set_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags); 1800f4f5df23SVikas Chaudhary qla4xxx_wake_dpc(ha); 1801f4f5df23SVikas Chaudhary } else { 1802f4f5df23SVikas Chaudhary /* Check firmware health */ 1803f4f5df23SVikas Chaudhary qla4_8xxx_check_fw_alive(ha); 1804f4f5df23SVikas Chaudhary } 1805f4f5df23SVikas Chaudhary } 1806f4f5df23SVikas Chaudhary } 1807f4f5df23SVikas Chaudhary 1808f4f5df23SVikas Chaudhary /** 1809afaf5a2dSDavid Somayajulu * qla4xxx_timer - checks every second for work to do. 1810afaf5a2dSDavid Somayajulu * @ha: Pointer to host adapter structure. 1811afaf5a2dSDavid Somayajulu **/ 1812afaf5a2dSDavid Somayajulu static void qla4xxx_timer(struct scsi_qla_host *ha) 1813afaf5a2dSDavid Somayajulu { 1814afaf5a2dSDavid Somayajulu int start_dpc = 0; 18152232be0dSLalit Chandivade uint16_t w; 18162232be0dSLalit Chandivade 18172232be0dSLalit Chandivade /* If we are in the middle of AER/EEH processing 18182232be0dSLalit Chandivade * skip any processing and reschedule the timer 18192232be0dSLalit Chandivade */ 18202232be0dSLalit Chandivade if (test_bit(AF_EEH_BUSY, &ha->flags)) { 18212232be0dSLalit Chandivade mod_timer(&ha->timer, jiffies + HZ); 18222232be0dSLalit Chandivade return; 18232232be0dSLalit Chandivade } 18242232be0dSLalit Chandivade 18252232be0dSLalit Chandivade /* Hardware read to trigger an EEH error during mailbox waits. */ 18262232be0dSLalit Chandivade if (!pci_channel_offline(ha->pdev)) 18272232be0dSLalit Chandivade pci_read_config_word(ha->pdev, PCI_VENDOR_ID, &w); 1828afaf5a2dSDavid Somayajulu 1829f4f5df23SVikas Chaudhary if (is_qla8022(ha)) { 1830f4f5df23SVikas Chaudhary qla4_8xxx_watchdog(ha); 1831f4f5df23SVikas Chaudhary } 1832f4f5df23SVikas Chaudhary 1833f4f5df23SVikas Chaudhary if (!is_qla8022(ha)) { 1834afaf5a2dSDavid Somayajulu /* Check for heartbeat interval. */ 1835afaf5a2dSDavid Somayajulu if (ha->firmware_options & FWOPT_HEARTBEAT_ENABLE && 1836afaf5a2dSDavid Somayajulu ha->heartbeat_interval != 0) { 1837afaf5a2dSDavid Somayajulu ha->seconds_since_last_heartbeat++; 1838afaf5a2dSDavid Somayajulu if (ha->seconds_since_last_heartbeat > 1839afaf5a2dSDavid Somayajulu ha->heartbeat_interval + 2) 1840afaf5a2dSDavid Somayajulu set_bit(DPC_RESET_HA, &ha->dpc_flags); 1841afaf5a2dSDavid Somayajulu } 1842f4f5df23SVikas Chaudhary } 1843afaf5a2dSDavid Somayajulu 1844afaf5a2dSDavid Somayajulu /* Wakeup the dpc routine for this adapter, if needed. */ 18451b46807eSLalit Chandivade if (start_dpc || 1846afaf5a2dSDavid Somayajulu test_bit(DPC_RESET_HA, &ha->dpc_flags) || 1847afaf5a2dSDavid Somayajulu test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags) || 1848afaf5a2dSDavid Somayajulu test_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags) || 1849f4f5df23SVikas Chaudhary test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags) || 1850afaf5a2dSDavid Somayajulu test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) || 1851afaf5a2dSDavid Somayajulu test_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags) || 1852065aa1b4SVikas Chaudhary test_bit(DPC_LINK_CHANGED, &ha->dpc_flags) || 1853f4f5df23SVikas Chaudhary test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags) || 1854f4f5df23SVikas Chaudhary test_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags) || 18551b46807eSLalit Chandivade test_bit(DPC_AEN, &ha->dpc_flags)) { 1856afaf5a2dSDavid Somayajulu DEBUG2(printk("scsi%ld: %s: scheduling dpc routine" 1857afaf5a2dSDavid Somayajulu " - dpc flags = 0x%lx\n", 1858afaf5a2dSDavid Somayajulu ha->host_no, __func__, ha->dpc_flags)); 1859f4f5df23SVikas Chaudhary qla4xxx_wake_dpc(ha); 1860afaf5a2dSDavid Somayajulu } 1861afaf5a2dSDavid Somayajulu 1862afaf5a2dSDavid Somayajulu /* Reschedule timer thread to call us back in one second */ 1863afaf5a2dSDavid Somayajulu mod_timer(&ha->timer, jiffies + HZ); 1864afaf5a2dSDavid Somayajulu 1865afaf5a2dSDavid Somayajulu DEBUG2(ha->seconds_since_last_intr++); 1866afaf5a2dSDavid Somayajulu } 1867afaf5a2dSDavid Somayajulu 1868afaf5a2dSDavid Somayajulu /** 1869afaf5a2dSDavid Somayajulu * qla4xxx_cmd_wait - waits for all outstanding commands to complete 1870afaf5a2dSDavid Somayajulu * @ha: Pointer to host adapter structure. 1871afaf5a2dSDavid Somayajulu * 1872afaf5a2dSDavid Somayajulu * This routine stalls the driver until all outstanding commands are returned. 1873afaf5a2dSDavid Somayajulu * Caller must release the Hardware Lock prior to calling this routine. 1874afaf5a2dSDavid Somayajulu **/ 1875afaf5a2dSDavid Somayajulu static int qla4xxx_cmd_wait(struct scsi_qla_host *ha) 1876afaf5a2dSDavid Somayajulu { 1877afaf5a2dSDavid Somayajulu uint32_t index = 0; 1878afaf5a2dSDavid Somayajulu unsigned long flags; 1879afaf5a2dSDavid Somayajulu struct scsi_cmnd *cmd; 1880afaf5a2dSDavid Somayajulu 1881f4f5df23SVikas Chaudhary unsigned long wtime = jiffies + (WAIT_CMD_TOV * HZ); 1882f4f5df23SVikas Chaudhary 1883f4f5df23SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, "Wait up to %d seconds for cmds to " 1884f4f5df23SVikas Chaudhary "complete\n", WAIT_CMD_TOV)); 1885f4f5df23SVikas Chaudhary 1886f4f5df23SVikas Chaudhary while (!time_after_eq(jiffies, wtime)) { 1887afaf5a2dSDavid Somayajulu spin_lock_irqsave(&ha->hardware_lock, flags); 1888afaf5a2dSDavid Somayajulu /* Find a command that hasn't completed. */ 1889afaf5a2dSDavid Somayajulu for (index = 0; index < ha->host->can_queue; index++) { 1890afaf5a2dSDavid Somayajulu cmd = scsi_host_find_tag(ha->host, index); 1891a1e0063dSMike Christie /* 1892a1e0063dSMike Christie * We cannot just check if the index is valid, 1893a1e0063dSMike Christie * becase if we are run from the scsi eh, then 1894a1e0063dSMike Christie * the scsi/block layer is going to prevent 1895a1e0063dSMike Christie * the tag from being released. 1896a1e0063dSMike Christie */ 1897a1e0063dSMike Christie if (cmd != NULL && CMD_SP(cmd)) 1898afaf5a2dSDavid Somayajulu break; 1899afaf5a2dSDavid Somayajulu } 1900afaf5a2dSDavid Somayajulu spin_unlock_irqrestore(&ha->hardware_lock, flags); 1901afaf5a2dSDavid Somayajulu 1902afaf5a2dSDavid Somayajulu /* If No Commands are pending, wait is complete */ 1903f4f5df23SVikas Chaudhary if (index == ha->host->can_queue) 1904f4f5df23SVikas Chaudhary return QLA_SUCCESS; 1905afaf5a2dSDavid Somayajulu 1906afaf5a2dSDavid Somayajulu msleep(1000); 1907afaf5a2dSDavid Somayajulu } 1908f4f5df23SVikas Chaudhary /* If we timed out on waiting for commands to come back 1909f4f5df23SVikas Chaudhary * return ERROR. */ 1910f4f5df23SVikas Chaudhary return QLA_ERROR; 1911afaf5a2dSDavid Somayajulu } 1912afaf5a2dSDavid Somayajulu 1913f4f5df23SVikas Chaudhary int qla4xxx_hw_reset(struct scsi_qla_host *ha) 1914afaf5a2dSDavid Somayajulu { 1915afaf5a2dSDavid Somayajulu uint32_t ctrl_status; 1916477ffb9dSDavid C Somayajulu unsigned long flags = 0; 1917477ffb9dSDavid C Somayajulu 1918477ffb9dSDavid C Somayajulu DEBUG2(printk(KERN_ERR "scsi%ld: %s\n", ha->host_no, __func__)); 1919afaf5a2dSDavid Somayajulu 1920f4f5df23SVikas Chaudhary if (ql4xxx_lock_drvr_wait(ha) != QLA_SUCCESS) 1921f4f5df23SVikas Chaudhary return QLA_ERROR; 1922f4f5df23SVikas Chaudhary 1923afaf5a2dSDavid Somayajulu spin_lock_irqsave(&ha->hardware_lock, flags); 1924afaf5a2dSDavid Somayajulu 1925afaf5a2dSDavid Somayajulu /* 1926afaf5a2dSDavid Somayajulu * If the SCSI Reset Interrupt bit is set, clear it. 1927afaf5a2dSDavid Somayajulu * Otherwise, the Soft Reset won't work. 1928afaf5a2dSDavid Somayajulu */ 1929afaf5a2dSDavid Somayajulu ctrl_status = readw(&ha->reg->ctrl_status); 1930afaf5a2dSDavid Somayajulu if ((ctrl_status & CSR_SCSI_RESET_INTR) != 0) 1931afaf5a2dSDavid Somayajulu writel(set_rmask(CSR_SCSI_RESET_INTR), &ha->reg->ctrl_status); 1932afaf5a2dSDavid Somayajulu 1933afaf5a2dSDavid Somayajulu /* Issue Soft Reset */ 1934afaf5a2dSDavid Somayajulu writel(set_rmask(CSR_SOFT_RESET), &ha->reg->ctrl_status); 1935afaf5a2dSDavid Somayajulu readl(&ha->reg->ctrl_status); 1936afaf5a2dSDavid Somayajulu 1937afaf5a2dSDavid Somayajulu spin_unlock_irqrestore(&ha->hardware_lock, flags); 1938f4f5df23SVikas Chaudhary return QLA_SUCCESS; 1939477ffb9dSDavid C Somayajulu } 1940477ffb9dSDavid C Somayajulu 1941477ffb9dSDavid C Somayajulu /** 1942477ffb9dSDavid C Somayajulu * qla4xxx_soft_reset - performs soft reset. 1943477ffb9dSDavid C Somayajulu * @ha: Pointer to host adapter structure. 1944477ffb9dSDavid C Somayajulu **/ 1945477ffb9dSDavid C Somayajulu int qla4xxx_soft_reset(struct scsi_qla_host *ha) 1946477ffb9dSDavid C Somayajulu { 1947477ffb9dSDavid C Somayajulu uint32_t max_wait_time; 1948477ffb9dSDavid C Somayajulu unsigned long flags = 0; 1949f931c534SVikas Chaudhary int status; 1950477ffb9dSDavid C Somayajulu uint32_t ctrl_status; 1951477ffb9dSDavid C Somayajulu 1952f931c534SVikas Chaudhary status = qla4xxx_hw_reset(ha); 1953f931c534SVikas Chaudhary if (status != QLA_SUCCESS) 1954f931c534SVikas Chaudhary return status; 1955afaf5a2dSDavid Somayajulu 1956f931c534SVikas Chaudhary status = QLA_ERROR; 1957afaf5a2dSDavid Somayajulu /* Wait until the Network Reset Intr bit is cleared */ 1958afaf5a2dSDavid Somayajulu max_wait_time = RESET_INTR_TOV; 1959afaf5a2dSDavid Somayajulu do { 1960afaf5a2dSDavid Somayajulu spin_lock_irqsave(&ha->hardware_lock, flags); 1961afaf5a2dSDavid Somayajulu ctrl_status = readw(&ha->reg->ctrl_status); 1962afaf5a2dSDavid Somayajulu spin_unlock_irqrestore(&ha->hardware_lock, flags); 1963afaf5a2dSDavid Somayajulu 1964afaf5a2dSDavid Somayajulu if ((ctrl_status & CSR_NET_RESET_INTR) == 0) 1965afaf5a2dSDavid Somayajulu break; 1966afaf5a2dSDavid Somayajulu 1967afaf5a2dSDavid Somayajulu msleep(1000); 1968afaf5a2dSDavid Somayajulu } while ((--max_wait_time)); 1969afaf5a2dSDavid Somayajulu 1970afaf5a2dSDavid Somayajulu if ((ctrl_status & CSR_NET_RESET_INTR) != 0) { 1971afaf5a2dSDavid Somayajulu DEBUG2(printk(KERN_WARNING 1972afaf5a2dSDavid Somayajulu "scsi%ld: Network Reset Intr not cleared by " 1973afaf5a2dSDavid Somayajulu "Network function, clearing it now!\n", 1974afaf5a2dSDavid Somayajulu ha->host_no)); 1975afaf5a2dSDavid Somayajulu spin_lock_irqsave(&ha->hardware_lock, flags); 1976afaf5a2dSDavid Somayajulu writel(set_rmask(CSR_NET_RESET_INTR), &ha->reg->ctrl_status); 1977afaf5a2dSDavid Somayajulu readl(&ha->reg->ctrl_status); 1978afaf5a2dSDavid Somayajulu spin_unlock_irqrestore(&ha->hardware_lock, flags); 1979afaf5a2dSDavid Somayajulu } 1980afaf5a2dSDavid Somayajulu 1981afaf5a2dSDavid Somayajulu /* Wait until the firmware tells us the Soft Reset is done */ 1982afaf5a2dSDavid Somayajulu max_wait_time = SOFT_RESET_TOV; 1983afaf5a2dSDavid Somayajulu do { 1984afaf5a2dSDavid Somayajulu spin_lock_irqsave(&ha->hardware_lock, flags); 1985afaf5a2dSDavid Somayajulu ctrl_status = readw(&ha->reg->ctrl_status); 1986afaf5a2dSDavid Somayajulu spin_unlock_irqrestore(&ha->hardware_lock, flags); 1987afaf5a2dSDavid Somayajulu 1988afaf5a2dSDavid Somayajulu if ((ctrl_status & CSR_SOFT_RESET) == 0) { 1989afaf5a2dSDavid Somayajulu status = QLA_SUCCESS; 1990afaf5a2dSDavid Somayajulu break; 1991afaf5a2dSDavid Somayajulu } 1992afaf5a2dSDavid Somayajulu 1993afaf5a2dSDavid Somayajulu msleep(1000); 1994afaf5a2dSDavid Somayajulu } while ((--max_wait_time)); 1995afaf5a2dSDavid Somayajulu 1996afaf5a2dSDavid Somayajulu /* 1997afaf5a2dSDavid Somayajulu * Also, make sure that the SCSI Reset Interrupt bit has been cleared 1998afaf5a2dSDavid Somayajulu * after the soft reset has taken place. 1999afaf5a2dSDavid Somayajulu */ 2000afaf5a2dSDavid Somayajulu spin_lock_irqsave(&ha->hardware_lock, flags); 2001afaf5a2dSDavid Somayajulu ctrl_status = readw(&ha->reg->ctrl_status); 2002afaf5a2dSDavid Somayajulu if ((ctrl_status & CSR_SCSI_RESET_INTR) != 0) { 2003afaf5a2dSDavid Somayajulu writel(set_rmask(CSR_SCSI_RESET_INTR), &ha->reg->ctrl_status); 2004afaf5a2dSDavid Somayajulu readl(&ha->reg->ctrl_status); 2005afaf5a2dSDavid Somayajulu } 2006afaf5a2dSDavid Somayajulu spin_unlock_irqrestore(&ha->hardware_lock, flags); 2007afaf5a2dSDavid Somayajulu 2008afaf5a2dSDavid Somayajulu /* If soft reset fails then most probably the bios on other 2009afaf5a2dSDavid Somayajulu * function is also enabled. 2010afaf5a2dSDavid Somayajulu * Since the initialization is sequential the other fn 2011afaf5a2dSDavid Somayajulu * wont be able to acknowledge the soft reset. 2012afaf5a2dSDavid Somayajulu * Issue a force soft reset to workaround this scenario. 2013afaf5a2dSDavid Somayajulu */ 2014afaf5a2dSDavid Somayajulu if (max_wait_time == 0) { 2015afaf5a2dSDavid Somayajulu /* Issue Force Soft Reset */ 2016afaf5a2dSDavid Somayajulu spin_lock_irqsave(&ha->hardware_lock, flags); 2017afaf5a2dSDavid Somayajulu writel(set_rmask(CSR_FORCE_SOFT_RESET), &ha->reg->ctrl_status); 2018afaf5a2dSDavid Somayajulu readl(&ha->reg->ctrl_status); 2019afaf5a2dSDavid Somayajulu spin_unlock_irqrestore(&ha->hardware_lock, flags); 2020afaf5a2dSDavid Somayajulu /* Wait until the firmware tells us the Soft Reset is done */ 2021afaf5a2dSDavid Somayajulu max_wait_time = SOFT_RESET_TOV; 2022afaf5a2dSDavid Somayajulu do { 2023afaf5a2dSDavid Somayajulu spin_lock_irqsave(&ha->hardware_lock, flags); 2024afaf5a2dSDavid Somayajulu ctrl_status = readw(&ha->reg->ctrl_status); 2025afaf5a2dSDavid Somayajulu spin_unlock_irqrestore(&ha->hardware_lock, flags); 2026afaf5a2dSDavid Somayajulu 2027afaf5a2dSDavid Somayajulu if ((ctrl_status & CSR_FORCE_SOFT_RESET) == 0) { 2028afaf5a2dSDavid Somayajulu status = QLA_SUCCESS; 2029afaf5a2dSDavid Somayajulu break; 2030afaf5a2dSDavid Somayajulu } 2031afaf5a2dSDavid Somayajulu 2032afaf5a2dSDavid Somayajulu msleep(1000); 2033afaf5a2dSDavid Somayajulu } while ((--max_wait_time)); 2034afaf5a2dSDavid Somayajulu } 2035afaf5a2dSDavid Somayajulu 2036afaf5a2dSDavid Somayajulu return status; 2037afaf5a2dSDavid Somayajulu } 2038afaf5a2dSDavid Somayajulu 2039afaf5a2dSDavid Somayajulu /** 2040f4f5df23SVikas Chaudhary * qla4xxx_abort_active_cmds - returns all outstanding i/o requests to O.S. 2041afaf5a2dSDavid Somayajulu * @ha: Pointer to host adapter structure. 2042f4f5df23SVikas Chaudhary * @res: returned scsi status 2043afaf5a2dSDavid Somayajulu * 2044afaf5a2dSDavid Somayajulu * This routine is called just prior to a HARD RESET to return all 2045afaf5a2dSDavid Somayajulu * outstanding commands back to the Operating System. 2046afaf5a2dSDavid Somayajulu * Caller should make sure that the following locks are released 2047afaf5a2dSDavid Somayajulu * before this calling routine: Hardware lock, and io_request_lock. 2048afaf5a2dSDavid Somayajulu **/ 2049f4f5df23SVikas Chaudhary static void qla4xxx_abort_active_cmds(struct scsi_qla_host *ha, int res) 2050afaf5a2dSDavid Somayajulu { 2051afaf5a2dSDavid Somayajulu struct srb *srb; 2052afaf5a2dSDavid Somayajulu int i; 2053afaf5a2dSDavid Somayajulu unsigned long flags; 2054afaf5a2dSDavid Somayajulu 2055afaf5a2dSDavid Somayajulu spin_lock_irqsave(&ha->hardware_lock, flags); 2056afaf5a2dSDavid Somayajulu for (i = 0; i < ha->host->can_queue; i++) { 2057afaf5a2dSDavid Somayajulu srb = qla4xxx_del_from_active_array(ha, i); 2058afaf5a2dSDavid Somayajulu if (srb != NULL) { 2059f4f5df23SVikas Chaudhary srb->cmd->result = res; 206009a0f719SVikas Chaudhary kref_put(&srb->srb_ref, qla4xxx_srb_compl); 2061afaf5a2dSDavid Somayajulu } 2062afaf5a2dSDavid Somayajulu } 2063afaf5a2dSDavid Somayajulu spin_unlock_irqrestore(&ha->hardware_lock, flags); 2064afaf5a2dSDavid Somayajulu } 2065afaf5a2dSDavid Somayajulu 2066f4f5df23SVikas Chaudhary void qla4xxx_dead_adapter_cleanup(struct scsi_qla_host *ha) 2067f4f5df23SVikas Chaudhary { 2068f4f5df23SVikas Chaudhary clear_bit(AF_ONLINE, &ha->flags); 2069f4f5df23SVikas Chaudhary 2070f4f5df23SVikas Chaudhary /* Disable the board */ 2071f4f5df23SVikas Chaudhary ql4_printk(KERN_INFO, ha, "Disabling the board\n"); 2072f4f5df23SVikas Chaudhary 2073f4f5df23SVikas Chaudhary qla4xxx_abort_active_cmds(ha, DID_NO_CONNECT << 16); 2074f4f5df23SVikas Chaudhary qla4xxx_mark_all_devices_missing(ha); 2075f4f5df23SVikas Chaudhary clear_bit(AF_INIT_DONE, &ha->flags); 2076f4f5df23SVikas Chaudhary } 2077f4f5df23SVikas Chaudhary 2078b3a271a9SManish Rangankar static void qla4xxx_fail_session(struct iscsi_cls_session *cls_session) 2079b3a271a9SManish Rangankar { 2080b3a271a9SManish Rangankar struct iscsi_session *sess; 2081b3a271a9SManish Rangankar struct ddb_entry *ddb_entry; 2082b3a271a9SManish Rangankar 2083b3a271a9SManish Rangankar sess = cls_session->dd_data; 2084b3a271a9SManish Rangankar ddb_entry = sess->dd_data; 2085b3a271a9SManish Rangankar ddb_entry->fw_ddb_device_state = DDB_DS_SESSION_FAILED; 2086b3a271a9SManish Rangankar iscsi_session_failure(cls_session->dd_data, ISCSI_ERR_CONN_FAILED); 2087b3a271a9SManish Rangankar } 2088b3a271a9SManish Rangankar 2089afaf5a2dSDavid Somayajulu /** 2090afaf5a2dSDavid Somayajulu * qla4xxx_recover_adapter - recovers adapter after a fatal error 2091afaf5a2dSDavid Somayajulu * @ha: Pointer to host adapter structure. 2092afaf5a2dSDavid Somayajulu **/ 2093f4f5df23SVikas Chaudhary static int qla4xxx_recover_adapter(struct scsi_qla_host *ha) 2094afaf5a2dSDavid Somayajulu { 2095f4f5df23SVikas Chaudhary int status = QLA_ERROR; 2096f4f5df23SVikas Chaudhary uint8_t reset_chip = 0; 2097afaf5a2dSDavid Somayajulu 2098afaf5a2dSDavid Somayajulu /* Stall incoming I/O until we are done */ 2099f4f5df23SVikas Chaudhary scsi_block_requests(ha->host); 2100afaf5a2dSDavid Somayajulu clear_bit(AF_ONLINE, &ha->flags); 2101b3a271a9SManish Rangankar clear_bit(AF_LINK_UP, &ha->flags); 210250a29aecSMike Christie 2103f4f5df23SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, "%s: adapter OFFLINE\n", __func__)); 2104afaf5a2dSDavid Somayajulu 2105f4f5df23SVikas Chaudhary set_bit(DPC_RESET_ACTIVE, &ha->dpc_flags); 2106afaf5a2dSDavid Somayajulu 2107b3a271a9SManish Rangankar iscsi_host_for_each_session(ha->host, qla4xxx_fail_session); 2108b3a271a9SManish Rangankar 2109f4f5df23SVikas Chaudhary if (test_bit(DPC_RESET_HA, &ha->dpc_flags)) 2110f4f5df23SVikas Chaudhary reset_chip = 1; 2111afaf5a2dSDavid Somayajulu 2112f4f5df23SVikas Chaudhary /* For the DPC_RESET_HA_INTR case (ISP-4xxx specific) 2113f4f5df23SVikas Chaudhary * do not reset adapter, jump to initialize_adapter */ 2114f4f5df23SVikas Chaudhary if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) { 2115f4f5df23SVikas Chaudhary status = QLA_SUCCESS; 2116f4f5df23SVikas Chaudhary goto recover_ha_init_adapter; 2117afaf5a2dSDavid Somayajulu } 2118afaf5a2dSDavid Somayajulu 2119f4f5df23SVikas Chaudhary /* For the ISP-82xx adapter, issue a stop_firmware if invoked 2120f4f5df23SVikas Chaudhary * from eh_host_reset or ioctl module */ 2121f4f5df23SVikas Chaudhary if (is_qla8022(ha) && !reset_chip && 2122f4f5df23SVikas Chaudhary test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags)) { 2123f4f5df23SVikas Chaudhary 2124f4f5df23SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, 2125f4f5df23SVikas Chaudhary "scsi%ld: %s - Performing stop_firmware...\n", 2126f4f5df23SVikas Chaudhary ha->host_no, __func__)); 2127f4f5df23SVikas Chaudhary status = ha->isp_ops->reset_firmware(ha); 2128f4f5df23SVikas Chaudhary if (status == QLA_SUCCESS) { 21292bd1e2beSNilesh Javali if (!test_bit(AF_FW_RECOVERY, &ha->flags)) 2130f4f5df23SVikas Chaudhary qla4xxx_cmd_wait(ha); 2131f4f5df23SVikas Chaudhary ha->isp_ops->disable_intrs(ha); 2132f4f5df23SVikas Chaudhary qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); 2133f4f5df23SVikas Chaudhary qla4xxx_abort_active_cmds(ha, DID_RESET << 16); 2134f4f5df23SVikas Chaudhary } else { 2135f4f5df23SVikas Chaudhary /* If the stop_firmware fails then 2136f4f5df23SVikas Chaudhary * reset the entire chip */ 2137f4f5df23SVikas Chaudhary reset_chip = 1; 2138f4f5df23SVikas Chaudhary clear_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags); 2139f4f5df23SVikas Chaudhary set_bit(DPC_RESET_HA, &ha->dpc_flags); 2140f4f5df23SVikas Chaudhary } 2141f4f5df23SVikas Chaudhary } 2142f4f5df23SVikas Chaudhary 2143f4f5df23SVikas Chaudhary /* Issue full chip reset if recovering from a catastrophic error, 2144f4f5df23SVikas Chaudhary * or if stop_firmware fails for ISP-82xx. 2145f4f5df23SVikas Chaudhary * This is the default case for ISP-4xxx */ 2146f4f5df23SVikas Chaudhary if (!is_qla8022(ha) || reset_chip) { 21472bd1e2beSNilesh Javali if (!test_bit(AF_FW_RECOVERY, &ha->flags)) 2148f4f5df23SVikas Chaudhary qla4xxx_cmd_wait(ha); 2149f4f5df23SVikas Chaudhary qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); 2150f4f5df23SVikas Chaudhary qla4xxx_abort_active_cmds(ha, DID_RESET << 16); 2151f4f5df23SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, 2152f4f5df23SVikas Chaudhary "scsi%ld: %s - Performing chip reset..\n", 2153f4f5df23SVikas Chaudhary ha->host_no, __func__)); 2154f4f5df23SVikas Chaudhary status = ha->isp_ops->reset_chip(ha); 2155f4f5df23SVikas Chaudhary } 2156f4f5df23SVikas Chaudhary 2157f4f5df23SVikas Chaudhary /* Flush any pending ddb changed AENs */ 2158f4f5df23SVikas Chaudhary qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); 2159f4f5df23SVikas Chaudhary 2160f4f5df23SVikas Chaudhary recover_ha_init_adapter: 2161f4f5df23SVikas Chaudhary /* Upon successful firmware/chip reset, re-initialize the adapter */ 2162f4f5df23SVikas Chaudhary if (status == QLA_SUCCESS) { 2163f4f5df23SVikas Chaudhary /* For ISP-4xxx, force function 1 to always initialize 2164f4f5df23SVikas Chaudhary * before function 3 to prevent both funcions from 2165f4f5df23SVikas Chaudhary * stepping on top of the other */ 2166f4f5df23SVikas Chaudhary if (!is_qla8022(ha) && (ha->mac_index == 3)) 2167f4f5df23SVikas Chaudhary ssleep(6); 2168f4f5df23SVikas Chaudhary 2169f4f5df23SVikas Chaudhary /* NOTE: AF_ONLINE flag set upon successful completion of 2170f4f5df23SVikas Chaudhary * qla4xxx_initialize_adapter */ 21710e7e8501SManish Rangankar status = qla4xxx_initialize_adapter(ha); 2172f4f5df23SVikas Chaudhary } 2173f4f5df23SVikas Chaudhary 2174f4f5df23SVikas Chaudhary /* Retry failed adapter initialization, if necessary 2175f4f5df23SVikas Chaudhary * Do not retry initialize_adapter for RESET_HA_INTR (ISP-4xxx specific) 2176f4f5df23SVikas Chaudhary * case to prevent ping-pong resets between functions */ 2177f4f5df23SVikas Chaudhary if (!test_bit(AF_ONLINE, &ha->flags) && 2178f4f5df23SVikas Chaudhary !test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) { 2179afaf5a2dSDavid Somayajulu /* Adapter initialization failed, see if we can retry 2180f4f5df23SVikas Chaudhary * resetting the ha. 2181f4f5df23SVikas Chaudhary * Since we don't want to block the DPC for too long 2182f4f5df23SVikas Chaudhary * with multiple resets in the same thread, 2183f4f5df23SVikas Chaudhary * utilize DPC to retry */ 2184afaf5a2dSDavid Somayajulu if (!test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags)) { 2185afaf5a2dSDavid Somayajulu ha->retry_reset_ha_cnt = MAX_RESET_HA_RETRIES; 2186afaf5a2dSDavid Somayajulu DEBUG2(printk("scsi%ld: recover adapter - retrying " 2187afaf5a2dSDavid Somayajulu "(%d) more times\n", ha->host_no, 2188afaf5a2dSDavid Somayajulu ha->retry_reset_ha_cnt)); 2189afaf5a2dSDavid Somayajulu set_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags); 2190afaf5a2dSDavid Somayajulu status = QLA_ERROR; 2191afaf5a2dSDavid Somayajulu } else { 2192afaf5a2dSDavid Somayajulu if (ha->retry_reset_ha_cnt > 0) { 2193afaf5a2dSDavid Somayajulu /* Schedule another Reset HA--DPC will retry */ 2194afaf5a2dSDavid Somayajulu ha->retry_reset_ha_cnt--; 2195afaf5a2dSDavid Somayajulu DEBUG2(printk("scsi%ld: recover adapter - " 2196afaf5a2dSDavid Somayajulu "retry remaining %d\n", 2197afaf5a2dSDavid Somayajulu ha->host_no, 2198afaf5a2dSDavid Somayajulu ha->retry_reset_ha_cnt)); 2199afaf5a2dSDavid Somayajulu status = QLA_ERROR; 2200afaf5a2dSDavid Somayajulu } 2201afaf5a2dSDavid Somayajulu 2202afaf5a2dSDavid Somayajulu if (ha->retry_reset_ha_cnt == 0) { 2203afaf5a2dSDavid Somayajulu /* Recover adapter retries have been exhausted. 2204afaf5a2dSDavid Somayajulu * Adapter DEAD */ 2205afaf5a2dSDavid Somayajulu DEBUG2(printk("scsi%ld: recover adapter " 2206afaf5a2dSDavid Somayajulu "failed - board disabled\n", 2207afaf5a2dSDavid Somayajulu ha->host_no)); 2208f4f5df23SVikas Chaudhary qla4xxx_dead_adapter_cleanup(ha); 2209afaf5a2dSDavid Somayajulu clear_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags); 2210afaf5a2dSDavid Somayajulu clear_bit(DPC_RESET_HA, &ha->dpc_flags); 2211f4f5df23SVikas Chaudhary clear_bit(DPC_RESET_HA_FW_CONTEXT, 2212afaf5a2dSDavid Somayajulu &ha->dpc_flags); 2213afaf5a2dSDavid Somayajulu status = QLA_ERROR; 2214afaf5a2dSDavid Somayajulu } 2215afaf5a2dSDavid Somayajulu } 2216afaf5a2dSDavid Somayajulu } else { 2217afaf5a2dSDavid Somayajulu clear_bit(DPC_RESET_HA, &ha->dpc_flags); 2218f4f5df23SVikas Chaudhary clear_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags); 2219afaf5a2dSDavid Somayajulu clear_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags); 2220afaf5a2dSDavid Somayajulu } 2221afaf5a2dSDavid Somayajulu 2222afaf5a2dSDavid Somayajulu ha->adapter_error_count++; 2223afaf5a2dSDavid Somayajulu 2224f4f5df23SVikas Chaudhary if (test_bit(AF_ONLINE, &ha->flags)) 2225f4f5df23SVikas Chaudhary ha->isp_ops->enable_intrs(ha); 2226afaf5a2dSDavid Somayajulu 2227f4f5df23SVikas Chaudhary scsi_unblock_requests(ha->host); 2228f4f5df23SVikas Chaudhary 2229f4f5df23SVikas Chaudhary clear_bit(DPC_RESET_ACTIVE, &ha->dpc_flags); 2230f4f5df23SVikas Chaudhary DEBUG2(printk("scsi%ld: recover adapter: %s\n", ha->host_no, 223125985edcSLucas De Marchi status == QLA_ERROR ? "FAILED" : "SUCCEEDED")); 2232f4f5df23SVikas Chaudhary 2233afaf5a2dSDavid Somayajulu return status; 2234afaf5a2dSDavid Somayajulu } 2235afaf5a2dSDavid Somayajulu 2236b3a271a9SManish Rangankar static void qla4xxx_relogin_devices(struct iscsi_cls_session *cls_session) 2237b3a271a9SManish Rangankar { 2238b3a271a9SManish Rangankar struct iscsi_session *sess; 2239b3a271a9SManish Rangankar struct ddb_entry *ddb_entry; 2240b3a271a9SManish Rangankar struct scsi_qla_host *ha; 2241b3a271a9SManish Rangankar 2242b3a271a9SManish Rangankar sess = cls_session->dd_data; 2243b3a271a9SManish Rangankar ddb_entry = sess->dd_data; 2244b3a271a9SManish Rangankar ha = ddb_entry->ha; 2245b3a271a9SManish Rangankar if (!iscsi_is_session_online(cls_session)) { 2246b3a271a9SManish Rangankar if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) { 2247b3a271a9SManish Rangankar ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ddb[%d]" 2248b3a271a9SManish Rangankar " unblock session\n", ha->host_no, __func__, 2249b3a271a9SManish Rangankar ddb_entry->fw_ddb_index); 2250b3a271a9SManish Rangankar iscsi_unblock_session(ddb_entry->sess); 2251b3a271a9SManish Rangankar } else { 2252b3a271a9SManish Rangankar /* Trigger relogin */ 2253b3a271a9SManish Rangankar iscsi_session_failure(cls_session->dd_data, 2254b3a271a9SManish Rangankar ISCSI_ERR_CONN_FAILED); 2255b3a271a9SManish Rangankar } 2256b3a271a9SManish Rangankar } 2257b3a271a9SManish Rangankar } 2258b3a271a9SManish Rangankar 22592d7924e6SVikas Chaudhary static void qla4xxx_relogin_all_devices(struct scsi_qla_host *ha) 22602d7924e6SVikas Chaudhary { 2261b3a271a9SManish Rangankar iscsi_host_for_each_session(ha->host, qla4xxx_relogin_devices); 22622d7924e6SVikas Chaudhary } 22632d7924e6SVikas Chaudhary 2264f4f5df23SVikas Chaudhary void qla4xxx_wake_dpc(struct scsi_qla_host *ha) 2265f4f5df23SVikas Chaudhary { 22661b46807eSLalit Chandivade if (ha->dpc_thread) 2267f4f5df23SVikas Chaudhary queue_work(ha->dpc_thread, &ha->dpc_work); 2268f4f5df23SVikas Chaudhary } 2269f4f5df23SVikas Chaudhary 2270afaf5a2dSDavid Somayajulu /** 2271afaf5a2dSDavid Somayajulu * qla4xxx_do_dpc - dpc routine 2272afaf5a2dSDavid Somayajulu * @data: in our case pointer to adapter structure 2273afaf5a2dSDavid Somayajulu * 2274afaf5a2dSDavid Somayajulu * This routine is a task that is schedule by the interrupt handler 2275afaf5a2dSDavid Somayajulu * to perform the background processing for interrupts. We put it 2276afaf5a2dSDavid Somayajulu * on a task queue that is consumed whenever the scheduler runs; that's 2277afaf5a2dSDavid Somayajulu * so you can do anything (i.e. put the process to sleep etc). In fact, 2278afaf5a2dSDavid Somayajulu * the mid-level tries to sleep when it reaches the driver threshold 2279afaf5a2dSDavid Somayajulu * "host->can_queue". This can cause a panic if we were in our interrupt code. 2280afaf5a2dSDavid Somayajulu **/ 2281c4028958SDavid Howells static void qla4xxx_do_dpc(struct work_struct *work) 2282afaf5a2dSDavid Somayajulu { 2283c4028958SDavid Howells struct scsi_qla_host *ha = 2284c4028958SDavid Howells container_of(work, struct scsi_qla_host, dpc_work); 2285477ffb9dSDavid C Somayajulu int status = QLA_ERROR; 2286afaf5a2dSDavid Somayajulu 2287f26b9044SDavid C Somayajulu DEBUG2(printk("scsi%ld: %s: DPC handler waking up." 2288f4f5df23SVikas Chaudhary "flags = 0x%08lx, dpc_flags = 0x%08lx\n", 2289f4f5df23SVikas Chaudhary ha->host_no, __func__, ha->flags, ha->dpc_flags)) 2290afaf5a2dSDavid Somayajulu 2291afaf5a2dSDavid Somayajulu /* Initialization not yet finished. Don't do anything yet. */ 2292afaf5a2dSDavid Somayajulu if (!test_bit(AF_INIT_DONE, &ha->flags)) 22931b46807eSLalit Chandivade return; 2294afaf5a2dSDavid Somayajulu 22952232be0dSLalit Chandivade if (test_bit(AF_EEH_BUSY, &ha->flags)) { 22962232be0dSLalit Chandivade DEBUG2(printk(KERN_INFO "scsi%ld: %s: flags = %lx\n", 22972232be0dSLalit Chandivade ha->host_no, __func__, ha->flags)); 22981b46807eSLalit Chandivade return; 22992232be0dSLalit Chandivade } 23002232be0dSLalit Chandivade 2301f4f5df23SVikas Chaudhary if (is_qla8022(ha)) { 2302f4f5df23SVikas Chaudhary if (test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags)) { 2303f4f5df23SVikas Chaudhary qla4_8xxx_idc_lock(ha); 2304f4f5df23SVikas Chaudhary qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, 2305f4f5df23SVikas Chaudhary QLA82XX_DEV_FAILED); 2306f4f5df23SVikas Chaudhary qla4_8xxx_idc_unlock(ha); 2307f4f5df23SVikas Chaudhary ql4_printk(KERN_INFO, ha, "HW State: FAILED\n"); 2308f4f5df23SVikas Chaudhary qla4_8xxx_device_state_handler(ha); 2309f4f5df23SVikas Chaudhary } 2310f4f5df23SVikas Chaudhary if (test_and_clear_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags)) { 2311f4f5df23SVikas Chaudhary qla4_8xxx_need_qsnt_handler(ha); 2312f4f5df23SVikas Chaudhary } 2313f4f5df23SVikas Chaudhary } 2314f4f5df23SVikas Chaudhary 2315f4f5df23SVikas Chaudhary if (!test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags) && 2316f4f5df23SVikas Chaudhary (test_bit(DPC_RESET_HA, &ha->dpc_flags) || 2317afaf5a2dSDavid Somayajulu test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) || 2318f4f5df23SVikas Chaudhary test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags))) { 2319f4f5df23SVikas Chaudhary if (ql4xdontresethba) { 2320f4f5df23SVikas Chaudhary DEBUG2(printk("scsi%ld: %s: Don't Reset HBA\n", 2321f4f5df23SVikas Chaudhary ha->host_no, __func__)); 2322f4f5df23SVikas Chaudhary clear_bit(DPC_RESET_HA, &ha->dpc_flags); 2323f4f5df23SVikas Chaudhary clear_bit(DPC_RESET_HA_INTR, &ha->dpc_flags); 2324f4f5df23SVikas Chaudhary clear_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags); 2325f4f5df23SVikas Chaudhary goto dpc_post_reset_ha; 2326f4f5df23SVikas Chaudhary } 2327f4f5df23SVikas Chaudhary if (test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags) || 2328f26b9044SDavid C Somayajulu test_bit(DPC_RESET_HA, &ha->dpc_flags)) 2329f4f5df23SVikas Chaudhary qla4xxx_recover_adapter(ha); 2330afaf5a2dSDavid Somayajulu 2331477ffb9dSDavid C Somayajulu if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) { 2332afaf5a2dSDavid Somayajulu uint8_t wait_time = RESET_INTR_TOV; 2333afaf5a2dSDavid Somayajulu 2334afaf5a2dSDavid Somayajulu while ((readw(&ha->reg->ctrl_status) & 2335afaf5a2dSDavid Somayajulu (CSR_SOFT_RESET | CSR_FORCE_SOFT_RESET)) != 0) { 2336afaf5a2dSDavid Somayajulu if (--wait_time == 0) 2337afaf5a2dSDavid Somayajulu break; 2338afaf5a2dSDavid Somayajulu msleep(1000); 2339afaf5a2dSDavid Somayajulu } 2340afaf5a2dSDavid Somayajulu if (wait_time == 0) 2341afaf5a2dSDavid Somayajulu DEBUG2(printk("scsi%ld: %s: SR|FSR " 2342afaf5a2dSDavid Somayajulu "bit not cleared-- resetting\n", 2343afaf5a2dSDavid Somayajulu ha->host_no, __func__)); 2344f4f5df23SVikas Chaudhary qla4xxx_abort_active_cmds(ha, DID_RESET << 16); 2345477ffb9dSDavid C Somayajulu if (ql4xxx_lock_drvr_wait(ha) == QLA_SUCCESS) { 2346477ffb9dSDavid C Somayajulu qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); 2347f4f5df23SVikas Chaudhary status = qla4xxx_recover_adapter(ha); 2348477ffb9dSDavid C Somayajulu } 2349477ffb9dSDavid C Somayajulu clear_bit(DPC_RESET_HA_INTR, &ha->dpc_flags); 2350477ffb9dSDavid C Somayajulu if (status == QLA_SUCCESS) 2351f4f5df23SVikas Chaudhary ha->isp_ops->enable_intrs(ha); 2352afaf5a2dSDavid Somayajulu } 2353afaf5a2dSDavid Somayajulu } 2354afaf5a2dSDavid Somayajulu 2355f4f5df23SVikas Chaudhary dpc_post_reset_ha: 2356afaf5a2dSDavid Somayajulu /* ---- process AEN? --- */ 2357afaf5a2dSDavid Somayajulu if (test_and_clear_bit(DPC_AEN, &ha->dpc_flags)) 2358afaf5a2dSDavid Somayajulu qla4xxx_process_aen(ha, PROCESS_ALL_AENS); 2359afaf5a2dSDavid Somayajulu 2360afaf5a2dSDavid Somayajulu /* ---- Get DHCP IP Address? --- */ 2361afaf5a2dSDavid Somayajulu if (test_and_clear_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags)) 2362afaf5a2dSDavid Somayajulu qla4xxx_get_dhcp_ip_address(ha); 2363afaf5a2dSDavid Somayajulu 2364065aa1b4SVikas Chaudhary /* ---- link change? --- */ 2365065aa1b4SVikas Chaudhary if (test_and_clear_bit(DPC_LINK_CHANGED, &ha->dpc_flags)) { 2366065aa1b4SVikas Chaudhary if (!test_bit(AF_LINK_UP, &ha->flags)) { 2367065aa1b4SVikas Chaudhary /* ---- link down? --- */ 23682d7924e6SVikas Chaudhary qla4xxx_mark_all_devices_missing(ha); 2369065aa1b4SVikas Chaudhary } else { 2370065aa1b4SVikas Chaudhary /* ---- link up? --- * 2371065aa1b4SVikas Chaudhary * F/W will auto login to all devices ONLY ONCE after 2372065aa1b4SVikas Chaudhary * link up during driver initialization and runtime 2373065aa1b4SVikas Chaudhary * fatal error recovery. Therefore, the driver must 2374065aa1b4SVikas Chaudhary * manually relogin to devices when recovering from 2375065aa1b4SVikas Chaudhary * connection failures, logouts, expired KATO, etc. */ 2376065aa1b4SVikas Chaudhary 23772d7924e6SVikas Chaudhary qla4xxx_relogin_all_devices(ha); 2378065aa1b4SVikas Chaudhary } 2379065aa1b4SVikas Chaudhary } 2380afaf5a2dSDavid Somayajulu } 2381afaf5a2dSDavid Somayajulu 2382afaf5a2dSDavid Somayajulu /** 2383afaf5a2dSDavid Somayajulu * qla4xxx_free_adapter - release the adapter 2384afaf5a2dSDavid Somayajulu * @ha: pointer to adapter structure 2385afaf5a2dSDavid Somayajulu **/ 2386afaf5a2dSDavid Somayajulu static void qla4xxx_free_adapter(struct scsi_qla_host *ha) 2387afaf5a2dSDavid Somayajulu { 2388afaf5a2dSDavid Somayajulu 2389afaf5a2dSDavid Somayajulu if (test_bit(AF_INTERRUPTS_ON, &ha->flags)) { 2390afaf5a2dSDavid Somayajulu /* Turn-off interrupts on the card. */ 2391f4f5df23SVikas Chaudhary ha->isp_ops->disable_intrs(ha); 2392afaf5a2dSDavid Somayajulu } 2393afaf5a2dSDavid Somayajulu 2394afaf5a2dSDavid Somayajulu /* Remove timer thread, if present */ 2395afaf5a2dSDavid Somayajulu if (ha->timer_active) 2396afaf5a2dSDavid Somayajulu qla4xxx_stop_timer(ha); 2397afaf5a2dSDavid Somayajulu 2398f4f5df23SVikas Chaudhary /* Kill the kernel thread for this host */ 2399f4f5df23SVikas Chaudhary if (ha->dpc_thread) 2400f4f5df23SVikas Chaudhary destroy_workqueue(ha->dpc_thread); 2401f4f5df23SVikas Chaudhary 2402b3a271a9SManish Rangankar /* Kill the kernel thread for this host */ 2403b3a271a9SManish Rangankar if (ha->task_wq) 2404b3a271a9SManish Rangankar destroy_workqueue(ha->task_wq); 2405b3a271a9SManish Rangankar 2406f4f5df23SVikas Chaudhary /* Put firmware in known state */ 2407f4f5df23SVikas Chaudhary ha->isp_ops->reset_firmware(ha); 2408f4f5df23SVikas Chaudhary 2409f4f5df23SVikas Chaudhary if (is_qla8022(ha)) { 2410f4f5df23SVikas Chaudhary qla4_8xxx_idc_lock(ha); 2411f4f5df23SVikas Chaudhary qla4_8xxx_clear_drv_active(ha); 2412f4f5df23SVikas Chaudhary qla4_8xxx_idc_unlock(ha); 2413f4f5df23SVikas Chaudhary } 2414f4f5df23SVikas Chaudhary 2415afaf5a2dSDavid Somayajulu /* Detach interrupts */ 2416afaf5a2dSDavid Somayajulu if (test_and_clear_bit(AF_IRQ_ATTACHED, &ha->flags)) 2417f4f5df23SVikas Chaudhary qla4xxx_free_irqs(ha); 2418afaf5a2dSDavid Somayajulu 2419bee4fe8eSDavid C Somayajulu /* free extra memory */ 2420bee4fe8eSDavid C Somayajulu qla4xxx_mem_free(ha); 2421f4f5df23SVikas Chaudhary } 2422bee4fe8eSDavid C Somayajulu 2423f4f5df23SVikas Chaudhary int qla4_8xxx_iospace_config(struct scsi_qla_host *ha) 2424f4f5df23SVikas Chaudhary { 2425f4f5df23SVikas Chaudhary int status = 0; 2426f4f5df23SVikas Chaudhary uint8_t revision_id; 2427f4f5df23SVikas Chaudhary unsigned long mem_base, mem_len, db_base, db_len; 2428f4f5df23SVikas Chaudhary struct pci_dev *pdev = ha->pdev; 2429afaf5a2dSDavid Somayajulu 2430f4f5df23SVikas Chaudhary status = pci_request_regions(pdev, DRIVER_NAME); 2431f4f5df23SVikas Chaudhary if (status) { 2432f4f5df23SVikas Chaudhary printk(KERN_WARNING 2433f4f5df23SVikas Chaudhary "scsi(%ld) Failed to reserve PIO regions (%s) " 2434f4f5df23SVikas Chaudhary "status=%d\n", ha->host_no, pci_name(pdev), status); 2435f4f5df23SVikas Chaudhary goto iospace_error_exit; 2436f4f5df23SVikas Chaudhary } 2437f4f5df23SVikas Chaudhary 2438f4f5df23SVikas Chaudhary pci_read_config_byte(pdev, PCI_REVISION_ID, &revision_id); 2439f4f5df23SVikas Chaudhary DEBUG2(printk(KERN_INFO "%s: revision-id=%d\n", 2440f4f5df23SVikas Chaudhary __func__, revision_id)); 2441f4f5df23SVikas Chaudhary ha->revision_id = revision_id; 2442f4f5df23SVikas Chaudhary 2443f4f5df23SVikas Chaudhary /* remap phys address */ 2444f4f5df23SVikas Chaudhary mem_base = pci_resource_start(pdev, 0); /* 0 is for BAR 0 */ 2445f4f5df23SVikas Chaudhary mem_len = pci_resource_len(pdev, 0); 2446f4f5df23SVikas Chaudhary DEBUG2(printk(KERN_INFO "%s: ioremap from %lx a size of %lx\n", 2447f4f5df23SVikas Chaudhary __func__, mem_base, mem_len)); 2448f4f5df23SVikas Chaudhary 2449f4f5df23SVikas Chaudhary /* mapping of pcibase pointer */ 2450f4f5df23SVikas Chaudhary ha->nx_pcibase = (unsigned long)ioremap(mem_base, mem_len); 2451f4f5df23SVikas Chaudhary if (!ha->nx_pcibase) { 2452f4f5df23SVikas Chaudhary printk(KERN_ERR 2453f4f5df23SVikas Chaudhary "cannot remap MMIO (%s), aborting\n", pci_name(pdev)); 2454f4f5df23SVikas Chaudhary pci_release_regions(ha->pdev); 2455f4f5df23SVikas Chaudhary goto iospace_error_exit; 2456f4f5df23SVikas Chaudhary } 2457f4f5df23SVikas Chaudhary 2458f4f5df23SVikas Chaudhary /* Mapping of IO base pointer, door bell read and write pointer */ 2459f4f5df23SVikas Chaudhary 2460f4f5df23SVikas Chaudhary /* mapping of IO base pointer */ 2461f4f5df23SVikas Chaudhary ha->qla4_8xxx_reg = 2462f4f5df23SVikas Chaudhary (struct device_reg_82xx __iomem *)((uint8_t *)ha->nx_pcibase + 2463f4f5df23SVikas Chaudhary 0xbc000 + (ha->pdev->devfn << 11)); 2464f4f5df23SVikas Chaudhary 2465f4f5df23SVikas Chaudhary db_base = pci_resource_start(pdev, 4); /* doorbell is on bar 4 */ 2466f4f5df23SVikas Chaudhary db_len = pci_resource_len(pdev, 4); 2467f4f5df23SVikas Chaudhary 24682657c800SShyam Sundar ha->nx_db_wr_ptr = (ha->pdev->devfn == 4 ? QLA82XX_CAM_RAM_DB1 : 24692657c800SShyam Sundar QLA82XX_CAM_RAM_DB2); 2470f4f5df23SVikas Chaudhary 24712657c800SShyam Sundar return 0; 2472f4f5df23SVikas Chaudhary iospace_error_exit: 2473f4f5df23SVikas Chaudhary return -ENOMEM; 2474afaf5a2dSDavid Somayajulu } 2475afaf5a2dSDavid Somayajulu 2476afaf5a2dSDavid Somayajulu /*** 2477afaf5a2dSDavid Somayajulu * qla4xxx_iospace_config - maps registers 2478afaf5a2dSDavid Somayajulu * @ha: pointer to adapter structure 2479afaf5a2dSDavid Somayajulu * 2480afaf5a2dSDavid Somayajulu * This routines maps HBA's registers from the pci address space 2481afaf5a2dSDavid Somayajulu * into the kernel virtual address space for memory mapped i/o. 2482afaf5a2dSDavid Somayajulu **/ 2483f4f5df23SVikas Chaudhary int qla4xxx_iospace_config(struct scsi_qla_host *ha) 2484afaf5a2dSDavid Somayajulu { 2485afaf5a2dSDavid Somayajulu unsigned long pio, pio_len, pio_flags; 2486afaf5a2dSDavid Somayajulu unsigned long mmio, mmio_len, mmio_flags; 2487afaf5a2dSDavid Somayajulu 2488afaf5a2dSDavid Somayajulu pio = pci_resource_start(ha->pdev, 0); 2489afaf5a2dSDavid Somayajulu pio_len = pci_resource_len(ha->pdev, 0); 2490afaf5a2dSDavid Somayajulu pio_flags = pci_resource_flags(ha->pdev, 0); 2491afaf5a2dSDavid Somayajulu if (pio_flags & IORESOURCE_IO) { 2492afaf5a2dSDavid Somayajulu if (pio_len < MIN_IOBASE_LEN) { 2493c2660df3SVikas Chaudhary ql4_printk(KERN_WARNING, ha, 2494afaf5a2dSDavid Somayajulu "Invalid PCI I/O region size\n"); 2495afaf5a2dSDavid Somayajulu pio = 0; 2496afaf5a2dSDavid Somayajulu } 2497afaf5a2dSDavid Somayajulu } else { 2498c2660df3SVikas Chaudhary ql4_printk(KERN_WARNING, ha, "region #0 not a PIO resource\n"); 2499afaf5a2dSDavid Somayajulu pio = 0; 2500afaf5a2dSDavid Somayajulu } 2501afaf5a2dSDavid Somayajulu 2502afaf5a2dSDavid Somayajulu /* Use MMIO operations for all accesses. */ 2503afaf5a2dSDavid Somayajulu mmio = pci_resource_start(ha->pdev, 1); 2504afaf5a2dSDavid Somayajulu mmio_len = pci_resource_len(ha->pdev, 1); 2505afaf5a2dSDavid Somayajulu mmio_flags = pci_resource_flags(ha->pdev, 1); 2506afaf5a2dSDavid Somayajulu 2507afaf5a2dSDavid Somayajulu if (!(mmio_flags & IORESOURCE_MEM)) { 2508c2660df3SVikas Chaudhary ql4_printk(KERN_ERR, ha, 2509afaf5a2dSDavid Somayajulu "region #0 not an MMIO resource, aborting\n"); 2510afaf5a2dSDavid Somayajulu 2511afaf5a2dSDavid Somayajulu goto iospace_error_exit; 2512afaf5a2dSDavid Somayajulu } 2513c2660df3SVikas Chaudhary 2514afaf5a2dSDavid Somayajulu if (mmio_len < MIN_IOBASE_LEN) { 2515c2660df3SVikas Chaudhary ql4_printk(KERN_ERR, ha, 2516afaf5a2dSDavid Somayajulu "Invalid PCI mem region size, aborting\n"); 2517afaf5a2dSDavid Somayajulu goto iospace_error_exit; 2518afaf5a2dSDavid Somayajulu } 2519afaf5a2dSDavid Somayajulu 2520afaf5a2dSDavid Somayajulu if (pci_request_regions(ha->pdev, DRIVER_NAME)) { 2521c2660df3SVikas Chaudhary ql4_printk(KERN_WARNING, ha, 2522afaf5a2dSDavid Somayajulu "Failed to reserve PIO/MMIO regions\n"); 2523afaf5a2dSDavid Somayajulu 2524afaf5a2dSDavid Somayajulu goto iospace_error_exit; 2525afaf5a2dSDavid Somayajulu } 2526afaf5a2dSDavid Somayajulu 2527afaf5a2dSDavid Somayajulu ha->pio_address = pio; 2528afaf5a2dSDavid Somayajulu ha->pio_length = pio_len; 2529afaf5a2dSDavid Somayajulu ha->reg = ioremap(mmio, MIN_IOBASE_LEN); 2530afaf5a2dSDavid Somayajulu if (!ha->reg) { 2531c2660df3SVikas Chaudhary ql4_printk(KERN_ERR, ha, 2532afaf5a2dSDavid Somayajulu "cannot remap MMIO, aborting\n"); 2533afaf5a2dSDavid Somayajulu 2534afaf5a2dSDavid Somayajulu goto iospace_error_exit; 2535afaf5a2dSDavid Somayajulu } 2536afaf5a2dSDavid Somayajulu 2537afaf5a2dSDavid Somayajulu return 0; 2538afaf5a2dSDavid Somayajulu 2539afaf5a2dSDavid Somayajulu iospace_error_exit: 2540afaf5a2dSDavid Somayajulu return -ENOMEM; 2541afaf5a2dSDavid Somayajulu } 2542afaf5a2dSDavid Somayajulu 2543f4f5df23SVikas Chaudhary static struct isp_operations qla4xxx_isp_ops = { 2544f4f5df23SVikas Chaudhary .iospace_config = qla4xxx_iospace_config, 2545f4f5df23SVikas Chaudhary .pci_config = qla4xxx_pci_config, 2546f4f5df23SVikas Chaudhary .disable_intrs = qla4xxx_disable_intrs, 2547f4f5df23SVikas Chaudhary .enable_intrs = qla4xxx_enable_intrs, 2548f4f5df23SVikas Chaudhary .start_firmware = qla4xxx_start_firmware, 2549f4f5df23SVikas Chaudhary .intr_handler = qla4xxx_intr_handler, 2550f4f5df23SVikas Chaudhary .interrupt_service_routine = qla4xxx_interrupt_service_routine, 2551f4f5df23SVikas Chaudhary .reset_chip = qla4xxx_soft_reset, 2552f4f5df23SVikas Chaudhary .reset_firmware = qla4xxx_hw_reset, 2553f4f5df23SVikas Chaudhary .queue_iocb = qla4xxx_queue_iocb, 2554f4f5df23SVikas Chaudhary .complete_iocb = qla4xxx_complete_iocb, 2555f4f5df23SVikas Chaudhary .rd_shdw_req_q_out = qla4xxx_rd_shdw_req_q_out, 2556f4f5df23SVikas Chaudhary .rd_shdw_rsp_q_in = qla4xxx_rd_shdw_rsp_q_in, 2557f4f5df23SVikas Chaudhary .get_sys_info = qla4xxx_get_sys_info, 2558f4f5df23SVikas Chaudhary }; 2559f4f5df23SVikas Chaudhary 2560f4f5df23SVikas Chaudhary static struct isp_operations qla4_8xxx_isp_ops = { 2561f4f5df23SVikas Chaudhary .iospace_config = qla4_8xxx_iospace_config, 2562f4f5df23SVikas Chaudhary .pci_config = qla4_8xxx_pci_config, 2563f4f5df23SVikas Chaudhary .disable_intrs = qla4_8xxx_disable_intrs, 2564f4f5df23SVikas Chaudhary .enable_intrs = qla4_8xxx_enable_intrs, 2565f4f5df23SVikas Chaudhary .start_firmware = qla4_8xxx_load_risc, 2566f4f5df23SVikas Chaudhary .intr_handler = qla4_8xxx_intr_handler, 2567f4f5df23SVikas Chaudhary .interrupt_service_routine = qla4_8xxx_interrupt_service_routine, 2568f4f5df23SVikas Chaudhary .reset_chip = qla4_8xxx_isp_reset, 2569f4f5df23SVikas Chaudhary .reset_firmware = qla4_8xxx_stop_firmware, 2570f4f5df23SVikas Chaudhary .queue_iocb = qla4_8xxx_queue_iocb, 2571f4f5df23SVikas Chaudhary .complete_iocb = qla4_8xxx_complete_iocb, 2572f4f5df23SVikas Chaudhary .rd_shdw_req_q_out = qla4_8xxx_rd_shdw_req_q_out, 2573f4f5df23SVikas Chaudhary .rd_shdw_rsp_q_in = qla4_8xxx_rd_shdw_rsp_q_in, 2574f4f5df23SVikas Chaudhary .get_sys_info = qla4_8xxx_get_sys_info, 2575f4f5df23SVikas Chaudhary }; 2576f4f5df23SVikas Chaudhary 2577f4f5df23SVikas Chaudhary uint16_t qla4xxx_rd_shdw_req_q_out(struct scsi_qla_host *ha) 2578f4f5df23SVikas Chaudhary { 2579f4f5df23SVikas Chaudhary return (uint16_t)le32_to_cpu(ha->shadow_regs->req_q_out); 2580f4f5df23SVikas Chaudhary } 2581f4f5df23SVikas Chaudhary 2582f4f5df23SVikas Chaudhary uint16_t qla4_8xxx_rd_shdw_req_q_out(struct scsi_qla_host *ha) 2583f4f5df23SVikas Chaudhary { 2584f4f5df23SVikas Chaudhary return (uint16_t)le32_to_cpu(readl(&ha->qla4_8xxx_reg->req_q_out)); 2585f4f5df23SVikas Chaudhary } 2586f4f5df23SVikas Chaudhary 2587f4f5df23SVikas Chaudhary uint16_t qla4xxx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha) 2588f4f5df23SVikas Chaudhary { 2589f4f5df23SVikas Chaudhary return (uint16_t)le32_to_cpu(ha->shadow_regs->rsp_q_in); 2590f4f5df23SVikas Chaudhary } 2591f4f5df23SVikas Chaudhary 2592f4f5df23SVikas Chaudhary uint16_t qla4_8xxx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha) 2593f4f5df23SVikas Chaudhary { 2594f4f5df23SVikas Chaudhary return (uint16_t)le32_to_cpu(readl(&ha->qla4_8xxx_reg->rsp_q_in)); 2595f4f5df23SVikas Chaudhary } 2596f4f5df23SVikas Chaudhary 25972a991c21SManish Rangankar static ssize_t qla4xxx_show_boot_eth_info(void *data, int type, char *buf) 25982a991c21SManish Rangankar { 25992a991c21SManish Rangankar struct scsi_qla_host *ha = data; 26002a991c21SManish Rangankar char *str = buf; 26012a991c21SManish Rangankar int rc; 26022a991c21SManish Rangankar 26032a991c21SManish Rangankar switch (type) { 26042a991c21SManish Rangankar case ISCSI_BOOT_ETH_FLAGS: 26052a991c21SManish Rangankar rc = sprintf(str, "%d\n", SYSFS_FLAG_FW_SEL_BOOT); 26062a991c21SManish Rangankar break; 26072a991c21SManish Rangankar case ISCSI_BOOT_ETH_INDEX: 26082a991c21SManish Rangankar rc = sprintf(str, "0\n"); 26092a991c21SManish Rangankar break; 26102a991c21SManish Rangankar case ISCSI_BOOT_ETH_MAC: 26112a991c21SManish Rangankar rc = sysfs_format_mac(str, ha->my_mac, 26122a991c21SManish Rangankar MAC_ADDR_LEN); 26132a991c21SManish Rangankar break; 26142a991c21SManish Rangankar default: 26152a991c21SManish Rangankar rc = -ENOSYS; 26162a991c21SManish Rangankar break; 26172a991c21SManish Rangankar } 26182a991c21SManish Rangankar return rc; 26192a991c21SManish Rangankar } 26202a991c21SManish Rangankar 26212a991c21SManish Rangankar static mode_t qla4xxx_eth_get_attr_visibility(void *data, int type) 26222a991c21SManish Rangankar { 26232a991c21SManish Rangankar int rc; 26242a991c21SManish Rangankar 26252a991c21SManish Rangankar switch (type) { 26262a991c21SManish Rangankar case ISCSI_BOOT_ETH_FLAGS: 26272a991c21SManish Rangankar case ISCSI_BOOT_ETH_MAC: 26282a991c21SManish Rangankar case ISCSI_BOOT_ETH_INDEX: 26292a991c21SManish Rangankar rc = S_IRUGO; 26302a991c21SManish Rangankar break; 26312a991c21SManish Rangankar default: 26322a991c21SManish Rangankar rc = 0; 26332a991c21SManish Rangankar break; 26342a991c21SManish Rangankar } 26352a991c21SManish Rangankar return rc; 26362a991c21SManish Rangankar } 26372a991c21SManish Rangankar 26382a991c21SManish Rangankar static ssize_t qla4xxx_show_boot_ini_info(void *data, int type, char *buf) 26392a991c21SManish Rangankar { 26402a991c21SManish Rangankar struct scsi_qla_host *ha = data; 26412a991c21SManish Rangankar char *str = buf; 26422a991c21SManish Rangankar int rc; 26432a991c21SManish Rangankar 26442a991c21SManish Rangankar switch (type) { 26452a991c21SManish Rangankar case ISCSI_BOOT_INI_INITIATOR_NAME: 26462a991c21SManish Rangankar rc = sprintf(str, "%s\n", ha->name_string); 26472a991c21SManish Rangankar break; 26482a991c21SManish Rangankar default: 26492a991c21SManish Rangankar rc = -ENOSYS; 26502a991c21SManish Rangankar break; 26512a991c21SManish Rangankar } 26522a991c21SManish Rangankar return rc; 26532a991c21SManish Rangankar } 26542a991c21SManish Rangankar 26552a991c21SManish Rangankar static mode_t qla4xxx_ini_get_attr_visibility(void *data, int type) 26562a991c21SManish Rangankar { 26572a991c21SManish Rangankar int rc; 26582a991c21SManish Rangankar 26592a991c21SManish Rangankar switch (type) { 26602a991c21SManish Rangankar case ISCSI_BOOT_INI_INITIATOR_NAME: 26612a991c21SManish Rangankar rc = S_IRUGO; 26622a991c21SManish Rangankar break; 26632a991c21SManish Rangankar default: 26642a991c21SManish Rangankar rc = 0; 26652a991c21SManish Rangankar break; 26662a991c21SManish Rangankar } 26672a991c21SManish Rangankar return rc; 26682a991c21SManish Rangankar } 26692a991c21SManish Rangankar 26702a991c21SManish Rangankar static ssize_t 26712a991c21SManish Rangankar qla4xxx_show_boot_tgt_info(struct ql4_boot_session_info *boot_sess, int type, 26722a991c21SManish Rangankar char *buf) 26732a991c21SManish Rangankar { 26742a991c21SManish Rangankar struct ql4_conn_info *boot_conn = &boot_sess->conn_list[0]; 26752a991c21SManish Rangankar char *str = buf; 26762a991c21SManish Rangankar int rc; 26772a991c21SManish Rangankar 26782a991c21SManish Rangankar switch (type) { 26792a991c21SManish Rangankar case ISCSI_BOOT_TGT_NAME: 26802a991c21SManish Rangankar rc = sprintf(buf, "%s\n", (char *)&boot_sess->target_name); 26812a991c21SManish Rangankar break; 26822a991c21SManish Rangankar case ISCSI_BOOT_TGT_IP_ADDR: 26832a991c21SManish Rangankar if (boot_sess->conn_list[0].dest_ipaddr.ip_type == 0x1) 26842a991c21SManish Rangankar rc = sprintf(buf, "%pI4\n", 26852a991c21SManish Rangankar &boot_conn->dest_ipaddr.ip_address); 26862a991c21SManish Rangankar else 26872a991c21SManish Rangankar rc = sprintf(str, "%pI6\n", 26882a991c21SManish Rangankar &boot_conn->dest_ipaddr.ip_address); 26892a991c21SManish Rangankar break; 26902a991c21SManish Rangankar case ISCSI_BOOT_TGT_PORT: 26912a991c21SManish Rangankar rc = sprintf(str, "%d\n", boot_conn->dest_port); 26922a991c21SManish Rangankar break; 26932a991c21SManish Rangankar case ISCSI_BOOT_TGT_CHAP_NAME: 26942a991c21SManish Rangankar rc = sprintf(str, "%.*s\n", 26952a991c21SManish Rangankar boot_conn->chap.target_chap_name_length, 26962a991c21SManish Rangankar (char *)&boot_conn->chap.target_chap_name); 26972a991c21SManish Rangankar break; 26982a991c21SManish Rangankar case ISCSI_BOOT_TGT_CHAP_SECRET: 26992a991c21SManish Rangankar rc = sprintf(str, "%.*s\n", 27002a991c21SManish Rangankar boot_conn->chap.target_secret_length, 27012a991c21SManish Rangankar (char *)&boot_conn->chap.target_secret); 27022a991c21SManish Rangankar break; 27032a991c21SManish Rangankar case ISCSI_BOOT_TGT_REV_CHAP_NAME: 27042a991c21SManish Rangankar rc = sprintf(str, "%.*s\n", 27052a991c21SManish Rangankar boot_conn->chap.intr_chap_name_length, 27062a991c21SManish Rangankar (char *)&boot_conn->chap.intr_chap_name); 27072a991c21SManish Rangankar break; 27082a991c21SManish Rangankar case ISCSI_BOOT_TGT_REV_CHAP_SECRET: 27092a991c21SManish Rangankar rc = sprintf(str, "%.*s\n", 27102a991c21SManish Rangankar boot_conn->chap.intr_secret_length, 27112a991c21SManish Rangankar (char *)&boot_conn->chap.intr_secret); 27122a991c21SManish Rangankar break; 27132a991c21SManish Rangankar case ISCSI_BOOT_TGT_FLAGS: 27142a991c21SManish Rangankar rc = sprintf(str, "%d\n", SYSFS_FLAG_FW_SEL_BOOT); 27152a991c21SManish Rangankar break; 27162a991c21SManish Rangankar case ISCSI_BOOT_TGT_NIC_ASSOC: 27172a991c21SManish Rangankar rc = sprintf(str, "0\n"); 27182a991c21SManish Rangankar break; 27192a991c21SManish Rangankar default: 27202a991c21SManish Rangankar rc = -ENOSYS; 27212a991c21SManish Rangankar break; 27222a991c21SManish Rangankar } 27232a991c21SManish Rangankar return rc; 27242a991c21SManish Rangankar } 27252a991c21SManish Rangankar 27262a991c21SManish Rangankar static ssize_t qla4xxx_show_boot_tgt_pri_info(void *data, int type, char *buf) 27272a991c21SManish Rangankar { 27282a991c21SManish Rangankar struct scsi_qla_host *ha = data; 27292a991c21SManish Rangankar struct ql4_boot_session_info *boot_sess = &(ha->boot_tgt.boot_pri_sess); 27302a991c21SManish Rangankar 27312a991c21SManish Rangankar return qla4xxx_show_boot_tgt_info(boot_sess, type, buf); 27322a991c21SManish Rangankar } 27332a991c21SManish Rangankar 27342a991c21SManish Rangankar static ssize_t qla4xxx_show_boot_tgt_sec_info(void *data, int type, char *buf) 27352a991c21SManish Rangankar { 27362a991c21SManish Rangankar struct scsi_qla_host *ha = data; 27372a991c21SManish Rangankar struct ql4_boot_session_info *boot_sess = &(ha->boot_tgt.boot_sec_sess); 27382a991c21SManish Rangankar 27392a991c21SManish Rangankar return qla4xxx_show_boot_tgt_info(boot_sess, type, buf); 27402a991c21SManish Rangankar } 27412a991c21SManish Rangankar 27422a991c21SManish Rangankar static mode_t qla4xxx_tgt_get_attr_visibility(void *data, int type) 27432a991c21SManish Rangankar { 27442a991c21SManish Rangankar int rc; 27452a991c21SManish Rangankar 27462a991c21SManish Rangankar switch (type) { 27472a991c21SManish Rangankar case ISCSI_BOOT_TGT_NAME: 27482a991c21SManish Rangankar case ISCSI_BOOT_TGT_IP_ADDR: 27492a991c21SManish Rangankar case ISCSI_BOOT_TGT_PORT: 27502a991c21SManish Rangankar case ISCSI_BOOT_TGT_CHAP_NAME: 27512a991c21SManish Rangankar case ISCSI_BOOT_TGT_CHAP_SECRET: 27522a991c21SManish Rangankar case ISCSI_BOOT_TGT_REV_CHAP_NAME: 27532a991c21SManish Rangankar case ISCSI_BOOT_TGT_REV_CHAP_SECRET: 27542a991c21SManish Rangankar case ISCSI_BOOT_TGT_NIC_ASSOC: 27552a991c21SManish Rangankar case ISCSI_BOOT_TGT_FLAGS: 27562a991c21SManish Rangankar rc = S_IRUGO; 27572a991c21SManish Rangankar break; 27582a991c21SManish Rangankar default: 27592a991c21SManish Rangankar rc = 0; 27602a991c21SManish Rangankar break; 27612a991c21SManish Rangankar } 27622a991c21SManish Rangankar return rc; 27632a991c21SManish Rangankar } 27642a991c21SManish Rangankar 27652a991c21SManish Rangankar static void qla4xxx_boot_release(void *data) 27662a991c21SManish Rangankar { 27672a991c21SManish Rangankar struct scsi_qla_host *ha = data; 27682a991c21SManish Rangankar 27692a991c21SManish Rangankar scsi_host_put(ha->host); 27702a991c21SManish Rangankar } 27712a991c21SManish Rangankar 27722a991c21SManish Rangankar static int get_fw_boot_info(struct scsi_qla_host *ha, uint16_t ddb_index[]) 27732a991c21SManish Rangankar { 27742a991c21SManish Rangankar dma_addr_t buf_dma; 27752a991c21SManish Rangankar uint32_t addr, pri_addr, sec_addr; 27762a991c21SManish Rangankar uint32_t offset; 27772a991c21SManish Rangankar uint16_t func_num; 27782a991c21SManish Rangankar uint8_t val; 27792a991c21SManish Rangankar uint8_t *buf = NULL; 27802a991c21SManish Rangankar size_t size = 13 * sizeof(uint8_t); 27812a991c21SManish Rangankar int ret = QLA_SUCCESS; 27822a991c21SManish Rangankar 27832a991c21SManish Rangankar func_num = PCI_FUNC(ha->pdev->devfn); 27842a991c21SManish Rangankar 27852a991c21SManish Rangankar DEBUG2(ql4_printk(KERN_INFO, ha, 27862a991c21SManish Rangankar "%s: Get FW boot info for 0x%x func %d\n", __func__, 27872a991c21SManish Rangankar (is_qla4032(ha) ? PCI_DEVICE_ID_QLOGIC_ISP4032 : 27882a991c21SManish Rangankar PCI_DEVICE_ID_QLOGIC_ISP8022), func_num)); 27892a991c21SManish Rangankar 27902a991c21SManish Rangankar if (is_qla4032(ha)) { 27912a991c21SManish Rangankar if (func_num == 1) { 27922a991c21SManish Rangankar addr = NVRAM_PORT0_BOOT_MODE; 27932a991c21SManish Rangankar pri_addr = NVRAM_PORT0_BOOT_PRI_TGT; 27942a991c21SManish Rangankar sec_addr = NVRAM_PORT0_BOOT_SEC_TGT; 27952a991c21SManish Rangankar } else if (func_num == 3) { 27962a991c21SManish Rangankar addr = NVRAM_PORT1_BOOT_MODE; 27972a991c21SManish Rangankar pri_addr = NVRAM_PORT1_BOOT_PRI_TGT; 27982a991c21SManish Rangankar sec_addr = NVRAM_PORT1_BOOT_SEC_TGT; 27992a991c21SManish Rangankar } else { 28002a991c21SManish Rangankar ret = QLA_ERROR; 28012a991c21SManish Rangankar goto exit_boot_info; 28022a991c21SManish Rangankar } 28032a991c21SManish Rangankar 28042a991c21SManish Rangankar /* Check Boot Mode */ 28052a991c21SManish Rangankar val = rd_nvram_byte(ha, addr); 28062a991c21SManish Rangankar if (!(val & 0x07)) { 28072a991c21SManish Rangankar DEBUG2(ql4_printk(KERN_ERR, ha, 28082a991c21SManish Rangankar "%s: Failed Boot options : 0x%x\n", 28092a991c21SManish Rangankar __func__, val)); 28102a991c21SManish Rangankar ret = QLA_ERROR; 28112a991c21SManish Rangankar goto exit_boot_info; 28122a991c21SManish Rangankar } 28132a991c21SManish Rangankar 28142a991c21SManish Rangankar /* get primary valid target index */ 28152a991c21SManish Rangankar val = rd_nvram_byte(ha, pri_addr); 28162a991c21SManish Rangankar if (val & BIT_7) 28172a991c21SManish Rangankar ddb_index[0] = (val & 0x7f); 28182a991c21SManish Rangankar 28192a991c21SManish Rangankar /* get secondary valid target index */ 28202a991c21SManish Rangankar val = rd_nvram_byte(ha, sec_addr); 28212a991c21SManish Rangankar if (val & BIT_7) 28222a991c21SManish Rangankar ddb_index[1] = (val & 0x7f); 28232a991c21SManish Rangankar 28242a991c21SManish Rangankar } else if (is_qla8022(ha)) { 28252a991c21SManish Rangankar buf = dma_alloc_coherent(&ha->pdev->dev, size, 28262a991c21SManish Rangankar &buf_dma, GFP_KERNEL); 28272a991c21SManish Rangankar if (!buf) { 28282a991c21SManish Rangankar DEBUG2(ql4_printk(KERN_ERR, ha, 28292a991c21SManish Rangankar "%s: Unable to allocate dma buffer\n", 28302a991c21SManish Rangankar __func__)); 28312a991c21SManish Rangankar ret = QLA_ERROR; 28322a991c21SManish Rangankar goto exit_boot_info; 28332a991c21SManish Rangankar } 28342a991c21SManish Rangankar 28352a991c21SManish Rangankar if (ha->port_num == 0) 28362a991c21SManish Rangankar offset = BOOT_PARAM_OFFSET_PORT0; 28372a991c21SManish Rangankar else if (ha->port_num == 1) 28382a991c21SManish Rangankar offset = BOOT_PARAM_OFFSET_PORT1; 28392a991c21SManish Rangankar else { 28402a991c21SManish Rangankar ret = QLA_ERROR; 28412a991c21SManish Rangankar goto exit_boot_info_free; 28422a991c21SManish Rangankar } 28432a991c21SManish Rangankar addr = FLASH_RAW_ACCESS_ADDR + (ha->hw.flt_iscsi_param * 4) + 28442a991c21SManish Rangankar offset; 28452a991c21SManish Rangankar if (qla4xxx_get_flash(ha, buf_dma, addr, 28462a991c21SManish Rangankar 13 * sizeof(uint8_t)) != QLA_SUCCESS) { 28472a991c21SManish Rangankar DEBUG2(ql4_printk(KERN_ERR, ha, "scsi%ld: %s: Get Flash" 28482a991c21SManish Rangankar "failed\n", ha->host_no, __func__)); 28492a991c21SManish Rangankar ret = QLA_ERROR; 28502a991c21SManish Rangankar goto exit_boot_info_free; 28512a991c21SManish Rangankar } 28522a991c21SManish Rangankar /* Check Boot Mode */ 28532a991c21SManish Rangankar if (!(buf[1] & 0x07)) { 28542a991c21SManish Rangankar DEBUG2(ql4_printk(KERN_INFO, ha, 28552a991c21SManish Rangankar "Failed: Boot options : 0x%x\n", 28562a991c21SManish Rangankar buf[1])); 28572a991c21SManish Rangankar ret = QLA_ERROR; 28582a991c21SManish Rangankar goto exit_boot_info_free; 28592a991c21SManish Rangankar } 28602a991c21SManish Rangankar 28612a991c21SManish Rangankar /* get primary valid target index */ 28622a991c21SManish Rangankar if (buf[2] & BIT_7) 28632a991c21SManish Rangankar ddb_index[0] = buf[2] & 0x7f; 28642a991c21SManish Rangankar 28652a991c21SManish Rangankar /* get secondary valid target index */ 28662a991c21SManish Rangankar if (buf[11] & BIT_7) 28672a991c21SManish Rangankar ddb_index[1] = buf[11] & 0x7f; 28682a991c21SManish Rangankar } else { 28692a991c21SManish Rangankar ret = QLA_ERROR; 28702a991c21SManish Rangankar goto exit_boot_info; 28712a991c21SManish Rangankar } 28722a991c21SManish Rangankar 28732a991c21SManish Rangankar DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Primary target ID %d, Secondary" 28742a991c21SManish Rangankar " target ID %d\n", __func__, ddb_index[0], 28752a991c21SManish Rangankar ddb_index[1])); 28762a991c21SManish Rangankar 28772a991c21SManish Rangankar exit_boot_info_free: 28782a991c21SManish Rangankar dma_free_coherent(&ha->pdev->dev, size, buf, buf_dma); 28792a991c21SManish Rangankar exit_boot_info: 28802a991c21SManish Rangankar return ret; 28812a991c21SManish Rangankar } 28822a991c21SManish Rangankar 288328deb45cSLalit Chandivade /** 288428deb45cSLalit Chandivade * qla4xxx_get_bidi_chap - Get a BIDI CHAP user and password 288528deb45cSLalit Chandivade * @ha: pointer to adapter structure 288628deb45cSLalit Chandivade * @username: CHAP username to be returned 288728deb45cSLalit Chandivade * @password: CHAP password to be returned 288828deb45cSLalit Chandivade * 288928deb45cSLalit Chandivade * If a boot entry has BIDI CHAP enabled then we need to set the BIDI CHAP 289028deb45cSLalit Chandivade * user and password in the sysfs entry in /sys/firmware/iscsi_boot#/. 289128deb45cSLalit Chandivade * So from the CHAP cache find the first BIDI CHAP entry and set it 289228deb45cSLalit Chandivade * to the boot record in sysfs. 289328deb45cSLalit Chandivade **/ 289428deb45cSLalit Chandivade static int qla4xxx_get_bidi_chap(struct scsi_qla_host *ha, char *username, 289528deb45cSLalit Chandivade char *password) 289628deb45cSLalit Chandivade { 289728deb45cSLalit Chandivade int i, ret = -EINVAL; 289828deb45cSLalit Chandivade int max_chap_entries = 0; 289928deb45cSLalit Chandivade struct ql4_chap_table *chap_table; 290028deb45cSLalit Chandivade 290128deb45cSLalit Chandivade if (is_qla8022(ha)) 290228deb45cSLalit Chandivade max_chap_entries = (ha->hw.flt_chap_size / 2) / 290328deb45cSLalit Chandivade sizeof(struct ql4_chap_table); 290428deb45cSLalit Chandivade else 290528deb45cSLalit Chandivade max_chap_entries = MAX_CHAP_ENTRIES_40XX; 290628deb45cSLalit Chandivade 290728deb45cSLalit Chandivade if (!ha->chap_list) { 290828deb45cSLalit Chandivade ql4_printk(KERN_ERR, ha, "Do not have CHAP table cache\n"); 290928deb45cSLalit Chandivade return ret; 291028deb45cSLalit Chandivade } 291128deb45cSLalit Chandivade 291228deb45cSLalit Chandivade mutex_lock(&ha->chap_sem); 291328deb45cSLalit Chandivade for (i = 0; i < max_chap_entries; i++) { 291428deb45cSLalit Chandivade chap_table = (struct ql4_chap_table *)ha->chap_list + i; 291528deb45cSLalit Chandivade if (chap_table->cookie != 291628deb45cSLalit Chandivade __constant_cpu_to_le16(CHAP_VALID_COOKIE)) { 291728deb45cSLalit Chandivade continue; 291828deb45cSLalit Chandivade } 291928deb45cSLalit Chandivade 292028deb45cSLalit Chandivade if (chap_table->flags & BIT_7) /* local */ 292128deb45cSLalit Chandivade continue; 292228deb45cSLalit Chandivade 292328deb45cSLalit Chandivade if (!(chap_table->flags & BIT_6)) /* Not BIDI */ 292428deb45cSLalit Chandivade continue; 292528deb45cSLalit Chandivade 292628deb45cSLalit Chandivade strncpy(password, chap_table->secret, QL4_CHAP_MAX_SECRET_LEN); 292728deb45cSLalit Chandivade strncpy(username, chap_table->name, QL4_CHAP_MAX_NAME_LEN); 292828deb45cSLalit Chandivade ret = 0; 292928deb45cSLalit Chandivade break; 293028deb45cSLalit Chandivade } 293128deb45cSLalit Chandivade mutex_unlock(&ha->chap_sem); 293228deb45cSLalit Chandivade 293328deb45cSLalit Chandivade return ret; 293428deb45cSLalit Chandivade } 293528deb45cSLalit Chandivade 293628deb45cSLalit Chandivade 29372a991c21SManish Rangankar static int qla4xxx_get_boot_target(struct scsi_qla_host *ha, 29382a991c21SManish Rangankar struct ql4_boot_session_info *boot_sess, 29392a991c21SManish Rangankar uint16_t ddb_index) 29402a991c21SManish Rangankar { 29412a991c21SManish Rangankar struct ql4_conn_info *boot_conn = &boot_sess->conn_list[0]; 29422a991c21SManish Rangankar struct dev_db_entry *fw_ddb_entry; 29432a991c21SManish Rangankar dma_addr_t fw_ddb_entry_dma; 29442a991c21SManish Rangankar uint16_t idx; 29452a991c21SManish Rangankar uint16_t options; 29462a991c21SManish Rangankar int ret = QLA_SUCCESS; 29472a991c21SManish Rangankar 29482a991c21SManish Rangankar fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), 29492a991c21SManish Rangankar &fw_ddb_entry_dma, GFP_KERNEL); 29502a991c21SManish Rangankar if (!fw_ddb_entry) { 29512a991c21SManish Rangankar DEBUG2(ql4_printk(KERN_ERR, ha, 29522a991c21SManish Rangankar "%s: Unable to allocate dma buffer.\n", 29532a991c21SManish Rangankar __func__)); 29542a991c21SManish Rangankar ret = QLA_ERROR; 29552a991c21SManish Rangankar return ret; 29562a991c21SManish Rangankar } 29572a991c21SManish Rangankar 29582a991c21SManish Rangankar if (qla4xxx_bootdb_by_index(ha, fw_ddb_entry, 29592a991c21SManish Rangankar fw_ddb_entry_dma, ddb_index)) { 29602a991c21SManish Rangankar DEBUG2(ql4_printk(KERN_ERR, ha, 29612a991c21SManish Rangankar "%s: Flash DDB read Failed\n", __func__)); 29622a991c21SManish Rangankar ret = QLA_ERROR; 29632a991c21SManish Rangankar goto exit_boot_target; 29642a991c21SManish Rangankar } 29652a991c21SManish Rangankar 29662a991c21SManish Rangankar /* Update target name and IP from DDB */ 29672a991c21SManish Rangankar memcpy(boot_sess->target_name, fw_ddb_entry->iscsi_name, 29682a991c21SManish Rangankar min(sizeof(boot_sess->target_name), 29692a991c21SManish Rangankar sizeof(fw_ddb_entry->iscsi_name))); 29702a991c21SManish Rangankar 29712a991c21SManish Rangankar options = le16_to_cpu(fw_ddb_entry->options); 29722a991c21SManish Rangankar if (options & DDB_OPT_IPV6_DEVICE) { 29732a991c21SManish Rangankar memcpy(&boot_conn->dest_ipaddr.ip_address, 29742a991c21SManish Rangankar &fw_ddb_entry->ip_addr[0], IPv6_ADDR_LEN); 29752a991c21SManish Rangankar } else { 29762a991c21SManish Rangankar boot_conn->dest_ipaddr.ip_type = 0x1; 29772a991c21SManish Rangankar memcpy(&boot_conn->dest_ipaddr.ip_address, 29782a991c21SManish Rangankar &fw_ddb_entry->ip_addr[0], IP_ADDR_LEN); 29792a991c21SManish Rangankar } 29802a991c21SManish Rangankar 29812a991c21SManish Rangankar boot_conn->dest_port = le16_to_cpu(fw_ddb_entry->port); 29822a991c21SManish Rangankar 29832a991c21SManish Rangankar /* update chap information */ 29842a991c21SManish Rangankar idx = __le16_to_cpu(fw_ddb_entry->chap_tbl_idx); 29852a991c21SManish Rangankar 29862a991c21SManish Rangankar if (BIT_7 & le16_to_cpu(fw_ddb_entry->iscsi_options)) { 29872a991c21SManish Rangankar 29882a991c21SManish Rangankar DEBUG2(ql4_printk(KERN_INFO, ha, "Setting chap\n")); 29892a991c21SManish Rangankar 29902a991c21SManish Rangankar ret = qla4xxx_get_chap(ha, (char *)&boot_conn->chap. 29912a991c21SManish Rangankar target_chap_name, 29922a991c21SManish Rangankar (char *)&boot_conn->chap.target_secret, 29932a991c21SManish Rangankar idx); 29942a991c21SManish Rangankar if (ret) { 29952a991c21SManish Rangankar ql4_printk(KERN_ERR, ha, "Failed to set chap\n"); 29962a991c21SManish Rangankar ret = QLA_ERROR; 29972a991c21SManish Rangankar goto exit_boot_target; 29982a991c21SManish Rangankar } 29992a991c21SManish Rangankar 30002a991c21SManish Rangankar boot_conn->chap.target_chap_name_length = QL4_CHAP_MAX_NAME_LEN; 30012a991c21SManish Rangankar boot_conn->chap.target_secret_length = QL4_CHAP_MAX_SECRET_LEN; 30022a991c21SManish Rangankar } 30032a991c21SManish Rangankar 30042a991c21SManish Rangankar if (BIT_4 & le16_to_cpu(fw_ddb_entry->iscsi_options)) { 30052a991c21SManish Rangankar 30062a991c21SManish Rangankar DEBUG2(ql4_printk(KERN_INFO, ha, "Setting BIDI chap\n")); 30072a991c21SManish Rangankar 300828deb45cSLalit Chandivade ret = qla4xxx_get_bidi_chap(ha, 300928deb45cSLalit Chandivade (char *)&boot_conn->chap.intr_chap_name, 301028deb45cSLalit Chandivade (char *)&boot_conn->chap.intr_secret); 301128deb45cSLalit Chandivade 30122a991c21SManish Rangankar if (ret) { 30132a991c21SManish Rangankar ql4_printk(KERN_ERR, ha, "Failed to set BIDI chap\n"); 30142a991c21SManish Rangankar ret = QLA_ERROR; 30152a991c21SManish Rangankar goto exit_boot_target; 30162a991c21SManish Rangankar } 30172a991c21SManish Rangankar 30182a991c21SManish Rangankar boot_conn->chap.intr_chap_name_length = QL4_CHAP_MAX_NAME_LEN; 30192a991c21SManish Rangankar boot_conn->chap.intr_secret_length = QL4_CHAP_MAX_SECRET_LEN; 30202a991c21SManish Rangankar } 30212a991c21SManish Rangankar 30222a991c21SManish Rangankar exit_boot_target: 30232a991c21SManish Rangankar dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), 30242a991c21SManish Rangankar fw_ddb_entry, fw_ddb_entry_dma); 30252a991c21SManish Rangankar return ret; 30262a991c21SManish Rangankar } 30272a991c21SManish Rangankar 30282a991c21SManish Rangankar static int qla4xxx_get_boot_info(struct scsi_qla_host *ha) 30292a991c21SManish Rangankar { 30302a991c21SManish Rangankar uint16_t ddb_index[2]; 30318de5b958SLalit Chandivade int ret = QLA_ERROR; 30328de5b958SLalit Chandivade int rval; 30332a991c21SManish Rangankar 30342a991c21SManish Rangankar memset(ddb_index, 0, sizeof(ddb_index)); 30358de5b958SLalit Chandivade ddb_index[0] = 0xffff; 30368de5b958SLalit Chandivade ddb_index[1] = 0xffff; 30372a991c21SManish Rangankar ret = get_fw_boot_info(ha, ddb_index); 30382a991c21SManish Rangankar if (ret != QLA_SUCCESS) { 30392a991c21SManish Rangankar DEBUG2(ql4_printk(KERN_ERR, ha, 30402a991c21SManish Rangankar "%s: Failed to set boot info.\n", __func__)); 30412a991c21SManish Rangankar return ret; 30422a991c21SManish Rangankar } 30432a991c21SManish Rangankar 30448de5b958SLalit Chandivade if (ddb_index[0] == 0xffff) 30458de5b958SLalit Chandivade goto sec_target; 30468de5b958SLalit Chandivade 30478de5b958SLalit Chandivade rval = qla4xxx_get_boot_target(ha, &(ha->boot_tgt.boot_pri_sess), 30482a991c21SManish Rangankar ddb_index[0]); 30498de5b958SLalit Chandivade if (rval != QLA_SUCCESS) { 30502a991c21SManish Rangankar DEBUG2(ql4_printk(KERN_ERR, ha, "%s: Failed to get " 30512a991c21SManish Rangankar "primary target\n", __func__)); 30528de5b958SLalit Chandivade } else 30538de5b958SLalit Chandivade ret = QLA_SUCCESS; 30542a991c21SManish Rangankar 30558de5b958SLalit Chandivade sec_target: 30568de5b958SLalit Chandivade if (ddb_index[1] == 0xffff) 30578de5b958SLalit Chandivade goto exit_get_boot_info; 30588de5b958SLalit Chandivade 30598de5b958SLalit Chandivade rval = qla4xxx_get_boot_target(ha, &(ha->boot_tgt.boot_sec_sess), 30602a991c21SManish Rangankar ddb_index[1]); 30618de5b958SLalit Chandivade if (rval != QLA_SUCCESS) { 30622a991c21SManish Rangankar DEBUG2(ql4_printk(KERN_ERR, ha, "%s: Failed to get " 30632a991c21SManish Rangankar "secondary target\n", __func__)); 30648de5b958SLalit Chandivade } else 30658de5b958SLalit Chandivade ret = QLA_SUCCESS; 30668de5b958SLalit Chandivade 30678de5b958SLalit Chandivade exit_get_boot_info: 30682a991c21SManish Rangankar return ret; 30692a991c21SManish Rangankar } 30702a991c21SManish Rangankar 30712a991c21SManish Rangankar static int qla4xxx_setup_boot_info(struct scsi_qla_host *ha) 30722a991c21SManish Rangankar { 30732a991c21SManish Rangankar struct iscsi_boot_kobj *boot_kobj; 30742a991c21SManish Rangankar 30752a991c21SManish Rangankar if (qla4xxx_get_boot_info(ha) != QLA_SUCCESS) 30762a991c21SManish Rangankar return 0; 30772a991c21SManish Rangankar 30782a991c21SManish Rangankar ha->boot_kset = iscsi_boot_create_host_kset(ha->host->host_no); 30792a991c21SManish Rangankar if (!ha->boot_kset) 30802a991c21SManish Rangankar goto kset_free; 30812a991c21SManish Rangankar 30822a991c21SManish Rangankar if (!scsi_host_get(ha->host)) 30832a991c21SManish Rangankar goto kset_free; 30842a991c21SManish Rangankar boot_kobj = iscsi_boot_create_target(ha->boot_kset, 0, ha, 30852a991c21SManish Rangankar qla4xxx_show_boot_tgt_pri_info, 30862a991c21SManish Rangankar qla4xxx_tgt_get_attr_visibility, 30872a991c21SManish Rangankar qla4xxx_boot_release); 30882a991c21SManish Rangankar if (!boot_kobj) 30892a991c21SManish Rangankar goto put_host; 30902a991c21SManish Rangankar 30912a991c21SManish Rangankar if (!scsi_host_get(ha->host)) 30922a991c21SManish Rangankar goto kset_free; 30932a991c21SManish Rangankar boot_kobj = iscsi_boot_create_target(ha->boot_kset, 1, ha, 30942a991c21SManish Rangankar qla4xxx_show_boot_tgt_sec_info, 30952a991c21SManish Rangankar qla4xxx_tgt_get_attr_visibility, 30962a991c21SManish Rangankar qla4xxx_boot_release); 30972a991c21SManish Rangankar if (!boot_kobj) 30982a991c21SManish Rangankar goto put_host; 30992a991c21SManish Rangankar 31002a991c21SManish Rangankar if (!scsi_host_get(ha->host)) 31012a991c21SManish Rangankar goto kset_free; 31022a991c21SManish Rangankar boot_kobj = iscsi_boot_create_initiator(ha->boot_kset, 0, ha, 31032a991c21SManish Rangankar qla4xxx_show_boot_ini_info, 31042a991c21SManish Rangankar qla4xxx_ini_get_attr_visibility, 31052a991c21SManish Rangankar qla4xxx_boot_release); 31062a991c21SManish Rangankar if (!boot_kobj) 31072a991c21SManish Rangankar goto put_host; 31082a991c21SManish Rangankar 31092a991c21SManish Rangankar if (!scsi_host_get(ha->host)) 31102a991c21SManish Rangankar goto kset_free; 31112a991c21SManish Rangankar boot_kobj = iscsi_boot_create_ethernet(ha->boot_kset, 0, ha, 31122a991c21SManish Rangankar qla4xxx_show_boot_eth_info, 31132a991c21SManish Rangankar qla4xxx_eth_get_attr_visibility, 31142a991c21SManish Rangankar qla4xxx_boot_release); 31152a991c21SManish Rangankar if (!boot_kobj) 31162a991c21SManish Rangankar goto put_host; 31172a991c21SManish Rangankar 31182a991c21SManish Rangankar return 0; 31192a991c21SManish Rangankar 31202a991c21SManish Rangankar put_host: 31212a991c21SManish Rangankar scsi_host_put(ha->host); 31222a991c21SManish Rangankar kset_free: 31232a991c21SManish Rangankar iscsi_boot_destroy_kset(ha->boot_kset); 31242a991c21SManish Rangankar return -ENOMEM; 31252a991c21SManish Rangankar } 31262a991c21SManish Rangankar 31274549415aSLalit Chandivade 31284549415aSLalit Chandivade /** 31294549415aSLalit Chandivade * qla4xxx_create chap_list - Create CHAP list from FLASH 31304549415aSLalit Chandivade * @ha: pointer to adapter structure 31314549415aSLalit Chandivade * 31324549415aSLalit Chandivade * Read flash and make a list of CHAP entries, during login when a CHAP entry 31334549415aSLalit Chandivade * is received, it will be checked in this list. If entry exist then the CHAP 31344549415aSLalit Chandivade * entry index is set in the DDB. If CHAP entry does not exist in this list 31354549415aSLalit Chandivade * then a new entry is added in FLASH in CHAP table and the index obtained is 31364549415aSLalit Chandivade * used in the DDB. 31374549415aSLalit Chandivade **/ 31384549415aSLalit Chandivade static void qla4xxx_create_chap_list(struct scsi_qla_host *ha) 31394549415aSLalit Chandivade { 31404549415aSLalit Chandivade int rval = 0; 31414549415aSLalit Chandivade uint8_t *chap_flash_data = NULL; 31424549415aSLalit Chandivade uint32_t offset; 31434549415aSLalit Chandivade dma_addr_t chap_dma; 31444549415aSLalit Chandivade uint32_t chap_size = 0; 31454549415aSLalit Chandivade 31464549415aSLalit Chandivade if (is_qla40XX(ha)) 31474549415aSLalit Chandivade chap_size = MAX_CHAP_ENTRIES_40XX * 31484549415aSLalit Chandivade sizeof(struct ql4_chap_table); 31494549415aSLalit Chandivade else /* Single region contains CHAP info for both 31504549415aSLalit Chandivade * ports which is divided into half for each port. 31514549415aSLalit Chandivade */ 31524549415aSLalit Chandivade chap_size = ha->hw.flt_chap_size / 2; 31534549415aSLalit Chandivade 31544549415aSLalit Chandivade chap_flash_data = dma_alloc_coherent(&ha->pdev->dev, chap_size, 31554549415aSLalit Chandivade &chap_dma, GFP_KERNEL); 31564549415aSLalit Chandivade if (!chap_flash_data) { 31574549415aSLalit Chandivade ql4_printk(KERN_ERR, ha, "No memory for chap_flash_data\n"); 31584549415aSLalit Chandivade return; 31594549415aSLalit Chandivade } 31604549415aSLalit Chandivade if (is_qla40XX(ha)) 31614549415aSLalit Chandivade offset = FLASH_CHAP_OFFSET; 31624549415aSLalit Chandivade else { 31634549415aSLalit Chandivade offset = FLASH_RAW_ACCESS_ADDR + (ha->hw.flt_region_chap << 2); 31644549415aSLalit Chandivade if (ha->port_num == 1) 31654549415aSLalit Chandivade offset += chap_size; 31664549415aSLalit Chandivade } 31674549415aSLalit Chandivade 31684549415aSLalit Chandivade rval = qla4xxx_get_flash(ha, chap_dma, offset, chap_size); 31694549415aSLalit Chandivade if (rval != QLA_SUCCESS) 31704549415aSLalit Chandivade goto exit_chap_list; 31714549415aSLalit Chandivade 31724549415aSLalit Chandivade if (ha->chap_list == NULL) 31734549415aSLalit Chandivade ha->chap_list = vmalloc(chap_size); 31744549415aSLalit Chandivade if (ha->chap_list == NULL) { 31754549415aSLalit Chandivade ql4_printk(KERN_ERR, ha, "No memory for ha->chap_list\n"); 31764549415aSLalit Chandivade goto exit_chap_list; 31774549415aSLalit Chandivade } 31784549415aSLalit Chandivade 31794549415aSLalit Chandivade memcpy(ha->chap_list, chap_flash_data, chap_size); 31804549415aSLalit Chandivade 31814549415aSLalit Chandivade exit_chap_list: 31824549415aSLalit Chandivade dma_free_coherent(&ha->pdev->dev, chap_size, 31834549415aSLalit Chandivade chap_flash_data, chap_dma); 31844549415aSLalit Chandivade return; 31854549415aSLalit Chandivade } 31864549415aSLalit Chandivade 3187afaf5a2dSDavid Somayajulu /** 3188afaf5a2dSDavid Somayajulu * qla4xxx_probe_adapter - callback function to probe HBA 3189afaf5a2dSDavid Somayajulu * @pdev: pointer to pci_dev structure 3190afaf5a2dSDavid Somayajulu * @pci_device_id: pointer to pci_device entry 3191afaf5a2dSDavid Somayajulu * 3192afaf5a2dSDavid Somayajulu * This routine will probe for Qlogic 4xxx iSCSI host adapters. 3193afaf5a2dSDavid Somayajulu * It returns zero if successful. It also initializes all data necessary for 3194afaf5a2dSDavid Somayajulu * the driver. 3195afaf5a2dSDavid Somayajulu **/ 3196afaf5a2dSDavid Somayajulu static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, 3197afaf5a2dSDavid Somayajulu const struct pci_device_id *ent) 3198afaf5a2dSDavid Somayajulu { 3199afaf5a2dSDavid Somayajulu int ret = -ENODEV, status; 3200afaf5a2dSDavid Somayajulu struct Scsi_Host *host; 3201afaf5a2dSDavid Somayajulu struct scsi_qla_host *ha; 3202afaf5a2dSDavid Somayajulu uint8_t init_retry_count = 0; 3203afaf5a2dSDavid Somayajulu char buf[34]; 3204f4f5df23SVikas Chaudhary struct qla4_8xxx_legacy_intr_set *nx_legacy_intr; 3205f9880e76SPrasanna Mumbai uint32_t dev_state; 3206afaf5a2dSDavid Somayajulu 3207afaf5a2dSDavid Somayajulu if (pci_enable_device(pdev)) 3208afaf5a2dSDavid Somayajulu return -1; 3209afaf5a2dSDavid Somayajulu 3210b3a271a9SManish Rangankar host = iscsi_host_alloc(&qla4xxx_driver_template, sizeof(*ha), 0); 3211afaf5a2dSDavid Somayajulu if (host == NULL) { 3212afaf5a2dSDavid Somayajulu printk(KERN_WARNING 3213afaf5a2dSDavid Somayajulu "qla4xxx: Couldn't allocate host from scsi layer!\n"); 3214afaf5a2dSDavid Somayajulu goto probe_disable_device; 3215afaf5a2dSDavid Somayajulu } 3216afaf5a2dSDavid Somayajulu 3217afaf5a2dSDavid Somayajulu /* Clear our data area */ 3218b3a271a9SManish Rangankar ha = to_qla_host(host); 3219afaf5a2dSDavid Somayajulu memset(ha, 0, sizeof(*ha)); 3220afaf5a2dSDavid Somayajulu 3221afaf5a2dSDavid Somayajulu /* Save the information from PCI BIOS. */ 3222afaf5a2dSDavid Somayajulu ha->pdev = pdev; 3223afaf5a2dSDavid Somayajulu ha->host = host; 3224afaf5a2dSDavid Somayajulu ha->host_no = host->host_no; 3225afaf5a2dSDavid Somayajulu 32262232be0dSLalit Chandivade pci_enable_pcie_error_reporting(pdev); 32272232be0dSLalit Chandivade 3228f4f5df23SVikas Chaudhary /* Setup Runtime configurable options */ 3229f4f5df23SVikas Chaudhary if (is_qla8022(ha)) { 3230f4f5df23SVikas Chaudhary ha->isp_ops = &qla4_8xxx_isp_ops; 3231f4f5df23SVikas Chaudhary rwlock_init(&ha->hw_lock); 3232f4f5df23SVikas Chaudhary ha->qdr_sn_window = -1; 3233f4f5df23SVikas Chaudhary ha->ddr_mn_window = -1; 3234f4f5df23SVikas Chaudhary ha->curr_window = 255; 3235f4f5df23SVikas Chaudhary ha->func_num = PCI_FUNC(ha->pdev->devfn); 3236f4f5df23SVikas Chaudhary nx_legacy_intr = &legacy_intr[ha->func_num]; 3237f4f5df23SVikas Chaudhary ha->nx_legacy_intr.int_vec_bit = nx_legacy_intr->int_vec_bit; 3238f4f5df23SVikas Chaudhary ha->nx_legacy_intr.tgt_status_reg = 3239f4f5df23SVikas Chaudhary nx_legacy_intr->tgt_status_reg; 3240f4f5df23SVikas Chaudhary ha->nx_legacy_intr.tgt_mask_reg = nx_legacy_intr->tgt_mask_reg; 3241f4f5df23SVikas Chaudhary ha->nx_legacy_intr.pci_int_reg = nx_legacy_intr->pci_int_reg; 3242f4f5df23SVikas Chaudhary } else { 3243f4f5df23SVikas Chaudhary ha->isp_ops = &qla4xxx_isp_ops; 3244f4f5df23SVikas Chaudhary } 3245f4f5df23SVikas Chaudhary 32462232be0dSLalit Chandivade /* Set EEH reset type to fundamental if required by hba */ 32472232be0dSLalit Chandivade if (is_qla8022(ha)) 32482232be0dSLalit Chandivade pdev->needs_freset = 1; 32492232be0dSLalit Chandivade 3250afaf5a2dSDavid Somayajulu /* Configure PCI I/O space. */ 3251f4f5df23SVikas Chaudhary ret = ha->isp_ops->iospace_config(ha); 3252afaf5a2dSDavid Somayajulu if (ret) 3253f4f5df23SVikas Chaudhary goto probe_failed_ioconfig; 3254afaf5a2dSDavid Somayajulu 3255c2660df3SVikas Chaudhary ql4_printk(KERN_INFO, ha, "Found an ISP%04x, irq %d, iobase 0x%p\n", 3256afaf5a2dSDavid Somayajulu pdev->device, pdev->irq, ha->reg); 3257afaf5a2dSDavid Somayajulu 3258afaf5a2dSDavid Somayajulu qla4xxx_config_dma_addressing(ha); 3259afaf5a2dSDavid Somayajulu 3260afaf5a2dSDavid Somayajulu /* Initialize lists and spinlocks. */ 3261afaf5a2dSDavid Somayajulu INIT_LIST_HEAD(&ha->free_srb_q); 3262afaf5a2dSDavid Somayajulu 3263afaf5a2dSDavid Somayajulu mutex_init(&ha->mbox_sem); 32644549415aSLalit Chandivade mutex_init(&ha->chap_sem); 3265f4f5df23SVikas Chaudhary init_completion(&ha->mbx_intr_comp); 326695d31262SVikas Chaudhary init_completion(&ha->disable_acb_comp); 3267afaf5a2dSDavid Somayajulu 3268afaf5a2dSDavid Somayajulu spin_lock_init(&ha->hardware_lock); 3269afaf5a2dSDavid Somayajulu 3270afaf5a2dSDavid Somayajulu /* Allocate dma buffers */ 3271afaf5a2dSDavid Somayajulu if (qla4xxx_mem_alloc(ha)) { 3272c2660df3SVikas Chaudhary ql4_printk(KERN_WARNING, ha, 3273afaf5a2dSDavid Somayajulu "[ERROR] Failed to allocate memory for adapter\n"); 3274afaf5a2dSDavid Somayajulu 3275afaf5a2dSDavid Somayajulu ret = -ENOMEM; 3276afaf5a2dSDavid Somayajulu goto probe_failed; 3277afaf5a2dSDavid Somayajulu } 3278afaf5a2dSDavid Somayajulu 3279b3a271a9SManish Rangankar host->cmd_per_lun = 3; 3280b3a271a9SManish Rangankar host->max_channel = 0; 3281b3a271a9SManish Rangankar host->max_lun = MAX_LUNS - 1; 3282b3a271a9SManish Rangankar host->max_id = MAX_TARGETS; 3283b3a271a9SManish Rangankar host->max_cmd_len = IOCB_MAX_CDB_LEN; 3284b3a271a9SManish Rangankar host->can_queue = MAX_SRBS ; 3285b3a271a9SManish Rangankar host->transportt = qla4xxx_scsi_transport; 3286b3a271a9SManish Rangankar 3287b3a271a9SManish Rangankar ret = scsi_init_shared_tag_map(host, MAX_SRBS); 3288b3a271a9SManish Rangankar if (ret) { 3289b3a271a9SManish Rangankar ql4_printk(KERN_WARNING, ha, 3290b3a271a9SManish Rangankar "%s: scsi_init_shared_tag_map failed\n", __func__); 3291b3a271a9SManish Rangankar goto probe_failed; 3292b3a271a9SManish Rangankar } 3293b3a271a9SManish Rangankar 3294b3a271a9SManish Rangankar pci_set_drvdata(pdev, ha); 3295b3a271a9SManish Rangankar 3296b3a271a9SManish Rangankar ret = scsi_add_host(host, &pdev->dev); 3297b3a271a9SManish Rangankar if (ret) 3298b3a271a9SManish Rangankar goto probe_failed; 3299b3a271a9SManish Rangankar 3300f4f5df23SVikas Chaudhary if (is_qla8022(ha)) 3301f4f5df23SVikas Chaudhary (void) qla4_8xxx_get_flash_info(ha); 3302f4f5df23SVikas Chaudhary 3303afaf5a2dSDavid Somayajulu /* 3304afaf5a2dSDavid Somayajulu * Initialize the Host adapter request/response queues and 3305afaf5a2dSDavid Somayajulu * firmware 3306afaf5a2dSDavid Somayajulu * NOTE: interrupts enabled upon successful completion 3307afaf5a2dSDavid Somayajulu */ 33080e7e8501SManish Rangankar status = qla4xxx_initialize_adapter(ha); 3309f4f5df23SVikas Chaudhary while ((!test_bit(AF_ONLINE, &ha->flags)) && 3310f4f5df23SVikas Chaudhary init_retry_count++ < MAX_INIT_RETRIES) { 3311f9880e76SPrasanna Mumbai 3312f9880e76SPrasanna Mumbai if (is_qla8022(ha)) { 3313f9880e76SPrasanna Mumbai qla4_8xxx_idc_lock(ha); 3314f9880e76SPrasanna Mumbai dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE); 3315f9880e76SPrasanna Mumbai qla4_8xxx_idc_unlock(ha); 3316f9880e76SPrasanna Mumbai if (dev_state == QLA82XX_DEV_FAILED) { 3317f9880e76SPrasanna Mumbai ql4_printk(KERN_WARNING, ha, "%s: don't retry " 3318f9880e76SPrasanna Mumbai "initialize adapter. H/W is in failed state\n", 3319f9880e76SPrasanna Mumbai __func__); 3320f9880e76SPrasanna Mumbai break; 3321f9880e76SPrasanna Mumbai } 3322f9880e76SPrasanna Mumbai } 3323afaf5a2dSDavid Somayajulu DEBUG2(printk("scsi: %s: retrying adapter initialization " 3324afaf5a2dSDavid Somayajulu "(%d)\n", __func__, init_retry_count)); 3325f4f5df23SVikas Chaudhary 3326f4f5df23SVikas Chaudhary if (ha->isp_ops->reset_chip(ha) == QLA_ERROR) 3327f4f5df23SVikas Chaudhary continue; 3328f4f5df23SVikas Chaudhary 33290e7e8501SManish Rangankar status = qla4xxx_initialize_adapter(ha); 3330afaf5a2dSDavid Somayajulu } 3331f4f5df23SVikas Chaudhary 3332f4f5df23SVikas Chaudhary if (!test_bit(AF_ONLINE, &ha->flags)) { 3333c2660df3SVikas Chaudhary ql4_printk(KERN_WARNING, ha, "Failed to initialize adapter\n"); 3334afaf5a2dSDavid Somayajulu 3335fe998527SLalit Chandivade if (is_qla8022(ha) && ql4xdontresethba) { 3336fe998527SLalit Chandivade /* Put the device in failed state. */ 3337fe998527SLalit Chandivade DEBUG2(printk(KERN_ERR "HW STATE: FAILED\n")); 3338fe998527SLalit Chandivade qla4_8xxx_idc_lock(ha); 3339fe998527SLalit Chandivade qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, 3340fe998527SLalit Chandivade QLA82XX_DEV_FAILED); 3341fe998527SLalit Chandivade qla4_8xxx_idc_unlock(ha); 3342fe998527SLalit Chandivade } 3343afaf5a2dSDavid Somayajulu ret = -ENODEV; 3344b3a271a9SManish Rangankar goto remove_host; 3345afaf5a2dSDavid Somayajulu } 3346afaf5a2dSDavid Somayajulu 3347afaf5a2dSDavid Somayajulu /* Startup the kernel thread for this host adapter. */ 3348afaf5a2dSDavid Somayajulu DEBUG2(printk("scsi: %s: Starting kernel thread for " 3349afaf5a2dSDavid Somayajulu "qla4xxx_dpc\n", __func__)); 3350afaf5a2dSDavid Somayajulu sprintf(buf, "qla4xxx_%lu_dpc", ha->host_no); 3351afaf5a2dSDavid Somayajulu ha->dpc_thread = create_singlethread_workqueue(buf); 3352afaf5a2dSDavid Somayajulu if (!ha->dpc_thread) { 3353c2660df3SVikas Chaudhary ql4_printk(KERN_WARNING, ha, "Unable to start DPC thread!\n"); 3354afaf5a2dSDavid Somayajulu ret = -ENODEV; 3355b3a271a9SManish Rangankar goto remove_host; 3356afaf5a2dSDavid Somayajulu } 3357c4028958SDavid Howells INIT_WORK(&ha->dpc_work, qla4xxx_do_dpc); 3358afaf5a2dSDavid Somayajulu 3359b3a271a9SManish Rangankar sprintf(buf, "qla4xxx_%lu_task", ha->host_no); 3360b3a271a9SManish Rangankar ha->task_wq = alloc_workqueue(buf, WQ_MEM_RECLAIM, 1); 3361b3a271a9SManish Rangankar if (!ha->task_wq) { 3362b3a271a9SManish Rangankar ql4_printk(KERN_WARNING, ha, "Unable to start task thread!\n"); 3363b3a271a9SManish Rangankar ret = -ENODEV; 3364b3a271a9SManish Rangankar goto remove_host; 3365b3a271a9SManish Rangankar } 3366b3a271a9SManish Rangankar 3367f4f5df23SVikas Chaudhary /* For ISP-82XX, request_irqs is called in qla4_8xxx_load_risc 3368f4f5df23SVikas Chaudhary * (which is called indirectly by qla4xxx_initialize_adapter), 3369f4f5df23SVikas Chaudhary * so that irqs will be registered after crbinit but before 3370f4f5df23SVikas Chaudhary * mbx_intr_enable. 3371f4f5df23SVikas Chaudhary */ 3372f4f5df23SVikas Chaudhary if (!is_qla8022(ha)) { 3373f4f5df23SVikas Chaudhary ret = qla4xxx_request_irqs(ha); 3374afaf5a2dSDavid Somayajulu if (ret) { 3375f4f5df23SVikas Chaudhary ql4_printk(KERN_WARNING, ha, "Failed to reserve " 3376f4f5df23SVikas Chaudhary "interrupt %d already in use.\n", pdev->irq); 3377b3a271a9SManish Rangankar goto remove_host; 3378afaf5a2dSDavid Somayajulu } 3379f4f5df23SVikas Chaudhary } 3380afaf5a2dSDavid Somayajulu 33812232be0dSLalit Chandivade pci_save_state(ha->pdev); 3382f4f5df23SVikas Chaudhary ha->isp_ops->enable_intrs(ha); 3383afaf5a2dSDavid Somayajulu 3384afaf5a2dSDavid Somayajulu /* Start timer thread. */ 3385afaf5a2dSDavid Somayajulu qla4xxx_start_timer(ha, qla4xxx_timer, 1); 3386afaf5a2dSDavid Somayajulu 3387afaf5a2dSDavid Somayajulu set_bit(AF_INIT_DONE, &ha->flags); 3388afaf5a2dSDavid Somayajulu 3389afaf5a2dSDavid Somayajulu printk(KERN_INFO 3390afaf5a2dSDavid Somayajulu " QLogic iSCSI HBA Driver version: %s\n" 3391afaf5a2dSDavid Somayajulu " QLogic ISP%04x @ %s, host#=%ld, fw=%02d.%02d.%02d.%02d\n", 3392afaf5a2dSDavid Somayajulu qla4xxx_version_str, ha->pdev->device, pci_name(ha->pdev), 3393afaf5a2dSDavid Somayajulu ha->host_no, ha->firmware_version[0], ha->firmware_version[1], 3394afaf5a2dSDavid Somayajulu ha->patch_number, ha->build_number); 3395ed1086e0SVikas Chaudhary 33964549415aSLalit Chandivade qla4xxx_create_chap_list(ha); 33974549415aSLalit Chandivade 33982a991c21SManish Rangankar if (qla4xxx_setup_boot_info(ha)) 33992a991c21SManish Rangankar ql4_printk(KERN_ERR, ha, "%s:ISCSI boot info setup failed\n", 34002a991c21SManish Rangankar __func__); 34012a991c21SManish Rangankar 3402ed1086e0SVikas Chaudhary qla4xxx_create_ifaces(ha); 3403afaf5a2dSDavid Somayajulu return 0; 3404afaf5a2dSDavid Somayajulu 3405b3a271a9SManish Rangankar remove_host: 3406b3a271a9SManish Rangankar scsi_remove_host(ha->host); 3407b3a271a9SManish Rangankar 3408afaf5a2dSDavid Somayajulu probe_failed: 3409afaf5a2dSDavid Somayajulu qla4xxx_free_adapter(ha); 3410f4f5df23SVikas Chaudhary 3411f4f5df23SVikas Chaudhary probe_failed_ioconfig: 34122232be0dSLalit Chandivade pci_disable_pcie_error_reporting(pdev); 3413afaf5a2dSDavid Somayajulu scsi_host_put(ha->host); 3414afaf5a2dSDavid Somayajulu 3415afaf5a2dSDavid Somayajulu probe_disable_device: 3416afaf5a2dSDavid Somayajulu pci_disable_device(pdev); 3417afaf5a2dSDavid Somayajulu 3418afaf5a2dSDavid Somayajulu return ret; 3419afaf5a2dSDavid Somayajulu } 3420afaf5a2dSDavid Somayajulu 3421afaf5a2dSDavid Somayajulu /** 34227eece5a0SKaren Higgins * qla4xxx_prevent_other_port_reinit - prevent other port from re-initialize 34237eece5a0SKaren Higgins * @ha: pointer to adapter structure 34247eece5a0SKaren Higgins * 34257eece5a0SKaren Higgins * Mark the other ISP-4xxx port to indicate that the driver is being removed, 34267eece5a0SKaren Higgins * so that the other port will not re-initialize while in the process of 34277eece5a0SKaren Higgins * removing the ha due to driver unload or hba hotplug. 34287eece5a0SKaren Higgins **/ 34297eece5a0SKaren Higgins static void qla4xxx_prevent_other_port_reinit(struct scsi_qla_host *ha) 34307eece5a0SKaren Higgins { 34317eece5a0SKaren Higgins struct scsi_qla_host *other_ha = NULL; 34327eece5a0SKaren Higgins struct pci_dev *other_pdev = NULL; 34337eece5a0SKaren Higgins int fn = ISP4XXX_PCI_FN_2; 34347eece5a0SKaren Higgins 34357eece5a0SKaren Higgins /*iscsi function numbers for ISP4xxx is 1 and 3*/ 34367eece5a0SKaren Higgins if (PCI_FUNC(ha->pdev->devfn) & BIT_1) 34377eece5a0SKaren Higgins fn = ISP4XXX_PCI_FN_1; 34387eece5a0SKaren Higgins 34397eece5a0SKaren Higgins other_pdev = 34407eece5a0SKaren Higgins pci_get_domain_bus_and_slot(pci_domain_nr(ha->pdev->bus), 34417eece5a0SKaren Higgins ha->pdev->bus->number, PCI_DEVFN(PCI_SLOT(ha->pdev->devfn), 34427eece5a0SKaren Higgins fn)); 34437eece5a0SKaren Higgins 34447eece5a0SKaren Higgins /* Get other_ha if other_pdev is valid and state is enable*/ 34457eece5a0SKaren Higgins if (other_pdev) { 34467eece5a0SKaren Higgins if (atomic_read(&other_pdev->enable_cnt)) { 34477eece5a0SKaren Higgins other_ha = pci_get_drvdata(other_pdev); 34487eece5a0SKaren Higgins if (other_ha) { 34497eece5a0SKaren Higgins set_bit(AF_HA_REMOVAL, &other_ha->flags); 34507eece5a0SKaren Higgins DEBUG2(ql4_printk(KERN_INFO, ha, "%s: " 34517eece5a0SKaren Higgins "Prevent %s reinit\n", __func__, 34527eece5a0SKaren Higgins dev_name(&other_ha->pdev->dev))); 34537eece5a0SKaren Higgins } 34547eece5a0SKaren Higgins } 34557eece5a0SKaren Higgins pci_dev_put(other_pdev); 34567eece5a0SKaren Higgins } 34577eece5a0SKaren Higgins } 34587eece5a0SKaren Higgins 34597eece5a0SKaren Higgins /** 3460afaf5a2dSDavid Somayajulu * qla4xxx_remove_adapter - calback function to remove adapter. 3461afaf5a2dSDavid Somayajulu * @pci_dev: PCI device pointer 3462afaf5a2dSDavid Somayajulu **/ 3463afaf5a2dSDavid Somayajulu static void __devexit qla4xxx_remove_adapter(struct pci_dev *pdev) 3464afaf5a2dSDavid Somayajulu { 3465afaf5a2dSDavid Somayajulu struct scsi_qla_host *ha; 3466afaf5a2dSDavid Somayajulu 3467afaf5a2dSDavid Somayajulu ha = pci_get_drvdata(pdev); 3468afaf5a2dSDavid Somayajulu 34697eece5a0SKaren Higgins if (!is_qla8022(ha)) 34707eece5a0SKaren Higgins qla4xxx_prevent_other_port_reinit(ha); 3471bee4fe8eSDavid C Somayajulu 3472ed1086e0SVikas Chaudhary /* destroy iface from sysfs */ 3473ed1086e0SVikas Chaudhary qla4xxx_destroy_ifaces(ha); 3474ed1086e0SVikas Chaudhary 34752a991c21SManish Rangankar if (ha->boot_kset) 34762a991c21SManish Rangankar iscsi_boot_destroy_kset(ha->boot_kset); 34772a991c21SManish Rangankar 3478afaf5a2dSDavid Somayajulu scsi_remove_host(ha->host); 3479afaf5a2dSDavid Somayajulu 3480afaf5a2dSDavid Somayajulu qla4xxx_free_adapter(ha); 3481afaf5a2dSDavid Somayajulu 3482afaf5a2dSDavid Somayajulu scsi_host_put(ha->host); 3483afaf5a2dSDavid Somayajulu 34842232be0dSLalit Chandivade pci_disable_pcie_error_reporting(pdev); 3485f4f5df23SVikas Chaudhary pci_disable_device(pdev); 3486afaf5a2dSDavid Somayajulu pci_set_drvdata(pdev, NULL); 3487afaf5a2dSDavid Somayajulu } 3488afaf5a2dSDavid Somayajulu 3489afaf5a2dSDavid Somayajulu /** 3490afaf5a2dSDavid Somayajulu * qla4xxx_config_dma_addressing() - Configure OS DMA addressing method. 3491afaf5a2dSDavid Somayajulu * @ha: HA context 3492afaf5a2dSDavid Somayajulu * 3493afaf5a2dSDavid Somayajulu * At exit, the @ha's flags.enable_64bit_addressing set to indicated 3494afaf5a2dSDavid Somayajulu * supported addressing method. 3495afaf5a2dSDavid Somayajulu */ 349647975477SAdrian Bunk static void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha) 3497afaf5a2dSDavid Somayajulu { 3498afaf5a2dSDavid Somayajulu int retval; 3499afaf5a2dSDavid Somayajulu 3500afaf5a2dSDavid Somayajulu /* Update our PCI device dma_mask for full 64 bit mask */ 35016a35528aSYang Hongyang if (pci_set_dma_mask(ha->pdev, DMA_BIT_MASK(64)) == 0) { 35026a35528aSYang Hongyang if (pci_set_consistent_dma_mask(ha->pdev, DMA_BIT_MASK(64))) { 3503afaf5a2dSDavid Somayajulu dev_dbg(&ha->pdev->dev, 3504afaf5a2dSDavid Somayajulu "Failed to set 64 bit PCI consistent mask; " 3505afaf5a2dSDavid Somayajulu "using 32 bit.\n"); 3506afaf5a2dSDavid Somayajulu retval = pci_set_consistent_dma_mask(ha->pdev, 3507284901a9SYang Hongyang DMA_BIT_MASK(32)); 3508afaf5a2dSDavid Somayajulu } 3509afaf5a2dSDavid Somayajulu } else 3510284901a9SYang Hongyang retval = pci_set_dma_mask(ha->pdev, DMA_BIT_MASK(32)); 3511afaf5a2dSDavid Somayajulu } 3512afaf5a2dSDavid Somayajulu 3513afaf5a2dSDavid Somayajulu static int qla4xxx_slave_alloc(struct scsi_device *sdev) 3514afaf5a2dSDavid Somayajulu { 3515b3a271a9SManish Rangankar struct iscsi_cls_session *cls_sess; 3516b3a271a9SManish Rangankar struct iscsi_session *sess; 3517b3a271a9SManish Rangankar struct ddb_entry *ddb; 35188bb4033dSVikas Chaudhary int queue_depth = QL4_DEF_QDEPTH; 3519afaf5a2dSDavid Somayajulu 3520b3a271a9SManish Rangankar cls_sess = starget_to_session(sdev->sdev_target); 3521b3a271a9SManish Rangankar sess = cls_sess->dd_data; 3522b3a271a9SManish Rangankar ddb = sess->dd_data; 3523b3a271a9SManish Rangankar 3524afaf5a2dSDavid Somayajulu sdev->hostdata = ddb; 3525afaf5a2dSDavid Somayajulu sdev->tagged_supported = 1; 35268bb4033dSVikas Chaudhary 35278bb4033dSVikas Chaudhary if (ql4xmaxqdepth != 0 && ql4xmaxqdepth <= 0xffffU) 35288bb4033dSVikas Chaudhary queue_depth = ql4xmaxqdepth; 35298bb4033dSVikas Chaudhary 35308bb4033dSVikas Chaudhary scsi_activate_tcq(sdev, queue_depth); 3531afaf5a2dSDavid Somayajulu return 0; 3532afaf5a2dSDavid Somayajulu } 3533afaf5a2dSDavid Somayajulu 3534afaf5a2dSDavid Somayajulu static int qla4xxx_slave_configure(struct scsi_device *sdev) 3535afaf5a2dSDavid Somayajulu { 3536afaf5a2dSDavid Somayajulu sdev->tagged_supported = 1; 3537afaf5a2dSDavid Somayajulu return 0; 3538afaf5a2dSDavid Somayajulu } 3539afaf5a2dSDavid Somayajulu 3540afaf5a2dSDavid Somayajulu static void qla4xxx_slave_destroy(struct scsi_device *sdev) 3541afaf5a2dSDavid Somayajulu { 3542afaf5a2dSDavid Somayajulu scsi_deactivate_tcq(sdev, 1); 3543afaf5a2dSDavid Somayajulu } 3544afaf5a2dSDavid Somayajulu 3545afaf5a2dSDavid Somayajulu /** 3546afaf5a2dSDavid Somayajulu * qla4xxx_del_from_active_array - returns an active srb 3547afaf5a2dSDavid Somayajulu * @ha: Pointer to host adapter structure. 3548fd589a8fSAnand Gadiyar * @index: index into the active_array 3549afaf5a2dSDavid Somayajulu * 3550afaf5a2dSDavid Somayajulu * This routine removes and returns the srb at the specified index 3551afaf5a2dSDavid Somayajulu **/ 3552f4f5df23SVikas Chaudhary struct srb *qla4xxx_del_from_active_array(struct scsi_qla_host *ha, 3553f4f5df23SVikas Chaudhary uint32_t index) 3554afaf5a2dSDavid Somayajulu { 3555afaf5a2dSDavid Somayajulu struct srb *srb = NULL; 35565369887aSVikas Chaudhary struct scsi_cmnd *cmd = NULL; 3557afaf5a2dSDavid Somayajulu 35585369887aSVikas Chaudhary cmd = scsi_host_find_tag(ha->host, index); 35595369887aSVikas Chaudhary if (!cmd) 3560afaf5a2dSDavid Somayajulu return srb; 3561afaf5a2dSDavid Somayajulu 35625369887aSVikas Chaudhary srb = (struct srb *)CMD_SP(cmd); 35635369887aSVikas Chaudhary if (!srb) 3564afaf5a2dSDavid Somayajulu return srb; 3565afaf5a2dSDavid Somayajulu 3566afaf5a2dSDavid Somayajulu /* update counters */ 3567afaf5a2dSDavid Somayajulu if (srb->flags & SRB_DMA_VALID) { 3568afaf5a2dSDavid Somayajulu ha->req_q_count += srb->iocb_cnt; 3569afaf5a2dSDavid Somayajulu ha->iocb_cnt -= srb->iocb_cnt; 3570afaf5a2dSDavid Somayajulu if (srb->cmd) 35715369887aSVikas Chaudhary srb->cmd->host_scribble = 35725369887aSVikas Chaudhary (unsigned char *)(unsigned long) MAX_SRBS; 3573afaf5a2dSDavid Somayajulu } 3574afaf5a2dSDavid Somayajulu return srb; 3575afaf5a2dSDavid Somayajulu } 3576afaf5a2dSDavid Somayajulu 3577afaf5a2dSDavid Somayajulu /** 3578afaf5a2dSDavid Somayajulu * qla4xxx_eh_wait_on_command - waits for command to be returned by firmware 357909a0f719SVikas Chaudhary * @ha: Pointer to host adapter structure. 3580afaf5a2dSDavid Somayajulu * @cmd: Scsi Command to wait on. 3581afaf5a2dSDavid Somayajulu * 3582afaf5a2dSDavid Somayajulu * This routine waits for the command to be returned by the Firmware 3583afaf5a2dSDavid Somayajulu * for some max time. 3584afaf5a2dSDavid Somayajulu **/ 3585afaf5a2dSDavid Somayajulu static int qla4xxx_eh_wait_on_command(struct scsi_qla_host *ha, 3586afaf5a2dSDavid Somayajulu struct scsi_cmnd *cmd) 3587afaf5a2dSDavid Somayajulu { 3588afaf5a2dSDavid Somayajulu int done = 0; 3589afaf5a2dSDavid Somayajulu struct srb *rp; 3590afaf5a2dSDavid Somayajulu uint32_t max_wait_time = EH_WAIT_CMD_TOV; 35912232be0dSLalit Chandivade int ret = SUCCESS; 35922232be0dSLalit Chandivade 35932232be0dSLalit Chandivade /* Dont wait on command if PCI error is being handled 35942232be0dSLalit Chandivade * by PCI AER driver 35952232be0dSLalit Chandivade */ 35962232be0dSLalit Chandivade if (unlikely(pci_channel_offline(ha->pdev)) || 35972232be0dSLalit Chandivade (test_bit(AF_EEH_BUSY, &ha->flags))) { 35982232be0dSLalit Chandivade ql4_printk(KERN_WARNING, ha, "scsi%ld: Return from %s\n", 35992232be0dSLalit Chandivade ha->host_no, __func__); 36002232be0dSLalit Chandivade return ret; 36012232be0dSLalit Chandivade } 3602afaf5a2dSDavid Somayajulu 3603afaf5a2dSDavid Somayajulu do { 3604afaf5a2dSDavid Somayajulu /* Checking to see if its returned to OS */ 36055369887aSVikas Chaudhary rp = (struct srb *) CMD_SP(cmd); 3606afaf5a2dSDavid Somayajulu if (rp == NULL) { 3607afaf5a2dSDavid Somayajulu done++; 3608afaf5a2dSDavid Somayajulu break; 3609afaf5a2dSDavid Somayajulu } 3610afaf5a2dSDavid Somayajulu 3611afaf5a2dSDavid Somayajulu msleep(2000); 3612afaf5a2dSDavid Somayajulu } while (max_wait_time--); 3613afaf5a2dSDavid Somayajulu 3614afaf5a2dSDavid Somayajulu return done; 3615afaf5a2dSDavid Somayajulu } 3616afaf5a2dSDavid Somayajulu 3617afaf5a2dSDavid Somayajulu /** 3618afaf5a2dSDavid Somayajulu * qla4xxx_wait_for_hba_online - waits for HBA to come online 3619afaf5a2dSDavid Somayajulu * @ha: Pointer to host adapter structure 3620afaf5a2dSDavid Somayajulu **/ 3621afaf5a2dSDavid Somayajulu static int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha) 3622afaf5a2dSDavid Somayajulu { 3623afaf5a2dSDavid Somayajulu unsigned long wait_online; 3624afaf5a2dSDavid Somayajulu 3625f581a3f7SVikas Chaudhary wait_online = jiffies + (HBA_ONLINE_TOV * HZ); 3626afaf5a2dSDavid Somayajulu while (time_before(jiffies, wait_online)) { 3627afaf5a2dSDavid Somayajulu 3628afaf5a2dSDavid Somayajulu if (adapter_up(ha)) 3629afaf5a2dSDavid Somayajulu return QLA_SUCCESS; 3630afaf5a2dSDavid Somayajulu 3631afaf5a2dSDavid Somayajulu msleep(2000); 3632afaf5a2dSDavid Somayajulu } 3633afaf5a2dSDavid Somayajulu 3634afaf5a2dSDavid Somayajulu return QLA_ERROR; 3635afaf5a2dSDavid Somayajulu } 3636afaf5a2dSDavid Somayajulu 3637afaf5a2dSDavid Somayajulu /** 3638ce545039SMike Christie * qla4xxx_eh_wait_for_commands - wait for active cmds to finish. 3639fd589a8fSAnand Gadiyar * @ha: pointer to HBA 3640afaf5a2dSDavid Somayajulu * @t: target id 3641afaf5a2dSDavid Somayajulu * @l: lun id 3642afaf5a2dSDavid Somayajulu * 3643afaf5a2dSDavid Somayajulu * This function waits for all outstanding commands to a lun to complete. It 3644afaf5a2dSDavid Somayajulu * returns 0 if all pending commands are returned and 1 otherwise. 3645afaf5a2dSDavid Somayajulu **/ 3646ce545039SMike Christie static int qla4xxx_eh_wait_for_commands(struct scsi_qla_host *ha, 3647ce545039SMike Christie struct scsi_target *stgt, 3648ce545039SMike Christie struct scsi_device *sdev) 3649afaf5a2dSDavid Somayajulu { 3650afaf5a2dSDavid Somayajulu int cnt; 3651afaf5a2dSDavid Somayajulu int status = 0; 3652afaf5a2dSDavid Somayajulu struct scsi_cmnd *cmd; 3653afaf5a2dSDavid Somayajulu 3654afaf5a2dSDavid Somayajulu /* 3655ce545039SMike Christie * Waiting for all commands for the designated target or dev 3656ce545039SMike Christie * in the active array 3657afaf5a2dSDavid Somayajulu */ 3658afaf5a2dSDavid Somayajulu for (cnt = 0; cnt < ha->host->can_queue; cnt++) { 3659afaf5a2dSDavid Somayajulu cmd = scsi_host_find_tag(ha->host, cnt); 3660ce545039SMike Christie if (cmd && stgt == scsi_target(cmd->device) && 3661ce545039SMike Christie (!sdev || sdev == cmd->device)) { 3662afaf5a2dSDavid Somayajulu if (!qla4xxx_eh_wait_on_command(ha, cmd)) { 3663afaf5a2dSDavid Somayajulu status++; 3664afaf5a2dSDavid Somayajulu break; 3665afaf5a2dSDavid Somayajulu } 3666afaf5a2dSDavid Somayajulu } 3667afaf5a2dSDavid Somayajulu } 3668afaf5a2dSDavid Somayajulu return status; 3669afaf5a2dSDavid Somayajulu } 3670afaf5a2dSDavid Somayajulu 3671afaf5a2dSDavid Somayajulu /** 367209a0f719SVikas Chaudhary * qla4xxx_eh_abort - callback for abort task. 367309a0f719SVikas Chaudhary * @cmd: Pointer to Linux's SCSI command structure 367409a0f719SVikas Chaudhary * 367509a0f719SVikas Chaudhary * This routine is called by the Linux OS to abort the specified 367609a0f719SVikas Chaudhary * command. 367709a0f719SVikas Chaudhary **/ 367809a0f719SVikas Chaudhary static int qla4xxx_eh_abort(struct scsi_cmnd *cmd) 367909a0f719SVikas Chaudhary { 368009a0f719SVikas Chaudhary struct scsi_qla_host *ha = to_qla_host(cmd->device->host); 368109a0f719SVikas Chaudhary unsigned int id = cmd->device->id; 368209a0f719SVikas Chaudhary unsigned int lun = cmd->device->lun; 368392b3e5bbSMike Christie unsigned long flags; 368409a0f719SVikas Chaudhary struct srb *srb = NULL; 368509a0f719SVikas Chaudhary int ret = SUCCESS; 368609a0f719SVikas Chaudhary int wait = 0; 368709a0f719SVikas Chaudhary 3688c2660df3SVikas Chaudhary ql4_printk(KERN_INFO, ha, 36895cd049a5SChristoph Hellwig "scsi%ld:%d:%d: Abort command issued cmd=%p\n", 36905cd049a5SChristoph Hellwig ha->host_no, id, lun, cmd); 369109a0f719SVikas Chaudhary 369292b3e5bbSMike Christie spin_lock_irqsave(&ha->hardware_lock, flags); 369309a0f719SVikas Chaudhary srb = (struct srb *) CMD_SP(cmd); 369492b3e5bbSMike Christie if (!srb) { 369592b3e5bbSMike Christie spin_unlock_irqrestore(&ha->hardware_lock, flags); 369609a0f719SVikas Chaudhary return SUCCESS; 369792b3e5bbSMike Christie } 369809a0f719SVikas Chaudhary kref_get(&srb->srb_ref); 369992b3e5bbSMike Christie spin_unlock_irqrestore(&ha->hardware_lock, flags); 370009a0f719SVikas Chaudhary 370109a0f719SVikas Chaudhary if (qla4xxx_abort_task(ha, srb) != QLA_SUCCESS) { 370209a0f719SVikas Chaudhary DEBUG3(printk("scsi%ld:%d:%d: Abort_task mbx failed.\n", 370309a0f719SVikas Chaudhary ha->host_no, id, lun)); 370409a0f719SVikas Chaudhary ret = FAILED; 370509a0f719SVikas Chaudhary } else { 370609a0f719SVikas Chaudhary DEBUG3(printk("scsi%ld:%d:%d: Abort_task mbx success.\n", 370709a0f719SVikas Chaudhary ha->host_no, id, lun)); 370809a0f719SVikas Chaudhary wait = 1; 370909a0f719SVikas Chaudhary } 371009a0f719SVikas Chaudhary 371109a0f719SVikas Chaudhary kref_put(&srb->srb_ref, qla4xxx_srb_compl); 371209a0f719SVikas Chaudhary 371309a0f719SVikas Chaudhary /* Wait for command to complete */ 371409a0f719SVikas Chaudhary if (wait) { 371509a0f719SVikas Chaudhary if (!qla4xxx_eh_wait_on_command(ha, cmd)) { 371609a0f719SVikas Chaudhary DEBUG2(printk("scsi%ld:%d:%d: Abort handler timed out\n", 371709a0f719SVikas Chaudhary ha->host_no, id, lun)); 371809a0f719SVikas Chaudhary ret = FAILED; 371909a0f719SVikas Chaudhary } 372009a0f719SVikas Chaudhary } 372109a0f719SVikas Chaudhary 3722c2660df3SVikas Chaudhary ql4_printk(KERN_INFO, ha, 372309a0f719SVikas Chaudhary "scsi%ld:%d:%d: Abort command - %s\n", 372425985edcSLucas De Marchi ha->host_no, id, lun, (ret == SUCCESS) ? "succeeded" : "failed"); 372509a0f719SVikas Chaudhary 372609a0f719SVikas Chaudhary return ret; 372709a0f719SVikas Chaudhary } 372809a0f719SVikas Chaudhary 372909a0f719SVikas Chaudhary /** 3730afaf5a2dSDavid Somayajulu * qla4xxx_eh_device_reset - callback for target reset. 3731afaf5a2dSDavid Somayajulu * @cmd: Pointer to Linux's SCSI command structure 3732afaf5a2dSDavid Somayajulu * 3733afaf5a2dSDavid Somayajulu * This routine is called by the Linux OS to reset all luns on the 3734afaf5a2dSDavid Somayajulu * specified target. 3735afaf5a2dSDavid Somayajulu **/ 3736afaf5a2dSDavid Somayajulu static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd) 3737afaf5a2dSDavid Somayajulu { 3738afaf5a2dSDavid Somayajulu struct scsi_qla_host *ha = to_qla_host(cmd->device->host); 3739afaf5a2dSDavid Somayajulu struct ddb_entry *ddb_entry = cmd->device->hostdata; 3740afaf5a2dSDavid Somayajulu int ret = FAILED, stat; 3741afaf5a2dSDavid Somayajulu 3742612f7348SKaren Higgins if (!ddb_entry) 3743afaf5a2dSDavid Somayajulu return ret; 3744afaf5a2dSDavid Somayajulu 3745c01be6dcSMike Christie ret = iscsi_block_scsi_eh(cmd); 3746c01be6dcSMike Christie if (ret) 3747c01be6dcSMike Christie return ret; 3748c01be6dcSMike Christie ret = FAILED; 3749c01be6dcSMike Christie 3750c2660df3SVikas Chaudhary ql4_printk(KERN_INFO, ha, 3751afaf5a2dSDavid Somayajulu "scsi%ld:%d:%d:%d: DEVICE RESET ISSUED.\n", ha->host_no, 3752afaf5a2dSDavid Somayajulu cmd->device->channel, cmd->device->id, cmd->device->lun); 3753afaf5a2dSDavid Somayajulu 3754afaf5a2dSDavid Somayajulu DEBUG2(printk(KERN_INFO 3755afaf5a2dSDavid Somayajulu "scsi%ld: DEVICE_RESET cmd=%p jiffies = 0x%lx, to=%x," 3756afaf5a2dSDavid Somayajulu "dpc_flags=%lx, status=%x allowed=%d\n", ha->host_no, 3757242f9dcbSJens Axboe cmd, jiffies, cmd->request->timeout / HZ, 3758afaf5a2dSDavid Somayajulu ha->dpc_flags, cmd->result, cmd->allowed)); 3759afaf5a2dSDavid Somayajulu 3760afaf5a2dSDavid Somayajulu /* FIXME: wait for hba to go online */ 3761afaf5a2dSDavid Somayajulu stat = qla4xxx_reset_lun(ha, ddb_entry, cmd->device->lun); 3762afaf5a2dSDavid Somayajulu if (stat != QLA_SUCCESS) { 3763c2660df3SVikas Chaudhary ql4_printk(KERN_INFO, ha, "DEVICE RESET FAILED. %d\n", stat); 3764afaf5a2dSDavid Somayajulu goto eh_dev_reset_done; 3765afaf5a2dSDavid Somayajulu } 3766afaf5a2dSDavid Somayajulu 3767ce545039SMike Christie if (qla4xxx_eh_wait_for_commands(ha, scsi_target(cmd->device), 3768ce545039SMike Christie cmd->device)) { 3769c2660df3SVikas Chaudhary ql4_printk(KERN_INFO, ha, 3770afaf5a2dSDavid Somayajulu "DEVICE RESET FAILED - waiting for " 3771afaf5a2dSDavid Somayajulu "commands.\n"); 3772afaf5a2dSDavid Somayajulu goto eh_dev_reset_done; 3773afaf5a2dSDavid Somayajulu } 3774afaf5a2dSDavid Somayajulu 37759d562913SDavid C Somayajulu /* Send marker. */ 37769d562913SDavid C Somayajulu if (qla4xxx_send_marker_iocb(ha, ddb_entry, cmd->device->lun, 37779d562913SDavid C Somayajulu MM_LUN_RESET) != QLA_SUCCESS) 37789d562913SDavid C Somayajulu goto eh_dev_reset_done; 37799d562913SDavid C Somayajulu 3780c2660df3SVikas Chaudhary ql4_printk(KERN_INFO, ha, 3781afaf5a2dSDavid Somayajulu "scsi(%ld:%d:%d:%d): DEVICE RESET SUCCEEDED.\n", 3782afaf5a2dSDavid Somayajulu ha->host_no, cmd->device->channel, cmd->device->id, 3783afaf5a2dSDavid Somayajulu cmd->device->lun); 3784afaf5a2dSDavid Somayajulu 3785afaf5a2dSDavid Somayajulu ret = SUCCESS; 3786afaf5a2dSDavid Somayajulu 3787afaf5a2dSDavid Somayajulu eh_dev_reset_done: 3788afaf5a2dSDavid Somayajulu 3789afaf5a2dSDavid Somayajulu return ret; 3790afaf5a2dSDavid Somayajulu } 3791afaf5a2dSDavid Somayajulu 3792afaf5a2dSDavid Somayajulu /** 3793ce545039SMike Christie * qla4xxx_eh_target_reset - callback for target reset. 3794ce545039SMike Christie * @cmd: Pointer to Linux's SCSI command structure 3795ce545039SMike Christie * 3796ce545039SMike Christie * This routine is called by the Linux OS to reset the target. 3797ce545039SMike Christie **/ 3798ce545039SMike Christie static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd) 3799ce545039SMike Christie { 3800ce545039SMike Christie struct scsi_qla_host *ha = to_qla_host(cmd->device->host); 3801ce545039SMike Christie struct ddb_entry *ddb_entry = cmd->device->hostdata; 3802c01be6dcSMike Christie int stat, ret; 3803ce545039SMike Christie 3804ce545039SMike Christie if (!ddb_entry) 3805ce545039SMike Christie return FAILED; 3806ce545039SMike Christie 3807c01be6dcSMike Christie ret = iscsi_block_scsi_eh(cmd); 3808c01be6dcSMike Christie if (ret) 3809c01be6dcSMike Christie return ret; 3810c01be6dcSMike Christie 3811ce545039SMike Christie starget_printk(KERN_INFO, scsi_target(cmd->device), 3812ce545039SMike Christie "WARM TARGET RESET ISSUED.\n"); 3813ce545039SMike Christie 3814ce545039SMike Christie DEBUG2(printk(KERN_INFO 3815ce545039SMike Christie "scsi%ld: TARGET_DEVICE_RESET cmd=%p jiffies = 0x%lx, " 3816ce545039SMike Christie "to=%x,dpc_flags=%lx, status=%x allowed=%d\n", 3817242f9dcbSJens Axboe ha->host_no, cmd, jiffies, cmd->request->timeout / HZ, 3818ce545039SMike Christie ha->dpc_flags, cmd->result, cmd->allowed)); 3819ce545039SMike Christie 3820ce545039SMike Christie stat = qla4xxx_reset_target(ha, ddb_entry); 3821ce545039SMike Christie if (stat != QLA_SUCCESS) { 3822ce545039SMike Christie starget_printk(KERN_INFO, scsi_target(cmd->device), 3823ce545039SMike Christie "WARM TARGET RESET FAILED.\n"); 3824ce545039SMike Christie return FAILED; 3825ce545039SMike Christie } 3826ce545039SMike Christie 3827ce545039SMike Christie if (qla4xxx_eh_wait_for_commands(ha, scsi_target(cmd->device), 3828ce545039SMike Christie NULL)) { 3829ce545039SMike Christie starget_printk(KERN_INFO, scsi_target(cmd->device), 3830ce545039SMike Christie "WARM TARGET DEVICE RESET FAILED - " 3831ce545039SMike Christie "waiting for commands.\n"); 3832ce545039SMike Christie return FAILED; 3833ce545039SMike Christie } 3834ce545039SMike Christie 38359d562913SDavid C Somayajulu /* Send marker. */ 38369d562913SDavid C Somayajulu if (qla4xxx_send_marker_iocb(ha, ddb_entry, cmd->device->lun, 38379d562913SDavid C Somayajulu MM_TGT_WARM_RESET) != QLA_SUCCESS) { 38389d562913SDavid C Somayajulu starget_printk(KERN_INFO, scsi_target(cmd->device), 38399d562913SDavid C Somayajulu "WARM TARGET DEVICE RESET FAILED - " 38409d562913SDavid C Somayajulu "marker iocb failed.\n"); 38419d562913SDavid C Somayajulu return FAILED; 38429d562913SDavid C Somayajulu } 38439d562913SDavid C Somayajulu 3844ce545039SMike Christie starget_printk(KERN_INFO, scsi_target(cmd->device), 3845ce545039SMike Christie "WARM TARGET RESET SUCCEEDED.\n"); 3846ce545039SMike Christie return SUCCESS; 3847ce545039SMike Christie } 3848ce545039SMike Christie 3849ce545039SMike Christie /** 3850afaf5a2dSDavid Somayajulu * qla4xxx_eh_host_reset - kernel callback 3851afaf5a2dSDavid Somayajulu * @cmd: Pointer to Linux's SCSI command structure 3852afaf5a2dSDavid Somayajulu * 3853afaf5a2dSDavid Somayajulu * This routine is invoked by the Linux kernel to perform fatal error 3854afaf5a2dSDavid Somayajulu * recovery on the specified adapter. 3855afaf5a2dSDavid Somayajulu **/ 3856afaf5a2dSDavid Somayajulu static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd) 3857afaf5a2dSDavid Somayajulu { 3858afaf5a2dSDavid Somayajulu int return_status = FAILED; 3859afaf5a2dSDavid Somayajulu struct scsi_qla_host *ha; 3860afaf5a2dSDavid Somayajulu 3861b3a271a9SManish Rangankar ha = to_qla_host(cmd->device->host); 3862afaf5a2dSDavid Somayajulu 3863f4f5df23SVikas Chaudhary if (ql4xdontresethba) { 3864f4f5df23SVikas Chaudhary DEBUG2(printk("scsi%ld: %s: Don't Reset HBA\n", 3865f4f5df23SVikas Chaudhary ha->host_no, __func__)); 3866f4f5df23SVikas Chaudhary return FAILED; 3867f4f5df23SVikas Chaudhary } 3868f4f5df23SVikas Chaudhary 3869c2660df3SVikas Chaudhary ql4_printk(KERN_INFO, ha, 3870dca05c4cSKaren Higgins "scsi(%ld:%d:%d:%d): HOST RESET ISSUED.\n", ha->host_no, 3871afaf5a2dSDavid Somayajulu cmd->device->channel, cmd->device->id, cmd->device->lun); 3872afaf5a2dSDavid Somayajulu 3873afaf5a2dSDavid Somayajulu if (qla4xxx_wait_for_hba_online(ha) != QLA_SUCCESS) { 3874afaf5a2dSDavid Somayajulu DEBUG2(printk("scsi%ld:%d: %s: Unable to reset host. Adapter " 3875afaf5a2dSDavid Somayajulu "DEAD.\n", ha->host_no, cmd->device->channel, 3876afaf5a2dSDavid Somayajulu __func__)); 3877afaf5a2dSDavid Somayajulu 3878afaf5a2dSDavid Somayajulu return FAILED; 3879afaf5a2dSDavid Somayajulu } 3880afaf5a2dSDavid Somayajulu 3881f4f5df23SVikas Chaudhary if (!test_bit(DPC_RESET_HA, &ha->dpc_flags)) { 3882f4f5df23SVikas Chaudhary if (is_qla8022(ha)) 3883f4f5df23SVikas Chaudhary set_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags); 3884f4f5df23SVikas Chaudhary else 3885f4f5df23SVikas Chaudhary set_bit(DPC_RESET_HA, &ha->dpc_flags); 3886f4f5df23SVikas Chaudhary } 388750a29aecSMike Christie 3888f4f5df23SVikas Chaudhary if (qla4xxx_recover_adapter(ha) == QLA_SUCCESS) 3889afaf5a2dSDavid Somayajulu return_status = SUCCESS; 3890afaf5a2dSDavid Somayajulu 3891c2660df3SVikas Chaudhary ql4_printk(KERN_INFO, ha, "HOST RESET %s.\n", 389225985edcSLucas De Marchi return_status == FAILED ? "FAILED" : "SUCCEEDED"); 3893afaf5a2dSDavid Somayajulu 3894afaf5a2dSDavid Somayajulu return return_status; 3895afaf5a2dSDavid Somayajulu } 3896afaf5a2dSDavid Somayajulu 389795d31262SVikas Chaudhary static int qla4xxx_context_reset(struct scsi_qla_host *ha) 389895d31262SVikas Chaudhary { 389995d31262SVikas Chaudhary uint32_t mbox_cmd[MBOX_REG_COUNT]; 390095d31262SVikas Chaudhary uint32_t mbox_sts[MBOX_REG_COUNT]; 390195d31262SVikas Chaudhary struct addr_ctrl_blk_def *acb = NULL; 390295d31262SVikas Chaudhary uint32_t acb_len = sizeof(struct addr_ctrl_blk_def); 390395d31262SVikas Chaudhary int rval = QLA_SUCCESS; 390495d31262SVikas Chaudhary dma_addr_t acb_dma; 390595d31262SVikas Chaudhary 390695d31262SVikas Chaudhary acb = dma_alloc_coherent(&ha->pdev->dev, 390795d31262SVikas Chaudhary sizeof(struct addr_ctrl_blk_def), 390895d31262SVikas Chaudhary &acb_dma, GFP_KERNEL); 390995d31262SVikas Chaudhary if (!acb) { 391095d31262SVikas Chaudhary ql4_printk(KERN_ERR, ha, "%s: Unable to alloc acb\n", 391195d31262SVikas Chaudhary __func__); 391295d31262SVikas Chaudhary rval = -ENOMEM; 391395d31262SVikas Chaudhary goto exit_port_reset; 391495d31262SVikas Chaudhary } 391595d31262SVikas Chaudhary 391695d31262SVikas Chaudhary memset(acb, 0, acb_len); 391795d31262SVikas Chaudhary 391895d31262SVikas Chaudhary rval = qla4xxx_get_acb(ha, acb_dma, PRIMARI_ACB, acb_len); 391995d31262SVikas Chaudhary if (rval != QLA_SUCCESS) { 392095d31262SVikas Chaudhary rval = -EIO; 392195d31262SVikas Chaudhary goto exit_free_acb; 392295d31262SVikas Chaudhary } 392395d31262SVikas Chaudhary 392495d31262SVikas Chaudhary rval = qla4xxx_disable_acb(ha); 392595d31262SVikas Chaudhary if (rval != QLA_SUCCESS) { 392695d31262SVikas Chaudhary rval = -EIO; 392795d31262SVikas Chaudhary goto exit_free_acb; 392895d31262SVikas Chaudhary } 392995d31262SVikas Chaudhary 393095d31262SVikas Chaudhary wait_for_completion_timeout(&ha->disable_acb_comp, 393195d31262SVikas Chaudhary DISABLE_ACB_TOV * HZ); 393295d31262SVikas Chaudhary 393395d31262SVikas Chaudhary rval = qla4xxx_set_acb(ha, &mbox_cmd[0], &mbox_sts[0], acb_dma); 393495d31262SVikas Chaudhary if (rval != QLA_SUCCESS) { 393595d31262SVikas Chaudhary rval = -EIO; 393695d31262SVikas Chaudhary goto exit_free_acb; 393795d31262SVikas Chaudhary } 393895d31262SVikas Chaudhary 393995d31262SVikas Chaudhary exit_free_acb: 394095d31262SVikas Chaudhary dma_free_coherent(&ha->pdev->dev, sizeof(struct addr_ctrl_blk_def), 394195d31262SVikas Chaudhary acb, acb_dma); 394295d31262SVikas Chaudhary exit_port_reset: 394395d31262SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, "%s %s\n", __func__, 394495d31262SVikas Chaudhary rval == QLA_SUCCESS ? "SUCCEEDED" : "FAILED")); 394595d31262SVikas Chaudhary return rval; 394695d31262SVikas Chaudhary } 394795d31262SVikas Chaudhary 394895d31262SVikas Chaudhary static int qla4xxx_host_reset(struct Scsi_Host *shost, int reset_type) 394995d31262SVikas Chaudhary { 395095d31262SVikas Chaudhary struct scsi_qla_host *ha = to_qla_host(shost); 395195d31262SVikas Chaudhary int rval = QLA_SUCCESS; 395295d31262SVikas Chaudhary 395395d31262SVikas Chaudhary if (ql4xdontresethba) { 395495d31262SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Don't Reset HBA\n", 395595d31262SVikas Chaudhary __func__)); 395695d31262SVikas Chaudhary rval = -EPERM; 395795d31262SVikas Chaudhary goto exit_host_reset; 395895d31262SVikas Chaudhary } 395995d31262SVikas Chaudhary 396095d31262SVikas Chaudhary rval = qla4xxx_wait_for_hba_online(ha); 396195d31262SVikas Chaudhary if (rval != QLA_SUCCESS) { 396295d31262SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Unable to reset host " 396395d31262SVikas Chaudhary "adapter\n", __func__)); 396495d31262SVikas Chaudhary rval = -EIO; 396595d31262SVikas Chaudhary goto exit_host_reset; 396695d31262SVikas Chaudhary } 396795d31262SVikas Chaudhary 396895d31262SVikas Chaudhary if (test_bit(DPC_RESET_HA, &ha->dpc_flags)) 396995d31262SVikas Chaudhary goto recover_adapter; 397095d31262SVikas Chaudhary 397195d31262SVikas Chaudhary switch (reset_type) { 397295d31262SVikas Chaudhary case SCSI_ADAPTER_RESET: 397395d31262SVikas Chaudhary set_bit(DPC_RESET_HA, &ha->dpc_flags); 397495d31262SVikas Chaudhary break; 397595d31262SVikas Chaudhary case SCSI_FIRMWARE_RESET: 397695d31262SVikas Chaudhary if (!test_bit(DPC_RESET_HA, &ha->dpc_flags)) { 397795d31262SVikas Chaudhary if (is_qla8022(ha)) 397895d31262SVikas Chaudhary /* set firmware context reset */ 397995d31262SVikas Chaudhary set_bit(DPC_RESET_HA_FW_CONTEXT, 398095d31262SVikas Chaudhary &ha->dpc_flags); 398195d31262SVikas Chaudhary else { 398295d31262SVikas Chaudhary rval = qla4xxx_context_reset(ha); 398395d31262SVikas Chaudhary goto exit_host_reset; 398495d31262SVikas Chaudhary } 398595d31262SVikas Chaudhary } 398695d31262SVikas Chaudhary break; 398795d31262SVikas Chaudhary } 398895d31262SVikas Chaudhary 398995d31262SVikas Chaudhary recover_adapter: 399095d31262SVikas Chaudhary rval = qla4xxx_recover_adapter(ha); 399195d31262SVikas Chaudhary if (rval != QLA_SUCCESS) { 399295d31262SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, "%s: recover adapter fail\n", 399395d31262SVikas Chaudhary __func__)); 399495d31262SVikas Chaudhary rval = -EIO; 399595d31262SVikas Chaudhary } 399695d31262SVikas Chaudhary 399795d31262SVikas Chaudhary exit_host_reset: 399895d31262SVikas Chaudhary return rval; 399995d31262SVikas Chaudhary } 400095d31262SVikas Chaudhary 40012232be0dSLalit Chandivade /* PCI AER driver recovers from all correctable errors w/o 40022232be0dSLalit Chandivade * driver intervention. For uncorrectable errors PCI AER 40032232be0dSLalit Chandivade * driver calls the following device driver's callbacks 40042232be0dSLalit Chandivade * 40052232be0dSLalit Chandivade * - Fatal Errors - link_reset 40062232be0dSLalit Chandivade * - Non-Fatal Errors - driver's pci_error_detected() which 40072232be0dSLalit Chandivade * returns CAN_RECOVER, NEED_RESET or DISCONNECT. 40082232be0dSLalit Chandivade * 40092232be0dSLalit Chandivade * PCI AER driver calls 40102232be0dSLalit Chandivade * CAN_RECOVER - driver's pci_mmio_enabled(), mmio_enabled 40112232be0dSLalit Chandivade * returns RECOVERED or NEED_RESET if fw_hung 40122232be0dSLalit Chandivade * NEED_RESET - driver's slot_reset() 40132232be0dSLalit Chandivade * DISCONNECT - device is dead & cannot recover 40142232be0dSLalit Chandivade * RECOVERED - driver's pci_resume() 40152232be0dSLalit Chandivade */ 40162232be0dSLalit Chandivade static pci_ers_result_t 40172232be0dSLalit Chandivade qla4xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) 40182232be0dSLalit Chandivade { 40192232be0dSLalit Chandivade struct scsi_qla_host *ha = pci_get_drvdata(pdev); 40202232be0dSLalit Chandivade 40212232be0dSLalit Chandivade ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: error detected:state %x\n", 40222232be0dSLalit Chandivade ha->host_no, __func__, state); 40232232be0dSLalit Chandivade 40242232be0dSLalit Chandivade if (!is_aer_supported(ha)) 40252232be0dSLalit Chandivade return PCI_ERS_RESULT_NONE; 40262232be0dSLalit Chandivade 40272232be0dSLalit Chandivade switch (state) { 40282232be0dSLalit Chandivade case pci_channel_io_normal: 40292232be0dSLalit Chandivade clear_bit(AF_EEH_BUSY, &ha->flags); 40302232be0dSLalit Chandivade return PCI_ERS_RESULT_CAN_RECOVER; 40312232be0dSLalit Chandivade case pci_channel_io_frozen: 40322232be0dSLalit Chandivade set_bit(AF_EEH_BUSY, &ha->flags); 40332232be0dSLalit Chandivade qla4xxx_mailbox_premature_completion(ha); 40342232be0dSLalit Chandivade qla4xxx_free_irqs(ha); 40352232be0dSLalit Chandivade pci_disable_device(pdev); 40367b3595dfSVikas Chaudhary /* Return back all IOs */ 40377b3595dfSVikas Chaudhary qla4xxx_abort_active_cmds(ha, DID_RESET << 16); 40382232be0dSLalit Chandivade return PCI_ERS_RESULT_NEED_RESET; 40392232be0dSLalit Chandivade case pci_channel_io_perm_failure: 40402232be0dSLalit Chandivade set_bit(AF_EEH_BUSY, &ha->flags); 40412232be0dSLalit Chandivade set_bit(AF_PCI_CHANNEL_IO_PERM_FAILURE, &ha->flags); 40422232be0dSLalit Chandivade qla4xxx_abort_active_cmds(ha, DID_NO_CONNECT << 16); 40432232be0dSLalit Chandivade return PCI_ERS_RESULT_DISCONNECT; 40442232be0dSLalit Chandivade } 40452232be0dSLalit Chandivade return PCI_ERS_RESULT_NEED_RESET; 40462232be0dSLalit Chandivade } 40472232be0dSLalit Chandivade 40482232be0dSLalit Chandivade /** 40492232be0dSLalit Chandivade * qla4xxx_pci_mmio_enabled() gets called if 40502232be0dSLalit Chandivade * qla4xxx_pci_error_detected() returns PCI_ERS_RESULT_CAN_RECOVER 40512232be0dSLalit Chandivade * and read/write to the device still works. 40522232be0dSLalit Chandivade **/ 40532232be0dSLalit Chandivade static pci_ers_result_t 40542232be0dSLalit Chandivade qla4xxx_pci_mmio_enabled(struct pci_dev *pdev) 40552232be0dSLalit Chandivade { 40562232be0dSLalit Chandivade struct scsi_qla_host *ha = pci_get_drvdata(pdev); 40572232be0dSLalit Chandivade 40582232be0dSLalit Chandivade if (!is_aer_supported(ha)) 40592232be0dSLalit Chandivade return PCI_ERS_RESULT_NONE; 40602232be0dSLalit Chandivade 40612232be0dSLalit Chandivade return PCI_ERS_RESULT_RECOVERED; 40622232be0dSLalit Chandivade } 40632232be0dSLalit Chandivade 40647b3595dfSVikas Chaudhary static uint32_t qla4_8xxx_error_recovery(struct scsi_qla_host *ha) 40652232be0dSLalit Chandivade { 40662232be0dSLalit Chandivade uint32_t rval = QLA_ERROR; 40677b3595dfSVikas Chaudhary uint32_t ret = 0; 40682232be0dSLalit Chandivade int fn; 40692232be0dSLalit Chandivade struct pci_dev *other_pdev = NULL; 40702232be0dSLalit Chandivade 40712232be0dSLalit Chandivade ql4_printk(KERN_WARNING, ha, "scsi%ld: In %s\n", ha->host_no, __func__); 40722232be0dSLalit Chandivade 40732232be0dSLalit Chandivade set_bit(DPC_RESET_ACTIVE, &ha->dpc_flags); 40742232be0dSLalit Chandivade 40752232be0dSLalit Chandivade if (test_bit(AF_ONLINE, &ha->flags)) { 40762232be0dSLalit Chandivade clear_bit(AF_ONLINE, &ha->flags); 4077b3a271a9SManish Rangankar clear_bit(AF_LINK_UP, &ha->flags); 4078b3a271a9SManish Rangankar iscsi_host_for_each_session(ha->host, qla4xxx_fail_session); 40792232be0dSLalit Chandivade qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); 40802232be0dSLalit Chandivade } 40812232be0dSLalit Chandivade 40822232be0dSLalit Chandivade fn = PCI_FUNC(ha->pdev->devfn); 40832232be0dSLalit Chandivade while (fn > 0) { 40842232be0dSLalit Chandivade fn--; 40852232be0dSLalit Chandivade ql4_printk(KERN_INFO, ha, "scsi%ld: %s: Finding PCI device at " 40862232be0dSLalit Chandivade "func %x\n", ha->host_no, __func__, fn); 40872232be0dSLalit Chandivade /* Get the pci device given the domain, bus, 40882232be0dSLalit Chandivade * slot/function number */ 40892232be0dSLalit Chandivade other_pdev = 40902232be0dSLalit Chandivade pci_get_domain_bus_and_slot(pci_domain_nr(ha->pdev->bus), 40912232be0dSLalit Chandivade ha->pdev->bus->number, PCI_DEVFN(PCI_SLOT(ha->pdev->devfn), 40922232be0dSLalit Chandivade fn)); 40932232be0dSLalit Chandivade 40942232be0dSLalit Chandivade if (!other_pdev) 40952232be0dSLalit Chandivade continue; 40962232be0dSLalit Chandivade 40972232be0dSLalit Chandivade if (atomic_read(&other_pdev->enable_cnt)) { 40982232be0dSLalit Chandivade ql4_printk(KERN_INFO, ha, "scsi%ld: %s: Found PCI " 40992232be0dSLalit Chandivade "func in enabled state%x\n", ha->host_no, 41002232be0dSLalit Chandivade __func__, fn); 41012232be0dSLalit Chandivade pci_dev_put(other_pdev); 41022232be0dSLalit Chandivade break; 41032232be0dSLalit Chandivade } 41042232be0dSLalit Chandivade pci_dev_put(other_pdev); 41052232be0dSLalit Chandivade } 41062232be0dSLalit Chandivade 41072232be0dSLalit Chandivade /* The first function on the card, the reset owner will 41082232be0dSLalit Chandivade * start & initialize the firmware. The other functions 41092232be0dSLalit Chandivade * on the card will reset the firmware context 41102232be0dSLalit Chandivade */ 41112232be0dSLalit Chandivade if (!fn) { 41122232be0dSLalit Chandivade ql4_printk(KERN_INFO, ha, "scsi%ld: %s: devfn being reset " 41132232be0dSLalit Chandivade "0x%x is the owner\n", ha->host_no, __func__, 41142232be0dSLalit Chandivade ha->pdev->devfn); 41152232be0dSLalit Chandivade 41162232be0dSLalit Chandivade qla4_8xxx_idc_lock(ha); 41172232be0dSLalit Chandivade qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, 41182232be0dSLalit Chandivade QLA82XX_DEV_COLD); 41192232be0dSLalit Chandivade 41202232be0dSLalit Chandivade qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_IDC_VERSION, 41212232be0dSLalit Chandivade QLA82XX_IDC_VERSION); 41222232be0dSLalit Chandivade 41232232be0dSLalit Chandivade qla4_8xxx_idc_unlock(ha); 41242232be0dSLalit Chandivade clear_bit(AF_FW_RECOVERY, &ha->flags); 41250e7e8501SManish Rangankar rval = qla4xxx_initialize_adapter(ha); 41262232be0dSLalit Chandivade qla4_8xxx_idc_lock(ha); 41272232be0dSLalit Chandivade 41282232be0dSLalit Chandivade if (rval != QLA_SUCCESS) { 41292232be0dSLalit Chandivade ql4_printk(KERN_INFO, ha, "scsi%ld: %s: HW State: " 41302232be0dSLalit Chandivade "FAILED\n", ha->host_no, __func__); 41312232be0dSLalit Chandivade qla4_8xxx_clear_drv_active(ha); 41322232be0dSLalit Chandivade qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, 41332232be0dSLalit Chandivade QLA82XX_DEV_FAILED); 41342232be0dSLalit Chandivade } else { 41352232be0dSLalit Chandivade ql4_printk(KERN_INFO, ha, "scsi%ld: %s: HW State: " 41362232be0dSLalit Chandivade "READY\n", ha->host_no, __func__); 41372232be0dSLalit Chandivade qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, 41382232be0dSLalit Chandivade QLA82XX_DEV_READY); 41392232be0dSLalit Chandivade /* Clear driver state register */ 41402232be0dSLalit Chandivade qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_STATE, 0); 41412232be0dSLalit Chandivade qla4_8xxx_set_drv_active(ha); 41427b3595dfSVikas Chaudhary ret = qla4xxx_request_irqs(ha); 41437b3595dfSVikas Chaudhary if (ret) { 41447b3595dfSVikas Chaudhary ql4_printk(KERN_WARNING, ha, "Failed to " 41457b3595dfSVikas Chaudhary "reserve interrupt %d already in use.\n", 41467b3595dfSVikas Chaudhary ha->pdev->irq); 41477b3595dfSVikas Chaudhary rval = QLA_ERROR; 41487b3595dfSVikas Chaudhary } else { 41492232be0dSLalit Chandivade ha->isp_ops->enable_intrs(ha); 41507b3595dfSVikas Chaudhary rval = QLA_SUCCESS; 41517b3595dfSVikas Chaudhary } 41522232be0dSLalit Chandivade } 41532232be0dSLalit Chandivade qla4_8xxx_idc_unlock(ha); 41542232be0dSLalit Chandivade } else { 41552232be0dSLalit Chandivade ql4_printk(KERN_INFO, ha, "scsi%ld: %s: devfn 0x%x is not " 41562232be0dSLalit Chandivade "the reset owner\n", ha->host_no, __func__, 41572232be0dSLalit Chandivade ha->pdev->devfn); 41582232be0dSLalit Chandivade if ((qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE) == 41592232be0dSLalit Chandivade QLA82XX_DEV_READY)) { 41602232be0dSLalit Chandivade clear_bit(AF_FW_RECOVERY, &ha->flags); 41610e7e8501SManish Rangankar rval = qla4xxx_initialize_adapter(ha); 41627b3595dfSVikas Chaudhary if (rval == QLA_SUCCESS) { 41637b3595dfSVikas Chaudhary ret = qla4xxx_request_irqs(ha); 41647b3595dfSVikas Chaudhary if (ret) { 41657b3595dfSVikas Chaudhary ql4_printk(KERN_WARNING, ha, "Failed to" 41667b3595dfSVikas Chaudhary " reserve interrupt %d already in" 41677b3595dfSVikas Chaudhary " use.\n", ha->pdev->irq); 41687b3595dfSVikas Chaudhary rval = QLA_ERROR; 41697b3595dfSVikas Chaudhary } else { 41702232be0dSLalit Chandivade ha->isp_ops->enable_intrs(ha); 41717b3595dfSVikas Chaudhary rval = QLA_SUCCESS; 41727b3595dfSVikas Chaudhary } 41737b3595dfSVikas Chaudhary } 41742232be0dSLalit Chandivade qla4_8xxx_idc_lock(ha); 41752232be0dSLalit Chandivade qla4_8xxx_set_drv_active(ha); 41762232be0dSLalit Chandivade qla4_8xxx_idc_unlock(ha); 41772232be0dSLalit Chandivade } 41782232be0dSLalit Chandivade } 41792232be0dSLalit Chandivade clear_bit(DPC_RESET_ACTIVE, &ha->dpc_flags); 41802232be0dSLalit Chandivade return rval; 41812232be0dSLalit Chandivade } 41822232be0dSLalit Chandivade 41832232be0dSLalit Chandivade static pci_ers_result_t 41842232be0dSLalit Chandivade qla4xxx_pci_slot_reset(struct pci_dev *pdev) 41852232be0dSLalit Chandivade { 41862232be0dSLalit Chandivade pci_ers_result_t ret = PCI_ERS_RESULT_DISCONNECT; 41872232be0dSLalit Chandivade struct scsi_qla_host *ha = pci_get_drvdata(pdev); 41882232be0dSLalit Chandivade int rc; 41892232be0dSLalit Chandivade 41902232be0dSLalit Chandivade ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: slot_reset\n", 41912232be0dSLalit Chandivade ha->host_no, __func__); 41922232be0dSLalit Chandivade 41932232be0dSLalit Chandivade if (!is_aer_supported(ha)) 41942232be0dSLalit Chandivade return PCI_ERS_RESULT_NONE; 41952232be0dSLalit Chandivade 41962232be0dSLalit Chandivade /* Restore the saved state of PCIe device - 41972232be0dSLalit Chandivade * BAR registers, PCI Config space, PCIX, MSI, 41982232be0dSLalit Chandivade * IOV states 41992232be0dSLalit Chandivade */ 42002232be0dSLalit Chandivade pci_restore_state(pdev); 42012232be0dSLalit Chandivade 42022232be0dSLalit Chandivade /* pci_restore_state() clears the saved_state flag of the device 42032232be0dSLalit Chandivade * save restored state which resets saved_state flag 42042232be0dSLalit Chandivade */ 42052232be0dSLalit Chandivade pci_save_state(pdev); 42062232be0dSLalit Chandivade 42072232be0dSLalit Chandivade /* Initialize device or resume if in suspended state */ 42082232be0dSLalit Chandivade rc = pci_enable_device(pdev); 42092232be0dSLalit Chandivade if (rc) { 421025985edcSLucas De Marchi ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: Can't re-enable " 42112232be0dSLalit Chandivade "device after reset\n", ha->host_no, __func__); 42122232be0dSLalit Chandivade goto exit_slot_reset; 42132232be0dSLalit Chandivade } 42142232be0dSLalit Chandivade 42157b3595dfSVikas Chaudhary ha->isp_ops->disable_intrs(ha); 42162232be0dSLalit Chandivade 42172232be0dSLalit Chandivade if (is_qla8022(ha)) { 42182232be0dSLalit Chandivade if (qla4_8xxx_error_recovery(ha) == QLA_SUCCESS) { 42192232be0dSLalit Chandivade ret = PCI_ERS_RESULT_RECOVERED; 42202232be0dSLalit Chandivade goto exit_slot_reset; 42212232be0dSLalit Chandivade } else 42222232be0dSLalit Chandivade goto exit_slot_reset; 42232232be0dSLalit Chandivade } 42242232be0dSLalit Chandivade 42252232be0dSLalit Chandivade exit_slot_reset: 42262232be0dSLalit Chandivade ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: Return=%x\n" 42272232be0dSLalit Chandivade "device after reset\n", ha->host_no, __func__, ret); 42282232be0dSLalit Chandivade return ret; 42292232be0dSLalit Chandivade } 42302232be0dSLalit Chandivade 42312232be0dSLalit Chandivade static void 42322232be0dSLalit Chandivade qla4xxx_pci_resume(struct pci_dev *pdev) 42332232be0dSLalit Chandivade { 42342232be0dSLalit Chandivade struct scsi_qla_host *ha = pci_get_drvdata(pdev); 42352232be0dSLalit Chandivade int ret; 42362232be0dSLalit Chandivade 42372232be0dSLalit Chandivade ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: pci_resume\n", 42382232be0dSLalit Chandivade ha->host_no, __func__); 42392232be0dSLalit Chandivade 42402232be0dSLalit Chandivade ret = qla4xxx_wait_for_hba_online(ha); 42412232be0dSLalit Chandivade if (ret != QLA_SUCCESS) { 42422232be0dSLalit Chandivade ql4_printk(KERN_ERR, ha, "scsi%ld: %s: the device failed to " 42432232be0dSLalit Chandivade "resume I/O from slot/link_reset\n", ha->host_no, 42442232be0dSLalit Chandivade __func__); 42452232be0dSLalit Chandivade } 42462232be0dSLalit Chandivade 42472232be0dSLalit Chandivade pci_cleanup_aer_uncorrect_error_status(pdev); 42482232be0dSLalit Chandivade clear_bit(AF_EEH_BUSY, &ha->flags); 42492232be0dSLalit Chandivade } 42502232be0dSLalit Chandivade 42512232be0dSLalit Chandivade static struct pci_error_handlers qla4xxx_err_handler = { 42522232be0dSLalit Chandivade .error_detected = qla4xxx_pci_error_detected, 42532232be0dSLalit Chandivade .mmio_enabled = qla4xxx_pci_mmio_enabled, 42542232be0dSLalit Chandivade .slot_reset = qla4xxx_pci_slot_reset, 42552232be0dSLalit Chandivade .resume = qla4xxx_pci_resume, 42562232be0dSLalit Chandivade }; 42572232be0dSLalit Chandivade 4258afaf5a2dSDavid Somayajulu static struct pci_device_id qla4xxx_pci_tbl[] = { 4259afaf5a2dSDavid Somayajulu { 4260afaf5a2dSDavid Somayajulu .vendor = PCI_VENDOR_ID_QLOGIC, 4261afaf5a2dSDavid Somayajulu .device = PCI_DEVICE_ID_QLOGIC_ISP4010, 4262afaf5a2dSDavid Somayajulu .subvendor = PCI_ANY_ID, 4263afaf5a2dSDavid Somayajulu .subdevice = PCI_ANY_ID, 4264afaf5a2dSDavid Somayajulu }, 4265afaf5a2dSDavid Somayajulu { 4266afaf5a2dSDavid Somayajulu .vendor = PCI_VENDOR_ID_QLOGIC, 4267afaf5a2dSDavid Somayajulu .device = PCI_DEVICE_ID_QLOGIC_ISP4022, 4268afaf5a2dSDavid Somayajulu .subvendor = PCI_ANY_ID, 4269afaf5a2dSDavid Somayajulu .subdevice = PCI_ANY_ID, 4270afaf5a2dSDavid Somayajulu }, 4271d915058fSDavid C Somayajulu { 4272d915058fSDavid C Somayajulu .vendor = PCI_VENDOR_ID_QLOGIC, 4273d915058fSDavid C Somayajulu .device = PCI_DEVICE_ID_QLOGIC_ISP4032, 4274d915058fSDavid C Somayajulu .subvendor = PCI_ANY_ID, 4275d915058fSDavid C Somayajulu .subdevice = PCI_ANY_ID, 4276d915058fSDavid C Somayajulu }, 4277f4f5df23SVikas Chaudhary { 4278f4f5df23SVikas Chaudhary .vendor = PCI_VENDOR_ID_QLOGIC, 4279f4f5df23SVikas Chaudhary .device = PCI_DEVICE_ID_QLOGIC_ISP8022, 4280f4f5df23SVikas Chaudhary .subvendor = PCI_ANY_ID, 4281f4f5df23SVikas Chaudhary .subdevice = PCI_ANY_ID, 4282f4f5df23SVikas Chaudhary }, 4283afaf5a2dSDavid Somayajulu {0, 0}, 4284afaf5a2dSDavid Somayajulu }; 4285afaf5a2dSDavid Somayajulu MODULE_DEVICE_TABLE(pci, qla4xxx_pci_tbl); 4286afaf5a2dSDavid Somayajulu 428747975477SAdrian Bunk static struct pci_driver qla4xxx_pci_driver = { 4288afaf5a2dSDavid Somayajulu .name = DRIVER_NAME, 4289afaf5a2dSDavid Somayajulu .id_table = qla4xxx_pci_tbl, 4290afaf5a2dSDavid Somayajulu .probe = qla4xxx_probe_adapter, 4291afaf5a2dSDavid Somayajulu .remove = qla4xxx_remove_adapter, 42922232be0dSLalit Chandivade .err_handler = &qla4xxx_err_handler, 4293afaf5a2dSDavid Somayajulu }; 4294afaf5a2dSDavid Somayajulu 4295afaf5a2dSDavid Somayajulu static int __init qla4xxx_module_init(void) 4296afaf5a2dSDavid Somayajulu { 4297afaf5a2dSDavid Somayajulu int ret; 4298afaf5a2dSDavid Somayajulu 4299afaf5a2dSDavid Somayajulu /* Allocate cache for SRBs. */ 4300afaf5a2dSDavid Somayajulu srb_cachep = kmem_cache_create("qla4xxx_srbs", sizeof(struct srb), 0, 430120c2df83SPaul Mundt SLAB_HWCACHE_ALIGN, NULL); 4302afaf5a2dSDavid Somayajulu if (srb_cachep == NULL) { 4303afaf5a2dSDavid Somayajulu printk(KERN_ERR 4304afaf5a2dSDavid Somayajulu "%s: Unable to allocate SRB cache..." 4305afaf5a2dSDavid Somayajulu "Failing load!\n", DRIVER_NAME); 4306afaf5a2dSDavid Somayajulu ret = -ENOMEM; 4307afaf5a2dSDavid Somayajulu goto no_srp_cache; 4308afaf5a2dSDavid Somayajulu } 4309afaf5a2dSDavid Somayajulu 4310afaf5a2dSDavid Somayajulu /* Derive version string. */ 4311afaf5a2dSDavid Somayajulu strcpy(qla4xxx_version_str, QLA4XXX_DRIVER_VERSION); 431211010fecSAndrew Vasquez if (ql4xextended_error_logging) 4313afaf5a2dSDavid Somayajulu strcat(qla4xxx_version_str, "-debug"); 4314afaf5a2dSDavid Somayajulu 4315afaf5a2dSDavid Somayajulu qla4xxx_scsi_transport = 4316afaf5a2dSDavid Somayajulu iscsi_register_transport(&qla4xxx_iscsi_transport); 4317afaf5a2dSDavid Somayajulu if (!qla4xxx_scsi_transport){ 4318afaf5a2dSDavid Somayajulu ret = -ENODEV; 4319afaf5a2dSDavid Somayajulu goto release_srb_cache; 4320afaf5a2dSDavid Somayajulu } 4321afaf5a2dSDavid Somayajulu 4322afaf5a2dSDavid Somayajulu ret = pci_register_driver(&qla4xxx_pci_driver); 4323afaf5a2dSDavid Somayajulu if (ret) 4324afaf5a2dSDavid Somayajulu goto unregister_transport; 4325afaf5a2dSDavid Somayajulu 4326afaf5a2dSDavid Somayajulu printk(KERN_INFO "QLogic iSCSI HBA Driver\n"); 4327afaf5a2dSDavid Somayajulu return 0; 43285ae16db3SDoug Maxey 4329afaf5a2dSDavid Somayajulu unregister_transport: 4330afaf5a2dSDavid Somayajulu iscsi_unregister_transport(&qla4xxx_iscsi_transport); 4331afaf5a2dSDavid Somayajulu release_srb_cache: 4332afaf5a2dSDavid Somayajulu kmem_cache_destroy(srb_cachep); 4333afaf5a2dSDavid Somayajulu no_srp_cache: 4334afaf5a2dSDavid Somayajulu return ret; 4335afaf5a2dSDavid Somayajulu } 4336afaf5a2dSDavid Somayajulu 4337afaf5a2dSDavid Somayajulu static void __exit qla4xxx_module_exit(void) 4338afaf5a2dSDavid Somayajulu { 4339afaf5a2dSDavid Somayajulu pci_unregister_driver(&qla4xxx_pci_driver); 4340afaf5a2dSDavid Somayajulu iscsi_unregister_transport(&qla4xxx_iscsi_transport); 4341afaf5a2dSDavid Somayajulu kmem_cache_destroy(srb_cachep); 4342afaf5a2dSDavid Somayajulu } 4343afaf5a2dSDavid Somayajulu 4344afaf5a2dSDavid Somayajulu module_init(qla4xxx_module_init); 4345afaf5a2dSDavid Somayajulu module_exit(qla4xxx_module_exit); 4346afaf5a2dSDavid Somayajulu 4347afaf5a2dSDavid Somayajulu MODULE_AUTHOR("QLogic Corporation"); 4348afaf5a2dSDavid Somayajulu MODULE_DESCRIPTION("QLogic iSCSI HBA Driver"); 4349afaf5a2dSDavid Somayajulu MODULE_LICENSE("GPL"); 4350afaf5a2dSDavid Somayajulu MODULE_VERSION(QLA4XXX_DRIVER_VERSION); 4351