1afaf5a2dSDavid Somayajulu /* 2afaf5a2dSDavid Somayajulu * QLogic iSCSI HBA Driver 37d01d069SVikas Chaudhary * Copyright (c) 2003-2010 QLogic Corporation 4afaf5a2dSDavid Somayajulu * 5afaf5a2dSDavid Somayajulu * See LICENSE.qla4xxx for copyright and licensing details. 6afaf5a2dSDavid Somayajulu */ 7afaf5a2dSDavid Somayajulu #include <linux/moduleparam.h> 85a0e3ad6STejun Heo #include <linux/slab.h> 92a991c21SManish Rangankar #include <linux/blkdev.h> 102a991c21SManish Rangankar #include <linux/iscsi_boot_sysfs.h> 1113483730SMike Christie #include <linux/inet.h> 12afaf5a2dSDavid Somayajulu 13afaf5a2dSDavid Somayajulu #include <scsi/scsi_tcq.h> 14afaf5a2dSDavid Somayajulu #include <scsi/scsicam.h> 15afaf5a2dSDavid Somayajulu 16afaf5a2dSDavid Somayajulu #include "ql4_def.h" 17bee4fe8eSDavid C Somayajulu #include "ql4_version.h" 18bee4fe8eSDavid C Somayajulu #include "ql4_glbl.h" 19bee4fe8eSDavid C Somayajulu #include "ql4_dbg.h" 20bee4fe8eSDavid C Somayajulu #include "ql4_inline.h" 21afaf5a2dSDavid Somayajulu 22afaf5a2dSDavid Somayajulu /* 23afaf5a2dSDavid Somayajulu * Driver version 24afaf5a2dSDavid Somayajulu */ 2547975477SAdrian Bunk static char qla4xxx_version_str[40]; 26afaf5a2dSDavid Somayajulu 27afaf5a2dSDavid Somayajulu /* 28afaf5a2dSDavid Somayajulu * SRB allocation cache 29afaf5a2dSDavid Somayajulu */ 30e18b890bSChristoph Lameter static struct kmem_cache *srb_cachep; 31afaf5a2dSDavid Somayajulu 32afaf5a2dSDavid Somayajulu /* 33afaf5a2dSDavid Somayajulu * Module parameter information and variables 34afaf5a2dSDavid Somayajulu */ 3513483730SMike Christie int ql4xdisablesysfsboot = 1; 3613483730SMike Christie module_param(ql4xdisablesysfsboot, int, S_IRUGO | S_IWUSR); 3713483730SMike Christie MODULE_PARM_DESC(ql4xdisablesysfsboot, 38a4e8a715SKaren Higgins " Set to disable exporting boot targets to sysfs.\n" 39a4e8a715SKaren Higgins "\t\t 0 - Export boot targets\n" 40a4e8a715SKaren Higgins "\t\t 1 - Do not export boot targets (Default)"); 4113483730SMike Christie 42afaf5a2dSDavid Somayajulu int ql4xdontresethba = 0; 43f4f5df23SVikas Chaudhary module_param(ql4xdontresethba, int, S_IRUGO | S_IWUSR); 44afaf5a2dSDavid Somayajulu MODULE_PARM_DESC(ql4xdontresethba, 45a4e8a715SKaren Higgins " Don't reset the HBA for driver recovery.\n" 46a4e8a715SKaren Higgins "\t\t 0 - It will reset HBA (Default)\n" 47a4e8a715SKaren Higgins "\t\t 1 - It will NOT reset HBA"); 48afaf5a2dSDavid Somayajulu 49a4e8a715SKaren Higgins int ql4xextended_error_logging; 50f4f5df23SVikas Chaudhary module_param(ql4xextended_error_logging, int, S_IRUGO | S_IWUSR); 5111010fecSAndrew Vasquez MODULE_PARM_DESC(ql4xextended_error_logging, 52a4e8a715SKaren Higgins " Option to enable extended error logging.\n" 53a4e8a715SKaren Higgins "\t\t 0 - no logging (Default)\n" 54a4e8a715SKaren Higgins "\t\t 2 - debug logging"); 55afaf5a2dSDavid Somayajulu 56f4f5df23SVikas Chaudhary int ql4xenablemsix = 1; 57f4f5df23SVikas Chaudhary module_param(ql4xenablemsix, int, S_IRUGO|S_IWUSR); 58f4f5df23SVikas Chaudhary MODULE_PARM_DESC(ql4xenablemsix, 59f4f5df23SVikas Chaudhary " Set to enable MSI or MSI-X interrupt mechanism.\n" 60a4e8a715SKaren Higgins "\t\t 0 = enable INTx interrupt mechanism.\n" 61a4e8a715SKaren Higgins "\t\t 1 = enable MSI-X interrupt mechanism (Default).\n" 62a4e8a715SKaren Higgins "\t\t 2 = enable MSI interrupt mechanism."); 63477ffb9dSDavid C Somayajulu 64d510d965SMike Christie #define QL4_DEF_QDEPTH 32 658bb4033dSVikas Chaudhary static int ql4xmaxqdepth = QL4_DEF_QDEPTH; 668bb4033dSVikas Chaudhary module_param(ql4xmaxqdepth, int, S_IRUGO | S_IWUSR); 678bb4033dSVikas Chaudhary MODULE_PARM_DESC(ql4xmaxqdepth, 688bb4033dSVikas Chaudhary " Maximum queue depth to report for target devices.\n" 69a4e8a715SKaren Higgins "\t\t Default: 32."); 70d510d965SMike Christie 713038727cSVikas Chaudhary static int ql4xsess_recovery_tmo = QL4_SESS_RECOVERY_TMO; 723038727cSVikas Chaudhary module_param(ql4xsess_recovery_tmo, int, S_IRUGO); 733038727cSVikas Chaudhary MODULE_PARM_DESC(ql4xsess_recovery_tmo, 743038727cSVikas Chaudhary "Target Session Recovery Timeout.\n" 75a4e8a715SKaren Higgins "\t\t Default: 120 sec."); 763038727cSVikas Chaudhary 77b3a271a9SManish Rangankar static int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha); 78afaf5a2dSDavid Somayajulu /* 79afaf5a2dSDavid Somayajulu * SCSI host template entry points 80afaf5a2dSDavid Somayajulu */ 8147975477SAdrian Bunk static void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha); 82afaf5a2dSDavid Somayajulu 83afaf5a2dSDavid Somayajulu /* 84afaf5a2dSDavid Somayajulu * iSCSI template entry points 85afaf5a2dSDavid Somayajulu */ 86afaf5a2dSDavid Somayajulu static int qla4xxx_conn_get_param(struct iscsi_cls_conn *conn, 87afaf5a2dSDavid Somayajulu enum iscsi_param param, char *buf); 88aa1e93a2SMike Christie static int qla4xxx_host_get_param(struct Scsi_Host *shost, 89aa1e93a2SMike Christie enum iscsi_host_param param, char *buf); 9000c31889SMike Christie static int qla4xxx_iface_set_param(struct Scsi_Host *shost, void *data, 9100c31889SMike Christie uint32_t len); 92ed1086e0SVikas Chaudhary static int qla4xxx_get_iface_param(struct iscsi_iface *iface, 93ed1086e0SVikas Chaudhary enum iscsi_param_type param_type, 94ed1086e0SVikas Chaudhary int param, char *buf); 955c656af7SMike Christie static enum blk_eh_timer_return qla4xxx_eh_cmd_timed_out(struct scsi_cmnd *sc); 96b3a271a9SManish Rangankar static struct iscsi_endpoint *qla4xxx_ep_connect(struct Scsi_Host *shost, 97b3a271a9SManish Rangankar struct sockaddr *dst_addr, 98b3a271a9SManish Rangankar int non_blocking); 99b3a271a9SManish Rangankar static int qla4xxx_ep_poll(struct iscsi_endpoint *ep, int timeout_ms); 100b3a271a9SManish Rangankar static void qla4xxx_ep_disconnect(struct iscsi_endpoint *ep); 101b3a271a9SManish Rangankar static int qla4xxx_get_ep_param(struct iscsi_endpoint *ep, 102b3a271a9SManish Rangankar enum iscsi_param param, char *buf); 103b3a271a9SManish Rangankar static int qla4xxx_conn_start(struct iscsi_cls_conn *conn); 104b3a271a9SManish Rangankar static struct iscsi_cls_conn * 105b3a271a9SManish Rangankar qla4xxx_conn_create(struct iscsi_cls_session *cls_sess, uint32_t conn_idx); 106b3a271a9SManish Rangankar static int qla4xxx_conn_bind(struct iscsi_cls_session *cls_session, 107b3a271a9SManish Rangankar struct iscsi_cls_conn *cls_conn, 108b3a271a9SManish Rangankar uint64_t transport_fd, int is_leading); 109b3a271a9SManish Rangankar static void qla4xxx_conn_destroy(struct iscsi_cls_conn *conn); 110b3a271a9SManish Rangankar static struct iscsi_cls_session * 111b3a271a9SManish Rangankar qla4xxx_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max, 112b3a271a9SManish Rangankar uint16_t qdepth, uint32_t initial_cmdsn); 113b3a271a9SManish Rangankar static void qla4xxx_session_destroy(struct iscsi_cls_session *sess); 114b3a271a9SManish Rangankar static void qla4xxx_task_work(struct work_struct *wdata); 115b3a271a9SManish Rangankar static int qla4xxx_alloc_pdu(struct iscsi_task *, uint8_t); 116b3a271a9SManish Rangankar static int qla4xxx_task_xmit(struct iscsi_task *); 117b3a271a9SManish Rangankar static void qla4xxx_task_cleanup(struct iscsi_task *); 118b3a271a9SManish Rangankar static void qla4xxx_fail_session(struct iscsi_cls_session *cls_session); 119b3a271a9SManish Rangankar static void qla4xxx_conn_get_stats(struct iscsi_cls_conn *cls_conn, 120b3a271a9SManish Rangankar struct iscsi_stats *stats); 121c0b9d3f7SVikas Chaudhary static int qla4xxx_send_ping(struct Scsi_Host *shost, uint32_t iface_num, 122c0b9d3f7SVikas Chaudhary uint32_t iface_type, uint32_t payload_size, 123c0b9d3f7SVikas Chaudhary uint32_t pid, struct sockaddr *dst_addr); 124c0b9d3f7SVikas Chaudhary 125afaf5a2dSDavid Somayajulu /* 126afaf5a2dSDavid Somayajulu * SCSI host template entry points 127afaf5a2dSDavid Somayajulu */ 128f281233dSJeff Garzik static int qla4xxx_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *cmd); 12909a0f719SVikas Chaudhary static int qla4xxx_eh_abort(struct scsi_cmnd *cmd); 130afaf5a2dSDavid Somayajulu static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd); 131ce545039SMike Christie static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd); 132afaf5a2dSDavid Somayajulu static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd); 133afaf5a2dSDavid Somayajulu static int qla4xxx_slave_alloc(struct scsi_device *device); 134afaf5a2dSDavid Somayajulu static int qla4xxx_slave_configure(struct scsi_device *device); 135afaf5a2dSDavid Somayajulu static void qla4xxx_slave_destroy(struct scsi_device *sdev); 136587a1f16SAl Viro static umode_t ql4_attr_is_visible(int param_type, int param); 13795d31262SVikas Chaudhary static int qla4xxx_host_reset(struct Scsi_Host *shost, int reset_type); 138afaf5a2dSDavid Somayajulu 139f4f5df23SVikas Chaudhary static struct qla4_8xxx_legacy_intr_set legacy_intr[] = 140f4f5df23SVikas Chaudhary QLA82XX_LEGACY_INTR_CONFIG; 141f4f5df23SVikas Chaudhary 142afaf5a2dSDavid Somayajulu static struct scsi_host_template qla4xxx_driver_template = { 143afaf5a2dSDavid Somayajulu .module = THIS_MODULE, 144afaf5a2dSDavid Somayajulu .name = DRIVER_NAME, 145afaf5a2dSDavid Somayajulu .proc_name = DRIVER_NAME, 146afaf5a2dSDavid Somayajulu .queuecommand = qla4xxx_queuecommand, 147afaf5a2dSDavid Somayajulu 14809a0f719SVikas Chaudhary .eh_abort_handler = qla4xxx_eh_abort, 149afaf5a2dSDavid Somayajulu .eh_device_reset_handler = qla4xxx_eh_device_reset, 150ce545039SMike Christie .eh_target_reset_handler = qla4xxx_eh_target_reset, 151afaf5a2dSDavid Somayajulu .eh_host_reset_handler = qla4xxx_eh_host_reset, 1525c656af7SMike Christie .eh_timed_out = qla4xxx_eh_cmd_timed_out, 153afaf5a2dSDavid Somayajulu 154afaf5a2dSDavid Somayajulu .slave_configure = qla4xxx_slave_configure, 155afaf5a2dSDavid Somayajulu .slave_alloc = qla4xxx_slave_alloc, 156afaf5a2dSDavid Somayajulu .slave_destroy = qla4xxx_slave_destroy, 157afaf5a2dSDavid Somayajulu 158afaf5a2dSDavid Somayajulu .this_id = -1, 159afaf5a2dSDavid Somayajulu .cmd_per_lun = 3, 160afaf5a2dSDavid Somayajulu .use_clustering = ENABLE_CLUSTERING, 161afaf5a2dSDavid Somayajulu .sg_tablesize = SG_ALL, 162afaf5a2dSDavid Somayajulu 163afaf5a2dSDavid Somayajulu .max_sectors = 0xFFFF, 1647ad633c0SHarish Zunjarrao .shost_attrs = qla4xxx_host_attrs, 16595d31262SVikas Chaudhary .host_reset = qla4xxx_host_reset, 166a355943cSVikas Chaudhary .vendor_id = SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_QLOGIC, 167afaf5a2dSDavid Somayajulu }; 168afaf5a2dSDavid Somayajulu 169afaf5a2dSDavid Somayajulu static struct iscsi_transport qla4xxx_iscsi_transport = { 170afaf5a2dSDavid Somayajulu .owner = THIS_MODULE, 171afaf5a2dSDavid Somayajulu .name = DRIVER_NAME, 172b3a271a9SManish Rangankar .caps = CAP_TEXT_NEGO | 173b3a271a9SManish Rangankar CAP_DATA_PATH_OFFLOAD | CAP_HDRDGST | 174b3a271a9SManish Rangankar CAP_DATADGST | CAP_LOGIN_OFFLOAD | 175b3a271a9SManish Rangankar CAP_MULTI_R2T, 1763128c6c7SMike Christie .attr_is_visible = ql4_attr_is_visible, 177b3a271a9SManish Rangankar .create_session = qla4xxx_session_create, 178b3a271a9SManish Rangankar .destroy_session = qla4xxx_session_destroy, 179b3a271a9SManish Rangankar .start_conn = qla4xxx_conn_start, 180b3a271a9SManish Rangankar .create_conn = qla4xxx_conn_create, 181b3a271a9SManish Rangankar .bind_conn = qla4xxx_conn_bind, 182b3a271a9SManish Rangankar .stop_conn = iscsi_conn_stop, 183b3a271a9SManish Rangankar .destroy_conn = qla4xxx_conn_destroy, 184b3a271a9SManish Rangankar .set_param = iscsi_set_param, 185afaf5a2dSDavid Somayajulu .get_conn_param = qla4xxx_conn_get_param, 186b3a271a9SManish Rangankar .get_session_param = iscsi_session_get_param, 187b3a271a9SManish Rangankar .get_ep_param = qla4xxx_get_ep_param, 188b3a271a9SManish Rangankar .ep_connect = qla4xxx_ep_connect, 189b3a271a9SManish Rangankar .ep_poll = qla4xxx_ep_poll, 190b3a271a9SManish Rangankar .ep_disconnect = qla4xxx_ep_disconnect, 191b3a271a9SManish Rangankar .get_stats = qla4xxx_conn_get_stats, 192b3a271a9SManish Rangankar .send_pdu = iscsi_conn_send_pdu, 193b3a271a9SManish Rangankar .xmit_task = qla4xxx_task_xmit, 194b3a271a9SManish Rangankar .cleanup_task = qla4xxx_task_cleanup, 195b3a271a9SManish Rangankar .alloc_pdu = qla4xxx_alloc_pdu, 196b3a271a9SManish Rangankar 197aa1e93a2SMike Christie .get_host_param = qla4xxx_host_get_param, 198d00efe3fSMike Christie .set_iface_param = qla4xxx_iface_set_param, 199ed1086e0SVikas Chaudhary .get_iface_param = qla4xxx_get_iface_param, 200a355943cSVikas Chaudhary .bsg_request = qla4xxx_bsg_request, 201c0b9d3f7SVikas Chaudhary .send_ping = qla4xxx_send_ping, 202afaf5a2dSDavid Somayajulu }; 203afaf5a2dSDavid Somayajulu 204afaf5a2dSDavid Somayajulu static struct scsi_transport_template *qla4xxx_scsi_transport; 205afaf5a2dSDavid Somayajulu 206c0b9d3f7SVikas Chaudhary static int qla4xxx_send_ping(struct Scsi_Host *shost, uint32_t iface_num, 207c0b9d3f7SVikas Chaudhary uint32_t iface_type, uint32_t payload_size, 208c0b9d3f7SVikas Chaudhary uint32_t pid, struct sockaddr *dst_addr) 209c0b9d3f7SVikas Chaudhary { 210c0b9d3f7SVikas Chaudhary struct scsi_qla_host *ha = to_qla_host(shost); 211c0b9d3f7SVikas Chaudhary struct sockaddr_in *addr; 212c0b9d3f7SVikas Chaudhary struct sockaddr_in6 *addr6; 213c0b9d3f7SVikas Chaudhary uint32_t options = 0; 214c0b9d3f7SVikas Chaudhary uint8_t ipaddr[IPv6_ADDR_LEN]; 215c0b9d3f7SVikas Chaudhary int rval; 216c0b9d3f7SVikas Chaudhary 217c0b9d3f7SVikas Chaudhary memset(ipaddr, 0, IPv6_ADDR_LEN); 218c0b9d3f7SVikas Chaudhary /* IPv4 to IPv4 */ 219c0b9d3f7SVikas Chaudhary if ((iface_type == ISCSI_IFACE_TYPE_IPV4) && 220c0b9d3f7SVikas Chaudhary (dst_addr->sa_family == AF_INET)) { 221c0b9d3f7SVikas Chaudhary addr = (struct sockaddr_in *)dst_addr; 222c0b9d3f7SVikas Chaudhary memcpy(ipaddr, &addr->sin_addr.s_addr, IP_ADDR_LEN); 223c0b9d3f7SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, "%s: IPv4 Ping src: %pI4 " 224c0b9d3f7SVikas Chaudhary "dest: %pI4\n", __func__, 225c0b9d3f7SVikas Chaudhary &ha->ip_config.ip_address, ipaddr)); 226c0b9d3f7SVikas Chaudhary rval = qla4xxx_ping_iocb(ha, options, payload_size, pid, 227c0b9d3f7SVikas Chaudhary ipaddr); 228c0b9d3f7SVikas Chaudhary if (rval) 229c0b9d3f7SVikas Chaudhary rval = -EINVAL; 230c0b9d3f7SVikas Chaudhary } else if ((iface_type == ISCSI_IFACE_TYPE_IPV6) && 231c0b9d3f7SVikas Chaudhary (dst_addr->sa_family == AF_INET6)) { 232c0b9d3f7SVikas Chaudhary /* IPv6 to IPv6 */ 233c0b9d3f7SVikas Chaudhary addr6 = (struct sockaddr_in6 *)dst_addr; 234c0b9d3f7SVikas Chaudhary memcpy(ipaddr, &addr6->sin6_addr.in6_u.u6_addr8, IPv6_ADDR_LEN); 235c0b9d3f7SVikas Chaudhary 236c0b9d3f7SVikas Chaudhary options |= PING_IPV6_PROTOCOL_ENABLE; 237c0b9d3f7SVikas Chaudhary 238c0b9d3f7SVikas Chaudhary /* Ping using LinkLocal address */ 239c0b9d3f7SVikas Chaudhary if ((iface_num == 0) || (iface_num == 1)) { 240c0b9d3f7SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, "%s: LinkLocal Ping " 241c0b9d3f7SVikas Chaudhary "src: %pI6 dest: %pI6\n", __func__, 242c0b9d3f7SVikas Chaudhary &ha->ip_config.ipv6_link_local_addr, 243c0b9d3f7SVikas Chaudhary ipaddr)); 244c0b9d3f7SVikas Chaudhary options |= PING_IPV6_LINKLOCAL_ADDR; 245c0b9d3f7SVikas Chaudhary rval = qla4xxx_ping_iocb(ha, options, payload_size, 246c0b9d3f7SVikas Chaudhary pid, ipaddr); 247c0b9d3f7SVikas Chaudhary } else { 248c0b9d3f7SVikas Chaudhary ql4_printk(KERN_WARNING, ha, "%s: iface num = %d " 249c0b9d3f7SVikas Chaudhary "not supported\n", __func__, iface_num); 250c0b9d3f7SVikas Chaudhary rval = -ENOSYS; 251c0b9d3f7SVikas Chaudhary goto exit_send_ping; 252c0b9d3f7SVikas Chaudhary } 253c0b9d3f7SVikas Chaudhary 254c0b9d3f7SVikas Chaudhary /* 255c0b9d3f7SVikas Chaudhary * If ping using LinkLocal address fails, try ping using 256c0b9d3f7SVikas Chaudhary * IPv6 address 257c0b9d3f7SVikas Chaudhary */ 258c0b9d3f7SVikas Chaudhary if (rval != QLA_SUCCESS) { 259c0b9d3f7SVikas Chaudhary options &= ~PING_IPV6_LINKLOCAL_ADDR; 260c0b9d3f7SVikas Chaudhary if (iface_num == 0) { 261c0b9d3f7SVikas Chaudhary options |= PING_IPV6_ADDR0; 262c0b9d3f7SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, "%s: IPv6 " 263c0b9d3f7SVikas Chaudhary "Ping src: %pI6 " 264c0b9d3f7SVikas Chaudhary "dest: %pI6\n", __func__, 265c0b9d3f7SVikas Chaudhary &ha->ip_config.ipv6_addr0, 266c0b9d3f7SVikas Chaudhary ipaddr)); 267c0b9d3f7SVikas Chaudhary } else if (iface_num == 1) { 268c0b9d3f7SVikas Chaudhary options |= PING_IPV6_ADDR1; 269c0b9d3f7SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, "%s: IPv6 " 270c0b9d3f7SVikas Chaudhary "Ping src: %pI6 " 271c0b9d3f7SVikas Chaudhary "dest: %pI6\n", __func__, 272c0b9d3f7SVikas Chaudhary &ha->ip_config.ipv6_addr1, 273c0b9d3f7SVikas Chaudhary ipaddr)); 274c0b9d3f7SVikas Chaudhary } 275c0b9d3f7SVikas Chaudhary rval = qla4xxx_ping_iocb(ha, options, payload_size, 276c0b9d3f7SVikas Chaudhary pid, ipaddr); 277c0b9d3f7SVikas Chaudhary if (rval) 278c0b9d3f7SVikas Chaudhary rval = -EINVAL; 279c0b9d3f7SVikas Chaudhary } 280c0b9d3f7SVikas Chaudhary } else 281c0b9d3f7SVikas Chaudhary rval = -ENOSYS; 282c0b9d3f7SVikas Chaudhary exit_send_ping: 283c0b9d3f7SVikas Chaudhary return rval; 284c0b9d3f7SVikas Chaudhary } 285c0b9d3f7SVikas Chaudhary 286587a1f16SAl Viro static umode_t ql4_attr_is_visible(int param_type, int param) 2873128c6c7SMike Christie { 2883128c6c7SMike Christie switch (param_type) { 289f27fb2efSMike Christie case ISCSI_HOST_PARAM: 290f27fb2efSMike Christie switch (param) { 291f27fb2efSMike Christie case ISCSI_HOST_PARAM_HWADDRESS: 292f27fb2efSMike Christie case ISCSI_HOST_PARAM_IPADDRESS: 293f27fb2efSMike Christie case ISCSI_HOST_PARAM_INITIATOR_NAME: 2943254dbe9SVikas Chaudhary case ISCSI_HOST_PARAM_PORT_STATE: 2953254dbe9SVikas Chaudhary case ISCSI_HOST_PARAM_PORT_SPEED: 296f27fb2efSMike Christie return S_IRUGO; 297f27fb2efSMike Christie default: 298f27fb2efSMike Christie return 0; 299f27fb2efSMike Christie } 3003128c6c7SMike Christie case ISCSI_PARAM: 3013128c6c7SMike Christie switch (param) { 302590134faSMike Christie case ISCSI_PARAM_PERSISTENT_ADDRESS: 303590134faSMike Christie case ISCSI_PARAM_PERSISTENT_PORT: 3043128c6c7SMike Christie case ISCSI_PARAM_CONN_ADDRESS: 3053128c6c7SMike Christie case ISCSI_PARAM_CONN_PORT: 3061d063c17SMike Christie case ISCSI_PARAM_TARGET_NAME: 3071d063c17SMike Christie case ISCSI_PARAM_TPGT: 3081d063c17SMike Christie case ISCSI_PARAM_TARGET_ALIAS: 309b3a271a9SManish Rangankar case ISCSI_PARAM_MAX_BURST: 310b3a271a9SManish Rangankar case ISCSI_PARAM_MAX_R2T: 311b3a271a9SManish Rangankar case ISCSI_PARAM_FIRST_BURST: 312b3a271a9SManish Rangankar case ISCSI_PARAM_MAX_RECV_DLENGTH: 313b3a271a9SManish Rangankar case ISCSI_PARAM_MAX_XMIT_DLENGTH: 314de37920bSMike Christie case ISCSI_PARAM_IFACE_NAME: 3153128c6c7SMike Christie return S_IRUGO; 3163128c6c7SMike Christie default: 3173128c6c7SMike Christie return 0; 3183128c6c7SMike Christie } 319b78dbba0SMike Christie case ISCSI_NET_PARAM: 320b78dbba0SMike Christie switch (param) { 321b78dbba0SMike Christie case ISCSI_NET_PARAM_IPV4_ADDR: 322b78dbba0SMike Christie case ISCSI_NET_PARAM_IPV4_SUBNET: 323b78dbba0SMike Christie case ISCSI_NET_PARAM_IPV4_GW: 324b78dbba0SMike Christie case ISCSI_NET_PARAM_IPV4_BOOTPROTO: 325b78dbba0SMike Christie case ISCSI_NET_PARAM_IFACE_ENABLE: 326b78dbba0SMike Christie case ISCSI_NET_PARAM_IPV6_LINKLOCAL: 327b78dbba0SMike Christie case ISCSI_NET_PARAM_IPV6_ADDR: 328b78dbba0SMike Christie case ISCSI_NET_PARAM_IPV6_ROUTER: 329b78dbba0SMike Christie case ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG: 330b78dbba0SMike Christie case ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG: 3316ac73e8cSVikas Chaudhary case ISCSI_NET_PARAM_VLAN_ID: 3326ac73e8cSVikas Chaudhary case ISCSI_NET_PARAM_VLAN_PRIORITY: 3336ac73e8cSVikas Chaudhary case ISCSI_NET_PARAM_VLAN_ENABLED: 334943c157bSVikas Chaudhary case ISCSI_NET_PARAM_MTU: 3352ada7fc5SVikas Chaudhary case ISCSI_NET_PARAM_PORT: 336b78dbba0SMike Christie return S_IRUGO; 337b78dbba0SMike Christie default: 338b78dbba0SMike Christie return 0; 339b78dbba0SMike Christie } 3403128c6c7SMike Christie } 3413128c6c7SMike Christie 3423128c6c7SMike Christie return 0; 3433128c6c7SMike Christie } 3443128c6c7SMike Christie 345ed1086e0SVikas Chaudhary static int qla4xxx_get_iface_param(struct iscsi_iface *iface, 346ed1086e0SVikas Chaudhary enum iscsi_param_type param_type, 347ed1086e0SVikas Chaudhary int param, char *buf) 348ed1086e0SVikas Chaudhary { 349ed1086e0SVikas Chaudhary struct Scsi_Host *shost = iscsi_iface_to_shost(iface); 350ed1086e0SVikas Chaudhary struct scsi_qla_host *ha = to_qla_host(shost); 351ed1086e0SVikas Chaudhary int len = -ENOSYS; 352ed1086e0SVikas Chaudhary 353ed1086e0SVikas Chaudhary if (param_type != ISCSI_NET_PARAM) 354ed1086e0SVikas Chaudhary return -ENOSYS; 355ed1086e0SVikas Chaudhary 356ed1086e0SVikas Chaudhary switch (param) { 357ed1086e0SVikas Chaudhary case ISCSI_NET_PARAM_IPV4_ADDR: 358ed1086e0SVikas Chaudhary len = sprintf(buf, "%pI4\n", &ha->ip_config.ip_address); 359ed1086e0SVikas Chaudhary break; 360ed1086e0SVikas Chaudhary case ISCSI_NET_PARAM_IPV4_SUBNET: 361ed1086e0SVikas Chaudhary len = sprintf(buf, "%pI4\n", &ha->ip_config.subnet_mask); 362ed1086e0SVikas Chaudhary break; 363ed1086e0SVikas Chaudhary case ISCSI_NET_PARAM_IPV4_GW: 364ed1086e0SVikas Chaudhary len = sprintf(buf, "%pI4\n", &ha->ip_config.gateway); 365ed1086e0SVikas Chaudhary break; 366ed1086e0SVikas Chaudhary case ISCSI_NET_PARAM_IFACE_ENABLE: 367ed1086e0SVikas Chaudhary if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) 368ed1086e0SVikas Chaudhary len = sprintf(buf, "%s\n", 369ed1086e0SVikas Chaudhary (ha->ip_config.ipv4_options & 370ed1086e0SVikas Chaudhary IPOPT_IPV4_PROTOCOL_ENABLE) ? 371ed1086e0SVikas Chaudhary "enabled" : "disabled"); 372ed1086e0SVikas Chaudhary else if (iface->iface_type == ISCSI_IFACE_TYPE_IPV6) 373ed1086e0SVikas Chaudhary len = sprintf(buf, "%s\n", 374ed1086e0SVikas Chaudhary (ha->ip_config.ipv6_options & 375ed1086e0SVikas Chaudhary IPV6_OPT_IPV6_PROTOCOL_ENABLE) ? 376ed1086e0SVikas Chaudhary "enabled" : "disabled"); 377ed1086e0SVikas Chaudhary break; 378ed1086e0SVikas Chaudhary case ISCSI_NET_PARAM_IPV4_BOOTPROTO: 379ed1086e0SVikas Chaudhary len = sprintf(buf, "%s\n", 380ed1086e0SVikas Chaudhary (ha->ip_config.tcp_options & TCPOPT_DHCP_ENABLE) ? 381ed1086e0SVikas Chaudhary "dhcp" : "static"); 382ed1086e0SVikas Chaudhary break; 383ed1086e0SVikas Chaudhary case ISCSI_NET_PARAM_IPV6_ADDR: 384ed1086e0SVikas Chaudhary if (iface->iface_num == 0) 385ed1086e0SVikas Chaudhary len = sprintf(buf, "%pI6\n", &ha->ip_config.ipv6_addr0); 386ed1086e0SVikas Chaudhary if (iface->iface_num == 1) 387ed1086e0SVikas Chaudhary len = sprintf(buf, "%pI6\n", &ha->ip_config.ipv6_addr1); 388ed1086e0SVikas Chaudhary break; 389ed1086e0SVikas Chaudhary case ISCSI_NET_PARAM_IPV6_LINKLOCAL: 390ed1086e0SVikas Chaudhary len = sprintf(buf, "%pI6\n", 391ed1086e0SVikas Chaudhary &ha->ip_config.ipv6_link_local_addr); 392ed1086e0SVikas Chaudhary break; 393ed1086e0SVikas Chaudhary case ISCSI_NET_PARAM_IPV6_ROUTER: 394ed1086e0SVikas Chaudhary len = sprintf(buf, "%pI6\n", 395ed1086e0SVikas Chaudhary &ha->ip_config.ipv6_default_router_addr); 396ed1086e0SVikas Chaudhary break; 397ed1086e0SVikas Chaudhary case ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG: 398ed1086e0SVikas Chaudhary len = sprintf(buf, "%s\n", 399ed1086e0SVikas Chaudhary (ha->ip_config.ipv6_addl_options & 400ed1086e0SVikas Chaudhary IPV6_ADDOPT_NEIGHBOR_DISCOVERY_ADDR_ENABLE) ? 401ed1086e0SVikas Chaudhary "nd" : "static"); 402ed1086e0SVikas Chaudhary break; 403ed1086e0SVikas Chaudhary case ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG: 404ed1086e0SVikas Chaudhary len = sprintf(buf, "%s\n", 405ed1086e0SVikas Chaudhary (ha->ip_config.ipv6_addl_options & 406ed1086e0SVikas Chaudhary IPV6_ADDOPT_AUTOCONFIG_LINK_LOCAL_ADDR) ? 407ed1086e0SVikas Chaudhary "auto" : "static"); 408ed1086e0SVikas Chaudhary break; 4096ac73e8cSVikas Chaudhary case ISCSI_NET_PARAM_VLAN_ID: 4106ac73e8cSVikas Chaudhary if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) 4116ac73e8cSVikas Chaudhary len = sprintf(buf, "%d\n", 4126ac73e8cSVikas Chaudhary (ha->ip_config.ipv4_vlan_tag & 4136ac73e8cSVikas Chaudhary ISCSI_MAX_VLAN_ID)); 4146ac73e8cSVikas Chaudhary else if (iface->iface_type == ISCSI_IFACE_TYPE_IPV6) 4156ac73e8cSVikas Chaudhary len = sprintf(buf, "%d\n", 4166ac73e8cSVikas Chaudhary (ha->ip_config.ipv6_vlan_tag & 4176ac73e8cSVikas Chaudhary ISCSI_MAX_VLAN_ID)); 4186ac73e8cSVikas Chaudhary break; 4196ac73e8cSVikas Chaudhary case ISCSI_NET_PARAM_VLAN_PRIORITY: 4206ac73e8cSVikas Chaudhary if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) 4216ac73e8cSVikas Chaudhary len = sprintf(buf, "%d\n", 4226ac73e8cSVikas Chaudhary ((ha->ip_config.ipv4_vlan_tag >> 13) & 4236ac73e8cSVikas Chaudhary ISCSI_MAX_VLAN_PRIORITY)); 4246ac73e8cSVikas Chaudhary else if (iface->iface_type == ISCSI_IFACE_TYPE_IPV6) 4256ac73e8cSVikas Chaudhary len = sprintf(buf, "%d\n", 4266ac73e8cSVikas Chaudhary ((ha->ip_config.ipv6_vlan_tag >> 13) & 4276ac73e8cSVikas Chaudhary ISCSI_MAX_VLAN_PRIORITY)); 4286ac73e8cSVikas Chaudhary break; 4296ac73e8cSVikas Chaudhary case ISCSI_NET_PARAM_VLAN_ENABLED: 4306ac73e8cSVikas Chaudhary if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) 4316ac73e8cSVikas Chaudhary len = sprintf(buf, "%s\n", 4326ac73e8cSVikas Chaudhary (ha->ip_config.ipv4_options & 4336ac73e8cSVikas Chaudhary IPOPT_VLAN_TAGGING_ENABLE) ? 4346ac73e8cSVikas Chaudhary "enabled" : "disabled"); 4356ac73e8cSVikas Chaudhary else if (iface->iface_type == ISCSI_IFACE_TYPE_IPV6) 4366ac73e8cSVikas Chaudhary len = sprintf(buf, "%s\n", 4376ac73e8cSVikas Chaudhary (ha->ip_config.ipv6_options & 4386ac73e8cSVikas Chaudhary IPV6_OPT_VLAN_TAGGING_ENABLE) ? 4396ac73e8cSVikas Chaudhary "enabled" : "disabled"); 4406ac73e8cSVikas Chaudhary break; 441943c157bSVikas Chaudhary case ISCSI_NET_PARAM_MTU: 442943c157bSVikas Chaudhary len = sprintf(buf, "%d\n", ha->ip_config.eth_mtu_size); 443943c157bSVikas Chaudhary break; 4442ada7fc5SVikas Chaudhary case ISCSI_NET_PARAM_PORT: 4452ada7fc5SVikas Chaudhary if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) 4462ada7fc5SVikas Chaudhary len = sprintf(buf, "%d\n", ha->ip_config.ipv4_port); 4472ada7fc5SVikas Chaudhary else if (iface->iface_type == ISCSI_IFACE_TYPE_IPV6) 4482ada7fc5SVikas Chaudhary len = sprintf(buf, "%d\n", ha->ip_config.ipv6_port); 4492ada7fc5SVikas Chaudhary break; 450ed1086e0SVikas Chaudhary default: 451ed1086e0SVikas Chaudhary len = -ENOSYS; 452ed1086e0SVikas Chaudhary } 453ed1086e0SVikas Chaudhary 454ed1086e0SVikas Chaudhary return len; 455ed1086e0SVikas Chaudhary } 456ed1086e0SVikas Chaudhary 457b3a271a9SManish Rangankar static struct iscsi_endpoint * 458b3a271a9SManish Rangankar qla4xxx_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr, 459b3a271a9SManish Rangankar int non_blocking) 460b3a271a9SManish Rangankar { 461b3a271a9SManish Rangankar int ret; 462b3a271a9SManish Rangankar struct iscsi_endpoint *ep; 463b3a271a9SManish Rangankar struct qla_endpoint *qla_ep; 464b3a271a9SManish Rangankar struct scsi_qla_host *ha; 465b3a271a9SManish Rangankar struct sockaddr_in *addr; 466b3a271a9SManish Rangankar struct sockaddr_in6 *addr6; 467b3a271a9SManish Rangankar 468b3a271a9SManish Rangankar DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); 469b3a271a9SManish Rangankar if (!shost) { 470b3a271a9SManish Rangankar ret = -ENXIO; 471b3a271a9SManish Rangankar printk(KERN_ERR "%s: shost is NULL\n", 472b3a271a9SManish Rangankar __func__); 473b3a271a9SManish Rangankar return ERR_PTR(ret); 474b3a271a9SManish Rangankar } 475b3a271a9SManish Rangankar 476b3a271a9SManish Rangankar ha = iscsi_host_priv(shost); 477b3a271a9SManish Rangankar 478b3a271a9SManish Rangankar ep = iscsi_create_endpoint(sizeof(struct qla_endpoint)); 479b3a271a9SManish Rangankar if (!ep) { 480b3a271a9SManish Rangankar ret = -ENOMEM; 481b3a271a9SManish Rangankar return ERR_PTR(ret); 482b3a271a9SManish Rangankar } 483b3a271a9SManish Rangankar 484b3a271a9SManish Rangankar qla_ep = ep->dd_data; 485b3a271a9SManish Rangankar memset(qla_ep, 0, sizeof(struct qla_endpoint)); 486b3a271a9SManish Rangankar if (dst_addr->sa_family == AF_INET) { 487b3a271a9SManish Rangankar memcpy(&qla_ep->dst_addr, dst_addr, sizeof(struct sockaddr_in)); 488b3a271a9SManish Rangankar addr = (struct sockaddr_in *)&qla_ep->dst_addr; 489b3a271a9SManish Rangankar DEBUG2(ql4_printk(KERN_INFO, ha, "%s: %pI4\n", __func__, 490b3a271a9SManish Rangankar (char *)&addr->sin_addr)); 491b3a271a9SManish Rangankar } else if (dst_addr->sa_family == AF_INET6) { 492b3a271a9SManish Rangankar memcpy(&qla_ep->dst_addr, dst_addr, 493b3a271a9SManish Rangankar sizeof(struct sockaddr_in6)); 494b3a271a9SManish Rangankar addr6 = (struct sockaddr_in6 *)&qla_ep->dst_addr; 495b3a271a9SManish Rangankar DEBUG2(ql4_printk(KERN_INFO, ha, "%s: %pI6\n", __func__, 496b3a271a9SManish Rangankar (char *)&addr6->sin6_addr)); 497b3a271a9SManish Rangankar } 498b3a271a9SManish Rangankar 499b3a271a9SManish Rangankar qla_ep->host = shost; 500b3a271a9SManish Rangankar 501b3a271a9SManish Rangankar return ep; 502b3a271a9SManish Rangankar } 503b3a271a9SManish Rangankar 504b3a271a9SManish Rangankar static int qla4xxx_ep_poll(struct iscsi_endpoint *ep, int timeout_ms) 505b3a271a9SManish Rangankar { 506b3a271a9SManish Rangankar struct qla_endpoint *qla_ep; 507b3a271a9SManish Rangankar struct scsi_qla_host *ha; 508b3a271a9SManish Rangankar int ret = 0; 509b3a271a9SManish Rangankar 510b3a271a9SManish Rangankar DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); 511b3a271a9SManish Rangankar qla_ep = ep->dd_data; 512b3a271a9SManish Rangankar ha = to_qla_host(qla_ep->host); 513b3a271a9SManish Rangankar 51413483730SMike Christie if (adapter_up(ha) && !test_bit(AF_BUILD_DDB_LIST, &ha->flags)) 515b3a271a9SManish Rangankar ret = 1; 516b3a271a9SManish Rangankar 517b3a271a9SManish Rangankar return ret; 518b3a271a9SManish Rangankar } 519b3a271a9SManish Rangankar 520b3a271a9SManish Rangankar static void qla4xxx_ep_disconnect(struct iscsi_endpoint *ep) 521b3a271a9SManish Rangankar { 522b3a271a9SManish Rangankar DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); 523b3a271a9SManish Rangankar iscsi_destroy_endpoint(ep); 524b3a271a9SManish Rangankar } 525b3a271a9SManish Rangankar 526b3a271a9SManish Rangankar static int qla4xxx_get_ep_param(struct iscsi_endpoint *ep, 527b3a271a9SManish Rangankar enum iscsi_param param, 528b3a271a9SManish Rangankar char *buf) 529b3a271a9SManish Rangankar { 530b3a271a9SManish Rangankar struct qla_endpoint *qla_ep = ep->dd_data; 531b3a271a9SManish Rangankar struct sockaddr *dst_addr; 532b3a271a9SManish Rangankar 533b3a271a9SManish Rangankar DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); 534b3a271a9SManish Rangankar 535b3a271a9SManish Rangankar switch (param) { 536b3a271a9SManish Rangankar case ISCSI_PARAM_CONN_PORT: 537b3a271a9SManish Rangankar case ISCSI_PARAM_CONN_ADDRESS: 538b3a271a9SManish Rangankar if (!qla_ep) 539b3a271a9SManish Rangankar return -ENOTCONN; 540b3a271a9SManish Rangankar 541b3a271a9SManish Rangankar dst_addr = (struct sockaddr *)&qla_ep->dst_addr; 542b3a271a9SManish Rangankar if (!dst_addr) 543b3a271a9SManish Rangankar return -ENOTCONN; 544b3a271a9SManish Rangankar 545b3a271a9SManish Rangankar return iscsi_conn_get_addr_param((struct sockaddr_storage *) 546b3a271a9SManish Rangankar &qla_ep->dst_addr, param, buf); 547b3a271a9SManish Rangankar default: 548b3a271a9SManish Rangankar return -ENOSYS; 549b3a271a9SManish Rangankar } 550b3a271a9SManish Rangankar } 551b3a271a9SManish Rangankar 552b3a271a9SManish Rangankar static void qla4xxx_conn_get_stats(struct iscsi_cls_conn *cls_conn, 553b3a271a9SManish Rangankar struct iscsi_stats *stats) 554b3a271a9SManish Rangankar { 555b3a271a9SManish Rangankar struct iscsi_session *sess; 556b3a271a9SManish Rangankar struct iscsi_cls_session *cls_sess; 557b3a271a9SManish Rangankar struct ddb_entry *ddb_entry; 558b3a271a9SManish Rangankar struct scsi_qla_host *ha; 559b3a271a9SManish Rangankar struct ql_iscsi_stats *ql_iscsi_stats; 560b3a271a9SManish Rangankar int stats_size; 561b3a271a9SManish Rangankar int ret; 562b3a271a9SManish Rangankar dma_addr_t iscsi_stats_dma; 563b3a271a9SManish Rangankar 564b3a271a9SManish Rangankar DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); 565b3a271a9SManish Rangankar 566b3a271a9SManish Rangankar cls_sess = iscsi_conn_to_session(cls_conn); 567b3a271a9SManish Rangankar sess = cls_sess->dd_data; 568b3a271a9SManish Rangankar ddb_entry = sess->dd_data; 569b3a271a9SManish Rangankar ha = ddb_entry->ha; 570b3a271a9SManish Rangankar 571b3a271a9SManish Rangankar stats_size = PAGE_ALIGN(sizeof(struct ql_iscsi_stats)); 572b3a271a9SManish Rangankar /* Allocate memory */ 573b3a271a9SManish Rangankar ql_iscsi_stats = dma_alloc_coherent(&ha->pdev->dev, stats_size, 574b3a271a9SManish Rangankar &iscsi_stats_dma, GFP_KERNEL); 575b3a271a9SManish Rangankar if (!ql_iscsi_stats) { 576b3a271a9SManish Rangankar ql4_printk(KERN_ERR, ha, 577b3a271a9SManish Rangankar "Unable to allocate memory for iscsi stats\n"); 578b3a271a9SManish Rangankar goto exit_get_stats; 579b3a271a9SManish Rangankar } 580b3a271a9SManish Rangankar 581b3a271a9SManish Rangankar ret = qla4xxx_get_mgmt_data(ha, ddb_entry->fw_ddb_index, stats_size, 582b3a271a9SManish Rangankar iscsi_stats_dma); 583b3a271a9SManish Rangankar if (ret != QLA_SUCCESS) { 584b3a271a9SManish Rangankar ql4_printk(KERN_ERR, ha, 585b3a271a9SManish Rangankar "Unable to retreive iscsi stats\n"); 586b3a271a9SManish Rangankar goto free_stats; 587b3a271a9SManish Rangankar } 588b3a271a9SManish Rangankar 589b3a271a9SManish Rangankar /* octets */ 590b3a271a9SManish Rangankar stats->txdata_octets = le64_to_cpu(ql_iscsi_stats->tx_data_octets); 591b3a271a9SManish Rangankar stats->rxdata_octets = le64_to_cpu(ql_iscsi_stats->rx_data_octets); 592b3a271a9SManish Rangankar /* xmit pdus */ 593b3a271a9SManish Rangankar stats->noptx_pdus = le32_to_cpu(ql_iscsi_stats->tx_nopout_pdus); 594b3a271a9SManish Rangankar stats->scsicmd_pdus = le32_to_cpu(ql_iscsi_stats->tx_scsi_cmd_pdus); 595b3a271a9SManish Rangankar stats->tmfcmd_pdus = le32_to_cpu(ql_iscsi_stats->tx_tmf_cmd_pdus); 596b3a271a9SManish Rangankar stats->login_pdus = le32_to_cpu(ql_iscsi_stats->tx_login_cmd_pdus); 597b3a271a9SManish Rangankar stats->text_pdus = le32_to_cpu(ql_iscsi_stats->tx_text_cmd_pdus); 598b3a271a9SManish Rangankar stats->dataout_pdus = le32_to_cpu(ql_iscsi_stats->tx_scsi_write_pdus); 599b3a271a9SManish Rangankar stats->logout_pdus = le32_to_cpu(ql_iscsi_stats->tx_logout_cmd_pdus); 600b3a271a9SManish Rangankar stats->snack_pdus = le32_to_cpu(ql_iscsi_stats->tx_snack_req_pdus); 601b3a271a9SManish Rangankar /* recv pdus */ 602b3a271a9SManish Rangankar stats->noprx_pdus = le32_to_cpu(ql_iscsi_stats->rx_nopin_pdus); 603b3a271a9SManish Rangankar stats->scsirsp_pdus = le32_to_cpu(ql_iscsi_stats->rx_scsi_resp_pdus); 604b3a271a9SManish Rangankar stats->tmfrsp_pdus = le32_to_cpu(ql_iscsi_stats->rx_tmf_resp_pdus); 605b3a271a9SManish Rangankar stats->textrsp_pdus = le32_to_cpu(ql_iscsi_stats->rx_text_resp_pdus); 606b3a271a9SManish Rangankar stats->datain_pdus = le32_to_cpu(ql_iscsi_stats->rx_scsi_read_pdus); 607b3a271a9SManish Rangankar stats->logoutrsp_pdus = 608b3a271a9SManish Rangankar le32_to_cpu(ql_iscsi_stats->rx_logout_resp_pdus); 609b3a271a9SManish Rangankar stats->r2t_pdus = le32_to_cpu(ql_iscsi_stats->rx_r2t_pdus); 610b3a271a9SManish Rangankar stats->async_pdus = le32_to_cpu(ql_iscsi_stats->rx_async_pdus); 611b3a271a9SManish Rangankar stats->rjt_pdus = le32_to_cpu(ql_iscsi_stats->rx_reject_pdus); 612b3a271a9SManish Rangankar 613b3a271a9SManish Rangankar free_stats: 614b3a271a9SManish Rangankar dma_free_coherent(&ha->pdev->dev, stats_size, ql_iscsi_stats, 615b3a271a9SManish Rangankar iscsi_stats_dma); 616b3a271a9SManish Rangankar exit_get_stats: 617b3a271a9SManish Rangankar return; 618b3a271a9SManish Rangankar } 619b3a271a9SManish Rangankar 6205c656af7SMike Christie static enum blk_eh_timer_return qla4xxx_eh_cmd_timed_out(struct scsi_cmnd *sc) 6215c656af7SMike Christie { 6225c656af7SMike Christie struct iscsi_cls_session *session; 623b3a271a9SManish Rangankar struct iscsi_session *sess; 624b3a271a9SManish Rangankar unsigned long flags; 625b3a271a9SManish Rangankar enum blk_eh_timer_return ret = BLK_EH_NOT_HANDLED; 6265c656af7SMike Christie 6275c656af7SMike Christie session = starget_to_session(scsi_target(sc->device)); 628b3a271a9SManish Rangankar sess = session->dd_data; 6295c656af7SMike Christie 630b3a271a9SManish Rangankar spin_lock_irqsave(&session->lock, flags); 631b3a271a9SManish Rangankar if (session->state == ISCSI_SESSION_FAILED) 632b3a271a9SManish Rangankar ret = BLK_EH_RESET_TIMER; 633b3a271a9SManish Rangankar spin_unlock_irqrestore(&session->lock, flags); 6345c656af7SMike Christie 635b3a271a9SManish Rangankar return ret; 636568d303bSMike Christie } 637afaf5a2dSDavid Somayajulu 6383254dbe9SVikas Chaudhary static void qla4xxx_set_port_speed(struct Scsi_Host *shost) 6393254dbe9SVikas Chaudhary { 6403254dbe9SVikas Chaudhary struct scsi_qla_host *ha = to_qla_host(shost); 6413254dbe9SVikas Chaudhary struct iscsi_cls_host *ihost = shost_priv(shost); 6423254dbe9SVikas Chaudhary uint32_t speed = ISCSI_PORT_SPEED_UNKNOWN; 6433254dbe9SVikas Chaudhary 6443254dbe9SVikas Chaudhary qla4xxx_get_firmware_state(ha); 6453254dbe9SVikas Chaudhary 6463254dbe9SVikas Chaudhary switch (ha->addl_fw_state & 0x0F00) { 6473254dbe9SVikas Chaudhary case FW_ADDSTATE_LINK_SPEED_10MBPS: 6483254dbe9SVikas Chaudhary speed = ISCSI_PORT_SPEED_10MBPS; 6493254dbe9SVikas Chaudhary break; 6503254dbe9SVikas Chaudhary case FW_ADDSTATE_LINK_SPEED_100MBPS: 6513254dbe9SVikas Chaudhary speed = ISCSI_PORT_SPEED_100MBPS; 6523254dbe9SVikas Chaudhary break; 6533254dbe9SVikas Chaudhary case FW_ADDSTATE_LINK_SPEED_1GBPS: 6543254dbe9SVikas Chaudhary speed = ISCSI_PORT_SPEED_1GBPS; 6553254dbe9SVikas Chaudhary break; 6563254dbe9SVikas Chaudhary case FW_ADDSTATE_LINK_SPEED_10GBPS: 6573254dbe9SVikas Chaudhary speed = ISCSI_PORT_SPEED_10GBPS; 6583254dbe9SVikas Chaudhary break; 6593254dbe9SVikas Chaudhary } 6603254dbe9SVikas Chaudhary ihost->port_speed = speed; 6613254dbe9SVikas Chaudhary } 6623254dbe9SVikas Chaudhary 6633254dbe9SVikas Chaudhary static void qla4xxx_set_port_state(struct Scsi_Host *shost) 6643254dbe9SVikas Chaudhary { 6653254dbe9SVikas Chaudhary struct scsi_qla_host *ha = to_qla_host(shost); 6663254dbe9SVikas Chaudhary struct iscsi_cls_host *ihost = shost_priv(shost); 6673254dbe9SVikas Chaudhary uint32_t state = ISCSI_PORT_STATE_DOWN; 6683254dbe9SVikas Chaudhary 6693254dbe9SVikas Chaudhary if (test_bit(AF_LINK_UP, &ha->flags)) 6703254dbe9SVikas Chaudhary state = ISCSI_PORT_STATE_UP; 6713254dbe9SVikas Chaudhary 6723254dbe9SVikas Chaudhary ihost->port_state = state; 6733254dbe9SVikas Chaudhary } 6743254dbe9SVikas Chaudhary 675aa1e93a2SMike Christie static int qla4xxx_host_get_param(struct Scsi_Host *shost, 676aa1e93a2SMike Christie enum iscsi_host_param param, char *buf) 677aa1e93a2SMike Christie { 678aa1e93a2SMike Christie struct scsi_qla_host *ha = to_qla_host(shost); 679aa1e93a2SMike Christie int len; 680aa1e93a2SMike Christie 681aa1e93a2SMike Christie switch (param) { 682aa1e93a2SMike Christie case ISCSI_HOST_PARAM_HWADDRESS: 6837ffc49a6SMichael Chan len = sysfs_format_mac(buf, ha->my_mac, MAC_ADDR_LEN); 684aa1e93a2SMike Christie break; 68522236961SMike Christie case ISCSI_HOST_PARAM_IPADDRESS: 6862bab08fcSVikas Chaudhary len = sprintf(buf, "%pI4\n", &ha->ip_config.ip_address); 68722236961SMike Christie break; 6888ad5781aSMike Christie case ISCSI_HOST_PARAM_INITIATOR_NAME: 68922236961SMike Christie len = sprintf(buf, "%s\n", ha->name_string); 6908ad5781aSMike Christie break; 6913254dbe9SVikas Chaudhary case ISCSI_HOST_PARAM_PORT_STATE: 6923254dbe9SVikas Chaudhary qla4xxx_set_port_state(shost); 6933254dbe9SVikas Chaudhary len = sprintf(buf, "%s\n", iscsi_get_port_state_name(shost)); 6943254dbe9SVikas Chaudhary break; 6953254dbe9SVikas Chaudhary case ISCSI_HOST_PARAM_PORT_SPEED: 6963254dbe9SVikas Chaudhary qla4xxx_set_port_speed(shost); 6973254dbe9SVikas Chaudhary len = sprintf(buf, "%s\n", iscsi_get_port_speed_name(shost)); 6983254dbe9SVikas Chaudhary break; 699aa1e93a2SMike Christie default: 700aa1e93a2SMike Christie return -ENOSYS; 701aa1e93a2SMike Christie } 702aa1e93a2SMike Christie 703aa1e93a2SMike Christie return len; 704aa1e93a2SMike Christie } 705aa1e93a2SMike Christie 706ed1086e0SVikas Chaudhary static void qla4xxx_create_ipv4_iface(struct scsi_qla_host *ha) 707ed1086e0SVikas Chaudhary { 708ed1086e0SVikas Chaudhary if (ha->iface_ipv4) 709ed1086e0SVikas Chaudhary return; 710ed1086e0SVikas Chaudhary 711ed1086e0SVikas Chaudhary /* IPv4 */ 712ed1086e0SVikas Chaudhary ha->iface_ipv4 = iscsi_create_iface(ha->host, 713ed1086e0SVikas Chaudhary &qla4xxx_iscsi_transport, 714ed1086e0SVikas Chaudhary ISCSI_IFACE_TYPE_IPV4, 0, 0); 715ed1086e0SVikas Chaudhary if (!ha->iface_ipv4) 716ed1086e0SVikas Chaudhary ql4_printk(KERN_ERR, ha, "Could not create IPv4 iSCSI " 717ed1086e0SVikas Chaudhary "iface0.\n"); 718ed1086e0SVikas Chaudhary } 719ed1086e0SVikas Chaudhary 720ed1086e0SVikas Chaudhary static void qla4xxx_create_ipv6_iface(struct scsi_qla_host *ha) 721ed1086e0SVikas Chaudhary { 722ed1086e0SVikas Chaudhary if (!ha->iface_ipv6_0) 723ed1086e0SVikas Chaudhary /* IPv6 iface-0 */ 724ed1086e0SVikas Chaudhary ha->iface_ipv6_0 = iscsi_create_iface(ha->host, 725ed1086e0SVikas Chaudhary &qla4xxx_iscsi_transport, 726ed1086e0SVikas Chaudhary ISCSI_IFACE_TYPE_IPV6, 0, 727ed1086e0SVikas Chaudhary 0); 728ed1086e0SVikas Chaudhary if (!ha->iface_ipv6_0) 729ed1086e0SVikas Chaudhary ql4_printk(KERN_ERR, ha, "Could not create IPv6 iSCSI " 730ed1086e0SVikas Chaudhary "iface0.\n"); 731ed1086e0SVikas Chaudhary 732ed1086e0SVikas Chaudhary if (!ha->iface_ipv6_1) 733ed1086e0SVikas Chaudhary /* IPv6 iface-1 */ 734ed1086e0SVikas Chaudhary ha->iface_ipv6_1 = iscsi_create_iface(ha->host, 735ed1086e0SVikas Chaudhary &qla4xxx_iscsi_transport, 736ed1086e0SVikas Chaudhary ISCSI_IFACE_TYPE_IPV6, 1, 737ed1086e0SVikas Chaudhary 0); 738ed1086e0SVikas Chaudhary if (!ha->iface_ipv6_1) 739ed1086e0SVikas Chaudhary ql4_printk(KERN_ERR, ha, "Could not create IPv6 iSCSI " 740ed1086e0SVikas Chaudhary "iface1.\n"); 741ed1086e0SVikas Chaudhary } 742ed1086e0SVikas Chaudhary 743ed1086e0SVikas Chaudhary static void qla4xxx_create_ifaces(struct scsi_qla_host *ha) 744ed1086e0SVikas Chaudhary { 745ed1086e0SVikas Chaudhary if (ha->ip_config.ipv4_options & IPOPT_IPV4_PROTOCOL_ENABLE) 746ed1086e0SVikas Chaudhary qla4xxx_create_ipv4_iface(ha); 747ed1086e0SVikas Chaudhary 748ed1086e0SVikas Chaudhary if (ha->ip_config.ipv6_options & IPV6_OPT_IPV6_PROTOCOL_ENABLE) 749ed1086e0SVikas Chaudhary qla4xxx_create_ipv6_iface(ha); 750ed1086e0SVikas Chaudhary } 751ed1086e0SVikas Chaudhary 752ed1086e0SVikas Chaudhary static void qla4xxx_destroy_ipv4_iface(struct scsi_qla_host *ha) 753ed1086e0SVikas Chaudhary { 754ed1086e0SVikas Chaudhary if (ha->iface_ipv4) { 755ed1086e0SVikas Chaudhary iscsi_destroy_iface(ha->iface_ipv4); 756ed1086e0SVikas Chaudhary ha->iface_ipv4 = NULL; 757ed1086e0SVikas Chaudhary } 758ed1086e0SVikas Chaudhary } 759ed1086e0SVikas Chaudhary 760ed1086e0SVikas Chaudhary static void qla4xxx_destroy_ipv6_iface(struct scsi_qla_host *ha) 761ed1086e0SVikas Chaudhary { 762ed1086e0SVikas Chaudhary if (ha->iface_ipv6_0) { 763ed1086e0SVikas Chaudhary iscsi_destroy_iface(ha->iface_ipv6_0); 764ed1086e0SVikas Chaudhary ha->iface_ipv6_0 = NULL; 765ed1086e0SVikas Chaudhary } 766ed1086e0SVikas Chaudhary if (ha->iface_ipv6_1) { 767ed1086e0SVikas Chaudhary iscsi_destroy_iface(ha->iface_ipv6_1); 768ed1086e0SVikas Chaudhary ha->iface_ipv6_1 = NULL; 769ed1086e0SVikas Chaudhary } 770ed1086e0SVikas Chaudhary } 771ed1086e0SVikas Chaudhary 772ed1086e0SVikas Chaudhary static void qla4xxx_destroy_ifaces(struct scsi_qla_host *ha) 773ed1086e0SVikas Chaudhary { 774ed1086e0SVikas Chaudhary qla4xxx_destroy_ipv4_iface(ha); 775ed1086e0SVikas Chaudhary qla4xxx_destroy_ipv6_iface(ha); 776ed1086e0SVikas Chaudhary } 777ed1086e0SVikas Chaudhary 778d00efe3fSMike Christie static void qla4xxx_set_ipv6(struct scsi_qla_host *ha, 779d00efe3fSMike Christie struct iscsi_iface_param_info *iface_param, 780d00efe3fSMike Christie struct addr_ctrl_blk *init_fw_cb) 781d00efe3fSMike Christie { 782d00efe3fSMike Christie /* 783d00efe3fSMike Christie * iface_num 0 is valid for IPv6 Addr, linklocal, router, autocfg. 784d00efe3fSMike Christie * iface_num 1 is valid only for IPv6 Addr. 785d00efe3fSMike Christie */ 786d00efe3fSMike Christie switch (iface_param->param) { 787d00efe3fSMike Christie case ISCSI_NET_PARAM_IPV6_ADDR: 788d00efe3fSMike Christie if (iface_param->iface_num & 0x1) 789d00efe3fSMike Christie /* IPv6 Addr 1 */ 790d00efe3fSMike Christie memcpy(init_fw_cb->ipv6_addr1, iface_param->value, 791d00efe3fSMike Christie sizeof(init_fw_cb->ipv6_addr1)); 792d00efe3fSMike Christie else 793d00efe3fSMike Christie /* IPv6 Addr 0 */ 794d00efe3fSMike Christie memcpy(init_fw_cb->ipv6_addr0, iface_param->value, 795d00efe3fSMike Christie sizeof(init_fw_cb->ipv6_addr0)); 796d00efe3fSMike Christie break; 797d00efe3fSMike Christie case ISCSI_NET_PARAM_IPV6_LINKLOCAL: 798d00efe3fSMike Christie if (iface_param->iface_num & 0x1) 799d00efe3fSMike Christie break; 800d00efe3fSMike Christie memcpy(init_fw_cb->ipv6_if_id, &iface_param->value[8], 801d00efe3fSMike Christie sizeof(init_fw_cb->ipv6_if_id)); 802d00efe3fSMike Christie break; 803d00efe3fSMike Christie case ISCSI_NET_PARAM_IPV6_ROUTER: 804d00efe3fSMike Christie if (iface_param->iface_num & 0x1) 805d00efe3fSMike Christie break; 806d00efe3fSMike Christie memcpy(init_fw_cb->ipv6_dflt_rtr_addr, iface_param->value, 807d00efe3fSMike Christie sizeof(init_fw_cb->ipv6_dflt_rtr_addr)); 808d00efe3fSMike Christie break; 809d00efe3fSMike Christie case ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG: 810d00efe3fSMike Christie /* Autocfg applies to even interface */ 811d00efe3fSMike Christie if (iface_param->iface_num & 0x1) 812d00efe3fSMike Christie break; 813d00efe3fSMike Christie 814d00efe3fSMike Christie if (iface_param->value[0] == ISCSI_IPV6_AUTOCFG_DISABLE) 815d00efe3fSMike Christie init_fw_cb->ipv6_addtl_opts &= 816d00efe3fSMike Christie cpu_to_le16( 817d00efe3fSMike Christie ~IPV6_ADDOPT_NEIGHBOR_DISCOVERY_ADDR_ENABLE); 818d00efe3fSMike Christie else if (iface_param->value[0] == ISCSI_IPV6_AUTOCFG_ND_ENABLE) 819d00efe3fSMike Christie init_fw_cb->ipv6_addtl_opts |= 820d00efe3fSMike Christie cpu_to_le16( 821d00efe3fSMike Christie IPV6_ADDOPT_NEIGHBOR_DISCOVERY_ADDR_ENABLE); 822d00efe3fSMike Christie else 823d00efe3fSMike Christie ql4_printk(KERN_ERR, ha, "Invalid autocfg setting for " 824d00efe3fSMike Christie "IPv6 addr\n"); 825d00efe3fSMike Christie break; 826d00efe3fSMike Christie case ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG: 827d00efe3fSMike Christie /* Autocfg applies to even interface */ 828d00efe3fSMike Christie if (iface_param->iface_num & 0x1) 829d00efe3fSMike Christie break; 830d00efe3fSMike Christie 831d00efe3fSMike Christie if (iface_param->value[0] == 832d00efe3fSMike Christie ISCSI_IPV6_LINKLOCAL_AUTOCFG_ENABLE) 833d00efe3fSMike Christie init_fw_cb->ipv6_addtl_opts |= cpu_to_le16( 834d00efe3fSMike Christie IPV6_ADDOPT_AUTOCONFIG_LINK_LOCAL_ADDR); 835d00efe3fSMike Christie else if (iface_param->value[0] == 836d00efe3fSMike Christie ISCSI_IPV6_LINKLOCAL_AUTOCFG_DISABLE) 837d00efe3fSMike Christie init_fw_cb->ipv6_addtl_opts &= cpu_to_le16( 838d00efe3fSMike Christie ~IPV6_ADDOPT_AUTOCONFIG_LINK_LOCAL_ADDR); 839d00efe3fSMike Christie else 840d00efe3fSMike Christie ql4_printk(KERN_ERR, ha, "Invalid autocfg setting for " 841d00efe3fSMike Christie "IPv6 linklocal addr\n"); 842d00efe3fSMike Christie break; 843d00efe3fSMike Christie case ISCSI_NET_PARAM_IPV6_ROUTER_AUTOCFG: 844d00efe3fSMike Christie /* Autocfg applies to even interface */ 845d00efe3fSMike Christie if (iface_param->iface_num & 0x1) 846d00efe3fSMike Christie break; 847d00efe3fSMike Christie 848d00efe3fSMike Christie if (iface_param->value[0] == ISCSI_IPV6_ROUTER_AUTOCFG_ENABLE) 849d00efe3fSMike Christie memset(init_fw_cb->ipv6_dflt_rtr_addr, 0, 850d00efe3fSMike Christie sizeof(init_fw_cb->ipv6_dflt_rtr_addr)); 851d00efe3fSMike Christie break; 852d00efe3fSMike Christie case ISCSI_NET_PARAM_IFACE_ENABLE: 853ed1086e0SVikas Chaudhary if (iface_param->value[0] == ISCSI_IFACE_ENABLE) { 854d00efe3fSMike Christie init_fw_cb->ipv6_opts |= 855d00efe3fSMike Christie cpu_to_le16(IPV6_OPT_IPV6_PROTOCOL_ENABLE); 856ed1086e0SVikas Chaudhary qla4xxx_create_ipv6_iface(ha); 857ed1086e0SVikas Chaudhary } else { 858d00efe3fSMike Christie init_fw_cb->ipv6_opts &= 859d00efe3fSMike Christie cpu_to_le16(~IPV6_OPT_IPV6_PROTOCOL_ENABLE & 860d00efe3fSMike Christie 0xFFFF); 861ed1086e0SVikas Chaudhary qla4xxx_destroy_ipv6_iface(ha); 862ed1086e0SVikas Chaudhary } 863d00efe3fSMike Christie break; 8642d63673bSMike Christie case ISCSI_NET_PARAM_VLAN_TAG: 865d00efe3fSMike Christie if (iface_param->len != sizeof(init_fw_cb->ipv6_vlan_tag)) 866d00efe3fSMike Christie break; 8676ac73e8cSVikas Chaudhary init_fw_cb->ipv6_vlan_tag = 8686ac73e8cSVikas Chaudhary cpu_to_be16(*(uint16_t *)iface_param->value); 8696ac73e8cSVikas Chaudhary break; 8706ac73e8cSVikas Chaudhary case ISCSI_NET_PARAM_VLAN_ENABLED: 8716ac73e8cSVikas Chaudhary if (iface_param->value[0] == ISCSI_VLAN_ENABLE) 8726ac73e8cSVikas Chaudhary init_fw_cb->ipv6_opts |= 8736ac73e8cSVikas Chaudhary cpu_to_le16(IPV6_OPT_VLAN_TAGGING_ENABLE); 8746ac73e8cSVikas Chaudhary else 8756ac73e8cSVikas Chaudhary init_fw_cb->ipv6_opts &= 8766ac73e8cSVikas Chaudhary cpu_to_le16(~IPV6_OPT_VLAN_TAGGING_ENABLE); 877d00efe3fSMike Christie break; 878943c157bSVikas Chaudhary case ISCSI_NET_PARAM_MTU: 879943c157bSVikas Chaudhary init_fw_cb->eth_mtu_size = 880943c157bSVikas Chaudhary cpu_to_le16(*(uint16_t *)iface_param->value); 881943c157bSVikas Chaudhary break; 8822ada7fc5SVikas Chaudhary case ISCSI_NET_PARAM_PORT: 8832ada7fc5SVikas Chaudhary /* Autocfg applies to even interface */ 8842ada7fc5SVikas Chaudhary if (iface_param->iface_num & 0x1) 8852ada7fc5SVikas Chaudhary break; 8862ada7fc5SVikas Chaudhary 8872ada7fc5SVikas Chaudhary init_fw_cb->ipv6_port = 8882ada7fc5SVikas Chaudhary cpu_to_le16(*(uint16_t *)iface_param->value); 8892ada7fc5SVikas Chaudhary break; 890d00efe3fSMike Christie default: 891d00efe3fSMike Christie ql4_printk(KERN_ERR, ha, "Unknown IPv6 param = %d\n", 892d00efe3fSMike Christie iface_param->param); 893d00efe3fSMike Christie break; 894d00efe3fSMike Christie } 895d00efe3fSMike Christie } 896d00efe3fSMike Christie 897d00efe3fSMike Christie static void qla4xxx_set_ipv4(struct scsi_qla_host *ha, 898d00efe3fSMike Christie struct iscsi_iface_param_info *iface_param, 899d00efe3fSMike Christie struct addr_ctrl_blk *init_fw_cb) 900d00efe3fSMike Christie { 901d00efe3fSMike Christie switch (iface_param->param) { 902d00efe3fSMike Christie case ISCSI_NET_PARAM_IPV4_ADDR: 903d00efe3fSMike Christie memcpy(init_fw_cb->ipv4_addr, iface_param->value, 904d00efe3fSMike Christie sizeof(init_fw_cb->ipv4_addr)); 905d00efe3fSMike Christie break; 906d00efe3fSMike Christie case ISCSI_NET_PARAM_IPV4_SUBNET: 907d00efe3fSMike Christie memcpy(init_fw_cb->ipv4_subnet, iface_param->value, 908d00efe3fSMike Christie sizeof(init_fw_cb->ipv4_subnet)); 909d00efe3fSMike Christie break; 910d00efe3fSMike Christie case ISCSI_NET_PARAM_IPV4_GW: 911d00efe3fSMike Christie memcpy(init_fw_cb->ipv4_gw_addr, iface_param->value, 912d00efe3fSMike Christie sizeof(init_fw_cb->ipv4_gw_addr)); 913d00efe3fSMike Christie break; 914d00efe3fSMike Christie case ISCSI_NET_PARAM_IPV4_BOOTPROTO: 915d00efe3fSMike Christie if (iface_param->value[0] == ISCSI_BOOTPROTO_DHCP) 916d00efe3fSMike Christie init_fw_cb->ipv4_tcp_opts |= 917d00efe3fSMike Christie cpu_to_le16(TCPOPT_DHCP_ENABLE); 918d00efe3fSMike Christie else if (iface_param->value[0] == ISCSI_BOOTPROTO_STATIC) 919d00efe3fSMike Christie init_fw_cb->ipv4_tcp_opts &= 920d00efe3fSMike Christie cpu_to_le16(~TCPOPT_DHCP_ENABLE); 921d00efe3fSMike Christie else 922d00efe3fSMike Christie ql4_printk(KERN_ERR, ha, "Invalid IPv4 bootproto\n"); 923d00efe3fSMike Christie break; 924d00efe3fSMike Christie case ISCSI_NET_PARAM_IFACE_ENABLE: 925ed1086e0SVikas Chaudhary if (iface_param->value[0] == ISCSI_IFACE_ENABLE) { 926d00efe3fSMike Christie init_fw_cb->ipv4_ip_opts |= 9272bab08fcSVikas Chaudhary cpu_to_le16(IPOPT_IPV4_PROTOCOL_ENABLE); 928ed1086e0SVikas Chaudhary qla4xxx_create_ipv4_iface(ha); 929ed1086e0SVikas Chaudhary } else { 930d00efe3fSMike Christie init_fw_cb->ipv4_ip_opts &= 9312bab08fcSVikas Chaudhary cpu_to_le16(~IPOPT_IPV4_PROTOCOL_ENABLE & 932d00efe3fSMike Christie 0xFFFF); 933ed1086e0SVikas Chaudhary qla4xxx_destroy_ipv4_iface(ha); 934ed1086e0SVikas Chaudhary } 935d00efe3fSMike Christie break; 9362d63673bSMike Christie case ISCSI_NET_PARAM_VLAN_TAG: 937d00efe3fSMike Christie if (iface_param->len != sizeof(init_fw_cb->ipv4_vlan_tag)) 938d00efe3fSMike Christie break; 9396ac73e8cSVikas Chaudhary init_fw_cb->ipv4_vlan_tag = 9406ac73e8cSVikas Chaudhary cpu_to_be16(*(uint16_t *)iface_param->value); 9416ac73e8cSVikas Chaudhary break; 9426ac73e8cSVikas Chaudhary case ISCSI_NET_PARAM_VLAN_ENABLED: 9436ac73e8cSVikas Chaudhary if (iface_param->value[0] == ISCSI_VLAN_ENABLE) 9446ac73e8cSVikas Chaudhary init_fw_cb->ipv4_ip_opts |= 9456ac73e8cSVikas Chaudhary cpu_to_le16(IPOPT_VLAN_TAGGING_ENABLE); 9466ac73e8cSVikas Chaudhary else 9476ac73e8cSVikas Chaudhary init_fw_cb->ipv4_ip_opts &= 9486ac73e8cSVikas Chaudhary cpu_to_le16(~IPOPT_VLAN_TAGGING_ENABLE); 949d00efe3fSMike Christie break; 950943c157bSVikas Chaudhary case ISCSI_NET_PARAM_MTU: 951943c157bSVikas Chaudhary init_fw_cb->eth_mtu_size = 952943c157bSVikas Chaudhary cpu_to_le16(*(uint16_t *)iface_param->value); 953943c157bSVikas Chaudhary break; 9542ada7fc5SVikas Chaudhary case ISCSI_NET_PARAM_PORT: 9552ada7fc5SVikas Chaudhary init_fw_cb->ipv4_port = 9562ada7fc5SVikas Chaudhary cpu_to_le16(*(uint16_t *)iface_param->value); 9572ada7fc5SVikas Chaudhary break; 958d00efe3fSMike Christie default: 959d00efe3fSMike Christie ql4_printk(KERN_ERR, ha, "Unknown IPv4 param = %d\n", 960d00efe3fSMike Christie iface_param->param); 961d00efe3fSMike Christie break; 962d00efe3fSMike Christie } 963d00efe3fSMike Christie } 964d00efe3fSMike Christie 965d00efe3fSMike Christie static void 966d00efe3fSMike Christie qla4xxx_initcb_to_acb(struct addr_ctrl_blk *init_fw_cb) 967d00efe3fSMike Christie { 968d00efe3fSMike Christie struct addr_ctrl_blk_def *acb; 969d00efe3fSMike Christie acb = (struct addr_ctrl_blk_def *)init_fw_cb; 970d00efe3fSMike Christie memset(acb->reserved1, 0, sizeof(acb->reserved1)); 971d00efe3fSMike Christie memset(acb->reserved2, 0, sizeof(acb->reserved2)); 972d00efe3fSMike Christie memset(acb->reserved3, 0, sizeof(acb->reserved3)); 973d00efe3fSMike Christie memset(acb->reserved4, 0, sizeof(acb->reserved4)); 974d00efe3fSMike Christie memset(acb->reserved5, 0, sizeof(acb->reserved5)); 975d00efe3fSMike Christie memset(acb->reserved6, 0, sizeof(acb->reserved6)); 976d00efe3fSMike Christie memset(acb->reserved7, 0, sizeof(acb->reserved7)); 977d00efe3fSMike Christie memset(acb->reserved8, 0, sizeof(acb->reserved8)); 978d00efe3fSMike Christie memset(acb->reserved9, 0, sizeof(acb->reserved9)); 979d00efe3fSMike Christie memset(acb->reserved10, 0, sizeof(acb->reserved10)); 980d00efe3fSMike Christie memset(acb->reserved11, 0, sizeof(acb->reserved11)); 981d00efe3fSMike Christie memset(acb->reserved12, 0, sizeof(acb->reserved12)); 982d00efe3fSMike Christie memset(acb->reserved13, 0, sizeof(acb->reserved13)); 983d00efe3fSMike Christie memset(acb->reserved14, 0, sizeof(acb->reserved14)); 984d00efe3fSMike Christie memset(acb->reserved15, 0, sizeof(acb->reserved15)); 985d00efe3fSMike Christie } 986d00efe3fSMike Christie 987d00efe3fSMike Christie static int 98800c31889SMike Christie qla4xxx_iface_set_param(struct Scsi_Host *shost, void *data, uint32_t len) 989d00efe3fSMike Christie { 990d00efe3fSMike Christie struct scsi_qla_host *ha = to_qla_host(shost); 991d00efe3fSMike Christie int rval = 0; 992d00efe3fSMike Christie struct iscsi_iface_param_info *iface_param = NULL; 993d00efe3fSMike Christie struct addr_ctrl_blk *init_fw_cb = NULL; 994d00efe3fSMike Christie dma_addr_t init_fw_cb_dma; 995d00efe3fSMike Christie uint32_t mbox_cmd[MBOX_REG_COUNT]; 996d00efe3fSMike Christie uint32_t mbox_sts[MBOX_REG_COUNT]; 99700c31889SMike Christie uint32_t rem = len; 99800c31889SMike Christie struct nlattr *attr; 999d00efe3fSMike Christie 1000d00efe3fSMike Christie init_fw_cb = dma_alloc_coherent(&ha->pdev->dev, 1001d00efe3fSMike Christie sizeof(struct addr_ctrl_blk), 1002d00efe3fSMike Christie &init_fw_cb_dma, GFP_KERNEL); 1003d00efe3fSMike Christie if (!init_fw_cb) { 1004d00efe3fSMike Christie ql4_printk(KERN_ERR, ha, "%s: Unable to alloc init_cb\n", 1005d00efe3fSMike Christie __func__); 1006d00efe3fSMike Christie return -ENOMEM; 1007d00efe3fSMike Christie } 1008d00efe3fSMike Christie 1009d00efe3fSMike Christie memset(init_fw_cb, 0, sizeof(struct addr_ctrl_blk)); 1010d00efe3fSMike Christie memset(&mbox_cmd, 0, sizeof(mbox_cmd)); 1011d00efe3fSMike Christie memset(&mbox_sts, 0, sizeof(mbox_sts)); 1012d00efe3fSMike Christie 1013d00efe3fSMike Christie if (qla4xxx_get_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb_dma)) { 1014d00efe3fSMike Christie ql4_printk(KERN_ERR, ha, "%s: get ifcb failed\n", __func__); 1015d00efe3fSMike Christie rval = -EIO; 1016d00efe3fSMike Christie goto exit_init_fw_cb; 1017d00efe3fSMike Christie } 1018d00efe3fSMike Christie 101900c31889SMike Christie nla_for_each_attr(attr, data, len, rem) { 102000c31889SMike Christie iface_param = nla_data(attr); 1021d00efe3fSMike Christie 1022d00efe3fSMike Christie if (iface_param->param_type != ISCSI_NET_PARAM) 1023d00efe3fSMike Christie continue; 1024d00efe3fSMike Christie 1025d00efe3fSMike Christie switch (iface_param->iface_type) { 1026d00efe3fSMike Christie case ISCSI_IFACE_TYPE_IPV4: 1027d00efe3fSMike Christie switch (iface_param->iface_num) { 1028d00efe3fSMike Christie case 0: 1029d00efe3fSMike Christie qla4xxx_set_ipv4(ha, iface_param, init_fw_cb); 1030d00efe3fSMike Christie break; 1031d00efe3fSMike Christie default: 1032d00efe3fSMike Christie /* Cannot have more than one IPv4 interface */ 1033d00efe3fSMike Christie ql4_printk(KERN_ERR, ha, "Invalid IPv4 iface " 1034d00efe3fSMike Christie "number = %d\n", 1035d00efe3fSMike Christie iface_param->iface_num); 1036d00efe3fSMike Christie break; 1037d00efe3fSMike Christie } 1038d00efe3fSMike Christie break; 1039d00efe3fSMike Christie case ISCSI_IFACE_TYPE_IPV6: 1040d00efe3fSMike Christie switch (iface_param->iface_num) { 1041d00efe3fSMike Christie case 0: 1042d00efe3fSMike Christie case 1: 1043d00efe3fSMike Christie qla4xxx_set_ipv6(ha, iface_param, init_fw_cb); 1044d00efe3fSMike Christie break; 1045d00efe3fSMike Christie default: 1046d00efe3fSMike Christie /* Cannot have more than two IPv6 interface */ 1047d00efe3fSMike Christie ql4_printk(KERN_ERR, ha, "Invalid IPv6 iface " 1048d00efe3fSMike Christie "number = %d\n", 1049d00efe3fSMike Christie iface_param->iface_num); 1050d00efe3fSMike Christie break; 1051d00efe3fSMike Christie } 1052d00efe3fSMike Christie break; 1053d00efe3fSMike Christie default: 1054d00efe3fSMike Christie ql4_printk(KERN_ERR, ha, "Invalid iface type\n"); 1055d00efe3fSMike Christie break; 1056d00efe3fSMike Christie } 1057d00efe3fSMike Christie } 1058d00efe3fSMike Christie 1059d00efe3fSMike Christie init_fw_cb->cookie = cpu_to_le32(0x11BEAD5A); 1060d00efe3fSMike Christie 1061d00efe3fSMike Christie rval = qla4xxx_set_flash(ha, init_fw_cb_dma, FLASH_SEGMENT_IFCB, 1062d00efe3fSMike Christie sizeof(struct addr_ctrl_blk), 1063d00efe3fSMike Christie FLASH_OPT_RMW_COMMIT); 1064d00efe3fSMike Christie if (rval != QLA_SUCCESS) { 1065d00efe3fSMike Christie ql4_printk(KERN_ERR, ha, "%s: set flash mbx failed\n", 1066d00efe3fSMike Christie __func__); 1067d00efe3fSMike Christie rval = -EIO; 1068d00efe3fSMike Christie goto exit_init_fw_cb; 1069d00efe3fSMike Christie } 1070d00efe3fSMike Christie 1071ce505f9dSVikas Chaudhary rval = qla4xxx_disable_acb(ha); 1072ce505f9dSVikas Chaudhary if (rval != QLA_SUCCESS) { 1073ce505f9dSVikas Chaudhary ql4_printk(KERN_ERR, ha, "%s: disable acb mbx failed\n", 1074ce505f9dSVikas Chaudhary __func__); 1075ce505f9dSVikas Chaudhary rval = -EIO; 1076ce505f9dSVikas Chaudhary goto exit_init_fw_cb; 1077ce505f9dSVikas Chaudhary } 1078ce505f9dSVikas Chaudhary 1079ce505f9dSVikas Chaudhary wait_for_completion_timeout(&ha->disable_acb_comp, 1080ce505f9dSVikas Chaudhary DISABLE_ACB_TOV * HZ); 1081d00efe3fSMike Christie 1082d00efe3fSMike Christie qla4xxx_initcb_to_acb(init_fw_cb); 1083d00efe3fSMike Christie 1084d00efe3fSMike Christie rval = qla4xxx_set_acb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb_dma); 1085d00efe3fSMike Christie if (rval != QLA_SUCCESS) { 1086d00efe3fSMike Christie ql4_printk(KERN_ERR, ha, "%s: set acb mbx failed\n", 1087d00efe3fSMike Christie __func__); 1088d00efe3fSMike Christie rval = -EIO; 1089d00efe3fSMike Christie goto exit_init_fw_cb; 1090d00efe3fSMike Christie } 1091d00efe3fSMike Christie 1092d00efe3fSMike Christie memset(init_fw_cb, 0, sizeof(struct addr_ctrl_blk)); 1093d00efe3fSMike Christie qla4xxx_update_local_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb, 1094d00efe3fSMike Christie init_fw_cb_dma); 1095d00efe3fSMike Christie 1096d00efe3fSMike Christie exit_init_fw_cb: 1097d00efe3fSMike Christie dma_free_coherent(&ha->pdev->dev, sizeof(struct addr_ctrl_blk), 1098d00efe3fSMike Christie init_fw_cb, init_fw_cb_dma); 1099d00efe3fSMike Christie 1100d00efe3fSMike Christie return rval; 1101d00efe3fSMike Christie } 1102d00efe3fSMike Christie 1103b3a271a9SManish Rangankar static int qla4xxx_conn_get_param(struct iscsi_cls_conn *cls_conn, 1104afaf5a2dSDavid Somayajulu enum iscsi_param param, char *buf) 1105afaf5a2dSDavid Somayajulu { 1106b3a271a9SManish Rangankar struct iscsi_conn *conn; 1107b3a271a9SManish Rangankar struct qla_conn *qla_conn; 1108b3a271a9SManish Rangankar struct sockaddr *dst_addr; 1109b3a271a9SManish Rangankar int len = 0; 1110afaf5a2dSDavid Somayajulu 1111b3a271a9SManish Rangankar conn = cls_conn->dd_data; 1112b3a271a9SManish Rangankar qla_conn = conn->dd_data; 1113b3a271a9SManish Rangankar dst_addr = &qla_conn->qla_ep->dst_addr; 1114afaf5a2dSDavid Somayajulu 1115afaf5a2dSDavid Somayajulu switch (param) { 1116afaf5a2dSDavid Somayajulu case ISCSI_PARAM_CONN_PORT: 1117afaf5a2dSDavid Somayajulu case ISCSI_PARAM_CONN_ADDRESS: 1118b3a271a9SManish Rangankar return iscsi_conn_get_addr_param((struct sockaddr_storage *) 1119b3a271a9SManish Rangankar dst_addr, param, buf); 1120afaf5a2dSDavid Somayajulu default: 1121b3a271a9SManish Rangankar return iscsi_conn_get_param(cls_conn, param, buf); 1122afaf5a2dSDavid Somayajulu } 1123afaf5a2dSDavid Somayajulu 1124afaf5a2dSDavid Somayajulu return len; 1125b3a271a9SManish Rangankar 1126afaf5a2dSDavid Somayajulu } 1127afaf5a2dSDavid Somayajulu 112813483730SMike Christie int qla4xxx_get_ddb_index(struct scsi_qla_host *ha, uint16_t *ddb_index) 112913483730SMike Christie { 113013483730SMike Christie uint32_t mbx_sts = 0; 113113483730SMike Christie uint16_t tmp_ddb_index; 113213483730SMike Christie int ret; 113313483730SMike Christie 113413483730SMike Christie get_ddb_index: 113513483730SMike Christie tmp_ddb_index = find_first_zero_bit(ha->ddb_idx_map, MAX_DDB_ENTRIES); 113613483730SMike Christie 113713483730SMike Christie if (tmp_ddb_index >= MAX_DDB_ENTRIES) { 113813483730SMike Christie DEBUG2(ql4_printk(KERN_INFO, ha, 113913483730SMike Christie "Free DDB index not available\n")); 114013483730SMike Christie ret = QLA_ERROR; 114113483730SMike Christie goto exit_get_ddb_index; 114213483730SMike Christie } 114313483730SMike Christie 114413483730SMike Christie if (test_and_set_bit(tmp_ddb_index, ha->ddb_idx_map)) 114513483730SMike Christie goto get_ddb_index; 114613483730SMike Christie 114713483730SMike Christie DEBUG2(ql4_printk(KERN_INFO, ha, 114813483730SMike Christie "Found a free DDB index at %d\n", tmp_ddb_index)); 114913483730SMike Christie ret = qla4xxx_req_ddb_entry(ha, tmp_ddb_index, &mbx_sts); 115013483730SMike Christie if (ret == QLA_ERROR) { 115113483730SMike Christie if (mbx_sts == MBOX_STS_COMMAND_ERROR) { 115213483730SMike Christie ql4_printk(KERN_INFO, ha, 115313483730SMike Christie "DDB index = %d not available trying next\n", 115413483730SMike Christie tmp_ddb_index); 115513483730SMike Christie goto get_ddb_index; 115613483730SMike Christie } 115713483730SMike Christie DEBUG2(ql4_printk(KERN_INFO, ha, 115813483730SMike Christie "Free FW DDB not available\n")); 115913483730SMike Christie } 116013483730SMike Christie 116113483730SMike Christie *ddb_index = tmp_ddb_index; 116213483730SMike Christie 116313483730SMike Christie exit_get_ddb_index: 116413483730SMike Christie return ret; 116513483730SMike Christie } 116613483730SMike Christie 116713483730SMike Christie static int qla4xxx_match_ipaddress(struct scsi_qla_host *ha, 116813483730SMike Christie struct ddb_entry *ddb_entry, 116913483730SMike Christie char *existing_ipaddr, 117013483730SMike Christie char *user_ipaddr) 117113483730SMike Christie { 117213483730SMike Christie uint8_t dst_ipaddr[IPv6_ADDR_LEN]; 117313483730SMike Christie char formatted_ipaddr[DDB_IPADDR_LEN]; 117413483730SMike Christie int status = QLA_SUCCESS, ret = 0; 117513483730SMike Christie 117613483730SMike Christie if (ddb_entry->fw_ddb_entry.options & DDB_OPT_IPV6_DEVICE) { 117713483730SMike Christie ret = in6_pton(user_ipaddr, strlen(user_ipaddr), dst_ipaddr, 117813483730SMike Christie '\0', NULL); 117913483730SMike Christie if (ret == 0) { 118013483730SMike Christie status = QLA_ERROR; 118113483730SMike Christie goto out_match; 118213483730SMike Christie } 118313483730SMike Christie ret = sprintf(formatted_ipaddr, "%pI6", dst_ipaddr); 118413483730SMike Christie } else { 118513483730SMike Christie ret = in4_pton(user_ipaddr, strlen(user_ipaddr), dst_ipaddr, 118613483730SMike Christie '\0', NULL); 118713483730SMike Christie if (ret == 0) { 118813483730SMike Christie status = QLA_ERROR; 118913483730SMike Christie goto out_match; 119013483730SMike Christie } 119113483730SMike Christie ret = sprintf(formatted_ipaddr, "%pI4", dst_ipaddr); 119213483730SMike Christie } 119313483730SMike Christie 119413483730SMike Christie if (strcmp(existing_ipaddr, formatted_ipaddr)) 119513483730SMike Christie status = QLA_ERROR; 119613483730SMike Christie 119713483730SMike Christie out_match: 119813483730SMike Christie return status; 119913483730SMike Christie } 120013483730SMike Christie 120113483730SMike Christie static int qla4xxx_match_fwdb_session(struct scsi_qla_host *ha, 120213483730SMike Christie struct iscsi_cls_conn *cls_conn) 120313483730SMike Christie { 120413483730SMike Christie int idx = 0, max_ddbs, rval; 120513483730SMike Christie struct iscsi_cls_session *cls_sess = iscsi_conn_to_session(cls_conn); 120613483730SMike Christie struct iscsi_session *sess, *existing_sess; 120713483730SMike Christie struct iscsi_conn *conn, *existing_conn; 120813483730SMike Christie struct ddb_entry *ddb_entry; 120913483730SMike Christie 121013483730SMike Christie sess = cls_sess->dd_data; 121113483730SMike Christie conn = cls_conn->dd_data; 121213483730SMike Christie 121313483730SMike Christie if (sess->targetname == NULL || 121413483730SMike Christie conn->persistent_address == NULL || 121513483730SMike Christie conn->persistent_port == 0) 121613483730SMike Christie return QLA_ERROR; 121713483730SMike Christie 121813483730SMike Christie max_ddbs = is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX : 121913483730SMike Christie MAX_DEV_DB_ENTRIES; 122013483730SMike Christie 122113483730SMike Christie for (idx = 0; idx < max_ddbs; idx++) { 122213483730SMike Christie ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx); 122313483730SMike Christie if (ddb_entry == NULL) 122413483730SMike Christie continue; 122513483730SMike Christie 122613483730SMike Christie if (ddb_entry->ddb_type != FLASH_DDB) 122713483730SMike Christie continue; 122813483730SMike Christie 122913483730SMike Christie existing_sess = ddb_entry->sess->dd_data; 123013483730SMike Christie existing_conn = ddb_entry->conn->dd_data; 123113483730SMike Christie 123213483730SMike Christie if (existing_sess->targetname == NULL || 123313483730SMike Christie existing_conn->persistent_address == NULL || 123413483730SMike Christie existing_conn->persistent_port == 0) 123513483730SMike Christie continue; 123613483730SMike Christie 123713483730SMike Christie DEBUG2(ql4_printk(KERN_INFO, ha, 123813483730SMike Christie "IQN = %s User IQN = %s\n", 123913483730SMike Christie existing_sess->targetname, 124013483730SMike Christie sess->targetname)); 124113483730SMike Christie 124213483730SMike Christie DEBUG2(ql4_printk(KERN_INFO, ha, 124313483730SMike Christie "IP = %s User IP = %s\n", 124413483730SMike Christie existing_conn->persistent_address, 124513483730SMike Christie conn->persistent_address)); 124613483730SMike Christie 124713483730SMike Christie DEBUG2(ql4_printk(KERN_INFO, ha, 124813483730SMike Christie "Port = %d User Port = %d\n", 124913483730SMike Christie existing_conn->persistent_port, 125013483730SMike Christie conn->persistent_port)); 125113483730SMike Christie 125213483730SMike Christie if (strcmp(existing_sess->targetname, sess->targetname)) 125313483730SMike Christie continue; 125413483730SMike Christie rval = qla4xxx_match_ipaddress(ha, ddb_entry, 125513483730SMike Christie existing_conn->persistent_address, 125613483730SMike Christie conn->persistent_address); 125713483730SMike Christie if (rval == QLA_ERROR) 125813483730SMike Christie continue; 125913483730SMike Christie if (existing_conn->persistent_port != conn->persistent_port) 126013483730SMike Christie continue; 126113483730SMike Christie break; 126213483730SMike Christie } 126313483730SMike Christie 126413483730SMike Christie if (idx == max_ddbs) 126513483730SMike Christie return QLA_ERROR; 126613483730SMike Christie 126713483730SMike Christie DEBUG2(ql4_printk(KERN_INFO, ha, 126813483730SMike Christie "Match found in fwdb sessions\n")); 126913483730SMike Christie return QLA_SUCCESS; 127013483730SMike Christie } 127113483730SMike Christie 1272b3a271a9SManish Rangankar static struct iscsi_cls_session * 1273b3a271a9SManish Rangankar qla4xxx_session_create(struct iscsi_endpoint *ep, 1274b3a271a9SManish Rangankar uint16_t cmds_max, uint16_t qdepth, 1275b3a271a9SManish Rangankar uint32_t initial_cmdsn) 1276b3a271a9SManish Rangankar { 1277b3a271a9SManish Rangankar struct iscsi_cls_session *cls_sess; 1278b3a271a9SManish Rangankar struct scsi_qla_host *ha; 1279b3a271a9SManish Rangankar struct qla_endpoint *qla_ep; 1280b3a271a9SManish Rangankar struct ddb_entry *ddb_entry; 128113483730SMike Christie uint16_t ddb_index; 1282b3a271a9SManish Rangankar struct iscsi_session *sess; 1283b3a271a9SManish Rangankar struct sockaddr *dst_addr; 1284b3a271a9SManish Rangankar int ret; 1285b3a271a9SManish Rangankar 1286b3a271a9SManish Rangankar DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); 1287b3a271a9SManish Rangankar if (!ep) { 1288b3a271a9SManish Rangankar printk(KERN_ERR "qla4xxx: missing ep.\n"); 1289b3a271a9SManish Rangankar return NULL; 1290b3a271a9SManish Rangankar } 1291b3a271a9SManish Rangankar 1292b3a271a9SManish Rangankar qla_ep = ep->dd_data; 1293b3a271a9SManish Rangankar dst_addr = (struct sockaddr *)&qla_ep->dst_addr; 1294b3a271a9SManish Rangankar ha = to_qla_host(qla_ep->host); 1295736cf369SManish Rangankar 129613483730SMike Christie ret = qla4xxx_get_ddb_index(ha, &ddb_index); 129713483730SMike Christie if (ret == QLA_ERROR) 1298b3a271a9SManish Rangankar return NULL; 1299b3a271a9SManish Rangankar 1300b3a271a9SManish Rangankar cls_sess = iscsi_session_setup(&qla4xxx_iscsi_transport, qla_ep->host, 1301b3a271a9SManish Rangankar cmds_max, sizeof(struct ddb_entry), 1302b3a271a9SManish Rangankar sizeof(struct ql4_task_data), 1303b3a271a9SManish Rangankar initial_cmdsn, ddb_index); 1304b3a271a9SManish Rangankar if (!cls_sess) 1305b3a271a9SManish Rangankar return NULL; 1306b3a271a9SManish Rangankar 1307b3a271a9SManish Rangankar sess = cls_sess->dd_data; 1308b3a271a9SManish Rangankar ddb_entry = sess->dd_data; 1309b3a271a9SManish Rangankar ddb_entry->fw_ddb_index = ddb_index; 1310b3a271a9SManish Rangankar ddb_entry->fw_ddb_device_state = DDB_DS_NO_CONNECTION_ACTIVE; 1311b3a271a9SManish Rangankar ddb_entry->ha = ha; 1312b3a271a9SManish Rangankar ddb_entry->sess = cls_sess; 131313483730SMike Christie ddb_entry->unblock_sess = qla4xxx_unblock_ddb; 131413483730SMike Christie ddb_entry->ddb_change = qla4xxx_ddb_change; 1315b3a271a9SManish Rangankar cls_sess->recovery_tmo = ql4xsess_recovery_tmo; 1316b3a271a9SManish Rangankar ha->fw_ddb_index_map[ddb_entry->fw_ddb_index] = ddb_entry; 1317b3a271a9SManish Rangankar ha->tot_ddbs++; 1318b3a271a9SManish Rangankar 1319b3a271a9SManish Rangankar return cls_sess; 1320b3a271a9SManish Rangankar } 1321b3a271a9SManish Rangankar 1322b3a271a9SManish Rangankar static void qla4xxx_session_destroy(struct iscsi_cls_session *cls_sess) 1323b3a271a9SManish Rangankar { 1324b3a271a9SManish Rangankar struct iscsi_session *sess; 1325b3a271a9SManish Rangankar struct ddb_entry *ddb_entry; 1326b3a271a9SManish Rangankar struct scsi_qla_host *ha; 1327b3a271a9SManish Rangankar unsigned long flags; 1328b3a271a9SManish Rangankar 1329b3a271a9SManish Rangankar DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); 1330b3a271a9SManish Rangankar sess = cls_sess->dd_data; 1331b3a271a9SManish Rangankar ddb_entry = sess->dd_data; 1332b3a271a9SManish Rangankar ha = ddb_entry->ha; 1333b3a271a9SManish Rangankar 1334736cf369SManish Rangankar qla4xxx_clear_ddb_entry(ha, ddb_entry->fw_ddb_index); 1335736cf369SManish Rangankar 1336b3a271a9SManish Rangankar spin_lock_irqsave(&ha->hardware_lock, flags); 1337b3a271a9SManish Rangankar qla4xxx_free_ddb(ha, ddb_entry); 1338b3a271a9SManish Rangankar spin_unlock_irqrestore(&ha->hardware_lock, flags); 1339b3a271a9SManish Rangankar iscsi_session_teardown(cls_sess); 1340b3a271a9SManish Rangankar } 1341b3a271a9SManish Rangankar 1342b3a271a9SManish Rangankar static struct iscsi_cls_conn * 1343b3a271a9SManish Rangankar qla4xxx_conn_create(struct iscsi_cls_session *cls_sess, uint32_t conn_idx) 1344b3a271a9SManish Rangankar { 1345b3a271a9SManish Rangankar struct iscsi_cls_conn *cls_conn; 1346b3a271a9SManish Rangankar struct iscsi_session *sess; 1347b3a271a9SManish Rangankar struct ddb_entry *ddb_entry; 1348b3a271a9SManish Rangankar 1349b3a271a9SManish Rangankar DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); 1350b3a271a9SManish Rangankar cls_conn = iscsi_conn_setup(cls_sess, sizeof(struct qla_conn), 1351b3a271a9SManish Rangankar conn_idx); 1352ff1d0319SMike Christie if (!cls_conn) 1353ff1d0319SMike Christie return NULL; 1354ff1d0319SMike Christie 1355b3a271a9SManish Rangankar sess = cls_sess->dd_data; 1356b3a271a9SManish Rangankar ddb_entry = sess->dd_data; 1357b3a271a9SManish Rangankar ddb_entry->conn = cls_conn; 1358b3a271a9SManish Rangankar 1359b3a271a9SManish Rangankar return cls_conn; 1360b3a271a9SManish Rangankar } 1361b3a271a9SManish Rangankar 1362b3a271a9SManish Rangankar static int qla4xxx_conn_bind(struct iscsi_cls_session *cls_session, 1363b3a271a9SManish Rangankar struct iscsi_cls_conn *cls_conn, 1364b3a271a9SManish Rangankar uint64_t transport_fd, int is_leading) 1365b3a271a9SManish Rangankar { 1366b3a271a9SManish Rangankar struct iscsi_conn *conn; 1367b3a271a9SManish Rangankar struct qla_conn *qla_conn; 1368b3a271a9SManish Rangankar struct iscsi_endpoint *ep; 1369b3a271a9SManish Rangankar 1370b3a271a9SManish Rangankar DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); 1371b3a271a9SManish Rangankar 1372b3a271a9SManish Rangankar if (iscsi_conn_bind(cls_session, cls_conn, is_leading)) 1373b3a271a9SManish Rangankar return -EINVAL; 1374b3a271a9SManish Rangankar ep = iscsi_lookup_endpoint(transport_fd); 1375b3a271a9SManish Rangankar conn = cls_conn->dd_data; 1376b3a271a9SManish Rangankar qla_conn = conn->dd_data; 1377b3a271a9SManish Rangankar qla_conn->qla_ep = ep->dd_data; 1378b3a271a9SManish Rangankar return 0; 1379b3a271a9SManish Rangankar } 1380b3a271a9SManish Rangankar 1381b3a271a9SManish Rangankar static int qla4xxx_conn_start(struct iscsi_cls_conn *cls_conn) 1382b3a271a9SManish Rangankar { 1383b3a271a9SManish Rangankar struct iscsi_cls_session *cls_sess = iscsi_conn_to_session(cls_conn); 1384b3a271a9SManish Rangankar struct iscsi_session *sess; 1385b3a271a9SManish Rangankar struct ddb_entry *ddb_entry; 1386b3a271a9SManish Rangankar struct scsi_qla_host *ha; 138713483730SMike Christie struct dev_db_entry *fw_ddb_entry = NULL; 1388b3a271a9SManish Rangankar dma_addr_t fw_ddb_entry_dma; 1389b3a271a9SManish Rangankar uint32_t mbx_sts = 0; 1390b3a271a9SManish Rangankar int ret = 0; 1391b3a271a9SManish Rangankar int status = QLA_SUCCESS; 1392b3a271a9SManish Rangankar 1393b3a271a9SManish Rangankar DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); 1394b3a271a9SManish Rangankar sess = cls_sess->dd_data; 1395b3a271a9SManish Rangankar ddb_entry = sess->dd_data; 1396b3a271a9SManish Rangankar ha = ddb_entry->ha; 1397b3a271a9SManish Rangankar 139813483730SMike Christie /* Check if we have matching FW DDB, if yes then do not 139913483730SMike Christie * login to this target. This could cause target to logout previous 140013483730SMike Christie * connection 140113483730SMike Christie */ 140213483730SMike Christie ret = qla4xxx_match_fwdb_session(ha, cls_conn); 140313483730SMike Christie if (ret == QLA_SUCCESS) { 140413483730SMike Christie ql4_printk(KERN_INFO, ha, 140513483730SMike Christie "Session already exist in FW.\n"); 140613483730SMike Christie ret = -EEXIST; 140713483730SMike Christie goto exit_conn_start; 140813483730SMike Christie } 140913483730SMike Christie 1410b3a271a9SManish Rangankar fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), 1411b3a271a9SManish Rangankar &fw_ddb_entry_dma, GFP_KERNEL); 1412b3a271a9SManish Rangankar if (!fw_ddb_entry) { 1413b3a271a9SManish Rangankar ql4_printk(KERN_ERR, ha, 1414b3a271a9SManish Rangankar "%s: Unable to allocate dma buffer\n", __func__); 141513483730SMike Christie ret = -ENOMEM; 141613483730SMike Christie goto exit_conn_start; 1417b3a271a9SManish Rangankar } 1418b3a271a9SManish Rangankar 1419b3a271a9SManish Rangankar ret = qla4xxx_set_param_ddbentry(ha, ddb_entry, cls_conn, &mbx_sts); 1420b3a271a9SManish Rangankar if (ret) { 1421b3a271a9SManish Rangankar /* If iscsid is stopped and started then no need to do 1422b3a271a9SManish Rangankar * set param again since ddb state will be already 1423b3a271a9SManish Rangankar * active and FW does not allow set ddb to an 1424b3a271a9SManish Rangankar * active session. 1425b3a271a9SManish Rangankar */ 1426b3a271a9SManish Rangankar if (mbx_sts) 1427b3a271a9SManish Rangankar if (ddb_entry->fw_ddb_device_state == 1428f922da79SManish Rangankar DDB_DS_SESSION_ACTIVE) { 142913483730SMike Christie ddb_entry->unblock_sess(ddb_entry->sess); 1430b3a271a9SManish Rangankar goto exit_set_param; 1431f922da79SManish Rangankar } 1432b3a271a9SManish Rangankar 1433b3a271a9SManish Rangankar ql4_printk(KERN_ERR, ha, "%s: Failed set param for index[%d]\n", 1434b3a271a9SManish Rangankar __func__, ddb_entry->fw_ddb_index); 1435b3a271a9SManish Rangankar goto exit_conn_start; 1436b3a271a9SManish Rangankar } 1437b3a271a9SManish Rangankar 1438b3a271a9SManish Rangankar status = qla4xxx_conn_open(ha, ddb_entry->fw_ddb_index); 1439b3a271a9SManish Rangankar if (status == QLA_ERROR) { 14400e7e8501SManish Rangankar ql4_printk(KERN_ERR, ha, "%s: Login failed: %s\n", __func__, 14410e7e8501SManish Rangankar sess->targetname); 1442b3a271a9SManish Rangankar ret = -EINVAL; 1443b3a271a9SManish Rangankar goto exit_conn_start; 1444b3a271a9SManish Rangankar } 1445b3a271a9SManish Rangankar 144698270ab4SManish Rangankar if (ddb_entry->fw_ddb_device_state == DDB_DS_NO_CONNECTION_ACTIVE) 1447b3a271a9SManish Rangankar ddb_entry->fw_ddb_device_state = DDB_DS_LOGIN_IN_PROCESS; 1448b3a271a9SManish Rangankar 144998270ab4SManish Rangankar DEBUG2(printk(KERN_INFO "%s: DDB state [%d]\n", __func__, 145098270ab4SManish Rangankar ddb_entry->fw_ddb_device_state)); 145198270ab4SManish Rangankar 1452b3a271a9SManish Rangankar exit_set_param: 1453b3a271a9SManish Rangankar ret = 0; 1454b3a271a9SManish Rangankar 1455b3a271a9SManish Rangankar exit_conn_start: 145613483730SMike Christie if (fw_ddb_entry) 1457b3a271a9SManish Rangankar dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), 1458b3a271a9SManish Rangankar fw_ddb_entry, fw_ddb_entry_dma); 1459b3a271a9SManish Rangankar return ret; 1460b3a271a9SManish Rangankar } 1461b3a271a9SManish Rangankar 1462b3a271a9SManish Rangankar static void qla4xxx_conn_destroy(struct iscsi_cls_conn *cls_conn) 1463b3a271a9SManish Rangankar { 1464b3a271a9SManish Rangankar struct iscsi_cls_session *cls_sess = iscsi_conn_to_session(cls_conn); 1465b3a271a9SManish Rangankar struct iscsi_session *sess; 1466b3a271a9SManish Rangankar struct scsi_qla_host *ha; 1467b3a271a9SManish Rangankar struct ddb_entry *ddb_entry; 1468b3a271a9SManish Rangankar int options; 1469b3a271a9SManish Rangankar 1470b3a271a9SManish Rangankar DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); 1471b3a271a9SManish Rangankar sess = cls_sess->dd_data; 1472b3a271a9SManish Rangankar ddb_entry = sess->dd_data; 1473b3a271a9SManish Rangankar ha = ddb_entry->ha; 1474b3a271a9SManish Rangankar 1475b3a271a9SManish Rangankar options = LOGOUT_OPTION_CLOSE_SESSION; 1476b3a271a9SManish Rangankar if (qla4xxx_session_logout_ddb(ha, ddb_entry, options) == QLA_ERROR) 1477b3a271a9SManish Rangankar ql4_printk(KERN_ERR, ha, "%s: Logout failed\n", __func__); 1478b3a271a9SManish Rangankar } 1479b3a271a9SManish Rangankar 1480b3a271a9SManish Rangankar static void qla4xxx_task_work(struct work_struct *wdata) 1481b3a271a9SManish Rangankar { 1482b3a271a9SManish Rangankar struct ql4_task_data *task_data; 1483b3a271a9SManish Rangankar struct scsi_qla_host *ha; 1484b3a271a9SManish Rangankar struct passthru_status *sts; 1485b3a271a9SManish Rangankar struct iscsi_task *task; 1486b3a271a9SManish Rangankar struct iscsi_hdr *hdr; 1487b3a271a9SManish Rangankar uint8_t *data; 1488b3a271a9SManish Rangankar uint32_t data_len; 1489b3a271a9SManish Rangankar struct iscsi_conn *conn; 1490b3a271a9SManish Rangankar int hdr_len; 1491b3a271a9SManish Rangankar itt_t itt; 1492b3a271a9SManish Rangankar 1493b3a271a9SManish Rangankar task_data = container_of(wdata, struct ql4_task_data, task_work); 1494b3a271a9SManish Rangankar ha = task_data->ha; 1495b3a271a9SManish Rangankar task = task_data->task; 1496b3a271a9SManish Rangankar sts = &task_data->sts; 1497b3a271a9SManish Rangankar hdr_len = sizeof(struct iscsi_hdr); 1498b3a271a9SManish Rangankar 1499b3a271a9SManish Rangankar DEBUG3(printk(KERN_INFO "Status returned\n")); 1500b3a271a9SManish Rangankar DEBUG3(qla4xxx_dump_buffer(sts, 64)); 1501b3a271a9SManish Rangankar DEBUG3(printk(KERN_INFO "Response buffer")); 1502b3a271a9SManish Rangankar DEBUG3(qla4xxx_dump_buffer(task_data->resp_buffer, 64)); 1503b3a271a9SManish Rangankar 1504b3a271a9SManish Rangankar conn = task->conn; 1505b3a271a9SManish Rangankar 1506b3a271a9SManish Rangankar switch (sts->completionStatus) { 1507b3a271a9SManish Rangankar case PASSTHRU_STATUS_COMPLETE: 1508b3a271a9SManish Rangankar hdr = (struct iscsi_hdr *)task_data->resp_buffer; 1509b3a271a9SManish Rangankar /* Assign back the itt in hdr, until we use the PREASSIGN_TAG */ 1510b3a271a9SManish Rangankar itt = sts->handle; 1511b3a271a9SManish Rangankar hdr->itt = itt; 1512b3a271a9SManish Rangankar data = task_data->resp_buffer + hdr_len; 1513b3a271a9SManish Rangankar data_len = task_data->resp_len - hdr_len; 1514b3a271a9SManish Rangankar iscsi_complete_pdu(conn, hdr, data, data_len); 1515b3a271a9SManish Rangankar break; 1516b3a271a9SManish Rangankar default: 1517b3a271a9SManish Rangankar ql4_printk(KERN_ERR, ha, "Passthru failed status = 0x%x\n", 1518b3a271a9SManish Rangankar sts->completionStatus); 1519b3a271a9SManish Rangankar break; 1520b3a271a9SManish Rangankar } 1521b3a271a9SManish Rangankar return; 1522b3a271a9SManish Rangankar } 1523b3a271a9SManish Rangankar 1524b3a271a9SManish Rangankar static int qla4xxx_alloc_pdu(struct iscsi_task *task, uint8_t opcode) 1525b3a271a9SManish Rangankar { 1526b3a271a9SManish Rangankar struct ql4_task_data *task_data; 1527b3a271a9SManish Rangankar struct iscsi_session *sess; 1528b3a271a9SManish Rangankar struct ddb_entry *ddb_entry; 1529b3a271a9SManish Rangankar struct scsi_qla_host *ha; 1530b3a271a9SManish Rangankar int hdr_len; 1531b3a271a9SManish Rangankar 1532b3a271a9SManish Rangankar sess = task->conn->session; 1533b3a271a9SManish Rangankar ddb_entry = sess->dd_data; 1534b3a271a9SManish Rangankar ha = ddb_entry->ha; 1535b3a271a9SManish Rangankar task_data = task->dd_data; 1536b3a271a9SManish Rangankar memset(task_data, 0, sizeof(struct ql4_task_data)); 1537b3a271a9SManish Rangankar 1538b3a271a9SManish Rangankar if (task->sc) { 1539b3a271a9SManish Rangankar ql4_printk(KERN_INFO, ha, 1540b3a271a9SManish Rangankar "%s: SCSI Commands not implemented\n", __func__); 1541b3a271a9SManish Rangankar return -EINVAL; 1542b3a271a9SManish Rangankar } 1543b3a271a9SManish Rangankar 1544b3a271a9SManish Rangankar hdr_len = sizeof(struct iscsi_hdr); 1545b3a271a9SManish Rangankar task_data->ha = ha; 1546b3a271a9SManish Rangankar task_data->task = task; 1547b3a271a9SManish Rangankar 1548b3a271a9SManish Rangankar if (task->data_count) { 1549b3a271a9SManish Rangankar task_data->data_dma = dma_map_single(&ha->pdev->dev, task->data, 1550b3a271a9SManish Rangankar task->data_count, 1551b3a271a9SManish Rangankar PCI_DMA_TODEVICE); 1552b3a271a9SManish Rangankar } 1553b3a271a9SManish Rangankar 1554b3a271a9SManish Rangankar DEBUG2(ql4_printk(KERN_INFO, ha, "%s: MaxRecvLen %u, iscsi hrd %d\n", 1555b3a271a9SManish Rangankar __func__, task->conn->max_recv_dlength, hdr_len)); 1556b3a271a9SManish Rangankar 155769ca216eSManish Rangankar task_data->resp_len = task->conn->max_recv_dlength + hdr_len; 1558b3a271a9SManish Rangankar task_data->resp_buffer = dma_alloc_coherent(&ha->pdev->dev, 1559b3a271a9SManish Rangankar task_data->resp_len, 1560b3a271a9SManish Rangankar &task_data->resp_dma, 1561b3a271a9SManish Rangankar GFP_ATOMIC); 1562b3a271a9SManish Rangankar if (!task_data->resp_buffer) 1563b3a271a9SManish Rangankar goto exit_alloc_pdu; 1564b3a271a9SManish Rangankar 156569ca216eSManish Rangankar task_data->req_len = task->data_count + hdr_len; 1566b3a271a9SManish Rangankar task_data->req_buffer = dma_alloc_coherent(&ha->pdev->dev, 156769ca216eSManish Rangankar task_data->req_len, 1568b3a271a9SManish Rangankar &task_data->req_dma, 1569b3a271a9SManish Rangankar GFP_ATOMIC); 1570b3a271a9SManish Rangankar if (!task_data->req_buffer) 1571b3a271a9SManish Rangankar goto exit_alloc_pdu; 1572b3a271a9SManish Rangankar 1573b3a271a9SManish Rangankar task->hdr = task_data->req_buffer; 1574b3a271a9SManish Rangankar 1575b3a271a9SManish Rangankar INIT_WORK(&task_data->task_work, qla4xxx_task_work); 1576b3a271a9SManish Rangankar 1577b3a271a9SManish Rangankar return 0; 1578b3a271a9SManish Rangankar 1579b3a271a9SManish Rangankar exit_alloc_pdu: 1580b3a271a9SManish Rangankar if (task_data->resp_buffer) 1581b3a271a9SManish Rangankar dma_free_coherent(&ha->pdev->dev, task_data->resp_len, 1582b3a271a9SManish Rangankar task_data->resp_buffer, task_data->resp_dma); 1583b3a271a9SManish Rangankar 1584b3a271a9SManish Rangankar if (task_data->req_buffer) 158569ca216eSManish Rangankar dma_free_coherent(&ha->pdev->dev, task_data->req_len, 1586b3a271a9SManish Rangankar task_data->req_buffer, task_data->req_dma); 1587b3a271a9SManish Rangankar return -ENOMEM; 1588b3a271a9SManish Rangankar } 1589b3a271a9SManish Rangankar 1590b3a271a9SManish Rangankar static void qla4xxx_task_cleanup(struct iscsi_task *task) 1591b3a271a9SManish Rangankar { 1592b3a271a9SManish Rangankar struct ql4_task_data *task_data; 1593b3a271a9SManish Rangankar struct iscsi_session *sess; 1594b3a271a9SManish Rangankar struct ddb_entry *ddb_entry; 1595b3a271a9SManish Rangankar struct scsi_qla_host *ha; 1596b3a271a9SManish Rangankar int hdr_len; 1597b3a271a9SManish Rangankar 1598b3a271a9SManish Rangankar hdr_len = sizeof(struct iscsi_hdr); 1599b3a271a9SManish Rangankar sess = task->conn->session; 1600b3a271a9SManish Rangankar ddb_entry = sess->dd_data; 1601b3a271a9SManish Rangankar ha = ddb_entry->ha; 1602b3a271a9SManish Rangankar task_data = task->dd_data; 1603b3a271a9SManish Rangankar 1604b3a271a9SManish Rangankar if (task->data_count) { 1605b3a271a9SManish Rangankar dma_unmap_single(&ha->pdev->dev, task_data->data_dma, 1606b3a271a9SManish Rangankar task->data_count, PCI_DMA_TODEVICE); 1607b3a271a9SManish Rangankar } 1608b3a271a9SManish Rangankar 1609b3a271a9SManish Rangankar DEBUG2(ql4_printk(KERN_INFO, ha, "%s: MaxRecvLen %u, iscsi hrd %d\n", 1610b3a271a9SManish Rangankar __func__, task->conn->max_recv_dlength, hdr_len)); 1611b3a271a9SManish Rangankar 1612b3a271a9SManish Rangankar dma_free_coherent(&ha->pdev->dev, task_data->resp_len, 1613b3a271a9SManish Rangankar task_data->resp_buffer, task_data->resp_dma); 161469ca216eSManish Rangankar dma_free_coherent(&ha->pdev->dev, task_data->req_len, 1615b3a271a9SManish Rangankar task_data->req_buffer, task_data->req_dma); 1616b3a271a9SManish Rangankar return; 1617b3a271a9SManish Rangankar } 1618b3a271a9SManish Rangankar 1619b3a271a9SManish Rangankar static int qla4xxx_task_xmit(struct iscsi_task *task) 1620b3a271a9SManish Rangankar { 1621b3a271a9SManish Rangankar struct scsi_cmnd *sc = task->sc; 1622b3a271a9SManish Rangankar struct iscsi_session *sess = task->conn->session; 1623b3a271a9SManish Rangankar struct ddb_entry *ddb_entry = sess->dd_data; 1624b3a271a9SManish Rangankar struct scsi_qla_host *ha = ddb_entry->ha; 1625b3a271a9SManish Rangankar 1626b3a271a9SManish Rangankar if (!sc) 1627b3a271a9SManish Rangankar return qla4xxx_send_passthru0(task); 1628b3a271a9SManish Rangankar 1629b3a271a9SManish Rangankar ql4_printk(KERN_INFO, ha, "%s: scsi cmd xmit not implemented\n", 1630b3a271a9SManish Rangankar __func__); 1631b3a271a9SManish Rangankar return -ENOSYS; 1632b3a271a9SManish Rangankar } 1633b3a271a9SManish Rangankar 163413483730SMike Christie static void qla4xxx_copy_fwddb_param(struct scsi_qla_host *ha, 163513483730SMike Christie struct dev_db_entry *fw_ddb_entry, 163613483730SMike Christie struct iscsi_cls_session *cls_sess, 163713483730SMike Christie struct iscsi_cls_conn *cls_conn) 163813483730SMike Christie { 163913483730SMike Christie int buflen = 0; 164013483730SMike Christie struct iscsi_session *sess; 164113483730SMike Christie struct iscsi_conn *conn; 164213483730SMike Christie char ip_addr[DDB_IPADDR_LEN]; 164313483730SMike Christie uint16_t options = 0; 164413483730SMike Christie 164513483730SMike Christie sess = cls_sess->dd_data; 164613483730SMike Christie conn = cls_conn->dd_data; 164713483730SMike Christie 164813483730SMike Christie conn->max_recv_dlength = BYTE_UNITS * 164913483730SMike Christie le16_to_cpu(fw_ddb_entry->iscsi_max_rcv_data_seg_len); 165013483730SMike Christie 165113483730SMike Christie conn->max_xmit_dlength = BYTE_UNITS * 165213483730SMike Christie le16_to_cpu(fw_ddb_entry->iscsi_max_snd_data_seg_len); 165313483730SMike Christie 165413483730SMike Christie sess->initial_r2t_en = 165513483730SMike Christie (BIT_10 & le16_to_cpu(fw_ddb_entry->iscsi_options)); 165613483730SMike Christie 165713483730SMike Christie sess->max_r2t = le16_to_cpu(fw_ddb_entry->iscsi_max_outsnd_r2t); 165813483730SMike Christie 165913483730SMike Christie sess->imm_data_en = (BIT_11 & le16_to_cpu(fw_ddb_entry->iscsi_options)); 166013483730SMike Christie 166113483730SMike Christie sess->first_burst = BYTE_UNITS * 166213483730SMike Christie le16_to_cpu(fw_ddb_entry->iscsi_first_burst_len); 166313483730SMike Christie 166413483730SMike Christie sess->max_burst = BYTE_UNITS * 166513483730SMike Christie le16_to_cpu(fw_ddb_entry->iscsi_max_burst_len); 166613483730SMike Christie 166713483730SMike Christie sess->time2wait = le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait); 166813483730SMike Christie 166913483730SMike Christie sess->time2retain = le16_to_cpu(fw_ddb_entry->iscsi_def_time2retain); 167013483730SMike Christie 167113483730SMike Christie conn->persistent_port = le16_to_cpu(fw_ddb_entry->port); 167213483730SMike Christie 167313483730SMike Christie sess->tpgt = le32_to_cpu(fw_ddb_entry->tgt_portal_grp); 167413483730SMike Christie 167513483730SMike Christie options = le16_to_cpu(fw_ddb_entry->options); 167613483730SMike Christie if (options & DDB_OPT_IPV6_DEVICE) 167713483730SMike Christie sprintf(ip_addr, "%pI6", fw_ddb_entry->ip_addr); 167813483730SMike Christie else 167913483730SMike Christie sprintf(ip_addr, "%pI4", fw_ddb_entry->ip_addr); 168013483730SMike Christie 168113483730SMike Christie iscsi_set_param(cls_conn, ISCSI_PARAM_TARGET_NAME, 168213483730SMike Christie (char *)fw_ddb_entry->iscsi_name, buflen); 168313483730SMike Christie iscsi_set_param(cls_conn, ISCSI_PARAM_INITIATOR_NAME, 168413483730SMike Christie (char *)ha->name_string, buflen); 168513483730SMike Christie iscsi_set_param(cls_conn, ISCSI_PARAM_PERSISTENT_ADDRESS, 168613483730SMike Christie (char *)ip_addr, buflen); 16876c1b8789SVikas Chaudhary iscsi_set_param(cls_conn, ISCSI_PARAM_TARGET_ALIAS, 16886c1b8789SVikas Chaudhary (char *)fw_ddb_entry->iscsi_alias, buflen); 168913483730SMike Christie } 169013483730SMike Christie 169113483730SMike Christie void qla4xxx_update_session_conn_fwddb_param(struct scsi_qla_host *ha, 169213483730SMike Christie struct ddb_entry *ddb_entry) 169313483730SMike Christie { 169413483730SMike Christie struct iscsi_cls_session *cls_sess; 169513483730SMike Christie struct iscsi_cls_conn *cls_conn; 169613483730SMike Christie uint32_t ddb_state; 169713483730SMike Christie dma_addr_t fw_ddb_entry_dma; 169813483730SMike Christie struct dev_db_entry *fw_ddb_entry; 169913483730SMike Christie 170013483730SMike Christie fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), 170113483730SMike Christie &fw_ddb_entry_dma, GFP_KERNEL); 170213483730SMike Christie if (!fw_ddb_entry) { 170313483730SMike Christie ql4_printk(KERN_ERR, ha, 170413483730SMike Christie "%s: Unable to allocate dma buffer\n", __func__); 170513483730SMike Christie goto exit_session_conn_fwddb_param; 170613483730SMike Christie } 170713483730SMike Christie 170813483730SMike Christie if (qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index, fw_ddb_entry, 170913483730SMike Christie fw_ddb_entry_dma, NULL, NULL, &ddb_state, 171013483730SMike Christie NULL, NULL, NULL) == QLA_ERROR) { 171113483730SMike Christie DEBUG2(ql4_printk(KERN_ERR, ha, "scsi%ld: %s: failed " 171213483730SMike Christie "get_ddb_entry for fw_ddb_index %d\n", 171313483730SMike Christie ha->host_no, __func__, 171413483730SMike Christie ddb_entry->fw_ddb_index)); 171513483730SMike Christie goto exit_session_conn_fwddb_param; 171613483730SMike Christie } 171713483730SMike Christie 171813483730SMike Christie cls_sess = ddb_entry->sess; 171913483730SMike Christie 172013483730SMike Christie cls_conn = ddb_entry->conn; 172113483730SMike Christie 172213483730SMike Christie /* Update params */ 172313483730SMike Christie qla4xxx_copy_fwddb_param(ha, fw_ddb_entry, cls_sess, cls_conn); 172413483730SMike Christie 172513483730SMike Christie exit_session_conn_fwddb_param: 172613483730SMike Christie if (fw_ddb_entry) 172713483730SMike Christie dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), 172813483730SMike Christie fw_ddb_entry, fw_ddb_entry_dma); 172913483730SMike Christie } 173013483730SMike Christie 1731b3a271a9SManish Rangankar void qla4xxx_update_session_conn_param(struct scsi_qla_host *ha, 1732b3a271a9SManish Rangankar struct ddb_entry *ddb_entry) 1733b3a271a9SManish Rangankar { 1734b3a271a9SManish Rangankar struct iscsi_cls_session *cls_sess; 1735b3a271a9SManish Rangankar struct iscsi_cls_conn *cls_conn; 1736b3a271a9SManish Rangankar struct iscsi_session *sess; 1737b3a271a9SManish Rangankar struct iscsi_conn *conn; 1738b3a271a9SManish Rangankar uint32_t ddb_state; 1739b3a271a9SManish Rangankar dma_addr_t fw_ddb_entry_dma; 1740b3a271a9SManish Rangankar struct dev_db_entry *fw_ddb_entry; 1741b3a271a9SManish Rangankar 1742b3a271a9SManish Rangankar fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), 1743b3a271a9SManish Rangankar &fw_ddb_entry_dma, GFP_KERNEL); 1744b3a271a9SManish Rangankar if (!fw_ddb_entry) { 1745b3a271a9SManish Rangankar ql4_printk(KERN_ERR, ha, 1746b3a271a9SManish Rangankar "%s: Unable to allocate dma buffer\n", __func__); 174713483730SMike Christie goto exit_session_conn_param; 1748b3a271a9SManish Rangankar } 1749b3a271a9SManish Rangankar 1750b3a271a9SManish Rangankar if (qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index, fw_ddb_entry, 1751b3a271a9SManish Rangankar fw_ddb_entry_dma, NULL, NULL, &ddb_state, 1752b3a271a9SManish Rangankar NULL, NULL, NULL) == QLA_ERROR) { 1753b3a271a9SManish Rangankar DEBUG2(ql4_printk(KERN_ERR, ha, "scsi%ld: %s: failed " 1754b3a271a9SManish Rangankar "get_ddb_entry for fw_ddb_index %d\n", 1755b3a271a9SManish Rangankar ha->host_no, __func__, 1756b3a271a9SManish Rangankar ddb_entry->fw_ddb_index)); 175713483730SMike Christie goto exit_session_conn_param; 1758b3a271a9SManish Rangankar } 1759b3a271a9SManish Rangankar 1760b3a271a9SManish Rangankar cls_sess = ddb_entry->sess; 1761b3a271a9SManish Rangankar sess = cls_sess->dd_data; 1762b3a271a9SManish Rangankar 1763b3a271a9SManish Rangankar cls_conn = ddb_entry->conn; 1764b3a271a9SManish Rangankar conn = cls_conn->dd_data; 1765b3a271a9SManish Rangankar 176613483730SMike Christie /* Update timers after login */ 176713483730SMike Christie ddb_entry->default_relogin_timeout = 1768c28eaacaSNilesh Javali (le16_to_cpu(fw_ddb_entry->def_timeout) > LOGIN_TOV) && 1769c28eaacaSNilesh Javali (le16_to_cpu(fw_ddb_entry->def_timeout) < LOGIN_TOV * 10) ? 1770c28eaacaSNilesh Javali le16_to_cpu(fw_ddb_entry->def_timeout) : LOGIN_TOV; 177113483730SMike Christie ddb_entry->default_time2wait = 177213483730SMike Christie le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait); 177313483730SMike Christie 1774b3a271a9SManish Rangankar /* Update params */ 1775b3a271a9SManish Rangankar conn->max_recv_dlength = BYTE_UNITS * 1776b3a271a9SManish Rangankar le16_to_cpu(fw_ddb_entry->iscsi_max_rcv_data_seg_len); 1777b3a271a9SManish Rangankar 1778b3a271a9SManish Rangankar conn->max_xmit_dlength = BYTE_UNITS * 1779b3a271a9SManish Rangankar le16_to_cpu(fw_ddb_entry->iscsi_max_snd_data_seg_len); 1780b3a271a9SManish Rangankar 1781b3a271a9SManish Rangankar sess->initial_r2t_en = 1782b3a271a9SManish Rangankar (BIT_10 & le16_to_cpu(fw_ddb_entry->iscsi_options)); 1783b3a271a9SManish Rangankar 1784b3a271a9SManish Rangankar sess->max_r2t = le16_to_cpu(fw_ddb_entry->iscsi_max_outsnd_r2t); 1785b3a271a9SManish Rangankar 1786b3a271a9SManish Rangankar sess->imm_data_en = (BIT_11 & le16_to_cpu(fw_ddb_entry->iscsi_options)); 1787b3a271a9SManish Rangankar 1788b3a271a9SManish Rangankar sess->first_burst = BYTE_UNITS * 1789b3a271a9SManish Rangankar le16_to_cpu(fw_ddb_entry->iscsi_first_burst_len); 1790b3a271a9SManish Rangankar 1791b3a271a9SManish Rangankar sess->max_burst = BYTE_UNITS * 1792b3a271a9SManish Rangankar le16_to_cpu(fw_ddb_entry->iscsi_max_burst_len); 1793b3a271a9SManish Rangankar 1794b3a271a9SManish Rangankar sess->time2wait = le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait); 1795b3a271a9SManish Rangankar 1796b3a271a9SManish Rangankar sess->time2retain = le16_to_cpu(fw_ddb_entry->iscsi_def_time2retain); 1797b3a271a9SManish Rangankar 1798b3a271a9SManish Rangankar sess->tpgt = le32_to_cpu(fw_ddb_entry->tgt_portal_grp); 1799b3a271a9SManish Rangankar 1800b3a271a9SManish Rangankar memcpy(sess->initiatorname, ha->name_string, 1801b3a271a9SManish Rangankar min(sizeof(ha->name_string), sizeof(sess->initiatorname))); 180213483730SMike Christie 18036c1b8789SVikas Chaudhary iscsi_set_param(cls_conn, ISCSI_PARAM_TARGET_ALIAS, 18046c1b8789SVikas Chaudhary (char *)fw_ddb_entry->iscsi_alias, 0); 18056c1b8789SVikas Chaudhary 180613483730SMike Christie exit_session_conn_param: 180713483730SMike Christie if (fw_ddb_entry) 180813483730SMike Christie dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), 180913483730SMike Christie fw_ddb_entry, fw_ddb_entry_dma); 1810b3a271a9SManish Rangankar } 1811b3a271a9SManish Rangankar 1812afaf5a2dSDavid Somayajulu /* 1813afaf5a2dSDavid Somayajulu * Timer routines 1814afaf5a2dSDavid Somayajulu */ 1815afaf5a2dSDavid Somayajulu 1816afaf5a2dSDavid Somayajulu static void qla4xxx_start_timer(struct scsi_qla_host *ha, void *func, 1817afaf5a2dSDavid Somayajulu unsigned long interval) 1818afaf5a2dSDavid Somayajulu { 1819afaf5a2dSDavid Somayajulu DEBUG(printk("scsi: %s: Starting timer thread for adapter %d\n", 1820afaf5a2dSDavid Somayajulu __func__, ha->host->host_no)); 1821afaf5a2dSDavid Somayajulu init_timer(&ha->timer); 1822afaf5a2dSDavid Somayajulu ha->timer.expires = jiffies + interval * HZ; 1823afaf5a2dSDavid Somayajulu ha->timer.data = (unsigned long)ha; 1824afaf5a2dSDavid Somayajulu ha->timer.function = (void (*)(unsigned long))func; 1825afaf5a2dSDavid Somayajulu add_timer(&ha->timer); 1826afaf5a2dSDavid Somayajulu ha->timer_active = 1; 1827afaf5a2dSDavid Somayajulu } 1828afaf5a2dSDavid Somayajulu 1829afaf5a2dSDavid Somayajulu static void qla4xxx_stop_timer(struct scsi_qla_host *ha) 1830afaf5a2dSDavid Somayajulu { 1831afaf5a2dSDavid Somayajulu del_timer_sync(&ha->timer); 1832afaf5a2dSDavid Somayajulu ha->timer_active = 0; 1833afaf5a2dSDavid Somayajulu } 1834afaf5a2dSDavid Somayajulu 1835afaf5a2dSDavid Somayajulu /*** 1836b3a271a9SManish Rangankar * qla4xxx_mark_device_missing - blocks the session 1837b3a271a9SManish Rangankar * @cls_session: Pointer to the session to be blocked 1838afaf5a2dSDavid Somayajulu * @ddb_entry: Pointer to device database entry 1839afaf5a2dSDavid Somayajulu * 1840f4f5df23SVikas Chaudhary * This routine marks a device missing and close connection. 1841afaf5a2dSDavid Somayajulu **/ 1842b3a271a9SManish Rangankar void qla4xxx_mark_device_missing(struct iscsi_cls_session *cls_session) 1843afaf5a2dSDavid Somayajulu { 1844b3a271a9SManish Rangankar iscsi_block_session(cls_session); 1845afaf5a2dSDavid Somayajulu } 1846afaf5a2dSDavid Somayajulu 1847f4f5df23SVikas Chaudhary /** 1848f4f5df23SVikas Chaudhary * qla4xxx_mark_all_devices_missing - mark all devices as missing. 1849f4f5df23SVikas Chaudhary * @ha: Pointer to host adapter structure. 1850f4f5df23SVikas Chaudhary * 1851f4f5df23SVikas Chaudhary * This routine marks a device missing and resets the relogin retry count. 1852f4f5df23SVikas Chaudhary **/ 1853f4f5df23SVikas Chaudhary void qla4xxx_mark_all_devices_missing(struct scsi_qla_host *ha) 1854f4f5df23SVikas Chaudhary { 1855b3a271a9SManish Rangankar iscsi_host_for_each_session(ha->host, qla4xxx_mark_device_missing); 1856f4f5df23SVikas Chaudhary } 1857f4f5df23SVikas Chaudhary 1858afaf5a2dSDavid Somayajulu static struct srb* qla4xxx_get_new_srb(struct scsi_qla_host *ha, 1859afaf5a2dSDavid Somayajulu struct ddb_entry *ddb_entry, 18608f0722caSVikas Chaudhary struct scsi_cmnd *cmd) 1861afaf5a2dSDavid Somayajulu { 1862afaf5a2dSDavid Somayajulu struct srb *srb; 1863afaf5a2dSDavid Somayajulu 1864afaf5a2dSDavid Somayajulu srb = mempool_alloc(ha->srb_mempool, GFP_ATOMIC); 1865afaf5a2dSDavid Somayajulu if (!srb) 1866afaf5a2dSDavid Somayajulu return srb; 1867afaf5a2dSDavid Somayajulu 186809a0f719SVikas Chaudhary kref_init(&srb->srb_ref); 1869afaf5a2dSDavid Somayajulu srb->ha = ha; 1870afaf5a2dSDavid Somayajulu srb->ddb = ddb_entry; 1871afaf5a2dSDavid Somayajulu srb->cmd = cmd; 1872afaf5a2dSDavid Somayajulu srb->flags = 0; 18735369887aSVikas Chaudhary CMD_SP(cmd) = (void *)srb; 1874afaf5a2dSDavid Somayajulu 1875afaf5a2dSDavid Somayajulu return srb; 1876afaf5a2dSDavid Somayajulu } 1877afaf5a2dSDavid Somayajulu 1878afaf5a2dSDavid Somayajulu static void qla4xxx_srb_free_dma(struct scsi_qla_host *ha, struct srb *srb) 1879afaf5a2dSDavid Somayajulu { 1880afaf5a2dSDavid Somayajulu struct scsi_cmnd *cmd = srb->cmd; 1881afaf5a2dSDavid Somayajulu 1882afaf5a2dSDavid Somayajulu if (srb->flags & SRB_DMA_VALID) { 18835f7186c8SFUJITA Tomonori scsi_dma_unmap(cmd); 1884afaf5a2dSDavid Somayajulu srb->flags &= ~SRB_DMA_VALID; 1885afaf5a2dSDavid Somayajulu } 18865369887aSVikas Chaudhary CMD_SP(cmd) = NULL; 1887afaf5a2dSDavid Somayajulu } 1888afaf5a2dSDavid Somayajulu 188909a0f719SVikas Chaudhary void qla4xxx_srb_compl(struct kref *ref) 1890afaf5a2dSDavid Somayajulu { 189109a0f719SVikas Chaudhary struct srb *srb = container_of(ref, struct srb, srb_ref); 1892afaf5a2dSDavid Somayajulu struct scsi_cmnd *cmd = srb->cmd; 189309a0f719SVikas Chaudhary struct scsi_qla_host *ha = srb->ha; 1894afaf5a2dSDavid Somayajulu 1895afaf5a2dSDavid Somayajulu qla4xxx_srb_free_dma(ha, srb); 1896afaf5a2dSDavid Somayajulu 1897afaf5a2dSDavid Somayajulu mempool_free(srb, ha->srb_mempool); 1898afaf5a2dSDavid Somayajulu 1899afaf5a2dSDavid Somayajulu cmd->scsi_done(cmd); 1900afaf5a2dSDavid Somayajulu } 1901afaf5a2dSDavid Somayajulu 1902afaf5a2dSDavid Somayajulu /** 1903afaf5a2dSDavid Somayajulu * qla4xxx_queuecommand - scsi layer issues scsi command to driver. 19048f0722caSVikas Chaudhary * @host: scsi host 1905afaf5a2dSDavid Somayajulu * @cmd: Pointer to Linux's SCSI command structure 1906afaf5a2dSDavid Somayajulu * 1907afaf5a2dSDavid Somayajulu * Remarks: 1908afaf5a2dSDavid Somayajulu * This routine is invoked by Linux to send a SCSI command to the driver. 1909afaf5a2dSDavid Somayajulu * The mid-level driver tries to ensure that queuecommand never gets 1910afaf5a2dSDavid Somayajulu * invoked concurrently with itself or the interrupt handler (although 1911afaf5a2dSDavid Somayajulu * the interrupt handler may call this routine as part of request- 1912afaf5a2dSDavid Somayajulu * completion handling). Unfortunely, it sometimes calls the scheduler 1913afaf5a2dSDavid Somayajulu * in interrupt context which is a big NO! NO!. 1914afaf5a2dSDavid Somayajulu **/ 19158f0722caSVikas Chaudhary static int qla4xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) 1916afaf5a2dSDavid Somayajulu { 19178f0722caSVikas Chaudhary struct scsi_qla_host *ha = to_qla_host(host); 1918afaf5a2dSDavid Somayajulu struct ddb_entry *ddb_entry = cmd->device->hostdata; 19197fb1921bSMike Christie struct iscsi_cls_session *sess = ddb_entry->sess; 1920afaf5a2dSDavid Somayajulu struct srb *srb; 1921afaf5a2dSDavid Somayajulu int rval; 1922afaf5a2dSDavid Somayajulu 19232232be0dSLalit Chandivade if (test_bit(AF_EEH_BUSY, &ha->flags)) { 19242232be0dSLalit Chandivade if (test_bit(AF_PCI_CHANNEL_IO_PERM_FAILURE, &ha->flags)) 19252232be0dSLalit Chandivade cmd->result = DID_NO_CONNECT << 16; 19262232be0dSLalit Chandivade else 19272232be0dSLalit Chandivade cmd->result = DID_REQUEUE << 16; 19282232be0dSLalit Chandivade goto qc_fail_command; 19292232be0dSLalit Chandivade } 19302232be0dSLalit Chandivade 19317fb1921bSMike Christie if (!sess) { 19327fb1921bSMike Christie cmd->result = DID_IMM_RETRY << 16; 19337fb1921bSMike Christie goto qc_fail_command; 19347fb1921bSMike Christie } 19357fb1921bSMike Christie 19367fb1921bSMike Christie rval = iscsi_session_chkready(sess); 19377fb1921bSMike Christie if (rval) { 19387fb1921bSMike Christie cmd->result = rval; 19397fb1921bSMike Christie goto qc_fail_command; 19407fb1921bSMike Christie } 19417fb1921bSMike Christie 1942f4f5df23SVikas Chaudhary if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) || 1943f4f5df23SVikas Chaudhary test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags) || 1944f4f5df23SVikas Chaudhary test_bit(DPC_RESET_HA, &ha->dpc_flags) || 1945f4f5df23SVikas Chaudhary test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags) || 1946f4f5df23SVikas Chaudhary test_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags) || 1947f4f5df23SVikas Chaudhary !test_bit(AF_ONLINE, &ha->flags) || 1948b3a271a9SManish Rangankar !test_bit(AF_LINK_UP, &ha->flags) || 1949f4f5df23SVikas Chaudhary test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags)) 1950477ffb9dSDavid C Somayajulu goto qc_host_busy; 1951477ffb9dSDavid C Somayajulu 19528f0722caSVikas Chaudhary srb = qla4xxx_get_new_srb(ha, ddb_entry, cmd); 1953afaf5a2dSDavid Somayajulu if (!srb) 19548f0722caSVikas Chaudhary goto qc_host_busy; 1955afaf5a2dSDavid Somayajulu 1956afaf5a2dSDavid Somayajulu rval = qla4xxx_send_command_to_isp(ha, srb); 1957afaf5a2dSDavid Somayajulu if (rval != QLA_SUCCESS) 1958afaf5a2dSDavid Somayajulu goto qc_host_busy_free_sp; 1959afaf5a2dSDavid Somayajulu 1960afaf5a2dSDavid Somayajulu return 0; 1961afaf5a2dSDavid Somayajulu 1962afaf5a2dSDavid Somayajulu qc_host_busy_free_sp: 1963afaf5a2dSDavid Somayajulu qla4xxx_srb_free_dma(ha, srb); 1964afaf5a2dSDavid Somayajulu mempool_free(srb, ha->srb_mempool); 1965afaf5a2dSDavid Somayajulu 1966afaf5a2dSDavid Somayajulu qc_host_busy: 1967afaf5a2dSDavid Somayajulu return SCSI_MLQUEUE_HOST_BUSY; 1968afaf5a2dSDavid Somayajulu 1969afaf5a2dSDavid Somayajulu qc_fail_command: 19708f0722caSVikas Chaudhary cmd->scsi_done(cmd); 1971afaf5a2dSDavid Somayajulu 1972afaf5a2dSDavid Somayajulu return 0; 1973afaf5a2dSDavid Somayajulu } 1974afaf5a2dSDavid Somayajulu 1975afaf5a2dSDavid Somayajulu /** 1976afaf5a2dSDavid Somayajulu * qla4xxx_mem_free - frees memory allocated to adapter 1977afaf5a2dSDavid Somayajulu * @ha: Pointer to host adapter structure. 1978afaf5a2dSDavid Somayajulu * 1979afaf5a2dSDavid Somayajulu * Frees memory previously allocated by qla4xxx_mem_alloc 1980afaf5a2dSDavid Somayajulu **/ 1981afaf5a2dSDavid Somayajulu static void qla4xxx_mem_free(struct scsi_qla_host *ha) 1982afaf5a2dSDavid Somayajulu { 1983afaf5a2dSDavid Somayajulu if (ha->queues) 1984afaf5a2dSDavid Somayajulu dma_free_coherent(&ha->pdev->dev, ha->queues_len, ha->queues, 1985afaf5a2dSDavid Somayajulu ha->queues_dma); 1986afaf5a2dSDavid Somayajulu 1987afaf5a2dSDavid Somayajulu ha->queues_len = 0; 1988afaf5a2dSDavid Somayajulu ha->queues = NULL; 1989afaf5a2dSDavid Somayajulu ha->queues_dma = 0; 1990afaf5a2dSDavid Somayajulu ha->request_ring = NULL; 1991afaf5a2dSDavid Somayajulu ha->request_dma = 0; 1992afaf5a2dSDavid Somayajulu ha->response_ring = NULL; 1993afaf5a2dSDavid Somayajulu ha->response_dma = 0; 1994afaf5a2dSDavid Somayajulu ha->shadow_regs = NULL; 1995afaf5a2dSDavid Somayajulu ha->shadow_regs_dma = 0; 1996afaf5a2dSDavid Somayajulu 1997afaf5a2dSDavid Somayajulu /* Free srb pool. */ 1998afaf5a2dSDavid Somayajulu if (ha->srb_mempool) 1999afaf5a2dSDavid Somayajulu mempool_destroy(ha->srb_mempool); 2000afaf5a2dSDavid Somayajulu 2001afaf5a2dSDavid Somayajulu ha->srb_mempool = NULL; 2002afaf5a2dSDavid Somayajulu 2003b3a271a9SManish Rangankar if (ha->chap_dma_pool) 2004b3a271a9SManish Rangankar dma_pool_destroy(ha->chap_dma_pool); 2005b3a271a9SManish Rangankar 20064549415aSLalit Chandivade if (ha->chap_list) 20074549415aSLalit Chandivade vfree(ha->chap_list); 20084549415aSLalit Chandivade ha->chap_list = NULL; 20094549415aSLalit Chandivade 201013483730SMike Christie if (ha->fw_ddb_dma_pool) 201113483730SMike Christie dma_pool_destroy(ha->fw_ddb_dma_pool); 201213483730SMike Christie 2013afaf5a2dSDavid Somayajulu /* release io space registers */ 2014f4f5df23SVikas Chaudhary if (is_qla8022(ha)) { 2015f4f5df23SVikas Chaudhary if (ha->nx_pcibase) 2016f4f5df23SVikas Chaudhary iounmap( 2017f4f5df23SVikas Chaudhary (struct device_reg_82xx __iomem *)ha->nx_pcibase); 2018f4f5df23SVikas Chaudhary } else if (ha->reg) 2019afaf5a2dSDavid Somayajulu iounmap(ha->reg); 2020afaf5a2dSDavid Somayajulu pci_release_regions(ha->pdev); 2021afaf5a2dSDavid Somayajulu } 2022afaf5a2dSDavid Somayajulu 2023afaf5a2dSDavid Somayajulu /** 2024afaf5a2dSDavid Somayajulu * qla4xxx_mem_alloc - allocates memory for use by adapter. 2025afaf5a2dSDavid Somayajulu * @ha: Pointer to host adapter structure 2026afaf5a2dSDavid Somayajulu * 2027afaf5a2dSDavid Somayajulu * Allocates DMA memory for request and response queues. Also allocates memory 2028afaf5a2dSDavid Somayajulu * for srbs. 2029afaf5a2dSDavid Somayajulu **/ 2030afaf5a2dSDavid Somayajulu static int qla4xxx_mem_alloc(struct scsi_qla_host *ha) 2031afaf5a2dSDavid Somayajulu { 2032afaf5a2dSDavid Somayajulu unsigned long align; 2033afaf5a2dSDavid Somayajulu 2034afaf5a2dSDavid Somayajulu /* Allocate contiguous block of DMA memory for queues. */ 2035afaf5a2dSDavid Somayajulu ha->queues_len = ((REQUEST_QUEUE_DEPTH * QUEUE_SIZE) + 2036afaf5a2dSDavid Somayajulu (RESPONSE_QUEUE_DEPTH * QUEUE_SIZE) + 2037afaf5a2dSDavid Somayajulu sizeof(struct shadow_regs) + 2038afaf5a2dSDavid Somayajulu MEM_ALIGN_VALUE + 2039afaf5a2dSDavid Somayajulu (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1); 2040afaf5a2dSDavid Somayajulu ha->queues = dma_alloc_coherent(&ha->pdev->dev, ha->queues_len, 2041afaf5a2dSDavid Somayajulu &ha->queues_dma, GFP_KERNEL); 2042afaf5a2dSDavid Somayajulu if (ha->queues == NULL) { 2043c2660df3SVikas Chaudhary ql4_printk(KERN_WARNING, ha, 2044afaf5a2dSDavid Somayajulu "Memory Allocation failed - queues.\n"); 2045afaf5a2dSDavid Somayajulu 2046afaf5a2dSDavid Somayajulu goto mem_alloc_error_exit; 2047afaf5a2dSDavid Somayajulu } 2048afaf5a2dSDavid Somayajulu memset(ha->queues, 0, ha->queues_len); 2049afaf5a2dSDavid Somayajulu 2050afaf5a2dSDavid Somayajulu /* 2051afaf5a2dSDavid Somayajulu * As per RISC alignment requirements -- the bus-address must be a 2052afaf5a2dSDavid Somayajulu * multiple of the request-ring size (in bytes). 2053afaf5a2dSDavid Somayajulu */ 2054afaf5a2dSDavid Somayajulu align = 0; 2055afaf5a2dSDavid Somayajulu if ((unsigned long)ha->queues_dma & (MEM_ALIGN_VALUE - 1)) 2056afaf5a2dSDavid Somayajulu align = MEM_ALIGN_VALUE - ((unsigned long)ha->queues_dma & 2057afaf5a2dSDavid Somayajulu (MEM_ALIGN_VALUE - 1)); 2058afaf5a2dSDavid Somayajulu 2059afaf5a2dSDavid Somayajulu /* Update request and response queue pointers. */ 2060afaf5a2dSDavid Somayajulu ha->request_dma = ha->queues_dma + align; 2061afaf5a2dSDavid Somayajulu ha->request_ring = (struct queue_entry *) (ha->queues + align); 2062afaf5a2dSDavid Somayajulu ha->response_dma = ha->queues_dma + align + 2063afaf5a2dSDavid Somayajulu (REQUEST_QUEUE_DEPTH * QUEUE_SIZE); 2064afaf5a2dSDavid Somayajulu ha->response_ring = (struct queue_entry *) (ha->queues + align + 2065afaf5a2dSDavid Somayajulu (REQUEST_QUEUE_DEPTH * 2066afaf5a2dSDavid Somayajulu QUEUE_SIZE)); 2067afaf5a2dSDavid Somayajulu ha->shadow_regs_dma = ha->queues_dma + align + 2068afaf5a2dSDavid Somayajulu (REQUEST_QUEUE_DEPTH * QUEUE_SIZE) + 2069afaf5a2dSDavid Somayajulu (RESPONSE_QUEUE_DEPTH * QUEUE_SIZE); 2070afaf5a2dSDavid Somayajulu ha->shadow_regs = (struct shadow_regs *) (ha->queues + align + 2071afaf5a2dSDavid Somayajulu (REQUEST_QUEUE_DEPTH * 2072afaf5a2dSDavid Somayajulu QUEUE_SIZE) + 2073afaf5a2dSDavid Somayajulu (RESPONSE_QUEUE_DEPTH * 2074afaf5a2dSDavid Somayajulu QUEUE_SIZE)); 2075afaf5a2dSDavid Somayajulu 2076afaf5a2dSDavid Somayajulu /* Allocate memory for srb pool. */ 2077afaf5a2dSDavid Somayajulu ha->srb_mempool = mempool_create(SRB_MIN_REQ, mempool_alloc_slab, 2078afaf5a2dSDavid Somayajulu mempool_free_slab, srb_cachep); 2079afaf5a2dSDavid Somayajulu if (ha->srb_mempool == NULL) { 2080c2660df3SVikas Chaudhary ql4_printk(KERN_WARNING, ha, 2081afaf5a2dSDavid Somayajulu "Memory Allocation failed - SRB Pool.\n"); 2082afaf5a2dSDavid Somayajulu 2083afaf5a2dSDavid Somayajulu goto mem_alloc_error_exit; 2084afaf5a2dSDavid Somayajulu } 2085afaf5a2dSDavid Somayajulu 2086b3a271a9SManish Rangankar ha->chap_dma_pool = dma_pool_create("ql4_chap", &ha->pdev->dev, 2087b3a271a9SManish Rangankar CHAP_DMA_BLOCK_SIZE, 8, 0); 2088b3a271a9SManish Rangankar 2089b3a271a9SManish Rangankar if (ha->chap_dma_pool == NULL) { 2090b3a271a9SManish Rangankar ql4_printk(KERN_WARNING, ha, 2091b3a271a9SManish Rangankar "%s: chap_dma_pool allocation failed..\n", __func__); 2092b3a271a9SManish Rangankar goto mem_alloc_error_exit; 2093b3a271a9SManish Rangankar } 2094b3a271a9SManish Rangankar 209513483730SMike Christie ha->fw_ddb_dma_pool = dma_pool_create("ql4_fw_ddb", &ha->pdev->dev, 209613483730SMike Christie DDB_DMA_BLOCK_SIZE, 8, 0); 209713483730SMike Christie 209813483730SMike Christie if (ha->fw_ddb_dma_pool == NULL) { 209913483730SMike Christie ql4_printk(KERN_WARNING, ha, 210013483730SMike Christie "%s: fw_ddb_dma_pool allocation failed..\n", 210113483730SMike Christie __func__); 210213483730SMike Christie goto mem_alloc_error_exit; 210313483730SMike Christie } 210413483730SMike Christie 2105afaf5a2dSDavid Somayajulu return QLA_SUCCESS; 2106afaf5a2dSDavid Somayajulu 2107afaf5a2dSDavid Somayajulu mem_alloc_error_exit: 2108afaf5a2dSDavid Somayajulu qla4xxx_mem_free(ha); 2109afaf5a2dSDavid Somayajulu return QLA_ERROR; 2110afaf5a2dSDavid Somayajulu } 2111afaf5a2dSDavid Somayajulu 2112afaf5a2dSDavid Somayajulu /** 21134f77083eSMike Hernandez * qla4_8xxx_check_temp - Check the ISP82XX temperature. 21144f77083eSMike Hernandez * @ha: adapter block pointer. 21154f77083eSMike Hernandez * 21164f77083eSMike Hernandez * Note: The caller should not hold the idc lock. 21174f77083eSMike Hernandez **/ 21184f77083eSMike Hernandez static int qla4_8xxx_check_temp(struct scsi_qla_host *ha) 21194f77083eSMike Hernandez { 21204f77083eSMike Hernandez uint32_t temp, temp_state, temp_val; 21214f77083eSMike Hernandez int status = QLA_SUCCESS; 21224f77083eSMike Hernandez 21234f77083eSMike Hernandez temp = qla4_8xxx_rd_32(ha, CRB_TEMP_STATE); 21244f77083eSMike Hernandez 21254f77083eSMike Hernandez temp_state = qla82xx_get_temp_state(temp); 21264f77083eSMike Hernandez temp_val = qla82xx_get_temp_val(temp); 21274f77083eSMike Hernandez 21284f77083eSMike Hernandez if (temp_state == QLA82XX_TEMP_PANIC) { 21294f77083eSMike Hernandez ql4_printk(KERN_WARNING, ha, "Device temperature %d degrees C" 21304f77083eSMike Hernandez " exceeds maximum allowed. Hardware has been shut" 21314f77083eSMike Hernandez " down.\n", temp_val); 21324f77083eSMike Hernandez status = QLA_ERROR; 21334f77083eSMike Hernandez } else if (temp_state == QLA82XX_TEMP_WARN) { 21344f77083eSMike Hernandez if (ha->temperature == QLA82XX_TEMP_NORMAL) 21354f77083eSMike Hernandez ql4_printk(KERN_WARNING, ha, "Device temperature %d" 21364f77083eSMike Hernandez " degrees C exceeds operating range." 21374f77083eSMike Hernandez " Immediate action needed.\n", temp_val); 21384f77083eSMike Hernandez } else { 21394f77083eSMike Hernandez if (ha->temperature == QLA82XX_TEMP_WARN) 21404f77083eSMike Hernandez ql4_printk(KERN_INFO, ha, "Device temperature is" 21414f77083eSMike Hernandez " now %d degrees C in normal range.\n", 21424f77083eSMike Hernandez temp_val); 21434f77083eSMike Hernandez } 21444f77083eSMike Hernandez ha->temperature = temp_state; 21454f77083eSMike Hernandez return status; 21464f77083eSMike Hernandez } 21474f77083eSMike Hernandez 21484f77083eSMike Hernandez /** 2149f4f5df23SVikas Chaudhary * qla4_8xxx_check_fw_alive - Check firmware health 2150f4f5df23SVikas Chaudhary * @ha: Pointer to host adapter structure. 2151f4f5df23SVikas Chaudhary * 2152f4f5df23SVikas Chaudhary * Context: Interrupt 2153f4f5df23SVikas Chaudhary **/ 21549ee91a38SShyam Sunder static int qla4_8xxx_check_fw_alive(struct scsi_qla_host *ha) 2155f4f5df23SVikas Chaudhary { 21569ee91a38SShyam Sunder uint32_t fw_heartbeat_counter; 21579ee91a38SShyam Sunder int status = QLA_SUCCESS; 2158f4f5df23SVikas Chaudhary 2159f4f5df23SVikas Chaudhary fw_heartbeat_counter = qla4_8xxx_rd_32(ha, QLA82XX_PEG_ALIVE_COUNTER); 21602232be0dSLalit Chandivade /* If PEG_ALIVE_COUNTER is 0xffffffff, AER/EEH is in progress, ignore */ 21612232be0dSLalit Chandivade if (fw_heartbeat_counter == 0xffffffff) { 21622232be0dSLalit Chandivade DEBUG2(printk(KERN_WARNING "scsi%ld: %s: Device in frozen " 21632232be0dSLalit Chandivade "state, QLA82XX_PEG_ALIVE_COUNTER is 0xffffffff\n", 21642232be0dSLalit Chandivade ha->host_no, __func__)); 21659ee91a38SShyam Sunder return status; 21662232be0dSLalit Chandivade } 2167f4f5df23SVikas Chaudhary 2168f4f5df23SVikas Chaudhary if (ha->fw_heartbeat_counter == fw_heartbeat_counter) { 2169f4f5df23SVikas Chaudhary ha->seconds_since_last_heartbeat++; 2170f4f5df23SVikas Chaudhary /* FW not alive after 2 seconds */ 2171f4f5df23SVikas Chaudhary if (ha->seconds_since_last_heartbeat == 2) { 2172f4f5df23SVikas Chaudhary ha->seconds_since_last_heartbeat = 0; 217368d92ebfSVikas Chaudhary 217468d92ebfSVikas Chaudhary ql4_printk(KERN_INFO, ha, 217568d92ebfSVikas Chaudhary "scsi(%ld): %s, Dumping hw/fw registers:\n " 217668d92ebfSVikas Chaudhary " PEG_HALT_STATUS1: 0x%x, PEG_HALT_STATUS2:" 217768d92ebfSVikas Chaudhary " 0x%x,\n PEG_NET_0_PC: 0x%x, PEG_NET_1_PC:" 217868d92ebfSVikas Chaudhary " 0x%x,\n PEG_NET_2_PC: 0x%x, PEG_NET_3_PC:" 217968d92ebfSVikas Chaudhary " 0x%x,\n PEG_NET_4_PC: 0x%x\n", 21809ee91a38SShyam Sunder ha->host_no, __func__, 21819ee91a38SShyam Sunder qla4_8xxx_rd_32(ha, 21829ee91a38SShyam Sunder QLA82XX_PEG_HALT_STATUS1), 218368d92ebfSVikas Chaudhary qla4_8xxx_rd_32(ha, 218468d92ebfSVikas Chaudhary QLA82XX_PEG_HALT_STATUS2), 218568d92ebfSVikas Chaudhary qla4_8xxx_rd_32(ha, QLA82XX_CRB_PEG_NET_0 + 218668d92ebfSVikas Chaudhary 0x3c), 218768d92ebfSVikas Chaudhary qla4_8xxx_rd_32(ha, QLA82XX_CRB_PEG_NET_1 + 218868d92ebfSVikas Chaudhary 0x3c), 218968d92ebfSVikas Chaudhary qla4_8xxx_rd_32(ha, QLA82XX_CRB_PEG_NET_2 + 219068d92ebfSVikas Chaudhary 0x3c), 219168d92ebfSVikas Chaudhary qla4_8xxx_rd_32(ha, QLA82XX_CRB_PEG_NET_3 + 219268d92ebfSVikas Chaudhary 0x3c), 219368d92ebfSVikas Chaudhary qla4_8xxx_rd_32(ha, QLA82XX_CRB_PEG_NET_4 + 219468d92ebfSVikas Chaudhary 0x3c)); 21959ee91a38SShyam Sunder status = QLA_ERROR; 2196f4f5df23SVikas Chaudhary } 219799457d75SLalit Chandivade } else 219899457d75SLalit Chandivade ha->seconds_since_last_heartbeat = 0; 219999457d75SLalit Chandivade 2200f4f5df23SVikas Chaudhary ha->fw_heartbeat_counter = fw_heartbeat_counter; 22019ee91a38SShyam Sunder return status; 2202f4f5df23SVikas Chaudhary } 2203f4f5df23SVikas Chaudhary 2204f4f5df23SVikas Chaudhary /** 2205f4f5df23SVikas Chaudhary * qla4_8xxx_watchdog - Poll dev state 2206f4f5df23SVikas Chaudhary * @ha: Pointer to host adapter structure. 2207f4f5df23SVikas Chaudhary * 2208f4f5df23SVikas Chaudhary * Context: Interrupt 2209f4f5df23SVikas Chaudhary **/ 2210f4f5df23SVikas Chaudhary void qla4_8xxx_watchdog(struct scsi_qla_host *ha) 2211f4f5df23SVikas Chaudhary { 22129ee91a38SShyam Sunder uint32_t dev_state, halt_status; 2213f4f5df23SVikas Chaudhary 2214f4f5df23SVikas Chaudhary /* don't poll if reset is going on */ 2215d56a1f7bSLalit Chandivade if (!(test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags) || 2216d56a1f7bSLalit Chandivade test_bit(DPC_RESET_HA, &ha->dpc_flags) || 2217977f46a4SVikas Chaudhary test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags))) { 22189ee91a38SShyam Sunder dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE); 22194f77083eSMike Hernandez 22204f77083eSMike Hernandez if (qla4_8xxx_check_temp(ha)) { 2221e6bd0ebdSGiridhar Malavali ql4_printk(KERN_INFO, ha, "disabling pause" 2222e6bd0ebdSGiridhar Malavali " transmit on port 0 & 1.\n"); 2223e6bd0ebdSGiridhar Malavali qla4_8xxx_wr_32(ha, QLA82XX_CRB_NIU + 0x98, 2224e6bd0ebdSGiridhar Malavali CRB_NIU_XG_PAUSE_CTL_P0 | 2225e6bd0ebdSGiridhar Malavali CRB_NIU_XG_PAUSE_CTL_P1); 22264f77083eSMike Hernandez set_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags); 22274f77083eSMike Hernandez qla4xxx_wake_dpc(ha); 22284f77083eSMike Hernandez } else if (dev_state == QLA82XX_DEV_NEED_RESET && 2229f4f5df23SVikas Chaudhary !test_bit(DPC_RESET_HA, &ha->dpc_flags)) { 22303930b8c1SVikas Chaudhary if (!ql4xdontresethba) { 22313930b8c1SVikas Chaudhary ql4_printk(KERN_INFO, ha, "%s: HW State: " 22323930b8c1SVikas Chaudhary "NEED RESET!\n", __func__); 2233f4f5df23SVikas Chaudhary set_bit(DPC_RESET_HA, &ha->dpc_flags); 2234f4f5df23SVikas Chaudhary qla4xxx_wake_dpc(ha); 22353930b8c1SVikas Chaudhary } 2236f4f5df23SVikas Chaudhary } else if (dev_state == QLA82XX_DEV_NEED_QUIESCENT && 2237f4f5df23SVikas Chaudhary !test_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags)) { 22383930b8c1SVikas Chaudhary ql4_printk(KERN_INFO, ha, "%s: HW State: NEED QUIES!\n", 22393930b8c1SVikas Chaudhary __func__); 2240f4f5df23SVikas Chaudhary set_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags); 2241f4f5df23SVikas Chaudhary qla4xxx_wake_dpc(ha); 2242f4f5df23SVikas Chaudhary } else { 2243f4f5df23SVikas Chaudhary /* Check firmware health */ 22449ee91a38SShyam Sunder if (qla4_8xxx_check_fw_alive(ha)) { 2245e6bd0ebdSGiridhar Malavali ql4_printk(KERN_INFO, ha, "disabling pause" 2246e6bd0ebdSGiridhar Malavali " transmit on port 0 & 1.\n"); 2247e6bd0ebdSGiridhar Malavali qla4_8xxx_wr_32(ha, QLA82XX_CRB_NIU + 0x98, 2248e6bd0ebdSGiridhar Malavali CRB_NIU_XG_PAUSE_CTL_P0 | 2249e6bd0ebdSGiridhar Malavali CRB_NIU_XG_PAUSE_CTL_P1); 22509ee91a38SShyam Sunder halt_status = qla4_8xxx_rd_32(ha, 22519ee91a38SShyam Sunder QLA82XX_PEG_HALT_STATUS1); 22529ee91a38SShyam Sunder 225346801ba6SVikas Chaudhary if (QLA82XX_FWERROR_CODE(halt_status) == 0x67) 2254527c8b2eSNilesh Javali ql4_printk(KERN_ERR, ha, "%s:" 2255527c8b2eSNilesh Javali " Firmware aborted with" 2256527c8b2eSNilesh Javali " error code 0x00006700." 2257527c8b2eSNilesh Javali " Device is being reset\n", 2258527c8b2eSNilesh Javali __func__); 2259527c8b2eSNilesh Javali 22609ee91a38SShyam Sunder /* Since we cannot change dev_state in interrupt 22619ee91a38SShyam Sunder * context, set appropriate DPC flag then wakeup 22629ee91a38SShyam Sunder * DPC */ 22639ee91a38SShyam Sunder if (halt_status & HALT_STATUS_UNRECOVERABLE) 22649ee91a38SShyam Sunder set_bit(DPC_HA_UNRECOVERABLE, 22659ee91a38SShyam Sunder &ha->dpc_flags); 22669ee91a38SShyam Sunder else { 22679ee91a38SShyam Sunder ql4_printk(KERN_INFO, ha, "%s: detect " 22689ee91a38SShyam Sunder "abort needed!\n", __func__); 22699ee91a38SShyam Sunder set_bit(DPC_RESET_HA, &ha->dpc_flags); 22709ee91a38SShyam Sunder } 22719ee91a38SShyam Sunder qla4xxx_mailbox_premature_completion(ha); 22729ee91a38SShyam Sunder qla4xxx_wake_dpc(ha); 22739ee91a38SShyam Sunder } 2274f4f5df23SVikas Chaudhary } 2275f4f5df23SVikas Chaudhary } 2276f4f5df23SVikas Chaudhary } 2277f4f5df23SVikas Chaudhary 22784a4bc2e9SLalit Chandivade static void qla4xxx_check_relogin_flash_ddb(struct iscsi_cls_session *cls_sess) 227913483730SMike Christie { 228013483730SMike Christie struct iscsi_session *sess; 228113483730SMike Christie struct ddb_entry *ddb_entry; 228213483730SMike Christie struct scsi_qla_host *ha; 228313483730SMike Christie 228413483730SMike Christie sess = cls_sess->dd_data; 228513483730SMike Christie ddb_entry = sess->dd_data; 228613483730SMike Christie ha = ddb_entry->ha; 228713483730SMike Christie 228813483730SMike Christie if (!(ddb_entry->ddb_type == FLASH_DDB)) 228913483730SMike Christie return; 229013483730SMike Christie 229113483730SMike Christie if (adapter_up(ha) && !test_bit(DF_RELOGIN, &ddb_entry->flags) && 229213483730SMike Christie !iscsi_is_session_online(cls_sess)) { 229313483730SMike Christie if (atomic_read(&ddb_entry->retry_relogin_timer) != 229413483730SMike Christie INVALID_ENTRY) { 229513483730SMike Christie if (atomic_read(&ddb_entry->retry_relogin_timer) == 229613483730SMike Christie 0) { 229713483730SMike Christie atomic_set(&ddb_entry->retry_relogin_timer, 229813483730SMike Christie INVALID_ENTRY); 229913483730SMike Christie set_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags); 230013483730SMike Christie set_bit(DF_RELOGIN, &ddb_entry->flags); 230113483730SMike Christie DEBUG2(ql4_printk(KERN_INFO, ha, 230213483730SMike Christie "%s: index [%d] login device\n", 230313483730SMike Christie __func__, ddb_entry->fw_ddb_index)); 230413483730SMike Christie } else 230513483730SMike Christie atomic_dec(&ddb_entry->retry_relogin_timer); 230613483730SMike Christie } 230713483730SMike Christie } 230813483730SMike Christie 230913483730SMike Christie /* Wait for relogin to timeout */ 231013483730SMike Christie if (atomic_read(&ddb_entry->relogin_timer) && 231113483730SMike Christie (atomic_dec_and_test(&ddb_entry->relogin_timer) != 0)) { 231213483730SMike Christie /* 231313483730SMike Christie * If the relogin times out and the device is 231413483730SMike Christie * still NOT ONLINE then try and relogin again. 231513483730SMike Christie */ 231613483730SMike Christie if (!iscsi_is_session_online(cls_sess)) { 231713483730SMike Christie /* Reset retry relogin timer */ 231813483730SMike Christie atomic_inc(&ddb_entry->relogin_retry_count); 231913483730SMike Christie DEBUG2(ql4_printk(KERN_INFO, ha, 232013483730SMike Christie "%s: index[%d] relogin timed out-retrying" 232113483730SMike Christie " relogin (%d), retry (%d)\n", __func__, 232213483730SMike Christie ddb_entry->fw_ddb_index, 232313483730SMike Christie atomic_read(&ddb_entry->relogin_retry_count), 232413483730SMike Christie ddb_entry->default_time2wait + 4)); 232513483730SMike Christie set_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags); 232613483730SMike Christie atomic_set(&ddb_entry->retry_relogin_timer, 232713483730SMike Christie ddb_entry->default_time2wait + 4); 232813483730SMike Christie } 232913483730SMike Christie } 233013483730SMike Christie } 233113483730SMike Christie 2332f4f5df23SVikas Chaudhary /** 2333afaf5a2dSDavid Somayajulu * qla4xxx_timer - checks every second for work to do. 2334afaf5a2dSDavid Somayajulu * @ha: Pointer to host adapter structure. 2335afaf5a2dSDavid Somayajulu **/ 2336afaf5a2dSDavid Somayajulu static void qla4xxx_timer(struct scsi_qla_host *ha) 2337afaf5a2dSDavid Somayajulu { 2338afaf5a2dSDavid Somayajulu int start_dpc = 0; 23392232be0dSLalit Chandivade uint16_t w; 23402232be0dSLalit Chandivade 234113483730SMike Christie iscsi_host_for_each_session(ha->host, qla4xxx_check_relogin_flash_ddb); 234213483730SMike Christie 23432232be0dSLalit Chandivade /* If we are in the middle of AER/EEH processing 23442232be0dSLalit Chandivade * skip any processing and reschedule the timer 23452232be0dSLalit Chandivade */ 23462232be0dSLalit Chandivade if (test_bit(AF_EEH_BUSY, &ha->flags)) { 23472232be0dSLalit Chandivade mod_timer(&ha->timer, jiffies + HZ); 23482232be0dSLalit Chandivade return; 23492232be0dSLalit Chandivade } 23502232be0dSLalit Chandivade 23512232be0dSLalit Chandivade /* Hardware read to trigger an EEH error during mailbox waits. */ 23522232be0dSLalit Chandivade if (!pci_channel_offline(ha->pdev)) 23532232be0dSLalit Chandivade pci_read_config_word(ha->pdev, PCI_VENDOR_ID, &w); 2354afaf5a2dSDavid Somayajulu 2355f4f5df23SVikas Chaudhary if (is_qla8022(ha)) { 2356f4f5df23SVikas Chaudhary qla4_8xxx_watchdog(ha); 2357f4f5df23SVikas Chaudhary } 2358f4f5df23SVikas Chaudhary 2359f4f5df23SVikas Chaudhary if (!is_qla8022(ha)) { 2360afaf5a2dSDavid Somayajulu /* Check for heartbeat interval. */ 2361afaf5a2dSDavid Somayajulu if (ha->firmware_options & FWOPT_HEARTBEAT_ENABLE && 2362afaf5a2dSDavid Somayajulu ha->heartbeat_interval != 0) { 2363afaf5a2dSDavid Somayajulu ha->seconds_since_last_heartbeat++; 2364afaf5a2dSDavid Somayajulu if (ha->seconds_since_last_heartbeat > 2365afaf5a2dSDavid Somayajulu ha->heartbeat_interval + 2) 2366afaf5a2dSDavid Somayajulu set_bit(DPC_RESET_HA, &ha->dpc_flags); 2367afaf5a2dSDavid Somayajulu } 2368f4f5df23SVikas Chaudhary } 2369afaf5a2dSDavid Somayajulu 2370ff884430SVikas Chaudhary /* Process any deferred work. */ 2371ff884430SVikas Chaudhary if (!list_empty(&ha->work_list)) 2372ff884430SVikas Chaudhary start_dpc++; 2373ff884430SVikas Chaudhary 2374afaf5a2dSDavid Somayajulu /* Wakeup the dpc routine for this adapter, if needed. */ 23751b46807eSLalit Chandivade if (start_dpc || 2376afaf5a2dSDavid Somayajulu test_bit(DPC_RESET_HA, &ha->dpc_flags) || 2377afaf5a2dSDavid Somayajulu test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags) || 2378afaf5a2dSDavid Somayajulu test_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags) || 2379f4f5df23SVikas Chaudhary test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags) || 2380afaf5a2dSDavid Somayajulu test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) || 2381afaf5a2dSDavid Somayajulu test_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags) || 2382065aa1b4SVikas Chaudhary test_bit(DPC_LINK_CHANGED, &ha->dpc_flags) || 2383f4f5df23SVikas Chaudhary test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags) || 2384f4f5df23SVikas Chaudhary test_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags) || 23851b46807eSLalit Chandivade test_bit(DPC_AEN, &ha->dpc_flags)) { 2386afaf5a2dSDavid Somayajulu DEBUG2(printk("scsi%ld: %s: scheduling dpc routine" 2387afaf5a2dSDavid Somayajulu " - dpc flags = 0x%lx\n", 2388afaf5a2dSDavid Somayajulu ha->host_no, __func__, ha->dpc_flags)); 2389f4f5df23SVikas Chaudhary qla4xxx_wake_dpc(ha); 2390afaf5a2dSDavid Somayajulu } 2391afaf5a2dSDavid Somayajulu 2392afaf5a2dSDavid Somayajulu /* Reschedule timer thread to call us back in one second */ 2393afaf5a2dSDavid Somayajulu mod_timer(&ha->timer, jiffies + HZ); 2394afaf5a2dSDavid Somayajulu 2395afaf5a2dSDavid Somayajulu DEBUG2(ha->seconds_since_last_intr++); 2396afaf5a2dSDavid Somayajulu } 2397afaf5a2dSDavid Somayajulu 2398afaf5a2dSDavid Somayajulu /** 2399afaf5a2dSDavid Somayajulu * qla4xxx_cmd_wait - waits for all outstanding commands to complete 2400afaf5a2dSDavid Somayajulu * @ha: Pointer to host adapter structure. 2401afaf5a2dSDavid Somayajulu * 2402afaf5a2dSDavid Somayajulu * This routine stalls the driver until all outstanding commands are returned. 2403afaf5a2dSDavid Somayajulu * Caller must release the Hardware Lock prior to calling this routine. 2404afaf5a2dSDavid Somayajulu **/ 2405afaf5a2dSDavid Somayajulu static int qla4xxx_cmd_wait(struct scsi_qla_host *ha) 2406afaf5a2dSDavid Somayajulu { 2407afaf5a2dSDavid Somayajulu uint32_t index = 0; 2408afaf5a2dSDavid Somayajulu unsigned long flags; 2409afaf5a2dSDavid Somayajulu struct scsi_cmnd *cmd; 2410afaf5a2dSDavid Somayajulu 2411f4f5df23SVikas Chaudhary unsigned long wtime = jiffies + (WAIT_CMD_TOV * HZ); 2412f4f5df23SVikas Chaudhary 2413f4f5df23SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, "Wait up to %d seconds for cmds to " 2414f4f5df23SVikas Chaudhary "complete\n", WAIT_CMD_TOV)); 2415f4f5df23SVikas Chaudhary 2416f4f5df23SVikas Chaudhary while (!time_after_eq(jiffies, wtime)) { 2417afaf5a2dSDavid Somayajulu spin_lock_irqsave(&ha->hardware_lock, flags); 2418afaf5a2dSDavid Somayajulu /* Find a command that hasn't completed. */ 2419afaf5a2dSDavid Somayajulu for (index = 0; index < ha->host->can_queue; index++) { 2420afaf5a2dSDavid Somayajulu cmd = scsi_host_find_tag(ha->host, index); 2421a1e0063dSMike Christie /* 2422a1e0063dSMike Christie * We cannot just check if the index is valid, 2423a1e0063dSMike Christie * becase if we are run from the scsi eh, then 2424a1e0063dSMike Christie * the scsi/block layer is going to prevent 2425a1e0063dSMike Christie * the tag from being released. 2426a1e0063dSMike Christie */ 2427a1e0063dSMike Christie if (cmd != NULL && CMD_SP(cmd)) 2428afaf5a2dSDavid Somayajulu break; 2429afaf5a2dSDavid Somayajulu } 2430afaf5a2dSDavid Somayajulu spin_unlock_irqrestore(&ha->hardware_lock, flags); 2431afaf5a2dSDavid Somayajulu 2432afaf5a2dSDavid Somayajulu /* If No Commands are pending, wait is complete */ 2433f4f5df23SVikas Chaudhary if (index == ha->host->can_queue) 2434f4f5df23SVikas Chaudhary return QLA_SUCCESS; 2435afaf5a2dSDavid Somayajulu 2436afaf5a2dSDavid Somayajulu msleep(1000); 2437afaf5a2dSDavid Somayajulu } 2438f4f5df23SVikas Chaudhary /* If we timed out on waiting for commands to come back 2439f4f5df23SVikas Chaudhary * return ERROR. */ 2440f4f5df23SVikas Chaudhary return QLA_ERROR; 2441afaf5a2dSDavid Somayajulu } 2442afaf5a2dSDavid Somayajulu 2443f4f5df23SVikas Chaudhary int qla4xxx_hw_reset(struct scsi_qla_host *ha) 2444afaf5a2dSDavid Somayajulu { 2445afaf5a2dSDavid Somayajulu uint32_t ctrl_status; 2446477ffb9dSDavid C Somayajulu unsigned long flags = 0; 2447477ffb9dSDavid C Somayajulu 2448477ffb9dSDavid C Somayajulu DEBUG2(printk(KERN_ERR "scsi%ld: %s\n", ha->host_no, __func__)); 2449afaf5a2dSDavid Somayajulu 2450f4f5df23SVikas Chaudhary if (ql4xxx_lock_drvr_wait(ha) != QLA_SUCCESS) 2451f4f5df23SVikas Chaudhary return QLA_ERROR; 2452f4f5df23SVikas Chaudhary 2453afaf5a2dSDavid Somayajulu spin_lock_irqsave(&ha->hardware_lock, flags); 2454afaf5a2dSDavid Somayajulu 2455afaf5a2dSDavid Somayajulu /* 2456afaf5a2dSDavid Somayajulu * If the SCSI Reset Interrupt bit is set, clear it. 2457afaf5a2dSDavid Somayajulu * Otherwise, the Soft Reset won't work. 2458afaf5a2dSDavid Somayajulu */ 2459afaf5a2dSDavid Somayajulu ctrl_status = readw(&ha->reg->ctrl_status); 2460afaf5a2dSDavid Somayajulu if ((ctrl_status & CSR_SCSI_RESET_INTR) != 0) 2461afaf5a2dSDavid Somayajulu writel(set_rmask(CSR_SCSI_RESET_INTR), &ha->reg->ctrl_status); 2462afaf5a2dSDavid Somayajulu 2463afaf5a2dSDavid Somayajulu /* Issue Soft Reset */ 2464afaf5a2dSDavid Somayajulu writel(set_rmask(CSR_SOFT_RESET), &ha->reg->ctrl_status); 2465afaf5a2dSDavid Somayajulu readl(&ha->reg->ctrl_status); 2466afaf5a2dSDavid Somayajulu 2467afaf5a2dSDavid Somayajulu spin_unlock_irqrestore(&ha->hardware_lock, flags); 2468f4f5df23SVikas Chaudhary return QLA_SUCCESS; 2469477ffb9dSDavid C Somayajulu } 2470477ffb9dSDavid C Somayajulu 2471477ffb9dSDavid C Somayajulu /** 2472477ffb9dSDavid C Somayajulu * qla4xxx_soft_reset - performs soft reset. 2473477ffb9dSDavid C Somayajulu * @ha: Pointer to host adapter structure. 2474477ffb9dSDavid C Somayajulu **/ 2475477ffb9dSDavid C Somayajulu int qla4xxx_soft_reset(struct scsi_qla_host *ha) 2476477ffb9dSDavid C Somayajulu { 2477477ffb9dSDavid C Somayajulu uint32_t max_wait_time; 2478477ffb9dSDavid C Somayajulu unsigned long flags = 0; 2479f931c534SVikas Chaudhary int status; 2480477ffb9dSDavid C Somayajulu uint32_t ctrl_status; 2481477ffb9dSDavid C Somayajulu 2482f931c534SVikas Chaudhary status = qla4xxx_hw_reset(ha); 2483f931c534SVikas Chaudhary if (status != QLA_SUCCESS) 2484f931c534SVikas Chaudhary return status; 2485afaf5a2dSDavid Somayajulu 2486f931c534SVikas Chaudhary status = QLA_ERROR; 2487afaf5a2dSDavid Somayajulu /* Wait until the Network Reset Intr bit is cleared */ 2488afaf5a2dSDavid Somayajulu max_wait_time = RESET_INTR_TOV; 2489afaf5a2dSDavid Somayajulu do { 2490afaf5a2dSDavid Somayajulu spin_lock_irqsave(&ha->hardware_lock, flags); 2491afaf5a2dSDavid Somayajulu ctrl_status = readw(&ha->reg->ctrl_status); 2492afaf5a2dSDavid Somayajulu spin_unlock_irqrestore(&ha->hardware_lock, flags); 2493afaf5a2dSDavid Somayajulu 2494afaf5a2dSDavid Somayajulu if ((ctrl_status & CSR_NET_RESET_INTR) == 0) 2495afaf5a2dSDavid Somayajulu break; 2496afaf5a2dSDavid Somayajulu 2497afaf5a2dSDavid Somayajulu msleep(1000); 2498afaf5a2dSDavid Somayajulu } while ((--max_wait_time)); 2499afaf5a2dSDavid Somayajulu 2500afaf5a2dSDavid Somayajulu if ((ctrl_status & CSR_NET_RESET_INTR) != 0) { 2501afaf5a2dSDavid Somayajulu DEBUG2(printk(KERN_WARNING 2502afaf5a2dSDavid Somayajulu "scsi%ld: Network Reset Intr not cleared by " 2503afaf5a2dSDavid Somayajulu "Network function, clearing it now!\n", 2504afaf5a2dSDavid Somayajulu ha->host_no)); 2505afaf5a2dSDavid Somayajulu spin_lock_irqsave(&ha->hardware_lock, flags); 2506afaf5a2dSDavid Somayajulu writel(set_rmask(CSR_NET_RESET_INTR), &ha->reg->ctrl_status); 2507afaf5a2dSDavid Somayajulu readl(&ha->reg->ctrl_status); 2508afaf5a2dSDavid Somayajulu spin_unlock_irqrestore(&ha->hardware_lock, flags); 2509afaf5a2dSDavid Somayajulu } 2510afaf5a2dSDavid Somayajulu 2511afaf5a2dSDavid Somayajulu /* Wait until the firmware tells us the Soft Reset is done */ 2512afaf5a2dSDavid Somayajulu max_wait_time = SOFT_RESET_TOV; 2513afaf5a2dSDavid Somayajulu do { 2514afaf5a2dSDavid Somayajulu spin_lock_irqsave(&ha->hardware_lock, flags); 2515afaf5a2dSDavid Somayajulu ctrl_status = readw(&ha->reg->ctrl_status); 2516afaf5a2dSDavid Somayajulu spin_unlock_irqrestore(&ha->hardware_lock, flags); 2517afaf5a2dSDavid Somayajulu 2518afaf5a2dSDavid Somayajulu if ((ctrl_status & CSR_SOFT_RESET) == 0) { 2519afaf5a2dSDavid Somayajulu status = QLA_SUCCESS; 2520afaf5a2dSDavid Somayajulu break; 2521afaf5a2dSDavid Somayajulu } 2522afaf5a2dSDavid Somayajulu 2523afaf5a2dSDavid Somayajulu msleep(1000); 2524afaf5a2dSDavid Somayajulu } while ((--max_wait_time)); 2525afaf5a2dSDavid Somayajulu 2526afaf5a2dSDavid Somayajulu /* 2527afaf5a2dSDavid Somayajulu * Also, make sure that the SCSI Reset Interrupt bit has been cleared 2528afaf5a2dSDavid Somayajulu * after the soft reset has taken place. 2529afaf5a2dSDavid Somayajulu */ 2530afaf5a2dSDavid Somayajulu spin_lock_irqsave(&ha->hardware_lock, flags); 2531afaf5a2dSDavid Somayajulu ctrl_status = readw(&ha->reg->ctrl_status); 2532afaf5a2dSDavid Somayajulu if ((ctrl_status & CSR_SCSI_RESET_INTR) != 0) { 2533afaf5a2dSDavid Somayajulu writel(set_rmask(CSR_SCSI_RESET_INTR), &ha->reg->ctrl_status); 2534afaf5a2dSDavid Somayajulu readl(&ha->reg->ctrl_status); 2535afaf5a2dSDavid Somayajulu } 2536afaf5a2dSDavid Somayajulu spin_unlock_irqrestore(&ha->hardware_lock, flags); 2537afaf5a2dSDavid Somayajulu 2538afaf5a2dSDavid Somayajulu /* If soft reset fails then most probably the bios on other 2539afaf5a2dSDavid Somayajulu * function is also enabled. 2540afaf5a2dSDavid Somayajulu * Since the initialization is sequential the other fn 2541afaf5a2dSDavid Somayajulu * wont be able to acknowledge the soft reset. 2542afaf5a2dSDavid Somayajulu * Issue a force soft reset to workaround this scenario. 2543afaf5a2dSDavid Somayajulu */ 2544afaf5a2dSDavid Somayajulu if (max_wait_time == 0) { 2545afaf5a2dSDavid Somayajulu /* Issue Force Soft Reset */ 2546afaf5a2dSDavid Somayajulu spin_lock_irqsave(&ha->hardware_lock, flags); 2547afaf5a2dSDavid Somayajulu writel(set_rmask(CSR_FORCE_SOFT_RESET), &ha->reg->ctrl_status); 2548afaf5a2dSDavid Somayajulu readl(&ha->reg->ctrl_status); 2549afaf5a2dSDavid Somayajulu spin_unlock_irqrestore(&ha->hardware_lock, flags); 2550afaf5a2dSDavid Somayajulu /* Wait until the firmware tells us the Soft Reset is done */ 2551afaf5a2dSDavid Somayajulu max_wait_time = SOFT_RESET_TOV; 2552afaf5a2dSDavid Somayajulu do { 2553afaf5a2dSDavid Somayajulu spin_lock_irqsave(&ha->hardware_lock, flags); 2554afaf5a2dSDavid Somayajulu ctrl_status = readw(&ha->reg->ctrl_status); 2555afaf5a2dSDavid Somayajulu spin_unlock_irqrestore(&ha->hardware_lock, flags); 2556afaf5a2dSDavid Somayajulu 2557afaf5a2dSDavid Somayajulu if ((ctrl_status & CSR_FORCE_SOFT_RESET) == 0) { 2558afaf5a2dSDavid Somayajulu status = QLA_SUCCESS; 2559afaf5a2dSDavid Somayajulu break; 2560afaf5a2dSDavid Somayajulu } 2561afaf5a2dSDavid Somayajulu 2562afaf5a2dSDavid Somayajulu msleep(1000); 2563afaf5a2dSDavid Somayajulu } while ((--max_wait_time)); 2564afaf5a2dSDavid Somayajulu } 2565afaf5a2dSDavid Somayajulu 2566afaf5a2dSDavid Somayajulu return status; 2567afaf5a2dSDavid Somayajulu } 2568afaf5a2dSDavid Somayajulu 2569afaf5a2dSDavid Somayajulu /** 2570f4f5df23SVikas Chaudhary * qla4xxx_abort_active_cmds - returns all outstanding i/o requests to O.S. 2571afaf5a2dSDavid Somayajulu * @ha: Pointer to host adapter structure. 2572f4f5df23SVikas Chaudhary * @res: returned scsi status 2573afaf5a2dSDavid Somayajulu * 2574afaf5a2dSDavid Somayajulu * This routine is called just prior to a HARD RESET to return all 2575afaf5a2dSDavid Somayajulu * outstanding commands back to the Operating System. 2576afaf5a2dSDavid Somayajulu * Caller should make sure that the following locks are released 2577afaf5a2dSDavid Somayajulu * before this calling routine: Hardware lock, and io_request_lock. 2578afaf5a2dSDavid Somayajulu **/ 2579f4f5df23SVikas Chaudhary static void qla4xxx_abort_active_cmds(struct scsi_qla_host *ha, int res) 2580afaf5a2dSDavid Somayajulu { 2581afaf5a2dSDavid Somayajulu struct srb *srb; 2582afaf5a2dSDavid Somayajulu int i; 2583afaf5a2dSDavid Somayajulu unsigned long flags; 2584afaf5a2dSDavid Somayajulu 2585afaf5a2dSDavid Somayajulu spin_lock_irqsave(&ha->hardware_lock, flags); 2586afaf5a2dSDavid Somayajulu for (i = 0; i < ha->host->can_queue; i++) { 2587afaf5a2dSDavid Somayajulu srb = qla4xxx_del_from_active_array(ha, i); 2588afaf5a2dSDavid Somayajulu if (srb != NULL) { 2589f4f5df23SVikas Chaudhary srb->cmd->result = res; 259009a0f719SVikas Chaudhary kref_put(&srb->srb_ref, qla4xxx_srb_compl); 2591afaf5a2dSDavid Somayajulu } 2592afaf5a2dSDavid Somayajulu } 2593afaf5a2dSDavid Somayajulu spin_unlock_irqrestore(&ha->hardware_lock, flags); 2594afaf5a2dSDavid Somayajulu } 2595afaf5a2dSDavid Somayajulu 2596f4f5df23SVikas Chaudhary void qla4xxx_dead_adapter_cleanup(struct scsi_qla_host *ha) 2597f4f5df23SVikas Chaudhary { 2598f4f5df23SVikas Chaudhary clear_bit(AF_ONLINE, &ha->flags); 2599f4f5df23SVikas Chaudhary 2600f4f5df23SVikas Chaudhary /* Disable the board */ 2601f4f5df23SVikas Chaudhary ql4_printk(KERN_INFO, ha, "Disabling the board\n"); 2602f4f5df23SVikas Chaudhary 2603f4f5df23SVikas Chaudhary qla4xxx_abort_active_cmds(ha, DID_NO_CONNECT << 16); 2604f4f5df23SVikas Chaudhary qla4xxx_mark_all_devices_missing(ha); 2605f4f5df23SVikas Chaudhary clear_bit(AF_INIT_DONE, &ha->flags); 2606f4f5df23SVikas Chaudhary } 2607f4f5df23SVikas Chaudhary 2608b3a271a9SManish Rangankar static void qla4xxx_fail_session(struct iscsi_cls_session *cls_session) 2609b3a271a9SManish Rangankar { 2610b3a271a9SManish Rangankar struct iscsi_session *sess; 2611b3a271a9SManish Rangankar struct ddb_entry *ddb_entry; 2612b3a271a9SManish Rangankar 2613b3a271a9SManish Rangankar sess = cls_session->dd_data; 2614b3a271a9SManish Rangankar ddb_entry = sess->dd_data; 2615b3a271a9SManish Rangankar ddb_entry->fw_ddb_device_state = DDB_DS_SESSION_FAILED; 261613483730SMike Christie 261713483730SMike Christie if (ddb_entry->ddb_type == FLASH_DDB) 261813483730SMike Christie iscsi_block_session(ddb_entry->sess); 261913483730SMike Christie else 262013483730SMike Christie iscsi_session_failure(cls_session->dd_data, 262113483730SMike Christie ISCSI_ERR_CONN_FAILED); 2622b3a271a9SManish Rangankar } 2623b3a271a9SManish Rangankar 2624afaf5a2dSDavid Somayajulu /** 2625afaf5a2dSDavid Somayajulu * qla4xxx_recover_adapter - recovers adapter after a fatal error 2626afaf5a2dSDavid Somayajulu * @ha: Pointer to host adapter structure. 2627afaf5a2dSDavid Somayajulu **/ 2628f4f5df23SVikas Chaudhary static int qla4xxx_recover_adapter(struct scsi_qla_host *ha) 2629afaf5a2dSDavid Somayajulu { 2630f4f5df23SVikas Chaudhary int status = QLA_ERROR; 2631f4f5df23SVikas Chaudhary uint8_t reset_chip = 0; 26328e0f3a66SSarang Radke uint32_t dev_state; 26339ee91a38SShyam Sunder unsigned long wait; 2634afaf5a2dSDavid Somayajulu 2635afaf5a2dSDavid Somayajulu /* Stall incoming I/O until we are done */ 2636f4f5df23SVikas Chaudhary scsi_block_requests(ha->host); 2637afaf5a2dSDavid Somayajulu clear_bit(AF_ONLINE, &ha->flags); 2638b3a271a9SManish Rangankar clear_bit(AF_LINK_UP, &ha->flags); 263950a29aecSMike Christie 2640f4f5df23SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, "%s: adapter OFFLINE\n", __func__)); 2641afaf5a2dSDavid Somayajulu 2642f4f5df23SVikas Chaudhary set_bit(DPC_RESET_ACTIVE, &ha->dpc_flags); 2643afaf5a2dSDavid Somayajulu 2644b3a271a9SManish Rangankar iscsi_host_for_each_session(ha->host, qla4xxx_fail_session); 2645b3a271a9SManish Rangankar 2646f4f5df23SVikas Chaudhary if (test_bit(DPC_RESET_HA, &ha->dpc_flags)) 2647f4f5df23SVikas Chaudhary reset_chip = 1; 2648afaf5a2dSDavid Somayajulu 2649f4f5df23SVikas Chaudhary /* For the DPC_RESET_HA_INTR case (ISP-4xxx specific) 2650f4f5df23SVikas Chaudhary * do not reset adapter, jump to initialize_adapter */ 2651f4f5df23SVikas Chaudhary if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) { 2652f4f5df23SVikas Chaudhary status = QLA_SUCCESS; 2653f4f5df23SVikas Chaudhary goto recover_ha_init_adapter; 2654afaf5a2dSDavid Somayajulu } 2655afaf5a2dSDavid Somayajulu 2656f4f5df23SVikas Chaudhary /* For the ISP-82xx adapter, issue a stop_firmware if invoked 2657f4f5df23SVikas Chaudhary * from eh_host_reset or ioctl module */ 2658f4f5df23SVikas Chaudhary if (is_qla8022(ha) && !reset_chip && 2659f4f5df23SVikas Chaudhary test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags)) { 2660f4f5df23SVikas Chaudhary 2661f4f5df23SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, 2662f4f5df23SVikas Chaudhary "scsi%ld: %s - Performing stop_firmware...\n", 2663f4f5df23SVikas Chaudhary ha->host_no, __func__)); 2664f4f5df23SVikas Chaudhary status = ha->isp_ops->reset_firmware(ha); 2665f4f5df23SVikas Chaudhary if (status == QLA_SUCCESS) { 26662bd1e2beSNilesh Javali if (!test_bit(AF_FW_RECOVERY, &ha->flags)) 2667f4f5df23SVikas Chaudhary qla4xxx_cmd_wait(ha); 2668f4f5df23SVikas Chaudhary ha->isp_ops->disable_intrs(ha); 2669f4f5df23SVikas Chaudhary qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); 2670f4f5df23SVikas Chaudhary qla4xxx_abort_active_cmds(ha, DID_RESET << 16); 2671f4f5df23SVikas Chaudhary } else { 2672f4f5df23SVikas Chaudhary /* If the stop_firmware fails then 2673f4f5df23SVikas Chaudhary * reset the entire chip */ 2674f4f5df23SVikas Chaudhary reset_chip = 1; 2675f4f5df23SVikas Chaudhary clear_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags); 2676f4f5df23SVikas Chaudhary set_bit(DPC_RESET_HA, &ha->dpc_flags); 2677f4f5df23SVikas Chaudhary } 2678f4f5df23SVikas Chaudhary } 2679f4f5df23SVikas Chaudhary 2680f4f5df23SVikas Chaudhary /* Issue full chip reset if recovering from a catastrophic error, 2681f4f5df23SVikas Chaudhary * or if stop_firmware fails for ISP-82xx. 2682f4f5df23SVikas Chaudhary * This is the default case for ISP-4xxx */ 2683f4f5df23SVikas Chaudhary if (!is_qla8022(ha) || reset_chip) { 26849ee91a38SShyam Sunder if (!is_qla8022(ha)) 26859ee91a38SShyam Sunder goto chip_reset; 26869ee91a38SShyam Sunder 26879ee91a38SShyam Sunder /* Check if 82XX firmware is alive or not 26889ee91a38SShyam Sunder * We may have arrived here from NEED_RESET 26899ee91a38SShyam Sunder * detection only */ 26909ee91a38SShyam Sunder if (test_bit(AF_FW_RECOVERY, &ha->flags)) 26919ee91a38SShyam Sunder goto chip_reset; 26929ee91a38SShyam Sunder 26939ee91a38SShyam Sunder wait = jiffies + (FW_ALIVE_WAIT_TOV * HZ); 26949ee91a38SShyam Sunder while (time_before(jiffies, wait)) { 26959ee91a38SShyam Sunder if (qla4_8xxx_check_fw_alive(ha)) { 26969ee91a38SShyam Sunder qla4xxx_mailbox_premature_completion(ha); 26979ee91a38SShyam Sunder break; 26989ee91a38SShyam Sunder } 26999ee91a38SShyam Sunder 27009ee91a38SShyam Sunder set_current_state(TASK_UNINTERRUPTIBLE); 27019ee91a38SShyam Sunder schedule_timeout(HZ); 27029ee91a38SShyam Sunder } 27039ee91a38SShyam Sunder 27042bd1e2beSNilesh Javali if (!test_bit(AF_FW_RECOVERY, &ha->flags)) 2705f4f5df23SVikas Chaudhary qla4xxx_cmd_wait(ha); 27069ee91a38SShyam Sunder chip_reset: 2707f4f5df23SVikas Chaudhary qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); 2708f4f5df23SVikas Chaudhary qla4xxx_abort_active_cmds(ha, DID_RESET << 16); 2709f4f5df23SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, 2710f4f5df23SVikas Chaudhary "scsi%ld: %s - Performing chip reset..\n", 2711f4f5df23SVikas Chaudhary ha->host_no, __func__)); 2712f4f5df23SVikas Chaudhary status = ha->isp_ops->reset_chip(ha); 2713f4f5df23SVikas Chaudhary } 2714f4f5df23SVikas Chaudhary 2715f4f5df23SVikas Chaudhary /* Flush any pending ddb changed AENs */ 2716f4f5df23SVikas Chaudhary qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); 2717f4f5df23SVikas Chaudhary 2718f4f5df23SVikas Chaudhary recover_ha_init_adapter: 2719f4f5df23SVikas Chaudhary /* Upon successful firmware/chip reset, re-initialize the adapter */ 2720f4f5df23SVikas Chaudhary if (status == QLA_SUCCESS) { 2721f4f5df23SVikas Chaudhary /* For ISP-4xxx, force function 1 to always initialize 2722f4f5df23SVikas Chaudhary * before function 3 to prevent both funcions from 2723f4f5df23SVikas Chaudhary * stepping on top of the other */ 2724f4f5df23SVikas Chaudhary if (!is_qla8022(ha) && (ha->mac_index == 3)) 2725f4f5df23SVikas Chaudhary ssleep(6); 2726f4f5df23SVikas Chaudhary 2727f4f5df23SVikas Chaudhary /* NOTE: AF_ONLINE flag set upon successful completion of 2728f4f5df23SVikas Chaudhary * qla4xxx_initialize_adapter */ 272913483730SMike Christie status = qla4xxx_initialize_adapter(ha, RESET_ADAPTER); 2730f4f5df23SVikas Chaudhary } 2731f4f5df23SVikas Chaudhary 2732f4f5df23SVikas Chaudhary /* Retry failed adapter initialization, if necessary 2733f4f5df23SVikas Chaudhary * Do not retry initialize_adapter for RESET_HA_INTR (ISP-4xxx specific) 2734f4f5df23SVikas Chaudhary * case to prevent ping-pong resets between functions */ 2735f4f5df23SVikas Chaudhary if (!test_bit(AF_ONLINE, &ha->flags) && 2736f4f5df23SVikas Chaudhary !test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) { 2737afaf5a2dSDavid Somayajulu /* Adapter initialization failed, see if we can retry 2738f4f5df23SVikas Chaudhary * resetting the ha. 2739f4f5df23SVikas Chaudhary * Since we don't want to block the DPC for too long 2740f4f5df23SVikas Chaudhary * with multiple resets in the same thread, 2741f4f5df23SVikas Chaudhary * utilize DPC to retry */ 27428e0f3a66SSarang Radke if (is_qla8022(ha)) { 27438e0f3a66SSarang Radke qla4_8xxx_idc_lock(ha); 27448e0f3a66SSarang Radke dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE); 27458e0f3a66SSarang Radke qla4_8xxx_idc_unlock(ha); 27468e0f3a66SSarang Radke if (dev_state == QLA82XX_DEV_FAILED) { 27478e0f3a66SSarang Radke ql4_printk(KERN_INFO, ha, "%s: don't retry " 27488e0f3a66SSarang Radke "recover adapter. H/W is in Failed " 27498e0f3a66SSarang Radke "state\n", __func__); 27508e0f3a66SSarang Radke qla4xxx_dead_adapter_cleanup(ha); 27518e0f3a66SSarang Radke clear_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags); 27528e0f3a66SSarang Radke clear_bit(DPC_RESET_HA, &ha->dpc_flags); 27538e0f3a66SSarang Radke clear_bit(DPC_RESET_HA_FW_CONTEXT, 27548e0f3a66SSarang Radke &ha->dpc_flags); 27558e0f3a66SSarang Radke status = QLA_ERROR; 27568e0f3a66SSarang Radke 27578e0f3a66SSarang Radke goto exit_recover; 27588e0f3a66SSarang Radke } 27598e0f3a66SSarang Radke } 27608e0f3a66SSarang Radke 2761afaf5a2dSDavid Somayajulu if (!test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags)) { 2762afaf5a2dSDavid Somayajulu ha->retry_reset_ha_cnt = MAX_RESET_HA_RETRIES; 2763afaf5a2dSDavid Somayajulu DEBUG2(printk("scsi%ld: recover adapter - retrying " 2764afaf5a2dSDavid Somayajulu "(%d) more times\n", ha->host_no, 2765afaf5a2dSDavid Somayajulu ha->retry_reset_ha_cnt)); 2766afaf5a2dSDavid Somayajulu set_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags); 2767afaf5a2dSDavid Somayajulu status = QLA_ERROR; 2768afaf5a2dSDavid Somayajulu } else { 2769afaf5a2dSDavid Somayajulu if (ha->retry_reset_ha_cnt > 0) { 2770afaf5a2dSDavid Somayajulu /* Schedule another Reset HA--DPC will retry */ 2771afaf5a2dSDavid Somayajulu ha->retry_reset_ha_cnt--; 2772afaf5a2dSDavid Somayajulu DEBUG2(printk("scsi%ld: recover adapter - " 2773afaf5a2dSDavid Somayajulu "retry remaining %d\n", 2774afaf5a2dSDavid Somayajulu ha->host_no, 2775afaf5a2dSDavid Somayajulu ha->retry_reset_ha_cnt)); 2776afaf5a2dSDavid Somayajulu status = QLA_ERROR; 2777afaf5a2dSDavid Somayajulu } 2778afaf5a2dSDavid Somayajulu 2779afaf5a2dSDavid Somayajulu if (ha->retry_reset_ha_cnt == 0) { 2780afaf5a2dSDavid Somayajulu /* Recover adapter retries have been exhausted. 2781afaf5a2dSDavid Somayajulu * Adapter DEAD */ 2782afaf5a2dSDavid Somayajulu DEBUG2(printk("scsi%ld: recover adapter " 2783afaf5a2dSDavid Somayajulu "failed - board disabled\n", 2784afaf5a2dSDavid Somayajulu ha->host_no)); 2785f4f5df23SVikas Chaudhary qla4xxx_dead_adapter_cleanup(ha); 2786afaf5a2dSDavid Somayajulu clear_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags); 2787afaf5a2dSDavid Somayajulu clear_bit(DPC_RESET_HA, &ha->dpc_flags); 2788f4f5df23SVikas Chaudhary clear_bit(DPC_RESET_HA_FW_CONTEXT, 2789afaf5a2dSDavid Somayajulu &ha->dpc_flags); 2790afaf5a2dSDavid Somayajulu status = QLA_ERROR; 2791afaf5a2dSDavid Somayajulu } 2792afaf5a2dSDavid Somayajulu } 2793afaf5a2dSDavid Somayajulu } else { 2794afaf5a2dSDavid Somayajulu clear_bit(DPC_RESET_HA, &ha->dpc_flags); 2795f4f5df23SVikas Chaudhary clear_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags); 2796afaf5a2dSDavid Somayajulu clear_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags); 2797afaf5a2dSDavid Somayajulu } 2798afaf5a2dSDavid Somayajulu 27998e0f3a66SSarang Radke exit_recover: 2800afaf5a2dSDavid Somayajulu ha->adapter_error_count++; 2801afaf5a2dSDavid Somayajulu 2802f4f5df23SVikas Chaudhary if (test_bit(AF_ONLINE, &ha->flags)) 2803f4f5df23SVikas Chaudhary ha->isp_ops->enable_intrs(ha); 2804afaf5a2dSDavid Somayajulu 2805f4f5df23SVikas Chaudhary scsi_unblock_requests(ha->host); 2806f4f5df23SVikas Chaudhary 2807f4f5df23SVikas Chaudhary clear_bit(DPC_RESET_ACTIVE, &ha->dpc_flags); 2808f4f5df23SVikas Chaudhary DEBUG2(printk("scsi%ld: recover adapter: %s\n", ha->host_no, 280925985edcSLucas De Marchi status == QLA_ERROR ? "FAILED" : "SUCCEEDED")); 2810f4f5df23SVikas Chaudhary 2811afaf5a2dSDavid Somayajulu return status; 2812afaf5a2dSDavid Somayajulu } 2813afaf5a2dSDavid Somayajulu 2814b3a271a9SManish Rangankar static void qla4xxx_relogin_devices(struct iscsi_cls_session *cls_session) 2815b3a271a9SManish Rangankar { 2816b3a271a9SManish Rangankar struct iscsi_session *sess; 2817b3a271a9SManish Rangankar struct ddb_entry *ddb_entry; 2818b3a271a9SManish Rangankar struct scsi_qla_host *ha; 2819b3a271a9SManish Rangankar 2820b3a271a9SManish Rangankar sess = cls_session->dd_data; 2821b3a271a9SManish Rangankar ddb_entry = sess->dd_data; 2822b3a271a9SManish Rangankar ha = ddb_entry->ha; 2823b3a271a9SManish Rangankar if (!iscsi_is_session_online(cls_session)) { 2824b3a271a9SManish Rangankar if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) { 2825b3a271a9SManish Rangankar ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ddb[%d]" 2826b3a271a9SManish Rangankar " unblock session\n", ha->host_no, __func__, 2827b3a271a9SManish Rangankar ddb_entry->fw_ddb_index); 2828b3a271a9SManish Rangankar iscsi_unblock_session(ddb_entry->sess); 2829b3a271a9SManish Rangankar } else { 2830b3a271a9SManish Rangankar /* Trigger relogin */ 283113483730SMike Christie if (ddb_entry->ddb_type == FLASH_DDB) { 283213483730SMike Christie if (!test_bit(DF_RELOGIN, &ddb_entry->flags)) 283313483730SMike Christie qla4xxx_arm_relogin_timer(ddb_entry); 283413483730SMike Christie } else 2835b3a271a9SManish Rangankar iscsi_session_failure(cls_session->dd_data, 2836b3a271a9SManish Rangankar ISCSI_ERR_CONN_FAILED); 2837b3a271a9SManish Rangankar } 2838b3a271a9SManish Rangankar } 2839b3a271a9SManish Rangankar } 2840b3a271a9SManish Rangankar 284113483730SMike Christie int qla4xxx_unblock_flash_ddb(struct iscsi_cls_session *cls_session) 284213483730SMike Christie { 284313483730SMike Christie struct iscsi_session *sess; 284413483730SMike Christie struct ddb_entry *ddb_entry; 284513483730SMike Christie struct scsi_qla_host *ha; 284613483730SMike Christie 284713483730SMike Christie sess = cls_session->dd_data; 284813483730SMike Christie ddb_entry = sess->dd_data; 284913483730SMike Christie ha = ddb_entry->ha; 285013483730SMike Christie ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ddb[%d]" 285113483730SMike Christie " unblock session\n", ha->host_no, __func__, 285213483730SMike Christie ddb_entry->fw_ddb_index); 285313483730SMike Christie 285413483730SMike Christie iscsi_unblock_session(ddb_entry->sess); 285513483730SMike Christie 285613483730SMike Christie /* Start scan target */ 285713483730SMike Christie if (test_bit(AF_ONLINE, &ha->flags)) { 285813483730SMike Christie ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ddb[%d]" 285913483730SMike Christie " start scan\n", ha->host_no, __func__, 286013483730SMike Christie ddb_entry->fw_ddb_index); 286113483730SMike Christie scsi_queue_work(ha->host, &ddb_entry->sess->scan_work); 286213483730SMike Christie } 286313483730SMike Christie return QLA_SUCCESS; 286413483730SMike Christie } 286513483730SMike Christie 286613483730SMike Christie int qla4xxx_unblock_ddb(struct iscsi_cls_session *cls_session) 286713483730SMike Christie { 286813483730SMike Christie struct iscsi_session *sess; 286913483730SMike Christie struct ddb_entry *ddb_entry; 287013483730SMike Christie struct scsi_qla_host *ha; 287113483730SMike Christie 287213483730SMike Christie sess = cls_session->dd_data; 287313483730SMike Christie ddb_entry = sess->dd_data; 287413483730SMike Christie ha = ddb_entry->ha; 287513483730SMike Christie ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ddb[%d]" 287613483730SMike Christie " unblock user space session\n", ha->host_no, __func__, 287713483730SMike Christie ddb_entry->fw_ddb_index); 287813483730SMike Christie iscsi_conn_start(ddb_entry->conn); 287913483730SMike Christie iscsi_conn_login_event(ddb_entry->conn, 288013483730SMike Christie ISCSI_CONN_STATE_LOGGED_IN); 288113483730SMike Christie 288213483730SMike Christie return QLA_SUCCESS; 288313483730SMike Christie } 288413483730SMike Christie 28852d7924e6SVikas Chaudhary static void qla4xxx_relogin_all_devices(struct scsi_qla_host *ha) 28862d7924e6SVikas Chaudhary { 2887b3a271a9SManish Rangankar iscsi_host_for_each_session(ha->host, qla4xxx_relogin_devices); 28882d7924e6SVikas Chaudhary } 28892d7924e6SVikas Chaudhary 289013483730SMike Christie static void qla4xxx_relogin_flash_ddb(struct iscsi_cls_session *cls_sess) 289113483730SMike Christie { 289213483730SMike Christie uint16_t relogin_timer; 289313483730SMike Christie struct iscsi_session *sess; 289413483730SMike Christie struct ddb_entry *ddb_entry; 289513483730SMike Christie struct scsi_qla_host *ha; 289613483730SMike Christie 289713483730SMike Christie sess = cls_sess->dd_data; 289813483730SMike Christie ddb_entry = sess->dd_data; 289913483730SMike Christie ha = ddb_entry->ha; 290013483730SMike Christie 290113483730SMike Christie relogin_timer = max(ddb_entry->default_relogin_timeout, 290213483730SMike Christie (uint16_t)RELOGIN_TOV); 290313483730SMike Christie atomic_set(&ddb_entry->relogin_timer, relogin_timer); 290413483730SMike Christie 290513483730SMike Christie DEBUG2(ql4_printk(KERN_INFO, ha, 290613483730SMike Christie "scsi%ld: Relogin index [%d]. TOV=%d\n", ha->host_no, 290713483730SMike Christie ddb_entry->fw_ddb_index, relogin_timer)); 290813483730SMike Christie 290913483730SMike Christie qla4xxx_login_flash_ddb(cls_sess); 291013483730SMike Christie } 291113483730SMike Christie 291213483730SMike Christie static void qla4xxx_dpc_relogin(struct iscsi_cls_session *cls_sess) 291313483730SMike Christie { 291413483730SMike Christie struct iscsi_session *sess; 291513483730SMike Christie struct ddb_entry *ddb_entry; 291613483730SMike Christie struct scsi_qla_host *ha; 291713483730SMike Christie 291813483730SMike Christie sess = cls_sess->dd_data; 291913483730SMike Christie ddb_entry = sess->dd_data; 292013483730SMike Christie ha = ddb_entry->ha; 292113483730SMike Christie 292213483730SMike Christie if (!(ddb_entry->ddb_type == FLASH_DDB)) 292313483730SMike Christie return; 292413483730SMike Christie 292513483730SMike Christie if (test_and_clear_bit(DF_RELOGIN, &ddb_entry->flags) && 292613483730SMike Christie !iscsi_is_session_online(cls_sess)) { 292713483730SMike Christie DEBUG2(ql4_printk(KERN_INFO, ha, 292813483730SMike Christie "relogin issued\n")); 292913483730SMike Christie qla4xxx_relogin_flash_ddb(cls_sess); 293013483730SMike Christie } 293113483730SMike Christie } 293213483730SMike Christie 2933f4f5df23SVikas Chaudhary void qla4xxx_wake_dpc(struct scsi_qla_host *ha) 2934f4f5df23SVikas Chaudhary { 29351b46807eSLalit Chandivade if (ha->dpc_thread) 2936f4f5df23SVikas Chaudhary queue_work(ha->dpc_thread, &ha->dpc_work); 2937f4f5df23SVikas Chaudhary } 2938f4f5df23SVikas Chaudhary 2939ff884430SVikas Chaudhary static struct qla4_work_evt * 2940ff884430SVikas Chaudhary qla4xxx_alloc_work(struct scsi_qla_host *ha, uint32_t data_size, 2941ff884430SVikas Chaudhary enum qla4_work_type type) 2942ff884430SVikas Chaudhary { 2943ff884430SVikas Chaudhary struct qla4_work_evt *e; 2944ff884430SVikas Chaudhary uint32_t size = sizeof(struct qla4_work_evt) + data_size; 2945ff884430SVikas Chaudhary 2946ff884430SVikas Chaudhary e = kzalloc(size, GFP_ATOMIC); 2947ff884430SVikas Chaudhary if (!e) 2948ff884430SVikas Chaudhary return NULL; 2949ff884430SVikas Chaudhary 2950ff884430SVikas Chaudhary INIT_LIST_HEAD(&e->list); 2951ff884430SVikas Chaudhary e->type = type; 2952ff884430SVikas Chaudhary return e; 2953ff884430SVikas Chaudhary } 2954ff884430SVikas Chaudhary 2955ff884430SVikas Chaudhary static void qla4xxx_post_work(struct scsi_qla_host *ha, 2956ff884430SVikas Chaudhary struct qla4_work_evt *e) 2957ff884430SVikas Chaudhary { 2958ff884430SVikas Chaudhary unsigned long flags; 2959ff884430SVikas Chaudhary 2960ff884430SVikas Chaudhary spin_lock_irqsave(&ha->work_lock, flags); 2961ff884430SVikas Chaudhary list_add_tail(&e->list, &ha->work_list); 2962ff884430SVikas Chaudhary spin_unlock_irqrestore(&ha->work_lock, flags); 2963ff884430SVikas Chaudhary qla4xxx_wake_dpc(ha); 2964ff884430SVikas Chaudhary } 2965ff884430SVikas Chaudhary 2966ff884430SVikas Chaudhary int qla4xxx_post_aen_work(struct scsi_qla_host *ha, 2967ff884430SVikas Chaudhary enum iscsi_host_event_code aen_code, 2968ff884430SVikas Chaudhary uint32_t data_size, uint8_t *data) 2969ff884430SVikas Chaudhary { 2970ff884430SVikas Chaudhary struct qla4_work_evt *e; 2971ff884430SVikas Chaudhary 2972ff884430SVikas Chaudhary e = qla4xxx_alloc_work(ha, data_size, QLA4_EVENT_AEN); 2973ff884430SVikas Chaudhary if (!e) 2974ff884430SVikas Chaudhary return QLA_ERROR; 2975ff884430SVikas Chaudhary 2976ff884430SVikas Chaudhary e->u.aen.code = aen_code; 2977ff884430SVikas Chaudhary e->u.aen.data_size = data_size; 2978ff884430SVikas Chaudhary memcpy(e->u.aen.data, data, data_size); 2979ff884430SVikas Chaudhary 2980ff884430SVikas Chaudhary qla4xxx_post_work(ha, e); 2981ff884430SVikas Chaudhary 2982ff884430SVikas Chaudhary return QLA_SUCCESS; 2983ff884430SVikas Chaudhary } 2984ff884430SVikas Chaudhary 2985c0b9d3f7SVikas Chaudhary int qla4xxx_post_ping_evt_work(struct scsi_qla_host *ha, 2986c0b9d3f7SVikas Chaudhary uint32_t status, uint32_t pid, 2987c0b9d3f7SVikas Chaudhary uint32_t data_size, uint8_t *data) 2988c0b9d3f7SVikas Chaudhary { 2989c0b9d3f7SVikas Chaudhary struct qla4_work_evt *e; 2990c0b9d3f7SVikas Chaudhary 2991c0b9d3f7SVikas Chaudhary e = qla4xxx_alloc_work(ha, data_size, QLA4_EVENT_PING_STATUS); 2992c0b9d3f7SVikas Chaudhary if (!e) 2993c0b9d3f7SVikas Chaudhary return QLA_ERROR; 2994c0b9d3f7SVikas Chaudhary 2995c0b9d3f7SVikas Chaudhary e->u.ping.status = status; 2996c0b9d3f7SVikas Chaudhary e->u.ping.pid = pid; 2997c0b9d3f7SVikas Chaudhary e->u.ping.data_size = data_size; 2998c0b9d3f7SVikas Chaudhary memcpy(e->u.ping.data, data, data_size); 2999c0b9d3f7SVikas Chaudhary 3000c0b9d3f7SVikas Chaudhary qla4xxx_post_work(ha, e); 3001c0b9d3f7SVikas Chaudhary 3002c0b9d3f7SVikas Chaudhary return QLA_SUCCESS; 3003c0b9d3f7SVikas Chaudhary } 3004c0b9d3f7SVikas Chaudhary 3005ff884430SVikas Chaudhary void qla4xxx_do_work(struct scsi_qla_host *ha) 3006ff884430SVikas Chaudhary { 3007ff884430SVikas Chaudhary struct qla4_work_evt *e, *tmp; 3008ff884430SVikas Chaudhary unsigned long flags; 3009ff884430SVikas Chaudhary LIST_HEAD(work); 3010ff884430SVikas Chaudhary 3011ff884430SVikas Chaudhary spin_lock_irqsave(&ha->work_lock, flags); 3012ff884430SVikas Chaudhary list_splice_init(&ha->work_list, &work); 3013ff884430SVikas Chaudhary spin_unlock_irqrestore(&ha->work_lock, flags); 3014ff884430SVikas Chaudhary 3015ff884430SVikas Chaudhary list_for_each_entry_safe(e, tmp, &work, list) { 3016ff884430SVikas Chaudhary list_del_init(&e->list); 3017ff884430SVikas Chaudhary 3018ff884430SVikas Chaudhary switch (e->type) { 3019ff884430SVikas Chaudhary case QLA4_EVENT_AEN: 3020ff884430SVikas Chaudhary iscsi_post_host_event(ha->host_no, 3021ff884430SVikas Chaudhary &qla4xxx_iscsi_transport, 3022ff884430SVikas Chaudhary e->u.aen.code, 3023ff884430SVikas Chaudhary e->u.aen.data_size, 3024ff884430SVikas Chaudhary e->u.aen.data); 3025ff884430SVikas Chaudhary break; 3026c0b9d3f7SVikas Chaudhary case QLA4_EVENT_PING_STATUS: 3027c0b9d3f7SVikas Chaudhary iscsi_ping_comp_event(ha->host_no, 3028c0b9d3f7SVikas Chaudhary &qla4xxx_iscsi_transport, 3029c0b9d3f7SVikas Chaudhary e->u.ping.status, 3030c0b9d3f7SVikas Chaudhary e->u.ping.pid, 3031c0b9d3f7SVikas Chaudhary e->u.ping.data_size, 3032c0b9d3f7SVikas Chaudhary e->u.ping.data); 3033c0b9d3f7SVikas Chaudhary break; 3034ff884430SVikas Chaudhary default: 3035ff884430SVikas Chaudhary ql4_printk(KERN_WARNING, ha, "event type: 0x%x not " 3036ff884430SVikas Chaudhary "supported", e->type); 3037ff884430SVikas Chaudhary } 3038ff884430SVikas Chaudhary kfree(e); 3039ff884430SVikas Chaudhary } 3040ff884430SVikas Chaudhary } 3041ff884430SVikas Chaudhary 3042afaf5a2dSDavid Somayajulu /** 3043afaf5a2dSDavid Somayajulu * qla4xxx_do_dpc - dpc routine 3044afaf5a2dSDavid Somayajulu * @data: in our case pointer to adapter structure 3045afaf5a2dSDavid Somayajulu * 3046afaf5a2dSDavid Somayajulu * This routine is a task that is schedule by the interrupt handler 3047afaf5a2dSDavid Somayajulu * to perform the background processing for interrupts. We put it 3048afaf5a2dSDavid Somayajulu * on a task queue that is consumed whenever the scheduler runs; that's 3049afaf5a2dSDavid Somayajulu * so you can do anything (i.e. put the process to sleep etc). In fact, 3050afaf5a2dSDavid Somayajulu * the mid-level tries to sleep when it reaches the driver threshold 3051afaf5a2dSDavid Somayajulu * "host->can_queue". This can cause a panic if we were in our interrupt code. 3052afaf5a2dSDavid Somayajulu **/ 3053c4028958SDavid Howells static void qla4xxx_do_dpc(struct work_struct *work) 3054afaf5a2dSDavid Somayajulu { 3055c4028958SDavid Howells struct scsi_qla_host *ha = 3056c4028958SDavid Howells container_of(work, struct scsi_qla_host, dpc_work); 3057477ffb9dSDavid C Somayajulu int status = QLA_ERROR; 3058afaf5a2dSDavid Somayajulu 3059f26b9044SDavid C Somayajulu DEBUG2(printk("scsi%ld: %s: DPC handler waking up." 3060f4f5df23SVikas Chaudhary "flags = 0x%08lx, dpc_flags = 0x%08lx\n", 3061f4f5df23SVikas Chaudhary ha->host_no, __func__, ha->flags, ha->dpc_flags)) 3062afaf5a2dSDavid Somayajulu 3063afaf5a2dSDavid Somayajulu /* Initialization not yet finished. Don't do anything yet. */ 3064afaf5a2dSDavid Somayajulu if (!test_bit(AF_INIT_DONE, &ha->flags)) 30651b46807eSLalit Chandivade return; 3066afaf5a2dSDavid Somayajulu 30672232be0dSLalit Chandivade if (test_bit(AF_EEH_BUSY, &ha->flags)) { 30682232be0dSLalit Chandivade DEBUG2(printk(KERN_INFO "scsi%ld: %s: flags = %lx\n", 30692232be0dSLalit Chandivade ha->host_no, __func__, ha->flags)); 30701b46807eSLalit Chandivade return; 30712232be0dSLalit Chandivade } 30722232be0dSLalit Chandivade 3073ff884430SVikas Chaudhary /* post events to application */ 3074ff884430SVikas Chaudhary qla4xxx_do_work(ha); 3075ff884430SVikas Chaudhary 3076f4f5df23SVikas Chaudhary if (is_qla8022(ha)) { 3077f4f5df23SVikas Chaudhary if (test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags)) { 3078f4f5df23SVikas Chaudhary qla4_8xxx_idc_lock(ha); 3079f4f5df23SVikas Chaudhary qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, 3080f4f5df23SVikas Chaudhary QLA82XX_DEV_FAILED); 3081f4f5df23SVikas Chaudhary qla4_8xxx_idc_unlock(ha); 3082f4f5df23SVikas Chaudhary ql4_printk(KERN_INFO, ha, "HW State: FAILED\n"); 3083f4f5df23SVikas Chaudhary qla4_8xxx_device_state_handler(ha); 3084f4f5df23SVikas Chaudhary } 3085f4f5df23SVikas Chaudhary if (test_and_clear_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags)) { 3086f4f5df23SVikas Chaudhary qla4_8xxx_need_qsnt_handler(ha); 3087f4f5df23SVikas Chaudhary } 3088f4f5df23SVikas Chaudhary } 3089f4f5df23SVikas Chaudhary 3090f4f5df23SVikas Chaudhary if (!test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags) && 3091f4f5df23SVikas Chaudhary (test_bit(DPC_RESET_HA, &ha->dpc_flags) || 3092afaf5a2dSDavid Somayajulu test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) || 3093f4f5df23SVikas Chaudhary test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags))) { 3094f4f5df23SVikas Chaudhary if (ql4xdontresethba) { 3095f4f5df23SVikas Chaudhary DEBUG2(printk("scsi%ld: %s: Don't Reset HBA\n", 3096f4f5df23SVikas Chaudhary ha->host_no, __func__)); 3097f4f5df23SVikas Chaudhary clear_bit(DPC_RESET_HA, &ha->dpc_flags); 3098f4f5df23SVikas Chaudhary clear_bit(DPC_RESET_HA_INTR, &ha->dpc_flags); 3099f4f5df23SVikas Chaudhary clear_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags); 3100f4f5df23SVikas Chaudhary goto dpc_post_reset_ha; 3101f4f5df23SVikas Chaudhary } 3102f4f5df23SVikas Chaudhary if (test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags) || 3103f26b9044SDavid C Somayajulu test_bit(DPC_RESET_HA, &ha->dpc_flags)) 3104f4f5df23SVikas Chaudhary qla4xxx_recover_adapter(ha); 3105afaf5a2dSDavid Somayajulu 3106477ffb9dSDavid C Somayajulu if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) { 3107afaf5a2dSDavid Somayajulu uint8_t wait_time = RESET_INTR_TOV; 3108afaf5a2dSDavid Somayajulu 3109afaf5a2dSDavid Somayajulu while ((readw(&ha->reg->ctrl_status) & 3110afaf5a2dSDavid Somayajulu (CSR_SOFT_RESET | CSR_FORCE_SOFT_RESET)) != 0) { 3111afaf5a2dSDavid Somayajulu if (--wait_time == 0) 3112afaf5a2dSDavid Somayajulu break; 3113afaf5a2dSDavid Somayajulu msleep(1000); 3114afaf5a2dSDavid Somayajulu } 3115afaf5a2dSDavid Somayajulu if (wait_time == 0) 3116afaf5a2dSDavid Somayajulu DEBUG2(printk("scsi%ld: %s: SR|FSR " 3117afaf5a2dSDavid Somayajulu "bit not cleared-- resetting\n", 3118afaf5a2dSDavid Somayajulu ha->host_no, __func__)); 3119f4f5df23SVikas Chaudhary qla4xxx_abort_active_cmds(ha, DID_RESET << 16); 3120477ffb9dSDavid C Somayajulu if (ql4xxx_lock_drvr_wait(ha) == QLA_SUCCESS) { 3121477ffb9dSDavid C Somayajulu qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); 3122f4f5df23SVikas Chaudhary status = qla4xxx_recover_adapter(ha); 3123477ffb9dSDavid C Somayajulu } 3124477ffb9dSDavid C Somayajulu clear_bit(DPC_RESET_HA_INTR, &ha->dpc_flags); 3125477ffb9dSDavid C Somayajulu if (status == QLA_SUCCESS) 3126f4f5df23SVikas Chaudhary ha->isp_ops->enable_intrs(ha); 3127afaf5a2dSDavid Somayajulu } 3128afaf5a2dSDavid Somayajulu } 3129afaf5a2dSDavid Somayajulu 3130f4f5df23SVikas Chaudhary dpc_post_reset_ha: 3131afaf5a2dSDavid Somayajulu /* ---- process AEN? --- */ 3132afaf5a2dSDavid Somayajulu if (test_and_clear_bit(DPC_AEN, &ha->dpc_flags)) 3133afaf5a2dSDavid Somayajulu qla4xxx_process_aen(ha, PROCESS_ALL_AENS); 3134afaf5a2dSDavid Somayajulu 3135afaf5a2dSDavid Somayajulu /* ---- Get DHCP IP Address? --- */ 3136afaf5a2dSDavid Somayajulu if (test_and_clear_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags)) 3137afaf5a2dSDavid Somayajulu qla4xxx_get_dhcp_ip_address(ha); 3138afaf5a2dSDavid Somayajulu 313913483730SMike Christie /* ---- relogin device? --- */ 314013483730SMike Christie if (adapter_up(ha) && 314113483730SMike Christie test_and_clear_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags)) { 314213483730SMike Christie iscsi_host_for_each_session(ha->host, qla4xxx_dpc_relogin); 314313483730SMike Christie } 314413483730SMike Christie 3145065aa1b4SVikas Chaudhary /* ---- link change? --- */ 3146065aa1b4SVikas Chaudhary if (test_and_clear_bit(DPC_LINK_CHANGED, &ha->dpc_flags)) { 3147065aa1b4SVikas Chaudhary if (!test_bit(AF_LINK_UP, &ha->flags)) { 3148065aa1b4SVikas Chaudhary /* ---- link down? --- */ 31492d7924e6SVikas Chaudhary qla4xxx_mark_all_devices_missing(ha); 3150065aa1b4SVikas Chaudhary } else { 3151065aa1b4SVikas Chaudhary /* ---- link up? --- * 3152065aa1b4SVikas Chaudhary * F/W will auto login to all devices ONLY ONCE after 3153065aa1b4SVikas Chaudhary * link up during driver initialization and runtime 3154065aa1b4SVikas Chaudhary * fatal error recovery. Therefore, the driver must 3155065aa1b4SVikas Chaudhary * manually relogin to devices when recovering from 3156065aa1b4SVikas Chaudhary * connection failures, logouts, expired KATO, etc. */ 315713483730SMike Christie if (test_and_clear_bit(AF_BUILD_DDB_LIST, &ha->flags)) { 315813483730SMike Christie qla4xxx_build_ddb_list(ha, ha->is_reset); 315913483730SMike Christie iscsi_host_for_each_session(ha->host, 316013483730SMike Christie qla4xxx_login_flash_ddb); 316113483730SMike Christie } else 31622d7924e6SVikas Chaudhary qla4xxx_relogin_all_devices(ha); 3163065aa1b4SVikas Chaudhary } 3164065aa1b4SVikas Chaudhary } 3165afaf5a2dSDavid Somayajulu } 3166afaf5a2dSDavid Somayajulu 3167afaf5a2dSDavid Somayajulu /** 3168afaf5a2dSDavid Somayajulu * qla4xxx_free_adapter - release the adapter 3169afaf5a2dSDavid Somayajulu * @ha: pointer to adapter structure 3170afaf5a2dSDavid Somayajulu **/ 3171afaf5a2dSDavid Somayajulu static void qla4xxx_free_adapter(struct scsi_qla_host *ha) 3172afaf5a2dSDavid Somayajulu { 31738a288960SSarang Radke qla4xxx_abort_active_cmds(ha, DID_NO_CONNECT << 16); 3174afaf5a2dSDavid Somayajulu 3175afaf5a2dSDavid Somayajulu if (test_bit(AF_INTERRUPTS_ON, &ha->flags)) { 3176afaf5a2dSDavid Somayajulu /* Turn-off interrupts on the card. */ 3177f4f5df23SVikas Chaudhary ha->isp_ops->disable_intrs(ha); 3178afaf5a2dSDavid Somayajulu } 3179afaf5a2dSDavid Somayajulu 3180afaf5a2dSDavid Somayajulu /* Remove timer thread, if present */ 3181afaf5a2dSDavid Somayajulu if (ha->timer_active) 3182afaf5a2dSDavid Somayajulu qla4xxx_stop_timer(ha); 3183afaf5a2dSDavid Somayajulu 3184f4f5df23SVikas Chaudhary /* Kill the kernel thread for this host */ 3185f4f5df23SVikas Chaudhary if (ha->dpc_thread) 3186f4f5df23SVikas Chaudhary destroy_workqueue(ha->dpc_thread); 3187f4f5df23SVikas Chaudhary 3188b3a271a9SManish Rangankar /* Kill the kernel thread for this host */ 3189b3a271a9SManish Rangankar if (ha->task_wq) 3190b3a271a9SManish Rangankar destroy_workqueue(ha->task_wq); 3191b3a271a9SManish Rangankar 3192f4f5df23SVikas Chaudhary /* Put firmware in known state */ 3193f4f5df23SVikas Chaudhary ha->isp_ops->reset_firmware(ha); 3194f4f5df23SVikas Chaudhary 3195f4f5df23SVikas Chaudhary if (is_qla8022(ha)) { 3196f4f5df23SVikas Chaudhary qla4_8xxx_idc_lock(ha); 3197f4f5df23SVikas Chaudhary qla4_8xxx_clear_drv_active(ha); 3198f4f5df23SVikas Chaudhary qla4_8xxx_idc_unlock(ha); 3199f4f5df23SVikas Chaudhary } 3200f4f5df23SVikas Chaudhary 3201afaf5a2dSDavid Somayajulu /* Detach interrupts */ 3202afaf5a2dSDavid Somayajulu if (test_and_clear_bit(AF_IRQ_ATTACHED, &ha->flags)) 3203f4f5df23SVikas Chaudhary qla4xxx_free_irqs(ha); 3204afaf5a2dSDavid Somayajulu 3205bee4fe8eSDavid C Somayajulu /* free extra memory */ 3206bee4fe8eSDavid C Somayajulu qla4xxx_mem_free(ha); 3207f4f5df23SVikas Chaudhary } 3208bee4fe8eSDavid C Somayajulu 3209f4f5df23SVikas Chaudhary int qla4_8xxx_iospace_config(struct scsi_qla_host *ha) 3210f4f5df23SVikas Chaudhary { 3211f4f5df23SVikas Chaudhary int status = 0; 3212f4f5df23SVikas Chaudhary uint8_t revision_id; 3213f4f5df23SVikas Chaudhary unsigned long mem_base, mem_len, db_base, db_len; 3214f4f5df23SVikas Chaudhary struct pci_dev *pdev = ha->pdev; 3215afaf5a2dSDavid Somayajulu 3216f4f5df23SVikas Chaudhary status = pci_request_regions(pdev, DRIVER_NAME); 3217f4f5df23SVikas Chaudhary if (status) { 3218f4f5df23SVikas Chaudhary printk(KERN_WARNING 3219f4f5df23SVikas Chaudhary "scsi(%ld) Failed to reserve PIO regions (%s) " 3220f4f5df23SVikas Chaudhary "status=%d\n", ha->host_no, pci_name(pdev), status); 3221f4f5df23SVikas Chaudhary goto iospace_error_exit; 3222f4f5df23SVikas Chaudhary } 3223f4f5df23SVikas Chaudhary 3224f4f5df23SVikas Chaudhary pci_read_config_byte(pdev, PCI_REVISION_ID, &revision_id); 3225f4f5df23SVikas Chaudhary DEBUG2(printk(KERN_INFO "%s: revision-id=%d\n", 3226f4f5df23SVikas Chaudhary __func__, revision_id)); 3227f4f5df23SVikas Chaudhary ha->revision_id = revision_id; 3228f4f5df23SVikas Chaudhary 3229f4f5df23SVikas Chaudhary /* remap phys address */ 3230f4f5df23SVikas Chaudhary mem_base = pci_resource_start(pdev, 0); /* 0 is for BAR 0 */ 3231f4f5df23SVikas Chaudhary mem_len = pci_resource_len(pdev, 0); 3232f4f5df23SVikas Chaudhary DEBUG2(printk(KERN_INFO "%s: ioremap from %lx a size of %lx\n", 3233f4f5df23SVikas Chaudhary __func__, mem_base, mem_len)); 3234f4f5df23SVikas Chaudhary 3235f4f5df23SVikas Chaudhary /* mapping of pcibase pointer */ 3236f4f5df23SVikas Chaudhary ha->nx_pcibase = (unsigned long)ioremap(mem_base, mem_len); 3237f4f5df23SVikas Chaudhary if (!ha->nx_pcibase) { 3238f4f5df23SVikas Chaudhary printk(KERN_ERR 3239f4f5df23SVikas Chaudhary "cannot remap MMIO (%s), aborting\n", pci_name(pdev)); 3240f4f5df23SVikas Chaudhary pci_release_regions(ha->pdev); 3241f4f5df23SVikas Chaudhary goto iospace_error_exit; 3242f4f5df23SVikas Chaudhary } 3243f4f5df23SVikas Chaudhary 3244f4f5df23SVikas Chaudhary /* Mapping of IO base pointer, door bell read and write pointer */ 3245f4f5df23SVikas Chaudhary 3246f4f5df23SVikas Chaudhary /* mapping of IO base pointer */ 3247f4f5df23SVikas Chaudhary ha->qla4_8xxx_reg = 3248f4f5df23SVikas Chaudhary (struct device_reg_82xx __iomem *)((uint8_t *)ha->nx_pcibase + 3249f4f5df23SVikas Chaudhary 0xbc000 + (ha->pdev->devfn << 11)); 3250f4f5df23SVikas Chaudhary 3251f4f5df23SVikas Chaudhary db_base = pci_resource_start(pdev, 4); /* doorbell is on bar 4 */ 3252f4f5df23SVikas Chaudhary db_len = pci_resource_len(pdev, 4); 3253f4f5df23SVikas Chaudhary 32542657c800SShyam Sundar ha->nx_db_wr_ptr = (ha->pdev->devfn == 4 ? QLA82XX_CAM_RAM_DB1 : 32552657c800SShyam Sundar QLA82XX_CAM_RAM_DB2); 3256f4f5df23SVikas Chaudhary 32572657c800SShyam Sundar return 0; 3258f4f5df23SVikas Chaudhary iospace_error_exit: 3259f4f5df23SVikas Chaudhary return -ENOMEM; 3260afaf5a2dSDavid Somayajulu } 3261afaf5a2dSDavid Somayajulu 3262afaf5a2dSDavid Somayajulu /*** 3263afaf5a2dSDavid Somayajulu * qla4xxx_iospace_config - maps registers 3264afaf5a2dSDavid Somayajulu * @ha: pointer to adapter structure 3265afaf5a2dSDavid Somayajulu * 3266afaf5a2dSDavid Somayajulu * This routines maps HBA's registers from the pci address space 3267afaf5a2dSDavid Somayajulu * into the kernel virtual address space for memory mapped i/o. 3268afaf5a2dSDavid Somayajulu **/ 3269f4f5df23SVikas Chaudhary int qla4xxx_iospace_config(struct scsi_qla_host *ha) 3270afaf5a2dSDavid Somayajulu { 3271afaf5a2dSDavid Somayajulu unsigned long pio, pio_len, pio_flags; 3272afaf5a2dSDavid Somayajulu unsigned long mmio, mmio_len, mmio_flags; 3273afaf5a2dSDavid Somayajulu 3274afaf5a2dSDavid Somayajulu pio = pci_resource_start(ha->pdev, 0); 3275afaf5a2dSDavid Somayajulu pio_len = pci_resource_len(ha->pdev, 0); 3276afaf5a2dSDavid Somayajulu pio_flags = pci_resource_flags(ha->pdev, 0); 3277afaf5a2dSDavid Somayajulu if (pio_flags & IORESOURCE_IO) { 3278afaf5a2dSDavid Somayajulu if (pio_len < MIN_IOBASE_LEN) { 3279c2660df3SVikas Chaudhary ql4_printk(KERN_WARNING, ha, 3280afaf5a2dSDavid Somayajulu "Invalid PCI I/O region size\n"); 3281afaf5a2dSDavid Somayajulu pio = 0; 3282afaf5a2dSDavid Somayajulu } 3283afaf5a2dSDavid Somayajulu } else { 3284c2660df3SVikas Chaudhary ql4_printk(KERN_WARNING, ha, "region #0 not a PIO resource\n"); 3285afaf5a2dSDavid Somayajulu pio = 0; 3286afaf5a2dSDavid Somayajulu } 3287afaf5a2dSDavid Somayajulu 3288afaf5a2dSDavid Somayajulu /* Use MMIO operations for all accesses. */ 3289afaf5a2dSDavid Somayajulu mmio = pci_resource_start(ha->pdev, 1); 3290afaf5a2dSDavid Somayajulu mmio_len = pci_resource_len(ha->pdev, 1); 3291afaf5a2dSDavid Somayajulu mmio_flags = pci_resource_flags(ha->pdev, 1); 3292afaf5a2dSDavid Somayajulu 3293afaf5a2dSDavid Somayajulu if (!(mmio_flags & IORESOURCE_MEM)) { 3294c2660df3SVikas Chaudhary ql4_printk(KERN_ERR, ha, 3295afaf5a2dSDavid Somayajulu "region #0 not an MMIO resource, aborting\n"); 3296afaf5a2dSDavid Somayajulu 3297afaf5a2dSDavid Somayajulu goto iospace_error_exit; 3298afaf5a2dSDavid Somayajulu } 3299c2660df3SVikas Chaudhary 3300afaf5a2dSDavid Somayajulu if (mmio_len < MIN_IOBASE_LEN) { 3301c2660df3SVikas Chaudhary ql4_printk(KERN_ERR, ha, 3302afaf5a2dSDavid Somayajulu "Invalid PCI mem region size, aborting\n"); 3303afaf5a2dSDavid Somayajulu goto iospace_error_exit; 3304afaf5a2dSDavid Somayajulu } 3305afaf5a2dSDavid Somayajulu 3306afaf5a2dSDavid Somayajulu if (pci_request_regions(ha->pdev, DRIVER_NAME)) { 3307c2660df3SVikas Chaudhary ql4_printk(KERN_WARNING, ha, 3308afaf5a2dSDavid Somayajulu "Failed to reserve PIO/MMIO regions\n"); 3309afaf5a2dSDavid Somayajulu 3310afaf5a2dSDavid Somayajulu goto iospace_error_exit; 3311afaf5a2dSDavid Somayajulu } 3312afaf5a2dSDavid Somayajulu 3313afaf5a2dSDavid Somayajulu ha->pio_address = pio; 3314afaf5a2dSDavid Somayajulu ha->pio_length = pio_len; 3315afaf5a2dSDavid Somayajulu ha->reg = ioremap(mmio, MIN_IOBASE_LEN); 3316afaf5a2dSDavid Somayajulu if (!ha->reg) { 3317c2660df3SVikas Chaudhary ql4_printk(KERN_ERR, ha, 3318afaf5a2dSDavid Somayajulu "cannot remap MMIO, aborting\n"); 3319afaf5a2dSDavid Somayajulu 3320afaf5a2dSDavid Somayajulu goto iospace_error_exit; 3321afaf5a2dSDavid Somayajulu } 3322afaf5a2dSDavid Somayajulu 3323afaf5a2dSDavid Somayajulu return 0; 3324afaf5a2dSDavid Somayajulu 3325afaf5a2dSDavid Somayajulu iospace_error_exit: 3326afaf5a2dSDavid Somayajulu return -ENOMEM; 3327afaf5a2dSDavid Somayajulu } 3328afaf5a2dSDavid Somayajulu 3329f4f5df23SVikas Chaudhary static struct isp_operations qla4xxx_isp_ops = { 3330f4f5df23SVikas Chaudhary .iospace_config = qla4xxx_iospace_config, 3331f4f5df23SVikas Chaudhary .pci_config = qla4xxx_pci_config, 3332f4f5df23SVikas Chaudhary .disable_intrs = qla4xxx_disable_intrs, 3333f4f5df23SVikas Chaudhary .enable_intrs = qla4xxx_enable_intrs, 3334f4f5df23SVikas Chaudhary .start_firmware = qla4xxx_start_firmware, 3335f4f5df23SVikas Chaudhary .intr_handler = qla4xxx_intr_handler, 3336f4f5df23SVikas Chaudhary .interrupt_service_routine = qla4xxx_interrupt_service_routine, 3337f4f5df23SVikas Chaudhary .reset_chip = qla4xxx_soft_reset, 3338f4f5df23SVikas Chaudhary .reset_firmware = qla4xxx_hw_reset, 3339f4f5df23SVikas Chaudhary .queue_iocb = qla4xxx_queue_iocb, 3340f4f5df23SVikas Chaudhary .complete_iocb = qla4xxx_complete_iocb, 3341f4f5df23SVikas Chaudhary .rd_shdw_req_q_out = qla4xxx_rd_shdw_req_q_out, 3342f4f5df23SVikas Chaudhary .rd_shdw_rsp_q_in = qla4xxx_rd_shdw_rsp_q_in, 3343f4f5df23SVikas Chaudhary .get_sys_info = qla4xxx_get_sys_info, 3344f4f5df23SVikas Chaudhary }; 3345f4f5df23SVikas Chaudhary 3346f4f5df23SVikas Chaudhary static struct isp_operations qla4_8xxx_isp_ops = { 3347f4f5df23SVikas Chaudhary .iospace_config = qla4_8xxx_iospace_config, 3348f4f5df23SVikas Chaudhary .pci_config = qla4_8xxx_pci_config, 3349f4f5df23SVikas Chaudhary .disable_intrs = qla4_8xxx_disable_intrs, 3350f4f5df23SVikas Chaudhary .enable_intrs = qla4_8xxx_enable_intrs, 3351f4f5df23SVikas Chaudhary .start_firmware = qla4_8xxx_load_risc, 3352f4f5df23SVikas Chaudhary .intr_handler = qla4_8xxx_intr_handler, 3353f4f5df23SVikas Chaudhary .interrupt_service_routine = qla4_8xxx_interrupt_service_routine, 3354f4f5df23SVikas Chaudhary .reset_chip = qla4_8xxx_isp_reset, 3355f4f5df23SVikas Chaudhary .reset_firmware = qla4_8xxx_stop_firmware, 3356f4f5df23SVikas Chaudhary .queue_iocb = qla4_8xxx_queue_iocb, 3357f4f5df23SVikas Chaudhary .complete_iocb = qla4_8xxx_complete_iocb, 3358f4f5df23SVikas Chaudhary .rd_shdw_req_q_out = qla4_8xxx_rd_shdw_req_q_out, 3359f4f5df23SVikas Chaudhary .rd_shdw_rsp_q_in = qla4_8xxx_rd_shdw_rsp_q_in, 3360f4f5df23SVikas Chaudhary .get_sys_info = qla4_8xxx_get_sys_info, 3361f4f5df23SVikas Chaudhary }; 3362f4f5df23SVikas Chaudhary 3363f4f5df23SVikas Chaudhary uint16_t qla4xxx_rd_shdw_req_q_out(struct scsi_qla_host *ha) 3364f4f5df23SVikas Chaudhary { 3365f4f5df23SVikas Chaudhary return (uint16_t)le32_to_cpu(ha->shadow_regs->req_q_out); 3366f4f5df23SVikas Chaudhary } 3367f4f5df23SVikas Chaudhary 3368f4f5df23SVikas Chaudhary uint16_t qla4_8xxx_rd_shdw_req_q_out(struct scsi_qla_host *ha) 3369f4f5df23SVikas Chaudhary { 3370f4f5df23SVikas Chaudhary return (uint16_t)le32_to_cpu(readl(&ha->qla4_8xxx_reg->req_q_out)); 3371f4f5df23SVikas Chaudhary } 3372f4f5df23SVikas Chaudhary 3373f4f5df23SVikas Chaudhary uint16_t qla4xxx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha) 3374f4f5df23SVikas Chaudhary { 3375f4f5df23SVikas Chaudhary return (uint16_t)le32_to_cpu(ha->shadow_regs->rsp_q_in); 3376f4f5df23SVikas Chaudhary } 3377f4f5df23SVikas Chaudhary 3378f4f5df23SVikas Chaudhary uint16_t qla4_8xxx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha) 3379f4f5df23SVikas Chaudhary { 3380f4f5df23SVikas Chaudhary return (uint16_t)le32_to_cpu(readl(&ha->qla4_8xxx_reg->rsp_q_in)); 3381f4f5df23SVikas Chaudhary } 3382f4f5df23SVikas Chaudhary 33832a991c21SManish Rangankar static ssize_t qla4xxx_show_boot_eth_info(void *data, int type, char *buf) 33842a991c21SManish Rangankar { 33852a991c21SManish Rangankar struct scsi_qla_host *ha = data; 33862a991c21SManish Rangankar char *str = buf; 33872a991c21SManish Rangankar int rc; 33882a991c21SManish Rangankar 33892a991c21SManish Rangankar switch (type) { 33902a991c21SManish Rangankar case ISCSI_BOOT_ETH_FLAGS: 33912a991c21SManish Rangankar rc = sprintf(str, "%d\n", SYSFS_FLAG_FW_SEL_BOOT); 33922a991c21SManish Rangankar break; 33932a991c21SManish Rangankar case ISCSI_BOOT_ETH_INDEX: 33942a991c21SManish Rangankar rc = sprintf(str, "0\n"); 33952a991c21SManish Rangankar break; 33962a991c21SManish Rangankar case ISCSI_BOOT_ETH_MAC: 33972a991c21SManish Rangankar rc = sysfs_format_mac(str, ha->my_mac, 33982a991c21SManish Rangankar MAC_ADDR_LEN); 33992a991c21SManish Rangankar break; 34002a991c21SManish Rangankar default: 34012a991c21SManish Rangankar rc = -ENOSYS; 34022a991c21SManish Rangankar break; 34032a991c21SManish Rangankar } 34042a991c21SManish Rangankar return rc; 34052a991c21SManish Rangankar } 34062a991c21SManish Rangankar 3407587a1f16SAl Viro static umode_t qla4xxx_eth_get_attr_visibility(void *data, int type) 34082a991c21SManish Rangankar { 34092a991c21SManish Rangankar int rc; 34102a991c21SManish Rangankar 34112a991c21SManish Rangankar switch (type) { 34122a991c21SManish Rangankar case ISCSI_BOOT_ETH_FLAGS: 34132a991c21SManish Rangankar case ISCSI_BOOT_ETH_MAC: 34142a991c21SManish Rangankar case ISCSI_BOOT_ETH_INDEX: 34152a991c21SManish Rangankar rc = S_IRUGO; 34162a991c21SManish Rangankar break; 34172a991c21SManish Rangankar default: 34182a991c21SManish Rangankar rc = 0; 34192a991c21SManish Rangankar break; 34202a991c21SManish Rangankar } 34212a991c21SManish Rangankar return rc; 34222a991c21SManish Rangankar } 34232a991c21SManish Rangankar 34242a991c21SManish Rangankar static ssize_t qla4xxx_show_boot_ini_info(void *data, int type, char *buf) 34252a991c21SManish Rangankar { 34262a991c21SManish Rangankar struct scsi_qla_host *ha = data; 34272a991c21SManish Rangankar char *str = buf; 34282a991c21SManish Rangankar int rc; 34292a991c21SManish Rangankar 34302a991c21SManish Rangankar switch (type) { 34312a991c21SManish Rangankar case ISCSI_BOOT_INI_INITIATOR_NAME: 34322a991c21SManish Rangankar rc = sprintf(str, "%s\n", ha->name_string); 34332a991c21SManish Rangankar break; 34342a991c21SManish Rangankar default: 34352a991c21SManish Rangankar rc = -ENOSYS; 34362a991c21SManish Rangankar break; 34372a991c21SManish Rangankar } 34382a991c21SManish Rangankar return rc; 34392a991c21SManish Rangankar } 34402a991c21SManish Rangankar 3441587a1f16SAl Viro static umode_t qla4xxx_ini_get_attr_visibility(void *data, int type) 34422a991c21SManish Rangankar { 34432a991c21SManish Rangankar int rc; 34442a991c21SManish Rangankar 34452a991c21SManish Rangankar switch (type) { 34462a991c21SManish Rangankar case ISCSI_BOOT_INI_INITIATOR_NAME: 34472a991c21SManish Rangankar rc = S_IRUGO; 34482a991c21SManish Rangankar break; 34492a991c21SManish Rangankar default: 34502a991c21SManish Rangankar rc = 0; 34512a991c21SManish Rangankar break; 34522a991c21SManish Rangankar } 34532a991c21SManish Rangankar return rc; 34542a991c21SManish Rangankar } 34552a991c21SManish Rangankar 34562a991c21SManish Rangankar static ssize_t 34572a991c21SManish Rangankar qla4xxx_show_boot_tgt_info(struct ql4_boot_session_info *boot_sess, int type, 34582a991c21SManish Rangankar char *buf) 34592a991c21SManish Rangankar { 34602a991c21SManish Rangankar struct ql4_conn_info *boot_conn = &boot_sess->conn_list[0]; 34612a991c21SManish Rangankar char *str = buf; 34622a991c21SManish Rangankar int rc; 34632a991c21SManish Rangankar 34642a991c21SManish Rangankar switch (type) { 34652a991c21SManish Rangankar case ISCSI_BOOT_TGT_NAME: 34662a991c21SManish Rangankar rc = sprintf(buf, "%s\n", (char *)&boot_sess->target_name); 34672a991c21SManish Rangankar break; 34682a991c21SManish Rangankar case ISCSI_BOOT_TGT_IP_ADDR: 34692a991c21SManish Rangankar if (boot_sess->conn_list[0].dest_ipaddr.ip_type == 0x1) 34702a991c21SManish Rangankar rc = sprintf(buf, "%pI4\n", 34712a991c21SManish Rangankar &boot_conn->dest_ipaddr.ip_address); 34722a991c21SManish Rangankar else 34732a991c21SManish Rangankar rc = sprintf(str, "%pI6\n", 34742a991c21SManish Rangankar &boot_conn->dest_ipaddr.ip_address); 34752a991c21SManish Rangankar break; 34762a991c21SManish Rangankar case ISCSI_BOOT_TGT_PORT: 34772a991c21SManish Rangankar rc = sprintf(str, "%d\n", boot_conn->dest_port); 34782a991c21SManish Rangankar break; 34792a991c21SManish Rangankar case ISCSI_BOOT_TGT_CHAP_NAME: 34802a991c21SManish Rangankar rc = sprintf(str, "%.*s\n", 34812a991c21SManish Rangankar boot_conn->chap.target_chap_name_length, 34822a991c21SManish Rangankar (char *)&boot_conn->chap.target_chap_name); 34832a991c21SManish Rangankar break; 34842a991c21SManish Rangankar case ISCSI_BOOT_TGT_CHAP_SECRET: 34852a991c21SManish Rangankar rc = sprintf(str, "%.*s\n", 34862a991c21SManish Rangankar boot_conn->chap.target_secret_length, 34872a991c21SManish Rangankar (char *)&boot_conn->chap.target_secret); 34882a991c21SManish Rangankar break; 34892a991c21SManish Rangankar case ISCSI_BOOT_TGT_REV_CHAP_NAME: 34902a991c21SManish Rangankar rc = sprintf(str, "%.*s\n", 34912a991c21SManish Rangankar boot_conn->chap.intr_chap_name_length, 34922a991c21SManish Rangankar (char *)&boot_conn->chap.intr_chap_name); 34932a991c21SManish Rangankar break; 34942a991c21SManish Rangankar case ISCSI_BOOT_TGT_REV_CHAP_SECRET: 34952a991c21SManish Rangankar rc = sprintf(str, "%.*s\n", 34962a991c21SManish Rangankar boot_conn->chap.intr_secret_length, 34972a991c21SManish Rangankar (char *)&boot_conn->chap.intr_secret); 34982a991c21SManish Rangankar break; 34992a991c21SManish Rangankar case ISCSI_BOOT_TGT_FLAGS: 35002a991c21SManish Rangankar rc = sprintf(str, "%d\n", SYSFS_FLAG_FW_SEL_BOOT); 35012a991c21SManish Rangankar break; 35022a991c21SManish Rangankar case ISCSI_BOOT_TGT_NIC_ASSOC: 35032a991c21SManish Rangankar rc = sprintf(str, "0\n"); 35042a991c21SManish Rangankar break; 35052a991c21SManish Rangankar default: 35062a991c21SManish Rangankar rc = -ENOSYS; 35072a991c21SManish Rangankar break; 35082a991c21SManish Rangankar } 35092a991c21SManish Rangankar return rc; 35102a991c21SManish Rangankar } 35112a991c21SManish Rangankar 35122a991c21SManish Rangankar static ssize_t qla4xxx_show_boot_tgt_pri_info(void *data, int type, char *buf) 35132a991c21SManish Rangankar { 35142a991c21SManish Rangankar struct scsi_qla_host *ha = data; 35152a991c21SManish Rangankar struct ql4_boot_session_info *boot_sess = &(ha->boot_tgt.boot_pri_sess); 35162a991c21SManish Rangankar 35172a991c21SManish Rangankar return qla4xxx_show_boot_tgt_info(boot_sess, type, buf); 35182a991c21SManish Rangankar } 35192a991c21SManish Rangankar 35202a991c21SManish Rangankar static ssize_t qla4xxx_show_boot_tgt_sec_info(void *data, int type, char *buf) 35212a991c21SManish Rangankar { 35222a991c21SManish Rangankar struct scsi_qla_host *ha = data; 35232a991c21SManish Rangankar struct ql4_boot_session_info *boot_sess = &(ha->boot_tgt.boot_sec_sess); 35242a991c21SManish Rangankar 35252a991c21SManish Rangankar return qla4xxx_show_boot_tgt_info(boot_sess, type, buf); 35262a991c21SManish Rangankar } 35272a991c21SManish Rangankar 3528587a1f16SAl Viro static umode_t qla4xxx_tgt_get_attr_visibility(void *data, int type) 35292a991c21SManish Rangankar { 35302a991c21SManish Rangankar int rc; 35312a991c21SManish Rangankar 35322a991c21SManish Rangankar switch (type) { 35332a991c21SManish Rangankar case ISCSI_BOOT_TGT_NAME: 35342a991c21SManish Rangankar case ISCSI_BOOT_TGT_IP_ADDR: 35352a991c21SManish Rangankar case ISCSI_BOOT_TGT_PORT: 35362a991c21SManish Rangankar case ISCSI_BOOT_TGT_CHAP_NAME: 35372a991c21SManish Rangankar case ISCSI_BOOT_TGT_CHAP_SECRET: 35382a991c21SManish Rangankar case ISCSI_BOOT_TGT_REV_CHAP_NAME: 35392a991c21SManish Rangankar case ISCSI_BOOT_TGT_REV_CHAP_SECRET: 35402a991c21SManish Rangankar case ISCSI_BOOT_TGT_NIC_ASSOC: 35412a991c21SManish Rangankar case ISCSI_BOOT_TGT_FLAGS: 35422a991c21SManish Rangankar rc = S_IRUGO; 35432a991c21SManish Rangankar break; 35442a991c21SManish Rangankar default: 35452a991c21SManish Rangankar rc = 0; 35462a991c21SManish Rangankar break; 35472a991c21SManish Rangankar } 35482a991c21SManish Rangankar return rc; 35492a991c21SManish Rangankar } 35502a991c21SManish Rangankar 35512a991c21SManish Rangankar static void qla4xxx_boot_release(void *data) 35522a991c21SManish Rangankar { 35532a991c21SManish Rangankar struct scsi_qla_host *ha = data; 35542a991c21SManish Rangankar 35552a991c21SManish Rangankar scsi_host_put(ha->host); 35562a991c21SManish Rangankar } 35572a991c21SManish Rangankar 35582a991c21SManish Rangankar static int get_fw_boot_info(struct scsi_qla_host *ha, uint16_t ddb_index[]) 35592a991c21SManish Rangankar { 35602a991c21SManish Rangankar dma_addr_t buf_dma; 35612a991c21SManish Rangankar uint32_t addr, pri_addr, sec_addr; 35622a991c21SManish Rangankar uint32_t offset; 35632a991c21SManish Rangankar uint16_t func_num; 35642a991c21SManish Rangankar uint8_t val; 35652a991c21SManish Rangankar uint8_t *buf = NULL; 35662a991c21SManish Rangankar size_t size = 13 * sizeof(uint8_t); 35672a991c21SManish Rangankar int ret = QLA_SUCCESS; 35682a991c21SManish Rangankar 35692a991c21SManish Rangankar func_num = PCI_FUNC(ha->pdev->devfn); 35702a991c21SManish Rangankar 35710d5b36b8SManish Rangankar ql4_printk(KERN_INFO, ha, "%s: Get FW boot info for 0x%x func %d\n", 35720d5b36b8SManish Rangankar __func__, ha->pdev->device, func_num); 35732a991c21SManish Rangankar 35740d5b36b8SManish Rangankar if (is_qla40XX(ha)) { 35752a991c21SManish Rangankar if (func_num == 1) { 35762a991c21SManish Rangankar addr = NVRAM_PORT0_BOOT_MODE; 35772a991c21SManish Rangankar pri_addr = NVRAM_PORT0_BOOT_PRI_TGT; 35782a991c21SManish Rangankar sec_addr = NVRAM_PORT0_BOOT_SEC_TGT; 35792a991c21SManish Rangankar } else if (func_num == 3) { 35802a991c21SManish Rangankar addr = NVRAM_PORT1_BOOT_MODE; 35812a991c21SManish Rangankar pri_addr = NVRAM_PORT1_BOOT_PRI_TGT; 35822a991c21SManish Rangankar sec_addr = NVRAM_PORT1_BOOT_SEC_TGT; 35832a991c21SManish Rangankar } else { 35842a991c21SManish Rangankar ret = QLA_ERROR; 35852a991c21SManish Rangankar goto exit_boot_info; 35862a991c21SManish Rangankar } 35872a991c21SManish Rangankar 35882a991c21SManish Rangankar /* Check Boot Mode */ 35892a991c21SManish Rangankar val = rd_nvram_byte(ha, addr); 35902a991c21SManish Rangankar if (!(val & 0x07)) { 3591e8fb00e0SManish Rangankar DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Adapter boot " 3592e8fb00e0SManish Rangankar "options : 0x%x\n", __func__, val)); 35932a991c21SManish Rangankar ret = QLA_ERROR; 35942a991c21SManish Rangankar goto exit_boot_info; 35952a991c21SManish Rangankar } 35962a991c21SManish Rangankar 35972a991c21SManish Rangankar /* get primary valid target index */ 35982a991c21SManish Rangankar val = rd_nvram_byte(ha, pri_addr); 35992a991c21SManish Rangankar if (val & BIT_7) 36002a991c21SManish Rangankar ddb_index[0] = (val & 0x7f); 36012a991c21SManish Rangankar 36022a991c21SManish Rangankar /* get secondary valid target index */ 36032a991c21SManish Rangankar val = rd_nvram_byte(ha, sec_addr); 36042a991c21SManish Rangankar if (val & BIT_7) 36052a991c21SManish Rangankar ddb_index[1] = (val & 0x7f); 36062a991c21SManish Rangankar 36072a991c21SManish Rangankar } else if (is_qla8022(ha)) { 36082a991c21SManish Rangankar buf = dma_alloc_coherent(&ha->pdev->dev, size, 36092a991c21SManish Rangankar &buf_dma, GFP_KERNEL); 36102a991c21SManish Rangankar if (!buf) { 36112a991c21SManish Rangankar DEBUG2(ql4_printk(KERN_ERR, ha, 36122a991c21SManish Rangankar "%s: Unable to allocate dma buffer\n", 36132a991c21SManish Rangankar __func__)); 36142a991c21SManish Rangankar ret = QLA_ERROR; 36152a991c21SManish Rangankar goto exit_boot_info; 36162a991c21SManish Rangankar } 36172a991c21SManish Rangankar 36182a991c21SManish Rangankar if (ha->port_num == 0) 36192a991c21SManish Rangankar offset = BOOT_PARAM_OFFSET_PORT0; 36202a991c21SManish Rangankar else if (ha->port_num == 1) 36212a991c21SManish Rangankar offset = BOOT_PARAM_OFFSET_PORT1; 36222a991c21SManish Rangankar else { 36232a991c21SManish Rangankar ret = QLA_ERROR; 36242a991c21SManish Rangankar goto exit_boot_info_free; 36252a991c21SManish Rangankar } 36262a991c21SManish Rangankar addr = FLASH_RAW_ACCESS_ADDR + (ha->hw.flt_iscsi_param * 4) + 36272a991c21SManish Rangankar offset; 36282a991c21SManish Rangankar if (qla4xxx_get_flash(ha, buf_dma, addr, 36292a991c21SManish Rangankar 13 * sizeof(uint8_t)) != QLA_SUCCESS) { 36302a991c21SManish Rangankar DEBUG2(ql4_printk(KERN_ERR, ha, "scsi%ld: %s: Get Flash" 36312a991c21SManish Rangankar "failed\n", ha->host_no, __func__)); 36322a991c21SManish Rangankar ret = QLA_ERROR; 36332a991c21SManish Rangankar goto exit_boot_info_free; 36342a991c21SManish Rangankar } 36352a991c21SManish Rangankar /* Check Boot Mode */ 36362a991c21SManish Rangankar if (!(buf[1] & 0x07)) { 3637e8fb00e0SManish Rangankar DEBUG2(ql4_printk(KERN_INFO, ha, "Firmware boot options" 3638e8fb00e0SManish Rangankar " : 0x%x\n", buf[1])); 36392a991c21SManish Rangankar ret = QLA_ERROR; 36402a991c21SManish Rangankar goto exit_boot_info_free; 36412a991c21SManish Rangankar } 36422a991c21SManish Rangankar 36432a991c21SManish Rangankar /* get primary valid target index */ 36442a991c21SManish Rangankar if (buf[2] & BIT_7) 36452a991c21SManish Rangankar ddb_index[0] = buf[2] & 0x7f; 36462a991c21SManish Rangankar 36472a991c21SManish Rangankar /* get secondary valid target index */ 36482a991c21SManish Rangankar if (buf[11] & BIT_7) 36492a991c21SManish Rangankar ddb_index[1] = buf[11] & 0x7f; 36502a991c21SManish Rangankar } else { 36512a991c21SManish Rangankar ret = QLA_ERROR; 36522a991c21SManish Rangankar goto exit_boot_info; 36532a991c21SManish Rangankar } 36542a991c21SManish Rangankar 36552a991c21SManish Rangankar DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Primary target ID %d, Secondary" 36562a991c21SManish Rangankar " target ID %d\n", __func__, ddb_index[0], 36572a991c21SManish Rangankar ddb_index[1])); 36582a991c21SManish Rangankar 36592a991c21SManish Rangankar exit_boot_info_free: 36602a991c21SManish Rangankar dma_free_coherent(&ha->pdev->dev, size, buf, buf_dma); 36612a991c21SManish Rangankar exit_boot_info: 366220e835b4SLalit Chandivade ha->pri_ddb_idx = ddb_index[0]; 366320e835b4SLalit Chandivade ha->sec_ddb_idx = ddb_index[1]; 36642a991c21SManish Rangankar return ret; 36652a991c21SManish Rangankar } 36662a991c21SManish Rangankar 366728deb45cSLalit Chandivade /** 366828deb45cSLalit Chandivade * qla4xxx_get_bidi_chap - Get a BIDI CHAP user and password 366928deb45cSLalit Chandivade * @ha: pointer to adapter structure 367028deb45cSLalit Chandivade * @username: CHAP username to be returned 367128deb45cSLalit Chandivade * @password: CHAP password to be returned 367228deb45cSLalit Chandivade * 367328deb45cSLalit Chandivade * If a boot entry has BIDI CHAP enabled then we need to set the BIDI CHAP 367428deb45cSLalit Chandivade * user and password in the sysfs entry in /sys/firmware/iscsi_boot#/. 367528deb45cSLalit Chandivade * So from the CHAP cache find the first BIDI CHAP entry and set it 367628deb45cSLalit Chandivade * to the boot record in sysfs. 367728deb45cSLalit Chandivade **/ 367828deb45cSLalit Chandivade static int qla4xxx_get_bidi_chap(struct scsi_qla_host *ha, char *username, 367928deb45cSLalit Chandivade char *password) 368028deb45cSLalit Chandivade { 368128deb45cSLalit Chandivade int i, ret = -EINVAL; 368228deb45cSLalit Chandivade int max_chap_entries = 0; 368328deb45cSLalit Chandivade struct ql4_chap_table *chap_table; 368428deb45cSLalit Chandivade 368528deb45cSLalit Chandivade if (is_qla8022(ha)) 368628deb45cSLalit Chandivade max_chap_entries = (ha->hw.flt_chap_size / 2) / 368728deb45cSLalit Chandivade sizeof(struct ql4_chap_table); 368828deb45cSLalit Chandivade else 368928deb45cSLalit Chandivade max_chap_entries = MAX_CHAP_ENTRIES_40XX; 369028deb45cSLalit Chandivade 369128deb45cSLalit Chandivade if (!ha->chap_list) { 369228deb45cSLalit Chandivade ql4_printk(KERN_ERR, ha, "Do not have CHAP table cache\n"); 369328deb45cSLalit Chandivade return ret; 369428deb45cSLalit Chandivade } 369528deb45cSLalit Chandivade 369628deb45cSLalit Chandivade mutex_lock(&ha->chap_sem); 369728deb45cSLalit Chandivade for (i = 0; i < max_chap_entries; i++) { 369828deb45cSLalit Chandivade chap_table = (struct ql4_chap_table *)ha->chap_list + i; 369928deb45cSLalit Chandivade if (chap_table->cookie != 370028deb45cSLalit Chandivade __constant_cpu_to_le16(CHAP_VALID_COOKIE)) { 370128deb45cSLalit Chandivade continue; 370228deb45cSLalit Chandivade } 370328deb45cSLalit Chandivade 370428deb45cSLalit Chandivade if (chap_table->flags & BIT_7) /* local */ 370528deb45cSLalit Chandivade continue; 370628deb45cSLalit Chandivade 370728deb45cSLalit Chandivade if (!(chap_table->flags & BIT_6)) /* Not BIDI */ 370828deb45cSLalit Chandivade continue; 370928deb45cSLalit Chandivade 371028deb45cSLalit Chandivade strncpy(password, chap_table->secret, QL4_CHAP_MAX_SECRET_LEN); 371128deb45cSLalit Chandivade strncpy(username, chap_table->name, QL4_CHAP_MAX_NAME_LEN); 371228deb45cSLalit Chandivade ret = 0; 371328deb45cSLalit Chandivade break; 371428deb45cSLalit Chandivade } 371528deb45cSLalit Chandivade mutex_unlock(&ha->chap_sem); 371628deb45cSLalit Chandivade 371728deb45cSLalit Chandivade return ret; 371828deb45cSLalit Chandivade } 371928deb45cSLalit Chandivade 372028deb45cSLalit Chandivade 37212a991c21SManish Rangankar static int qla4xxx_get_boot_target(struct scsi_qla_host *ha, 37222a991c21SManish Rangankar struct ql4_boot_session_info *boot_sess, 37232a991c21SManish Rangankar uint16_t ddb_index) 37242a991c21SManish Rangankar { 37252a991c21SManish Rangankar struct ql4_conn_info *boot_conn = &boot_sess->conn_list[0]; 37262a991c21SManish Rangankar struct dev_db_entry *fw_ddb_entry; 37272a991c21SManish Rangankar dma_addr_t fw_ddb_entry_dma; 37282a991c21SManish Rangankar uint16_t idx; 37292a991c21SManish Rangankar uint16_t options; 37302a991c21SManish Rangankar int ret = QLA_SUCCESS; 37312a991c21SManish Rangankar 37322a991c21SManish Rangankar fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), 37332a991c21SManish Rangankar &fw_ddb_entry_dma, GFP_KERNEL); 37342a991c21SManish Rangankar if (!fw_ddb_entry) { 37352a991c21SManish Rangankar DEBUG2(ql4_printk(KERN_ERR, ha, 37362a991c21SManish Rangankar "%s: Unable to allocate dma buffer.\n", 37372a991c21SManish Rangankar __func__)); 37382a991c21SManish Rangankar ret = QLA_ERROR; 37392a991c21SManish Rangankar return ret; 37402a991c21SManish Rangankar } 37412a991c21SManish Rangankar 37422a991c21SManish Rangankar if (qla4xxx_bootdb_by_index(ha, fw_ddb_entry, 37432a991c21SManish Rangankar fw_ddb_entry_dma, ddb_index)) { 3744e8fb00e0SManish Rangankar DEBUG2(ql4_printk(KERN_INFO, ha, "%s: No Flash DDB found at " 3745e8fb00e0SManish Rangankar "index [%d]\n", __func__, ddb_index)); 37462a991c21SManish Rangankar ret = QLA_ERROR; 37472a991c21SManish Rangankar goto exit_boot_target; 37482a991c21SManish Rangankar } 37492a991c21SManish Rangankar 37502a991c21SManish Rangankar /* Update target name and IP from DDB */ 37512a991c21SManish Rangankar memcpy(boot_sess->target_name, fw_ddb_entry->iscsi_name, 37522a991c21SManish Rangankar min(sizeof(boot_sess->target_name), 37532a991c21SManish Rangankar sizeof(fw_ddb_entry->iscsi_name))); 37542a991c21SManish Rangankar 37552a991c21SManish Rangankar options = le16_to_cpu(fw_ddb_entry->options); 37562a991c21SManish Rangankar if (options & DDB_OPT_IPV6_DEVICE) { 37572a991c21SManish Rangankar memcpy(&boot_conn->dest_ipaddr.ip_address, 37582a991c21SManish Rangankar &fw_ddb_entry->ip_addr[0], IPv6_ADDR_LEN); 37592a991c21SManish Rangankar } else { 37602a991c21SManish Rangankar boot_conn->dest_ipaddr.ip_type = 0x1; 37612a991c21SManish Rangankar memcpy(&boot_conn->dest_ipaddr.ip_address, 37622a991c21SManish Rangankar &fw_ddb_entry->ip_addr[0], IP_ADDR_LEN); 37632a991c21SManish Rangankar } 37642a991c21SManish Rangankar 37652a991c21SManish Rangankar boot_conn->dest_port = le16_to_cpu(fw_ddb_entry->port); 37662a991c21SManish Rangankar 37672a991c21SManish Rangankar /* update chap information */ 37682a991c21SManish Rangankar idx = __le16_to_cpu(fw_ddb_entry->chap_tbl_idx); 37692a991c21SManish Rangankar 37702a991c21SManish Rangankar if (BIT_7 & le16_to_cpu(fw_ddb_entry->iscsi_options)) { 37712a991c21SManish Rangankar 37722a991c21SManish Rangankar DEBUG2(ql4_printk(KERN_INFO, ha, "Setting chap\n")); 37732a991c21SManish Rangankar 37742a991c21SManish Rangankar ret = qla4xxx_get_chap(ha, (char *)&boot_conn->chap. 37752a991c21SManish Rangankar target_chap_name, 37762a991c21SManish Rangankar (char *)&boot_conn->chap.target_secret, 37772a991c21SManish Rangankar idx); 37782a991c21SManish Rangankar if (ret) { 37792a991c21SManish Rangankar ql4_printk(KERN_ERR, ha, "Failed to set chap\n"); 37802a991c21SManish Rangankar ret = QLA_ERROR; 37812a991c21SManish Rangankar goto exit_boot_target; 37822a991c21SManish Rangankar } 37832a991c21SManish Rangankar 37842a991c21SManish Rangankar boot_conn->chap.target_chap_name_length = QL4_CHAP_MAX_NAME_LEN; 37852a991c21SManish Rangankar boot_conn->chap.target_secret_length = QL4_CHAP_MAX_SECRET_LEN; 37862a991c21SManish Rangankar } 37872a991c21SManish Rangankar 37882a991c21SManish Rangankar if (BIT_4 & le16_to_cpu(fw_ddb_entry->iscsi_options)) { 37892a991c21SManish Rangankar 37902a991c21SManish Rangankar DEBUG2(ql4_printk(KERN_INFO, ha, "Setting BIDI chap\n")); 37912a991c21SManish Rangankar 379228deb45cSLalit Chandivade ret = qla4xxx_get_bidi_chap(ha, 379328deb45cSLalit Chandivade (char *)&boot_conn->chap.intr_chap_name, 379428deb45cSLalit Chandivade (char *)&boot_conn->chap.intr_secret); 379528deb45cSLalit Chandivade 37962a991c21SManish Rangankar if (ret) { 37972a991c21SManish Rangankar ql4_printk(KERN_ERR, ha, "Failed to set BIDI chap\n"); 37982a991c21SManish Rangankar ret = QLA_ERROR; 37992a991c21SManish Rangankar goto exit_boot_target; 38002a991c21SManish Rangankar } 38012a991c21SManish Rangankar 38022a991c21SManish Rangankar boot_conn->chap.intr_chap_name_length = QL4_CHAP_MAX_NAME_LEN; 38032a991c21SManish Rangankar boot_conn->chap.intr_secret_length = QL4_CHAP_MAX_SECRET_LEN; 38042a991c21SManish Rangankar } 38052a991c21SManish Rangankar 38062a991c21SManish Rangankar exit_boot_target: 38072a991c21SManish Rangankar dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), 38082a991c21SManish Rangankar fw_ddb_entry, fw_ddb_entry_dma); 38092a991c21SManish Rangankar return ret; 38102a991c21SManish Rangankar } 38112a991c21SManish Rangankar 38122a991c21SManish Rangankar static int qla4xxx_get_boot_info(struct scsi_qla_host *ha) 38132a991c21SManish Rangankar { 38142a991c21SManish Rangankar uint16_t ddb_index[2]; 38158de5b958SLalit Chandivade int ret = QLA_ERROR; 38168de5b958SLalit Chandivade int rval; 38172a991c21SManish Rangankar 38182a991c21SManish Rangankar memset(ddb_index, 0, sizeof(ddb_index)); 38198de5b958SLalit Chandivade ddb_index[0] = 0xffff; 38208de5b958SLalit Chandivade ddb_index[1] = 0xffff; 38212a991c21SManish Rangankar ret = get_fw_boot_info(ha, ddb_index); 38222a991c21SManish Rangankar if (ret != QLA_SUCCESS) { 3823e8fb00e0SManish Rangankar DEBUG2(ql4_printk(KERN_INFO, ha, 3824e8fb00e0SManish Rangankar "%s: No boot target configured.\n", __func__)); 38252a991c21SManish Rangankar return ret; 38262a991c21SManish Rangankar } 38272a991c21SManish Rangankar 382813483730SMike Christie if (ql4xdisablesysfsboot) 382913483730SMike Christie return QLA_SUCCESS; 383013483730SMike Christie 38318de5b958SLalit Chandivade if (ddb_index[0] == 0xffff) 38328de5b958SLalit Chandivade goto sec_target; 38338de5b958SLalit Chandivade 38348de5b958SLalit Chandivade rval = qla4xxx_get_boot_target(ha, &(ha->boot_tgt.boot_pri_sess), 38352a991c21SManish Rangankar ddb_index[0]); 38368de5b958SLalit Chandivade if (rval != QLA_SUCCESS) { 3837e8fb00e0SManish Rangankar DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Primary boot target not " 3838e8fb00e0SManish Rangankar "configured\n", __func__)); 38398de5b958SLalit Chandivade } else 38408de5b958SLalit Chandivade ret = QLA_SUCCESS; 38412a991c21SManish Rangankar 38428de5b958SLalit Chandivade sec_target: 38438de5b958SLalit Chandivade if (ddb_index[1] == 0xffff) 38448de5b958SLalit Chandivade goto exit_get_boot_info; 38458de5b958SLalit Chandivade 38468de5b958SLalit Chandivade rval = qla4xxx_get_boot_target(ha, &(ha->boot_tgt.boot_sec_sess), 38472a991c21SManish Rangankar ddb_index[1]); 38488de5b958SLalit Chandivade if (rval != QLA_SUCCESS) { 3849e8fb00e0SManish Rangankar DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Secondary boot target not" 3850e8fb00e0SManish Rangankar " configured\n", __func__)); 38518de5b958SLalit Chandivade } else 38528de5b958SLalit Chandivade ret = QLA_SUCCESS; 38538de5b958SLalit Chandivade 38548de5b958SLalit Chandivade exit_get_boot_info: 38552a991c21SManish Rangankar return ret; 38562a991c21SManish Rangankar } 38572a991c21SManish Rangankar 38582a991c21SManish Rangankar static int qla4xxx_setup_boot_info(struct scsi_qla_host *ha) 38592a991c21SManish Rangankar { 38602a991c21SManish Rangankar struct iscsi_boot_kobj *boot_kobj; 38612a991c21SManish Rangankar 38622a991c21SManish Rangankar if (qla4xxx_get_boot_info(ha) != QLA_SUCCESS) 386313483730SMike Christie return QLA_ERROR; 386413483730SMike Christie 386513483730SMike Christie if (ql4xdisablesysfsboot) { 386613483730SMike Christie ql4_printk(KERN_INFO, ha, 386713483730SMike Christie "%s: syfsboot disabled - driver will trigger login" 386813483730SMike Christie "and publish session for discovery .\n", __func__); 386913483730SMike Christie return QLA_SUCCESS; 387013483730SMike Christie } 387113483730SMike Christie 38722a991c21SManish Rangankar 38732a991c21SManish Rangankar ha->boot_kset = iscsi_boot_create_host_kset(ha->host->host_no); 38742a991c21SManish Rangankar if (!ha->boot_kset) 38752a991c21SManish Rangankar goto kset_free; 38762a991c21SManish Rangankar 38772a991c21SManish Rangankar if (!scsi_host_get(ha->host)) 38782a991c21SManish Rangankar goto kset_free; 38792a991c21SManish Rangankar boot_kobj = iscsi_boot_create_target(ha->boot_kset, 0, ha, 38802a991c21SManish Rangankar qla4xxx_show_boot_tgt_pri_info, 38812a991c21SManish Rangankar qla4xxx_tgt_get_attr_visibility, 38822a991c21SManish Rangankar qla4xxx_boot_release); 38832a991c21SManish Rangankar if (!boot_kobj) 38842a991c21SManish Rangankar goto put_host; 38852a991c21SManish Rangankar 38862a991c21SManish Rangankar if (!scsi_host_get(ha->host)) 38872a991c21SManish Rangankar goto kset_free; 38882a991c21SManish Rangankar boot_kobj = iscsi_boot_create_target(ha->boot_kset, 1, ha, 38892a991c21SManish Rangankar qla4xxx_show_boot_tgt_sec_info, 38902a991c21SManish Rangankar qla4xxx_tgt_get_attr_visibility, 38912a991c21SManish Rangankar qla4xxx_boot_release); 38922a991c21SManish Rangankar if (!boot_kobj) 38932a991c21SManish Rangankar goto put_host; 38942a991c21SManish Rangankar 38952a991c21SManish Rangankar if (!scsi_host_get(ha->host)) 38962a991c21SManish Rangankar goto kset_free; 38972a991c21SManish Rangankar boot_kobj = iscsi_boot_create_initiator(ha->boot_kset, 0, ha, 38982a991c21SManish Rangankar qla4xxx_show_boot_ini_info, 38992a991c21SManish Rangankar qla4xxx_ini_get_attr_visibility, 39002a991c21SManish Rangankar qla4xxx_boot_release); 39012a991c21SManish Rangankar if (!boot_kobj) 39022a991c21SManish Rangankar goto put_host; 39032a991c21SManish Rangankar 39042a991c21SManish Rangankar if (!scsi_host_get(ha->host)) 39052a991c21SManish Rangankar goto kset_free; 39062a991c21SManish Rangankar boot_kobj = iscsi_boot_create_ethernet(ha->boot_kset, 0, ha, 39072a991c21SManish Rangankar qla4xxx_show_boot_eth_info, 39082a991c21SManish Rangankar qla4xxx_eth_get_attr_visibility, 39092a991c21SManish Rangankar qla4xxx_boot_release); 39102a991c21SManish Rangankar if (!boot_kobj) 39112a991c21SManish Rangankar goto put_host; 39122a991c21SManish Rangankar 391313483730SMike Christie return QLA_SUCCESS; 39142a991c21SManish Rangankar 39152a991c21SManish Rangankar put_host: 39162a991c21SManish Rangankar scsi_host_put(ha->host); 39172a991c21SManish Rangankar kset_free: 39182a991c21SManish Rangankar iscsi_boot_destroy_kset(ha->boot_kset); 39192a991c21SManish Rangankar return -ENOMEM; 39202a991c21SManish Rangankar } 39212a991c21SManish Rangankar 39224549415aSLalit Chandivade 39234549415aSLalit Chandivade /** 39244549415aSLalit Chandivade * qla4xxx_create chap_list - Create CHAP list from FLASH 39254549415aSLalit Chandivade * @ha: pointer to adapter structure 39264549415aSLalit Chandivade * 39274549415aSLalit Chandivade * Read flash and make a list of CHAP entries, during login when a CHAP entry 39284549415aSLalit Chandivade * is received, it will be checked in this list. If entry exist then the CHAP 39294549415aSLalit Chandivade * entry index is set in the DDB. If CHAP entry does not exist in this list 39304549415aSLalit Chandivade * then a new entry is added in FLASH in CHAP table and the index obtained is 39314549415aSLalit Chandivade * used in the DDB. 39324549415aSLalit Chandivade **/ 39334549415aSLalit Chandivade static void qla4xxx_create_chap_list(struct scsi_qla_host *ha) 39344549415aSLalit Chandivade { 39354549415aSLalit Chandivade int rval = 0; 39364549415aSLalit Chandivade uint8_t *chap_flash_data = NULL; 39374549415aSLalit Chandivade uint32_t offset; 39384549415aSLalit Chandivade dma_addr_t chap_dma; 39394549415aSLalit Chandivade uint32_t chap_size = 0; 39404549415aSLalit Chandivade 39414549415aSLalit Chandivade if (is_qla40XX(ha)) 39424549415aSLalit Chandivade chap_size = MAX_CHAP_ENTRIES_40XX * 39434549415aSLalit Chandivade sizeof(struct ql4_chap_table); 39444549415aSLalit Chandivade else /* Single region contains CHAP info for both 39454549415aSLalit Chandivade * ports which is divided into half for each port. 39464549415aSLalit Chandivade */ 39474549415aSLalit Chandivade chap_size = ha->hw.flt_chap_size / 2; 39484549415aSLalit Chandivade 39494549415aSLalit Chandivade chap_flash_data = dma_alloc_coherent(&ha->pdev->dev, chap_size, 39504549415aSLalit Chandivade &chap_dma, GFP_KERNEL); 39514549415aSLalit Chandivade if (!chap_flash_data) { 39524549415aSLalit Chandivade ql4_printk(KERN_ERR, ha, "No memory for chap_flash_data\n"); 39534549415aSLalit Chandivade return; 39544549415aSLalit Chandivade } 39554549415aSLalit Chandivade if (is_qla40XX(ha)) 39564549415aSLalit Chandivade offset = FLASH_CHAP_OFFSET; 39574549415aSLalit Chandivade else { 39584549415aSLalit Chandivade offset = FLASH_RAW_ACCESS_ADDR + (ha->hw.flt_region_chap << 2); 39594549415aSLalit Chandivade if (ha->port_num == 1) 39604549415aSLalit Chandivade offset += chap_size; 39614549415aSLalit Chandivade } 39624549415aSLalit Chandivade 39634549415aSLalit Chandivade rval = qla4xxx_get_flash(ha, chap_dma, offset, chap_size); 39644549415aSLalit Chandivade if (rval != QLA_SUCCESS) 39654549415aSLalit Chandivade goto exit_chap_list; 39664549415aSLalit Chandivade 39674549415aSLalit Chandivade if (ha->chap_list == NULL) 39684549415aSLalit Chandivade ha->chap_list = vmalloc(chap_size); 39694549415aSLalit Chandivade if (ha->chap_list == NULL) { 39704549415aSLalit Chandivade ql4_printk(KERN_ERR, ha, "No memory for ha->chap_list\n"); 39714549415aSLalit Chandivade goto exit_chap_list; 39724549415aSLalit Chandivade } 39734549415aSLalit Chandivade 39744549415aSLalit Chandivade memcpy(ha->chap_list, chap_flash_data, chap_size); 39754549415aSLalit Chandivade 39764549415aSLalit Chandivade exit_chap_list: 39774549415aSLalit Chandivade dma_free_coherent(&ha->pdev->dev, chap_size, 39784549415aSLalit Chandivade chap_flash_data, chap_dma); 397913483730SMike Christie } 398013483730SMike Christie 398113483730SMike Christie static void qla4xxx_get_param_ddb(struct ddb_entry *ddb_entry, 398213483730SMike Christie struct ql4_tuple_ddb *tddb) 398313483730SMike Christie { 398413483730SMike Christie struct scsi_qla_host *ha; 398513483730SMike Christie struct iscsi_cls_session *cls_sess; 398613483730SMike Christie struct iscsi_cls_conn *cls_conn; 398713483730SMike Christie struct iscsi_session *sess; 398813483730SMike Christie struct iscsi_conn *conn; 398913483730SMike Christie 399013483730SMike Christie DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); 399113483730SMike Christie ha = ddb_entry->ha; 399213483730SMike Christie cls_sess = ddb_entry->sess; 399313483730SMike Christie sess = cls_sess->dd_data; 399413483730SMike Christie cls_conn = ddb_entry->conn; 399513483730SMike Christie conn = cls_conn->dd_data; 399613483730SMike Christie 399713483730SMike Christie tddb->tpgt = sess->tpgt; 399813483730SMike Christie tddb->port = conn->persistent_port; 399913483730SMike Christie strncpy(tddb->iscsi_name, sess->targetname, ISCSI_NAME_SIZE); 400013483730SMike Christie strncpy(tddb->ip_addr, conn->persistent_address, DDB_IPADDR_LEN); 400113483730SMike Christie } 400213483730SMike Christie 400313483730SMike Christie static void qla4xxx_convert_param_ddb(struct dev_db_entry *fw_ddb_entry, 400413483730SMike Christie struct ql4_tuple_ddb *tddb) 400513483730SMike Christie { 400613483730SMike Christie uint16_t options = 0; 400713483730SMike Christie 400813483730SMike Christie tddb->tpgt = le32_to_cpu(fw_ddb_entry->tgt_portal_grp); 400913483730SMike Christie memcpy(&tddb->iscsi_name[0], &fw_ddb_entry->iscsi_name[0], 401013483730SMike Christie min(sizeof(tddb->iscsi_name), sizeof(fw_ddb_entry->iscsi_name))); 401113483730SMike Christie 401213483730SMike Christie options = le16_to_cpu(fw_ddb_entry->options); 401313483730SMike Christie if (options & DDB_OPT_IPV6_DEVICE) 401413483730SMike Christie sprintf(tddb->ip_addr, "%pI6", fw_ddb_entry->ip_addr); 401513483730SMike Christie else 401613483730SMike Christie sprintf(tddb->ip_addr, "%pI4", fw_ddb_entry->ip_addr); 401713483730SMike Christie 401813483730SMike Christie tddb->port = le16_to_cpu(fw_ddb_entry->port); 401913483730SMike Christie } 402013483730SMike Christie 402113483730SMike Christie static int qla4xxx_compare_tuple_ddb(struct scsi_qla_host *ha, 402213483730SMike Christie struct ql4_tuple_ddb *old_tddb, 402313483730SMike Christie struct ql4_tuple_ddb *new_tddb) 402413483730SMike Christie { 402513483730SMike Christie if (strcmp(old_tddb->iscsi_name, new_tddb->iscsi_name)) 402613483730SMike Christie return QLA_ERROR; 402713483730SMike Christie 402813483730SMike Christie if (strcmp(old_tddb->ip_addr, new_tddb->ip_addr)) 402913483730SMike Christie return QLA_ERROR; 403013483730SMike Christie 403113483730SMike Christie if (old_tddb->port != new_tddb->port) 403213483730SMike Christie return QLA_ERROR; 403313483730SMike Christie 403413483730SMike Christie DEBUG2(ql4_printk(KERN_INFO, ha, 403513483730SMike Christie "Match Found, fw[%d,%d,%s,%s], [%d,%d,%s,%s]", 403613483730SMike Christie old_tddb->port, old_tddb->tpgt, old_tddb->ip_addr, 403713483730SMike Christie old_tddb->iscsi_name, new_tddb->port, new_tddb->tpgt, 403813483730SMike Christie new_tddb->ip_addr, new_tddb->iscsi_name)); 403913483730SMike Christie 404013483730SMike Christie return QLA_SUCCESS; 404113483730SMike Christie } 404213483730SMike Christie 404313483730SMike Christie static int qla4xxx_is_session_exists(struct scsi_qla_host *ha, 404413483730SMike Christie struct dev_db_entry *fw_ddb_entry) 404513483730SMike Christie { 404613483730SMike Christie struct ddb_entry *ddb_entry; 404713483730SMike Christie struct ql4_tuple_ddb *fw_tddb = NULL; 404813483730SMike Christie struct ql4_tuple_ddb *tmp_tddb = NULL; 404913483730SMike Christie int idx; 405013483730SMike Christie int ret = QLA_ERROR; 405113483730SMike Christie 405213483730SMike Christie fw_tddb = vzalloc(sizeof(*fw_tddb)); 405313483730SMike Christie if (!fw_tddb) { 405413483730SMike Christie DEBUG2(ql4_printk(KERN_WARNING, ha, 405513483730SMike Christie "Memory Allocation failed.\n")); 405613483730SMike Christie ret = QLA_SUCCESS; 405713483730SMike Christie goto exit_check; 405813483730SMike Christie } 405913483730SMike Christie 406013483730SMike Christie tmp_tddb = vzalloc(sizeof(*tmp_tddb)); 406113483730SMike Christie if (!tmp_tddb) { 406213483730SMike Christie DEBUG2(ql4_printk(KERN_WARNING, ha, 406313483730SMike Christie "Memory Allocation failed.\n")); 406413483730SMike Christie ret = QLA_SUCCESS; 406513483730SMike Christie goto exit_check; 406613483730SMike Christie } 406713483730SMike Christie 406813483730SMike Christie qla4xxx_convert_param_ddb(fw_ddb_entry, fw_tddb); 406913483730SMike Christie 407013483730SMike Christie for (idx = 0; idx < MAX_DDB_ENTRIES; idx++) { 407113483730SMike Christie ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx); 407213483730SMike Christie if (ddb_entry == NULL) 407313483730SMike Christie continue; 407413483730SMike Christie 407513483730SMike Christie qla4xxx_get_param_ddb(ddb_entry, tmp_tddb); 407613483730SMike Christie if (!qla4xxx_compare_tuple_ddb(ha, fw_tddb, tmp_tddb)) { 407713483730SMike Christie ret = QLA_SUCCESS; /* found */ 407813483730SMike Christie goto exit_check; 407913483730SMike Christie } 408013483730SMike Christie } 408113483730SMike Christie 408213483730SMike Christie exit_check: 408313483730SMike Christie if (fw_tddb) 408413483730SMike Christie vfree(fw_tddb); 408513483730SMike Christie if (tmp_tddb) 408613483730SMike Christie vfree(tmp_tddb); 408713483730SMike Christie return ret; 408813483730SMike Christie } 408913483730SMike Christie 409013483730SMike Christie static int qla4xxx_is_flash_ddb_exists(struct scsi_qla_host *ha, 409113483730SMike Christie struct list_head *list_nt, 409213483730SMike Christie struct dev_db_entry *fw_ddb_entry) 409313483730SMike Christie { 409413483730SMike Christie struct qla_ddb_index *nt_ddb_idx, *nt_ddb_idx_tmp; 409513483730SMike Christie struct ql4_tuple_ddb *fw_tddb = NULL; 409613483730SMike Christie struct ql4_tuple_ddb *tmp_tddb = NULL; 409713483730SMike Christie int ret = QLA_ERROR; 409813483730SMike Christie 409913483730SMike Christie fw_tddb = vzalloc(sizeof(*fw_tddb)); 410013483730SMike Christie if (!fw_tddb) { 410113483730SMike Christie DEBUG2(ql4_printk(KERN_WARNING, ha, 410213483730SMike Christie "Memory Allocation failed.\n")); 410313483730SMike Christie ret = QLA_SUCCESS; 410413483730SMike Christie goto exit_check; 410513483730SMike Christie } 410613483730SMike Christie 410713483730SMike Christie tmp_tddb = vzalloc(sizeof(*tmp_tddb)); 410813483730SMike Christie if (!tmp_tddb) { 410913483730SMike Christie DEBUG2(ql4_printk(KERN_WARNING, ha, 411013483730SMike Christie "Memory Allocation failed.\n")); 411113483730SMike Christie ret = QLA_SUCCESS; 411213483730SMike Christie goto exit_check; 411313483730SMike Christie } 411413483730SMike Christie 411513483730SMike Christie qla4xxx_convert_param_ddb(fw_ddb_entry, fw_tddb); 411613483730SMike Christie 411713483730SMike Christie list_for_each_entry_safe(nt_ddb_idx, nt_ddb_idx_tmp, list_nt, list) { 411813483730SMike Christie qla4xxx_convert_param_ddb(&nt_ddb_idx->fw_ddb, tmp_tddb); 411913483730SMike Christie if (!qla4xxx_compare_tuple_ddb(ha, fw_tddb, tmp_tddb)) { 412013483730SMike Christie ret = QLA_SUCCESS; /* found */ 412113483730SMike Christie goto exit_check; 412213483730SMike Christie } 412313483730SMike Christie } 412413483730SMike Christie 412513483730SMike Christie exit_check: 412613483730SMike Christie if (fw_tddb) 412713483730SMike Christie vfree(fw_tddb); 412813483730SMike Christie if (tmp_tddb) 412913483730SMike Christie vfree(tmp_tddb); 413013483730SMike Christie return ret; 413113483730SMike Christie } 413213483730SMike Christie 41334a4bc2e9SLalit Chandivade static void qla4xxx_free_ddb_list(struct list_head *list_ddb) 413413483730SMike Christie { 41354a4bc2e9SLalit Chandivade struct qla_ddb_index *ddb_idx, *ddb_idx_tmp; 413613483730SMike Christie 41374a4bc2e9SLalit Chandivade list_for_each_entry_safe(ddb_idx, ddb_idx_tmp, list_ddb, list) { 41384a4bc2e9SLalit Chandivade list_del_init(&ddb_idx->list); 41394a4bc2e9SLalit Chandivade vfree(ddb_idx); 414013483730SMike Christie } 414113483730SMike Christie } 414213483730SMike Christie 414313483730SMike Christie static struct iscsi_endpoint *qla4xxx_get_ep_fwdb(struct scsi_qla_host *ha, 414413483730SMike Christie struct dev_db_entry *fw_ddb_entry) 414513483730SMike Christie { 414613483730SMike Christie struct iscsi_endpoint *ep; 414713483730SMike Christie struct sockaddr_in *addr; 414813483730SMike Christie struct sockaddr_in6 *addr6; 414913483730SMike Christie struct sockaddr *dst_addr; 415013483730SMike Christie char *ip; 415113483730SMike Christie 415213483730SMike Christie /* TODO: need to destroy on unload iscsi_endpoint*/ 415313483730SMike Christie dst_addr = vmalloc(sizeof(*dst_addr)); 415413483730SMike Christie if (!dst_addr) 415513483730SMike Christie return NULL; 415613483730SMike Christie 415713483730SMike Christie if (fw_ddb_entry->options & DDB_OPT_IPV6_DEVICE) { 415813483730SMike Christie dst_addr->sa_family = AF_INET6; 415913483730SMike Christie addr6 = (struct sockaddr_in6 *)dst_addr; 416013483730SMike Christie ip = (char *)&addr6->sin6_addr; 416113483730SMike Christie memcpy(ip, fw_ddb_entry->ip_addr, IPv6_ADDR_LEN); 416213483730SMike Christie addr6->sin6_port = htons(le16_to_cpu(fw_ddb_entry->port)); 416313483730SMike Christie 416413483730SMike Christie } else { 416513483730SMike Christie dst_addr->sa_family = AF_INET; 416613483730SMike Christie addr = (struct sockaddr_in *)dst_addr; 416713483730SMike Christie ip = (char *)&addr->sin_addr; 416813483730SMike Christie memcpy(ip, fw_ddb_entry->ip_addr, IP_ADDR_LEN); 416913483730SMike Christie addr->sin_port = htons(le16_to_cpu(fw_ddb_entry->port)); 417013483730SMike Christie } 417113483730SMike Christie 417213483730SMike Christie ep = qla4xxx_ep_connect(ha->host, dst_addr, 0); 417313483730SMike Christie vfree(dst_addr); 417413483730SMike Christie return ep; 417513483730SMike Christie } 417613483730SMike Christie 417713483730SMike Christie static int qla4xxx_verify_boot_idx(struct scsi_qla_host *ha, uint16_t idx) 417813483730SMike Christie { 417913483730SMike Christie if (ql4xdisablesysfsboot) 418013483730SMike Christie return QLA_SUCCESS; 418113483730SMike Christie if (idx == ha->pri_ddb_idx || idx == ha->sec_ddb_idx) 418213483730SMike Christie return QLA_ERROR; 418313483730SMike Christie return QLA_SUCCESS; 418413483730SMike Christie } 418513483730SMike Christie 418613483730SMike Christie static void qla4xxx_setup_flash_ddb_entry(struct scsi_qla_host *ha, 418713483730SMike Christie struct ddb_entry *ddb_entry) 418813483730SMike Christie { 4189c28eaacaSNilesh Javali uint16_t def_timeout; 4190c28eaacaSNilesh Javali 419113483730SMike Christie ddb_entry->ddb_type = FLASH_DDB; 419213483730SMike Christie ddb_entry->fw_ddb_index = INVALID_ENTRY; 419313483730SMike Christie ddb_entry->fw_ddb_device_state = DDB_DS_NO_CONNECTION_ACTIVE; 419413483730SMike Christie ddb_entry->ha = ha; 419513483730SMike Christie ddb_entry->unblock_sess = qla4xxx_unblock_flash_ddb; 419613483730SMike Christie ddb_entry->ddb_change = qla4xxx_flash_ddb_change; 419713483730SMike Christie 419813483730SMike Christie atomic_set(&ddb_entry->retry_relogin_timer, INVALID_ENTRY); 419913483730SMike Christie atomic_set(&ddb_entry->relogin_timer, 0); 420013483730SMike Christie atomic_set(&ddb_entry->relogin_retry_count, 0); 4201c28eaacaSNilesh Javali def_timeout = le16_to_cpu(ddb_entry->fw_ddb_entry.def_timeout); 420213483730SMike Christie ddb_entry->default_relogin_timeout = 4203c28eaacaSNilesh Javali (def_timeout > LOGIN_TOV) && (def_timeout < LOGIN_TOV * 10) ? 4204c28eaacaSNilesh Javali def_timeout : LOGIN_TOV; 420513483730SMike Christie ddb_entry->default_time2wait = 420613483730SMike Christie le16_to_cpu(ddb_entry->fw_ddb_entry.iscsi_def_time2wait); 420713483730SMike Christie } 420813483730SMike Christie 420913483730SMike Christie static void qla4xxx_wait_for_ip_configuration(struct scsi_qla_host *ha) 421013483730SMike Christie { 421113483730SMike Christie uint32_t idx = 0; 421213483730SMike Christie uint32_t ip_idx[IP_ADDR_COUNT] = {0, 1, 2, 3}; /* 4 IP interfaces */ 421313483730SMike Christie uint32_t sts[MBOX_REG_COUNT]; 421413483730SMike Christie uint32_t ip_state; 421513483730SMike Christie unsigned long wtime; 421613483730SMike Christie int ret; 421713483730SMike Christie 421813483730SMike Christie wtime = jiffies + (HZ * IP_CONFIG_TOV); 421913483730SMike Christie do { 422013483730SMike Christie for (idx = 0; idx < IP_ADDR_COUNT; idx++) { 422113483730SMike Christie if (ip_idx[idx] == -1) 422213483730SMike Christie continue; 422313483730SMike Christie 422413483730SMike Christie ret = qla4xxx_get_ip_state(ha, 0, ip_idx[idx], sts); 422513483730SMike Christie 422613483730SMike Christie if (ret == QLA_ERROR) { 422713483730SMike Christie ip_idx[idx] = -1; 422813483730SMike Christie continue; 422913483730SMike Christie } 423013483730SMike Christie 423113483730SMike Christie ip_state = (sts[1] & IP_STATE_MASK) >> IP_STATE_SHIFT; 423213483730SMike Christie 423313483730SMike Christie DEBUG2(ql4_printk(KERN_INFO, ha, 423413483730SMike Christie "Waiting for IP state for idx = %d, state = 0x%x\n", 423513483730SMike Christie ip_idx[idx], ip_state)); 423613483730SMike Christie if (ip_state == IP_ADDRSTATE_UNCONFIGURED || 423713483730SMike Christie ip_state == IP_ADDRSTATE_INVALID || 423813483730SMike Christie ip_state == IP_ADDRSTATE_PREFERRED || 423913483730SMike Christie ip_state == IP_ADDRSTATE_DEPRICATED || 424013483730SMike Christie ip_state == IP_ADDRSTATE_DISABLING) 424113483730SMike Christie ip_idx[idx] = -1; 424213483730SMike Christie } 424313483730SMike Christie 424413483730SMike Christie /* Break if all IP states checked */ 424513483730SMike Christie if ((ip_idx[0] == -1) && 424613483730SMike Christie (ip_idx[1] == -1) && 424713483730SMike Christie (ip_idx[2] == -1) && 424813483730SMike Christie (ip_idx[3] == -1)) 424913483730SMike Christie break; 425013483730SMike Christie schedule_timeout_uninterruptible(HZ); 425113483730SMike Christie } while (time_after(wtime, jiffies)); 425213483730SMike Christie } 425313483730SMike Christie 42544a4bc2e9SLalit Chandivade static void qla4xxx_build_st_list(struct scsi_qla_host *ha, 42554a4bc2e9SLalit Chandivade struct list_head *list_st) 425613483730SMike Christie { 42574a4bc2e9SLalit Chandivade struct qla_ddb_index *st_ddb_idx; 425813483730SMike Christie int max_ddbs; 42594a4bc2e9SLalit Chandivade int fw_idx_size; 42604a4bc2e9SLalit Chandivade struct dev_db_entry *fw_ddb_entry; 42614a4bc2e9SLalit Chandivade dma_addr_t fw_ddb_dma; 426213483730SMike Christie int ret; 426313483730SMike Christie uint32_t idx = 0, next_idx = 0; 426413483730SMike Christie uint32_t state = 0, conn_err = 0; 42654a4bc2e9SLalit Chandivade uint16_t conn_id = 0; 426613483730SMike Christie 426713483730SMike Christie fw_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL, 426813483730SMike Christie &fw_ddb_dma); 426913483730SMike Christie if (fw_ddb_entry == NULL) { 427013483730SMike Christie DEBUG2(ql4_printk(KERN_ERR, ha, "Out of memory\n")); 42714a4bc2e9SLalit Chandivade goto exit_st_list; 427213483730SMike Christie } 427313483730SMike Christie 42744a4bc2e9SLalit Chandivade max_ddbs = is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX : 42754a4bc2e9SLalit Chandivade MAX_DEV_DB_ENTRIES; 427613483730SMike Christie fw_idx_size = sizeof(struct qla_ddb_index); 427713483730SMike Christie 427813483730SMike Christie for (idx = 0; idx < max_ddbs; idx = next_idx) { 42794a4bc2e9SLalit Chandivade ret = qla4xxx_get_fwddb_entry(ha, idx, fw_ddb_entry, fw_ddb_dma, 42804a4bc2e9SLalit Chandivade NULL, &next_idx, &state, 42814a4bc2e9SLalit Chandivade &conn_err, NULL, &conn_id); 428213483730SMike Christie if (ret == QLA_ERROR) 428313483730SMike Christie break; 428413483730SMike Christie 4285981c982cSLalit Chandivade /* Ignore DDB if invalid state (unassigned) */ 4286981c982cSLalit Chandivade if (state == DDB_DS_UNASSIGNED) 4287981c982cSLalit Chandivade goto continue_next_st; 4288981c982cSLalit Chandivade 428913483730SMike Christie /* Check if ST, add to the list_st */ 429013483730SMike Christie if (strlen((char *) fw_ddb_entry->iscsi_name) != 0) 429113483730SMike Christie goto continue_next_st; 429213483730SMike Christie 429313483730SMike Christie st_ddb_idx = vzalloc(fw_idx_size); 429413483730SMike Christie if (!st_ddb_idx) 429513483730SMike Christie break; 429613483730SMike Christie 429713483730SMike Christie st_ddb_idx->fw_ddb_idx = idx; 429813483730SMike Christie 42994a4bc2e9SLalit Chandivade list_add_tail(&st_ddb_idx->list, list_st); 430013483730SMike Christie continue_next_st: 430113483730SMike Christie if (next_idx == 0) 430213483730SMike Christie break; 430313483730SMike Christie } 430413483730SMike Christie 43054a4bc2e9SLalit Chandivade exit_st_list: 43064a4bc2e9SLalit Chandivade if (fw_ddb_entry) 43074a4bc2e9SLalit Chandivade dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma); 43084a4bc2e9SLalit Chandivade } 43094a4bc2e9SLalit Chandivade 43104a4bc2e9SLalit Chandivade /** 43114a4bc2e9SLalit Chandivade * qla4xxx_remove_failed_ddb - Remove inactive or failed ddb from list 43124a4bc2e9SLalit Chandivade * @ha: pointer to adapter structure 43134a4bc2e9SLalit Chandivade * @list_ddb: List from which failed ddb to be removed 43144a4bc2e9SLalit Chandivade * 43154a4bc2e9SLalit Chandivade * Iterate over the list of DDBs and find and remove DDBs that are either in 43164a4bc2e9SLalit Chandivade * no connection active state or failed state 43174a4bc2e9SLalit Chandivade **/ 43184a4bc2e9SLalit Chandivade static void qla4xxx_remove_failed_ddb(struct scsi_qla_host *ha, 43194a4bc2e9SLalit Chandivade struct list_head *list_ddb) 43204a4bc2e9SLalit Chandivade { 43214a4bc2e9SLalit Chandivade struct qla_ddb_index *ddb_idx, *ddb_idx_tmp; 43224a4bc2e9SLalit Chandivade uint32_t next_idx = 0; 43234a4bc2e9SLalit Chandivade uint32_t state = 0, conn_err = 0; 43244a4bc2e9SLalit Chandivade int ret; 43254a4bc2e9SLalit Chandivade 43264a4bc2e9SLalit Chandivade list_for_each_entry_safe(ddb_idx, ddb_idx_tmp, list_ddb, list) { 43274a4bc2e9SLalit Chandivade ret = qla4xxx_get_fwddb_entry(ha, ddb_idx->fw_ddb_idx, 43284a4bc2e9SLalit Chandivade NULL, 0, NULL, &next_idx, &state, 43294a4bc2e9SLalit Chandivade &conn_err, NULL, NULL); 43304a4bc2e9SLalit Chandivade if (ret == QLA_ERROR) 43314a4bc2e9SLalit Chandivade continue; 43324a4bc2e9SLalit Chandivade 43334a4bc2e9SLalit Chandivade if (state == DDB_DS_NO_CONNECTION_ACTIVE || 43344a4bc2e9SLalit Chandivade state == DDB_DS_SESSION_FAILED) { 43354a4bc2e9SLalit Chandivade list_del_init(&ddb_idx->list); 43364a4bc2e9SLalit Chandivade vfree(ddb_idx); 43374a4bc2e9SLalit Chandivade } 43384a4bc2e9SLalit Chandivade } 43394a4bc2e9SLalit Chandivade } 43404a4bc2e9SLalit Chandivade 43414a4bc2e9SLalit Chandivade static int qla4xxx_sess_conn_setup(struct scsi_qla_host *ha, 43424a4bc2e9SLalit Chandivade struct dev_db_entry *fw_ddb_entry, 43434a4bc2e9SLalit Chandivade int is_reset) 43444a4bc2e9SLalit Chandivade { 43454a4bc2e9SLalit Chandivade struct iscsi_cls_session *cls_sess; 43464a4bc2e9SLalit Chandivade struct iscsi_session *sess; 43474a4bc2e9SLalit Chandivade struct iscsi_cls_conn *cls_conn; 43484a4bc2e9SLalit Chandivade struct iscsi_endpoint *ep; 43494a4bc2e9SLalit Chandivade uint16_t cmds_max = 32; 43504a4bc2e9SLalit Chandivade uint16_t conn_id = 0; 43514a4bc2e9SLalit Chandivade uint32_t initial_cmdsn = 0; 43524a4bc2e9SLalit Chandivade int ret = QLA_SUCCESS; 43534a4bc2e9SLalit Chandivade 43544a4bc2e9SLalit Chandivade struct ddb_entry *ddb_entry = NULL; 43554a4bc2e9SLalit Chandivade 43564a4bc2e9SLalit Chandivade /* Create session object, with INVALID_ENTRY, 43574a4bc2e9SLalit Chandivade * the targer_id would get set when we issue the login 43584a4bc2e9SLalit Chandivade */ 43594a4bc2e9SLalit Chandivade cls_sess = iscsi_session_setup(&qla4xxx_iscsi_transport, ha->host, 43604a4bc2e9SLalit Chandivade cmds_max, sizeof(struct ddb_entry), 43614a4bc2e9SLalit Chandivade sizeof(struct ql4_task_data), 43624a4bc2e9SLalit Chandivade initial_cmdsn, INVALID_ENTRY); 43634a4bc2e9SLalit Chandivade if (!cls_sess) { 43644a4bc2e9SLalit Chandivade ret = QLA_ERROR; 43654a4bc2e9SLalit Chandivade goto exit_setup; 43664a4bc2e9SLalit Chandivade } 43674a4bc2e9SLalit Chandivade 43684a4bc2e9SLalit Chandivade /* 43694a4bc2e9SLalit Chandivade * so calling module_put function to decrement the 43704a4bc2e9SLalit Chandivade * reference count. 43714a4bc2e9SLalit Chandivade **/ 43724a4bc2e9SLalit Chandivade module_put(qla4xxx_iscsi_transport.owner); 43734a4bc2e9SLalit Chandivade sess = cls_sess->dd_data; 43744a4bc2e9SLalit Chandivade ddb_entry = sess->dd_data; 43754a4bc2e9SLalit Chandivade ddb_entry->sess = cls_sess; 43764a4bc2e9SLalit Chandivade 43774a4bc2e9SLalit Chandivade cls_sess->recovery_tmo = ql4xsess_recovery_tmo; 43784a4bc2e9SLalit Chandivade memcpy(&ddb_entry->fw_ddb_entry, fw_ddb_entry, 43794a4bc2e9SLalit Chandivade sizeof(struct dev_db_entry)); 43804a4bc2e9SLalit Chandivade 43814a4bc2e9SLalit Chandivade qla4xxx_setup_flash_ddb_entry(ha, ddb_entry); 43824a4bc2e9SLalit Chandivade 43834a4bc2e9SLalit Chandivade cls_conn = iscsi_conn_setup(cls_sess, sizeof(struct qla_conn), conn_id); 43844a4bc2e9SLalit Chandivade 43854a4bc2e9SLalit Chandivade if (!cls_conn) { 43864a4bc2e9SLalit Chandivade ret = QLA_ERROR; 43874a4bc2e9SLalit Chandivade goto exit_setup; 43884a4bc2e9SLalit Chandivade } 43894a4bc2e9SLalit Chandivade 43904a4bc2e9SLalit Chandivade ddb_entry->conn = cls_conn; 43914a4bc2e9SLalit Chandivade 43924a4bc2e9SLalit Chandivade /* Setup ep, for displaying attributes in sysfs */ 43934a4bc2e9SLalit Chandivade ep = qla4xxx_get_ep_fwdb(ha, fw_ddb_entry); 43944a4bc2e9SLalit Chandivade if (ep) { 43954a4bc2e9SLalit Chandivade ep->conn = cls_conn; 43964a4bc2e9SLalit Chandivade cls_conn->ep = ep; 43974a4bc2e9SLalit Chandivade } else { 43984a4bc2e9SLalit Chandivade DEBUG2(ql4_printk(KERN_ERR, ha, "Unable to get ep\n")); 43994a4bc2e9SLalit Chandivade ret = QLA_ERROR; 44004a4bc2e9SLalit Chandivade goto exit_setup; 44014a4bc2e9SLalit Chandivade } 44024a4bc2e9SLalit Chandivade 44034a4bc2e9SLalit Chandivade /* Update sess/conn params */ 44044a4bc2e9SLalit Chandivade qla4xxx_copy_fwddb_param(ha, fw_ddb_entry, cls_sess, cls_conn); 44054a4bc2e9SLalit Chandivade 44064a4bc2e9SLalit Chandivade if (is_reset == RESET_ADAPTER) { 44074a4bc2e9SLalit Chandivade iscsi_block_session(cls_sess); 44084a4bc2e9SLalit Chandivade /* Use the relogin path to discover new devices 44094a4bc2e9SLalit Chandivade * by short-circuting the logic of setting 44104a4bc2e9SLalit Chandivade * timer to relogin - instead set the flags 44114a4bc2e9SLalit Chandivade * to initiate login right away. 44124a4bc2e9SLalit Chandivade */ 44134a4bc2e9SLalit Chandivade set_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags); 44144a4bc2e9SLalit Chandivade set_bit(DF_RELOGIN, &ddb_entry->flags); 44154a4bc2e9SLalit Chandivade } 44164a4bc2e9SLalit Chandivade 44174a4bc2e9SLalit Chandivade exit_setup: 44184a4bc2e9SLalit Chandivade return ret; 44194a4bc2e9SLalit Chandivade } 44204a4bc2e9SLalit Chandivade 44214a4bc2e9SLalit Chandivade static void qla4xxx_build_nt_list(struct scsi_qla_host *ha, 44224a4bc2e9SLalit Chandivade struct list_head *list_nt, int is_reset) 44234a4bc2e9SLalit Chandivade { 44244a4bc2e9SLalit Chandivade struct dev_db_entry *fw_ddb_entry; 44254a4bc2e9SLalit Chandivade dma_addr_t fw_ddb_dma; 44264a4bc2e9SLalit Chandivade int max_ddbs; 44274a4bc2e9SLalit Chandivade int fw_idx_size; 44284a4bc2e9SLalit Chandivade int ret; 44294a4bc2e9SLalit Chandivade uint32_t idx = 0, next_idx = 0; 44304a4bc2e9SLalit Chandivade uint32_t state = 0, conn_err = 0; 44314a4bc2e9SLalit Chandivade uint16_t conn_id = 0; 44324a4bc2e9SLalit Chandivade struct qla_ddb_index *nt_ddb_idx; 44334a4bc2e9SLalit Chandivade 44344a4bc2e9SLalit Chandivade fw_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL, 44354a4bc2e9SLalit Chandivade &fw_ddb_dma); 44364a4bc2e9SLalit Chandivade if (fw_ddb_entry == NULL) { 44374a4bc2e9SLalit Chandivade DEBUG2(ql4_printk(KERN_ERR, ha, "Out of memory\n")); 44384a4bc2e9SLalit Chandivade goto exit_nt_list; 44394a4bc2e9SLalit Chandivade } 44404a4bc2e9SLalit Chandivade max_ddbs = is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX : 44414a4bc2e9SLalit Chandivade MAX_DEV_DB_ENTRIES; 44424a4bc2e9SLalit Chandivade fw_idx_size = sizeof(struct qla_ddb_index); 44434a4bc2e9SLalit Chandivade 44444a4bc2e9SLalit Chandivade for (idx = 0; idx < max_ddbs; idx = next_idx) { 44454a4bc2e9SLalit Chandivade ret = qla4xxx_get_fwddb_entry(ha, idx, fw_ddb_entry, fw_ddb_dma, 44464a4bc2e9SLalit Chandivade NULL, &next_idx, &state, 44474a4bc2e9SLalit Chandivade &conn_err, NULL, &conn_id); 44484a4bc2e9SLalit Chandivade if (ret == QLA_ERROR) 44494a4bc2e9SLalit Chandivade break; 44504a4bc2e9SLalit Chandivade 44514a4bc2e9SLalit Chandivade if (qla4xxx_verify_boot_idx(ha, idx) != QLA_SUCCESS) 44524a4bc2e9SLalit Chandivade goto continue_next_nt; 44534a4bc2e9SLalit Chandivade 44544a4bc2e9SLalit Chandivade /* Check if NT, then add to list it */ 44554a4bc2e9SLalit Chandivade if (strlen((char *) fw_ddb_entry->iscsi_name) == 0) 44564a4bc2e9SLalit Chandivade goto continue_next_nt; 44574a4bc2e9SLalit Chandivade 44584a4bc2e9SLalit Chandivade if (!(state == DDB_DS_NO_CONNECTION_ACTIVE || 44594a4bc2e9SLalit Chandivade state == DDB_DS_SESSION_FAILED)) 44604a4bc2e9SLalit Chandivade goto continue_next_nt; 44614a4bc2e9SLalit Chandivade 44624a4bc2e9SLalit Chandivade DEBUG2(ql4_printk(KERN_INFO, ha, 44634a4bc2e9SLalit Chandivade "Adding DDB to session = 0x%x\n", idx)); 44644a4bc2e9SLalit Chandivade if (is_reset == INIT_ADAPTER) { 44654a4bc2e9SLalit Chandivade nt_ddb_idx = vmalloc(fw_idx_size); 44664a4bc2e9SLalit Chandivade if (!nt_ddb_idx) 44674a4bc2e9SLalit Chandivade break; 44684a4bc2e9SLalit Chandivade 44694a4bc2e9SLalit Chandivade nt_ddb_idx->fw_ddb_idx = idx; 44704a4bc2e9SLalit Chandivade 44714a4bc2e9SLalit Chandivade memcpy(&nt_ddb_idx->fw_ddb, fw_ddb_entry, 44724a4bc2e9SLalit Chandivade sizeof(struct dev_db_entry)); 44734a4bc2e9SLalit Chandivade 44744a4bc2e9SLalit Chandivade if (qla4xxx_is_flash_ddb_exists(ha, list_nt, 44754a4bc2e9SLalit Chandivade fw_ddb_entry) == QLA_SUCCESS) { 44764a4bc2e9SLalit Chandivade vfree(nt_ddb_idx); 44774a4bc2e9SLalit Chandivade goto continue_next_nt; 44784a4bc2e9SLalit Chandivade } 44794a4bc2e9SLalit Chandivade list_add_tail(&nt_ddb_idx->list, list_nt); 44804a4bc2e9SLalit Chandivade } else if (is_reset == RESET_ADAPTER) { 44814a4bc2e9SLalit Chandivade if (qla4xxx_is_session_exists(ha, fw_ddb_entry) == 44824a4bc2e9SLalit Chandivade QLA_SUCCESS) 44834a4bc2e9SLalit Chandivade goto continue_next_nt; 44844a4bc2e9SLalit Chandivade } 44854a4bc2e9SLalit Chandivade 44864a4bc2e9SLalit Chandivade ret = qla4xxx_sess_conn_setup(ha, fw_ddb_entry, is_reset); 44874a4bc2e9SLalit Chandivade if (ret == QLA_ERROR) 44884a4bc2e9SLalit Chandivade goto exit_nt_list; 44894a4bc2e9SLalit Chandivade 44904a4bc2e9SLalit Chandivade continue_next_nt: 44914a4bc2e9SLalit Chandivade if (next_idx == 0) 44924a4bc2e9SLalit Chandivade break; 44934a4bc2e9SLalit Chandivade } 44944a4bc2e9SLalit Chandivade 44954a4bc2e9SLalit Chandivade exit_nt_list: 44964a4bc2e9SLalit Chandivade if (fw_ddb_entry) 44974a4bc2e9SLalit Chandivade dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma); 44984a4bc2e9SLalit Chandivade } 44994a4bc2e9SLalit Chandivade 45004a4bc2e9SLalit Chandivade /** 45014a4bc2e9SLalit Chandivade * qla4xxx_build_ddb_list - Build ddb list and setup sessions 45024a4bc2e9SLalit Chandivade * @ha: pointer to adapter structure 45034a4bc2e9SLalit Chandivade * @is_reset: Is this init path or reset path 45044a4bc2e9SLalit Chandivade * 45054a4bc2e9SLalit Chandivade * Create a list of sendtargets (st) from firmware DDBs, issue send targets 45064a4bc2e9SLalit Chandivade * using connection open, then create the list of normal targets (nt) 45074a4bc2e9SLalit Chandivade * from firmware DDBs. Based on the list of nt setup session and connection 45084a4bc2e9SLalit Chandivade * objects. 45094a4bc2e9SLalit Chandivade **/ 45104a4bc2e9SLalit Chandivade void qla4xxx_build_ddb_list(struct scsi_qla_host *ha, int is_reset) 45114a4bc2e9SLalit Chandivade { 45124a4bc2e9SLalit Chandivade uint16_t tmo = 0; 45134a4bc2e9SLalit Chandivade struct list_head list_st, list_nt; 45144a4bc2e9SLalit Chandivade struct qla_ddb_index *st_ddb_idx, *st_ddb_idx_tmp; 45154a4bc2e9SLalit Chandivade unsigned long wtime; 45164a4bc2e9SLalit Chandivade 45174a4bc2e9SLalit Chandivade if (!test_bit(AF_LINK_UP, &ha->flags)) { 45184a4bc2e9SLalit Chandivade set_bit(AF_BUILD_DDB_LIST, &ha->flags); 45194a4bc2e9SLalit Chandivade ha->is_reset = is_reset; 45204a4bc2e9SLalit Chandivade return; 45214a4bc2e9SLalit Chandivade } 45224a4bc2e9SLalit Chandivade 45234a4bc2e9SLalit Chandivade INIT_LIST_HEAD(&list_st); 45244a4bc2e9SLalit Chandivade INIT_LIST_HEAD(&list_nt); 45254a4bc2e9SLalit Chandivade 45264a4bc2e9SLalit Chandivade qla4xxx_build_st_list(ha, &list_st); 45274a4bc2e9SLalit Chandivade 452813483730SMike Christie /* Before issuing conn open mbox, ensure all IPs states are configured 452913483730SMike Christie * Note, conn open fails if IPs are not configured 453013483730SMike Christie */ 453113483730SMike Christie qla4xxx_wait_for_ip_configuration(ha); 453213483730SMike Christie 453313483730SMike Christie /* Go thru the STs and fire the sendtargets by issuing conn open mbx */ 453413483730SMike Christie list_for_each_entry_safe(st_ddb_idx, st_ddb_idx_tmp, &list_st, list) { 453513483730SMike Christie qla4xxx_conn_open(ha, st_ddb_idx->fw_ddb_idx); 453613483730SMike Christie } 453713483730SMike Christie 453813483730SMike Christie /* Wait to ensure all sendtargets are done for min 12 sec wait */ 4539c28eaacaSNilesh Javali tmo = ((ha->def_timeout > LOGIN_TOV) && 4540c28eaacaSNilesh Javali (ha->def_timeout < LOGIN_TOV * 10) ? 4541c28eaacaSNilesh Javali ha->def_timeout : LOGIN_TOV); 4542c28eaacaSNilesh Javali 454313483730SMike Christie DEBUG2(ql4_printk(KERN_INFO, ha, 454413483730SMike Christie "Default time to wait for build ddb %d\n", tmo)); 454513483730SMike Christie 454613483730SMike Christie wtime = jiffies + (HZ * tmo); 454713483730SMike Christie do { 4548f1f2e60eSNilesh Javali if (list_empty(&list_st)) 4549f1f2e60eSNilesh Javali break; 4550f1f2e60eSNilesh Javali 45514a4bc2e9SLalit Chandivade qla4xxx_remove_failed_ddb(ha, &list_st); 455213483730SMike Christie schedule_timeout_uninterruptible(HZ / 10); 455313483730SMike Christie } while (time_after(wtime, jiffies)); 455413483730SMike Christie 455513483730SMike Christie /* Free up the sendtargets list */ 45564a4bc2e9SLalit Chandivade qla4xxx_free_ddb_list(&list_st); 455713483730SMike Christie 45584a4bc2e9SLalit Chandivade qla4xxx_build_nt_list(ha, &list_nt, is_reset); 455913483730SMike Christie 45604a4bc2e9SLalit Chandivade qla4xxx_free_ddb_list(&list_nt); 456113483730SMike Christie 456213483730SMike Christie qla4xxx_free_ddb_index(ha); 456313483730SMike Christie } 456413483730SMike Christie 4565afaf5a2dSDavid Somayajulu /** 4566afaf5a2dSDavid Somayajulu * qla4xxx_probe_adapter - callback function to probe HBA 4567afaf5a2dSDavid Somayajulu * @pdev: pointer to pci_dev structure 4568afaf5a2dSDavid Somayajulu * @pci_device_id: pointer to pci_device entry 4569afaf5a2dSDavid Somayajulu * 4570afaf5a2dSDavid Somayajulu * This routine will probe for Qlogic 4xxx iSCSI host adapters. 4571afaf5a2dSDavid Somayajulu * It returns zero if successful. It also initializes all data necessary for 4572afaf5a2dSDavid Somayajulu * the driver. 4573afaf5a2dSDavid Somayajulu **/ 4574afaf5a2dSDavid Somayajulu static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, 4575afaf5a2dSDavid Somayajulu const struct pci_device_id *ent) 4576afaf5a2dSDavid Somayajulu { 4577afaf5a2dSDavid Somayajulu int ret = -ENODEV, status; 4578afaf5a2dSDavid Somayajulu struct Scsi_Host *host; 4579afaf5a2dSDavid Somayajulu struct scsi_qla_host *ha; 4580afaf5a2dSDavid Somayajulu uint8_t init_retry_count = 0; 4581afaf5a2dSDavid Somayajulu char buf[34]; 4582f4f5df23SVikas Chaudhary struct qla4_8xxx_legacy_intr_set *nx_legacy_intr; 4583f9880e76SPrasanna Mumbai uint32_t dev_state; 4584afaf5a2dSDavid Somayajulu 4585afaf5a2dSDavid Somayajulu if (pci_enable_device(pdev)) 4586afaf5a2dSDavid Somayajulu return -1; 4587afaf5a2dSDavid Somayajulu 4588b3a271a9SManish Rangankar host = iscsi_host_alloc(&qla4xxx_driver_template, sizeof(*ha), 0); 4589afaf5a2dSDavid Somayajulu if (host == NULL) { 4590afaf5a2dSDavid Somayajulu printk(KERN_WARNING 4591afaf5a2dSDavid Somayajulu "qla4xxx: Couldn't allocate host from scsi layer!\n"); 4592afaf5a2dSDavid Somayajulu goto probe_disable_device; 4593afaf5a2dSDavid Somayajulu } 4594afaf5a2dSDavid Somayajulu 4595afaf5a2dSDavid Somayajulu /* Clear our data area */ 4596b3a271a9SManish Rangankar ha = to_qla_host(host); 4597afaf5a2dSDavid Somayajulu memset(ha, 0, sizeof(*ha)); 4598afaf5a2dSDavid Somayajulu 4599afaf5a2dSDavid Somayajulu /* Save the information from PCI BIOS. */ 4600afaf5a2dSDavid Somayajulu ha->pdev = pdev; 4601afaf5a2dSDavid Somayajulu ha->host = host; 4602afaf5a2dSDavid Somayajulu ha->host_no = host->host_no; 4603afaf5a2dSDavid Somayajulu 46042232be0dSLalit Chandivade pci_enable_pcie_error_reporting(pdev); 46052232be0dSLalit Chandivade 4606f4f5df23SVikas Chaudhary /* Setup Runtime configurable options */ 4607f4f5df23SVikas Chaudhary if (is_qla8022(ha)) { 4608f4f5df23SVikas Chaudhary ha->isp_ops = &qla4_8xxx_isp_ops; 4609f4f5df23SVikas Chaudhary rwlock_init(&ha->hw_lock); 4610f4f5df23SVikas Chaudhary ha->qdr_sn_window = -1; 4611f4f5df23SVikas Chaudhary ha->ddr_mn_window = -1; 4612f4f5df23SVikas Chaudhary ha->curr_window = 255; 4613f4f5df23SVikas Chaudhary ha->func_num = PCI_FUNC(ha->pdev->devfn); 4614f4f5df23SVikas Chaudhary nx_legacy_intr = &legacy_intr[ha->func_num]; 4615f4f5df23SVikas Chaudhary ha->nx_legacy_intr.int_vec_bit = nx_legacy_intr->int_vec_bit; 4616f4f5df23SVikas Chaudhary ha->nx_legacy_intr.tgt_status_reg = 4617f4f5df23SVikas Chaudhary nx_legacy_intr->tgt_status_reg; 4618f4f5df23SVikas Chaudhary ha->nx_legacy_intr.tgt_mask_reg = nx_legacy_intr->tgt_mask_reg; 4619f4f5df23SVikas Chaudhary ha->nx_legacy_intr.pci_int_reg = nx_legacy_intr->pci_int_reg; 4620f4f5df23SVikas Chaudhary } else { 4621f4f5df23SVikas Chaudhary ha->isp_ops = &qla4xxx_isp_ops; 4622f4f5df23SVikas Chaudhary } 4623f4f5df23SVikas Chaudhary 46242232be0dSLalit Chandivade /* Set EEH reset type to fundamental if required by hba */ 46252232be0dSLalit Chandivade if (is_qla8022(ha)) 46262232be0dSLalit Chandivade pdev->needs_freset = 1; 46272232be0dSLalit Chandivade 4628afaf5a2dSDavid Somayajulu /* Configure PCI I/O space. */ 4629f4f5df23SVikas Chaudhary ret = ha->isp_ops->iospace_config(ha); 4630afaf5a2dSDavid Somayajulu if (ret) 4631f4f5df23SVikas Chaudhary goto probe_failed_ioconfig; 4632afaf5a2dSDavid Somayajulu 4633c2660df3SVikas Chaudhary ql4_printk(KERN_INFO, ha, "Found an ISP%04x, irq %d, iobase 0x%p\n", 4634afaf5a2dSDavid Somayajulu pdev->device, pdev->irq, ha->reg); 4635afaf5a2dSDavid Somayajulu 4636afaf5a2dSDavid Somayajulu qla4xxx_config_dma_addressing(ha); 4637afaf5a2dSDavid Somayajulu 4638afaf5a2dSDavid Somayajulu /* Initialize lists and spinlocks. */ 4639afaf5a2dSDavid Somayajulu INIT_LIST_HEAD(&ha->free_srb_q); 4640afaf5a2dSDavid Somayajulu 4641afaf5a2dSDavid Somayajulu mutex_init(&ha->mbox_sem); 46424549415aSLalit Chandivade mutex_init(&ha->chap_sem); 4643f4f5df23SVikas Chaudhary init_completion(&ha->mbx_intr_comp); 464495d31262SVikas Chaudhary init_completion(&ha->disable_acb_comp); 4645afaf5a2dSDavid Somayajulu 4646afaf5a2dSDavid Somayajulu spin_lock_init(&ha->hardware_lock); 4647afaf5a2dSDavid Somayajulu 4648ff884430SVikas Chaudhary /* Initialize work list */ 4649ff884430SVikas Chaudhary INIT_LIST_HEAD(&ha->work_list); 4650ff884430SVikas Chaudhary 4651afaf5a2dSDavid Somayajulu /* Allocate dma buffers */ 4652afaf5a2dSDavid Somayajulu if (qla4xxx_mem_alloc(ha)) { 4653c2660df3SVikas Chaudhary ql4_printk(KERN_WARNING, ha, 4654afaf5a2dSDavid Somayajulu "[ERROR] Failed to allocate memory for adapter\n"); 4655afaf5a2dSDavid Somayajulu 4656afaf5a2dSDavid Somayajulu ret = -ENOMEM; 4657afaf5a2dSDavid Somayajulu goto probe_failed; 4658afaf5a2dSDavid Somayajulu } 4659afaf5a2dSDavid Somayajulu 4660b3a271a9SManish Rangankar host->cmd_per_lun = 3; 4661b3a271a9SManish Rangankar host->max_channel = 0; 4662b3a271a9SManish Rangankar host->max_lun = MAX_LUNS - 1; 4663b3a271a9SManish Rangankar host->max_id = MAX_TARGETS; 4664b3a271a9SManish Rangankar host->max_cmd_len = IOCB_MAX_CDB_LEN; 4665b3a271a9SManish Rangankar host->can_queue = MAX_SRBS ; 4666b3a271a9SManish Rangankar host->transportt = qla4xxx_scsi_transport; 4667b3a271a9SManish Rangankar 4668b3a271a9SManish Rangankar ret = scsi_init_shared_tag_map(host, MAX_SRBS); 4669b3a271a9SManish Rangankar if (ret) { 4670b3a271a9SManish Rangankar ql4_printk(KERN_WARNING, ha, 4671b3a271a9SManish Rangankar "%s: scsi_init_shared_tag_map failed\n", __func__); 4672b3a271a9SManish Rangankar goto probe_failed; 4673b3a271a9SManish Rangankar } 4674b3a271a9SManish Rangankar 4675b3a271a9SManish Rangankar pci_set_drvdata(pdev, ha); 4676b3a271a9SManish Rangankar 4677b3a271a9SManish Rangankar ret = scsi_add_host(host, &pdev->dev); 4678b3a271a9SManish Rangankar if (ret) 4679b3a271a9SManish Rangankar goto probe_failed; 4680b3a271a9SManish Rangankar 4681f4f5df23SVikas Chaudhary if (is_qla8022(ha)) 4682f4f5df23SVikas Chaudhary (void) qla4_8xxx_get_flash_info(ha); 4683f4f5df23SVikas Chaudhary 4684afaf5a2dSDavid Somayajulu /* 4685afaf5a2dSDavid Somayajulu * Initialize the Host adapter request/response queues and 4686afaf5a2dSDavid Somayajulu * firmware 4687afaf5a2dSDavid Somayajulu * NOTE: interrupts enabled upon successful completion 4688afaf5a2dSDavid Somayajulu */ 468913483730SMike Christie status = qla4xxx_initialize_adapter(ha, INIT_ADAPTER); 4690f4f5df23SVikas Chaudhary while ((!test_bit(AF_ONLINE, &ha->flags)) && 4691f4f5df23SVikas Chaudhary init_retry_count++ < MAX_INIT_RETRIES) { 4692f9880e76SPrasanna Mumbai 4693f9880e76SPrasanna Mumbai if (is_qla8022(ha)) { 4694f9880e76SPrasanna Mumbai qla4_8xxx_idc_lock(ha); 4695f9880e76SPrasanna Mumbai dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE); 4696f9880e76SPrasanna Mumbai qla4_8xxx_idc_unlock(ha); 4697f9880e76SPrasanna Mumbai if (dev_state == QLA82XX_DEV_FAILED) { 4698f9880e76SPrasanna Mumbai ql4_printk(KERN_WARNING, ha, "%s: don't retry " 4699f9880e76SPrasanna Mumbai "initialize adapter. H/W is in failed state\n", 4700f9880e76SPrasanna Mumbai __func__); 4701f9880e76SPrasanna Mumbai break; 4702f9880e76SPrasanna Mumbai } 4703f9880e76SPrasanna Mumbai } 4704afaf5a2dSDavid Somayajulu DEBUG2(printk("scsi: %s: retrying adapter initialization " 4705afaf5a2dSDavid Somayajulu "(%d)\n", __func__, init_retry_count)); 4706f4f5df23SVikas Chaudhary 4707f4f5df23SVikas Chaudhary if (ha->isp_ops->reset_chip(ha) == QLA_ERROR) 4708f4f5df23SVikas Chaudhary continue; 4709f4f5df23SVikas Chaudhary 471013483730SMike Christie status = qla4xxx_initialize_adapter(ha, INIT_ADAPTER); 4711afaf5a2dSDavid Somayajulu } 4712f4f5df23SVikas Chaudhary 4713f4f5df23SVikas Chaudhary if (!test_bit(AF_ONLINE, &ha->flags)) { 4714c2660df3SVikas Chaudhary ql4_printk(KERN_WARNING, ha, "Failed to initialize adapter\n"); 4715afaf5a2dSDavid Somayajulu 4716fe998527SLalit Chandivade if (is_qla8022(ha) && ql4xdontresethba) { 4717fe998527SLalit Chandivade /* Put the device in failed state. */ 4718fe998527SLalit Chandivade DEBUG2(printk(KERN_ERR "HW STATE: FAILED\n")); 4719fe998527SLalit Chandivade qla4_8xxx_idc_lock(ha); 4720fe998527SLalit Chandivade qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, 4721fe998527SLalit Chandivade QLA82XX_DEV_FAILED); 4722fe998527SLalit Chandivade qla4_8xxx_idc_unlock(ha); 4723fe998527SLalit Chandivade } 4724afaf5a2dSDavid Somayajulu ret = -ENODEV; 4725b3a271a9SManish Rangankar goto remove_host; 4726afaf5a2dSDavid Somayajulu } 4727afaf5a2dSDavid Somayajulu 4728afaf5a2dSDavid Somayajulu /* Startup the kernel thread for this host adapter. */ 4729afaf5a2dSDavid Somayajulu DEBUG2(printk("scsi: %s: Starting kernel thread for " 4730afaf5a2dSDavid Somayajulu "qla4xxx_dpc\n", __func__)); 4731afaf5a2dSDavid Somayajulu sprintf(buf, "qla4xxx_%lu_dpc", ha->host_no); 4732afaf5a2dSDavid Somayajulu ha->dpc_thread = create_singlethread_workqueue(buf); 4733afaf5a2dSDavid Somayajulu if (!ha->dpc_thread) { 4734c2660df3SVikas Chaudhary ql4_printk(KERN_WARNING, ha, "Unable to start DPC thread!\n"); 4735afaf5a2dSDavid Somayajulu ret = -ENODEV; 4736b3a271a9SManish Rangankar goto remove_host; 4737afaf5a2dSDavid Somayajulu } 4738c4028958SDavid Howells INIT_WORK(&ha->dpc_work, qla4xxx_do_dpc); 4739afaf5a2dSDavid Somayajulu 4740b3a271a9SManish Rangankar sprintf(buf, "qla4xxx_%lu_task", ha->host_no); 4741b3a271a9SManish Rangankar ha->task_wq = alloc_workqueue(buf, WQ_MEM_RECLAIM, 1); 4742b3a271a9SManish Rangankar if (!ha->task_wq) { 4743b3a271a9SManish Rangankar ql4_printk(KERN_WARNING, ha, "Unable to start task thread!\n"); 4744b3a271a9SManish Rangankar ret = -ENODEV; 4745b3a271a9SManish Rangankar goto remove_host; 4746b3a271a9SManish Rangankar } 4747b3a271a9SManish Rangankar 4748f4f5df23SVikas Chaudhary /* For ISP-82XX, request_irqs is called in qla4_8xxx_load_risc 4749f4f5df23SVikas Chaudhary * (which is called indirectly by qla4xxx_initialize_adapter), 4750f4f5df23SVikas Chaudhary * so that irqs will be registered after crbinit but before 4751f4f5df23SVikas Chaudhary * mbx_intr_enable. 4752f4f5df23SVikas Chaudhary */ 4753f4f5df23SVikas Chaudhary if (!is_qla8022(ha)) { 4754f4f5df23SVikas Chaudhary ret = qla4xxx_request_irqs(ha); 4755afaf5a2dSDavid Somayajulu if (ret) { 4756f4f5df23SVikas Chaudhary ql4_printk(KERN_WARNING, ha, "Failed to reserve " 4757f4f5df23SVikas Chaudhary "interrupt %d already in use.\n", pdev->irq); 4758b3a271a9SManish Rangankar goto remove_host; 4759afaf5a2dSDavid Somayajulu } 4760f4f5df23SVikas Chaudhary } 4761afaf5a2dSDavid Somayajulu 47622232be0dSLalit Chandivade pci_save_state(ha->pdev); 4763f4f5df23SVikas Chaudhary ha->isp_ops->enable_intrs(ha); 4764afaf5a2dSDavid Somayajulu 4765afaf5a2dSDavid Somayajulu /* Start timer thread. */ 4766afaf5a2dSDavid Somayajulu qla4xxx_start_timer(ha, qla4xxx_timer, 1); 4767afaf5a2dSDavid Somayajulu 4768afaf5a2dSDavid Somayajulu set_bit(AF_INIT_DONE, &ha->flags); 4769afaf5a2dSDavid Somayajulu 4770afaf5a2dSDavid Somayajulu printk(KERN_INFO 4771afaf5a2dSDavid Somayajulu " QLogic iSCSI HBA Driver version: %s\n" 4772afaf5a2dSDavid Somayajulu " QLogic ISP%04x @ %s, host#=%ld, fw=%02d.%02d.%02d.%02d\n", 4773afaf5a2dSDavid Somayajulu qla4xxx_version_str, ha->pdev->device, pci_name(ha->pdev), 4774afaf5a2dSDavid Somayajulu ha->host_no, ha->firmware_version[0], ha->firmware_version[1], 4775afaf5a2dSDavid Somayajulu ha->patch_number, ha->build_number); 4776ed1086e0SVikas Chaudhary 47772a991c21SManish Rangankar if (qla4xxx_setup_boot_info(ha)) 47782a991c21SManish Rangankar ql4_printk(KERN_ERR, ha, "%s:ISCSI boot info setup failed\n", 47792a991c21SManish Rangankar __func__); 47802a991c21SManish Rangankar 478113483730SMike Christie /* Perform the build ddb list and login to each */ 478213483730SMike Christie qla4xxx_build_ddb_list(ha, INIT_ADAPTER); 478313483730SMike Christie iscsi_host_for_each_session(ha->host, qla4xxx_login_flash_ddb); 478413483730SMike Christie 478513483730SMike Christie qla4xxx_create_chap_list(ha); 478613483730SMike Christie 4787ed1086e0SVikas Chaudhary qla4xxx_create_ifaces(ha); 4788afaf5a2dSDavid Somayajulu return 0; 4789afaf5a2dSDavid Somayajulu 4790b3a271a9SManish Rangankar remove_host: 4791b3a271a9SManish Rangankar scsi_remove_host(ha->host); 4792b3a271a9SManish Rangankar 4793afaf5a2dSDavid Somayajulu probe_failed: 4794afaf5a2dSDavid Somayajulu qla4xxx_free_adapter(ha); 4795f4f5df23SVikas Chaudhary 4796f4f5df23SVikas Chaudhary probe_failed_ioconfig: 47972232be0dSLalit Chandivade pci_disable_pcie_error_reporting(pdev); 4798afaf5a2dSDavid Somayajulu scsi_host_put(ha->host); 4799afaf5a2dSDavid Somayajulu 4800afaf5a2dSDavid Somayajulu probe_disable_device: 4801afaf5a2dSDavid Somayajulu pci_disable_device(pdev); 4802afaf5a2dSDavid Somayajulu 4803afaf5a2dSDavid Somayajulu return ret; 4804afaf5a2dSDavid Somayajulu } 4805afaf5a2dSDavid Somayajulu 4806afaf5a2dSDavid Somayajulu /** 48077eece5a0SKaren Higgins * qla4xxx_prevent_other_port_reinit - prevent other port from re-initialize 48087eece5a0SKaren Higgins * @ha: pointer to adapter structure 48097eece5a0SKaren Higgins * 48107eece5a0SKaren Higgins * Mark the other ISP-4xxx port to indicate that the driver is being removed, 48117eece5a0SKaren Higgins * so that the other port will not re-initialize while in the process of 48127eece5a0SKaren Higgins * removing the ha due to driver unload or hba hotplug. 48137eece5a0SKaren Higgins **/ 48147eece5a0SKaren Higgins static void qla4xxx_prevent_other_port_reinit(struct scsi_qla_host *ha) 48157eece5a0SKaren Higgins { 48167eece5a0SKaren Higgins struct scsi_qla_host *other_ha = NULL; 48177eece5a0SKaren Higgins struct pci_dev *other_pdev = NULL; 48187eece5a0SKaren Higgins int fn = ISP4XXX_PCI_FN_2; 48197eece5a0SKaren Higgins 48207eece5a0SKaren Higgins /*iscsi function numbers for ISP4xxx is 1 and 3*/ 48217eece5a0SKaren Higgins if (PCI_FUNC(ha->pdev->devfn) & BIT_1) 48227eece5a0SKaren Higgins fn = ISP4XXX_PCI_FN_1; 48237eece5a0SKaren Higgins 48247eece5a0SKaren Higgins other_pdev = 48257eece5a0SKaren Higgins pci_get_domain_bus_and_slot(pci_domain_nr(ha->pdev->bus), 48267eece5a0SKaren Higgins ha->pdev->bus->number, PCI_DEVFN(PCI_SLOT(ha->pdev->devfn), 48277eece5a0SKaren Higgins fn)); 48287eece5a0SKaren Higgins 48297eece5a0SKaren Higgins /* Get other_ha if other_pdev is valid and state is enable*/ 48307eece5a0SKaren Higgins if (other_pdev) { 48317eece5a0SKaren Higgins if (atomic_read(&other_pdev->enable_cnt)) { 48327eece5a0SKaren Higgins other_ha = pci_get_drvdata(other_pdev); 48337eece5a0SKaren Higgins if (other_ha) { 48347eece5a0SKaren Higgins set_bit(AF_HA_REMOVAL, &other_ha->flags); 48357eece5a0SKaren Higgins DEBUG2(ql4_printk(KERN_INFO, ha, "%s: " 48367eece5a0SKaren Higgins "Prevent %s reinit\n", __func__, 48377eece5a0SKaren Higgins dev_name(&other_ha->pdev->dev))); 48387eece5a0SKaren Higgins } 48397eece5a0SKaren Higgins } 48407eece5a0SKaren Higgins pci_dev_put(other_pdev); 48417eece5a0SKaren Higgins } 48427eece5a0SKaren Higgins } 48437eece5a0SKaren Higgins 484413483730SMike Christie static void qla4xxx_destroy_fw_ddb_session(struct scsi_qla_host *ha) 484513483730SMike Christie { 484613483730SMike Christie struct ddb_entry *ddb_entry; 484713483730SMike Christie int options; 484813483730SMike Christie int idx; 484913483730SMike Christie 485013483730SMike Christie for (idx = 0; idx < MAX_DDB_ENTRIES; idx++) { 485113483730SMike Christie 485213483730SMike Christie ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx); 485313483730SMike Christie if ((ddb_entry != NULL) && 485413483730SMike Christie (ddb_entry->ddb_type == FLASH_DDB)) { 485513483730SMike Christie 485613483730SMike Christie options = LOGOUT_OPTION_CLOSE_SESSION; 485713483730SMike Christie if (qla4xxx_session_logout_ddb(ha, ddb_entry, options) 485813483730SMike Christie == QLA_ERROR) 485913483730SMike Christie ql4_printk(KERN_ERR, ha, "%s: Logout failed\n", 486013483730SMike Christie __func__); 486113483730SMike Christie 486213483730SMike Christie qla4xxx_clear_ddb_entry(ha, ddb_entry->fw_ddb_index); 486313483730SMike Christie /* 486413483730SMike Christie * we have decremented the reference count of the driver 486513483730SMike Christie * when we setup the session to have the driver unload 486613483730SMike Christie * to be seamless without actually destroying the 486713483730SMike Christie * session 486813483730SMike Christie **/ 486913483730SMike Christie try_module_get(qla4xxx_iscsi_transport.owner); 487013483730SMike Christie iscsi_destroy_endpoint(ddb_entry->conn->ep); 487113483730SMike Christie qla4xxx_free_ddb(ha, ddb_entry); 487213483730SMike Christie iscsi_session_teardown(ddb_entry->sess); 487313483730SMike Christie } 487413483730SMike Christie } 487513483730SMike Christie } 48767eece5a0SKaren Higgins /** 4877afaf5a2dSDavid Somayajulu * qla4xxx_remove_adapter - calback function to remove adapter. 4878afaf5a2dSDavid Somayajulu * @pci_dev: PCI device pointer 4879afaf5a2dSDavid Somayajulu **/ 4880afaf5a2dSDavid Somayajulu static void __devexit qla4xxx_remove_adapter(struct pci_dev *pdev) 4881afaf5a2dSDavid Somayajulu { 4882afaf5a2dSDavid Somayajulu struct scsi_qla_host *ha; 4883afaf5a2dSDavid Somayajulu 4884afaf5a2dSDavid Somayajulu ha = pci_get_drvdata(pdev); 4885afaf5a2dSDavid Somayajulu 48867eece5a0SKaren Higgins if (!is_qla8022(ha)) 48877eece5a0SKaren Higgins qla4xxx_prevent_other_port_reinit(ha); 4888bee4fe8eSDavid C Somayajulu 4889ed1086e0SVikas Chaudhary /* destroy iface from sysfs */ 4890ed1086e0SVikas Chaudhary qla4xxx_destroy_ifaces(ha); 4891ed1086e0SVikas Chaudhary 489213483730SMike Christie if ((!ql4xdisablesysfsboot) && ha->boot_kset) 48932a991c21SManish Rangankar iscsi_boot_destroy_kset(ha->boot_kset); 48942a991c21SManish Rangankar 489513483730SMike Christie qla4xxx_destroy_fw_ddb_session(ha); 489613483730SMike Christie 4897afaf5a2dSDavid Somayajulu scsi_remove_host(ha->host); 4898afaf5a2dSDavid Somayajulu 4899afaf5a2dSDavid Somayajulu qla4xxx_free_adapter(ha); 4900afaf5a2dSDavid Somayajulu 4901afaf5a2dSDavid Somayajulu scsi_host_put(ha->host); 4902afaf5a2dSDavid Somayajulu 49032232be0dSLalit Chandivade pci_disable_pcie_error_reporting(pdev); 4904f4f5df23SVikas Chaudhary pci_disable_device(pdev); 4905afaf5a2dSDavid Somayajulu pci_set_drvdata(pdev, NULL); 4906afaf5a2dSDavid Somayajulu } 4907afaf5a2dSDavid Somayajulu 4908afaf5a2dSDavid Somayajulu /** 4909afaf5a2dSDavid Somayajulu * qla4xxx_config_dma_addressing() - Configure OS DMA addressing method. 4910afaf5a2dSDavid Somayajulu * @ha: HA context 4911afaf5a2dSDavid Somayajulu * 4912afaf5a2dSDavid Somayajulu * At exit, the @ha's flags.enable_64bit_addressing set to indicated 4913afaf5a2dSDavid Somayajulu * supported addressing method. 4914afaf5a2dSDavid Somayajulu */ 491547975477SAdrian Bunk static void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha) 4916afaf5a2dSDavid Somayajulu { 4917afaf5a2dSDavid Somayajulu int retval; 4918afaf5a2dSDavid Somayajulu 4919afaf5a2dSDavid Somayajulu /* Update our PCI device dma_mask for full 64 bit mask */ 49206a35528aSYang Hongyang if (pci_set_dma_mask(ha->pdev, DMA_BIT_MASK(64)) == 0) { 49216a35528aSYang Hongyang if (pci_set_consistent_dma_mask(ha->pdev, DMA_BIT_MASK(64))) { 4922afaf5a2dSDavid Somayajulu dev_dbg(&ha->pdev->dev, 4923afaf5a2dSDavid Somayajulu "Failed to set 64 bit PCI consistent mask; " 4924afaf5a2dSDavid Somayajulu "using 32 bit.\n"); 4925afaf5a2dSDavid Somayajulu retval = pci_set_consistent_dma_mask(ha->pdev, 4926284901a9SYang Hongyang DMA_BIT_MASK(32)); 4927afaf5a2dSDavid Somayajulu } 4928afaf5a2dSDavid Somayajulu } else 4929284901a9SYang Hongyang retval = pci_set_dma_mask(ha->pdev, DMA_BIT_MASK(32)); 4930afaf5a2dSDavid Somayajulu } 4931afaf5a2dSDavid Somayajulu 4932afaf5a2dSDavid Somayajulu static int qla4xxx_slave_alloc(struct scsi_device *sdev) 4933afaf5a2dSDavid Somayajulu { 4934b3a271a9SManish Rangankar struct iscsi_cls_session *cls_sess; 4935b3a271a9SManish Rangankar struct iscsi_session *sess; 4936b3a271a9SManish Rangankar struct ddb_entry *ddb; 49378bb4033dSVikas Chaudhary int queue_depth = QL4_DEF_QDEPTH; 4938afaf5a2dSDavid Somayajulu 4939b3a271a9SManish Rangankar cls_sess = starget_to_session(sdev->sdev_target); 4940b3a271a9SManish Rangankar sess = cls_sess->dd_data; 4941b3a271a9SManish Rangankar ddb = sess->dd_data; 4942b3a271a9SManish Rangankar 4943afaf5a2dSDavid Somayajulu sdev->hostdata = ddb; 4944afaf5a2dSDavid Somayajulu sdev->tagged_supported = 1; 49458bb4033dSVikas Chaudhary 49468bb4033dSVikas Chaudhary if (ql4xmaxqdepth != 0 && ql4xmaxqdepth <= 0xffffU) 49478bb4033dSVikas Chaudhary queue_depth = ql4xmaxqdepth; 49488bb4033dSVikas Chaudhary 49498bb4033dSVikas Chaudhary scsi_activate_tcq(sdev, queue_depth); 4950afaf5a2dSDavid Somayajulu return 0; 4951afaf5a2dSDavid Somayajulu } 4952afaf5a2dSDavid Somayajulu 4953afaf5a2dSDavid Somayajulu static int qla4xxx_slave_configure(struct scsi_device *sdev) 4954afaf5a2dSDavid Somayajulu { 4955afaf5a2dSDavid Somayajulu sdev->tagged_supported = 1; 4956afaf5a2dSDavid Somayajulu return 0; 4957afaf5a2dSDavid Somayajulu } 4958afaf5a2dSDavid Somayajulu 4959afaf5a2dSDavid Somayajulu static void qla4xxx_slave_destroy(struct scsi_device *sdev) 4960afaf5a2dSDavid Somayajulu { 4961afaf5a2dSDavid Somayajulu scsi_deactivate_tcq(sdev, 1); 4962afaf5a2dSDavid Somayajulu } 4963afaf5a2dSDavid Somayajulu 4964afaf5a2dSDavid Somayajulu /** 4965afaf5a2dSDavid Somayajulu * qla4xxx_del_from_active_array - returns an active srb 4966afaf5a2dSDavid Somayajulu * @ha: Pointer to host adapter structure. 4967fd589a8fSAnand Gadiyar * @index: index into the active_array 4968afaf5a2dSDavid Somayajulu * 4969afaf5a2dSDavid Somayajulu * This routine removes and returns the srb at the specified index 4970afaf5a2dSDavid Somayajulu **/ 4971f4f5df23SVikas Chaudhary struct srb *qla4xxx_del_from_active_array(struct scsi_qla_host *ha, 4972f4f5df23SVikas Chaudhary uint32_t index) 4973afaf5a2dSDavid Somayajulu { 4974afaf5a2dSDavid Somayajulu struct srb *srb = NULL; 49755369887aSVikas Chaudhary struct scsi_cmnd *cmd = NULL; 4976afaf5a2dSDavid Somayajulu 49775369887aSVikas Chaudhary cmd = scsi_host_find_tag(ha->host, index); 49785369887aSVikas Chaudhary if (!cmd) 4979afaf5a2dSDavid Somayajulu return srb; 4980afaf5a2dSDavid Somayajulu 49815369887aSVikas Chaudhary srb = (struct srb *)CMD_SP(cmd); 49825369887aSVikas Chaudhary if (!srb) 4983afaf5a2dSDavid Somayajulu return srb; 4984afaf5a2dSDavid Somayajulu 4985afaf5a2dSDavid Somayajulu /* update counters */ 4986afaf5a2dSDavid Somayajulu if (srb->flags & SRB_DMA_VALID) { 4987afaf5a2dSDavid Somayajulu ha->req_q_count += srb->iocb_cnt; 4988afaf5a2dSDavid Somayajulu ha->iocb_cnt -= srb->iocb_cnt; 4989afaf5a2dSDavid Somayajulu if (srb->cmd) 49905369887aSVikas Chaudhary srb->cmd->host_scribble = 49915369887aSVikas Chaudhary (unsigned char *)(unsigned long) MAX_SRBS; 4992afaf5a2dSDavid Somayajulu } 4993afaf5a2dSDavid Somayajulu return srb; 4994afaf5a2dSDavid Somayajulu } 4995afaf5a2dSDavid Somayajulu 4996afaf5a2dSDavid Somayajulu /** 4997afaf5a2dSDavid Somayajulu * qla4xxx_eh_wait_on_command - waits for command to be returned by firmware 499809a0f719SVikas Chaudhary * @ha: Pointer to host adapter structure. 4999afaf5a2dSDavid Somayajulu * @cmd: Scsi Command to wait on. 5000afaf5a2dSDavid Somayajulu * 5001afaf5a2dSDavid Somayajulu * This routine waits for the command to be returned by the Firmware 5002afaf5a2dSDavid Somayajulu * for some max time. 5003afaf5a2dSDavid Somayajulu **/ 5004afaf5a2dSDavid Somayajulu static int qla4xxx_eh_wait_on_command(struct scsi_qla_host *ha, 5005afaf5a2dSDavid Somayajulu struct scsi_cmnd *cmd) 5006afaf5a2dSDavid Somayajulu { 5007afaf5a2dSDavid Somayajulu int done = 0; 5008afaf5a2dSDavid Somayajulu struct srb *rp; 5009afaf5a2dSDavid Somayajulu uint32_t max_wait_time = EH_WAIT_CMD_TOV; 50102232be0dSLalit Chandivade int ret = SUCCESS; 50112232be0dSLalit Chandivade 50122232be0dSLalit Chandivade /* Dont wait on command if PCI error is being handled 50132232be0dSLalit Chandivade * by PCI AER driver 50142232be0dSLalit Chandivade */ 50152232be0dSLalit Chandivade if (unlikely(pci_channel_offline(ha->pdev)) || 50162232be0dSLalit Chandivade (test_bit(AF_EEH_BUSY, &ha->flags))) { 50172232be0dSLalit Chandivade ql4_printk(KERN_WARNING, ha, "scsi%ld: Return from %s\n", 50182232be0dSLalit Chandivade ha->host_no, __func__); 50192232be0dSLalit Chandivade return ret; 50202232be0dSLalit Chandivade } 5021afaf5a2dSDavid Somayajulu 5022afaf5a2dSDavid Somayajulu do { 5023afaf5a2dSDavid Somayajulu /* Checking to see if its returned to OS */ 50245369887aSVikas Chaudhary rp = (struct srb *) CMD_SP(cmd); 5025afaf5a2dSDavid Somayajulu if (rp == NULL) { 5026afaf5a2dSDavid Somayajulu done++; 5027afaf5a2dSDavid Somayajulu break; 5028afaf5a2dSDavid Somayajulu } 5029afaf5a2dSDavid Somayajulu 5030afaf5a2dSDavid Somayajulu msleep(2000); 5031afaf5a2dSDavid Somayajulu } while (max_wait_time--); 5032afaf5a2dSDavid Somayajulu 5033afaf5a2dSDavid Somayajulu return done; 5034afaf5a2dSDavid Somayajulu } 5035afaf5a2dSDavid Somayajulu 5036afaf5a2dSDavid Somayajulu /** 5037afaf5a2dSDavid Somayajulu * qla4xxx_wait_for_hba_online - waits for HBA to come online 5038afaf5a2dSDavid Somayajulu * @ha: Pointer to host adapter structure 5039afaf5a2dSDavid Somayajulu **/ 5040afaf5a2dSDavid Somayajulu static int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha) 5041afaf5a2dSDavid Somayajulu { 5042afaf5a2dSDavid Somayajulu unsigned long wait_online; 5043afaf5a2dSDavid Somayajulu 5044f581a3f7SVikas Chaudhary wait_online = jiffies + (HBA_ONLINE_TOV * HZ); 5045afaf5a2dSDavid Somayajulu while (time_before(jiffies, wait_online)) { 5046afaf5a2dSDavid Somayajulu 5047afaf5a2dSDavid Somayajulu if (adapter_up(ha)) 5048afaf5a2dSDavid Somayajulu return QLA_SUCCESS; 5049afaf5a2dSDavid Somayajulu 5050afaf5a2dSDavid Somayajulu msleep(2000); 5051afaf5a2dSDavid Somayajulu } 5052afaf5a2dSDavid Somayajulu 5053afaf5a2dSDavid Somayajulu return QLA_ERROR; 5054afaf5a2dSDavid Somayajulu } 5055afaf5a2dSDavid Somayajulu 5056afaf5a2dSDavid Somayajulu /** 5057ce545039SMike Christie * qla4xxx_eh_wait_for_commands - wait for active cmds to finish. 5058fd589a8fSAnand Gadiyar * @ha: pointer to HBA 5059afaf5a2dSDavid Somayajulu * @t: target id 5060afaf5a2dSDavid Somayajulu * @l: lun id 5061afaf5a2dSDavid Somayajulu * 5062afaf5a2dSDavid Somayajulu * This function waits for all outstanding commands to a lun to complete. It 5063afaf5a2dSDavid Somayajulu * returns 0 if all pending commands are returned and 1 otherwise. 5064afaf5a2dSDavid Somayajulu **/ 5065ce545039SMike Christie static int qla4xxx_eh_wait_for_commands(struct scsi_qla_host *ha, 5066ce545039SMike Christie struct scsi_target *stgt, 5067ce545039SMike Christie struct scsi_device *sdev) 5068afaf5a2dSDavid Somayajulu { 5069afaf5a2dSDavid Somayajulu int cnt; 5070afaf5a2dSDavid Somayajulu int status = 0; 5071afaf5a2dSDavid Somayajulu struct scsi_cmnd *cmd; 5072afaf5a2dSDavid Somayajulu 5073afaf5a2dSDavid Somayajulu /* 5074ce545039SMike Christie * Waiting for all commands for the designated target or dev 5075ce545039SMike Christie * in the active array 5076afaf5a2dSDavid Somayajulu */ 5077afaf5a2dSDavid Somayajulu for (cnt = 0; cnt < ha->host->can_queue; cnt++) { 5078afaf5a2dSDavid Somayajulu cmd = scsi_host_find_tag(ha->host, cnt); 5079ce545039SMike Christie if (cmd && stgt == scsi_target(cmd->device) && 5080ce545039SMike Christie (!sdev || sdev == cmd->device)) { 5081afaf5a2dSDavid Somayajulu if (!qla4xxx_eh_wait_on_command(ha, cmd)) { 5082afaf5a2dSDavid Somayajulu status++; 5083afaf5a2dSDavid Somayajulu break; 5084afaf5a2dSDavid Somayajulu } 5085afaf5a2dSDavid Somayajulu } 5086afaf5a2dSDavid Somayajulu } 5087afaf5a2dSDavid Somayajulu return status; 5088afaf5a2dSDavid Somayajulu } 5089afaf5a2dSDavid Somayajulu 5090afaf5a2dSDavid Somayajulu /** 509109a0f719SVikas Chaudhary * qla4xxx_eh_abort - callback for abort task. 509209a0f719SVikas Chaudhary * @cmd: Pointer to Linux's SCSI command structure 509309a0f719SVikas Chaudhary * 509409a0f719SVikas Chaudhary * This routine is called by the Linux OS to abort the specified 509509a0f719SVikas Chaudhary * command. 509609a0f719SVikas Chaudhary **/ 509709a0f719SVikas Chaudhary static int qla4xxx_eh_abort(struct scsi_cmnd *cmd) 509809a0f719SVikas Chaudhary { 509909a0f719SVikas Chaudhary struct scsi_qla_host *ha = to_qla_host(cmd->device->host); 510009a0f719SVikas Chaudhary unsigned int id = cmd->device->id; 510109a0f719SVikas Chaudhary unsigned int lun = cmd->device->lun; 510292b3e5bbSMike Christie unsigned long flags; 510309a0f719SVikas Chaudhary struct srb *srb = NULL; 510409a0f719SVikas Chaudhary int ret = SUCCESS; 510509a0f719SVikas Chaudhary int wait = 0; 510609a0f719SVikas Chaudhary 5107c2660df3SVikas Chaudhary ql4_printk(KERN_INFO, ha, 51085cd049a5SChristoph Hellwig "scsi%ld:%d:%d: Abort command issued cmd=%p\n", 51095cd049a5SChristoph Hellwig ha->host_no, id, lun, cmd); 511009a0f719SVikas Chaudhary 511192b3e5bbSMike Christie spin_lock_irqsave(&ha->hardware_lock, flags); 511209a0f719SVikas Chaudhary srb = (struct srb *) CMD_SP(cmd); 511392b3e5bbSMike Christie if (!srb) { 511492b3e5bbSMike Christie spin_unlock_irqrestore(&ha->hardware_lock, flags); 511509a0f719SVikas Chaudhary return SUCCESS; 511692b3e5bbSMike Christie } 511709a0f719SVikas Chaudhary kref_get(&srb->srb_ref); 511892b3e5bbSMike Christie spin_unlock_irqrestore(&ha->hardware_lock, flags); 511909a0f719SVikas Chaudhary 512009a0f719SVikas Chaudhary if (qla4xxx_abort_task(ha, srb) != QLA_SUCCESS) { 512109a0f719SVikas Chaudhary DEBUG3(printk("scsi%ld:%d:%d: Abort_task mbx failed.\n", 512209a0f719SVikas Chaudhary ha->host_no, id, lun)); 512309a0f719SVikas Chaudhary ret = FAILED; 512409a0f719SVikas Chaudhary } else { 512509a0f719SVikas Chaudhary DEBUG3(printk("scsi%ld:%d:%d: Abort_task mbx success.\n", 512609a0f719SVikas Chaudhary ha->host_no, id, lun)); 512709a0f719SVikas Chaudhary wait = 1; 512809a0f719SVikas Chaudhary } 512909a0f719SVikas Chaudhary 513009a0f719SVikas Chaudhary kref_put(&srb->srb_ref, qla4xxx_srb_compl); 513109a0f719SVikas Chaudhary 513209a0f719SVikas Chaudhary /* Wait for command to complete */ 513309a0f719SVikas Chaudhary if (wait) { 513409a0f719SVikas Chaudhary if (!qla4xxx_eh_wait_on_command(ha, cmd)) { 513509a0f719SVikas Chaudhary DEBUG2(printk("scsi%ld:%d:%d: Abort handler timed out\n", 513609a0f719SVikas Chaudhary ha->host_no, id, lun)); 513709a0f719SVikas Chaudhary ret = FAILED; 513809a0f719SVikas Chaudhary } 513909a0f719SVikas Chaudhary } 514009a0f719SVikas Chaudhary 5141c2660df3SVikas Chaudhary ql4_printk(KERN_INFO, ha, 514209a0f719SVikas Chaudhary "scsi%ld:%d:%d: Abort command - %s\n", 514325985edcSLucas De Marchi ha->host_no, id, lun, (ret == SUCCESS) ? "succeeded" : "failed"); 514409a0f719SVikas Chaudhary 514509a0f719SVikas Chaudhary return ret; 514609a0f719SVikas Chaudhary } 514709a0f719SVikas Chaudhary 514809a0f719SVikas Chaudhary /** 5149afaf5a2dSDavid Somayajulu * qla4xxx_eh_device_reset - callback for target reset. 5150afaf5a2dSDavid Somayajulu * @cmd: Pointer to Linux's SCSI command structure 5151afaf5a2dSDavid Somayajulu * 5152afaf5a2dSDavid Somayajulu * This routine is called by the Linux OS to reset all luns on the 5153afaf5a2dSDavid Somayajulu * specified target. 5154afaf5a2dSDavid Somayajulu **/ 5155afaf5a2dSDavid Somayajulu static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd) 5156afaf5a2dSDavid Somayajulu { 5157afaf5a2dSDavid Somayajulu struct scsi_qla_host *ha = to_qla_host(cmd->device->host); 5158afaf5a2dSDavid Somayajulu struct ddb_entry *ddb_entry = cmd->device->hostdata; 5159afaf5a2dSDavid Somayajulu int ret = FAILED, stat; 5160afaf5a2dSDavid Somayajulu 5161612f7348SKaren Higgins if (!ddb_entry) 5162afaf5a2dSDavid Somayajulu return ret; 5163afaf5a2dSDavid Somayajulu 5164c01be6dcSMike Christie ret = iscsi_block_scsi_eh(cmd); 5165c01be6dcSMike Christie if (ret) 5166c01be6dcSMike Christie return ret; 5167c01be6dcSMike Christie ret = FAILED; 5168c01be6dcSMike Christie 5169c2660df3SVikas Chaudhary ql4_printk(KERN_INFO, ha, 5170afaf5a2dSDavid Somayajulu "scsi%ld:%d:%d:%d: DEVICE RESET ISSUED.\n", ha->host_no, 5171afaf5a2dSDavid Somayajulu cmd->device->channel, cmd->device->id, cmd->device->lun); 5172afaf5a2dSDavid Somayajulu 5173afaf5a2dSDavid Somayajulu DEBUG2(printk(KERN_INFO 5174afaf5a2dSDavid Somayajulu "scsi%ld: DEVICE_RESET cmd=%p jiffies = 0x%lx, to=%x," 5175afaf5a2dSDavid Somayajulu "dpc_flags=%lx, status=%x allowed=%d\n", ha->host_no, 5176242f9dcbSJens Axboe cmd, jiffies, cmd->request->timeout / HZ, 5177afaf5a2dSDavid Somayajulu ha->dpc_flags, cmd->result, cmd->allowed)); 5178afaf5a2dSDavid Somayajulu 5179afaf5a2dSDavid Somayajulu /* FIXME: wait for hba to go online */ 5180afaf5a2dSDavid Somayajulu stat = qla4xxx_reset_lun(ha, ddb_entry, cmd->device->lun); 5181afaf5a2dSDavid Somayajulu if (stat != QLA_SUCCESS) { 5182c2660df3SVikas Chaudhary ql4_printk(KERN_INFO, ha, "DEVICE RESET FAILED. %d\n", stat); 5183afaf5a2dSDavid Somayajulu goto eh_dev_reset_done; 5184afaf5a2dSDavid Somayajulu } 5185afaf5a2dSDavid Somayajulu 5186ce545039SMike Christie if (qla4xxx_eh_wait_for_commands(ha, scsi_target(cmd->device), 5187ce545039SMike Christie cmd->device)) { 5188c2660df3SVikas Chaudhary ql4_printk(KERN_INFO, ha, 5189afaf5a2dSDavid Somayajulu "DEVICE RESET FAILED - waiting for " 5190afaf5a2dSDavid Somayajulu "commands.\n"); 5191afaf5a2dSDavid Somayajulu goto eh_dev_reset_done; 5192afaf5a2dSDavid Somayajulu } 5193afaf5a2dSDavid Somayajulu 51949d562913SDavid C Somayajulu /* Send marker. */ 51959d562913SDavid C Somayajulu if (qla4xxx_send_marker_iocb(ha, ddb_entry, cmd->device->lun, 51969d562913SDavid C Somayajulu MM_LUN_RESET) != QLA_SUCCESS) 51979d562913SDavid C Somayajulu goto eh_dev_reset_done; 51989d562913SDavid C Somayajulu 5199c2660df3SVikas Chaudhary ql4_printk(KERN_INFO, ha, 5200afaf5a2dSDavid Somayajulu "scsi(%ld:%d:%d:%d): DEVICE RESET SUCCEEDED.\n", 5201afaf5a2dSDavid Somayajulu ha->host_no, cmd->device->channel, cmd->device->id, 5202afaf5a2dSDavid Somayajulu cmd->device->lun); 5203afaf5a2dSDavid Somayajulu 5204afaf5a2dSDavid Somayajulu ret = SUCCESS; 5205afaf5a2dSDavid Somayajulu 5206afaf5a2dSDavid Somayajulu eh_dev_reset_done: 5207afaf5a2dSDavid Somayajulu 5208afaf5a2dSDavid Somayajulu return ret; 5209afaf5a2dSDavid Somayajulu } 5210afaf5a2dSDavid Somayajulu 5211afaf5a2dSDavid Somayajulu /** 5212ce545039SMike Christie * qla4xxx_eh_target_reset - callback for target reset. 5213ce545039SMike Christie * @cmd: Pointer to Linux's SCSI command structure 5214ce545039SMike Christie * 5215ce545039SMike Christie * This routine is called by the Linux OS to reset the target. 5216ce545039SMike Christie **/ 5217ce545039SMike Christie static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd) 5218ce545039SMike Christie { 5219ce545039SMike Christie struct scsi_qla_host *ha = to_qla_host(cmd->device->host); 5220ce545039SMike Christie struct ddb_entry *ddb_entry = cmd->device->hostdata; 5221c01be6dcSMike Christie int stat, ret; 5222ce545039SMike Christie 5223ce545039SMike Christie if (!ddb_entry) 5224ce545039SMike Christie return FAILED; 5225ce545039SMike Christie 5226c01be6dcSMike Christie ret = iscsi_block_scsi_eh(cmd); 5227c01be6dcSMike Christie if (ret) 5228c01be6dcSMike Christie return ret; 5229c01be6dcSMike Christie 5230ce545039SMike Christie starget_printk(KERN_INFO, scsi_target(cmd->device), 5231ce545039SMike Christie "WARM TARGET RESET ISSUED.\n"); 5232ce545039SMike Christie 5233ce545039SMike Christie DEBUG2(printk(KERN_INFO 5234ce545039SMike Christie "scsi%ld: TARGET_DEVICE_RESET cmd=%p jiffies = 0x%lx, " 5235ce545039SMike Christie "to=%x,dpc_flags=%lx, status=%x allowed=%d\n", 5236242f9dcbSJens Axboe ha->host_no, cmd, jiffies, cmd->request->timeout / HZ, 5237ce545039SMike Christie ha->dpc_flags, cmd->result, cmd->allowed)); 5238ce545039SMike Christie 5239ce545039SMike Christie stat = qla4xxx_reset_target(ha, ddb_entry); 5240ce545039SMike Christie if (stat != QLA_SUCCESS) { 5241ce545039SMike Christie starget_printk(KERN_INFO, scsi_target(cmd->device), 5242ce545039SMike Christie "WARM TARGET RESET FAILED.\n"); 5243ce545039SMike Christie return FAILED; 5244ce545039SMike Christie } 5245ce545039SMike Christie 5246ce545039SMike Christie if (qla4xxx_eh_wait_for_commands(ha, scsi_target(cmd->device), 5247ce545039SMike Christie NULL)) { 5248ce545039SMike Christie starget_printk(KERN_INFO, scsi_target(cmd->device), 5249ce545039SMike Christie "WARM TARGET DEVICE RESET FAILED - " 5250ce545039SMike Christie "waiting for commands.\n"); 5251ce545039SMike Christie return FAILED; 5252ce545039SMike Christie } 5253ce545039SMike Christie 52549d562913SDavid C Somayajulu /* Send marker. */ 52559d562913SDavid C Somayajulu if (qla4xxx_send_marker_iocb(ha, ddb_entry, cmd->device->lun, 52569d562913SDavid C Somayajulu MM_TGT_WARM_RESET) != QLA_SUCCESS) { 52579d562913SDavid C Somayajulu starget_printk(KERN_INFO, scsi_target(cmd->device), 52589d562913SDavid C Somayajulu "WARM TARGET DEVICE RESET FAILED - " 52599d562913SDavid C Somayajulu "marker iocb failed.\n"); 52609d562913SDavid C Somayajulu return FAILED; 52619d562913SDavid C Somayajulu } 52629d562913SDavid C Somayajulu 5263ce545039SMike Christie starget_printk(KERN_INFO, scsi_target(cmd->device), 5264ce545039SMike Christie "WARM TARGET RESET SUCCEEDED.\n"); 5265ce545039SMike Christie return SUCCESS; 5266ce545039SMike Christie } 5267ce545039SMike Christie 5268ce545039SMike Christie /** 52698a288960SSarang Radke * qla4xxx_is_eh_active - check if error handler is running 52708a288960SSarang Radke * @shost: Pointer to SCSI Host struct 52718a288960SSarang Radke * 52728a288960SSarang Radke * This routine finds that if reset host is called in EH 52738a288960SSarang Radke * scenario or from some application like sg_reset 52748a288960SSarang Radke **/ 52758a288960SSarang Radke static int qla4xxx_is_eh_active(struct Scsi_Host *shost) 52768a288960SSarang Radke { 52778a288960SSarang Radke if (shost->shost_state == SHOST_RECOVERY) 52788a288960SSarang Radke return 1; 52798a288960SSarang Radke return 0; 52808a288960SSarang Radke } 52818a288960SSarang Radke 52828a288960SSarang Radke /** 5283afaf5a2dSDavid Somayajulu * qla4xxx_eh_host_reset - kernel callback 5284afaf5a2dSDavid Somayajulu * @cmd: Pointer to Linux's SCSI command structure 5285afaf5a2dSDavid Somayajulu * 5286afaf5a2dSDavid Somayajulu * This routine is invoked by the Linux kernel to perform fatal error 5287afaf5a2dSDavid Somayajulu * recovery on the specified adapter. 5288afaf5a2dSDavid Somayajulu **/ 5289afaf5a2dSDavid Somayajulu static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd) 5290afaf5a2dSDavid Somayajulu { 5291afaf5a2dSDavid Somayajulu int return_status = FAILED; 5292afaf5a2dSDavid Somayajulu struct scsi_qla_host *ha; 5293afaf5a2dSDavid Somayajulu 5294b3a271a9SManish Rangankar ha = to_qla_host(cmd->device->host); 5295afaf5a2dSDavid Somayajulu 5296f4f5df23SVikas Chaudhary if (ql4xdontresethba) { 5297f4f5df23SVikas Chaudhary DEBUG2(printk("scsi%ld: %s: Don't Reset HBA\n", 5298f4f5df23SVikas Chaudhary ha->host_no, __func__)); 52998a288960SSarang Radke 53008a288960SSarang Radke /* Clear outstanding srb in queues */ 53018a288960SSarang Radke if (qla4xxx_is_eh_active(cmd->device->host)) 53028a288960SSarang Radke qla4xxx_abort_active_cmds(ha, DID_ABORT << 16); 53038a288960SSarang Radke 5304f4f5df23SVikas Chaudhary return FAILED; 5305f4f5df23SVikas Chaudhary } 5306f4f5df23SVikas Chaudhary 5307c2660df3SVikas Chaudhary ql4_printk(KERN_INFO, ha, 5308dca05c4cSKaren Higgins "scsi(%ld:%d:%d:%d): HOST RESET ISSUED.\n", ha->host_no, 5309afaf5a2dSDavid Somayajulu cmd->device->channel, cmd->device->id, cmd->device->lun); 5310afaf5a2dSDavid Somayajulu 5311afaf5a2dSDavid Somayajulu if (qla4xxx_wait_for_hba_online(ha) != QLA_SUCCESS) { 5312afaf5a2dSDavid Somayajulu DEBUG2(printk("scsi%ld:%d: %s: Unable to reset host. Adapter " 5313afaf5a2dSDavid Somayajulu "DEAD.\n", ha->host_no, cmd->device->channel, 5314afaf5a2dSDavid Somayajulu __func__)); 5315afaf5a2dSDavid Somayajulu 5316afaf5a2dSDavid Somayajulu return FAILED; 5317afaf5a2dSDavid Somayajulu } 5318afaf5a2dSDavid Somayajulu 5319f4f5df23SVikas Chaudhary if (!test_bit(DPC_RESET_HA, &ha->dpc_flags)) { 5320f4f5df23SVikas Chaudhary if (is_qla8022(ha)) 5321f4f5df23SVikas Chaudhary set_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags); 5322f4f5df23SVikas Chaudhary else 5323f4f5df23SVikas Chaudhary set_bit(DPC_RESET_HA, &ha->dpc_flags); 5324f4f5df23SVikas Chaudhary } 532550a29aecSMike Christie 5326f4f5df23SVikas Chaudhary if (qla4xxx_recover_adapter(ha) == QLA_SUCCESS) 5327afaf5a2dSDavid Somayajulu return_status = SUCCESS; 5328afaf5a2dSDavid Somayajulu 5329c2660df3SVikas Chaudhary ql4_printk(KERN_INFO, ha, "HOST RESET %s.\n", 533025985edcSLucas De Marchi return_status == FAILED ? "FAILED" : "SUCCEEDED"); 5331afaf5a2dSDavid Somayajulu 5332afaf5a2dSDavid Somayajulu return return_status; 5333afaf5a2dSDavid Somayajulu } 5334afaf5a2dSDavid Somayajulu 533595d31262SVikas Chaudhary static int qla4xxx_context_reset(struct scsi_qla_host *ha) 533695d31262SVikas Chaudhary { 533795d31262SVikas Chaudhary uint32_t mbox_cmd[MBOX_REG_COUNT]; 533895d31262SVikas Chaudhary uint32_t mbox_sts[MBOX_REG_COUNT]; 533995d31262SVikas Chaudhary struct addr_ctrl_blk_def *acb = NULL; 534095d31262SVikas Chaudhary uint32_t acb_len = sizeof(struct addr_ctrl_blk_def); 534195d31262SVikas Chaudhary int rval = QLA_SUCCESS; 534295d31262SVikas Chaudhary dma_addr_t acb_dma; 534395d31262SVikas Chaudhary 534495d31262SVikas Chaudhary acb = dma_alloc_coherent(&ha->pdev->dev, 534595d31262SVikas Chaudhary sizeof(struct addr_ctrl_blk_def), 534695d31262SVikas Chaudhary &acb_dma, GFP_KERNEL); 534795d31262SVikas Chaudhary if (!acb) { 534895d31262SVikas Chaudhary ql4_printk(KERN_ERR, ha, "%s: Unable to alloc acb\n", 534995d31262SVikas Chaudhary __func__); 535095d31262SVikas Chaudhary rval = -ENOMEM; 535195d31262SVikas Chaudhary goto exit_port_reset; 535295d31262SVikas Chaudhary } 535395d31262SVikas Chaudhary 535495d31262SVikas Chaudhary memset(acb, 0, acb_len); 535595d31262SVikas Chaudhary 535695d31262SVikas Chaudhary rval = qla4xxx_get_acb(ha, acb_dma, PRIMARI_ACB, acb_len); 535795d31262SVikas Chaudhary if (rval != QLA_SUCCESS) { 535895d31262SVikas Chaudhary rval = -EIO; 535995d31262SVikas Chaudhary goto exit_free_acb; 536095d31262SVikas Chaudhary } 536195d31262SVikas Chaudhary 536295d31262SVikas Chaudhary rval = qla4xxx_disable_acb(ha); 536395d31262SVikas Chaudhary if (rval != QLA_SUCCESS) { 536495d31262SVikas Chaudhary rval = -EIO; 536595d31262SVikas Chaudhary goto exit_free_acb; 536695d31262SVikas Chaudhary } 536795d31262SVikas Chaudhary 536895d31262SVikas Chaudhary wait_for_completion_timeout(&ha->disable_acb_comp, 536995d31262SVikas Chaudhary DISABLE_ACB_TOV * HZ); 537095d31262SVikas Chaudhary 537195d31262SVikas Chaudhary rval = qla4xxx_set_acb(ha, &mbox_cmd[0], &mbox_sts[0], acb_dma); 537295d31262SVikas Chaudhary if (rval != QLA_SUCCESS) { 537395d31262SVikas Chaudhary rval = -EIO; 537495d31262SVikas Chaudhary goto exit_free_acb; 537595d31262SVikas Chaudhary } 537695d31262SVikas Chaudhary 537795d31262SVikas Chaudhary exit_free_acb: 537895d31262SVikas Chaudhary dma_free_coherent(&ha->pdev->dev, sizeof(struct addr_ctrl_blk_def), 537995d31262SVikas Chaudhary acb, acb_dma); 538095d31262SVikas Chaudhary exit_port_reset: 538195d31262SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, "%s %s\n", __func__, 538295d31262SVikas Chaudhary rval == QLA_SUCCESS ? "SUCCEEDED" : "FAILED")); 538395d31262SVikas Chaudhary return rval; 538495d31262SVikas Chaudhary } 538595d31262SVikas Chaudhary 538695d31262SVikas Chaudhary static int qla4xxx_host_reset(struct Scsi_Host *shost, int reset_type) 538795d31262SVikas Chaudhary { 538895d31262SVikas Chaudhary struct scsi_qla_host *ha = to_qla_host(shost); 538995d31262SVikas Chaudhary int rval = QLA_SUCCESS; 539095d31262SVikas Chaudhary 539195d31262SVikas Chaudhary if (ql4xdontresethba) { 539295d31262SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Don't Reset HBA\n", 539395d31262SVikas Chaudhary __func__)); 539495d31262SVikas Chaudhary rval = -EPERM; 539595d31262SVikas Chaudhary goto exit_host_reset; 539695d31262SVikas Chaudhary } 539795d31262SVikas Chaudhary 539895d31262SVikas Chaudhary rval = qla4xxx_wait_for_hba_online(ha); 539995d31262SVikas Chaudhary if (rval != QLA_SUCCESS) { 540095d31262SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Unable to reset host " 540195d31262SVikas Chaudhary "adapter\n", __func__)); 540295d31262SVikas Chaudhary rval = -EIO; 540395d31262SVikas Chaudhary goto exit_host_reset; 540495d31262SVikas Chaudhary } 540595d31262SVikas Chaudhary 540695d31262SVikas Chaudhary if (test_bit(DPC_RESET_HA, &ha->dpc_flags)) 540795d31262SVikas Chaudhary goto recover_adapter; 540895d31262SVikas Chaudhary 540995d31262SVikas Chaudhary switch (reset_type) { 541095d31262SVikas Chaudhary case SCSI_ADAPTER_RESET: 541195d31262SVikas Chaudhary set_bit(DPC_RESET_HA, &ha->dpc_flags); 541295d31262SVikas Chaudhary break; 541395d31262SVikas Chaudhary case SCSI_FIRMWARE_RESET: 541495d31262SVikas Chaudhary if (!test_bit(DPC_RESET_HA, &ha->dpc_flags)) { 541595d31262SVikas Chaudhary if (is_qla8022(ha)) 541695d31262SVikas Chaudhary /* set firmware context reset */ 541795d31262SVikas Chaudhary set_bit(DPC_RESET_HA_FW_CONTEXT, 541895d31262SVikas Chaudhary &ha->dpc_flags); 541995d31262SVikas Chaudhary else { 542095d31262SVikas Chaudhary rval = qla4xxx_context_reset(ha); 542195d31262SVikas Chaudhary goto exit_host_reset; 542295d31262SVikas Chaudhary } 542395d31262SVikas Chaudhary } 542495d31262SVikas Chaudhary break; 542595d31262SVikas Chaudhary } 542695d31262SVikas Chaudhary 542795d31262SVikas Chaudhary recover_adapter: 542895d31262SVikas Chaudhary rval = qla4xxx_recover_adapter(ha); 542995d31262SVikas Chaudhary if (rval != QLA_SUCCESS) { 543095d31262SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, "%s: recover adapter fail\n", 543195d31262SVikas Chaudhary __func__)); 543295d31262SVikas Chaudhary rval = -EIO; 543395d31262SVikas Chaudhary } 543495d31262SVikas Chaudhary 543595d31262SVikas Chaudhary exit_host_reset: 543695d31262SVikas Chaudhary return rval; 543795d31262SVikas Chaudhary } 543895d31262SVikas Chaudhary 54392232be0dSLalit Chandivade /* PCI AER driver recovers from all correctable errors w/o 54402232be0dSLalit Chandivade * driver intervention. For uncorrectable errors PCI AER 54412232be0dSLalit Chandivade * driver calls the following device driver's callbacks 54422232be0dSLalit Chandivade * 54432232be0dSLalit Chandivade * - Fatal Errors - link_reset 54442232be0dSLalit Chandivade * - Non-Fatal Errors - driver's pci_error_detected() which 54452232be0dSLalit Chandivade * returns CAN_RECOVER, NEED_RESET or DISCONNECT. 54462232be0dSLalit Chandivade * 54472232be0dSLalit Chandivade * PCI AER driver calls 54482232be0dSLalit Chandivade * CAN_RECOVER - driver's pci_mmio_enabled(), mmio_enabled 54492232be0dSLalit Chandivade * returns RECOVERED or NEED_RESET if fw_hung 54502232be0dSLalit Chandivade * NEED_RESET - driver's slot_reset() 54512232be0dSLalit Chandivade * DISCONNECT - device is dead & cannot recover 54522232be0dSLalit Chandivade * RECOVERED - driver's pci_resume() 54532232be0dSLalit Chandivade */ 54542232be0dSLalit Chandivade static pci_ers_result_t 54552232be0dSLalit Chandivade qla4xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) 54562232be0dSLalit Chandivade { 54572232be0dSLalit Chandivade struct scsi_qla_host *ha = pci_get_drvdata(pdev); 54582232be0dSLalit Chandivade 54592232be0dSLalit Chandivade ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: error detected:state %x\n", 54602232be0dSLalit Chandivade ha->host_no, __func__, state); 54612232be0dSLalit Chandivade 54622232be0dSLalit Chandivade if (!is_aer_supported(ha)) 54632232be0dSLalit Chandivade return PCI_ERS_RESULT_NONE; 54642232be0dSLalit Chandivade 54652232be0dSLalit Chandivade switch (state) { 54662232be0dSLalit Chandivade case pci_channel_io_normal: 54672232be0dSLalit Chandivade clear_bit(AF_EEH_BUSY, &ha->flags); 54682232be0dSLalit Chandivade return PCI_ERS_RESULT_CAN_RECOVER; 54692232be0dSLalit Chandivade case pci_channel_io_frozen: 54702232be0dSLalit Chandivade set_bit(AF_EEH_BUSY, &ha->flags); 54712232be0dSLalit Chandivade qla4xxx_mailbox_premature_completion(ha); 54722232be0dSLalit Chandivade qla4xxx_free_irqs(ha); 54732232be0dSLalit Chandivade pci_disable_device(pdev); 54747b3595dfSVikas Chaudhary /* Return back all IOs */ 54757b3595dfSVikas Chaudhary qla4xxx_abort_active_cmds(ha, DID_RESET << 16); 54762232be0dSLalit Chandivade return PCI_ERS_RESULT_NEED_RESET; 54772232be0dSLalit Chandivade case pci_channel_io_perm_failure: 54782232be0dSLalit Chandivade set_bit(AF_EEH_BUSY, &ha->flags); 54792232be0dSLalit Chandivade set_bit(AF_PCI_CHANNEL_IO_PERM_FAILURE, &ha->flags); 54802232be0dSLalit Chandivade qla4xxx_abort_active_cmds(ha, DID_NO_CONNECT << 16); 54812232be0dSLalit Chandivade return PCI_ERS_RESULT_DISCONNECT; 54822232be0dSLalit Chandivade } 54832232be0dSLalit Chandivade return PCI_ERS_RESULT_NEED_RESET; 54842232be0dSLalit Chandivade } 54852232be0dSLalit Chandivade 54862232be0dSLalit Chandivade /** 54872232be0dSLalit Chandivade * qla4xxx_pci_mmio_enabled() gets called if 54882232be0dSLalit Chandivade * qla4xxx_pci_error_detected() returns PCI_ERS_RESULT_CAN_RECOVER 54892232be0dSLalit Chandivade * and read/write to the device still works. 54902232be0dSLalit Chandivade **/ 54912232be0dSLalit Chandivade static pci_ers_result_t 54922232be0dSLalit Chandivade qla4xxx_pci_mmio_enabled(struct pci_dev *pdev) 54932232be0dSLalit Chandivade { 54942232be0dSLalit Chandivade struct scsi_qla_host *ha = pci_get_drvdata(pdev); 54952232be0dSLalit Chandivade 54962232be0dSLalit Chandivade if (!is_aer_supported(ha)) 54972232be0dSLalit Chandivade return PCI_ERS_RESULT_NONE; 54982232be0dSLalit Chandivade 54992232be0dSLalit Chandivade return PCI_ERS_RESULT_RECOVERED; 55002232be0dSLalit Chandivade } 55012232be0dSLalit Chandivade 55027b3595dfSVikas Chaudhary static uint32_t qla4_8xxx_error_recovery(struct scsi_qla_host *ha) 55032232be0dSLalit Chandivade { 55042232be0dSLalit Chandivade uint32_t rval = QLA_ERROR; 55057b3595dfSVikas Chaudhary uint32_t ret = 0; 55062232be0dSLalit Chandivade int fn; 55072232be0dSLalit Chandivade struct pci_dev *other_pdev = NULL; 55082232be0dSLalit Chandivade 55092232be0dSLalit Chandivade ql4_printk(KERN_WARNING, ha, "scsi%ld: In %s\n", ha->host_no, __func__); 55102232be0dSLalit Chandivade 55112232be0dSLalit Chandivade set_bit(DPC_RESET_ACTIVE, &ha->dpc_flags); 55122232be0dSLalit Chandivade 55132232be0dSLalit Chandivade if (test_bit(AF_ONLINE, &ha->flags)) { 55142232be0dSLalit Chandivade clear_bit(AF_ONLINE, &ha->flags); 5515b3a271a9SManish Rangankar clear_bit(AF_LINK_UP, &ha->flags); 5516b3a271a9SManish Rangankar iscsi_host_for_each_session(ha->host, qla4xxx_fail_session); 55172232be0dSLalit Chandivade qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); 55182232be0dSLalit Chandivade } 55192232be0dSLalit Chandivade 55202232be0dSLalit Chandivade fn = PCI_FUNC(ha->pdev->devfn); 55212232be0dSLalit Chandivade while (fn > 0) { 55222232be0dSLalit Chandivade fn--; 55232232be0dSLalit Chandivade ql4_printk(KERN_INFO, ha, "scsi%ld: %s: Finding PCI device at " 55242232be0dSLalit Chandivade "func %x\n", ha->host_no, __func__, fn); 55252232be0dSLalit Chandivade /* Get the pci device given the domain, bus, 55262232be0dSLalit Chandivade * slot/function number */ 55272232be0dSLalit Chandivade other_pdev = 55282232be0dSLalit Chandivade pci_get_domain_bus_and_slot(pci_domain_nr(ha->pdev->bus), 55292232be0dSLalit Chandivade ha->pdev->bus->number, PCI_DEVFN(PCI_SLOT(ha->pdev->devfn), 55302232be0dSLalit Chandivade fn)); 55312232be0dSLalit Chandivade 55322232be0dSLalit Chandivade if (!other_pdev) 55332232be0dSLalit Chandivade continue; 55342232be0dSLalit Chandivade 55352232be0dSLalit Chandivade if (atomic_read(&other_pdev->enable_cnt)) { 55362232be0dSLalit Chandivade ql4_printk(KERN_INFO, ha, "scsi%ld: %s: Found PCI " 55372232be0dSLalit Chandivade "func in enabled state%x\n", ha->host_no, 55382232be0dSLalit Chandivade __func__, fn); 55392232be0dSLalit Chandivade pci_dev_put(other_pdev); 55402232be0dSLalit Chandivade break; 55412232be0dSLalit Chandivade } 55422232be0dSLalit Chandivade pci_dev_put(other_pdev); 55432232be0dSLalit Chandivade } 55442232be0dSLalit Chandivade 55452232be0dSLalit Chandivade /* The first function on the card, the reset owner will 55462232be0dSLalit Chandivade * start & initialize the firmware. The other functions 55472232be0dSLalit Chandivade * on the card will reset the firmware context 55482232be0dSLalit Chandivade */ 55492232be0dSLalit Chandivade if (!fn) { 55502232be0dSLalit Chandivade ql4_printk(KERN_INFO, ha, "scsi%ld: %s: devfn being reset " 55512232be0dSLalit Chandivade "0x%x is the owner\n", ha->host_no, __func__, 55522232be0dSLalit Chandivade ha->pdev->devfn); 55532232be0dSLalit Chandivade 55542232be0dSLalit Chandivade qla4_8xxx_idc_lock(ha); 55552232be0dSLalit Chandivade qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, 55562232be0dSLalit Chandivade QLA82XX_DEV_COLD); 55572232be0dSLalit Chandivade 55582232be0dSLalit Chandivade qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_IDC_VERSION, 55592232be0dSLalit Chandivade QLA82XX_IDC_VERSION); 55602232be0dSLalit Chandivade 55612232be0dSLalit Chandivade qla4_8xxx_idc_unlock(ha); 55622232be0dSLalit Chandivade clear_bit(AF_FW_RECOVERY, &ha->flags); 556313483730SMike Christie rval = qla4xxx_initialize_adapter(ha, RESET_ADAPTER); 55642232be0dSLalit Chandivade qla4_8xxx_idc_lock(ha); 55652232be0dSLalit Chandivade 55662232be0dSLalit Chandivade if (rval != QLA_SUCCESS) { 55672232be0dSLalit Chandivade ql4_printk(KERN_INFO, ha, "scsi%ld: %s: HW State: " 55682232be0dSLalit Chandivade "FAILED\n", ha->host_no, __func__); 55692232be0dSLalit Chandivade qla4_8xxx_clear_drv_active(ha); 55702232be0dSLalit Chandivade qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, 55712232be0dSLalit Chandivade QLA82XX_DEV_FAILED); 55722232be0dSLalit Chandivade } else { 55732232be0dSLalit Chandivade ql4_printk(KERN_INFO, ha, "scsi%ld: %s: HW State: " 55742232be0dSLalit Chandivade "READY\n", ha->host_no, __func__); 55752232be0dSLalit Chandivade qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, 55762232be0dSLalit Chandivade QLA82XX_DEV_READY); 55772232be0dSLalit Chandivade /* Clear driver state register */ 55782232be0dSLalit Chandivade qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_STATE, 0); 55792232be0dSLalit Chandivade qla4_8xxx_set_drv_active(ha); 55807b3595dfSVikas Chaudhary ret = qla4xxx_request_irqs(ha); 55817b3595dfSVikas Chaudhary if (ret) { 55827b3595dfSVikas Chaudhary ql4_printk(KERN_WARNING, ha, "Failed to " 55837b3595dfSVikas Chaudhary "reserve interrupt %d already in use.\n", 55847b3595dfSVikas Chaudhary ha->pdev->irq); 55857b3595dfSVikas Chaudhary rval = QLA_ERROR; 55867b3595dfSVikas Chaudhary } else { 55872232be0dSLalit Chandivade ha->isp_ops->enable_intrs(ha); 55887b3595dfSVikas Chaudhary rval = QLA_SUCCESS; 55897b3595dfSVikas Chaudhary } 55902232be0dSLalit Chandivade } 55912232be0dSLalit Chandivade qla4_8xxx_idc_unlock(ha); 55922232be0dSLalit Chandivade } else { 55932232be0dSLalit Chandivade ql4_printk(KERN_INFO, ha, "scsi%ld: %s: devfn 0x%x is not " 55942232be0dSLalit Chandivade "the reset owner\n", ha->host_no, __func__, 55952232be0dSLalit Chandivade ha->pdev->devfn); 55962232be0dSLalit Chandivade if ((qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE) == 55972232be0dSLalit Chandivade QLA82XX_DEV_READY)) { 55982232be0dSLalit Chandivade clear_bit(AF_FW_RECOVERY, &ha->flags); 559913483730SMike Christie rval = qla4xxx_initialize_adapter(ha, RESET_ADAPTER); 56007b3595dfSVikas Chaudhary if (rval == QLA_SUCCESS) { 56017b3595dfSVikas Chaudhary ret = qla4xxx_request_irqs(ha); 56027b3595dfSVikas Chaudhary if (ret) { 56037b3595dfSVikas Chaudhary ql4_printk(KERN_WARNING, ha, "Failed to" 56047b3595dfSVikas Chaudhary " reserve interrupt %d already in" 56057b3595dfSVikas Chaudhary " use.\n", ha->pdev->irq); 56067b3595dfSVikas Chaudhary rval = QLA_ERROR; 56077b3595dfSVikas Chaudhary } else { 56082232be0dSLalit Chandivade ha->isp_ops->enable_intrs(ha); 56097b3595dfSVikas Chaudhary rval = QLA_SUCCESS; 56107b3595dfSVikas Chaudhary } 56117b3595dfSVikas Chaudhary } 56122232be0dSLalit Chandivade qla4_8xxx_idc_lock(ha); 56132232be0dSLalit Chandivade qla4_8xxx_set_drv_active(ha); 56142232be0dSLalit Chandivade qla4_8xxx_idc_unlock(ha); 56152232be0dSLalit Chandivade } 56162232be0dSLalit Chandivade } 56172232be0dSLalit Chandivade clear_bit(DPC_RESET_ACTIVE, &ha->dpc_flags); 56182232be0dSLalit Chandivade return rval; 56192232be0dSLalit Chandivade } 56202232be0dSLalit Chandivade 56212232be0dSLalit Chandivade static pci_ers_result_t 56222232be0dSLalit Chandivade qla4xxx_pci_slot_reset(struct pci_dev *pdev) 56232232be0dSLalit Chandivade { 56242232be0dSLalit Chandivade pci_ers_result_t ret = PCI_ERS_RESULT_DISCONNECT; 56252232be0dSLalit Chandivade struct scsi_qla_host *ha = pci_get_drvdata(pdev); 56262232be0dSLalit Chandivade int rc; 56272232be0dSLalit Chandivade 56282232be0dSLalit Chandivade ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: slot_reset\n", 56292232be0dSLalit Chandivade ha->host_no, __func__); 56302232be0dSLalit Chandivade 56312232be0dSLalit Chandivade if (!is_aer_supported(ha)) 56322232be0dSLalit Chandivade return PCI_ERS_RESULT_NONE; 56332232be0dSLalit Chandivade 56342232be0dSLalit Chandivade /* Restore the saved state of PCIe device - 56352232be0dSLalit Chandivade * BAR registers, PCI Config space, PCIX, MSI, 56362232be0dSLalit Chandivade * IOV states 56372232be0dSLalit Chandivade */ 56382232be0dSLalit Chandivade pci_restore_state(pdev); 56392232be0dSLalit Chandivade 56402232be0dSLalit Chandivade /* pci_restore_state() clears the saved_state flag of the device 56412232be0dSLalit Chandivade * save restored state which resets saved_state flag 56422232be0dSLalit Chandivade */ 56432232be0dSLalit Chandivade pci_save_state(pdev); 56442232be0dSLalit Chandivade 56452232be0dSLalit Chandivade /* Initialize device or resume if in suspended state */ 56462232be0dSLalit Chandivade rc = pci_enable_device(pdev); 56472232be0dSLalit Chandivade if (rc) { 564825985edcSLucas De Marchi ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: Can't re-enable " 56492232be0dSLalit Chandivade "device after reset\n", ha->host_no, __func__); 56502232be0dSLalit Chandivade goto exit_slot_reset; 56512232be0dSLalit Chandivade } 56522232be0dSLalit Chandivade 56537b3595dfSVikas Chaudhary ha->isp_ops->disable_intrs(ha); 56542232be0dSLalit Chandivade 56552232be0dSLalit Chandivade if (is_qla8022(ha)) { 56562232be0dSLalit Chandivade if (qla4_8xxx_error_recovery(ha) == QLA_SUCCESS) { 56572232be0dSLalit Chandivade ret = PCI_ERS_RESULT_RECOVERED; 56582232be0dSLalit Chandivade goto exit_slot_reset; 56592232be0dSLalit Chandivade } else 56602232be0dSLalit Chandivade goto exit_slot_reset; 56612232be0dSLalit Chandivade } 56622232be0dSLalit Chandivade 56632232be0dSLalit Chandivade exit_slot_reset: 56642232be0dSLalit Chandivade ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: Return=%x\n" 56652232be0dSLalit Chandivade "device after reset\n", ha->host_no, __func__, ret); 56662232be0dSLalit Chandivade return ret; 56672232be0dSLalit Chandivade } 56682232be0dSLalit Chandivade 56692232be0dSLalit Chandivade static void 56702232be0dSLalit Chandivade qla4xxx_pci_resume(struct pci_dev *pdev) 56712232be0dSLalit Chandivade { 56722232be0dSLalit Chandivade struct scsi_qla_host *ha = pci_get_drvdata(pdev); 56732232be0dSLalit Chandivade int ret; 56742232be0dSLalit Chandivade 56752232be0dSLalit Chandivade ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: pci_resume\n", 56762232be0dSLalit Chandivade ha->host_no, __func__); 56772232be0dSLalit Chandivade 56782232be0dSLalit Chandivade ret = qla4xxx_wait_for_hba_online(ha); 56792232be0dSLalit Chandivade if (ret != QLA_SUCCESS) { 56802232be0dSLalit Chandivade ql4_printk(KERN_ERR, ha, "scsi%ld: %s: the device failed to " 56812232be0dSLalit Chandivade "resume I/O from slot/link_reset\n", ha->host_no, 56822232be0dSLalit Chandivade __func__); 56832232be0dSLalit Chandivade } 56842232be0dSLalit Chandivade 56852232be0dSLalit Chandivade pci_cleanup_aer_uncorrect_error_status(pdev); 56862232be0dSLalit Chandivade clear_bit(AF_EEH_BUSY, &ha->flags); 56872232be0dSLalit Chandivade } 56882232be0dSLalit Chandivade 56892232be0dSLalit Chandivade static struct pci_error_handlers qla4xxx_err_handler = { 56902232be0dSLalit Chandivade .error_detected = qla4xxx_pci_error_detected, 56912232be0dSLalit Chandivade .mmio_enabled = qla4xxx_pci_mmio_enabled, 56922232be0dSLalit Chandivade .slot_reset = qla4xxx_pci_slot_reset, 56932232be0dSLalit Chandivade .resume = qla4xxx_pci_resume, 56942232be0dSLalit Chandivade }; 56952232be0dSLalit Chandivade 5696afaf5a2dSDavid Somayajulu static struct pci_device_id qla4xxx_pci_tbl[] = { 5697afaf5a2dSDavid Somayajulu { 5698afaf5a2dSDavid Somayajulu .vendor = PCI_VENDOR_ID_QLOGIC, 5699afaf5a2dSDavid Somayajulu .device = PCI_DEVICE_ID_QLOGIC_ISP4010, 5700afaf5a2dSDavid Somayajulu .subvendor = PCI_ANY_ID, 5701afaf5a2dSDavid Somayajulu .subdevice = PCI_ANY_ID, 5702afaf5a2dSDavid Somayajulu }, 5703afaf5a2dSDavid Somayajulu { 5704afaf5a2dSDavid Somayajulu .vendor = PCI_VENDOR_ID_QLOGIC, 5705afaf5a2dSDavid Somayajulu .device = PCI_DEVICE_ID_QLOGIC_ISP4022, 5706afaf5a2dSDavid Somayajulu .subvendor = PCI_ANY_ID, 5707afaf5a2dSDavid Somayajulu .subdevice = PCI_ANY_ID, 5708afaf5a2dSDavid Somayajulu }, 5709d915058fSDavid C Somayajulu { 5710d915058fSDavid C Somayajulu .vendor = PCI_VENDOR_ID_QLOGIC, 5711d915058fSDavid C Somayajulu .device = PCI_DEVICE_ID_QLOGIC_ISP4032, 5712d915058fSDavid C Somayajulu .subvendor = PCI_ANY_ID, 5713d915058fSDavid C Somayajulu .subdevice = PCI_ANY_ID, 5714d915058fSDavid C Somayajulu }, 5715f4f5df23SVikas Chaudhary { 5716f4f5df23SVikas Chaudhary .vendor = PCI_VENDOR_ID_QLOGIC, 5717f4f5df23SVikas Chaudhary .device = PCI_DEVICE_ID_QLOGIC_ISP8022, 5718f4f5df23SVikas Chaudhary .subvendor = PCI_ANY_ID, 5719f4f5df23SVikas Chaudhary .subdevice = PCI_ANY_ID, 5720f4f5df23SVikas Chaudhary }, 5721afaf5a2dSDavid Somayajulu {0, 0}, 5722afaf5a2dSDavid Somayajulu }; 5723afaf5a2dSDavid Somayajulu MODULE_DEVICE_TABLE(pci, qla4xxx_pci_tbl); 5724afaf5a2dSDavid Somayajulu 572547975477SAdrian Bunk static struct pci_driver qla4xxx_pci_driver = { 5726afaf5a2dSDavid Somayajulu .name = DRIVER_NAME, 5727afaf5a2dSDavid Somayajulu .id_table = qla4xxx_pci_tbl, 5728afaf5a2dSDavid Somayajulu .probe = qla4xxx_probe_adapter, 5729afaf5a2dSDavid Somayajulu .remove = qla4xxx_remove_adapter, 57302232be0dSLalit Chandivade .err_handler = &qla4xxx_err_handler, 5731afaf5a2dSDavid Somayajulu }; 5732afaf5a2dSDavid Somayajulu 5733afaf5a2dSDavid Somayajulu static int __init qla4xxx_module_init(void) 5734afaf5a2dSDavid Somayajulu { 5735afaf5a2dSDavid Somayajulu int ret; 5736afaf5a2dSDavid Somayajulu 5737afaf5a2dSDavid Somayajulu /* Allocate cache for SRBs. */ 5738afaf5a2dSDavid Somayajulu srb_cachep = kmem_cache_create("qla4xxx_srbs", sizeof(struct srb), 0, 573920c2df83SPaul Mundt SLAB_HWCACHE_ALIGN, NULL); 5740afaf5a2dSDavid Somayajulu if (srb_cachep == NULL) { 5741afaf5a2dSDavid Somayajulu printk(KERN_ERR 5742afaf5a2dSDavid Somayajulu "%s: Unable to allocate SRB cache..." 5743afaf5a2dSDavid Somayajulu "Failing load!\n", DRIVER_NAME); 5744afaf5a2dSDavid Somayajulu ret = -ENOMEM; 5745afaf5a2dSDavid Somayajulu goto no_srp_cache; 5746afaf5a2dSDavid Somayajulu } 5747afaf5a2dSDavid Somayajulu 5748afaf5a2dSDavid Somayajulu /* Derive version string. */ 5749afaf5a2dSDavid Somayajulu strcpy(qla4xxx_version_str, QLA4XXX_DRIVER_VERSION); 575011010fecSAndrew Vasquez if (ql4xextended_error_logging) 5751afaf5a2dSDavid Somayajulu strcat(qla4xxx_version_str, "-debug"); 5752afaf5a2dSDavid Somayajulu 5753afaf5a2dSDavid Somayajulu qla4xxx_scsi_transport = 5754afaf5a2dSDavid Somayajulu iscsi_register_transport(&qla4xxx_iscsi_transport); 5755afaf5a2dSDavid Somayajulu if (!qla4xxx_scsi_transport){ 5756afaf5a2dSDavid Somayajulu ret = -ENODEV; 5757afaf5a2dSDavid Somayajulu goto release_srb_cache; 5758afaf5a2dSDavid Somayajulu } 5759afaf5a2dSDavid Somayajulu 5760afaf5a2dSDavid Somayajulu ret = pci_register_driver(&qla4xxx_pci_driver); 5761afaf5a2dSDavid Somayajulu if (ret) 5762afaf5a2dSDavid Somayajulu goto unregister_transport; 5763afaf5a2dSDavid Somayajulu 5764afaf5a2dSDavid Somayajulu printk(KERN_INFO "QLogic iSCSI HBA Driver\n"); 5765afaf5a2dSDavid Somayajulu return 0; 57665ae16db3SDoug Maxey 5767afaf5a2dSDavid Somayajulu unregister_transport: 5768afaf5a2dSDavid Somayajulu iscsi_unregister_transport(&qla4xxx_iscsi_transport); 5769afaf5a2dSDavid Somayajulu release_srb_cache: 5770afaf5a2dSDavid Somayajulu kmem_cache_destroy(srb_cachep); 5771afaf5a2dSDavid Somayajulu no_srp_cache: 5772afaf5a2dSDavid Somayajulu return ret; 5773afaf5a2dSDavid Somayajulu } 5774afaf5a2dSDavid Somayajulu 5775afaf5a2dSDavid Somayajulu static void __exit qla4xxx_module_exit(void) 5776afaf5a2dSDavid Somayajulu { 5777afaf5a2dSDavid Somayajulu pci_unregister_driver(&qla4xxx_pci_driver); 5778afaf5a2dSDavid Somayajulu iscsi_unregister_transport(&qla4xxx_iscsi_transport); 5779afaf5a2dSDavid Somayajulu kmem_cache_destroy(srb_cachep); 5780afaf5a2dSDavid Somayajulu } 5781afaf5a2dSDavid Somayajulu 5782afaf5a2dSDavid Somayajulu module_init(qla4xxx_module_init); 5783afaf5a2dSDavid Somayajulu module_exit(qla4xxx_module_exit); 5784afaf5a2dSDavid Somayajulu 5785afaf5a2dSDavid Somayajulu MODULE_AUTHOR("QLogic Corporation"); 5786afaf5a2dSDavid Somayajulu MODULE_DESCRIPTION("QLogic iSCSI HBA Driver"); 5787afaf5a2dSDavid Somayajulu MODULE_LICENSE("GPL"); 5788afaf5a2dSDavid Somayajulu MODULE_VERSION(QLA4XXX_DRIVER_VERSION); 5789