162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * QLogic iSCSI HBA Driver 462306a36Sopenharmony_ci * Copyright (c) 2003-2013 QLogic Corporation 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci#include <linux/moduleparam.h> 762306a36Sopenharmony_ci#include <linux/slab.h> 862306a36Sopenharmony_ci#include <linux/blkdev.h> 962306a36Sopenharmony_ci#include <linux/iscsi_boot_sysfs.h> 1062306a36Sopenharmony_ci#include <linux/inet.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <scsi/scsi_tcq.h> 1362306a36Sopenharmony_ci#include <scsi/scsicam.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include "ql4_def.h" 1662306a36Sopenharmony_ci#include "ql4_version.h" 1762306a36Sopenharmony_ci#include "ql4_glbl.h" 1862306a36Sopenharmony_ci#include "ql4_dbg.h" 1962306a36Sopenharmony_ci#include "ql4_inline.h" 2062306a36Sopenharmony_ci#include "ql4_83xx.h" 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci/* 2362306a36Sopenharmony_ci * Driver version 2462306a36Sopenharmony_ci */ 2562306a36Sopenharmony_cistatic char qla4xxx_version_str[40]; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci/* 2862306a36Sopenharmony_ci * SRB allocation cache 2962306a36Sopenharmony_ci */ 3062306a36Sopenharmony_cistatic struct kmem_cache *srb_cachep; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci/* 3362306a36Sopenharmony_ci * Module parameter information and variables 3462306a36Sopenharmony_ci */ 3562306a36Sopenharmony_cistatic int ql4xdisablesysfsboot = 1; 3662306a36Sopenharmony_cimodule_param(ql4xdisablesysfsboot, int, S_IRUGO | S_IWUSR); 3762306a36Sopenharmony_ciMODULE_PARM_DESC(ql4xdisablesysfsboot, 3862306a36Sopenharmony_ci " Set to disable exporting boot targets to sysfs.\n" 3962306a36Sopenharmony_ci "\t\t 0 - Export boot targets\n" 4062306a36Sopenharmony_ci "\t\t 1 - Do not export boot targets (Default)"); 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ciint ql4xdontresethba; 4362306a36Sopenharmony_cimodule_param(ql4xdontresethba, int, S_IRUGO | S_IWUSR); 4462306a36Sopenharmony_ciMODULE_PARM_DESC(ql4xdontresethba, 4562306a36Sopenharmony_ci " Don't reset the HBA for driver recovery.\n" 4662306a36Sopenharmony_ci "\t\t 0 - It will reset HBA (Default)\n" 4762306a36Sopenharmony_ci "\t\t 1 - It will NOT reset HBA"); 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ciint ql4xextended_error_logging; 5062306a36Sopenharmony_cimodule_param(ql4xextended_error_logging, int, S_IRUGO | S_IWUSR); 5162306a36Sopenharmony_ciMODULE_PARM_DESC(ql4xextended_error_logging, 5262306a36Sopenharmony_ci " Option to enable extended error logging.\n" 5362306a36Sopenharmony_ci "\t\t 0 - no logging (Default)\n" 5462306a36Sopenharmony_ci "\t\t 2 - debug logging"); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ciint ql4xenablemsix = 1; 5762306a36Sopenharmony_cimodule_param(ql4xenablemsix, int, S_IRUGO|S_IWUSR); 5862306a36Sopenharmony_ciMODULE_PARM_DESC(ql4xenablemsix, 5962306a36Sopenharmony_ci " Set to enable MSI or MSI-X interrupt mechanism.\n" 6062306a36Sopenharmony_ci "\t\t 0 = enable INTx interrupt mechanism.\n" 6162306a36Sopenharmony_ci "\t\t 1 = enable MSI-X interrupt mechanism (Default).\n" 6262306a36Sopenharmony_ci "\t\t 2 = enable MSI interrupt mechanism."); 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci#define QL4_DEF_QDEPTH 32 6562306a36Sopenharmony_cistatic int ql4xmaxqdepth = QL4_DEF_QDEPTH; 6662306a36Sopenharmony_cimodule_param(ql4xmaxqdepth, int, S_IRUGO | S_IWUSR); 6762306a36Sopenharmony_ciMODULE_PARM_DESC(ql4xmaxqdepth, 6862306a36Sopenharmony_ci " Maximum queue depth to report for target devices.\n" 6962306a36Sopenharmony_ci "\t\t Default: 32."); 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic int ql4xqfulltracking = 1; 7262306a36Sopenharmony_cimodule_param(ql4xqfulltracking, int, S_IRUGO | S_IWUSR); 7362306a36Sopenharmony_ciMODULE_PARM_DESC(ql4xqfulltracking, 7462306a36Sopenharmony_ci " Enable or disable dynamic tracking and adjustment of\n" 7562306a36Sopenharmony_ci "\t\t scsi device queue depth.\n" 7662306a36Sopenharmony_ci "\t\t 0 - Disable.\n" 7762306a36Sopenharmony_ci "\t\t 1 - Enable. (Default)"); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistatic int ql4xsess_recovery_tmo = QL4_SESS_RECOVERY_TMO; 8062306a36Sopenharmony_cimodule_param(ql4xsess_recovery_tmo, int, S_IRUGO); 8162306a36Sopenharmony_ciMODULE_PARM_DESC(ql4xsess_recovery_tmo, 8262306a36Sopenharmony_ci " Target Session Recovery Timeout.\n" 8362306a36Sopenharmony_ci "\t\t Default: 120 sec."); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ciint ql4xmdcapmask = 0; 8662306a36Sopenharmony_cimodule_param(ql4xmdcapmask, int, S_IRUGO); 8762306a36Sopenharmony_ciMODULE_PARM_DESC(ql4xmdcapmask, 8862306a36Sopenharmony_ci " Set the Minidump driver capture mask level.\n" 8962306a36Sopenharmony_ci "\t\t Default is 0 (firmware default capture mask)\n" 9062306a36Sopenharmony_ci "\t\t Can be set to 0x3, 0x7, 0xF, 0x1F, 0x3F, 0x7F, 0xFF"); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ciint ql4xenablemd = 1; 9362306a36Sopenharmony_cimodule_param(ql4xenablemd, int, S_IRUGO | S_IWUSR); 9462306a36Sopenharmony_ciMODULE_PARM_DESC(ql4xenablemd, 9562306a36Sopenharmony_ci " Set to enable minidump.\n" 9662306a36Sopenharmony_ci "\t\t 0 - disable minidump\n" 9762306a36Sopenharmony_ci "\t\t 1 - enable minidump (Default)"); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistatic int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha); 10062306a36Sopenharmony_ci/* 10162306a36Sopenharmony_ci * SCSI host template entry points 10262306a36Sopenharmony_ci */ 10362306a36Sopenharmony_cistatic void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci/* 10662306a36Sopenharmony_ci * iSCSI template entry points 10762306a36Sopenharmony_ci */ 10862306a36Sopenharmony_cistatic int qla4xxx_session_get_param(struct iscsi_cls_session *cls_sess, 10962306a36Sopenharmony_ci enum iscsi_param param, char *buf); 11062306a36Sopenharmony_cistatic int qla4xxx_conn_get_param(struct iscsi_cls_conn *conn, 11162306a36Sopenharmony_ci enum iscsi_param param, char *buf); 11262306a36Sopenharmony_cistatic int qla4xxx_host_get_param(struct Scsi_Host *shost, 11362306a36Sopenharmony_ci enum iscsi_host_param param, char *buf); 11462306a36Sopenharmony_cistatic int qla4xxx_iface_set_param(struct Scsi_Host *shost, void *data, 11562306a36Sopenharmony_ci uint32_t len); 11662306a36Sopenharmony_cistatic int qla4xxx_get_iface_param(struct iscsi_iface *iface, 11762306a36Sopenharmony_ci enum iscsi_param_type param_type, 11862306a36Sopenharmony_ci int param, char *buf); 11962306a36Sopenharmony_cistatic enum scsi_timeout_action qla4xxx_eh_cmd_timed_out(struct scsi_cmnd *sc); 12062306a36Sopenharmony_cistatic struct iscsi_endpoint *qla4xxx_ep_connect(struct Scsi_Host *shost, 12162306a36Sopenharmony_ci struct sockaddr *dst_addr, 12262306a36Sopenharmony_ci int non_blocking); 12362306a36Sopenharmony_cistatic int qla4xxx_ep_poll(struct iscsi_endpoint *ep, int timeout_ms); 12462306a36Sopenharmony_cistatic void qla4xxx_ep_disconnect(struct iscsi_endpoint *ep); 12562306a36Sopenharmony_cistatic int qla4xxx_get_ep_param(struct iscsi_endpoint *ep, 12662306a36Sopenharmony_ci enum iscsi_param param, char *buf); 12762306a36Sopenharmony_cistatic int qla4xxx_conn_start(struct iscsi_cls_conn *conn); 12862306a36Sopenharmony_cistatic struct iscsi_cls_conn * 12962306a36Sopenharmony_ciqla4xxx_conn_create(struct iscsi_cls_session *cls_sess, uint32_t conn_idx); 13062306a36Sopenharmony_cistatic int qla4xxx_conn_bind(struct iscsi_cls_session *cls_session, 13162306a36Sopenharmony_ci struct iscsi_cls_conn *cls_conn, 13262306a36Sopenharmony_ci uint64_t transport_fd, int is_leading); 13362306a36Sopenharmony_cistatic void qla4xxx_conn_destroy(struct iscsi_cls_conn *conn); 13462306a36Sopenharmony_cistatic struct iscsi_cls_session * 13562306a36Sopenharmony_ciqla4xxx_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max, 13662306a36Sopenharmony_ci uint16_t qdepth, uint32_t initial_cmdsn); 13762306a36Sopenharmony_cistatic void qla4xxx_session_destroy(struct iscsi_cls_session *sess); 13862306a36Sopenharmony_cistatic void qla4xxx_task_work(struct work_struct *wdata); 13962306a36Sopenharmony_cistatic int qla4xxx_alloc_pdu(struct iscsi_task *, uint8_t); 14062306a36Sopenharmony_cistatic int qla4xxx_task_xmit(struct iscsi_task *); 14162306a36Sopenharmony_cistatic void qla4xxx_task_cleanup(struct iscsi_task *); 14262306a36Sopenharmony_cistatic void qla4xxx_fail_session(struct iscsi_cls_session *cls_session); 14362306a36Sopenharmony_cistatic void qla4xxx_conn_get_stats(struct iscsi_cls_conn *cls_conn, 14462306a36Sopenharmony_ci struct iscsi_stats *stats); 14562306a36Sopenharmony_cistatic int qla4xxx_send_ping(struct Scsi_Host *shost, uint32_t iface_num, 14662306a36Sopenharmony_ci uint32_t iface_type, uint32_t payload_size, 14762306a36Sopenharmony_ci uint32_t pid, struct sockaddr *dst_addr); 14862306a36Sopenharmony_cistatic int qla4xxx_get_chap_list(struct Scsi_Host *shost, uint16_t chap_tbl_idx, 14962306a36Sopenharmony_ci uint32_t *num_entries, char *buf); 15062306a36Sopenharmony_cistatic int qla4xxx_delete_chap(struct Scsi_Host *shost, uint16_t chap_tbl_idx); 15162306a36Sopenharmony_cistatic int qla4xxx_set_chap_entry(struct Scsi_Host *shost, void *data, 15262306a36Sopenharmony_ci int len); 15362306a36Sopenharmony_cistatic int qla4xxx_get_host_stats(struct Scsi_Host *shost, char *buf, int len); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci/* 15662306a36Sopenharmony_ci * SCSI host template entry points 15762306a36Sopenharmony_ci */ 15862306a36Sopenharmony_cistatic int qla4xxx_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *cmd); 15962306a36Sopenharmony_cistatic int qla4xxx_eh_abort(struct scsi_cmnd *cmd); 16062306a36Sopenharmony_cistatic int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd); 16162306a36Sopenharmony_cistatic int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd); 16262306a36Sopenharmony_cistatic int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd); 16362306a36Sopenharmony_cistatic int qla4xxx_slave_alloc(struct scsi_device *device); 16462306a36Sopenharmony_cistatic umode_t qla4_attr_is_visible(int param_type, int param); 16562306a36Sopenharmony_cistatic int qla4xxx_host_reset(struct Scsi_Host *shost, int reset_type); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci/* 16862306a36Sopenharmony_ci * iSCSI Flash DDB sysfs entry points 16962306a36Sopenharmony_ci */ 17062306a36Sopenharmony_cistatic int 17162306a36Sopenharmony_ciqla4xxx_sysfs_ddb_set_param(struct iscsi_bus_flash_session *fnode_sess, 17262306a36Sopenharmony_ci struct iscsi_bus_flash_conn *fnode_conn, 17362306a36Sopenharmony_ci void *data, int len); 17462306a36Sopenharmony_cistatic int 17562306a36Sopenharmony_ciqla4xxx_sysfs_ddb_get_param(struct iscsi_bus_flash_session *fnode_sess, 17662306a36Sopenharmony_ci int param, char *buf); 17762306a36Sopenharmony_cistatic int qla4xxx_sysfs_ddb_add(struct Scsi_Host *shost, const char *buf, 17862306a36Sopenharmony_ci int len); 17962306a36Sopenharmony_cistatic int 18062306a36Sopenharmony_ciqla4xxx_sysfs_ddb_delete(struct iscsi_bus_flash_session *fnode_sess); 18162306a36Sopenharmony_cistatic int qla4xxx_sysfs_ddb_login(struct iscsi_bus_flash_session *fnode_sess, 18262306a36Sopenharmony_ci struct iscsi_bus_flash_conn *fnode_conn); 18362306a36Sopenharmony_cistatic int qla4xxx_sysfs_ddb_logout(struct iscsi_bus_flash_session *fnode_sess, 18462306a36Sopenharmony_ci struct iscsi_bus_flash_conn *fnode_conn); 18562306a36Sopenharmony_cistatic int qla4xxx_sysfs_ddb_logout_sid(struct iscsi_cls_session *cls_sess); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_cistatic struct qla4_8xxx_legacy_intr_set legacy_intr[] = 18862306a36Sopenharmony_ci QLA82XX_LEGACY_INTR_CONFIG; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_cistatic const uint32_t qla4_82xx_reg_tbl[] = { 19162306a36Sopenharmony_ci QLA82XX_PEG_HALT_STATUS1, 19262306a36Sopenharmony_ci QLA82XX_PEG_HALT_STATUS2, 19362306a36Sopenharmony_ci QLA82XX_PEG_ALIVE_COUNTER, 19462306a36Sopenharmony_ci QLA82XX_CRB_DRV_ACTIVE, 19562306a36Sopenharmony_ci QLA82XX_CRB_DEV_STATE, 19662306a36Sopenharmony_ci QLA82XX_CRB_DRV_STATE, 19762306a36Sopenharmony_ci QLA82XX_CRB_DRV_SCRATCH, 19862306a36Sopenharmony_ci QLA82XX_CRB_DEV_PART_INFO, 19962306a36Sopenharmony_ci QLA82XX_CRB_DRV_IDC_VERSION, 20062306a36Sopenharmony_ci QLA82XX_FW_VERSION_MAJOR, 20162306a36Sopenharmony_ci QLA82XX_FW_VERSION_MINOR, 20262306a36Sopenharmony_ci QLA82XX_FW_VERSION_SUB, 20362306a36Sopenharmony_ci CRB_CMDPEG_STATE, 20462306a36Sopenharmony_ci CRB_TEMP_STATE, 20562306a36Sopenharmony_ci}; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_cistatic const uint32_t qla4_83xx_reg_tbl[] = { 20862306a36Sopenharmony_ci QLA83XX_PEG_HALT_STATUS1, 20962306a36Sopenharmony_ci QLA83XX_PEG_HALT_STATUS2, 21062306a36Sopenharmony_ci QLA83XX_PEG_ALIVE_COUNTER, 21162306a36Sopenharmony_ci QLA83XX_CRB_DRV_ACTIVE, 21262306a36Sopenharmony_ci QLA83XX_CRB_DEV_STATE, 21362306a36Sopenharmony_ci QLA83XX_CRB_DRV_STATE, 21462306a36Sopenharmony_ci QLA83XX_CRB_DRV_SCRATCH, 21562306a36Sopenharmony_ci QLA83XX_CRB_DEV_PART_INFO1, 21662306a36Sopenharmony_ci QLA83XX_CRB_IDC_VER_MAJOR, 21762306a36Sopenharmony_ci QLA83XX_FW_VER_MAJOR, 21862306a36Sopenharmony_ci QLA83XX_FW_VER_MINOR, 21962306a36Sopenharmony_ci QLA83XX_FW_VER_SUB, 22062306a36Sopenharmony_ci QLA83XX_CMDPEG_STATE, 22162306a36Sopenharmony_ci QLA83XX_ASIC_TEMP, 22262306a36Sopenharmony_ci}; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_cistatic struct scsi_host_template qla4xxx_driver_template = { 22562306a36Sopenharmony_ci .module = THIS_MODULE, 22662306a36Sopenharmony_ci .name = DRIVER_NAME, 22762306a36Sopenharmony_ci .proc_name = DRIVER_NAME, 22862306a36Sopenharmony_ci .queuecommand = qla4xxx_queuecommand, 22962306a36Sopenharmony_ci .cmd_size = sizeof(struct qla4xxx_cmd_priv), 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci .eh_abort_handler = qla4xxx_eh_abort, 23262306a36Sopenharmony_ci .eh_device_reset_handler = qla4xxx_eh_device_reset, 23362306a36Sopenharmony_ci .eh_target_reset_handler = qla4xxx_eh_target_reset, 23462306a36Sopenharmony_ci .eh_host_reset_handler = qla4xxx_eh_host_reset, 23562306a36Sopenharmony_ci .eh_timed_out = qla4xxx_eh_cmd_timed_out, 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci .slave_alloc = qla4xxx_slave_alloc, 23862306a36Sopenharmony_ci .change_queue_depth = scsi_change_queue_depth, 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci .this_id = -1, 24162306a36Sopenharmony_ci .cmd_per_lun = 3, 24262306a36Sopenharmony_ci .sg_tablesize = SG_ALL, 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci .max_sectors = 0xFFFF, 24562306a36Sopenharmony_ci .shost_groups = qla4xxx_host_groups, 24662306a36Sopenharmony_ci .host_reset = qla4xxx_host_reset, 24762306a36Sopenharmony_ci .vendor_id = SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_QLOGIC, 24862306a36Sopenharmony_ci}; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_cistatic struct iscsi_transport qla4xxx_iscsi_transport = { 25162306a36Sopenharmony_ci .owner = THIS_MODULE, 25262306a36Sopenharmony_ci .name = DRIVER_NAME, 25362306a36Sopenharmony_ci .caps = CAP_TEXT_NEGO | 25462306a36Sopenharmony_ci CAP_DATA_PATH_OFFLOAD | CAP_HDRDGST | 25562306a36Sopenharmony_ci CAP_DATADGST | CAP_LOGIN_OFFLOAD | 25662306a36Sopenharmony_ci CAP_MULTI_R2T, 25762306a36Sopenharmony_ci .attr_is_visible = qla4_attr_is_visible, 25862306a36Sopenharmony_ci .create_session = qla4xxx_session_create, 25962306a36Sopenharmony_ci .destroy_session = qla4xxx_session_destroy, 26062306a36Sopenharmony_ci .start_conn = qla4xxx_conn_start, 26162306a36Sopenharmony_ci .create_conn = qla4xxx_conn_create, 26262306a36Sopenharmony_ci .bind_conn = qla4xxx_conn_bind, 26362306a36Sopenharmony_ci .unbind_conn = iscsi_conn_unbind, 26462306a36Sopenharmony_ci .stop_conn = iscsi_conn_stop, 26562306a36Sopenharmony_ci .destroy_conn = qla4xxx_conn_destroy, 26662306a36Sopenharmony_ci .set_param = iscsi_set_param, 26762306a36Sopenharmony_ci .get_conn_param = qla4xxx_conn_get_param, 26862306a36Sopenharmony_ci .get_session_param = qla4xxx_session_get_param, 26962306a36Sopenharmony_ci .get_ep_param = qla4xxx_get_ep_param, 27062306a36Sopenharmony_ci .ep_connect = qla4xxx_ep_connect, 27162306a36Sopenharmony_ci .ep_poll = qla4xxx_ep_poll, 27262306a36Sopenharmony_ci .ep_disconnect = qla4xxx_ep_disconnect, 27362306a36Sopenharmony_ci .get_stats = qla4xxx_conn_get_stats, 27462306a36Sopenharmony_ci .send_pdu = iscsi_conn_send_pdu, 27562306a36Sopenharmony_ci .xmit_task = qla4xxx_task_xmit, 27662306a36Sopenharmony_ci .cleanup_task = qla4xxx_task_cleanup, 27762306a36Sopenharmony_ci .alloc_pdu = qla4xxx_alloc_pdu, 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci .get_host_param = qla4xxx_host_get_param, 28062306a36Sopenharmony_ci .set_iface_param = qla4xxx_iface_set_param, 28162306a36Sopenharmony_ci .get_iface_param = qla4xxx_get_iface_param, 28262306a36Sopenharmony_ci .bsg_request = qla4xxx_bsg_request, 28362306a36Sopenharmony_ci .send_ping = qla4xxx_send_ping, 28462306a36Sopenharmony_ci .get_chap = qla4xxx_get_chap_list, 28562306a36Sopenharmony_ci .delete_chap = qla4xxx_delete_chap, 28662306a36Sopenharmony_ci .set_chap = qla4xxx_set_chap_entry, 28762306a36Sopenharmony_ci .get_flashnode_param = qla4xxx_sysfs_ddb_get_param, 28862306a36Sopenharmony_ci .set_flashnode_param = qla4xxx_sysfs_ddb_set_param, 28962306a36Sopenharmony_ci .new_flashnode = qla4xxx_sysfs_ddb_add, 29062306a36Sopenharmony_ci .del_flashnode = qla4xxx_sysfs_ddb_delete, 29162306a36Sopenharmony_ci .login_flashnode = qla4xxx_sysfs_ddb_login, 29262306a36Sopenharmony_ci .logout_flashnode = qla4xxx_sysfs_ddb_logout, 29362306a36Sopenharmony_ci .logout_flashnode_sid = qla4xxx_sysfs_ddb_logout_sid, 29462306a36Sopenharmony_ci .get_host_stats = qla4xxx_get_host_stats, 29562306a36Sopenharmony_ci}; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_cistatic struct scsi_transport_template *qla4xxx_scsi_transport; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_cistatic int qla4xxx_isp_check_reg(struct scsi_qla_host *ha) 30062306a36Sopenharmony_ci{ 30162306a36Sopenharmony_ci u32 reg_val = 0; 30262306a36Sopenharmony_ci int rval = QLA_SUCCESS; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci if (is_qla8022(ha)) 30562306a36Sopenharmony_ci reg_val = readl(&ha->qla4_82xx_reg->host_status); 30662306a36Sopenharmony_ci else if (is_qla8032(ha) || is_qla8042(ha)) 30762306a36Sopenharmony_ci reg_val = qla4_8xxx_rd_direct(ha, QLA8XXX_PEG_ALIVE_COUNTER); 30862306a36Sopenharmony_ci else 30962306a36Sopenharmony_ci reg_val = readw(&ha->reg->ctrl_status); 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci if (reg_val == QL4_ISP_REG_DISCONNECT) 31262306a36Sopenharmony_ci rval = QLA_ERROR; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci return rval; 31562306a36Sopenharmony_ci} 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_cistatic int qla4xxx_send_ping(struct Scsi_Host *shost, uint32_t iface_num, 31862306a36Sopenharmony_ci uint32_t iface_type, uint32_t payload_size, 31962306a36Sopenharmony_ci uint32_t pid, struct sockaddr *dst_addr) 32062306a36Sopenharmony_ci{ 32162306a36Sopenharmony_ci struct scsi_qla_host *ha = to_qla_host(shost); 32262306a36Sopenharmony_ci struct sockaddr_in *addr; 32362306a36Sopenharmony_ci struct sockaddr_in6 *addr6; 32462306a36Sopenharmony_ci uint32_t options = 0; 32562306a36Sopenharmony_ci uint8_t ipaddr[IPv6_ADDR_LEN]; 32662306a36Sopenharmony_ci int rval; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci memset(ipaddr, 0, IPv6_ADDR_LEN); 32962306a36Sopenharmony_ci /* IPv4 to IPv4 */ 33062306a36Sopenharmony_ci if ((iface_type == ISCSI_IFACE_TYPE_IPV4) && 33162306a36Sopenharmony_ci (dst_addr->sa_family == AF_INET)) { 33262306a36Sopenharmony_ci addr = (struct sockaddr_in *)dst_addr; 33362306a36Sopenharmony_ci memcpy(ipaddr, &addr->sin_addr.s_addr, IP_ADDR_LEN); 33462306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "%s: IPv4 Ping src: %pI4 " 33562306a36Sopenharmony_ci "dest: %pI4\n", __func__, 33662306a36Sopenharmony_ci &ha->ip_config.ip_address, ipaddr)); 33762306a36Sopenharmony_ci rval = qla4xxx_ping_iocb(ha, options, payload_size, pid, 33862306a36Sopenharmony_ci ipaddr); 33962306a36Sopenharmony_ci if (rval) 34062306a36Sopenharmony_ci rval = -EINVAL; 34162306a36Sopenharmony_ci } else if ((iface_type == ISCSI_IFACE_TYPE_IPV6) && 34262306a36Sopenharmony_ci (dst_addr->sa_family == AF_INET6)) { 34362306a36Sopenharmony_ci /* IPv6 to IPv6 */ 34462306a36Sopenharmony_ci addr6 = (struct sockaddr_in6 *)dst_addr; 34562306a36Sopenharmony_ci memcpy(ipaddr, &addr6->sin6_addr.in6_u.u6_addr8, IPv6_ADDR_LEN); 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci options |= PING_IPV6_PROTOCOL_ENABLE; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci /* Ping using LinkLocal address */ 35062306a36Sopenharmony_ci if ((iface_num == 0) || (iface_num == 1)) { 35162306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "%s: LinkLocal Ping " 35262306a36Sopenharmony_ci "src: %pI6 dest: %pI6\n", __func__, 35362306a36Sopenharmony_ci &ha->ip_config.ipv6_link_local_addr, 35462306a36Sopenharmony_ci ipaddr)); 35562306a36Sopenharmony_ci options |= PING_IPV6_LINKLOCAL_ADDR; 35662306a36Sopenharmony_ci rval = qla4xxx_ping_iocb(ha, options, payload_size, 35762306a36Sopenharmony_ci pid, ipaddr); 35862306a36Sopenharmony_ci } else { 35962306a36Sopenharmony_ci ql4_printk(KERN_WARNING, ha, "%s: iface num = %d " 36062306a36Sopenharmony_ci "not supported\n", __func__, iface_num); 36162306a36Sopenharmony_ci rval = -ENOSYS; 36262306a36Sopenharmony_ci goto exit_send_ping; 36362306a36Sopenharmony_ci } 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci /* 36662306a36Sopenharmony_ci * If ping using LinkLocal address fails, try ping using 36762306a36Sopenharmony_ci * IPv6 address 36862306a36Sopenharmony_ci */ 36962306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 37062306a36Sopenharmony_ci options &= ~PING_IPV6_LINKLOCAL_ADDR; 37162306a36Sopenharmony_ci if (iface_num == 0) { 37262306a36Sopenharmony_ci options |= PING_IPV6_ADDR0; 37362306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "%s: IPv6 " 37462306a36Sopenharmony_ci "Ping src: %pI6 " 37562306a36Sopenharmony_ci "dest: %pI6\n", __func__, 37662306a36Sopenharmony_ci &ha->ip_config.ipv6_addr0, 37762306a36Sopenharmony_ci ipaddr)); 37862306a36Sopenharmony_ci } else if (iface_num == 1) { 37962306a36Sopenharmony_ci options |= PING_IPV6_ADDR1; 38062306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "%s: IPv6 " 38162306a36Sopenharmony_ci "Ping src: %pI6 " 38262306a36Sopenharmony_ci "dest: %pI6\n", __func__, 38362306a36Sopenharmony_ci &ha->ip_config.ipv6_addr1, 38462306a36Sopenharmony_ci ipaddr)); 38562306a36Sopenharmony_ci } 38662306a36Sopenharmony_ci rval = qla4xxx_ping_iocb(ha, options, payload_size, 38762306a36Sopenharmony_ci pid, ipaddr); 38862306a36Sopenharmony_ci if (rval) 38962306a36Sopenharmony_ci rval = -EINVAL; 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci } else 39262306a36Sopenharmony_ci rval = -ENOSYS; 39362306a36Sopenharmony_ciexit_send_ping: 39462306a36Sopenharmony_ci return rval; 39562306a36Sopenharmony_ci} 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_cistatic umode_t qla4_attr_is_visible(int param_type, int param) 39862306a36Sopenharmony_ci{ 39962306a36Sopenharmony_ci switch (param_type) { 40062306a36Sopenharmony_ci case ISCSI_HOST_PARAM: 40162306a36Sopenharmony_ci switch (param) { 40262306a36Sopenharmony_ci case ISCSI_HOST_PARAM_HWADDRESS: 40362306a36Sopenharmony_ci case ISCSI_HOST_PARAM_IPADDRESS: 40462306a36Sopenharmony_ci case ISCSI_HOST_PARAM_INITIATOR_NAME: 40562306a36Sopenharmony_ci case ISCSI_HOST_PARAM_PORT_STATE: 40662306a36Sopenharmony_ci case ISCSI_HOST_PARAM_PORT_SPEED: 40762306a36Sopenharmony_ci return S_IRUGO; 40862306a36Sopenharmony_ci default: 40962306a36Sopenharmony_ci return 0; 41062306a36Sopenharmony_ci } 41162306a36Sopenharmony_ci case ISCSI_PARAM: 41262306a36Sopenharmony_ci switch (param) { 41362306a36Sopenharmony_ci case ISCSI_PARAM_PERSISTENT_ADDRESS: 41462306a36Sopenharmony_ci case ISCSI_PARAM_PERSISTENT_PORT: 41562306a36Sopenharmony_ci case ISCSI_PARAM_CONN_ADDRESS: 41662306a36Sopenharmony_ci case ISCSI_PARAM_CONN_PORT: 41762306a36Sopenharmony_ci case ISCSI_PARAM_TARGET_NAME: 41862306a36Sopenharmony_ci case ISCSI_PARAM_TPGT: 41962306a36Sopenharmony_ci case ISCSI_PARAM_TARGET_ALIAS: 42062306a36Sopenharmony_ci case ISCSI_PARAM_MAX_BURST: 42162306a36Sopenharmony_ci case ISCSI_PARAM_MAX_R2T: 42262306a36Sopenharmony_ci case ISCSI_PARAM_FIRST_BURST: 42362306a36Sopenharmony_ci case ISCSI_PARAM_MAX_RECV_DLENGTH: 42462306a36Sopenharmony_ci case ISCSI_PARAM_MAX_XMIT_DLENGTH: 42562306a36Sopenharmony_ci case ISCSI_PARAM_IFACE_NAME: 42662306a36Sopenharmony_ci case ISCSI_PARAM_CHAP_OUT_IDX: 42762306a36Sopenharmony_ci case ISCSI_PARAM_CHAP_IN_IDX: 42862306a36Sopenharmony_ci case ISCSI_PARAM_USERNAME: 42962306a36Sopenharmony_ci case ISCSI_PARAM_PASSWORD: 43062306a36Sopenharmony_ci case ISCSI_PARAM_USERNAME_IN: 43162306a36Sopenharmony_ci case ISCSI_PARAM_PASSWORD_IN: 43262306a36Sopenharmony_ci case ISCSI_PARAM_AUTO_SND_TGT_DISABLE: 43362306a36Sopenharmony_ci case ISCSI_PARAM_DISCOVERY_SESS: 43462306a36Sopenharmony_ci case ISCSI_PARAM_PORTAL_TYPE: 43562306a36Sopenharmony_ci case ISCSI_PARAM_CHAP_AUTH_EN: 43662306a36Sopenharmony_ci case ISCSI_PARAM_DISCOVERY_LOGOUT_EN: 43762306a36Sopenharmony_ci case ISCSI_PARAM_BIDI_CHAP_EN: 43862306a36Sopenharmony_ci case ISCSI_PARAM_DISCOVERY_AUTH_OPTIONAL: 43962306a36Sopenharmony_ci case ISCSI_PARAM_DEF_TIME2WAIT: 44062306a36Sopenharmony_ci case ISCSI_PARAM_DEF_TIME2RETAIN: 44162306a36Sopenharmony_ci case ISCSI_PARAM_HDRDGST_EN: 44262306a36Sopenharmony_ci case ISCSI_PARAM_DATADGST_EN: 44362306a36Sopenharmony_ci case ISCSI_PARAM_INITIAL_R2T_EN: 44462306a36Sopenharmony_ci case ISCSI_PARAM_IMM_DATA_EN: 44562306a36Sopenharmony_ci case ISCSI_PARAM_PDU_INORDER_EN: 44662306a36Sopenharmony_ci case ISCSI_PARAM_DATASEQ_INORDER_EN: 44762306a36Sopenharmony_ci case ISCSI_PARAM_MAX_SEGMENT_SIZE: 44862306a36Sopenharmony_ci case ISCSI_PARAM_TCP_TIMESTAMP_STAT: 44962306a36Sopenharmony_ci case ISCSI_PARAM_TCP_WSF_DISABLE: 45062306a36Sopenharmony_ci case ISCSI_PARAM_TCP_NAGLE_DISABLE: 45162306a36Sopenharmony_ci case ISCSI_PARAM_TCP_TIMER_SCALE: 45262306a36Sopenharmony_ci case ISCSI_PARAM_TCP_TIMESTAMP_EN: 45362306a36Sopenharmony_ci case ISCSI_PARAM_TCP_XMIT_WSF: 45462306a36Sopenharmony_ci case ISCSI_PARAM_TCP_RECV_WSF: 45562306a36Sopenharmony_ci case ISCSI_PARAM_IP_FRAGMENT_DISABLE: 45662306a36Sopenharmony_ci case ISCSI_PARAM_IPV4_TOS: 45762306a36Sopenharmony_ci case ISCSI_PARAM_IPV6_TC: 45862306a36Sopenharmony_ci case ISCSI_PARAM_IPV6_FLOW_LABEL: 45962306a36Sopenharmony_ci case ISCSI_PARAM_IS_FW_ASSIGNED_IPV6: 46062306a36Sopenharmony_ci case ISCSI_PARAM_KEEPALIVE_TMO: 46162306a36Sopenharmony_ci case ISCSI_PARAM_LOCAL_PORT: 46262306a36Sopenharmony_ci case ISCSI_PARAM_ISID: 46362306a36Sopenharmony_ci case ISCSI_PARAM_TSID: 46462306a36Sopenharmony_ci case ISCSI_PARAM_DEF_TASKMGMT_TMO: 46562306a36Sopenharmony_ci case ISCSI_PARAM_ERL: 46662306a36Sopenharmony_ci case ISCSI_PARAM_STATSN: 46762306a36Sopenharmony_ci case ISCSI_PARAM_EXP_STATSN: 46862306a36Sopenharmony_ci case ISCSI_PARAM_DISCOVERY_PARENT_IDX: 46962306a36Sopenharmony_ci case ISCSI_PARAM_DISCOVERY_PARENT_TYPE: 47062306a36Sopenharmony_ci case ISCSI_PARAM_LOCAL_IPADDR: 47162306a36Sopenharmony_ci return S_IRUGO; 47262306a36Sopenharmony_ci default: 47362306a36Sopenharmony_ci return 0; 47462306a36Sopenharmony_ci } 47562306a36Sopenharmony_ci case ISCSI_NET_PARAM: 47662306a36Sopenharmony_ci switch (param) { 47762306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV4_ADDR: 47862306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV4_SUBNET: 47962306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV4_GW: 48062306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV4_BOOTPROTO: 48162306a36Sopenharmony_ci case ISCSI_NET_PARAM_IFACE_ENABLE: 48262306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV6_LINKLOCAL: 48362306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV6_ADDR: 48462306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV6_ROUTER: 48562306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG: 48662306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG: 48762306a36Sopenharmony_ci case ISCSI_NET_PARAM_VLAN_ID: 48862306a36Sopenharmony_ci case ISCSI_NET_PARAM_VLAN_PRIORITY: 48962306a36Sopenharmony_ci case ISCSI_NET_PARAM_VLAN_ENABLED: 49062306a36Sopenharmony_ci case ISCSI_NET_PARAM_MTU: 49162306a36Sopenharmony_ci case ISCSI_NET_PARAM_PORT: 49262306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPADDR_STATE: 49362306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV6_LINKLOCAL_STATE: 49462306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV6_ROUTER_STATE: 49562306a36Sopenharmony_ci case ISCSI_NET_PARAM_DELAYED_ACK_EN: 49662306a36Sopenharmony_ci case ISCSI_NET_PARAM_TCP_NAGLE_DISABLE: 49762306a36Sopenharmony_ci case ISCSI_NET_PARAM_TCP_WSF_DISABLE: 49862306a36Sopenharmony_ci case ISCSI_NET_PARAM_TCP_WSF: 49962306a36Sopenharmony_ci case ISCSI_NET_PARAM_TCP_TIMER_SCALE: 50062306a36Sopenharmony_ci case ISCSI_NET_PARAM_TCP_TIMESTAMP_EN: 50162306a36Sopenharmony_ci case ISCSI_NET_PARAM_CACHE_ID: 50262306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV4_DHCP_DNS_ADDR_EN: 50362306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV4_DHCP_SLP_DA_EN: 50462306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV4_TOS_EN: 50562306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV4_TOS: 50662306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV4_GRAT_ARP_EN: 50762306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV4_DHCP_ALT_CLIENT_ID_EN: 50862306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV4_DHCP_ALT_CLIENT_ID: 50962306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV4_DHCP_REQ_VENDOR_ID_EN: 51062306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV4_DHCP_USE_VENDOR_ID_EN: 51162306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV4_DHCP_VENDOR_ID: 51262306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV4_DHCP_LEARN_IQN_EN: 51362306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV4_FRAGMENT_DISABLE: 51462306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV4_IN_FORWARD_EN: 51562306a36Sopenharmony_ci case ISCSI_NET_PARAM_REDIRECT_EN: 51662306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV4_TTL: 51762306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV6_GRAT_NEIGHBOR_ADV_EN: 51862306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV6_MLD_EN: 51962306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV6_FLOW_LABEL: 52062306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV6_TRAFFIC_CLASS: 52162306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV6_HOP_LIMIT: 52262306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV6_ND_REACHABLE_TMO: 52362306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV6_ND_REXMIT_TIME: 52462306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV6_ND_STALE_TMO: 52562306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV6_DUP_ADDR_DETECT_CNT: 52662306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV6_RTR_ADV_LINK_MTU: 52762306a36Sopenharmony_ci return S_IRUGO; 52862306a36Sopenharmony_ci default: 52962306a36Sopenharmony_ci return 0; 53062306a36Sopenharmony_ci } 53162306a36Sopenharmony_ci case ISCSI_IFACE_PARAM: 53262306a36Sopenharmony_ci switch (param) { 53362306a36Sopenharmony_ci case ISCSI_IFACE_PARAM_DEF_TASKMGMT_TMO: 53462306a36Sopenharmony_ci case ISCSI_IFACE_PARAM_HDRDGST_EN: 53562306a36Sopenharmony_ci case ISCSI_IFACE_PARAM_DATADGST_EN: 53662306a36Sopenharmony_ci case ISCSI_IFACE_PARAM_IMM_DATA_EN: 53762306a36Sopenharmony_ci case ISCSI_IFACE_PARAM_INITIAL_R2T_EN: 53862306a36Sopenharmony_ci case ISCSI_IFACE_PARAM_DATASEQ_INORDER_EN: 53962306a36Sopenharmony_ci case ISCSI_IFACE_PARAM_PDU_INORDER_EN: 54062306a36Sopenharmony_ci case ISCSI_IFACE_PARAM_ERL: 54162306a36Sopenharmony_ci case ISCSI_IFACE_PARAM_MAX_RECV_DLENGTH: 54262306a36Sopenharmony_ci case ISCSI_IFACE_PARAM_FIRST_BURST: 54362306a36Sopenharmony_ci case ISCSI_IFACE_PARAM_MAX_R2T: 54462306a36Sopenharmony_ci case ISCSI_IFACE_PARAM_MAX_BURST: 54562306a36Sopenharmony_ci case ISCSI_IFACE_PARAM_CHAP_AUTH_EN: 54662306a36Sopenharmony_ci case ISCSI_IFACE_PARAM_BIDI_CHAP_EN: 54762306a36Sopenharmony_ci case ISCSI_IFACE_PARAM_DISCOVERY_AUTH_OPTIONAL: 54862306a36Sopenharmony_ci case ISCSI_IFACE_PARAM_DISCOVERY_LOGOUT_EN: 54962306a36Sopenharmony_ci case ISCSI_IFACE_PARAM_STRICT_LOGIN_COMP_EN: 55062306a36Sopenharmony_ci case ISCSI_IFACE_PARAM_INITIATOR_NAME: 55162306a36Sopenharmony_ci return S_IRUGO; 55262306a36Sopenharmony_ci default: 55362306a36Sopenharmony_ci return 0; 55462306a36Sopenharmony_ci } 55562306a36Sopenharmony_ci case ISCSI_FLASHNODE_PARAM: 55662306a36Sopenharmony_ci switch (param) { 55762306a36Sopenharmony_ci case ISCSI_FLASHNODE_IS_FW_ASSIGNED_IPV6: 55862306a36Sopenharmony_ci case ISCSI_FLASHNODE_PORTAL_TYPE: 55962306a36Sopenharmony_ci case ISCSI_FLASHNODE_AUTO_SND_TGT_DISABLE: 56062306a36Sopenharmony_ci case ISCSI_FLASHNODE_DISCOVERY_SESS: 56162306a36Sopenharmony_ci case ISCSI_FLASHNODE_ENTRY_EN: 56262306a36Sopenharmony_ci case ISCSI_FLASHNODE_HDR_DGST_EN: 56362306a36Sopenharmony_ci case ISCSI_FLASHNODE_DATA_DGST_EN: 56462306a36Sopenharmony_ci case ISCSI_FLASHNODE_IMM_DATA_EN: 56562306a36Sopenharmony_ci case ISCSI_FLASHNODE_INITIAL_R2T_EN: 56662306a36Sopenharmony_ci case ISCSI_FLASHNODE_DATASEQ_INORDER: 56762306a36Sopenharmony_ci case ISCSI_FLASHNODE_PDU_INORDER: 56862306a36Sopenharmony_ci case ISCSI_FLASHNODE_CHAP_AUTH_EN: 56962306a36Sopenharmony_ci case ISCSI_FLASHNODE_SNACK_REQ_EN: 57062306a36Sopenharmony_ci case ISCSI_FLASHNODE_DISCOVERY_LOGOUT_EN: 57162306a36Sopenharmony_ci case ISCSI_FLASHNODE_BIDI_CHAP_EN: 57262306a36Sopenharmony_ci case ISCSI_FLASHNODE_DISCOVERY_AUTH_OPTIONAL: 57362306a36Sopenharmony_ci case ISCSI_FLASHNODE_ERL: 57462306a36Sopenharmony_ci case ISCSI_FLASHNODE_TCP_TIMESTAMP_STAT: 57562306a36Sopenharmony_ci case ISCSI_FLASHNODE_TCP_NAGLE_DISABLE: 57662306a36Sopenharmony_ci case ISCSI_FLASHNODE_TCP_WSF_DISABLE: 57762306a36Sopenharmony_ci case ISCSI_FLASHNODE_TCP_TIMER_SCALE: 57862306a36Sopenharmony_ci case ISCSI_FLASHNODE_TCP_TIMESTAMP_EN: 57962306a36Sopenharmony_ci case ISCSI_FLASHNODE_IP_FRAG_DISABLE: 58062306a36Sopenharmony_ci case ISCSI_FLASHNODE_MAX_RECV_DLENGTH: 58162306a36Sopenharmony_ci case ISCSI_FLASHNODE_MAX_XMIT_DLENGTH: 58262306a36Sopenharmony_ci case ISCSI_FLASHNODE_FIRST_BURST: 58362306a36Sopenharmony_ci case ISCSI_FLASHNODE_DEF_TIME2WAIT: 58462306a36Sopenharmony_ci case ISCSI_FLASHNODE_DEF_TIME2RETAIN: 58562306a36Sopenharmony_ci case ISCSI_FLASHNODE_MAX_R2T: 58662306a36Sopenharmony_ci case ISCSI_FLASHNODE_KEEPALIVE_TMO: 58762306a36Sopenharmony_ci case ISCSI_FLASHNODE_ISID: 58862306a36Sopenharmony_ci case ISCSI_FLASHNODE_TSID: 58962306a36Sopenharmony_ci case ISCSI_FLASHNODE_PORT: 59062306a36Sopenharmony_ci case ISCSI_FLASHNODE_MAX_BURST: 59162306a36Sopenharmony_ci case ISCSI_FLASHNODE_DEF_TASKMGMT_TMO: 59262306a36Sopenharmony_ci case ISCSI_FLASHNODE_IPADDR: 59362306a36Sopenharmony_ci case ISCSI_FLASHNODE_ALIAS: 59462306a36Sopenharmony_ci case ISCSI_FLASHNODE_REDIRECT_IPADDR: 59562306a36Sopenharmony_ci case ISCSI_FLASHNODE_MAX_SEGMENT_SIZE: 59662306a36Sopenharmony_ci case ISCSI_FLASHNODE_LOCAL_PORT: 59762306a36Sopenharmony_ci case ISCSI_FLASHNODE_IPV4_TOS: 59862306a36Sopenharmony_ci case ISCSI_FLASHNODE_IPV6_TC: 59962306a36Sopenharmony_ci case ISCSI_FLASHNODE_IPV6_FLOW_LABEL: 60062306a36Sopenharmony_ci case ISCSI_FLASHNODE_NAME: 60162306a36Sopenharmony_ci case ISCSI_FLASHNODE_TPGT: 60262306a36Sopenharmony_ci case ISCSI_FLASHNODE_LINK_LOCAL_IPV6: 60362306a36Sopenharmony_ci case ISCSI_FLASHNODE_DISCOVERY_PARENT_IDX: 60462306a36Sopenharmony_ci case ISCSI_FLASHNODE_DISCOVERY_PARENT_TYPE: 60562306a36Sopenharmony_ci case ISCSI_FLASHNODE_TCP_XMIT_WSF: 60662306a36Sopenharmony_ci case ISCSI_FLASHNODE_TCP_RECV_WSF: 60762306a36Sopenharmony_ci case ISCSI_FLASHNODE_CHAP_OUT_IDX: 60862306a36Sopenharmony_ci case ISCSI_FLASHNODE_USERNAME: 60962306a36Sopenharmony_ci case ISCSI_FLASHNODE_PASSWORD: 61062306a36Sopenharmony_ci case ISCSI_FLASHNODE_STATSN: 61162306a36Sopenharmony_ci case ISCSI_FLASHNODE_EXP_STATSN: 61262306a36Sopenharmony_ci case ISCSI_FLASHNODE_IS_BOOT_TGT: 61362306a36Sopenharmony_ci return S_IRUGO; 61462306a36Sopenharmony_ci default: 61562306a36Sopenharmony_ci return 0; 61662306a36Sopenharmony_ci } 61762306a36Sopenharmony_ci } 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci return 0; 62062306a36Sopenharmony_ci} 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci/** 62362306a36Sopenharmony_ci * qla4xxx_create_chap_list - Create CHAP list from FLASH 62462306a36Sopenharmony_ci * @ha: pointer to adapter structure 62562306a36Sopenharmony_ci * 62662306a36Sopenharmony_ci * Read flash and make a list of CHAP entries, during login when a CHAP entry 62762306a36Sopenharmony_ci * is received, it will be checked in this list. If entry exist then the CHAP 62862306a36Sopenharmony_ci * entry index is set in the DDB. If CHAP entry does not exist in this list 62962306a36Sopenharmony_ci * then a new entry is added in FLASH in CHAP table and the index obtained is 63062306a36Sopenharmony_ci * used in the DDB. 63162306a36Sopenharmony_ci **/ 63262306a36Sopenharmony_cistatic void qla4xxx_create_chap_list(struct scsi_qla_host *ha) 63362306a36Sopenharmony_ci{ 63462306a36Sopenharmony_ci int rval = 0; 63562306a36Sopenharmony_ci uint8_t *chap_flash_data = NULL; 63662306a36Sopenharmony_ci uint32_t offset; 63762306a36Sopenharmony_ci dma_addr_t chap_dma; 63862306a36Sopenharmony_ci uint32_t chap_size = 0; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci if (is_qla40XX(ha)) 64162306a36Sopenharmony_ci chap_size = MAX_CHAP_ENTRIES_40XX * 64262306a36Sopenharmony_ci sizeof(struct ql4_chap_table); 64362306a36Sopenharmony_ci else /* Single region contains CHAP info for both 64462306a36Sopenharmony_ci * ports which is divided into half for each port. 64562306a36Sopenharmony_ci */ 64662306a36Sopenharmony_ci chap_size = ha->hw.flt_chap_size / 2; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci chap_flash_data = dma_alloc_coherent(&ha->pdev->dev, chap_size, 64962306a36Sopenharmony_ci &chap_dma, GFP_KERNEL); 65062306a36Sopenharmony_ci if (!chap_flash_data) { 65162306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "No memory for chap_flash_data\n"); 65262306a36Sopenharmony_ci return; 65362306a36Sopenharmony_ci } 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci if (is_qla40XX(ha)) { 65662306a36Sopenharmony_ci offset = FLASH_CHAP_OFFSET; 65762306a36Sopenharmony_ci } else { 65862306a36Sopenharmony_ci offset = FLASH_RAW_ACCESS_ADDR + (ha->hw.flt_region_chap << 2); 65962306a36Sopenharmony_ci if (ha->port_num == 1) 66062306a36Sopenharmony_ci offset += chap_size; 66162306a36Sopenharmony_ci } 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci rval = qla4xxx_get_flash(ha, chap_dma, offset, chap_size); 66462306a36Sopenharmony_ci if (rval != QLA_SUCCESS) 66562306a36Sopenharmony_ci goto exit_chap_list; 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci if (ha->chap_list == NULL) 66862306a36Sopenharmony_ci ha->chap_list = vmalloc(chap_size); 66962306a36Sopenharmony_ci if (ha->chap_list == NULL) { 67062306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "No memory for ha->chap_list\n"); 67162306a36Sopenharmony_ci goto exit_chap_list; 67262306a36Sopenharmony_ci } 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci memcpy(ha->chap_list, chap_flash_data, chap_size); 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ciexit_chap_list: 67762306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, chap_size, chap_flash_data, chap_dma); 67862306a36Sopenharmony_ci} 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_cistatic int qla4xxx_get_chap_by_index(struct scsi_qla_host *ha, 68162306a36Sopenharmony_ci int16_t chap_index, 68262306a36Sopenharmony_ci struct ql4_chap_table **chap_entry) 68362306a36Sopenharmony_ci{ 68462306a36Sopenharmony_ci int rval = QLA_ERROR; 68562306a36Sopenharmony_ci int max_chap_entries; 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci if (!ha->chap_list) { 68862306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "CHAP table cache is empty!\n"); 68962306a36Sopenharmony_ci goto exit_get_chap; 69062306a36Sopenharmony_ci } 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci if (is_qla80XX(ha)) 69362306a36Sopenharmony_ci max_chap_entries = (ha->hw.flt_chap_size / 2) / 69462306a36Sopenharmony_ci sizeof(struct ql4_chap_table); 69562306a36Sopenharmony_ci else 69662306a36Sopenharmony_ci max_chap_entries = MAX_CHAP_ENTRIES_40XX; 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci if (chap_index > max_chap_entries) { 69962306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "Invalid Chap index\n"); 70062306a36Sopenharmony_ci goto exit_get_chap; 70162306a36Sopenharmony_ci } 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci *chap_entry = (struct ql4_chap_table *)ha->chap_list + chap_index; 70462306a36Sopenharmony_ci if ((*chap_entry)->cookie != 70562306a36Sopenharmony_ci cpu_to_le16(CHAP_VALID_COOKIE)) { 70662306a36Sopenharmony_ci *chap_entry = NULL; 70762306a36Sopenharmony_ci } else { 70862306a36Sopenharmony_ci rval = QLA_SUCCESS; 70962306a36Sopenharmony_ci } 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ciexit_get_chap: 71262306a36Sopenharmony_ci return rval; 71362306a36Sopenharmony_ci} 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci/** 71662306a36Sopenharmony_ci * qla4xxx_find_free_chap_index - Find the first free chap index 71762306a36Sopenharmony_ci * @ha: pointer to adapter structure 71862306a36Sopenharmony_ci * @chap_index: CHAP index to be returned 71962306a36Sopenharmony_ci * 72062306a36Sopenharmony_ci * Find the first free chap index available in the chap table 72162306a36Sopenharmony_ci * 72262306a36Sopenharmony_ci * Note: Caller should acquire the chap lock before getting here. 72362306a36Sopenharmony_ci **/ 72462306a36Sopenharmony_cistatic int qla4xxx_find_free_chap_index(struct scsi_qla_host *ha, 72562306a36Sopenharmony_ci uint16_t *chap_index) 72662306a36Sopenharmony_ci{ 72762306a36Sopenharmony_ci int i, rval; 72862306a36Sopenharmony_ci int free_index = -1; 72962306a36Sopenharmony_ci int max_chap_entries = 0; 73062306a36Sopenharmony_ci struct ql4_chap_table *chap_table; 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci if (is_qla80XX(ha)) 73362306a36Sopenharmony_ci max_chap_entries = (ha->hw.flt_chap_size / 2) / 73462306a36Sopenharmony_ci sizeof(struct ql4_chap_table); 73562306a36Sopenharmony_ci else 73662306a36Sopenharmony_ci max_chap_entries = MAX_CHAP_ENTRIES_40XX; 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci if (!ha->chap_list) { 73962306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "CHAP table cache is empty!\n"); 74062306a36Sopenharmony_ci rval = QLA_ERROR; 74162306a36Sopenharmony_ci goto exit_find_chap; 74262306a36Sopenharmony_ci } 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci for (i = 0; i < max_chap_entries; i++) { 74562306a36Sopenharmony_ci chap_table = (struct ql4_chap_table *)ha->chap_list + i; 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci if ((chap_table->cookie != 74862306a36Sopenharmony_ci cpu_to_le16(CHAP_VALID_COOKIE)) && 74962306a36Sopenharmony_ci (i > MAX_RESRV_CHAP_IDX)) { 75062306a36Sopenharmony_ci free_index = i; 75162306a36Sopenharmony_ci break; 75262306a36Sopenharmony_ci } 75362306a36Sopenharmony_ci } 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci if (free_index != -1) { 75662306a36Sopenharmony_ci *chap_index = free_index; 75762306a36Sopenharmony_ci rval = QLA_SUCCESS; 75862306a36Sopenharmony_ci } else { 75962306a36Sopenharmony_ci rval = QLA_ERROR; 76062306a36Sopenharmony_ci } 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ciexit_find_chap: 76362306a36Sopenharmony_ci return rval; 76462306a36Sopenharmony_ci} 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_cistatic int qla4xxx_get_chap_list(struct Scsi_Host *shost, uint16_t chap_tbl_idx, 76762306a36Sopenharmony_ci uint32_t *num_entries, char *buf) 76862306a36Sopenharmony_ci{ 76962306a36Sopenharmony_ci struct scsi_qla_host *ha = to_qla_host(shost); 77062306a36Sopenharmony_ci struct ql4_chap_table *chap_table; 77162306a36Sopenharmony_ci struct iscsi_chap_rec *chap_rec; 77262306a36Sopenharmony_ci int max_chap_entries = 0; 77362306a36Sopenharmony_ci int valid_chap_entries = 0; 77462306a36Sopenharmony_ci int ret = 0, i; 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci if (is_qla80XX(ha)) 77762306a36Sopenharmony_ci max_chap_entries = (ha->hw.flt_chap_size / 2) / 77862306a36Sopenharmony_ci sizeof(struct ql4_chap_table); 77962306a36Sopenharmony_ci else 78062306a36Sopenharmony_ci max_chap_entries = MAX_CHAP_ENTRIES_40XX; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "%s: num_entries = %d, CHAP idx = %d\n", 78362306a36Sopenharmony_ci __func__, *num_entries, chap_tbl_idx); 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci if (!buf) { 78662306a36Sopenharmony_ci ret = -ENOMEM; 78762306a36Sopenharmony_ci goto exit_get_chap_list; 78862306a36Sopenharmony_ci } 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci qla4xxx_create_chap_list(ha); 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci chap_rec = (struct iscsi_chap_rec *) buf; 79362306a36Sopenharmony_ci mutex_lock(&ha->chap_sem); 79462306a36Sopenharmony_ci for (i = chap_tbl_idx; i < max_chap_entries; i++) { 79562306a36Sopenharmony_ci chap_table = (struct ql4_chap_table *)ha->chap_list + i; 79662306a36Sopenharmony_ci if (chap_table->cookie != 79762306a36Sopenharmony_ci cpu_to_le16(CHAP_VALID_COOKIE)) 79862306a36Sopenharmony_ci continue; 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci chap_rec->chap_tbl_idx = i; 80162306a36Sopenharmony_ci strscpy(chap_rec->username, chap_table->name, 80262306a36Sopenharmony_ci ISCSI_CHAP_AUTH_NAME_MAX_LEN); 80362306a36Sopenharmony_ci strscpy(chap_rec->password, chap_table->secret, 80462306a36Sopenharmony_ci QL4_CHAP_MAX_SECRET_LEN); 80562306a36Sopenharmony_ci chap_rec->password_length = chap_table->secret_len; 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci if (chap_table->flags & BIT_7) /* local */ 80862306a36Sopenharmony_ci chap_rec->chap_type = CHAP_TYPE_OUT; 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci if (chap_table->flags & BIT_6) /* peer */ 81162306a36Sopenharmony_ci chap_rec->chap_type = CHAP_TYPE_IN; 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci chap_rec++; 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci valid_chap_entries++; 81662306a36Sopenharmony_ci if (valid_chap_entries == *num_entries) 81762306a36Sopenharmony_ci break; 81862306a36Sopenharmony_ci } 81962306a36Sopenharmony_ci mutex_unlock(&ha->chap_sem); 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ciexit_get_chap_list: 82262306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "%s: Valid CHAP Entries = %d\n", 82362306a36Sopenharmony_ci __func__, valid_chap_entries); 82462306a36Sopenharmony_ci *num_entries = valid_chap_entries; 82562306a36Sopenharmony_ci return ret; 82662306a36Sopenharmony_ci} 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_cistatic int __qla4xxx_is_chap_active(struct device *dev, void *data) 82962306a36Sopenharmony_ci{ 83062306a36Sopenharmony_ci int ret = 0; 83162306a36Sopenharmony_ci uint16_t *chap_tbl_idx = (uint16_t *) data; 83262306a36Sopenharmony_ci struct iscsi_cls_session *cls_session; 83362306a36Sopenharmony_ci struct iscsi_session *sess; 83462306a36Sopenharmony_ci struct ddb_entry *ddb_entry; 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci if (!iscsi_is_session_dev(dev)) 83762306a36Sopenharmony_ci goto exit_is_chap_active; 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci cls_session = iscsi_dev_to_session(dev); 84062306a36Sopenharmony_ci sess = cls_session->dd_data; 84162306a36Sopenharmony_ci ddb_entry = sess->dd_data; 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci if (iscsi_is_session_online(cls_session)) 84462306a36Sopenharmony_ci goto exit_is_chap_active; 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci if (ddb_entry->chap_tbl_idx == *chap_tbl_idx) 84762306a36Sopenharmony_ci ret = 1; 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ciexit_is_chap_active: 85062306a36Sopenharmony_ci return ret; 85162306a36Sopenharmony_ci} 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_cistatic int qla4xxx_is_chap_active(struct Scsi_Host *shost, 85462306a36Sopenharmony_ci uint16_t chap_tbl_idx) 85562306a36Sopenharmony_ci{ 85662306a36Sopenharmony_ci int ret = 0; 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci ret = device_for_each_child(&shost->shost_gendev, &chap_tbl_idx, 85962306a36Sopenharmony_ci __qla4xxx_is_chap_active); 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci return ret; 86262306a36Sopenharmony_ci} 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_cistatic int qla4xxx_delete_chap(struct Scsi_Host *shost, uint16_t chap_tbl_idx) 86562306a36Sopenharmony_ci{ 86662306a36Sopenharmony_ci struct scsi_qla_host *ha = to_qla_host(shost); 86762306a36Sopenharmony_ci struct ql4_chap_table *chap_table; 86862306a36Sopenharmony_ci dma_addr_t chap_dma; 86962306a36Sopenharmony_ci int max_chap_entries = 0; 87062306a36Sopenharmony_ci uint32_t offset = 0; 87162306a36Sopenharmony_ci uint32_t chap_size; 87262306a36Sopenharmony_ci int ret = 0; 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci chap_table = dma_pool_zalloc(ha->chap_dma_pool, GFP_KERNEL, &chap_dma); 87562306a36Sopenharmony_ci if (chap_table == NULL) 87662306a36Sopenharmony_ci return -ENOMEM; 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci if (is_qla80XX(ha)) 87962306a36Sopenharmony_ci max_chap_entries = (ha->hw.flt_chap_size / 2) / 88062306a36Sopenharmony_ci sizeof(struct ql4_chap_table); 88162306a36Sopenharmony_ci else 88262306a36Sopenharmony_ci max_chap_entries = MAX_CHAP_ENTRIES_40XX; 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci if (chap_tbl_idx > max_chap_entries) { 88562306a36Sopenharmony_ci ret = -EINVAL; 88662306a36Sopenharmony_ci goto exit_delete_chap; 88762306a36Sopenharmony_ci } 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci /* Check if chap index is in use. 89062306a36Sopenharmony_ci * If chap is in use don't delet chap entry */ 89162306a36Sopenharmony_ci ret = qla4xxx_is_chap_active(shost, chap_tbl_idx); 89262306a36Sopenharmony_ci if (ret) { 89362306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "CHAP entry %d is in use, cannot " 89462306a36Sopenharmony_ci "delete from flash\n", chap_tbl_idx); 89562306a36Sopenharmony_ci ret = -EBUSY; 89662306a36Sopenharmony_ci goto exit_delete_chap; 89762306a36Sopenharmony_ci } 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci chap_size = sizeof(struct ql4_chap_table); 90062306a36Sopenharmony_ci if (is_qla40XX(ha)) 90162306a36Sopenharmony_ci offset = FLASH_CHAP_OFFSET | (chap_tbl_idx * chap_size); 90262306a36Sopenharmony_ci else { 90362306a36Sopenharmony_ci offset = FLASH_RAW_ACCESS_ADDR + (ha->hw.flt_region_chap << 2); 90462306a36Sopenharmony_ci /* flt_chap_size is CHAP table size for both ports 90562306a36Sopenharmony_ci * so divide it by 2 to calculate the offset for second port 90662306a36Sopenharmony_ci */ 90762306a36Sopenharmony_ci if (ha->port_num == 1) 90862306a36Sopenharmony_ci offset += (ha->hw.flt_chap_size / 2); 90962306a36Sopenharmony_ci offset += (chap_tbl_idx * chap_size); 91062306a36Sopenharmony_ci } 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci ret = qla4xxx_get_flash(ha, chap_dma, offset, chap_size); 91362306a36Sopenharmony_ci if (ret != QLA_SUCCESS) { 91462306a36Sopenharmony_ci ret = -EINVAL; 91562306a36Sopenharmony_ci goto exit_delete_chap; 91662306a36Sopenharmony_ci } 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "Chap Cookie: x%x\n", 91962306a36Sopenharmony_ci __le16_to_cpu(chap_table->cookie))); 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci if (__le16_to_cpu(chap_table->cookie) != CHAP_VALID_COOKIE) { 92262306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "No valid chap entry found\n"); 92362306a36Sopenharmony_ci goto exit_delete_chap; 92462306a36Sopenharmony_ci } 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci chap_table->cookie = cpu_to_le16(0xFFFF); 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci offset = FLASH_CHAP_OFFSET | 92962306a36Sopenharmony_ci (chap_tbl_idx * sizeof(struct ql4_chap_table)); 93062306a36Sopenharmony_ci ret = qla4xxx_set_flash(ha, chap_dma, offset, chap_size, 93162306a36Sopenharmony_ci FLASH_OPT_RMW_COMMIT); 93262306a36Sopenharmony_ci if (ret == QLA_SUCCESS && ha->chap_list) { 93362306a36Sopenharmony_ci mutex_lock(&ha->chap_sem); 93462306a36Sopenharmony_ci /* Update ha chap_list cache */ 93562306a36Sopenharmony_ci memcpy((struct ql4_chap_table *)ha->chap_list + chap_tbl_idx, 93662306a36Sopenharmony_ci chap_table, sizeof(struct ql4_chap_table)); 93762306a36Sopenharmony_ci mutex_unlock(&ha->chap_sem); 93862306a36Sopenharmony_ci } 93962306a36Sopenharmony_ci if (ret != QLA_SUCCESS) 94062306a36Sopenharmony_ci ret = -EINVAL; 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ciexit_delete_chap: 94362306a36Sopenharmony_ci dma_pool_free(ha->chap_dma_pool, chap_table, chap_dma); 94462306a36Sopenharmony_ci return ret; 94562306a36Sopenharmony_ci} 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci/** 94862306a36Sopenharmony_ci * qla4xxx_set_chap_entry - Make chap entry with given information 94962306a36Sopenharmony_ci * @shost: pointer to host 95062306a36Sopenharmony_ci * @data: chap info - credentials, index and type to make chap entry 95162306a36Sopenharmony_ci * @len: length of data 95262306a36Sopenharmony_ci * 95362306a36Sopenharmony_ci * Add or update chap entry with the given information 95462306a36Sopenharmony_ci **/ 95562306a36Sopenharmony_cistatic int qla4xxx_set_chap_entry(struct Scsi_Host *shost, void *data, int len) 95662306a36Sopenharmony_ci{ 95762306a36Sopenharmony_ci struct scsi_qla_host *ha = to_qla_host(shost); 95862306a36Sopenharmony_ci struct iscsi_chap_rec chap_rec; 95962306a36Sopenharmony_ci struct ql4_chap_table *chap_entry = NULL; 96062306a36Sopenharmony_ci struct iscsi_param_info *param_info; 96162306a36Sopenharmony_ci struct nlattr *attr; 96262306a36Sopenharmony_ci int max_chap_entries = 0; 96362306a36Sopenharmony_ci int type; 96462306a36Sopenharmony_ci int rem = len; 96562306a36Sopenharmony_ci int rc = 0; 96662306a36Sopenharmony_ci int size; 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci memset(&chap_rec, 0, sizeof(chap_rec)); 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci nla_for_each_attr(attr, data, len, rem) { 97162306a36Sopenharmony_ci if (nla_len(attr) < sizeof(*param_info)) { 97262306a36Sopenharmony_ci rc = -EINVAL; 97362306a36Sopenharmony_ci goto exit_set_chap; 97462306a36Sopenharmony_ci } 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci param_info = nla_data(attr); 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci switch (param_info->param) { 97962306a36Sopenharmony_ci case ISCSI_CHAP_PARAM_INDEX: 98062306a36Sopenharmony_ci chap_rec.chap_tbl_idx = *(uint16_t *)param_info->value; 98162306a36Sopenharmony_ci break; 98262306a36Sopenharmony_ci case ISCSI_CHAP_PARAM_CHAP_TYPE: 98362306a36Sopenharmony_ci chap_rec.chap_type = param_info->value[0]; 98462306a36Sopenharmony_ci break; 98562306a36Sopenharmony_ci case ISCSI_CHAP_PARAM_USERNAME: 98662306a36Sopenharmony_ci size = min_t(size_t, sizeof(chap_rec.username), 98762306a36Sopenharmony_ci param_info->len); 98862306a36Sopenharmony_ci memcpy(chap_rec.username, param_info->value, size); 98962306a36Sopenharmony_ci break; 99062306a36Sopenharmony_ci case ISCSI_CHAP_PARAM_PASSWORD: 99162306a36Sopenharmony_ci size = min_t(size_t, sizeof(chap_rec.password), 99262306a36Sopenharmony_ci param_info->len); 99362306a36Sopenharmony_ci memcpy(chap_rec.password, param_info->value, size); 99462306a36Sopenharmony_ci break; 99562306a36Sopenharmony_ci case ISCSI_CHAP_PARAM_PASSWORD_LEN: 99662306a36Sopenharmony_ci chap_rec.password_length = param_info->value[0]; 99762306a36Sopenharmony_ci break; 99862306a36Sopenharmony_ci default: 99962306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, 100062306a36Sopenharmony_ci "%s: No such sysfs attribute\n", __func__); 100162306a36Sopenharmony_ci rc = -ENOSYS; 100262306a36Sopenharmony_ci goto exit_set_chap; 100362306a36Sopenharmony_ci } 100462306a36Sopenharmony_ci } 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci if (chap_rec.chap_type == CHAP_TYPE_IN) 100762306a36Sopenharmony_ci type = BIDI_CHAP; 100862306a36Sopenharmony_ci else 100962306a36Sopenharmony_ci type = LOCAL_CHAP; 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci if (is_qla80XX(ha)) 101262306a36Sopenharmony_ci max_chap_entries = (ha->hw.flt_chap_size / 2) / 101362306a36Sopenharmony_ci sizeof(struct ql4_chap_table); 101462306a36Sopenharmony_ci else 101562306a36Sopenharmony_ci max_chap_entries = MAX_CHAP_ENTRIES_40XX; 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci mutex_lock(&ha->chap_sem); 101862306a36Sopenharmony_ci if (chap_rec.chap_tbl_idx < max_chap_entries) { 101962306a36Sopenharmony_ci rc = qla4xxx_get_chap_by_index(ha, chap_rec.chap_tbl_idx, 102062306a36Sopenharmony_ci &chap_entry); 102162306a36Sopenharmony_ci if (!rc) { 102262306a36Sopenharmony_ci if (!(type == qla4xxx_get_chap_type(chap_entry))) { 102362306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, 102462306a36Sopenharmony_ci "Type mismatch for CHAP entry %d\n", 102562306a36Sopenharmony_ci chap_rec.chap_tbl_idx); 102662306a36Sopenharmony_ci rc = -EINVAL; 102762306a36Sopenharmony_ci goto exit_unlock_chap; 102862306a36Sopenharmony_ci } 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci /* If chap index is in use then don't modify it */ 103162306a36Sopenharmony_ci rc = qla4xxx_is_chap_active(shost, 103262306a36Sopenharmony_ci chap_rec.chap_tbl_idx); 103362306a36Sopenharmony_ci if (rc) { 103462306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, 103562306a36Sopenharmony_ci "CHAP entry %d is in use\n", 103662306a36Sopenharmony_ci chap_rec.chap_tbl_idx); 103762306a36Sopenharmony_ci rc = -EBUSY; 103862306a36Sopenharmony_ci goto exit_unlock_chap; 103962306a36Sopenharmony_ci } 104062306a36Sopenharmony_ci } 104162306a36Sopenharmony_ci } else { 104262306a36Sopenharmony_ci rc = qla4xxx_find_free_chap_index(ha, &chap_rec.chap_tbl_idx); 104362306a36Sopenharmony_ci if (rc) { 104462306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "CHAP entry not available\n"); 104562306a36Sopenharmony_ci rc = -EBUSY; 104662306a36Sopenharmony_ci goto exit_unlock_chap; 104762306a36Sopenharmony_ci } 104862306a36Sopenharmony_ci } 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ci rc = qla4xxx_set_chap(ha, chap_rec.username, chap_rec.password, 105162306a36Sopenharmony_ci chap_rec.chap_tbl_idx, type); 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ciexit_unlock_chap: 105462306a36Sopenharmony_ci mutex_unlock(&ha->chap_sem); 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ciexit_set_chap: 105762306a36Sopenharmony_ci return rc; 105862306a36Sopenharmony_ci} 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_cistatic int qla4xxx_get_host_stats(struct Scsi_Host *shost, char *buf, int len) 106262306a36Sopenharmony_ci{ 106362306a36Sopenharmony_ci struct scsi_qla_host *ha = to_qla_host(shost); 106462306a36Sopenharmony_ci struct iscsi_offload_host_stats *host_stats = NULL; 106562306a36Sopenharmony_ci int host_stats_size; 106662306a36Sopenharmony_ci int ret = 0; 106762306a36Sopenharmony_ci int ddb_idx = 0; 106862306a36Sopenharmony_ci struct ql_iscsi_stats *ql_iscsi_stats = NULL; 106962306a36Sopenharmony_ci int stats_size; 107062306a36Sopenharmony_ci dma_addr_t iscsi_stats_dma; 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "Func: %s\n", __func__)); 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci host_stats_size = sizeof(struct iscsi_offload_host_stats); 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci if (host_stats_size != len) { 107762306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "%s: host_stats size mismatch expected = %d, is = %d\n", 107862306a36Sopenharmony_ci __func__, len, host_stats_size); 107962306a36Sopenharmony_ci ret = -EINVAL; 108062306a36Sopenharmony_ci goto exit_host_stats; 108162306a36Sopenharmony_ci } 108262306a36Sopenharmony_ci host_stats = (struct iscsi_offload_host_stats *)buf; 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_ci if (!buf) { 108562306a36Sopenharmony_ci ret = -ENOMEM; 108662306a36Sopenharmony_ci goto exit_host_stats; 108762306a36Sopenharmony_ci } 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci stats_size = PAGE_ALIGN(sizeof(struct ql_iscsi_stats)); 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci ql_iscsi_stats = dma_alloc_coherent(&ha->pdev->dev, stats_size, 109262306a36Sopenharmony_ci &iscsi_stats_dma, GFP_KERNEL); 109362306a36Sopenharmony_ci if (!ql_iscsi_stats) { 109462306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, 109562306a36Sopenharmony_ci "Unable to allocate memory for iscsi stats\n"); 109662306a36Sopenharmony_ci ret = -ENOMEM; 109762306a36Sopenharmony_ci goto exit_host_stats; 109862306a36Sopenharmony_ci } 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci ret = qla4xxx_get_mgmt_data(ha, ddb_idx, stats_size, 110162306a36Sopenharmony_ci iscsi_stats_dma); 110262306a36Sopenharmony_ci if (ret != QLA_SUCCESS) { 110362306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, 110462306a36Sopenharmony_ci "Unable to retrieve iscsi stats\n"); 110562306a36Sopenharmony_ci ret = -EIO; 110662306a36Sopenharmony_ci goto exit_host_stats; 110762306a36Sopenharmony_ci } 110862306a36Sopenharmony_ci host_stats->mactx_frames = le64_to_cpu(ql_iscsi_stats->mac_tx_frames); 110962306a36Sopenharmony_ci host_stats->mactx_bytes = le64_to_cpu(ql_iscsi_stats->mac_tx_bytes); 111062306a36Sopenharmony_ci host_stats->mactx_multicast_frames = 111162306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->mac_tx_multicast_frames); 111262306a36Sopenharmony_ci host_stats->mactx_broadcast_frames = 111362306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->mac_tx_broadcast_frames); 111462306a36Sopenharmony_ci host_stats->mactx_pause_frames = 111562306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->mac_tx_pause_frames); 111662306a36Sopenharmony_ci host_stats->mactx_control_frames = 111762306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->mac_tx_control_frames); 111862306a36Sopenharmony_ci host_stats->mactx_deferral = 111962306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->mac_tx_deferral); 112062306a36Sopenharmony_ci host_stats->mactx_excess_deferral = 112162306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->mac_tx_excess_deferral); 112262306a36Sopenharmony_ci host_stats->mactx_late_collision = 112362306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->mac_tx_late_collision); 112462306a36Sopenharmony_ci host_stats->mactx_abort = le64_to_cpu(ql_iscsi_stats->mac_tx_abort); 112562306a36Sopenharmony_ci host_stats->mactx_single_collision = 112662306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->mac_tx_single_collision); 112762306a36Sopenharmony_ci host_stats->mactx_multiple_collision = 112862306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->mac_tx_multiple_collision); 112962306a36Sopenharmony_ci host_stats->mactx_collision = 113062306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->mac_tx_collision); 113162306a36Sopenharmony_ci host_stats->mactx_frames_dropped = 113262306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->mac_tx_frames_dropped); 113362306a36Sopenharmony_ci host_stats->mactx_jumbo_frames = 113462306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->mac_tx_jumbo_frames); 113562306a36Sopenharmony_ci host_stats->macrx_frames = le64_to_cpu(ql_iscsi_stats->mac_rx_frames); 113662306a36Sopenharmony_ci host_stats->macrx_bytes = le64_to_cpu(ql_iscsi_stats->mac_rx_bytes); 113762306a36Sopenharmony_ci host_stats->macrx_unknown_control_frames = 113862306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->mac_rx_unknown_control_frames); 113962306a36Sopenharmony_ci host_stats->macrx_pause_frames = 114062306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->mac_rx_pause_frames); 114162306a36Sopenharmony_ci host_stats->macrx_control_frames = 114262306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->mac_rx_control_frames); 114362306a36Sopenharmony_ci host_stats->macrx_dribble = 114462306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->mac_rx_dribble); 114562306a36Sopenharmony_ci host_stats->macrx_frame_length_error = 114662306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->mac_rx_frame_length_error); 114762306a36Sopenharmony_ci host_stats->macrx_jabber = le64_to_cpu(ql_iscsi_stats->mac_rx_jabber); 114862306a36Sopenharmony_ci host_stats->macrx_carrier_sense_error = 114962306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->mac_rx_carrier_sense_error); 115062306a36Sopenharmony_ci host_stats->macrx_frame_discarded = 115162306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->mac_rx_frame_discarded); 115262306a36Sopenharmony_ci host_stats->macrx_frames_dropped = 115362306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->mac_rx_frames_dropped); 115462306a36Sopenharmony_ci host_stats->mac_crc_error = le64_to_cpu(ql_iscsi_stats->mac_crc_error); 115562306a36Sopenharmony_ci host_stats->mac_encoding_error = 115662306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->mac_encoding_error); 115762306a36Sopenharmony_ci host_stats->macrx_length_error_large = 115862306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->mac_rx_length_error_large); 115962306a36Sopenharmony_ci host_stats->macrx_length_error_small = 116062306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->mac_rx_length_error_small); 116162306a36Sopenharmony_ci host_stats->macrx_multicast_frames = 116262306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->mac_rx_multicast_frames); 116362306a36Sopenharmony_ci host_stats->macrx_broadcast_frames = 116462306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->mac_rx_broadcast_frames); 116562306a36Sopenharmony_ci host_stats->iptx_packets = le64_to_cpu(ql_iscsi_stats->ip_tx_packets); 116662306a36Sopenharmony_ci host_stats->iptx_bytes = le64_to_cpu(ql_iscsi_stats->ip_tx_bytes); 116762306a36Sopenharmony_ci host_stats->iptx_fragments = 116862306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->ip_tx_fragments); 116962306a36Sopenharmony_ci host_stats->iprx_packets = le64_to_cpu(ql_iscsi_stats->ip_rx_packets); 117062306a36Sopenharmony_ci host_stats->iprx_bytes = le64_to_cpu(ql_iscsi_stats->ip_rx_bytes); 117162306a36Sopenharmony_ci host_stats->iprx_fragments = 117262306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->ip_rx_fragments); 117362306a36Sopenharmony_ci host_stats->ip_datagram_reassembly = 117462306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->ip_datagram_reassembly); 117562306a36Sopenharmony_ci host_stats->ip_invalid_address_error = 117662306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->ip_invalid_address_error); 117762306a36Sopenharmony_ci host_stats->ip_error_packets = 117862306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->ip_error_packets); 117962306a36Sopenharmony_ci host_stats->ip_fragrx_overlap = 118062306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->ip_fragrx_overlap); 118162306a36Sopenharmony_ci host_stats->ip_fragrx_outoforder = 118262306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->ip_fragrx_outoforder); 118362306a36Sopenharmony_ci host_stats->ip_datagram_reassembly_timeout = 118462306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->ip_datagram_reassembly_timeout); 118562306a36Sopenharmony_ci host_stats->ipv6tx_packets = 118662306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->ipv6_tx_packets); 118762306a36Sopenharmony_ci host_stats->ipv6tx_bytes = le64_to_cpu(ql_iscsi_stats->ipv6_tx_bytes); 118862306a36Sopenharmony_ci host_stats->ipv6tx_fragments = 118962306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->ipv6_tx_fragments); 119062306a36Sopenharmony_ci host_stats->ipv6rx_packets = 119162306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->ipv6_rx_packets); 119262306a36Sopenharmony_ci host_stats->ipv6rx_bytes = le64_to_cpu(ql_iscsi_stats->ipv6_rx_bytes); 119362306a36Sopenharmony_ci host_stats->ipv6rx_fragments = 119462306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->ipv6_rx_fragments); 119562306a36Sopenharmony_ci host_stats->ipv6_datagram_reassembly = 119662306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->ipv6_datagram_reassembly); 119762306a36Sopenharmony_ci host_stats->ipv6_invalid_address_error = 119862306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->ipv6_invalid_address_error); 119962306a36Sopenharmony_ci host_stats->ipv6_error_packets = 120062306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->ipv6_error_packets); 120162306a36Sopenharmony_ci host_stats->ipv6_fragrx_overlap = 120262306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->ipv6_fragrx_overlap); 120362306a36Sopenharmony_ci host_stats->ipv6_fragrx_outoforder = 120462306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->ipv6_fragrx_outoforder); 120562306a36Sopenharmony_ci host_stats->ipv6_datagram_reassembly_timeout = 120662306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->ipv6_datagram_reassembly_timeout); 120762306a36Sopenharmony_ci host_stats->tcptx_segments = 120862306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->tcp_tx_segments); 120962306a36Sopenharmony_ci host_stats->tcptx_bytes = le64_to_cpu(ql_iscsi_stats->tcp_tx_bytes); 121062306a36Sopenharmony_ci host_stats->tcprx_segments = 121162306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->tcp_rx_segments); 121262306a36Sopenharmony_ci host_stats->tcprx_byte = le64_to_cpu(ql_iscsi_stats->tcp_rx_byte); 121362306a36Sopenharmony_ci host_stats->tcp_duplicate_ack_retx = 121462306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->tcp_duplicate_ack_retx); 121562306a36Sopenharmony_ci host_stats->tcp_retx_timer_expired = 121662306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->tcp_retx_timer_expired); 121762306a36Sopenharmony_ci host_stats->tcprx_duplicate_ack = 121862306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->tcp_rx_duplicate_ack); 121962306a36Sopenharmony_ci host_stats->tcprx_pure_ackr = 122062306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->tcp_rx_pure_ackr); 122162306a36Sopenharmony_ci host_stats->tcptx_delayed_ack = 122262306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->tcp_tx_delayed_ack); 122362306a36Sopenharmony_ci host_stats->tcptx_pure_ack = 122462306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->tcp_tx_pure_ack); 122562306a36Sopenharmony_ci host_stats->tcprx_segment_error = 122662306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->tcp_rx_segment_error); 122762306a36Sopenharmony_ci host_stats->tcprx_segment_outoforder = 122862306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->tcp_rx_segment_outoforder); 122962306a36Sopenharmony_ci host_stats->tcprx_window_probe = 123062306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->tcp_rx_window_probe); 123162306a36Sopenharmony_ci host_stats->tcprx_window_update = 123262306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->tcp_rx_window_update); 123362306a36Sopenharmony_ci host_stats->tcptx_window_probe_persist = 123462306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->tcp_tx_window_probe_persist); 123562306a36Sopenharmony_ci host_stats->ecc_error_correction = 123662306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->ecc_error_correction); 123762306a36Sopenharmony_ci host_stats->iscsi_pdu_tx = le64_to_cpu(ql_iscsi_stats->iscsi_pdu_tx); 123862306a36Sopenharmony_ci host_stats->iscsi_data_bytes_tx = 123962306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->iscsi_data_bytes_tx); 124062306a36Sopenharmony_ci host_stats->iscsi_pdu_rx = le64_to_cpu(ql_iscsi_stats->iscsi_pdu_rx); 124162306a36Sopenharmony_ci host_stats->iscsi_data_bytes_rx = 124262306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->iscsi_data_bytes_rx); 124362306a36Sopenharmony_ci host_stats->iscsi_io_completed = 124462306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->iscsi_io_completed); 124562306a36Sopenharmony_ci host_stats->iscsi_unexpected_io_rx = 124662306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->iscsi_unexpected_io_rx); 124762306a36Sopenharmony_ci host_stats->iscsi_format_error = 124862306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->iscsi_format_error); 124962306a36Sopenharmony_ci host_stats->iscsi_hdr_digest_error = 125062306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->iscsi_hdr_digest_error); 125162306a36Sopenharmony_ci host_stats->iscsi_data_digest_error = 125262306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->iscsi_data_digest_error); 125362306a36Sopenharmony_ci host_stats->iscsi_sequence_error = 125462306a36Sopenharmony_ci le64_to_cpu(ql_iscsi_stats->iscsi_sequence_error); 125562306a36Sopenharmony_ciexit_host_stats: 125662306a36Sopenharmony_ci if (ql_iscsi_stats) 125762306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, stats_size, 125862306a36Sopenharmony_ci ql_iscsi_stats, iscsi_stats_dma); 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "%s: Get host stats done\n", 126162306a36Sopenharmony_ci __func__); 126262306a36Sopenharmony_ci return ret; 126362306a36Sopenharmony_ci} 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_cistatic int qla4xxx_get_iface_param(struct iscsi_iface *iface, 126662306a36Sopenharmony_ci enum iscsi_param_type param_type, 126762306a36Sopenharmony_ci int param, char *buf) 126862306a36Sopenharmony_ci{ 126962306a36Sopenharmony_ci struct Scsi_Host *shost = iscsi_iface_to_shost(iface); 127062306a36Sopenharmony_ci struct scsi_qla_host *ha = to_qla_host(shost); 127162306a36Sopenharmony_ci int ival; 127262306a36Sopenharmony_ci char *pval = NULL; 127362306a36Sopenharmony_ci int len = -ENOSYS; 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_ci if (param_type == ISCSI_NET_PARAM) { 127662306a36Sopenharmony_ci switch (param) { 127762306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV4_ADDR: 127862306a36Sopenharmony_ci len = sprintf(buf, "%pI4\n", &ha->ip_config.ip_address); 127962306a36Sopenharmony_ci break; 128062306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV4_SUBNET: 128162306a36Sopenharmony_ci len = sprintf(buf, "%pI4\n", 128262306a36Sopenharmony_ci &ha->ip_config.subnet_mask); 128362306a36Sopenharmony_ci break; 128462306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV4_GW: 128562306a36Sopenharmony_ci len = sprintf(buf, "%pI4\n", &ha->ip_config.gateway); 128662306a36Sopenharmony_ci break; 128762306a36Sopenharmony_ci case ISCSI_NET_PARAM_IFACE_ENABLE: 128862306a36Sopenharmony_ci if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) { 128962306a36Sopenharmony_ci OP_STATE(ha->ip_config.ipv4_options, 129062306a36Sopenharmony_ci IPOPT_IPV4_PROTOCOL_ENABLE, pval); 129162306a36Sopenharmony_ci } else { 129262306a36Sopenharmony_ci OP_STATE(ha->ip_config.ipv6_options, 129362306a36Sopenharmony_ci IPV6_OPT_IPV6_PROTOCOL_ENABLE, pval); 129462306a36Sopenharmony_ci } 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_ci len = sprintf(buf, "%s\n", pval); 129762306a36Sopenharmony_ci break; 129862306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV4_BOOTPROTO: 129962306a36Sopenharmony_ci len = sprintf(buf, "%s\n", 130062306a36Sopenharmony_ci (ha->ip_config.tcp_options & 130162306a36Sopenharmony_ci TCPOPT_DHCP_ENABLE) ? 130262306a36Sopenharmony_ci "dhcp" : "static"); 130362306a36Sopenharmony_ci break; 130462306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV6_ADDR: 130562306a36Sopenharmony_ci if (iface->iface_num == 0) 130662306a36Sopenharmony_ci len = sprintf(buf, "%pI6\n", 130762306a36Sopenharmony_ci &ha->ip_config.ipv6_addr0); 130862306a36Sopenharmony_ci if (iface->iface_num == 1) 130962306a36Sopenharmony_ci len = sprintf(buf, "%pI6\n", 131062306a36Sopenharmony_ci &ha->ip_config.ipv6_addr1); 131162306a36Sopenharmony_ci break; 131262306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV6_LINKLOCAL: 131362306a36Sopenharmony_ci len = sprintf(buf, "%pI6\n", 131462306a36Sopenharmony_ci &ha->ip_config.ipv6_link_local_addr); 131562306a36Sopenharmony_ci break; 131662306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV6_ROUTER: 131762306a36Sopenharmony_ci len = sprintf(buf, "%pI6\n", 131862306a36Sopenharmony_ci &ha->ip_config.ipv6_default_router_addr); 131962306a36Sopenharmony_ci break; 132062306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG: 132162306a36Sopenharmony_ci pval = (ha->ip_config.ipv6_addl_options & 132262306a36Sopenharmony_ci IPV6_ADDOPT_NEIGHBOR_DISCOVERY_ADDR_ENABLE) ? 132362306a36Sopenharmony_ci "nd" : "static"; 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_ci len = sprintf(buf, "%s\n", pval); 132662306a36Sopenharmony_ci break; 132762306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG: 132862306a36Sopenharmony_ci pval = (ha->ip_config.ipv6_addl_options & 132962306a36Sopenharmony_ci IPV6_ADDOPT_AUTOCONFIG_LINK_LOCAL_ADDR) ? 133062306a36Sopenharmony_ci "auto" : "static"; 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_ci len = sprintf(buf, "%s\n", pval); 133362306a36Sopenharmony_ci break; 133462306a36Sopenharmony_ci case ISCSI_NET_PARAM_VLAN_ID: 133562306a36Sopenharmony_ci if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) 133662306a36Sopenharmony_ci ival = ha->ip_config.ipv4_vlan_tag & 133762306a36Sopenharmony_ci ISCSI_MAX_VLAN_ID; 133862306a36Sopenharmony_ci else 133962306a36Sopenharmony_ci ival = ha->ip_config.ipv6_vlan_tag & 134062306a36Sopenharmony_ci ISCSI_MAX_VLAN_ID; 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci len = sprintf(buf, "%d\n", ival); 134362306a36Sopenharmony_ci break; 134462306a36Sopenharmony_ci case ISCSI_NET_PARAM_VLAN_PRIORITY: 134562306a36Sopenharmony_ci if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) 134662306a36Sopenharmony_ci ival = (ha->ip_config.ipv4_vlan_tag >> 13) & 134762306a36Sopenharmony_ci ISCSI_MAX_VLAN_PRIORITY; 134862306a36Sopenharmony_ci else 134962306a36Sopenharmony_ci ival = (ha->ip_config.ipv6_vlan_tag >> 13) & 135062306a36Sopenharmony_ci ISCSI_MAX_VLAN_PRIORITY; 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_ci len = sprintf(buf, "%d\n", ival); 135362306a36Sopenharmony_ci break; 135462306a36Sopenharmony_ci case ISCSI_NET_PARAM_VLAN_ENABLED: 135562306a36Sopenharmony_ci if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) { 135662306a36Sopenharmony_ci OP_STATE(ha->ip_config.ipv4_options, 135762306a36Sopenharmony_ci IPOPT_VLAN_TAGGING_ENABLE, pval); 135862306a36Sopenharmony_ci } else { 135962306a36Sopenharmony_ci OP_STATE(ha->ip_config.ipv6_options, 136062306a36Sopenharmony_ci IPV6_OPT_VLAN_TAGGING_ENABLE, pval); 136162306a36Sopenharmony_ci } 136262306a36Sopenharmony_ci len = sprintf(buf, "%s\n", pval); 136362306a36Sopenharmony_ci break; 136462306a36Sopenharmony_ci case ISCSI_NET_PARAM_MTU: 136562306a36Sopenharmony_ci len = sprintf(buf, "%d\n", ha->ip_config.eth_mtu_size); 136662306a36Sopenharmony_ci break; 136762306a36Sopenharmony_ci case ISCSI_NET_PARAM_PORT: 136862306a36Sopenharmony_ci if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) 136962306a36Sopenharmony_ci len = sprintf(buf, "%d\n", 137062306a36Sopenharmony_ci ha->ip_config.ipv4_port); 137162306a36Sopenharmony_ci else 137262306a36Sopenharmony_ci len = sprintf(buf, "%d\n", 137362306a36Sopenharmony_ci ha->ip_config.ipv6_port); 137462306a36Sopenharmony_ci break; 137562306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPADDR_STATE: 137662306a36Sopenharmony_ci if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) { 137762306a36Sopenharmony_ci pval = iscsi_get_ipaddress_state_name( 137862306a36Sopenharmony_ci ha->ip_config.ipv4_addr_state); 137962306a36Sopenharmony_ci } else { 138062306a36Sopenharmony_ci if (iface->iface_num == 0) 138162306a36Sopenharmony_ci pval = iscsi_get_ipaddress_state_name( 138262306a36Sopenharmony_ci ha->ip_config.ipv6_addr0_state); 138362306a36Sopenharmony_ci else if (iface->iface_num == 1) 138462306a36Sopenharmony_ci pval = iscsi_get_ipaddress_state_name( 138562306a36Sopenharmony_ci ha->ip_config.ipv6_addr1_state); 138662306a36Sopenharmony_ci } 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_ci len = sprintf(buf, "%s\n", pval); 138962306a36Sopenharmony_ci break; 139062306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV6_LINKLOCAL_STATE: 139162306a36Sopenharmony_ci pval = iscsi_get_ipaddress_state_name( 139262306a36Sopenharmony_ci ha->ip_config.ipv6_link_local_state); 139362306a36Sopenharmony_ci len = sprintf(buf, "%s\n", pval); 139462306a36Sopenharmony_ci break; 139562306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV6_ROUTER_STATE: 139662306a36Sopenharmony_ci pval = iscsi_get_router_state_name( 139762306a36Sopenharmony_ci ha->ip_config.ipv6_default_router_state); 139862306a36Sopenharmony_ci len = sprintf(buf, "%s\n", pval); 139962306a36Sopenharmony_ci break; 140062306a36Sopenharmony_ci case ISCSI_NET_PARAM_DELAYED_ACK_EN: 140162306a36Sopenharmony_ci if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) { 140262306a36Sopenharmony_ci OP_STATE(~ha->ip_config.tcp_options, 140362306a36Sopenharmony_ci TCPOPT_DELAYED_ACK_DISABLE, pval); 140462306a36Sopenharmony_ci } else { 140562306a36Sopenharmony_ci OP_STATE(~ha->ip_config.ipv6_tcp_options, 140662306a36Sopenharmony_ci IPV6_TCPOPT_DELAYED_ACK_DISABLE, pval); 140762306a36Sopenharmony_ci } 140862306a36Sopenharmony_ci len = sprintf(buf, "%s\n", pval); 140962306a36Sopenharmony_ci break; 141062306a36Sopenharmony_ci case ISCSI_NET_PARAM_TCP_NAGLE_DISABLE: 141162306a36Sopenharmony_ci if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) { 141262306a36Sopenharmony_ci OP_STATE(~ha->ip_config.tcp_options, 141362306a36Sopenharmony_ci TCPOPT_NAGLE_ALGO_DISABLE, pval); 141462306a36Sopenharmony_ci } else { 141562306a36Sopenharmony_ci OP_STATE(~ha->ip_config.ipv6_tcp_options, 141662306a36Sopenharmony_ci IPV6_TCPOPT_NAGLE_ALGO_DISABLE, pval); 141762306a36Sopenharmony_ci } 141862306a36Sopenharmony_ci len = sprintf(buf, "%s\n", pval); 141962306a36Sopenharmony_ci break; 142062306a36Sopenharmony_ci case ISCSI_NET_PARAM_TCP_WSF_DISABLE: 142162306a36Sopenharmony_ci if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) { 142262306a36Sopenharmony_ci OP_STATE(~ha->ip_config.tcp_options, 142362306a36Sopenharmony_ci TCPOPT_WINDOW_SCALE_DISABLE, pval); 142462306a36Sopenharmony_ci } else { 142562306a36Sopenharmony_ci OP_STATE(~ha->ip_config.ipv6_tcp_options, 142662306a36Sopenharmony_ci IPV6_TCPOPT_WINDOW_SCALE_DISABLE, 142762306a36Sopenharmony_ci pval); 142862306a36Sopenharmony_ci } 142962306a36Sopenharmony_ci len = sprintf(buf, "%s\n", pval); 143062306a36Sopenharmony_ci break; 143162306a36Sopenharmony_ci case ISCSI_NET_PARAM_TCP_WSF: 143262306a36Sopenharmony_ci if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) 143362306a36Sopenharmony_ci len = sprintf(buf, "%d\n", 143462306a36Sopenharmony_ci ha->ip_config.tcp_wsf); 143562306a36Sopenharmony_ci else 143662306a36Sopenharmony_ci len = sprintf(buf, "%d\n", 143762306a36Sopenharmony_ci ha->ip_config.ipv6_tcp_wsf); 143862306a36Sopenharmony_ci break; 143962306a36Sopenharmony_ci case ISCSI_NET_PARAM_TCP_TIMER_SCALE: 144062306a36Sopenharmony_ci if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) 144162306a36Sopenharmony_ci ival = (ha->ip_config.tcp_options & 144262306a36Sopenharmony_ci TCPOPT_TIMER_SCALE) >> 1; 144362306a36Sopenharmony_ci else 144462306a36Sopenharmony_ci ival = (ha->ip_config.ipv6_tcp_options & 144562306a36Sopenharmony_ci IPV6_TCPOPT_TIMER_SCALE) >> 1; 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_ci len = sprintf(buf, "%d\n", ival); 144862306a36Sopenharmony_ci break; 144962306a36Sopenharmony_ci case ISCSI_NET_PARAM_TCP_TIMESTAMP_EN: 145062306a36Sopenharmony_ci if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) { 145162306a36Sopenharmony_ci OP_STATE(ha->ip_config.tcp_options, 145262306a36Sopenharmony_ci TCPOPT_TIMESTAMP_ENABLE, pval); 145362306a36Sopenharmony_ci } else { 145462306a36Sopenharmony_ci OP_STATE(ha->ip_config.ipv6_tcp_options, 145562306a36Sopenharmony_ci IPV6_TCPOPT_TIMESTAMP_EN, pval); 145662306a36Sopenharmony_ci } 145762306a36Sopenharmony_ci len = sprintf(buf, "%s\n", pval); 145862306a36Sopenharmony_ci break; 145962306a36Sopenharmony_ci case ISCSI_NET_PARAM_CACHE_ID: 146062306a36Sopenharmony_ci if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) 146162306a36Sopenharmony_ci len = sprintf(buf, "%d\n", 146262306a36Sopenharmony_ci ha->ip_config.ipv4_cache_id); 146362306a36Sopenharmony_ci else 146462306a36Sopenharmony_ci len = sprintf(buf, "%d\n", 146562306a36Sopenharmony_ci ha->ip_config.ipv6_cache_id); 146662306a36Sopenharmony_ci break; 146762306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV4_DHCP_DNS_ADDR_EN: 146862306a36Sopenharmony_ci OP_STATE(ha->ip_config.tcp_options, 146962306a36Sopenharmony_ci TCPOPT_DNS_SERVER_IP_EN, pval); 147062306a36Sopenharmony_ci 147162306a36Sopenharmony_ci len = sprintf(buf, "%s\n", pval); 147262306a36Sopenharmony_ci break; 147362306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV4_DHCP_SLP_DA_EN: 147462306a36Sopenharmony_ci OP_STATE(ha->ip_config.tcp_options, 147562306a36Sopenharmony_ci TCPOPT_SLP_DA_INFO_EN, pval); 147662306a36Sopenharmony_ci 147762306a36Sopenharmony_ci len = sprintf(buf, "%s\n", pval); 147862306a36Sopenharmony_ci break; 147962306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV4_TOS_EN: 148062306a36Sopenharmony_ci OP_STATE(ha->ip_config.ipv4_options, 148162306a36Sopenharmony_ci IPOPT_IPV4_TOS_EN, pval); 148262306a36Sopenharmony_ci 148362306a36Sopenharmony_ci len = sprintf(buf, "%s\n", pval); 148462306a36Sopenharmony_ci break; 148562306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV4_TOS: 148662306a36Sopenharmony_ci len = sprintf(buf, "%d\n", ha->ip_config.ipv4_tos); 148762306a36Sopenharmony_ci break; 148862306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV4_GRAT_ARP_EN: 148962306a36Sopenharmony_ci OP_STATE(ha->ip_config.ipv4_options, 149062306a36Sopenharmony_ci IPOPT_GRAT_ARP_EN, pval); 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci len = sprintf(buf, "%s\n", pval); 149362306a36Sopenharmony_ci break; 149462306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV4_DHCP_ALT_CLIENT_ID_EN: 149562306a36Sopenharmony_ci OP_STATE(ha->ip_config.ipv4_options, IPOPT_ALT_CID_EN, 149662306a36Sopenharmony_ci pval); 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_ci len = sprintf(buf, "%s\n", pval); 149962306a36Sopenharmony_ci break; 150062306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV4_DHCP_ALT_CLIENT_ID: 150162306a36Sopenharmony_ci pval = (ha->ip_config.ipv4_alt_cid_len) ? 150262306a36Sopenharmony_ci (char *)ha->ip_config.ipv4_alt_cid : ""; 150362306a36Sopenharmony_ci 150462306a36Sopenharmony_ci len = sprintf(buf, "%s\n", pval); 150562306a36Sopenharmony_ci break; 150662306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV4_DHCP_REQ_VENDOR_ID_EN: 150762306a36Sopenharmony_ci OP_STATE(ha->ip_config.ipv4_options, 150862306a36Sopenharmony_ci IPOPT_REQ_VID_EN, pval); 150962306a36Sopenharmony_ci 151062306a36Sopenharmony_ci len = sprintf(buf, "%s\n", pval); 151162306a36Sopenharmony_ci break; 151262306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV4_DHCP_USE_VENDOR_ID_EN: 151362306a36Sopenharmony_ci OP_STATE(ha->ip_config.ipv4_options, 151462306a36Sopenharmony_ci IPOPT_USE_VID_EN, pval); 151562306a36Sopenharmony_ci 151662306a36Sopenharmony_ci len = sprintf(buf, "%s\n", pval); 151762306a36Sopenharmony_ci break; 151862306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV4_DHCP_VENDOR_ID: 151962306a36Sopenharmony_ci pval = (ha->ip_config.ipv4_vid_len) ? 152062306a36Sopenharmony_ci (char *)ha->ip_config.ipv4_vid : ""; 152162306a36Sopenharmony_ci 152262306a36Sopenharmony_ci len = sprintf(buf, "%s\n", pval); 152362306a36Sopenharmony_ci break; 152462306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV4_DHCP_LEARN_IQN_EN: 152562306a36Sopenharmony_ci OP_STATE(ha->ip_config.ipv4_options, 152662306a36Sopenharmony_ci IPOPT_LEARN_IQN_EN, pval); 152762306a36Sopenharmony_ci 152862306a36Sopenharmony_ci len = sprintf(buf, "%s\n", pval); 152962306a36Sopenharmony_ci break; 153062306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV4_FRAGMENT_DISABLE: 153162306a36Sopenharmony_ci OP_STATE(~ha->ip_config.ipv4_options, 153262306a36Sopenharmony_ci IPOPT_FRAGMENTATION_DISABLE, pval); 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_ci len = sprintf(buf, "%s\n", pval); 153562306a36Sopenharmony_ci break; 153662306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV4_IN_FORWARD_EN: 153762306a36Sopenharmony_ci OP_STATE(ha->ip_config.ipv4_options, 153862306a36Sopenharmony_ci IPOPT_IN_FORWARD_EN, pval); 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_ci len = sprintf(buf, "%s\n", pval); 154162306a36Sopenharmony_ci break; 154262306a36Sopenharmony_ci case ISCSI_NET_PARAM_REDIRECT_EN: 154362306a36Sopenharmony_ci if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) { 154462306a36Sopenharmony_ci OP_STATE(ha->ip_config.ipv4_options, 154562306a36Sopenharmony_ci IPOPT_ARP_REDIRECT_EN, pval); 154662306a36Sopenharmony_ci } else { 154762306a36Sopenharmony_ci OP_STATE(ha->ip_config.ipv6_options, 154862306a36Sopenharmony_ci IPV6_OPT_REDIRECT_EN, pval); 154962306a36Sopenharmony_ci } 155062306a36Sopenharmony_ci len = sprintf(buf, "%s\n", pval); 155162306a36Sopenharmony_ci break; 155262306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV4_TTL: 155362306a36Sopenharmony_ci len = sprintf(buf, "%d\n", ha->ip_config.ipv4_ttl); 155462306a36Sopenharmony_ci break; 155562306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV6_GRAT_NEIGHBOR_ADV_EN: 155662306a36Sopenharmony_ci OP_STATE(ha->ip_config.ipv6_options, 155762306a36Sopenharmony_ci IPV6_OPT_GRAT_NEIGHBOR_ADV_EN, pval); 155862306a36Sopenharmony_ci 155962306a36Sopenharmony_ci len = sprintf(buf, "%s\n", pval); 156062306a36Sopenharmony_ci break; 156162306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV6_MLD_EN: 156262306a36Sopenharmony_ci OP_STATE(ha->ip_config.ipv6_addl_options, 156362306a36Sopenharmony_ci IPV6_ADDOPT_MLD_EN, pval); 156462306a36Sopenharmony_ci 156562306a36Sopenharmony_ci len = sprintf(buf, "%s\n", pval); 156662306a36Sopenharmony_ci break; 156762306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV6_FLOW_LABEL: 156862306a36Sopenharmony_ci len = sprintf(buf, "%u\n", ha->ip_config.ipv6_flow_lbl); 156962306a36Sopenharmony_ci break; 157062306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV6_TRAFFIC_CLASS: 157162306a36Sopenharmony_ci len = sprintf(buf, "%d\n", 157262306a36Sopenharmony_ci ha->ip_config.ipv6_traffic_class); 157362306a36Sopenharmony_ci break; 157462306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV6_HOP_LIMIT: 157562306a36Sopenharmony_ci len = sprintf(buf, "%d\n", 157662306a36Sopenharmony_ci ha->ip_config.ipv6_hop_limit); 157762306a36Sopenharmony_ci break; 157862306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV6_ND_REACHABLE_TMO: 157962306a36Sopenharmony_ci len = sprintf(buf, "%d\n", 158062306a36Sopenharmony_ci ha->ip_config.ipv6_nd_reach_time); 158162306a36Sopenharmony_ci break; 158262306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV6_ND_REXMIT_TIME: 158362306a36Sopenharmony_ci len = sprintf(buf, "%d\n", 158462306a36Sopenharmony_ci ha->ip_config.ipv6_nd_rexmit_timer); 158562306a36Sopenharmony_ci break; 158662306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV6_ND_STALE_TMO: 158762306a36Sopenharmony_ci len = sprintf(buf, "%d\n", 158862306a36Sopenharmony_ci ha->ip_config.ipv6_nd_stale_timeout); 158962306a36Sopenharmony_ci break; 159062306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV6_DUP_ADDR_DETECT_CNT: 159162306a36Sopenharmony_ci len = sprintf(buf, "%d\n", 159262306a36Sopenharmony_ci ha->ip_config.ipv6_dup_addr_detect_count); 159362306a36Sopenharmony_ci break; 159462306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV6_RTR_ADV_LINK_MTU: 159562306a36Sopenharmony_ci len = sprintf(buf, "%d\n", 159662306a36Sopenharmony_ci ha->ip_config.ipv6_gw_advrt_mtu); 159762306a36Sopenharmony_ci break; 159862306a36Sopenharmony_ci default: 159962306a36Sopenharmony_ci len = -ENOSYS; 160062306a36Sopenharmony_ci } 160162306a36Sopenharmony_ci } else if (param_type == ISCSI_IFACE_PARAM) { 160262306a36Sopenharmony_ci switch (param) { 160362306a36Sopenharmony_ci case ISCSI_IFACE_PARAM_DEF_TASKMGMT_TMO: 160462306a36Sopenharmony_ci len = sprintf(buf, "%d\n", ha->ip_config.def_timeout); 160562306a36Sopenharmony_ci break; 160662306a36Sopenharmony_ci case ISCSI_IFACE_PARAM_HDRDGST_EN: 160762306a36Sopenharmony_ci OP_STATE(ha->ip_config.iscsi_options, 160862306a36Sopenharmony_ci ISCSIOPTS_HEADER_DIGEST_EN, pval); 160962306a36Sopenharmony_ci 161062306a36Sopenharmony_ci len = sprintf(buf, "%s\n", pval); 161162306a36Sopenharmony_ci break; 161262306a36Sopenharmony_ci case ISCSI_IFACE_PARAM_DATADGST_EN: 161362306a36Sopenharmony_ci OP_STATE(ha->ip_config.iscsi_options, 161462306a36Sopenharmony_ci ISCSIOPTS_DATA_DIGEST_EN, pval); 161562306a36Sopenharmony_ci 161662306a36Sopenharmony_ci len = sprintf(buf, "%s\n", pval); 161762306a36Sopenharmony_ci break; 161862306a36Sopenharmony_ci case ISCSI_IFACE_PARAM_IMM_DATA_EN: 161962306a36Sopenharmony_ci OP_STATE(ha->ip_config.iscsi_options, 162062306a36Sopenharmony_ci ISCSIOPTS_IMMEDIATE_DATA_EN, pval); 162162306a36Sopenharmony_ci 162262306a36Sopenharmony_ci len = sprintf(buf, "%s\n", pval); 162362306a36Sopenharmony_ci break; 162462306a36Sopenharmony_ci case ISCSI_IFACE_PARAM_INITIAL_R2T_EN: 162562306a36Sopenharmony_ci OP_STATE(ha->ip_config.iscsi_options, 162662306a36Sopenharmony_ci ISCSIOPTS_INITIAL_R2T_EN, pval); 162762306a36Sopenharmony_ci 162862306a36Sopenharmony_ci len = sprintf(buf, "%s\n", pval); 162962306a36Sopenharmony_ci break; 163062306a36Sopenharmony_ci case ISCSI_IFACE_PARAM_DATASEQ_INORDER_EN: 163162306a36Sopenharmony_ci OP_STATE(ha->ip_config.iscsi_options, 163262306a36Sopenharmony_ci ISCSIOPTS_DATA_SEQ_INORDER_EN, pval); 163362306a36Sopenharmony_ci 163462306a36Sopenharmony_ci len = sprintf(buf, "%s\n", pval); 163562306a36Sopenharmony_ci break; 163662306a36Sopenharmony_ci case ISCSI_IFACE_PARAM_PDU_INORDER_EN: 163762306a36Sopenharmony_ci OP_STATE(ha->ip_config.iscsi_options, 163862306a36Sopenharmony_ci ISCSIOPTS_DATA_PDU_INORDER_EN, pval); 163962306a36Sopenharmony_ci 164062306a36Sopenharmony_ci len = sprintf(buf, "%s\n", pval); 164162306a36Sopenharmony_ci break; 164262306a36Sopenharmony_ci case ISCSI_IFACE_PARAM_ERL: 164362306a36Sopenharmony_ci len = sprintf(buf, "%d\n", 164462306a36Sopenharmony_ci (ha->ip_config.iscsi_options & 164562306a36Sopenharmony_ci ISCSIOPTS_ERL)); 164662306a36Sopenharmony_ci break; 164762306a36Sopenharmony_ci case ISCSI_IFACE_PARAM_MAX_RECV_DLENGTH: 164862306a36Sopenharmony_ci len = sprintf(buf, "%u\n", 164962306a36Sopenharmony_ci ha->ip_config.iscsi_max_pdu_size * 165062306a36Sopenharmony_ci BYTE_UNITS); 165162306a36Sopenharmony_ci break; 165262306a36Sopenharmony_ci case ISCSI_IFACE_PARAM_FIRST_BURST: 165362306a36Sopenharmony_ci len = sprintf(buf, "%u\n", 165462306a36Sopenharmony_ci ha->ip_config.iscsi_first_burst_len * 165562306a36Sopenharmony_ci BYTE_UNITS); 165662306a36Sopenharmony_ci break; 165762306a36Sopenharmony_ci case ISCSI_IFACE_PARAM_MAX_R2T: 165862306a36Sopenharmony_ci len = sprintf(buf, "%d\n", 165962306a36Sopenharmony_ci ha->ip_config.iscsi_max_outstnd_r2t); 166062306a36Sopenharmony_ci break; 166162306a36Sopenharmony_ci case ISCSI_IFACE_PARAM_MAX_BURST: 166262306a36Sopenharmony_ci len = sprintf(buf, "%u\n", 166362306a36Sopenharmony_ci ha->ip_config.iscsi_max_burst_len * 166462306a36Sopenharmony_ci BYTE_UNITS); 166562306a36Sopenharmony_ci break; 166662306a36Sopenharmony_ci case ISCSI_IFACE_PARAM_CHAP_AUTH_EN: 166762306a36Sopenharmony_ci OP_STATE(ha->ip_config.iscsi_options, 166862306a36Sopenharmony_ci ISCSIOPTS_CHAP_AUTH_EN, pval); 166962306a36Sopenharmony_ci 167062306a36Sopenharmony_ci len = sprintf(buf, "%s\n", pval); 167162306a36Sopenharmony_ci break; 167262306a36Sopenharmony_ci case ISCSI_IFACE_PARAM_BIDI_CHAP_EN: 167362306a36Sopenharmony_ci OP_STATE(ha->ip_config.iscsi_options, 167462306a36Sopenharmony_ci ISCSIOPTS_BIDI_CHAP_EN, pval); 167562306a36Sopenharmony_ci 167662306a36Sopenharmony_ci len = sprintf(buf, "%s\n", pval); 167762306a36Sopenharmony_ci break; 167862306a36Sopenharmony_ci case ISCSI_IFACE_PARAM_DISCOVERY_AUTH_OPTIONAL: 167962306a36Sopenharmony_ci OP_STATE(ha->ip_config.iscsi_options, 168062306a36Sopenharmony_ci ISCSIOPTS_DISCOVERY_AUTH_EN, pval); 168162306a36Sopenharmony_ci 168262306a36Sopenharmony_ci len = sprintf(buf, "%s\n", pval); 168362306a36Sopenharmony_ci break; 168462306a36Sopenharmony_ci case ISCSI_IFACE_PARAM_DISCOVERY_LOGOUT_EN: 168562306a36Sopenharmony_ci OP_STATE(ha->ip_config.iscsi_options, 168662306a36Sopenharmony_ci ISCSIOPTS_DISCOVERY_LOGOUT_EN, pval); 168762306a36Sopenharmony_ci 168862306a36Sopenharmony_ci len = sprintf(buf, "%s\n", pval); 168962306a36Sopenharmony_ci break; 169062306a36Sopenharmony_ci case ISCSI_IFACE_PARAM_STRICT_LOGIN_COMP_EN: 169162306a36Sopenharmony_ci OP_STATE(ha->ip_config.iscsi_options, 169262306a36Sopenharmony_ci ISCSIOPTS_STRICT_LOGIN_COMP_EN, pval); 169362306a36Sopenharmony_ci 169462306a36Sopenharmony_ci len = sprintf(buf, "%s\n", pval); 169562306a36Sopenharmony_ci break; 169662306a36Sopenharmony_ci case ISCSI_IFACE_PARAM_INITIATOR_NAME: 169762306a36Sopenharmony_ci len = sprintf(buf, "%s\n", ha->ip_config.iscsi_name); 169862306a36Sopenharmony_ci break; 169962306a36Sopenharmony_ci default: 170062306a36Sopenharmony_ci len = -ENOSYS; 170162306a36Sopenharmony_ci } 170262306a36Sopenharmony_ci } 170362306a36Sopenharmony_ci 170462306a36Sopenharmony_ci return len; 170562306a36Sopenharmony_ci} 170662306a36Sopenharmony_ci 170762306a36Sopenharmony_cistatic struct iscsi_endpoint * 170862306a36Sopenharmony_ciqla4xxx_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr, 170962306a36Sopenharmony_ci int non_blocking) 171062306a36Sopenharmony_ci{ 171162306a36Sopenharmony_ci int ret; 171262306a36Sopenharmony_ci struct iscsi_endpoint *ep; 171362306a36Sopenharmony_ci struct qla_endpoint *qla_ep; 171462306a36Sopenharmony_ci struct scsi_qla_host *ha; 171562306a36Sopenharmony_ci struct sockaddr_in *addr; 171662306a36Sopenharmony_ci struct sockaddr_in6 *addr6; 171762306a36Sopenharmony_ci 171862306a36Sopenharmony_ci if (!shost) { 171962306a36Sopenharmony_ci ret = -ENXIO; 172062306a36Sopenharmony_ci pr_err("%s: shost is NULL\n", __func__); 172162306a36Sopenharmony_ci return ERR_PTR(ret); 172262306a36Sopenharmony_ci } 172362306a36Sopenharmony_ci 172462306a36Sopenharmony_ci ha = iscsi_host_priv(shost); 172562306a36Sopenharmony_ci ep = iscsi_create_endpoint(sizeof(struct qla_endpoint)); 172662306a36Sopenharmony_ci if (!ep) { 172762306a36Sopenharmony_ci ret = -ENOMEM; 172862306a36Sopenharmony_ci return ERR_PTR(ret); 172962306a36Sopenharmony_ci } 173062306a36Sopenharmony_ci 173162306a36Sopenharmony_ci qla_ep = ep->dd_data; 173262306a36Sopenharmony_ci memset(qla_ep, 0, sizeof(struct qla_endpoint)); 173362306a36Sopenharmony_ci if (dst_addr->sa_family == AF_INET) { 173462306a36Sopenharmony_ci memcpy(&qla_ep->dst_addr, dst_addr, sizeof(struct sockaddr_in)); 173562306a36Sopenharmony_ci addr = (struct sockaddr_in *)&qla_ep->dst_addr; 173662306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "%s: %pI4\n", __func__, 173762306a36Sopenharmony_ci (char *)&addr->sin_addr)); 173862306a36Sopenharmony_ci } else if (dst_addr->sa_family == AF_INET6) { 173962306a36Sopenharmony_ci memcpy(&qla_ep->dst_addr, dst_addr, 174062306a36Sopenharmony_ci sizeof(struct sockaddr_in6)); 174162306a36Sopenharmony_ci addr6 = (struct sockaddr_in6 *)&qla_ep->dst_addr; 174262306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "%s: %pI6\n", __func__, 174362306a36Sopenharmony_ci (char *)&addr6->sin6_addr)); 174462306a36Sopenharmony_ci } else { 174562306a36Sopenharmony_ci ql4_printk(KERN_WARNING, ha, "%s: Invalid endpoint\n", 174662306a36Sopenharmony_ci __func__); 174762306a36Sopenharmony_ci } 174862306a36Sopenharmony_ci 174962306a36Sopenharmony_ci qla_ep->host = shost; 175062306a36Sopenharmony_ci 175162306a36Sopenharmony_ci return ep; 175262306a36Sopenharmony_ci} 175362306a36Sopenharmony_ci 175462306a36Sopenharmony_cistatic int qla4xxx_ep_poll(struct iscsi_endpoint *ep, int timeout_ms) 175562306a36Sopenharmony_ci{ 175662306a36Sopenharmony_ci struct qla_endpoint *qla_ep; 175762306a36Sopenharmony_ci struct scsi_qla_host *ha; 175862306a36Sopenharmony_ci int ret = 0; 175962306a36Sopenharmony_ci 176062306a36Sopenharmony_ci qla_ep = ep->dd_data; 176162306a36Sopenharmony_ci ha = to_qla_host(qla_ep->host); 176262306a36Sopenharmony_ci DEBUG2(pr_info_ratelimited("%s: host: %ld\n", __func__, ha->host_no)); 176362306a36Sopenharmony_ci 176462306a36Sopenharmony_ci if (adapter_up(ha) && !test_bit(AF_BUILD_DDB_LIST, &ha->flags)) 176562306a36Sopenharmony_ci ret = 1; 176662306a36Sopenharmony_ci 176762306a36Sopenharmony_ci return ret; 176862306a36Sopenharmony_ci} 176962306a36Sopenharmony_ci 177062306a36Sopenharmony_cistatic void qla4xxx_ep_disconnect(struct iscsi_endpoint *ep) 177162306a36Sopenharmony_ci{ 177262306a36Sopenharmony_ci struct qla_endpoint *qla_ep; 177362306a36Sopenharmony_ci struct scsi_qla_host *ha; 177462306a36Sopenharmony_ci 177562306a36Sopenharmony_ci qla_ep = ep->dd_data; 177662306a36Sopenharmony_ci ha = to_qla_host(qla_ep->host); 177762306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "%s: host: %ld\n", __func__, 177862306a36Sopenharmony_ci ha->host_no)); 177962306a36Sopenharmony_ci iscsi_destroy_endpoint(ep); 178062306a36Sopenharmony_ci} 178162306a36Sopenharmony_ci 178262306a36Sopenharmony_cistatic int qla4xxx_get_ep_param(struct iscsi_endpoint *ep, 178362306a36Sopenharmony_ci enum iscsi_param param, 178462306a36Sopenharmony_ci char *buf) 178562306a36Sopenharmony_ci{ 178662306a36Sopenharmony_ci struct qla_endpoint *qla_ep = ep->dd_data; 178762306a36Sopenharmony_ci struct sockaddr *dst_addr; 178862306a36Sopenharmony_ci struct scsi_qla_host *ha; 178962306a36Sopenharmony_ci 179062306a36Sopenharmony_ci if (!qla_ep) 179162306a36Sopenharmony_ci return -ENOTCONN; 179262306a36Sopenharmony_ci 179362306a36Sopenharmony_ci ha = to_qla_host(qla_ep->host); 179462306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "%s: host: %ld\n", __func__, 179562306a36Sopenharmony_ci ha->host_no)); 179662306a36Sopenharmony_ci 179762306a36Sopenharmony_ci switch (param) { 179862306a36Sopenharmony_ci case ISCSI_PARAM_CONN_PORT: 179962306a36Sopenharmony_ci case ISCSI_PARAM_CONN_ADDRESS: 180062306a36Sopenharmony_ci dst_addr = (struct sockaddr *)&qla_ep->dst_addr; 180162306a36Sopenharmony_ci if (!dst_addr) 180262306a36Sopenharmony_ci return -ENOTCONN; 180362306a36Sopenharmony_ci 180462306a36Sopenharmony_ci return iscsi_conn_get_addr_param((struct sockaddr_storage *) 180562306a36Sopenharmony_ci &qla_ep->dst_addr, param, buf); 180662306a36Sopenharmony_ci default: 180762306a36Sopenharmony_ci return -ENOSYS; 180862306a36Sopenharmony_ci } 180962306a36Sopenharmony_ci} 181062306a36Sopenharmony_ci 181162306a36Sopenharmony_cistatic void qla4xxx_conn_get_stats(struct iscsi_cls_conn *cls_conn, 181262306a36Sopenharmony_ci struct iscsi_stats *stats) 181362306a36Sopenharmony_ci{ 181462306a36Sopenharmony_ci struct iscsi_session *sess; 181562306a36Sopenharmony_ci struct iscsi_cls_session *cls_sess; 181662306a36Sopenharmony_ci struct ddb_entry *ddb_entry; 181762306a36Sopenharmony_ci struct scsi_qla_host *ha; 181862306a36Sopenharmony_ci struct ql_iscsi_stats *ql_iscsi_stats; 181962306a36Sopenharmony_ci int stats_size; 182062306a36Sopenharmony_ci int ret; 182162306a36Sopenharmony_ci dma_addr_t iscsi_stats_dma; 182262306a36Sopenharmony_ci 182362306a36Sopenharmony_ci cls_sess = iscsi_conn_to_session(cls_conn); 182462306a36Sopenharmony_ci sess = cls_sess->dd_data; 182562306a36Sopenharmony_ci ddb_entry = sess->dd_data; 182662306a36Sopenharmony_ci ha = ddb_entry->ha; 182762306a36Sopenharmony_ci 182862306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "%s: host: %ld\n", __func__, 182962306a36Sopenharmony_ci ha->host_no)); 183062306a36Sopenharmony_ci stats_size = PAGE_ALIGN(sizeof(struct ql_iscsi_stats)); 183162306a36Sopenharmony_ci /* Allocate memory */ 183262306a36Sopenharmony_ci ql_iscsi_stats = dma_alloc_coherent(&ha->pdev->dev, stats_size, 183362306a36Sopenharmony_ci &iscsi_stats_dma, GFP_KERNEL); 183462306a36Sopenharmony_ci if (!ql_iscsi_stats) { 183562306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, 183662306a36Sopenharmony_ci "Unable to allocate memory for iscsi stats\n"); 183762306a36Sopenharmony_ci goto exit_get_stats; 183862306a36Sopenharmony_ci } 183962306a36Sopenharmony_ci 184062306a36Sopenharmony_ci ret = qla4xxx_get_mgmt_data(ha, ddb_entry->fw_ddb_index, stats_size, 184162306a36Sopenharmony_ci iscsi_stats_dma); 184262306a36Sopenharmony_ci if (ret != QLA_SUCCESS) { 184362306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, 184462306a36Sopenharmony_ci "Unable to retrieve iscsi stats\n"); 184562306a36Sopenharmony_ci goto free_stats; 184662306a36Sopenharmony_ci } 184762306a36Sopenharmony_ci 184862306a36Sopenharmony_ci /* octets */ 184962306a36Sopenharmony_ci stats->txdata_octets = le64_to_cpu(ql_iscsi_stats->tx_data_octets); 185062306a36Sopenharmony_ci stats->rxdata_octets = le64_to_cpu(ql_iscsi_stats->rx_data_octets); 185162306a36Sopenharmony_ci /* xmit pdus */ 185262306a36Sopenharmony_ci stats->noptx_pdus = le32_to_cpu(ql_iscsi_stats->tx_nopout_pdus); 185362306a36Sopenharmony_ci stats->scsicmd_pdus = le32_to_cpu(ql_iscsi_stats->tx_scsi_cmd_pdus); 185462306a36Sopenharmony_ci stats->tmfcmd_pdus = le32_to_cpu(ql_iscsi_stats->tx_tmf_cmd_pdus); 185562306a36Sopenharmony_ci stats->login_pdus = le32_to_cpu(ql_iscsi_stats->tx_login_cmd_pdus); 185662306a36Sopenharmony_ci stats->text_pdus = le32_to_cpu(ql_iscsi_stats->tx_text_cmd_pdus); 185762306a36Sopenharmony_ci stats->dataout_pdus = le32_to_cpu(ql_iscsi_stats->tx_scsi_write_pdus); 185862306a36Sopenharmony_ci stats->logout_pdus = le32_to_cpu(ql_iscsi_stats->tx_logout_cmd_pdus); 185962306a36Sopenharmony_ci stats->snack_pdus = le32_to_cpu(ql_iscsi_stats->tx_snack_req_pdus); 186062306a36Sopenharmony_ci /* recv pdus */ 186162306a36Sopenharmony_ci stats->noprx_pdus = le32_to_cpu(ql_iscsi_stats->rx_nopin_pdus); 186262306a36Sopenharmony_ci stats->scsirsp_pdus = le32_to_cpu(ql_iscsi_stats->rx_scsi_resp_pdus); 186362306a36Sopenharmony_ci stats->tmfrsp_pdus = le32_to_cpu(ql_iscsi_stats->rx_tmf_resp_pdus); 186462306a36Sopenharmony_ci stats->textrsp_pdus = le32_to_cpu(ql_iscsi_stats->rx_text_resp_pdus); 186562306a36Sopenharmony_ci stats->datain_pdus = le32_to_cpu(ql_iscsi_stats->rx_scsi_read_pdus); 186662306a36Sopenharmony_ci stats->logoutrsp_pdus = 186762306a36Sopenharmony_ci le32_to_cpu(ql_iscsi_stats->rx_logout_resp_pdus); 186862306a36Sopenharmony_ci stats->r2t_pdus = le32_to_cpu(ql_iscsi_stats->rx_r2t_pdus); 186962306a36Sopenharmony_ci stats->async_pdus = le32_to_cpu(ql_iscsi_stats->rx_async_pdus); 187062306a36Sopenharmony_ci stats->rjt_pdus = le32_to_cpu(ql_iscsi_stats->rx_reject_pdus); 187162306a36Sopenharmony_ci 187262306a36Sopenharmony_cifree_stats: 187362306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, stats_size, ql_iscsi_stats, 187462306a36Sopenharmony_ci iscsi_stats_dma); 187562306a36Sopenharmony_ciexit_get_stats: 187662306a36Sopenharmony_ci return; 187762306a36Sopenharmony_ci} 187862306a36Sopenharmony_ci 187962306a36Sopenharmony_cistatic enum scsi_timeout_action qla4xxx_eh_cmd_timed_out(struct scsi_cmnd *sc) 188062306a36Sopenharmony_ci{ 188162306a36Sopenharmony_ci struct iscsi_cls_session *session; 188262306a36Sopenharmony_ci unsigned long flags; 188362306a36Sopenharmony_ci enum scsi_timeout_action ret = SCSI_EH_NOT_HANDLED; 188462306a36Sopenharmony_ci 188562306a36Sopenharmony_ci session = starget_to_session(scsi_target(sc->device)); 188662306a36Sopenharmony_ci 188762306a36Sopenharmony_ci spin_lock_irqsave(&session->lock, flags); 188862306a36Sopenharmony_ci if (session->state == ISCSI_SESSION_FAILED) 188962306a36Sopenharmony_ci ret = SCSI_EH_RESET_TIMER; 189062306a36Sopenharmony_ci spin_unlock_irqrestore(&session->lock, flags); 189162306a36Sopenharmony_ci 189262306a36Sopenharmony_ci return ret; 189362306a36Sopenharmony_ci} 189462306a36Sopenharmony_ci 189562306a36Sopenharmony_cistatic void qla4xxx_set_port_speed(struct Scsi_Host *shost) 189662306a36Sopenharmony_ci{ 189762306a36Sopenharmony_ci struct scsi_qla_host *ha = to_qla_host(shost); 189862306a36Sopenharmony_ci struct iscsi_cls_host *ihost = shost->shost_data; 189962306a36Sopenharmony_ci uint32_t speed = ISCSI_PORT_SPEED_UNKNOWN; 190062306a36Sopenharmony_ci 190162306a36Sopenharmony_ci qla4xxx_get_firmware_state(ha); 190262306a36Sopenharmony_ci 190362306a36Sopenharmony_ci switch (ha->addl_fw_state & 0x0F00) { 190462306a36Sopenharmony_ci case FW_ADDSTATE_LINK_SPEED_10MBPS: 190562306a36Sopenharmony_ci speed = ISCSI_PORT_SPEED_10MBPS; 190662306a36Sopenharmony_ci break; 190762306a36Sopenharmony_ci case FW_ADDSTATE_LINK_SPEED_100MBPS: 190862306a36Sopenharmony_ci speed = ISCSI_PORT_SPEED_100MBPS; 190962306a36Sopenharmony_ci break; 191062306a36Sopenharmony_ci case FW_ADDSTATE_LINK_SPEED_1GBPS: 191162306a36Sopenharmony_ci speed = ISCSI_PORT_SPEED_1GBPS; 191262306a36Sopenharmony_ci break; 191362306a36Sopenharmony_ci case FW_ADDSTATE_LINK_SPEED_10GBPS: 191462306a36Sopenharmony_ci speed = ISCSI_PORT_SPEED_10GBPS; 191562306a36Sopenharmony_ci break; 191662306a36Sopenharmony_ci } 191762306a36Sopenharmony_ci ihost->port_speed = speed; 191862306a36Sopenharmony_ci} 191962306a36Sopenharmony_ci 192062306a36Sopenharmony_cistatic void qla4xxx_set_port_state(struct Scsi_Host *shost) 192162306a36Sopenharmony_ci{ 192262306a36Sopenharmony_ci struct scsi_qla_host *ha = to_qla_host(shost); 192362306a36Sopenharmony_ci struct iscsi_cls_host *ihost = shost->shost_data; 192462306a36Sopenharmony_ci uint32_t state = ISCSI_PORT_STATE_DOWN; 192562306a36Sopenharmony_ci 192662306a36Sopenharmony_ci if (test_bit(AF_LINK_UP, &ha->flags)) 192762306a36Sopenharmony_ci state = ISCSI_PORT_STATE_UP; 192862306a36Sopenharmony_ci 192962306a36Sopenharmony_ci ihost->port_state = state; 193062306a36Sopenharmony_ci} 193162306a36Sopenharmony_ci 193262306a36Sopenharmony_cistatic int qla4xxx_host_get_param(struct Scsi_Host *shost, 193362306a36Sopenharmony_ci enum iscsi_host_param param, char *buf) 193462306a36Sopenharmony_ci{ 193562306a36Sopenharmony_ci struct scsi_qla_host *ha = to_qla_host(shost); 193662306a36Sopenharmony_ci int len; 193762306a36Sopenharmony_ci 193862306a36Sopenharmony_ci switch (param) { 193962306a36Sopenharmony_ci case ISCSI_HOST_PARAM_HWADDRESS: 194062306a36Sopenharmony_ci len = sysfs_format_mac(buf, ha->my_mac, MAC_ADDR_LEN); 194162306a36Sopenharmony_ci break; 194262306a36Sopenharmony_ci case ISCSI_HOST_PARAM_IPADDRESS: 194362306a36Sopenharmony_ci len = sprintf(buf, "%pI4\n", &ha->ip_config.ip_address); 194462306a36Sopenharmony_ci break; 194562306a36Sopenharmony_ci case ISCSI_HOST_PARAM_INITIATOR_NAME: 194662306a36Sopenharmony_ci len = sprintf(buf, "%s\n", ha->name_string); 194762306a36Sopenharmony_ci break; 194862306a36Sopenharmony_ci case ISCSI_HOST_PARAM_PORT_STATE: 194962306a36Sopenharmony_ci qla4xxx_set_port_state(shost); 195062306a36Sopenharmony_ci len = sprintf(buf, "%s\n", iscsi_get_port_state_name(shost)); 195162306a36Sopenharmony_ci break; 195262306a36Sopenharmony_ci case ISCSI_HOST_PARAM_PORT_SPEED: 195362306a36Sopenharmony_ci qla4xxx_set_port_speed(shost); 195462306a36Sopenharmony_ci len = sprintf(buf, "%s\n", iscsi_get_port_speed_name(shost)); 195562306a36Sopenharmony_ci break; 195662306a36Sopenharmony_ci default: 195762306a36Sopenharmony_ci return -ENOSYS; 195862306a36Sopenharmony_ci } 195962306a36Sopenharmony_ci 196062306a36Sopenharmony_ci return len; 196162306a36Sopenharmony_ci} 196262306a36Sopenharmony_ci 196362306a36Sopenharmony_cistatic void qla4xxx_create_ipv4_iface(struct scsi_qla_host *ha) 196462306a36Sopenharmony_ci{ 196562306a36Sopenharmony_ci if (ha->iface_ipv4) 196662306a36Sopenharmony_ci return; 196762306a36Sopenharmony_ci 196862306a36Sopenharmony_ci /* IPv4 */ 196962306a36Sopenharmony_ci ha->iface_ipv4 = iscsi_create_iface(ha->host, 197062306a36Sopenharmony_ci &qla4xxx_iscsi_transport, 197162306a36Sopenharmony_ci ISCSI_IFACE_TYPE_IPV4, 0, 0); 197262306a36Sopenharmony_ci if (!ha->iface_ipv4) 197362306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "Could not create IPv4 iSCSI " 197462306a36Sopenharmony_ci "iface0.\n"); 197562306a36Sopenharmony_ci} 197662306a36Sopenharmony_ci 197762306a36Sopenharmony_cistatic void qla4xxx_create_ipv6_iface(struct scsi_qla_host *ha) 197862306a36Sopenharmony_ci{ 197962306a36Sopenharmony_ci if (!ha->iface_ipv6_0) 198062306a36Sopenharmony_ci /* IPv6 iface-0 */ 198162306a36Sopenharmony_ci ha->iface_ipv6_0 = iscsi_create_iface(ha->host, 198262306a36Sopenharmony_ci &qla4xxx_iscsi_transport, 198362306a36Sopenharmony_ci ISCSI_IFACE_TYPE_IPV6, 0, 198462306a36Sopenharmony_ci 0); 198562306a36Sopenharmony_ci if (!ha->iface_ipv6_0) 198662306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "Could not create IPv6 iSCSI " 198762306a36Sopenharmony_ci "iface0.\n"); 198862306a36Sopenharmony_ci 198962306a36Sopenharmony_ci if (!ha->iface_ipv6_1) 199062306a36Sopenharmony_ci /* IPv6 iface-1 */ 199162306a36Sopenharmony_ci ha->iface_ipv6_1 = iscsi_create_iface(ha->host, 199262306a36Sopenharmony_ci &qla4xxx_iscsi_transport, 199362306a36Sopenharmony_ci ISCSI_IFACE_TYPE_IPV6, 1, 199462306a36Sopenharmony_ci 0); 199562306a36Sopenharmony_ci if (!ha->iface_ipv6_1) 199662306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "Could not create IPv6 iSCSI " 199762306a36Sopenharmony_ci "iface1.\n"); 199862306a36Sopenharmony_ci} 199962306a36Sopenharmony_ci 200062306a36Sopenharmony_cistatic void qla4xxx_create_ifaces(struct scsi_qla_host *ha) 200162306a36Sopenharmony_ci{ 200262306a36Sopenharmony_ci if (ha->ip_config.ipv4_options & IPOPT_IPV4_PROTOCOL_ENABLE) 200362306a36Sopenharmony_ci qla4xxx_create_ipv4_iface(ha); 200462306a36Sopenharmony_ci 200562306a36Sopenharmony_ci if (ha->ip_config.ipv6_options & IPV6_OPT_IPV6_PROTOCOL_ENABLE) 200662306a36Sopenharmony_ci qla4xxx_create_ipv6_iface(ha); 200762306a36Sopenharmony_ci} 200862306a36Sopenharmony_ci 200962306a36Sopenharmony_cistatic void qla4xxx_destroy_ipv4_iface(struct scsi_qla_host *ha) 201062306a36Sopenharmony_ci{ 201162306a36Sopenharmony_ci if (ha->iface_ipv4) { 201262306a36Sopenharmony_ci iscsi_destroy_iface(ha->iface_ipv4); 201362306a36Sopenharmony_ci ha->iface_ipv4 = NULL; 201462306a36Sopenharmony_ci } 201562306a36Sopenharmony_ci} 201662306a36Sopenharmony_ci 201762306a36Sopenharmony_cistatic void qla4xxx_destroy_ipv6_iface(struct scsi_qla_host *ha) 201862306a36Sopenharmony_ci{ 201962306a36Sopenharmony_ci if (ha->iface_ipv6_0) { 202062306a36Sopenharmony_ci iscsi_destroy_iface(ha->iface_ipv6_0); 202162306a36Sopenharmony_ci ha->iface_ipv6_0 = NULL; 202262306a36Sopenharmony_ci } 202362306a36Sopenharmony_ci if (ha->iface_ipv6_1) { 202462306a36Sopenharmony_ci iscsi_destroy_iface(ha->iface_ipv6_1); 202562306a36Sopenharmony_ci ha->iface_ipv6_1 = NULL; 202662306a36Sopenharmony_ci } 202762306a36Sopenharmony_ci} 202862306a36Sopenharmony_ci 202962306a36Sopenharmony_cistatic void qla4xxx_destroy_ifaces(struct scsi_qla_host *ha) 203062306a36Sopenharmony_ci{ 203162306a36Sopenharmony_ci qla4xxx_destroy_ipv4_iface(ha); 203262306a36Sopenharmony_ci qla4xxx_destroy_ipv6_iface(ha); 203362306a36Sopenharmony_ci} 203462306a36Sopenharmony_ci 203562306a36Sopenharmony_cistatic void qla4xxx_set_ipv6(struct scsi_qla_host *ha, 203662306a36Sopenharmony_ci struct iscsi_iface_param_info *iface_param, 203762306a36Sopenharmony_ci struct addr_ctrl_blk *init_fw_cb) 203862306a36Sopenharmony_ci{ 203962306a36Sopenharmony_ci /* 204062306a36Sopenharmony_ci * iface_num 0 is valid for IPv6 Addr, linklocal, router, autocfg. 204162306a36Sopenharmony_ci * iface_num 1 is valid only for IPv6 Addr. 204262306a36Sopenharmony_ci */ 204362306a36Sopenharmony_ci switch (iface_param->param) { 204462306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV6_ADDR: 204562306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 204662306a36Sopenharmony_ci /* IPv6 Addr 1 */ 204762306a36Sopenharmony_ci memcpy(init_fw_cb->ipv6_addr1, iface_param->value, 204862306a36Sopenharmony_ci sizeof(init_fw_cb->ipv6_addr1)); 204962306a36Sopenharmony_ci else 205062306a36Sopenharmony_ci /* IPv6 Addr 0 */ 205162306a36Sopenharmony_ci memcpy(init_fw_cb->ipv6_addr0, iface_param->value, 205262306a36Sopenharmony_ci sizeof(init_fw_cb->ipv6_addr0)); 205362306a36Sopenharmony_ci break; 205462306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV6_LINKLOCAL: 205562306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 205662306a36Sopenharmony_ci break; 205762306a36Sopenharmony_ci memcpy(init_fw_cb->ipv6_if_id, &iface_param->value[8], 205862306a36Sopenharmony_ci sizeof(init_fw_cb->ipv6_if_id)); 205962306a36Sopenharmony_ci break; 206062306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV6_ROUTER: 206162306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 206262306a36Sopenharmony_ci break; 206362306a36Sopenharmony_ci memcpy(init_fw_cb->ipv6_dflt_rtr_addr, iface_param->value, 206462306a36Sopenharmony_ci sizeof(init_fw_cb->ipv6_dflt_rtr_addr)); 206562306a36Sopenharmony_ci break; 206662306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG: 206762306a36Sopenharmony_ci /* Autocfg applies to even interface */ 206862306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 206962306a36Sopenharmony_ci break; 207062306a36Sopenharmony_ci 207162306a36Sopenharmony_ci if (iface_param->value[0] == ISCSI_IPV6_AUTOCFG_DISABLE) 207262306a36Sopenharmony_ci init_fw_cb->ipv6_addtl_opts &= 207362306a36Sopenharmony_ci cpu_to_le16( 207462306a36Sopenharmony_ci ~IPV6_ADDOPT_NEIGHBOR_DISCOVERY_ADDR_ENABLE); 207562306a36Sopenharmony_ci else if (iface_param->value[0] == ISCSI_IPV6_AUTOCFG_ND_ENABLE) 207662306a36Sopenharmony_ci init_fw_cb->ipv6_addtl_opts |= 207762306a36Sopenharmony_ci cpu_to_le16( 207862306a36Sopenharmony_ci IPV6_ADDOPT_NEIGHBOR_DISCOVERY_ADDR_ENABLE); 207962306a36Sopenharmony_ci else 208062306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, 208162306a36Sopenharmony_ci "Invalid autocfg setting for IPv6 addr\n"); 208262306a36Sopenharmony_ci break; 208362306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG: 208462306a36Sopenharmony_ci /* Autocfg applies to even interface */ 208562306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 208662306a36Sopenharmony_ci break; 208762306a36Sopenharmony_ci 208862306a36Sopenharmony_ci if (iface_param->value[0] == 208962306a36Sopenharmony_ci ISCSI_IPV6_LINKLOCAL_AUTOCFG_ENABLE) 209062306a36Sopenharmony_ci init_fw_cb->ipv6_addtl_opts |= cpu_to_le16( 209162306a36Sopenharmony_ci IPV6_ADDOPT_AUTOCONFIG_LINK_LOCAL_ADDR); 209262306a36Sopenharmony_ci else if (iface_param->value[0] == 209362306a36Sopenharmony_ci ISCSI_IPV6_LINKLOCAL_AUTOCFG_DISABLE) 209462306a36Sopenharmony_ci init_fw_cb->ipv6_addtl_opts &= cpu_to_le16( 209562306a36Sopenharmony_ci ~IPV6_ADDOPT_AUTOCONFIG_LINK_LOCAL_ADDR); 209662306a36Sopenharmony_ci else 209762306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, 209862306a36Sopenharmony_ci "Invalid autocfg setting for IPv6 linklocal addr\n"); 209962306a36Sopenharmony_ci break; 210062306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV6_ROUTER_AUTOCFG: 210162306a36Sopenharmony_ci /* Autocfg applies to even interface */ 210262306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 210362306a36Sopenharmony_ci break; 210462306a36Sopenharmony_ci 210562306a36Sopenharmony_ci if (iface_param->value[0] == ISCSI_IPV6_ROUTER_AUTOCFG_ENABLE) 210662306a36Sopenharmony_ci memset(init_fw_cb->ipv6_dflt_rtr_addr, 0, 210762306a36Sopenharmony_ci sizeof(init_fw_cb->ipv6_dflt_rtr_addr)); 210862306a36Sopenharmony_ci break; 210962306a36Sopenharmony_ci case ISCSI_NET_PARAM_IFACE_ENABLE: 211062306a36Sopenharmony_ci if (iface_param->value[0] == ISCSI_IFACE_ENABLE) { 211162306a36Sopenharmony_ci init_fw_cb->ipv6_opts |= 211262306a36Sopenharmony_ci cpu_to_le16(IPV6_OPT_IPV6_PROTOCOL_ENABLE); 211362306a36Sopenharmony_ci qla4xxx_create_ipv6_iface(ha); 211462306a36Sopenharmony_ci } else { 211562306a36Sopenharmony_ci init_fw_cb->ipv6_opts &= 211662306a36Sopenharmony_ci cpu_to_le16(~IPV6_OPT_IPV6_PROTOCOL_ENABLE & 211762306a36Sopenharmony_ci 0xFFFF); 211862306a36Sopenharmony_ci qla4xxx_destroy_ipv6_iface(ha); 211962306a36Sopenharmony_ci } 212062306a36Sopenharmony_ci break; 212162306a36Sopenharmony_ci case ISCSI_NET_PARAM_VLAN_TAG: 212262306a36Sopenharmony_ci if (iface_param->len != sizeof(init_fw_cb->ipv6_vlan_tag)) 212362306a36Sopenharmony_ci break; 212462306a36Sopenharmony_ci init_fw_cb->ipv6_vlan_tag = 212562306a36Sopenharmony_ci cpu_to_be16(*(uint16_t *)iface_param->value); 212662306a36Sopenharmony_ci break; 212762306a36Sopenharmony_ci case ISCSI_NET_PARAM_VLAN_ENABLED: 212862306a36Sopenharmony_ci if (iface_param->value[0] == ISCSI_VLAN_ENABLE) 212962306a36Sopenharmony_ci init_fw_cb->ipv6_opts |= 213062306a36Sopenharmony_ci cpu_to_le16(IPV6_OPT_VLAN_TAGGING_ENABLE); 213162306a36Sopenharmony_ci else 213262306a36Sopenharmony_ci init_fw_cb->ipv6_opts &= 213362306a36Sopenharmony_ci cpu_to_le16(~IPV6_OPT_VLAN_TAGGING_ENABLE); 213462306a36Sopenharmony_ci break; 213562306a36Sopenharmony_ci case ISCSI_NET_PARAM_MTU: 213662306a36Sopenharmony_ci init_fw_cb->eth_mtu_size = 213762306a36Sopenharmony_ci cpu_to_le16(*(uint16_t *)iface_param->value); 213862306a36Sopenharmony_ci break; 213962306a36Sopenharmony_ci case ISCSI_NET_PARAM_PORT: 214062306a36Sopenharmony_ci /* Autocfg applies to even interface */ 214162306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 214262306a36Sopenharmony_ci break; 214362306a36Sopenharmony_ci 214462306a36Sopenharmony_ci init_fw_cb->ipv6_port = 214562306a36Sopenharmony_ci cpu_to_le16(*(uint16_t *)iface_param->value); 214662306a36Sopenharmony_ci break; 214762306a36Sopenharmony_ci case ISCSI_NET_PARAM_DELAYED_ACK_EN: 214862306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 214962306a36Sopenharmony_ci break; 215062306a36Sopenharmony_ci if (iface_param->value[0] == ISCSI_NET_PARAM_DISABLE) 215162306a36Sopenharmony_ci init_fw_cb->ipv6_tcp_opts |= 215262306a36Sopenharmony_ci cpu_to_le16(IPV6_TCPOPT_DELAYED_ACK_DISABLE); 215362306a36Sopenharmony_ci else 215462306a36Sopenharmony_ci init_fw_cb->ipv6_tcp_opts &= 215562306a36Sopenharmony_ci cpu_to_le16(~IPV6_TCPOPT_DELAYED_ACK_DISABLE & 215662306a36Sopenharmony_ci 0xFFFF); 215762306a36Sopenharmony_ci break; 215862306a36Sopenharmony_ci case ISCSI_NET_PARAM_TCP_NAGLE_DISABLE: 215962306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 216062306a36Sopenharmony_ci break; 216162306a36Sopenharmony_ci if (iface_param->value[0] == ISCSI_NET_PARAM_DISABLE) 216262306a36Sopenharmony_ci init_fw_cb->ipv6_tcp_opts |= 216362306a36Sopenharmony_ci cpu_to_le16(IPV6_TCPOPT_NAGLE_ALGO_DISABLE); 216462306a36Sopenharmony_ci else 216562306a36Sopenharmony_ci init_fw_cb->ipv6_tcp_opts &= 216662306a36Sopenharmony_ci cpu_to_le16(~IPV6_TCPOPT_NAGLE_ALGO_DISABLE); 216762306a36Sopenharmony_ci break; 216862306a36Sopenharmony_ci case ISCSI_NET_PARAM_TCP_WSF_DISABLE: 216962306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 217062306a36Sopenharmony_ci break; 217162306a36Sopenharmony_ci if (iface_param->value[0] == ISCSI_NET_PARAM_DISABLE) 217262306a36Sopenharmony_ci init_fw_cb->ipv6_tcp_opts |= 217362306a36Sopenharmony_ci cpu_to_le16(IPV6_TCPOPT_WINDOW_SCALE_DISABLE); 217462306a36Sopenharmony_ci else 217562306a36Sopenharmony_ci init_fw_cb->ipv6_tcp_opts &= 217662306a36Sopenharmony_ci cpu_to_le16(~IPV6_TCPOPT_WINDOW_SCALE_DISABLE); 217762306a36Sopenharmony_ci break; 217862306a36Sopenharmony_ci case ISCSI_NET_PARAM_TCP_WSF: 217962306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 218062306a36Sopenharmony_ci break; 218162306a36Sopenharmony_ci init_fw_cb->ipv6_tcp_wsf = iface_param->value[0]; 218262306a36Sopenharmony_ci break; 218362306a36Sopenharmony_ci case ISCSI_NET_PARAM_TCP_TIMER_SCALE: 218462306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 218562306a36Sopenharmony_ci break; 218662306a36Sopenharmony_ci init_fw_cb->ipv6_tcp_opts &= 218762306a36Sopenharmony_ci cpu_to_le16(~IPV6_TCPOPT_TIMER_SCALE); 218862306a36Sopenharmony_ci init_fw_cb->ipv6_tcp_opts |= 218962306a36Sopenharmony_ci cpu_to_le16((iface_param->value[0] << 1) & 219062306a36Sopenharmony_ci IPV6_TCPOPT_TIMER_SCALE); 219162306a36Sopenharmony_ci break; 219262306a36Sopenharmony_ci case ISCSI_NET_PARAM_TCP_TIMESTAMP_EN: 219362306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 219462306a36Sopenharmony_ci break; 219562306a36Sopenharmony_ci if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE) 219662306a36Sopenharmony_ci init_fw_cb->ipv6_tcp_opts |= 219762306a36Sopenharmony_ci cpu_to_le16(IPV6_TCPOPT_TIMESTAMP_EN); 219862306a36Sopenharmony_ci else 219962306a36Sopenharmony_ci init_fw_cb->ipv6_tcp_opts &= 220062306a36Sopenharmony_ci cpu_to_le16(~IPV6_TCPOPT_TIMESTAMP_EN); 220162306a36Sopenharmony_ci break; 220262306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV6_GRAT_NEIGHBOR_ADV_EN: 220362306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 220462306a36Sopenharmony_ci break; 220562306a36Sopenharmony_ci if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE) 220662306a36Sopenharmony_ci init_fw_cb->ipv6_opts |= 220762306a36Sopenharmony_ci cpu_to_le16(IPV6_OPT_GRAT_NEIGHBOR_ADV_EN); 220862306a36Sopenharmony_ci else 220962306a36Sopenharmony_ci init_fw_cb->ipv6_opts &= 221062306a36Sopenharmony_ci cpu_to_le16(~IPV6_OPT_GRAT_NEIGHBOR_ADV_EN); 221162306a36Sopenharmony_ci break; 221262306a36Sopenharmony_ci case ISCSI_NET_PARAM_REDIRECT_EN: 221362306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 221462306a36Sopenharmony_ci break; 221562306a36Sopenharmony_ci if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE) 221662306a36Sopenharmony_ci init_fw_cb->ipv6_opts |= 221762306a36Sopenharmony_ci cpu_to_le16(IPV6_OPT_REDIRECT_EN); 221862306a36Sopenharmony_ci else 221962306a36Sopenharmony_ci init_fw_cb->ipv6_opts &= 222062306a36Sopenharmony_ci cpu_to_le16(~IPV6_OPT_REDIRECT_EN); 222162306a36Sopenharmony_ci break; 222262306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV6_MLD_EN: 222362306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 222462306a36Sopenharmony_ci break; 222562306a36Sopenharmony_ci if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE) 222662306a36Sopenharmony_ci init_fw_cb->ipv6_addtl_opts |= 222762306a36Sopenharmony_ci cpu_to_le16(IPV6_ADDOPT_MLD_EN); 222862306a36Sopenharmony_ci else 222962306a36Sopenharmony_ci init_fw_cb->ipv6_addtl_opts &= 223062306a36Sopenharmony_ci cpu_to_le16(~IPV6_ADDOPT_MLD_EN); 223162306a36Sopenharmony_ci break; 223262306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV6_FLOW_LABEL: 223362306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 223462306a36Sopenharmony_ci break; 223562306a36Sopenharmony_ci init_fw_cb->ipv6_flow_lbl = 223662306a36Sopenharmony_ci cpu_to_le16(*(uint16_t *)iface_param->value); 223762306a36Sopenharmony_ci break; 223862306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV6_TRAFFIC_CLASS: 223962306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 224062306a36Sopenharmony_ci break; 224162306a36Sopenharmony_ci init_fw_cb->ipv6_traffic_class = iface_param->value[0]; 224262306a36Sopenharmony_ci break; 224362306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV6_HOP_LIMIT: 224462306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 224562306a36Sopenharmony_ci break; 224662306a36Sopenharmony_ci init_fw_cb->ipv6_hop_limit = iface_param->value[0]; 224762306a36Sopenharmony_ci break; 224862306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV6_ND_REACHABLE_TMO: 224962306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 225062306a36Sopenharmony_ci break; 225162306a36Sopenharmony_ci init_fw_cb->ipv6_nd_reach_time = 225262306a36Sopenharmony_ci cpu_to_le32(*(uint32_t *)iface_param->value); 225362306a36Sopenharmony_ci break; 225462306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV6_ND_REXMIT_TIME: 225562306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 225662306a36Sopenharmony_ci break; 225762306a36Sopenharmony_ci init_fw_cb->ipv6_nd_rexmit_timer = 225862306a36Sopenharmony_ci cpu_to_le32(*(uint32_t *)iface_param->value); 225962306a36Sopenharmony_ci break; 226062306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV6_ND_STALE_TMO: 226162306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 226262306a36Sopenharmony_ci break; 226362306a36Sopenharmony_ci init_fw_cb->ipv6_nd_stale_timeout = 226462306a36Sopenharmony_ci cpu_to_le32(*(uint32_t *)iface_param->value); 226562306a36Sopenharmony_ci break; 226662306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV6_DUP_ADDR_DETECT_CNT: 226762306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 226862306a36Sopenharmony_ci break; 226962306a36Sopenharmony_ci init_fw_cb->ipv6_dup_addr_detect_count = iface_param->value[0]; 227062306a36Sopenharmony_ci break; 227162306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV6_RTR_ADV_LINK_MTU: 227262306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 227362306a36Sopenharmony_ci break; 227462306a36Sopenharmony_ci init_fw_cb->ipv6_gw_advrt_mtu = 227562306a36Sopenharmony_ci cpu_to_le32(*(uint32_t *)iface_param->value); 227662306a36Sopenharmony_ci break; 227762306a36Sopenharmony_ci default: 227862306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "Unknown IPv6 param = %d\n", 227962306a36Sopenharmony_ci iface_param->param); 228062306a36Sopenharmony_ci break; 228162306a36Sopenharmony_ci } 228262306a36Sopenharmony_ci} 228362306a36Sopenharmony_ci 228462306a36Sopenharmony_cistatic void qla4xxx_set_ipv4(struct scsi_qla_host *ha, 228562306a36Sopenharmony_ci struct iscsi_iface_param_info *iface_param, 228662306a36Sopenharmony_ci struct addr_ctrl_blk *init_fw_cb) 228762306a36Sopenharmony_ci{ 228862306a36Sopenharmony_ci switch (iface_param->param) { 228962306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV4_ADDR: 229062306a36Sopenharmony_ci memcpy(init_fw_cb->ipv4_addr, iface_param->value, 229162306a36Sopenharmony_ci sizeof(init_fw_cb->ipv4_addr)); 229262306a36Sopenharmony_ci break; 229362306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV4_SUBNET: 229462306a36Sopenharmony_ci memcpy(init_fw_cb->ipv4_subnet, iface_param->value, 229562306a36Sopenharmony_ci sizeof(init_fw_cb->ipv4_subnet)); 229662306a36Sopenharmony_ci break; 229762306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV4_GW: 229862306a36Sopenharmony_ci memcpy(init_fw_cb->ipv4_gw_addr, iface_param->value, 229962306a36Sopenharmony_ci sizeof(init_fw_cb->ipv4_gw_addr)); 230062306a36Sopenharmony_ci break; 230162306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV4_BOOTPROTO: 230262306a36Sopenharmony_ci if (iface_param->value[0] == ISCSI_BOOTPROTO_DHCP) 230362306a36Sopenharmony_ci init_fw_cb->ipv4_tcp_opts |= 230462306a36Sopenharmony_ci cpu_to_le16(TCPOPT_DHCP_ENABLE); 230562306a36Sopenharmony_ci else if (iface_param->value[0] == ISCSI_BOOTPROTO_STATIC) 230662306a36Sopenharmony_ci init_fw_cb->ipv4_tcp_opts &= 230762306a36Sopenharmony_ci cpu_to_le16(~TCPOPT_DHCP_ENABLE); 230862306a36Sopenharmony_ci else 230962306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "Invalid IPv4 bootproto\n"); 231062306a36Sopenharmony_ci break; 231162306a36Sopenharmony_ci case ISCSI_NET_PARAM_IFACE_ENABLE: 231262306a36Sopenharmony_ci if (iface_param->value[0] == ISCSI_IFACE_ENABLE) { 231362306a36Sopenharmony_ci init_fw_cb->ipv4_ip_opts |= 231462306a36Sopenharmony_ci cpu_to_le16(IPOPT_IPV4_PROTOCOL_ENABLE); 231562306a36Sopenharmony_ci qla4xxx_create_ipv4_iface(ha); 231662306a36Sopenharmony_ci } else { 231762306a36Sopenharmony_ci init_fw_cb->ipv4_ip_opts &= 231862306a36Sopenharmony_ci cpu_to_le16(~IPOPT_IPV4_PROTOCOL_ENABLE & 231962306a36Sopenharmony_ci 0xFFFF); 232062306a36Sopenharmony_ci qla4xxx_destroy_ipv4_iface(ha); 232162306a36Sopenharmony_ci } 232262306a36Sopenharmony_ci break; 232362306a36Sopenharmony_ci case ISCSI_NET_PARAM_VLAN_TAG: 232462306a36Sopenharmony_ci if (iface_param->len != sizeof(init_fw_cb->ipv4_vlan_tag)) 232562306a36Sopenharmony_ci break; 232662306a36Sopenharmony_ci init_fw_cb->ipv4_vlan_tag = 232762306a36Sopenharmony_ci cpu_to_be16(*(uint16_t *)iface_param->value); 232862306a36Sopenharmony_ci break; 232962306a36Sopenharmony_ci case ISCSI_NET_PARAM_VLAN_ENABLED: 233062306a36Sopenharmony_ci if (iface_param->value[0] == ISCSI_VLAN_ENABLE) 233162306a36Sopenharmony_ci init_fw_cb->ipv4_ip_opts |= 233262306a36Sopenharmony_ci cpu_to_le16(IPOPT_VLAN_TAGGING_ENABLE); 233362306a36Sopenharmony_ci else 233462306a36Sopenharmony_ci init_fw_cb->ipv4_ip_opts &= 233562306a36Sopenharmony_ci cpu_to_le16(~IPOPT_VLAN_TAGGING_ENABLE); 233662306a36Sopenharmony_ci break; 233762306a36Sopenharmony_ci case ISCSI_NET_PARAM_MTU: 233862306a36Sopenharmony_ci init_fw_cb->eth_mtu_size = 233962306a36Sopenharmony_ci cpu_to_le16(*(uint16_t *)iface_param->value); 234062306a36Sopenharmony_ci break; 234162306a36Sopenharmony_ci case ISCSI_NET_PARAM_PORT: 234262306a36Sopenharmony_ci init_fw_cb->ipv4_port = 234362306a36Sopenharmony_ci cpu_to_le16(*(uint16_t *)iface_param->value); 234462306a36Sopenharmony_ci break; 234562306a36Sopenharmony_ci case ISCSI_NET_PARAM_DELAYED_ACK_EN: 234662306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 234762306a36Sopenharmony_ci break; 234862306a36Sopenharmony_ci if (iface_param->value[0] == ISCSI_NET_PARAM_DISABLE) 234962306a36Sopenharmony_ci init_fw_cb->ipv4_tcp_opts |= 235062306a36Sopenharmony_ci cpu_to_le16(TCPOPT_DELAYED_ACK_DISABLE); 235162306a36Sopenharmony_ci else 235262306a36Sopenharmony_ci init_fw_cb->ipv4_tcp_opts &= 235362306a36Sopenharmony_ci cpu_to_le16(~TCPOPT_DELAYED_ACK_DISABLE & 235462306a36Sopenharmony_ci 0xFFFF); 235562306a36Sopenharmony_ci break; 235662306a36Sopenharmony_ci case ISCSI_NET_PARAM_TCP_NAGLE_DISABLE: 235762306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 235862306a36Sopenharmony_ci break; 235962306a36Sopenharmony_ci if (iface_param->value[0] == ISCSI_NET_PARAM_DISABLE) 236062306a36Sopenharmony_ci init_fw_cb->ipv4_tcp_opts |= 236162306a36Sopenharmony_ci cpu_to_le16(TCPOPT_NAGLE_ALGO_DISABLE); 236262306a36Sopenharmony_ci else 236362306a36Sopenharmony_ci init_fw_cb->ipv4_tcp_opts &= 236462306a36Sopenharmony_ci cpu_to_le16(~TCPOPT_NAGLE_ALGO_DISABLE); 236562306a36Sopenharmony_ci break; 236662306a36Sopenharmony_ci case ISCSI_NET_PARAM_TCP_WSF_DISABLE: 236762306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 236862306a36Sopenharmony_ci break; 236962306a36Sopenharmony_ci if (iface_param->value[0] == ISCSI_NET_PARAM_DISABLE) 237062306a36Sopenharmony_ci init_fw_cb->ipv4_tcp_opts |= 237162306a36Sopenharmony_ci cpu_to_le16(TCPOPT_WINDOW_SCALE_DISABLE); 237262306a36Sopenharmony_ci else 237362306a36Sopenharmony_ci init_fw_cb->ipv4_tcp_opts &= 237462306a36Sopenharmony_ci cpu_to_le16(~TCPOPT_WINDOW_SCALE_DISABLE); 237562306a36Sopenharmony_ci break; 237662306a36Sopenharmony_ci case ISCSI_NET_PARAM_TCP_WSF: 237762306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 237862306a36Sopenharmony_ci break; 237962306a36Sopenharmony_ci init_fw_cb->ipv4_tcp_wsf = iface_param->value[0]; 238062306a36Sopenharmony_ci break; 238162306a36Sopenharmony_ci case ISCSI_NET_PARAM_TCP_TIMER_SCALE: 238262306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 238362306a36Sopenharmony_ci break; 238462306a36Sopenharmony_ci init_fw_cb->ipv4_tcp_opts &= cpu_to_le16(~TCPOPT_TIMER_SCALE); 238562306a36Sopenharmony_ci init_fw_cb->ipv4_tcp_opts |= 238662306a36Sopenharmony_ci cpu_to_le16((iface_param->value[0] << 1) & 238762306a36Sopenharmony_ci TCPOPT_TIMER_SCALE); 238862306a36Sopenharmony_ci break; 238962306a36Sopenharmony_ci case ISCSI_NET_PARAM_TCP_TIMESTAMP_EN: 239062306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 239162306a36Sopenharmony_ci break; 239262306a36Sopenharmony_ci if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE) 239362306a36Sopenharmony_ci init_fw_cb->ipv4_tcp_opts |= 239462306a36Sopenharmony_ci cpu_to_le16(TCPOPT_TIMESTAMP_ENABLE); 239562306a36Sopenharmony_ci else 239662306a36Sopenharmony_ci init_fw_cb->ipv4_tcp_opts &= 239762306a36Sopenharmony_ci cpu_to_le16(~TCPOPT_TIMESTAMP_ENABLE); 239862306a36Sopenharmony_ci break; 239962306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV4_DHCP_DNS_ADDR_EN: 240062306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 240162306a36Sopenharmony_ci break; 240262306a36Sopenharmony_ci if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE) 240362306a36Sopenharmony_ci init_fw_cb->ipv4_tcp_opts |= 240462306a36Sopenharmony_ci cpu_to_le16(TCPOPT_DNS_SERVER_IP_EN); 240562306a36Sopenharmony_ci else 240662306a36Sopenharmony_ci init_fw_cb->ipv4_tcp_opts &= 240762306a36Sopenharmony_ci cpu_to_le16(~TCPOPT_DNS_SERVER_IP_EN); 240862306a36Sopenharmony_ci break; 240962306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV4_DHCP_SLP_DA_EN: 241062306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 241162306a36Sopenharmony_ci break; 241262306a36Sopenharmony_ci if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE) 241362306a36Sopenharmony_ci init_fw_cb->ipv4_tcp_opts |= 241462306a36Sopenharmony_ci cpu_to_le16(TCPOPT_SLP_DA_INFO_EN); 241562306a36Sopenharmony_ci else 241662306a36Sopenharmony_ci init_fw_cb->ipv4_tcp_opts &= 241762306a36Sopenharmony_ci cpu_to_le16(~TCPOPT_SLP_DA_INFO_EN); 241862306a36Sopenharmony_ci break; 241962306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV4_TOS_EN: 242062306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 242162306a36Sopenharmony_ci break; 242262306a36Sopenharmony_ci if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE) 242362306a36Sopenharmony_ci init_fw_cb->ipv4_ip_opts |= 242462306a36Sopenharmony_ci cpu_to_le16(IPOPT_IPV4_TOS_EN); 242562306a36Sopenharmony_ci else 242662306a36Sopenharmony_ci init_fw_cb->ipv4_ip_opts &= 242762306a36Sopenharmony_ci cpu_to_le16(~IPOPT_IPV4_TOS_EN); 242862306a36Sopenharmony_ci break; 242962306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV4_TOS: 243062306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 243162306a36Sopenharmony_ci break; 243262306a36Sopenharmony_ci init_fw_cb->ipv4_tos = iface_param->value[0]; 243362306a36Sopenharmony_ci break; 243462306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV4_GRAT_ARP_EN: 243562306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 243662306a36Sopenharmony_ci break; 243762306a36Sopenharmony_ci if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE) 243862306a36Sopenharmony_ci init_fw_cb->ipv4_ip_opts |= 243962306a36Sopenharmony_ci cpu_to_le16(IPOPT_GRAT_ARP_EN); 244062306a36Sopenharmony_ci else 244162306a36Sopenharmony_ci init_fw_cb->ipv4_ip_opts &= 244262306a36Sopenharmony_ci cpu_to_le16(~IPOPT_GRAT_ARP_EN); 244362306a36Sopenharmony_ci break; 244462306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV4_DHCP_ALT_CLIENT_ID_EN: 244562306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 244662306a36Sopenharmony_ci break; 244762306a36Sopenharmony_ci if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE) 244862306a36Sopenharmony_ci init_fw_cb->ipv4_ip_opts |= 244962306a36Sopenharmony_ci cpu_to_le16(IPOPT_ALT_CID_EN); 245062306a36Sopenharmony_ci else 245162306a36Sopenharmony_ci init_fw_cb->ipv4_ip_opts &= 245262306a36Sopenharmony_ci cpu_to_le16(~IPOPT_ALT_CID_EN); 245362306a36Sopenharmony_ci break; 245462306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV4_DHCP_ALT_CLIENT_ID: 245562306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 245662306a36Sopenharmony_ci break; 245762306a36Sopenharmony_ci memcpy(init_fw_cb->ipv4_dhcp_alt_cid, iface_param->value, 245862306a36Sopenharmony_ci (sizeof(init_fw_cb->ipv4_dhcp_alt_cid) - 1)); 245962306a36Sopenharmony_ci init_fw_cb->ipv4_dhcp_alt_cid_len = 246062306a36Sopenharmony_ci strlen(init_fw_cb->ipv4_dhcp_alt_cid); 246162306a36Sopenharmony_ci break; 246262306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV4_DHCP_REQ_VENDOR_ID_EN: 246362306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 246462306a36Sopenharmony_ci break; 246562306a36Sopenharmony_ci if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE) 246662306a36Sopenharmony_ci init_fw_cb->ipv4_ip_opts |= 246762306a36Sopenharmony_ci cpu_to_le16(IPOPT_REQ_VID_EN); 246862306a36Sopenharmony_ci else 246962306a36Sopenharmony_ci init_fw_cb->ipv4_ip_opts &= 247062306a36Sopenharmony_ci cpu_to_le16(~IPOPT_REQ_VID_EN); 247162306a36Sopenharmony_ci break; 247262306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV4_DHCP_USE_VENDOR_ID_EN: 247362306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 247462306a36Sopenharmony_ci break; 247562306a36Sopenharmony_ci if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE) 247662306a36Sopenharmony_ci init_fw_cb->ipv4_ip_opts |= 247762306a36Sopenharmony_ci cpu_to_le16(IPOPT_USE_VID_EN); 247862306a36Sopenharmony_ci else 247962306a36Sopenharmony_ci init_fw_cb->ipv4_ip_opts &= 248062306a36Sopenharmony_ci cpu_to_le16(~IPOPT_USE_VID_EN); 248162306a36Sopenharmony_ci break; 248262306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV4_DHCP_VENDOR_ID: 248362306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 248462306a36Sopenharmony_ci break; 248562306a36Sopenharmony_ci memcpy(init_fw_cb->ipv4_dhcp_vid, iface_param->value, 248662306a36Sopenharmony_ci (sizeof(init_fw_cb->ipv4_dhcp_vid) - 1)); 248762306a36Sopenharmony_ci init_fw_cb->ipv4_dhcp_vid_len = 248862306a36Sopenharmony_ci strlen(init_fw_cb->ipv4_dhcp_vid); 248962306a36Sopenharmony_ci break; 249062306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV4_DHCP_LEARN_IQN_EN: 249162306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 249262306a36Sopenharmony_ci break; 249362306a36Sopenharmony_ci if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE) 249462306a36Sopenharmony_ci init_fw_cb->ipv4_ip_opts |= 249562306a36Sopenharmony_ci cpu_to_le16(IPOPT_LEARN_IQN_EN); 249662306a36Sopenharmony_ci else 249762306a36Sopenharmony_ci init_fw_cb->ipv4_ip_opts &= 249862306a36Sopenharmony_ci cpu_to_le16(~IPOPT_LEARN_IQN_EN); 249962306a36Sopenharmony_ci break; 250062306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV4_FRAGMENT_DISABLE: 250162306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 250262306a36Sopenharmony_ci break; 250362306a36Sopenharmony_ci if (iface_param->value[0] == ISCSI_NET_PARAM_DISABLE) 250462306a36Sopenharmony_ci init_fw_cb->ipv4_ip_opts |= 250562306a36Sopenharmony_ci cpu_to_le16(IPOPT_FRAGMENTATION_DISABLE); 250662306a36Sopenharmony_ci else 250762306a36Sopenharmony_ci init_fw_cb->ipv4_ip_opts &= 250862306a36Sopenharmony_ci cpu_to_le16(~IPOPT_FRAGMENTATION_DISABLE); 250962306a36Sopenharmony_ci break; 251062306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV4_IN_FORWARD_EN: 251162306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 251262306a36Sopenharmony_ci break; 251362306a36Sopenharmony_ci if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE) 251462306a36Sopenharmony_ci init_fw_cb->ipv4_ip_opts |= 251562306a36Sopenharmony_ci cpu_to_le16(IPOPT_IN_FORWARD_EN); 251662306a36Sopenharmony_ci else 251762306a36Sopenharmony_ci init_fw_cb->ipv4_ip_opts &= 251862306a36Sopenharmony_ci cpu_to_le16(~IPOPT_IN_FORWARD_EN); 251962306a36Sopenharmony_ci break; 252062306a36Sopenharmony_ci case ISCSI_NET_PARAM_REDIRECT_EN: 252162306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 252262306a36Sopenharmony_ci break; 252362306a36Sopenharmony_ci if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE) 252462306a36Sopenharmony_ci init_fw_cb->ipv4_ip_opts |= 252562306a36Sopenharmony_ci cpu_to_le16(IPOPT_ARP_REDIRECT_EN); 252662306a36Sopenharmony_ci else 252762306a36Sopenharmony_ci init_fw_cb->ipv4_ip_opts &= 252862306a36Sopenharmony_ci cpu_to_le16(~IPOPT_ARP_REDIRECT_EN); 252962306a36Sopenharmony_ci break; 253062306a36Sopenharmony_ci case ISCSI_NET_PARAM_IPV4_TTL: 253162306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 253262306a36Sopenharmony_ci break; 253362306a36Sopenharmony_ci init_fw_cb->ipv4_ttl = iface_param->value[0]; 253462306a36Sopenharmony_ci break; 253562306a36Sopenharmony_ci default: 253662306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "Unknown IPv4 param = %d\n", 253762306a36Sopenharmony_ci iface_param->param); 253862306a36Sopenharmony_ci break; 253962306a36Sopenharmony_ci } 254062306a36Sopenharmony_ci} 254162306a36Sopenharmony_ci 254262306a36Sopenharmony_cistatic void qla4xxx_set_iscsi_param(struct scsi_qla_host *ha, 254362306a36Sopenharmony_ci struct iscsi_iface_param_info *iface_param, 254462306a36Sopenharmony_ci struct addr_ctrl_blk *init_fw_cb) 254562306a36Sopenharmony_ci{ 254662306a36Sopenharmony_ci switch (iface_param->param) { 254762306a36Sopenharmony_ci case ISCSI_IFACE_PARAM_DEF_TASKMGMT_TMO: 254862306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 254962306a36Sopenharmony_ci break; 255062306a36Sopenharmony_ci init_fw_cb->def_timeout = 255162306a36Sopenharmony_ci cpu_to_le16(*(uint16_t *)iface_param->value); 255262306a36Sopenharmony_ci break; 255362306a36Sopenharmony_ci case ISCSI_IFACE_PARAM_HDRDGST_EN: 255462306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 255562306a36Sopenharmony_ci break; 255662306a36Sopenharmony_ci if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE) 255762306a36Sopenharmony_ci init_fw_cb->iscsi_opts |= 255862306a36Sopenharmony_ci cpu_to_le16(ISCSIOPTS_HEADER_DIGEST_EN); 255962306a36Sopenharmony_ci else 256062306a36Sopenharmony_ci init_fw_cb->iscsi_opts &= 256162306a36Sopenharmony_ci cpu_to_le16(~ISCSIOPTS_HEADER_DIGEST_EN); 256262306a36Sopenharmony_ci break; 256362306a36Sopenharmony_ci case ISCSI_IFACE_PARAM_DATADGST_EN: 256462306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 256562306a36Sopenharmony_ci break; 256662306a36Sopenharmony_ci if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE) 256762306a36Sopenharmony_ci init_fw_cb->iscsi_opts |= 256862306a36Sopenharmony_ci cpu_to_le16(ISCSIOPTS_DATA_DIGEST_EN); 256962306a36Sopenharmony_ci else 257062306a36Sopenharmony_ci init_fw_cb->iscsi_opts &= 257162306a36Sopenharmony_ci cpu_to_le16(~ISCSIOPTS_DATA_DIGEST_EN); 257262306a36Sopenharmony_ci break; 257362306a36Sopenharmony_ci case ISCSI_IFACE_PARAM_IMM_DATA_EN: 257462306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 257562306a36Sopenharmony_ci break; 257662306a36Sopenharmony_ci if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE) 257762306a36Sopenharmony_ci init_fw_cb->iscsi_opts |= 257862306a36Sopenharmony_ci cpu_to_le16(ISCSIOPTS_IMMEDIATE_DATA_EN); 257962306a36Sopenharmony_ci else 258062306a36Sopenharmony_ci init_fw_cb->iscsi_opts &= 258162306a36Sopenharmony_ci cpu_to_le16(~ISCSIOPTS_IMMEDIATE_DATA_EN); 258262306a36Sopenharmony_ci break; 258362306a36Sopenharmony_ci case ISCSI_IFACE_PARAM_INITIAL_R2T_EN: 258462306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 258562306a36Sopenharmony_ci break; 258662306a36Sopenharmony_ci if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE) 258762306a36Sopenharmony_ci init_fw_cb->iscsi_opts |= 258862306a36Sopenharmony_ci cpu_to_le16(ISCSIOPTS_INITIAL_R2T_EN); 258962306a36Sopenharmony_ci else 259062306a36Sopenharmony_ci init_fw_cb->iscsi_opts &= 259162306a36Sopenharmony_ci cpu_to_le16(~ISCSIOPTS_INITIAL_R2T_EN); 259262306a36Sopenharmony_ci break; 259362306a36Sopenharmony_ci case ISCSI_IFACE_PARAM_DATASEQ_INORDER_EN: 259462306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 259562306a36Sopenharmony_ci break; 259662306a36Sopenharmony_ci if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE) 259762306a36Sopenharmony_ci init_fw_cb->iscsi_opts |= 259862306a36Sopenharmony_ci cpu_to_le16(ISCSIOPTS_DATA_SEQ_INORDER_EN); 259962306a36Sopenharmony_ci else 260062306a36Sopenharmony_ci init_fw_cb->iscsi_opts &= 260162306a36Sopenharmony_ci cpu_to_le16(~ISCSIOPTS_DATA_SEQ_INORDER_EN); 260262306a36Sopenharmony_ci break; 260362306a36Sopenharmony_ci case ISCSI_IFACE_PARAM_PDU_INORDER_EN: 260462306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 260562306a36Sopenharmony_ci break; 260662306a36Sopenharmony_ci if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE) 260762306a36Sopenharmony_ci init_fw_cb->iscsi_opts |= 260862306a36Sopenharmony_ci cpu_to_le16(ISCSIOPTS_DATA_PDU_INORDER_EN); 260962306a36Sopenharmony_ci else 261062306a36Sopenharmony_ci init_fw_cb->iscsi_opts &= 261162306a36Sopenharmony_ci cpu_to_le16(~ISCSIOPTS_DATA_PDU_INORDER_EN); 261262306a36Sopenharmony_ci break; 261362306a36Sopenharmony_ci case ISCSI_IFACE_PARAM_ERL: 261462306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 261562306a36Sopenharmony_ci break; 261662306a36Sopenharmony_ci init_fw_cb->iscsi_opts &= cpu_to_le16(~ISCSIOPTS_ERL); 261762306a36Sopenharmony_ci init_fw_cb->iscsi_opts |= cpu_to_le16(iface_param->value[0] & 261862306a36Sopenharmony_ci ISCSIOPTS_ERL); 261962306a36Sopenharmony_ci break; 262062306a36Sopenharmony_ci case ISCSI_IFACE_PARAM_MAX_RECV_DLENGTH: 262162306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 262262306a36Sopenharmony_ci break; 262362306a36Sopenharmony_ci init_fw_cb->iscsi_max_pdu_size = 262462306a36Sopenharmony_ci cpu_to_le32(*(uint32_t *)iface_param->value) / 262562306a36Sopenharmony_ci BYTE_UNITS; 262662306a36Sopenharmony_ci break; 262762306a36Sopenharmony_ci case ISCSI_IFACE_PARAM_FIRST_BURST: 262862306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 262962306a36Sopenharmony_ci break; 263062306a36Sopenharmony_ci init_fw_cb->iscsi_fburst_len = 263162306a36Sopenharmony_ci cpu_to_le32(*(uint32_t *)iface_param->value) / 263262306a36Sopenharmony_ci BYTE_UNITS; 263362306a36Sopenharmony_ci break; 263462306a36Sopenharmony_ci case ISCSI_IFACE_PARAM_MAX_R2T: 263562306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 263662306a36Sopenharmony_ci break; 263762306a36Sopenharmony_ci init_fw_cb->iscsi_max_outstnd_r2t = 263862306a36Sopenharmony_ci cpu_to_le16(*(uint16_t *)iface_param->value); 263962306a36Sopenharmony_ci break; 264062306a36Sopenharmony_ci case ISCSI_IFACE_PARAM_MAX_BURST: 264162306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 264262306a36Sopenharmony_ci break; 264362306a36Sopenharmony_ci init_fw_cb->iscsi_max_burst_len = 264462306a36Sopenharmony_ci cpu_to_le32(*(uint32_t *)iface_param->value) / 264562306a36Sopenharmony_ci BYTE_UNITS; 264662306a36Sopenharmony_ci break; 264762306a36Sopenharmony_ci case ISCSI_IFACE_PARAM_CHAP_AUTH_EN: 264862306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 264962306a36Sopenharmony_ci break; 265062306a36Sopenharmony_ci if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE) 265162306a36Sopenharmony_ci init_fw_cb->iscsi_opts |= 265262306a36Sopenharmony_ci cpu_to_le16(ISCSIOPTS_CHAP_AUTH_EN); 265362306a36Sopenharmony_ci else 265462306a36Sopenharmony_ci init_fw_cb->iscsi_opts &= 265562306a36Sopenharmony_ci cpu_to_le16(~ISCSIOPTS_CHAP_AUTH_EN); 265662306a36Sopenharmony_ci break; 265762306a36Sopenharmony_ci case ISCSI_IFACE_PARAM_BIDI_CHAP_EN: 265862306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 265962306a36Sopenharmony_ci break; 266062306a36Sopenharmony_ci if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE) 266162306a36Sopenharmony_ci init_fw_cb->iscsi_opts |= 266262306a36Sopenharmony_ci cpu_to_le16(ISCSIOPTS_BIDI_CHAP_EN); 266362306a36Sopenharmony_ci else 266462306a36Sopenharmony_ci init_fw_cb->iscsi_opts &= 266562306a36Sopenharmony_ci cpu_to_le16(~ISCSIOPTS_BIDI_CHAP_EN); 266662306a36Sopenharmony_ci break; 266762306a36Sopenharmony_ci case ISCSI_IFACE_PARAM_DISCOVERY_AUTH_OPTIONAL: 266862306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 266962306a36Sopenharmony_ci break; 267062306a36Sopenharmony_ci if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE) 267162306a36Sopenharmony_ci init_fw_cb->iscsi_opts |= 267262306a36Sopenharmony_ci cpu_to_le16(ISCSIOPTS_DISCOVERY_AUTH_EN); 267362306a36Sopenharmony_ci else 267462306a36Sopenharmony_ci init_fw_cb->iscsi_opts &= 267562306a36Sopenharmony_ci cpu_to_le16(~ISCSIOPTS_DISCOVERY_AUTH_EN); 267662306a36Sopenharmony_ci break; 267762306a36Sopenharmony_ci case ISCSI_IFACE_PARAM_DISCOVERY_LOGOUT_EN: 267862306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 267962306a36Sopenharmony_ci break; 268062306a36Sopenharmony_ci if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE) 268162306a36Sopenharmony_ci init_fw_cb->iscsi_opts |= 268262306a36Sopenharmony_ci cpu_to_le16(ISCSIOPTS_DISCOVERY_LOGOUT_EN); 268362306a36Sopenharmony_ci else 268462306a36Sopenharmony_ci init_fw_cb->iscsi_opts &= 268562306a36Sopenharmony_ci cpu_to_le16(~ISCSIOPTS_DISCOVERY_LOGOUT_EN); 268662306a36Sopenharmony_ci break; 268762306a36Sopenharmony_ci case ISCSI_IFACE_PARAM_STRICT_LOGIN_COMP_EN: 268862306a36Sopenharmony_ci if (iface_param->iface_num & 0x1) 268962306a36Sopenharmony_ci break; 269062306a36Sopenharmony_ci if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE) 269162306a36Sopenharmony_ci init_fw_cb->iscsi_opts |= 269262306a36Sopenharmony_ci cpu_to_le16(ISCSIOPTS_STRICT_LOGIN_COMP_EN); 269362306a36Sopenharmony_ci else 269462306a36Sopenharmony_ci init_fw_cb->iscsi_opts &= 269562306a36Sopenharmony_ci cpu_to_le16(~ISCSIOPTS_STRICT_LOGIN_COMP_EN); 269662306a36Sopenharmony_ci break; 269762306a36Sopenharmony_ci default: 269862306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "Unknown iscsi param = %d\n", 269962306a36Sopenharmony_ci iface_param->param); 270062306a36Sopenharmony_ci break; 270162306a36Sopenharmony_ci } 270262306a36Sopenharmony_ci} 270362306a36Sopenharmony_ci 270462306a36Sopenharmony_cistatic void 270562306a36Sopenharmony_ciqla4xxx_initcb_to_acb(struct addr_ctrl_blk *init_fw_cb) 270662306a36Sopenharmony_ci{ 270762306a36Sopenharmony_ci struct addr_ctrl_blk_def *acb; 270862306a36Sopenharmony_ci acb = (struct addr_ctrl_blk_def *)init_fw_cb; 270962306a36Sopenharmony_ci memset(acb->reserved1, 0, sizeof(acb->reserved1)); 271062306a36Sopenharmony_ci memset(acb->reserved2, 0, sizeof(acb->reserved2)); 271162306a36Sopenharmony_ci memset(acb->reserved3, 0, sizeof(acb->reserved3)); 271262306a36Sopenharmony_ci memset(acb->reserved4, 0, sizeof(acb->reserved4)); 271362306a36Sopenharmony_ci memset(acb->reserved5, 0, sizeof(acb->reserved5)); 271462306a36Sopenharmony_ci memset(acb->reserved6, 0, sizeof(acb->reserved6)); 271562306a36Sopenharmony_ci memset(acb->reserved7, 0, sizeof(acb->reserved7)); 271662306a36Sopenharmony_ci memset(acb->reserved8, 0, sizeof(acb->reserved8)); 271762306a36Sopenharmony_ci memset(acb->reserved9, 0, sizeof(acb->reserved9)); 271862306a36Sopenharmony_ci memset(acb->reserved10, 0, sizeof(acb->reserved10)); 271962306a36Sopenharmony_ci memset(acb->reserved11, 0, sizeof(acb->reserved11)); 272062306a36Sopenharmony_ci memset(acb->reserved12, 0, sizeof(acb->reserved12)); 272162306a36Sopenharmony_ci memset(acb->reserved13, 0, sizeof(acb->reserved13)); 272262306a36Sopenharmony_ci memset(acb->reserved14, 0, sizeof(acb->reserved14)); 272362306a36Sopenharmony_ci memset(acb->reserved15, 0, sizeof(acb->reserved15)); 272462306a36Sopenharmony_ci} 272562306a36Sopenharmony_ci 272662306a36Sopenharmony_cistatic int 272762306a36Sopenharmony_ciqla4xxx_iface_set_param(struct Scsi_Host *shost, void *data, uint32_t len) 272862306a36Sopenharmony_ci{ 272962306a36Sopenharmony_ci struct scsi_qla_host *ha = to_qla_host(shost); 273062306a36Sopenharmony_ci int rval = 0; 273162306a36Sopenharmony_ci struct iscsi_iface_param_info *iface_param = NULL; 273262306a36Sopenharmony_ci struct addr_ctrl_blk *init_fw_cb = NULL; 273362306a36Sopenharmony_ci dma_addr_t init_fw_cb_dma; 273462306a36Sopenharmony_ci uint32_t mbox_cmd[MBOX_REG_COUNT]; 273562306a36Sopenharmony_ci uint32_t mbox_sts[MBOX_REG_COUNT]; 273662306a36Sopenharmony_ci uint32_t rem = len; 273762306a36Sopenharmony_ci struct nlattr *attr; 273862306a36Sopenharmony_ci 273962306a36Sopenharmony_ci init_fw_cb = dma_alloc_coherent(&ha->pdev->dev, 274062306a36Sopenharmony_ci sizeof(struct addr_ctrl_blk), 274162306a36Sopenharmony_ci &init_fw_cb_dma, GFP_KERNEL); 274262306a36Sopenharmony_ci if (!init_fw_cb) { 274362306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: Unable to alloc init_cb\n", 274462306a36Sopenharmony_ci __func__); 274562306a36Sopenharmony_ci return -ENOMEM; 274662306a36Sopenharmony_ci } 274762306a36Sopenharmony_ci 274862306a36Sopenharmony_ci memset(&mbox_cmd, 0, sizeof(mbox_cmd)); 274962306a36Sopenharmony_ci memset(&mbox_sts, 0, sizeof(mbox_sts)); 275062306a36Sopenharmony_ci 275162306a36Sopenharmony_ci if (qla4xxx_get_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb_dma)) { 275262306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: get ifcb failed\n", __func__); 275362306a36Sopenharmony_ci rval = -EIO; 275462306a36Sopenharmony_ci goto exit_init_fw_cb; 275562306a36Sopenharmony_ci } 275662306a36Sopenharmony_ci 275762306a36Sopenharmony_ci nla_for_each_attr(attr, data, len, rem) { 275862306a36Sopenharmony_ci if (nla_len(attr) < sizeof(*iface_param)) { 275962306a36Sopenharmony_ci rval = -EINVAL; 276062306a36Sopenharmony_ci goto exit_init_fw_cb; 276162306a36Sopenharmony_ci } 276262306a36Sopenharmony_ci 276362306a36Sopenharmony_ci iface_param = nla_data(attr); 276462306a36Sopenharmony_ci 276562306a36Sopenharmony_ci if (iface_param->param_type == ISCSI_NET_PARAM) { 276662306a36Sopenharmony_ci switch (iface_param->iface_type) { 276762306a36Sopenharmony_ci case ISCSI_IFACE_TYPE_IPV4: 276862306a36Sopenharmony_ci switch (iface_param->iface_num) { 276962306a36Sopenharmony_ci case 0: 277062306a36Sopenharmony_ci qla4xxx_set_ipv4(ha, iface_param, 277162306a36Sopenharmony_ci init_fw_cb); 277262306a36Sopenharmony_ci break; 277362306a36Sopenharmony_ci default: 277462306a36Sopenharmony_ci /* Cannot have more than one IPv4 interface */ 277562306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, 277662306a36Sopenharmony_ci "Invalid IPv4 iface number = %d\n", 277762306a36Sopenharmony_ci iface_param->iface_num); 277862306a36Sopenharmony_ci break; 277962306a36Sopenharmony_ci } 278062306a36Sopenharmony_ci break; 278162306a36Sopenharmony_ci case ISCSI_IFACE_TYPE_IPV6: 278262306a36Sopenharmony_ci switch (iface_param->iface_num) { 278362306a36Sopenharmony_ci case 0: 278462306a36Sopenharmony_ci case 1: 278562306a36Sopenharmony_ci qla4xxx_set_ipv6(ha, iface_param, 278662306a36Sopenharmony_ci init_fw_cb); 278762306a36Sopenharmony_ci break; 278862306a36Sopenharmony_ci default: 278962306a36Sopenharmony_ci /* Cannot have more than two IPv6 interface */ 279062306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, 279162306a36Sopenharmony_ci "Invalid IPv6 iface number = %d\n", 279262306a36Sopenharmony_ci iface_param->iface_num); 279362306a36Sopenharmony_ci break; 279462306a36Sopenharmony_ci } 279562306a36Sopenharmony_ci break; 279662306a36Sopenharmony_ci default: 279762306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, 279862306a36Sopenharmony_ci "Invalid iface type\n"); 279962306a36Sopenharmony_ci break; 280062306a36Sopenharmony_ci } 280162306a36Sopenharmony_ci } else if (iface_param->param_type == ISCSI_IFACE_PARAM) { 280262306a36Sopenharmony_ci qla4xxx_set_iscsi_param(ha, iface_param, 280362306a36Sopenharmony_ci init_fw_cb); 280462306a36Sopenharmony_ci } else { 280562306a36Sopenharmony_ci continue; 280662306a36Sopenharmony_ci } 280762306a36Sopenharmony_ci } 280862306a36Sopenharmony_ci 280962306a36Sopenharmony_ci init_fw_cb->cookie = cpu_to_le32(0x11BEAD5A); 281062306a36Sopenharmony_ci 281162306a36Sopenharmony_ci rval = qla4xxx_set_flash(ha, init_fw_cb_dma, FLASH_SEGMENT_IFCB, 281262306a36Sopenharmony_ci sizeof(struct addr_ctrl_blk), 281362306a36Sopenharmony_ci FLASH_OPT_RMW_COMMIT); 281462306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 281562306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: set flash mbx failed\n", 281662306a36Sopenharmony_ci __func__); 281762306a36Sopenharmony_ci rval = -EIO; 281862306a36Sopenharmony_ci goto exit_init_fw_cb; 281962306a36Sopenharmony_ci } 282062306a36Sopenharmony_ci 282162306a36Sopenharmony_ci rval = qla4xxx_disable_acb(ha); 282262306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 282362306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: disable acb mbx failed\n", 282462306a36Sopenharmony_ci __func__); 282562306a36Sopenharmony_ci rval = -EIO; 282662306a36Sopenharmony_ci goto exit_init_fw_cb; 282762306a36Sopenharmony_ci } 282862306a36Sopenharmony_ci 282962306a36Sopenharmony_ci wait_for_completion_timeout(&ha->disable_acb_comp, 283062306a36Sopenharmony_ci DISABLE_ACB_TOV * HZ); 283162306a36Sopenharmony_ci 283262306a36Sopenharmony_ci qla4xxx_initcb_to_acb(init_fw_cb); 283362306a36Sopenharmony_ci 283462306a36Sopenharmony_ci rval = qla4xxx_set_acb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb_dma); 283562306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 283662306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: set acb mbx failed\n", 283762306a36Sopenharmony_ci __func__); 283862306a36Sopenharmony_ci rval = -EIO; 283962306a36Sopenharmony_ci goto exit_init_fw_cb; 284062306a36Sopenharmony_ci } 284162306a36Sopenharmony_ci 284262306a36Sopenharmony_ci memset(init_fw_cb, 0, sizeof(struct addr_ctrl_blk)); 284362306a36Sopenharmony_ci qla4xxx_update_local_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb, 284462306a36Sopenharmony_ci init_fw_cb_dma); 284562306a36Sopenharmony_ci 284662306a36Sopenharmony_ciexit_init_fw_cb: 284762306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, sizeof(struct addr_ctrl_blk), 284862306a36Sopenharmony_ci init_fw_cb, init_fw_cb_dma); 284962306a36Sopenharmony_ci 285062306a36Sopenharmony_ci return rval; 285162306a36Sopenharmony_ci} 285262306a36Sopenharmony_ci 285362306a36Sopenharmony_cistatic int qla4xxx_session_get_param(struct iscsi_cls_session *cls_sess, 285462306a36Sopenharmony_ci enum iscsi_param param, char *buf) 285562306a36Sopenharmony_ci{ 285662306a36Sopenharmony_ci struct iscsi_session *sess = cls_sess->dd_data; 285762306a36Sopenharmony_ci struct ddb_entry *ddb_entry = sess->dd_data; 285862306a36Sopenharmony_ci struct scsi_qla_host *ha = ddb_entry->ha; 285962306a36Sopenharmony_ci struct iscsi_cls_conn *cls_conn = ddb_entry->conn; 286062306a36Sopenharmony_ci struct ql4_chap_table chap_tbl; 286162306a36Sopenharmony_ci int rval, len; 286262306a36Sopenharmony_ci uint16_t idx; 286362306a36Sopenharmony_ci 286462306a36Sopenharmony_ci memset(&chap_tbl, 0, sizeof(chap_tbl)); 286562306a36Sopenharmony_ci switch (param) { 286662306a36Sopenharmony_ci case ISCSI_PARAM_CHAP_IN_IDX: 286762306a36Sopenharmony_ci rval = qla4xxx_get_chap_index(ha, sess->username_in, 286862306a36Sopenharmony_ci sess->password_in, BIDI_CHAP, 286962306a36Sopenharmony_ci &idx); 287062306a36Sopenharmony_ci if (rval) 287162306a36Sopenharmony_ci len = sprintf(buf, "\n"); 287262306a36Sopenharmony_ci else 287362306a36Sopenharmony_ci len = sprintf(buf, "%hu\n", idx); 287462306a36Sopenharmony_ci break; 287562306a36Sopenharmony_ci case ISCSI_PARAM_CHAP_OUT_IDX: 287662306a36Sopenharmony_ci if (ddb_entry->ddb_type == FLASH_DDB) { 287762306a36Sopenharmony_ci if (ddb_entry->chap_tbl_idx != INVALID_ENTRY) { 287862306a36Sopenharmony_ci idx = ddb_entry->chap_tbl_idx; 287962306a36Sopenharmony_ci rval = QLA_SUCCESS; 288062306a36Sopenharmony_ci } else { 288162306a36Sopenharmony_ci rval = QLA_ERROR; 288262306a36Sopenharmony_ci } 288362306a36Sopenharmony_ci } else { 288462306a36Sopenharmony_ci rval = qla4xxx_get_chap_index(ha, sess->username, 288562306a36Sopenharmony_ci sess->password, 288662306a36Sopenharmony_ci LOCAL_CHAP, &idx); 288762306a36Sopenharmony_ci } 288862306a36Sopenharmony_ci if (rval) 288962306a36Sopenharmony_ci len = sprintf(buf, "\n"); 289062306a36Sopenharmony_ci else 289162306a36Sopenharmony_ci len = sprintf(buf, "%hu\n", idx); 289262306a36Sopenharmony_ci break; 289362306a36Sopenharmony_ci case ISCSI_PARAM_USERNAME: 289462306a36Sopenharmony_ci case ISCSI_PARAM_PASSWORD: 289562306a36Sopenharmony_ci /* First, populate session username and password for FLASH DDB, 289662306a36Sopenharmony_ci * if not already done. This happens when session login fails 289762306a36Sopenharmony_ci * for a FLASH DDB. 289862306a36Sopenharmony_ci */ 289962306a36Sopenharmony_ci if (ddb_entry->ddb_type == FLASH_DDB && 290062306a36Sopenharmony_ci ddb_entry->chap_tbl_idx != INVALID_ENTRY && 290162306a36Sopenharmony_ci !sess->username && !sess->password) { 290262306a36Sopenharmony_ci idx = ddb_entry->chap_tbl_idx; 290362306a36Sopenharmony_ci rval = qla4xxx_get_uni_chap_at_index(ha, chap_tbl.name, 290462306a36Sopenharmony_ci chap_tbl.secret, 290562306a36Sopenharmony_ci idx); 290662306a36Sopenharmony_ci if (!rval) { 290762306a36Sopenharmony_ci iscsi_set_param(cls_conn, ISCSI_PARAM_USERNAME, 290862306a36Sopenharmony_ci (char *)chap_tbl.name, 290962306a36Sopenharmony_ci strlen((char *)chap_tbl.name)); 291062306a36Sopenharmony_ci iscsi_set_param(cls_conn, ISCSI_PARAM_PASSWORD, 291162306a36Sopenharmony_ci (char *)chap_tbl.secret, 291262306a36Sopenharmony_ci chap_tbl.secret_len); 291362306a36Sopenharmony_ci } 291462306a36Sopenharmony_ci } 291562306a36Sopenharmony_ci fallthrough; 291662306a36Sopenharmony_ci default: 291762306a36Sopenharmony_ci return iscsi_session_get_param(cls_sess, param, buf); 291862306a36Sopenharmony_ci } 291962306a36Sopenharmony_ci 292062306a36Sopenharmony_ci return len; 292162306a36Sopenharmony_ci} 292262306a36Sopenharmony_ci 292362306a36Sopenharmony_cistatic int qla4xxx_conn_get_param(struct iscsi_cls_conn *cls_conn, 292462306a36Sopenharmony_ci enum iscsi_param param, char *buf) 292562306a36Sopenharmony_ci{ 292662306a36Sopenharmony_ci struct iscsi_conn *conn; 292762306a36Sopenharmony_ci struct qla_conn *qla_conn; 292862306a36Sopenharmony_ci struct sockaddr *dst_addr; 292962306a36Sopenharmony_ci 293062306a36Sopenharmony_ci conn = cls_conn->dd_data; 293162306a36Sopenharmony_ci qla_conn = conn->dd_data; 293262306a36Sopenharmony_ci dst_addr = (struct sockaddr *)&qla_conn->qla_ep->dst_addr; 293362306a36Sopenharmony_ci 293462306a36Sopenharmony_ci switch (param) { 293562306a36Sopenharmony_ci case ISCSI_PARAM_CONN_PORT: 293662306a36Sopenharmony_ci case ISCSI_PARAM_CONN_ADDRESS: 293762306a36Sopenharmony_ci return iscsi_conn_get_addr_param((struct sockaddr_storage *) 293862306a36Sopenharmony_ci dst_addr, param, buf); 293962306a36Sopenharmony_ci default: 294062306a36Sopenharmony_ci return iscsi_conn_get_param(cls_conn, param, buf); 294162306a36Sopenharmony_ci } 294262306a36Sopenharmony_ci} 294362306a36Sopenharmony_ci 294462306a36Sopenharmony_ciint qla4xxx_get_ddb_index(struct scsi_qla_host *ha, uint16_t *ddb_index) 294562306a36Sopenharmony_ci{ 294662306a36Sopenharmony_ci uint32_t mbx_sts = 0; 294762306a36Sopenharmony_ci uint16_t tmp_ddb_index; 294862306a36Sopenharmony_ci int ret; 294962306a36Sopenharmony_ci 295062306a36Sopenharmony_ciget_ddb_index: 295162306a36Sopenharmony_ci tmp_ddb_index = find_first_zero_bit(ha->ddb_idx_map, MAX_DDB_ENTRIES); 295262306a36Sopenharmony_ci 295362306a36Sopenharmony_ci if (tmp_ddb_index >= MAX_DDB_ENTRIES) { 295462306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 295562306a36Sopenharmony_ci "Free DDB index not available\n")); 295662306a36Sopenharmony_ci ret = QLA_ERROR; 295762306a36Sopenharmony_ci goto exit_get_ddb_index; 295862306a36Sopenharmony_ci } 295962306a36Sopenharmony_ci 296062306a36Sopenharmony_ci if (test_and_set_bit(tmp_ddb_index, ha->ddb_idx_map)) 296162306a36Sopenharmony_ci goto get_ddb_index; 296262306a36Sopenharmony_ci 296362306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 296462306a36Sopenharmony_ci "Found a free DDB index at %d\n", tmp_ddb_index)); 296562306a36Sopenharmony_ci ret = qla4xxx_req_ddb_entry(ha, tmp_ddb_index, &mbx_sts); 296662306a36Sopenharmony_ci if (ret == QLA_ERROR) { 296762306a36Sopenharmony_ci if (mbx_sts == MBOX_STS_COMMAND_ERROR) { 296862306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, 296962306a36Sopenharmony_ci "DDB index = %d not available trying next\n", 297062306a36Sopenharmony_ci tmp_ddb_index); 297162306a36Sopenharmony_ci goto get_ddb_index; 297262306a36Sopenharmony_ci } 297362306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 297462306a36Sopenharmony_ci "Free FW DDB not available\n")); 297562306a36Sopenharmony_ci } 297662306a36Sopenharmony_ci 297762306a36Sopenharmony_ci *ddb_index = tmp_ddb_index; 297862306a36Sopenharmony_ci 297962306a36Sopenharmony_ciexit_get_ddb_index: 298062306a36Sopenharmony_ci return ret; 298162306a36Sopenharmony_ci} 298262306a36Sopenharmony_ci 298362306a36Sopenharmony_cistatic int qla4xxx_match_ipaddress(struct scsi_qla_host *ha, 298462306a36Sopenharmony_ci struct ddb_entry *ddb_entry, 298562306a36Sopenharmony_ci char *existing_ipaddr, 298662306a36Sopenharmony_ci char *user_ipaddr) 298762306a36Sopenharmony_ci{ 298862306a36Sopenharmony_ci uint8_t dst_ipaddr[IPv6_ADDR_LEN]; 298962306a36Sopenharmony_ci char formatted_ipaddr[DDB_IPADDR_LEN]; 299062306a36Sopenharmony_ci int status = QLA_SUCCESS, ret = 0; 299162306a36Sopenharmony_ci 299262306a36Sopenharmony_ci if (ddb_entry->fw_ddb_entry.options & DDB_OPT_IPV6_DEVICE) { 299362306a36Sopenharmony_ci ret = in6_pton(user_ipaddr, strlen(user_ipaddr), dst_ipaddr, 299462306a36Sopenharmony_ci '\0', NULL); 299562306a36Sopenharmony_ci if (ret == 0) { 299662306a36Sopenharmony_ci status = QLA_ERROR; 299762306a36Sopenharmony_ci goto out_match; 299862306a36Sopenharmony_ci } 299962306a36Sopenharmony_ci ret = sprintf(formatted_ipaddr, "%pI6", dst_ipaddr); 300062306a36Sopenharmony_ci } else { 300162306a36Sopenharmony_ci ret = in4_pton(user_ipaddr, strlen(user_ipaddr), dst_ipaddr, 300262306a36Sopenharmony_ci '\0', NULL); 300362306a36Sopenharmony_ci if (ret == 0) { 300462306a36Sopenharmony_ci status = QLA_ERROR; 300562306a36Sopenharmony_ci goto out_match; 300662306a36Sopenharmony_ci } 300762306a36Sopenharmony_ci ret = sprintf(formatted_ipaddr, "%pI4", dst_ipaddr); 300862306a36Sopenharmony_ci } 300962306a36Sopenharmony_ci 301062306a36Sopenharmony_ci if (strcmp(existing_ipaddr, formatted_ipaddr)) 301162306a36Sopenharmony_ci status = QLA_ERROR; 301262306a36Sopenharmony_ci 301362306a36Sopenharmony_ciout_match: 301462306a36Sopenharmony_ci return status; 301562306a36Sopenharmony_ci} 301662306a36Sopenharmony_ci 301762306a36Sopenharmony_cistatic int qla4xxx_match_fwdb_session(struct scsi_qla_host *ha, 301862306a36Sopenharmony_ci struct iscsi_cls_conn *cls_conn) 301962306a36Sopenharmony_ci{ 302062306a36Sopenharmony_ci int idx = 0, max_ddbs, rval; 302162306a36Sopenharmony_ci struct iscsi_cls_session *cls_sess = iscsi_conn_to_session(cls_conn); 302262306a36Sopenharmony_ci struct iscsi_session *sess, *existing_sess; 302362306a36Sopenharmony_ci struct iscsi_conn *conn, *existing_conn; 302462306a36Sopenharmony_ci struct ddb_entry *ddb_entry; 302562306a36Sopenharmony_ci 302662306a36Sopenharmony_ci sess = cls_sess->dd_data; 302762306a36Sopenharmony_ci conn = cls_conn->dd_data; 302862306a36Sopenharmony_ci 302962306a36Sopenharmony_ci if (sess->targetname == NULL || 303062306a36Sopenharmony_ci conn->persistent_address == NULL || 303162306a36Sopenharmony_ci conn->persistent_port == 0) 303262306a36Sopenharmony_ci return QLA_ERROR; 303362306a36Sopenharmony_ci 303462306a36Sopenharmony_ci max_ddbs = is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX : 303562306a36Sopenharmony_ci MAX_DEV_DB_ENTRIES; 303662306a36Sopenharmony_ci 303762306a36Sopenharmony_ci for (idx = 0; idx < max_ddbs; idx++) { 303862306a36Sopenharmony_ci ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx); 303962306a36Sopenharmony_ci if (ddb_entry == NULL) 304062306a36Sopenharmony_ci continue; 304162306a36Sopenharmony_ci 304262306a36Sopenharmony_ci if (ddb_entry->ddb_type != FLASH_DDB) 304362306a36Sopenharmony_ci continue; 304462306a36Sopenharmony_ci 304562306a36Sopenharmony_ci existing_sess = ddb_entry->sess->dd_data; 304662306a36Sopenharmony_ci existing_conn = ddb_entry->conn->dd_data; 304762306a36Sopenharmony_ci 304862306a36Sopenharmony_ci if (existing_sess->targetname == NULL || 304962306a36Sopenharmony_ci existing_conn->persistent_address == NULL || 305062306a36Sopenharmony_ci existing_conn->persistent_port == 0) 305162306a36Sopenharmony_ci continue; 305262306a36Sopenharmony_ci 305362306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 305462306a36Sopenharmony_ci "IQN = %s User IQN = %s\n", 305562306a36Sopenharmony_ci existing_sess->targetname, 305662306a36Sopenharmony_ci sess->targetname)); 305762306a36Sopenharmony_ci 305862306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 305962306a36Sopenharmony_ci "IP = %s User IP = %s\n", 306062306a36Sopenharmony_ci existing_conn->persistent_address, 306162306a36Sopenharmony_ci conn->persistent_address)); 306262306a36Sopenharmony_ci 306362306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 306462306a36Sopenharmony_ci "Port = %d User Port = %d\n", 306562306a36Sopenharmony_ci existing_conn->persistent_port, 306662306a36Sopenharmony_ci conn->persistent_port)); 306762306a36Sopenharmony_ci 306862306a36Sopenharmony_ci if (strcmp(existing_sess->targetname, sess->targetname)) 306962306a36Sopenharmony_ci continue; 307062306a36Sopenharmony_ci rval = qla4xxx_match_ipaddress(ha, ddb_entry, 307162306a36Sopenharmony_ci existing_conn->persistent_address, 307262306a36Sopenharmony_ci conn->persistent_address); 307362306a36Sopenharmony_ci if (rval == QLA_ERROR) 307462306a36Sopenharmony_ci continue; 307562306a36Sopenharmony_ci if (existing_conn->persistent_port != conn->persistent_port) 307662306a36Sopenharmony_ci continue; 307762306a36Sopenharmony_ci break; 307862306a36Sopenharmony_ci } 307962306a36Sopenharmony_ci 308062306a36Sopenharmony_ci if (idx == max_ddbs) 308162306a36Sopenharmony_ci return QLA_ERROR; 308262306a36Sopenharmony_ci 308362306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 308462306a36Sopenharmony_ci "Match found in fwdb sessions\n")); 308562306a36Sopenharmony_ci return QLA_SUCCESS; 308662306a36Sopenharmony_ci} 308762306a36Sopenharmony_ci 308862306a36Sopenharmony_cistatic struct iscsi_cls_session * 308962306a36Sopenharmony_ciqla4xxx_session_create(struct iscsi_endpoint *ep, 309062306a36Sopenharmony_ci uint16_t cmds_max, uint16_t qdepth, 309162306a36Sopenharmony_ci uint32_t initial_cmdsn) 309262306a36Sopenharmony_ci{ 309362306a36Sopenharmony_ci struct iscsi_cls_session *cls_sess; 309462306a36Sopenharmony_ci struct scsi_qla_host *ha; 309562306a36Sopenharmony_ci struct qla_endpoint *qla_ep; 309662306a36Sopenharmony_ci struct ddb_entry *ddb_entry; 309762306a36Sopenharmony_ci uint16_t ddb_index; 309862306a36Sopenharmony_ci struct iscsi_session *sess; 309962306a36Sopenharmony_ci int ret; 310062306a36Sopenharmony_ci 310162306a36Sopenharmony_ci if (!ep) { 310262306a36Sopenharmony_ci printk(KERN_ERR "qla4xxx: missing ep.\n"); 310362306a36Sopenharmony_ci return NULL; 310462306a36Sopenharmony_ci } 310562306a36Sopenharmony_ci 310662306a36Sopenharmony_ci qla_ep = ep->dd_data; 310762306a36Sopenharmony_ci ha = to_qla_host(qla_ep->host); 310862306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "%s: host: %ld\n", __func__, 310962306a36Sopenharmony_ci ha->host_no)); 311062306a36Sopenharmony_ci 311162306a36Sopenharmony_ci ret = qla4xxx_get_ddb_index(ha, &ddb_index); 311262306a36Sopenharmony_ci if (ret == QLA_ERROR) 311362306a36Sopenharmony_ci return NULL; 311462306a36Sopenharmony_ci 311562306a36Sopenharmony_ci cls_sess = iscsi_session_setup(&qla4xxx_iscsi_transport, qla_ep->host, 311662306a36Sopenharmony_ci cmds_max, sizeof(struct ddb_entry), 311762306a36Sopenharmony_ci sizeof(struct ql4_task_data), 311862306a36Sopenharmony_ci initial_cmdsn, ddb_index); 311962306a36Sopenharmony_ci if (!cls_sess) 312062306a36Sopenharmony_ci return NULL; 312162306a36Sopenharmony_ci 312262306a36Sopenharmony_ci sess = cls_sess->dd_data; 312362306a36Sopenharmony_ci ddb_entry = sess->dd_data; 312462306a36Sopenharmony_ci ddb_entry->fw_ddb_index = ddb_index; 312562306a36Sopenharmony_ci ddb_entry->fw_ddb_device_state = DDB_DS_NO_CONNECTION_ACTIVE; 312662306a36Sopenharmony_ci ddb_entry->ha = ha; 312762306a36Sopenharmony_ci ddb_entry->sess = cls_sess; 312862306a36Sopenharmony_ci ddb_entry->unblock_sess = qla4xxx_unblock_ddb; 312962306a36Sopenharmony_ci ddb_entry->ddb_change = qla4xxx_ddb_change; 313062306a36Sopenharmony_ci clear_bit(DDB_CONN_CLOSE_FAILURE, &ddb_entry->flags); 313162306a36Sopenharmony_ci cls_sess->recovery_tmo = ql4xsess_recovery_tmo; 313262306a36Sopenharmony_ci ha->fw_ddb_index_map[ddb_entry->fw_ddb_index] = ddb_entry; 313362306a36Sopenharmony_ci ha->tot_ddbs++; 313462306a36Sopenharmony_ci 313562306a36Sopenharmony_ci return cls_sess; 313662306a36Sopenharmony_ci} 313762306a36Sopenharmony_ci 313862306a36Sopenharmony_cistatic void qla4xxx_session_destroy(struct iscsi_cls_session *cls_sess) 313962306a36Sopenharmony_ci{ 314062306a36Sopenharmony_ci struct iscsi_session *sess; 314162306a36Sopenharmony_ci struct ddb_entry *ddb_entry; 314262306a36Sopenharmony_ci struct scsi_qla_host *ha; 314362306a36Sopenharmony_ci unsigned long flags, wtime; 314462306a36Sopenharmony_ci struct dev_db_entry *fw_ddb_entry = NULL; 314562306a36Sopenharmony_ci dma_addr_t fw_ddb_entry_dma; 314662306a36Sopenharmony_ci uint32_t ddb_state; 314762306a36Sopenharmony_ci int ret; 314862306a36Sopenharmony_ci 314962306a36Sopenharmony_ci sess = cls_sess->dd_data; 315062306a36Sopenharmony_ci ddb_entry = sess->dd_data; 315162306a36Sopenharmony_ci ha = ddb_entry->ha; 315262306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "%s: host: %ld\n", __func__, 315362306a36Sopenharmony_ci ha->host_no)); 315462306a36Sopenharmony_ci 315562306a36Sopenharmony_ci fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), 315662306a36Sopenharmony_ci &fw_ddb_entry_dma, GFP_KERNEL); 315762306a36Sopenharmony_ci if (!fw_ddb_entry) { 315862306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, 315962306a36Sopenharmony_ci "%s: Unable to allocate dma buffer\n", __func__); 316062306a36Sopenharmony_ci goto destroy_session; 316162306a36Sopenharmony_ci } 316262306a36Sopenharmony_ci 316362306a36Sopenharmony_ci wtime = jiffies + (HZ * LOGOUT_TOV); 316462306a36Sopenharmony_ci do { 316562306a36Sopenharmony_ci ret = qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index, 316662306a36Sopenharmony_ci fw_ddb_entry, fw_ddb_entry_dma, 316762306a36Sopenharmony_ci NULL, NULL, &ddb_state, NULL, 316862306a36Sopenharmony_ci NULL, NULL); 316962306a36Sopenharmony_ci if (ret == QLA_ERROR) 317062306a36Sopenharmony_ci goto destroy_session; 317162306a36Sopenharmony_ci 317262306a36Sopenharmony_ci if ((ddb_state == DDB_DS_NO_CONNECTION_ACTIVE) || 317362306a36Sopenharmony_ci (ddb_state == DDB_DS_SESSION_FAILED)) 317462306a36Sopenharmony_ci goto destroy_session; 317562306a36Sopenharmony_ci 317662306a36Sopenharmony_ci schedule_timeout_uninterruptible(HZ); 317762306a36Sopenharmony_ci } while ((time_after(wtime, jiffies))); 317862306a36Sopenharmony_ci 317962306a36Sopenharmony_cidestroy_session: 318062306a36Sopenharmony_ci qla4xxx_clear_ddb_entry(ha, ddb_entry->fw_ddb_index); 318162306a36Sopenharmony_ci if (test_and_clear_bit(DDB_CONN_CLOSE_FAILURE, &ddb_entry->flags)) 318262306a36Sopenharmony_ci clear_bit(ddb_entry->fw_ddb_index, ha->ddb_idx_map); 318362306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 318462306a36Sopenharmony_ci qla4xxx_free_ddb(ha, ddb_entry); 318562306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 318662306a36Sopenharmony_ci 318762306a36Sopenharmony_ci iscsi_session_teardown(cls_sess); 318862306a36Sopenharmony_ci 318962306a36Sopenharmony_ci if (fw_ddb_entry) 319062306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), 319162306a36Sopenharmony_ci fw_ddb_entry, fw_ddb_entry_dma); 319262306a36Sopenharmony_ci} 319362306a36Sopenharmony_ci 319462306a36Sopenharmony_cistatic struct iscsi_cls_conn * 319562306a36Sopenharmony_ciqla4xxx_conn_create(struct iscsi_cls_session *cls_sess, uint32_t conn_idx) 319662306a36Sopenharmony_ci{ 319762306a36Sopenharmony_ci struct iscsi_cls_conn *cls_conn; 319862306a36Sopenharmony_ci struct iscsi_session *sess; 319962306a36Sopenharmony_ci struct ddb_entry *ddb_entry; 320062306a36Sopenharmony_ci struct scsi_qla_host *ha; 320162306a36Sopenharmony_ci 320262306a36Sopenharmony_ci cls_conn = iscsi_conn_setup(cls_sess, sizeof(struct qla_conn), 320362306a36Sopenharmony_ci conn_idx); 320462306a36Sopenharmony_ci if (!cls_conn) { 320562306a36Sopenharmony_ci pr_info("%s: Can not create connection for conn_idx = %u\n", 320662306a36Sopenharmony_ci __func__, conn_idx); 320762306a36Sopenharmony_ci return NULL; 320862306a36Sopenharmony_ci } 320962306a36Sopenharmony_ci 321062306a36Sopenharmony_ci sess = cls_sess->dd_data; 321162306a36Sopenharmony_ci ddb_entry = sess->dd_data; 321262306a36Sopenharmony_ci ddb_entry->conn = cls_conn; 321362306a36Sopenharmony_ci 321462306a36Sopenharmony_ci ha = ddb_entry->ha; 321562306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "%s: conn_idx = %u\n", __func__, 321662306a36Sopenharmony_ci conn_idx)); 321762306a36Sopenharmony_ci return cls_conn; 321862306a36Sopenharmony_ci} 321962306a36Sopenharmony_ci 322062306a36Sopenharmony_cistatic int qla4xxx_conn_bind(struct iscsi_cls_session *cls_session, 322162306a36Sopenharmony_ci struct iscsi_cls_conn *cls_conn, 322262306a36Sopenharmony_ci uint64_t transport_fd, int is_leading) 322362306a36Sopenharmony_ci{ 322462306a36Sopenharmony_ci struct iscsi_conn *conn; 322562306a36Sopenharmony_ci struct qla_conn *qla_conn; 322662306a36Sopenharmony_ci struct iscsi_endpoint *ep; 322762306a36Sopenharmony_ci struct ddb_entry *ddb_entry; 322862306a36Sopenharmony_ci struct scsi_qla_host *ha; 322962306a36Sopenharmony_ci struct iscsi_session *sess; 323062306a36Sopenharmony_ci 323162306a36Sopenharmony_ci sess = cls_session->dd_data; 323262306a36Sopenharmony_ci ddb_entry = sess->dd_data; 323362306a36Sopenharmony_ci ha = ddb_entry->ha; 323462306a36Sopenharmony_ci 323562306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "%s: sid = %d, cid = %d\n", __func__, 323662306a36Sopenharmony_ci cls_session->sid, cls_conn->cid)); 323762306a36Sopenharmony_ci 323862306a36Sopenharmony_ci if (iscsi_conn_bind(cls_session, cls_conn, is_leading)) 323962306a36Sopenharmony_ci return -EINVAL; 324062306a36Sopenharmony_ci ep = iscsi_lookup_endpoint(transport_fd); 324162306a36Sopenharmony_ci if (!ep) 324262306a36Sopenharmony_ci return -EINVAL; 324362306a36Sopenharmony_ci conn = cls_conn->dd_data; 324462306a36Sopenharmony_ci qla_conn = conn->dd_data; 324562306a36Sopenharmony_ci qla_conn->qla_ep = ep->dd_data; 324662306a36Sopenharmony_ci iscsi_put_endpoint(ep); 324762306a36Sopenharmony_ci return 0; 324862306a36Sopenharmony_ci} 324962306a36Sopenharmony_ci 325062306a36Sopenharmony_cistatic int qla4xxx_conn_start(struct iscsi_cls_conn *cls_conn) 325162306a36Sopenharmony_ci{ 325262306a36Sopenharmony_ci struct iscsi_cls_session *cls_sess = iscsi_conn_to_session(cls_conn); 325362306a36Sopenharmony_ci struct iscsi_session *sess; 325462306a36Sopenharmony_ci struct ddb_entry *ddb_entry; 325562306a36Sopenharmony_ci struct scsi_qla_host *ha; 325662306a36Sopenharmony_ci struct dev_db_entry *fw_ddb_entry = NULL; 325762306a36Sopenharmony_ci dma_addr_t fw_ddb_entry_dma; 325862306a36Sopenharmony_ci uint32_t mbx_sts = 0; 325962306a36Sopenharmony_ci int ret = 0; 326062306a36Sopenharmony_ci int status = QLA_SUCCESS; 326162306a36Sopenharmony_ci 326262306a36Sopenharmony_ci sess = cls_sess->dd_data; 326362306a36Sopenharmony_ci ddb_entry = sess->dd_data; 326462306a36Sopenharmony_ci ha = ddb_entry->ha; 326562306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "%s: sid = %d, cid = %d\n", __func__, 326662306a36Sopenharmony_ci cls_sess->sid, cls_conn->cid)); 326762306a36Sopenharmony_ci 326862306a36Sopenharmony_ci /* Check if we have matching FW DDB, if yes then do not 326962306a36Sopenharmony_ci * login to this target. This could cause target to logout previous 327062306a36Sopenharmony_ci * connection 327162306a36Sopenharmony_ci */ 327262306a36Sopenharmony_ci ret = qla4xxx_match_fwdb_session(ha, cls_conn); 327362306a36Sopenharmony_ci if (ret == QLA_SUCCESS) { 327462306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, 327562306a36Sopenharmony_ci "Session already exist in FW.\n"); 327662306a36Sopenharmony_ci ret = -EEXIST; 327762306a36Sopenharmony_ci goto exit_conn_start; 327862306a36Sopenharmony_ci } 327962306a36Sopenharmony_ci 328062306a36Sopenharmony_ci fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), 328162306a36Sopenharmony_ci &fw_ddb_entry_dma, GFP_KERNEL); 328262306a36Sopenharmony_ci if (!fw_ddb_entry) { 328362306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, 328462306a36Sopenharmony_ci "%s: Unable to allocate dma buffer\n", __func__); 328562306a36Sopenharmony_ci ret = -ENOMEM; 328662306a36Sopenharmony_ci goto exit_conn_start; 328762306a36Sopenharmony_ci } 328862306a36Sopenharmony_ci 328962306a36Sopenharmony_ci ret = qla4xxx_set_param_ddbentry(ha, ddb_entry, cls_conn, &mbx_sts); 329062306a36Sopenharmony_ci if (ret) { 329162306a36Sopenharmony_ci /* If iscsid is stopped and started then no need to do 329262306a36Sopenharmony_ci * set param again since ddb state will be already 329362306a36Sopenharmony_ci * active and FW does not allow set ddb to an 329462306a36Sopenharmony_ci * active session. 329562306a36Sopenharmony_ci */ 329662306a36Sopenharmony_ci if (mbx_sts) 329762306a36Sopenharmony_ci if (ddb_entry->fw_ddb_device_state == 329862306a36Sopenharmony_ci DDB_DS_SESSION_ACTIVE) { 329962306a36Sopenharmony_ci ddb_entry->unblock_sess(ddb_entry->sess); 330062306a36Sopenharmony_ci goto exit_set_param; 330162306a36Sopenharmony_ci } 330262306a36Sopenharmony_ci 330362306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: Failed set param for index[%d]\n", 330462306a36Sopenharmony_ci __func__, ddb_entry->fw_ddb_index); 330562306a36Sopenharmony_ci goto exit_conn_start; 330662306a36Sopenharmony_ci } 330762306a36Sopenharmony_ci 330862306a36Sopenharmony_ci status = qla4xxx_conn_open(ha, ddb_entry->fw_ddb_index); 330962306a36Sopenharmony_ci if (status == QLA_ERROR) { 331062306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: Login failed: %s\n", __func__, 331162306a36Sopenharmony_ci sess->targetname); 331262306a36Sopenharmony_ci ret = -EINVAL; 331362306a36Sopenharmony_ci goto exit_conn_start; 331462306a36Sopenharmony_ci } 331562306a36Sopenharmony_ci 331662306a36Sopenharmony_ci if (ddb_entry->fw_ddb_device_state == DDB_DS_NO_CONNECTION_ACTIVE) 331762306a36Sopenharmony_ci ddb_entry->fw_ddb_device_state = DDB_DS_LOGIN_IN_PROCESS; 331862306a36Sopenharmony_ci 331962306a36Sopenharmony_ci DEBUG2(printk(KERN_INFO "%s: DDB state [%d]\n", __func__, 332062306a36Sopenharmony_ci ddb_entry->fw_ddb_device_state)); 332162306a36Sopenharmony_ci 332262306a36Sopenharmony_ciexit_set_param: 332362306a36Sopenharmony_ci ret = 0; 332462306a36Sopenharmony_ci 332562306a36Sopenharmony_ciexit_conn_start: 332662306a36Sopenharmony_ci if (fw_ddb_entry) 332762306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), 332862306a36Sopenharmony_ci fw_ddb_entry, fw_ddb_entry_dma); 332962306a36Sopenharmony_ci return ret; 333062306a36Sopenharmony_ci} 333162306a36Sopenharmony_ci 333262306a36Sopenharmony_cistatic void qla4xxx_conn_destroy(struct iscsi_cls_conn *cls_conn) 333362306a36Sopenharmony_ci{ 333462306a36Sopenharmony_ci struct iscsi_cls_session *cls_sess = iscsi_conn_to_session(cls_conn); 333562306a36Sopenharmony_ci struct iscsi_session *sess; 333662306a36Sopenharmony_ci struct scsi_qla_host *ha; 333762306a36Sopenharmony_ci struct ddb_entry *ddb_entry; 333862306a36Sopenharmony_ci int options; 333962306a36Sopenharmony_ci 334062306a36Sopenharmony_ci sess = cls_sess->dd_data; 334162306a36Sopenharmony_ci ddb_entry = sess->dd_data; 334262306a36Sopenharmony_ci ha = ddb_entry->ha; 334362306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "%s: cid = %d\n", __func__, 334462306a36Sopenharmony_ci cls_conn->cid)); 334562306a36Sopenharmony_ci 334662306a36Sopenharmony_ci options = LOGOUT_OPTION_CLOSE_SESSION; 334762306a36Sopenharmony_ci if (qla4xxx_session_logout_ddb(ha, ddb_entry, options) == QLA_ERROR) 334862306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: Logout failed\n", __func__); 334962306a36Sopenharmony_ci} 335062306a36Sopenharmony_ci 335162306a36Sopenharmony_cistatic void qla4xxx_task_work(struct work_struct *wdata) 335262306a36Sopenharmony_ci{ 335362306a36Sopenharmony_ci struct ql4_task_data *task_data; 335462306a36Sopenharmony_ci struct scsi_qla_host *ha; 335562306a36Sopenharmony_ci struct passthru_status *sts; 335662306a36Sopenharmony_ci struct iscsi_task *task; 335762306a36Sopenharmony_ci struct iscsi_hdr *hdr; 335862306a36Sopenharmony_ci uint8_t *data; 335962306a36Sopenharmony_ci uint32_t data_len; 336062306a36Sopenharmony_ci struct iscsi_conn *conn; 336162306a36Sopenharmony_ci int hdr_len; 336262306a36Sopenharmony_ci itt_t itt; 336362306a36Sopenharmony_ci 336462306a36Sopenharmony_ci task_data = container_of(wdata, struct ql4_task_data, task_work); 336562306a36Sopenharmony_ci ha = task_data->ha; 336662306a36Sopenharmony_ci task = task_data->task; 336762306a36Sopenharmony_ci sts = &task_data->sts; 336862306a36Sopenharmony_ci hdr_len = sizeof(struct iscsi_hdr); 336962306a36Sopenharmony_ci 337062306a36Sopenharmony_ci DEBUG3(printk(KERN_INFO "Status returned\n")); 337162306a36Sopenharmony_ci DEBUG3(qla4xxx_dump_buffer(sts, 64)); 337262306a36Sopenharmony_ci DEBUG3(printk(KERN_INFO "Response buffer")); 337362306a36Sopenharmony_ci DEBUG3(qla4xxx_dump_buffer(task_data->resp_buffer, 64)); 337462306a36Sopenharmony_ci 337562306a36Sopenharmony_ci conn = task->conn; 337662306a36Sopenharmony_ci 337762306a36Sopenharmony_ci switch (sts->completionStatus) { 337862306a36Sopenharmony_ci case PASSTHRU_STATUS_COMPLETE: 337962306a36Sopenharmony_ci hdr = (struct iscsi_hdr *)task_data->resp_buffer; 338062306a36Sopenharmony_ci /* Assign back the itt in hdr, until we use the PREASSIGN_TAG */ 338162306a36Sopenharmony_ci itt = sts->handle; 338262306a36Sopenharmony_ci hdr->itt = itt; 338362306a36Sopenharmony_ci data = task_data->resp_buffer + hdr_len; 338462306a36Sopenharmony_ci data_len = task_data->resp_len - hdr_len; 338562306a36Sopenharmony_ci iscsi_complete_pdu(conn, hdr, data, data_len); 338662306a36Sopenharmony_ci break; 338762306a36Sopenharmony_ci default: 338862306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "Passthru failed status = 0x%x\n", 338962306a36Sopenharmony_ci sts->completionStatus); 339062306a36Sopenharmony_ci break; 339162306a36Sopenharmony_ci } 339262306a36Sopenharmony_ci return; 339362306a36Sopenharmony_ci} 339462306a36Sopenharmony_ci 339562306a36Sopenharmony_cistatic int qla4xxx_alloc_pdu(struct iscsi_task *task, uint8_t opcode) 339662306a36Sopenharmony_ci{ 339762306a36Sopenharmony_ci struct ql4_task_data *task_data; 339862306a36Sopenharmony_ci struct iscsi_session *sess; 339962306a36Sopenharmony_ci struct ddb_entry *ddb_entry; 340062306a36Sopenharmony_ci struct scsi_qla_host *ha; 340162306a36Sopenharmony_ci int hdr_len; 340262306a36Sopenharmony_ci 340362306a36Sopenharmony_ci sess = task->conn->session; 340462306a36Sopenharmony_ci ddb_entry = sess->dd_data; 340562306a36Sopenharmony_ci ha = ddb_entry->ha; 340662306a36Sopenharmony_ci task_data = task->dd_data; 340762306a36Sopenharmony_ci memset(task_data, 0, sizeof(struct ql4_task_data)); 340862306a36Sopenharmony_ci 340962306a36Sopenharmony_ci if (task->sc) { 341062306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, 341162306a36Sopenharmony_ci "%s: SCSI Commands not implemented\n", __func__); 341262306a36Sopenharmony_ci return -EINVAL; 341362306a36Sopenharmony_ci } 341462306a36Sopenharmony_ci 341562306a36Sopenharmony_ci hdr_len = sizeof(struct iscsi_hdr); 341662306a36Sopenharmony_ci task_data->ha = ha; 341762306a36Sopenharmony_ci task_data->task = task; 341862306a36Sopenharmony_ci 341962306a36Sopenharmony_ci if (task->data_count) { 342062306a36Sopenharmony_ci task_data->data_dma = dma_map_single(&ha->pdev->dev, task->data, 342162306a36Sopenharmony_ci task->data_count, 342262306a36Sopenharmony_ci DMA_TO_DEVICE); 342362306a36Sopenharmony_ci } 342462306a36Sopenharmony_ci 342562306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "%s: MaxRecvLen %u, iscsi hrd %d\n", 342662306a36Sopenharmony_ci __func__, task->conn->max_recv_dlength, hdr_len)); 342762306a36Sopenharmony_ci 342862306a36Sopenharmony_ci task_data->resp_len = task->conn->max_recv_dlength + hdr_len; 342962306a36Sopenharmony_ci task_data->resp_buffer = dma_alloc_coherent(&ha->pdev->dev, 343062306a36Sopenharmony_ci task_data->resp_len, 343162306a36Sopenharmony_ci &task_data->resp_dma, 343262306a36Sopenharmony_ci GFP_ATOMIC); 343362306a36Sopenharmony_ci if (!task_data->resp_buffer) 343462306a36Sopenharmony_ci goto exit_alloc_pdu; 343562306a36Sopenharmony_ci 343662306a36Sopenharmony_ci task_data->req_len = task->data_count + hdr_len; 343762306a36Sopenharmony_ci task_data->req_buffer = dma_alloc_coherent(&ha->pdev->dev, 343862306a36Sopenharmony_ci task_data->req_len, 343962306a36Sopenharmony_ci &task_data->req_dma, 344062306a36Sopenharmony_ci GFP_ATOMIC); 344162306a36Sopenharmony_ci if (!task_data->req_buffer) 344262306a36Sopenharmony_ci goto exit_alloc_pdu; 344362306a36Sopenharmony_ci 344462306a36Sopenharmony_ci task->hdr = task_data->req_buffer; 344562306a36Sopenharmony_ci 344662306a36Sopenharmony_ci INIT_WORK(&task_data->task_work, qla4xxx_task_work); 344762306a36Sopenharmony_ci 344862306a36Sopenharmony_ci return 0; 344962306a36Sopenharmony_ci 345062306a36Sopenharmony_ciexit_alloc_pdu: 345162306a36Sopenharmony_ci if (task_data->resp_buffer) 345262306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, task_data->resp_len, 345362306a36Sopenharmony_ci task_data->resp_buffer, task_data->resp_dma); 345462306a36Sopenharmony_ci 345562306a36Sopenharmony_ci if (task_data->req_buffer) 345662306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, task_data->req_len, 345762306a36Sopenharmony_ci task_data->req_buffer, task_data->req_dma); 345862306a36Sopenharmony_ci return -ENOMEM; 345962306a36Sopenharmony_ci} 346062306a36Sopenharmony_ci 346162306a36Sopenharmony_cistatic void qla4xxx_task_cleanup(struct iscsi_task *task) 346262306a36Sopenharmony_ci{ 346362306a36Sopenharmony_ci struct ql4_task_data *task_data; 346462306a36Sopenharmony_ci struct iscsi_session *sess; 346562306a36Sopenharmony_ci struct ddb_entry *ddb_entry; 346662306a36Sopenharmony_ci struct scsi_qla_host *ha; 346762306a36Sopenharmony_ci int hdr_len; 346862306a36Sopenharmony_ci 346962306a36Sopenharmony_ci hdr_len = sizeof(struct iscsi_hdr); 347062306a36Sopenharmony_ci sess = task->conn->session; 347162306a36Sopenharmony_ci ddb_entry = sess->dd_data; 347262306a36Sopenharmony_ci ha = ddb_entry->ha; 347362306a36Sopenharmony_ci task_data = task->dd_data; 347462306a36Sopenharmony_ci 347562306a36Sopenharmony_ci if (task->data_count) { 347662306a36Sopenharmony_ci dma_unmap_single(&ha->pdev->dev, task_data->data_dma, 347762306a36Sopenharmony_ci task->data_count, DMA_TO_DEVICE); 347862306a36Sopenharmony_ci } 347962306a36Sopenharmony_ci 348062306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "%s: MaxRecvLen %u, iscsi hrd %d\n", 348162306a36Sopenharmony_ci __func__, task->conn->max_recv_dlength, hdr_len)); 348262306a36Sopenharmony_ci 348362306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, task_data->resp_len, 348462306a36Sopenharmony_ci task_data->resp_buffer, task_data->resp_dma); 348562306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, task_data->req_len, 348662306a36Sopenharmony_ci task_data->req_buffer, task_data->req_dma); 348762306a36Sopenharmony_ci return; 348862306a36Sopenharmony_ci} 348962306a36Sopenharmony_ci 349062306a36Sopenharmony_cistatic int qla4xxx_task_xmit(struct iscsi_task *task) 349162306a36Sopenharmony_ci{ 349262306a36Sopenharmony_ci struct scsi_cmnd *sc = task->sc; 349362306a36Sopenharmony_ci struct iscsi_session *sess = task->conn->session; 349462306a36Sopenharmony_ci struct ddb_entry *ddb_entry = sess->dd_data; 349562306a36Sopenharmony_ci struct scsi_qla_host *ha = ddb_entry->ha; 349662306a36Sopenharmony_ci 349762306a36Sopenharmony_ci if (!sc) 349862306a36Sopenharmony_ci return qla4xxx_send_passthru0(task); 349962306a36Sopenharmony_ci 350062306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "%s: scsi cmd xmit not implemented\n", 350162306a36Sopenharmony_ci __func__); 350262306a36Sopenharmony_ci return -ENOSYS; 350362306a36Sopenharmony_ci} 350462306a36Sopenharmony_ci 350562306a36Sopenharmony_cistatic int qla4xxx_copy_from_fwddb_param(struct iscsi_bus_flash_session *sess, 350662306a36Sopenharmony_ci struct iscsi_bus_flash_conn *conn, 350762306a36Sopenharmony_ci struct dev_db_entry *fw_ddb_entry) 350862306a36Sopenharmony_ci{ 350962306a36Sopenharmony_ci unsigned long options = 0; 351062306a36Sopenharmony_ci int rc = 0; 351162306a36Sopenharmony_ci 351262306a36Sopenharmony_ci options = le16_to_cpu(fw_ddb_entry->options); 351362306a36Sopenharmony_ci conn->is_fw_assigned_ipv6 = test_bit(OPT_IS_FW_ASSIGNED_IPV6, &options); 351462306a36Sopenharmony_ci if (test_bit(OPT_IPV6_DEVICE, &options)) { 351562306a36Sopenharmony_ci rc = iscsi_switch_str_param(&sess->portal_type, 351662306a36Sopenharmony_ci PORTAL_TYPE_IPV6); 351762306a36Sopenharmony_ci if (rc) 351862306a36Sopenharmony_ci goto exit_copy; 351962306a36Sopenharmony_ci } else { 352062306a36Sopenharmony_ci rc = iscsi_switch_str_param(&sess->portal_type, 352162306a36Sopenharmony_ci PORTAL_TYPE_IPV4); 352262306a36Sopenharmony_ci if (rc) 352362306a36Sopenharmony_ci goto exit_copy; 352462306a36Sopenharmony_ci } 352562306a36Sopenharmony_ci 352662306a36Sopenharmony_ci sess->auto_snd_tgt_disable = test_bit(OPT_AUTO_SENDTGTS_DISABLE, 352762306a36Sopenharmony_ci &options); 352862306a36Sopenharmony_ci sess->discovery_sess = test_bit(OPT_DISC_SESSION, &options); 352962306a36Sopenharmony_ci sess->entry_state = test_bit(OPT_ENTRY_STATE, &options); 353062306a36Sopenharmony_ci 353162306a36Sopenharmony_ci options = le16_to_cpu(fw_ddb_entry->iscsi_options); 353262306a36Sopenharmony_ci conn->hdrdgst_en = test_bit(ISCSIOPT_HEADER_DIGEST_EN, &options); 353362306a36Sopenharmony_ci conn->datadgst_en = test_bit(ISCSIOPT_DATA_DIGEST_EN, &options); 353462306a36Sopenharmony_ci sess->imm_data_en = test_bit(ISCSIOPT_IMMEDIATE_DATA_EN, &options); 353562306a36Sopenharmony_ci sess->initial_r2t_en = test_bit(ISCSIOPT_INITIAL_R2T_EN, &options); 353662306a36Sopenharmony_ci sess->dataseq_inorder_en = test_bit(ISCSIOPT_DATA_SEQ_IN_ORDER, 353762306a36Sopenharmony_ci &options); 353862306a36Sopenharmony_ci sess->pdu_inorder_en = test_bit(ISCSIOPT_DATA_PDU_IN_ORDER, &options); 353962306a36Sopenharmony_ci sess->chap_auth_en = test_bit(ISCSIOPT_CHAP_AUTH_EN, &options); 354062306a36Sopenharmony_ci conn->snack_req_en = test_bit(ISCSIOPT_SNACK_REQ_EN, &options); 354162306a36Sopenharmony_ci sess->discovery_logout_en = test_bit(ISCSIOPT_DISCOVERY_LOGOUT_EN, 354262306a36Sopenharmony_ci &options); 354362306a36Sopenharmony_ci sess->bidi_chap_en = test_bit(ISCSIOPT_BIDI_CHAP_EN, &options); 354462306a36Sopenharmony_ci sess->discovery_auth_optional = 354562306a36Sopenharmony_ci test_bit(ISCSIOPT_DISCOVERY_AUTH_OPTIONAL, &options); 354662306a36Sopenharmony_ci if (test_bit(ISCSIOPT_ERL1, &options)) 354762306a36Sopenharmony_ci sess->erl |= BIT_1; 354862306a36Sopenharmony_ci if (test_bit(ISCSIOPT_ERL0, &options)) 354962306a36Sopenharmony_ci sess->erl |= BIT_0; 355062306a36Sopenharmony_ci 355162306a36Sopenharmony_ci options = le16_to_cpu(fw_ddb_entry->tcp_options); 355262306a36Sopenharmony_ci conn->tcp_timestamp_stat = test_bit(TCPOPT_TIMESTAMP_STAT, &options); 355362306a36Sopenharmony_ci conn->tcp_nagle_disable = test_bit(TCPOPT_NAGLE_DISABLE, &options); 355462306a36Sopenharmony_ci conn->tcp_wsf_disable = test_bit(TCPOPT_WSF_DISABLE, &options); 355562306a36Sopenharmony_ci if (test_bit(TCPOPT_TIMER_SCALE3, &options)) 355662306a36Sopenharmony_ci conn->tcp_timer_scale |= BIT_3; 355762306a36Sopenharmony_ci if (test_bit(TCPOPT_TIMER_SCALE2, &options)) 355862306a36Sopenharmony_ci conn->tcp_timer_scale |= BIT_2; 355962306a36Sopenharmony_ci if (test_bit(TCPOPT_TIMER_SCALE1, &options)) 356062306a36Sopenharmony_ci conn->tcp_timer_scale |= BIT_1; 356162306a36Sopenharmony_ci 356262306a36Sopenharmony_ci conn->tcp_timer_scale >>= 1; 356362306a36Sopenharmony_ci conn->tcp_timestamp_en = test_bit(TCPOPT_TIMESTAMP_EN, &options); 356462306a36Sopenharmony_ci 356562306a36Sopenharmony_ci options = le16_to_cpu(fw_ddb_entry->ip_options); 356662306a36Sopenharmony_ci conn->fragment_disable = test_bit(IPOPT_FRAGMENT_DISABLE, &options); 356762306a36Sopenharmony_ci 356862306a36Sopenharmony_ci conn->max_recv_dlength = BYTE_UNITS * 356962306a36Sopenharmony_ci le16_to_cpu(fw_ddb_entry->iscsi_max_rcv_data_seg_len); 357062306a36Sopenharmony_ci conn->max_xmit_dlength = BYTE_UNITS * 357162306a36Sopenharmony_ci le16_to_cpu(fw_ddb_entry->iscsi_max_snd_data_seg_len); 357262306a36Sopenharmony_ci sess->first_burst = BYTE_UNITS * 357362306a36Sopenharmony_ci le16_to_cpu(fw_ddb_entry->iscsi_first_burst_len); 357462306a36Sopenharmony_ci sess->max_burst = BYTE_UNITS * 357562306a36Sopenharmony_ci le16_to_cpu(fw_ddb_entry->iscsi_max_burst_len); 357662306a36Sopenharmony_ci sess->max_r2t = le16_to_cpu(fw_ddb_entry->iscsi_max_outsnd_r2t); 357762306a36Sopenharmony_ci sess->time2wait = le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait); 357862306a36Sopenharmony_ci sess->time2retain = le16_to_cpu(fw_ddb_entry->iscsi_def_time2retain); 357962306a36Sopenharmony_ci sess->tpgt = le32_to_cpu(fw_ddb_entry->tgt_portal_grp); 358062306a36Sopenharmony_ci conn->max_segment_size = le16_to_cpu(fw_ddb_entry->mss); 358162306a36Sopenharmony_ci conn->tcp_xmit_wsf = fw_ddb_entry->tcp_xmt_wsf; 358262306a36Sopenharmony_ci conn->tcp_recv_wsf = fw_ddb_entry->tcp_rcv_wsf; 358362306a36Sopenharmony_ci conn->ipv6_flow_label = le16_to_cpu(fw_ddb_entry->ipv6_flow_lbl); 358462306a36Sopenharmony_ci conn->keepalive_timeout = le16_to_cpu(fw_ddb_entry->ka_timeout); 358562306a36Sopenharmony_ci conn->local_port = le16_to_cpu(fw_ddb_entry->lcl_port); 358662306a36Sopenharmony_ci conn->statsn = le32_to_cpu(fw_ddb_entry->stat_sn); 358762306a36Sopenharmony_ci conn->exp_statsn = le32_to_cpu(fw_ddb_entry->exp_stat_sn); 358862306a36Sopenharmony_ci sess->discovery_parent_idx = le16_to_cpu(fw_ddb_entry->ddb_link); 358962306a36Sopenharmony_ci sess->discovery_parent_type = le16_to_cpu(fw_ddb_entry->ddb_link); 359062306a36Sopenharmony_ci sess->chap_out_idx = le16_to_cpu(fw_ddb_entry->chap_tbl_idx); 359162306a36Sopenharmony_ci sess->tsid = le16_to_cpu(fw_ddb_entry->tsid); 359262306a36Sopenharmony_ci 359362306a36Sopenharmony_ci sess->default_taskmgmt_timeout = 359462306a36Sopenharmony_ci le16_to_cpu(fw_ddb_entry->def_timeout); 359562306a36Sopenharmony_ci conn->port = le16_to_cpu(fw_ddb_entry->port); 359662306a36Sopenharmony_ci 359762306a36Sopenharmony_ci options = le16_to_cpu(fw_ddb_entry->options); 359862306a36Sopenharmony_ci conn->ipaddress = kzalloc(IPv6_ADDR_LEN, GFP_KERNEL); 359962306a36Sopenharmony_ci if (!conn->ipaddress) { 360062306a36Sopenharmony_ci rc = -ENOMEM; 360162306a36Sopenharmony_ci goto exit_copy; 360262306a36Sopenharmony_ci } 360362306a36Sopenharmony_ci 360462306a36Sopenharmony_ci conn->redirect_ipaddr = kzalloc(IPv6_ADDR_LEN, GFP_KERNEL); 360562306a36Sopenharmony_ci if (!conn->redirect_ipaddr) { 360662306a36Sopenharmony_ci rc = -ENOMEM; 360762306a36Sopenharmony_ci goto exit_copy; 360862306a36Sopenharmony_ci } 360962306a36Sopenharmony_ci 361062306a36Sopenharmony_ci memcpy(conn->ipaddress, fw_ddb_entry->ip_addr, IPv6_ADDR_LEN); 361162306a36Sopenharmony_ci memcpy(conn->redirect_ipaddr, fw_ddb_entry->tgt_addr, IPv6_ADDR_LEN); 361262306a36Sopenharmony_ci 361362306a36Sopenharmony_ci if (test_bit(OPT_IPV6_DEVICE, &options)) { 361462306a36Sopenharmony_ci conn->ipv6_traffic_class = fw_ddb_entry->ipv4_tos; 361562306a36Sopenharmony_ci 361662306a36Sopenharmony_ci conn->link_local_ipv6_addr = kmemdup( 361762306a36Sopenharmony_ci fw_ddb_entry->link_local_ipv6_addr, 361862306a36Sopenharmony_ci IPv6_ADDR_LEN, GFP_KERNEL); 361962306a36Sopenharmony_ci if (!conn->link_local_ipv6_addr) { 362062306a36Sopenharmony_ci rc = -ENOMEM; 362162306a36Sopenharmony_ci goto exit_copy; 362262306a36Sopenharmony_ci } 362362306a36Sopenharmony_ci } else { 362462306a36Sopenharmony_ci conn->ipv4_tos = fw_ddb_entry->ipv4_tos; 362562306a36Sopenharmony_ci } 362662306a36Sopenharmony_ci 362762306a36Sopenharmony_ci if (fw_ddb_entry->iscsi_name[0]) { 362862306a36Sopenharmony_ci rc = iscsi_switch_str_param(&sess->targetname, 362962306a36Sopenharmony_ci (char *)fw_ddb_entry->iscsi_name); 363062306a36Sopenharmony_ci if (rc) 363162306a36Sopenharmony_ci goto exit_copy; 363262306a36Sopenharmony_ci } 363362306a36Sopenharmony_ci 363462306a36Sopenharmony_ci if (fw_ddb_entry->iscsi_alias[0]) { 363562306a36Sopenharmony_ci rc = iscsi_switch_str_param(&sess->targetalias, 363662306a36Sopenharmony_ci (char *)fw_ddb_entry->iscsi_alias); 363762306a36Sopenharmony_ci if (rc) 363862306a36Sopenharmony_ci goto exit_copy; 363962306a36Sopenharmony_ci } 364062306a36Sopenharmony_ci 364162306a36Sopenharmony_ci COPY_ISID(sess->isid, fw_ddb_entry->isid); 364262306a36Sopenharmony_ci 364362306a36Sopenharmony_ciexit_copy: 364462306a36Sopenharmony_ci return rc; 364562306a36Sopenharmony_ci} 364662306a36Sopenharmony_ci 364762306a36Sopenharmony_cistatic int qla4xxx_copy_to_fwddb_param(struct iscsi_bus_flash_session *sess, 364862306a36Sopenharmony_ci struct iscsi_bus_flash_conn *conn, 364962306a36Sopenharmony_ci struct dev_db_entry *fw_ddb_entry) 365062306a36Sopenharmony_ci{ 365162306a36Sopenharmony_ci uint16_t options; 365262306a36Sopenharmony_ci 365362306a36Sopenharmony_ci options = le16_to_cpu(fw_ddb_entry->options); 365462306a36Sopenharmony_ci SET_BITVAL(conn->is_fw_assigned_ipv6, options, BIT_11); 365562306a36Sopenharmony_ci if (!strncmp(sess->portal_type, PORTAL_TYPE_IPV6, 4)) 365662306a36Sopenharmony_ci options |= BIT_8; 365762306a36Sopenharmony_ci else 365862306a36Sopenharmony_ci options &= ~BIT_8; 365962306a36Sopenharmony_ci 366062306a36Sopenharmony_ci SET_BITVAL(sess->auto_snd_tgt_disable, options, BIT_6); 366162306a36Sopenharmony_ci SET_BITVAL(sess->discovery_sess, options, BIT_4); 366262306a36Sopenharmony_ci SET_BITVAL(sess->entry_state, options, BIT_3); 366362306a36Sopenharmony_ci fw_ddb_entry->options = cpu_to_le16(options); 366462306a36Sopenharmony_ci 366562306a36Sopenharmony_ci options = le16_to_cpu(fw_ddb_entry->iscsi_options); 366662306a36Sopenharmony_ci SET_BITVAL(conn->hdrdgst_en, options, BIT_13); 366762306a36Sopenharmony_ci SET_BITVAL(conn->datadgst_en, options, BIT_12); 366862306a36Sopenharmony_ci SET_BITVAL(sess->imm_data_en, options, BIT_11); 366962306a36Sopenharmony_ci SET_BITVAL(sess->initial_r2t_en, options, BIT_10); 367062306a36Sopenharmony_ci SET_BITVAL(sess->dataseq_inorder_en, options, BIT_9); 367162306a36Sopenharmony_ci SET_BITVAL(sess->pdu_inorder_en, options, BIT_8); 367262306a36Sopenharmony_ci SET_BITVAL(sess->chap_auth_en, options, BIT_7); 367362306a36Sopenharmony_ci SET_BITVAL(conn->snack_req_en, options, BIT_6); 367462306a36Sopenharmony_ci SET_BITVAL(sess->discovery_logout_en, options, BIT_5); 367562306a36Sopenharmony_ci SET_BITVAL(sess->bidi_chap_en, options, BIT_4); 367662306a36Sopenharmony_ci SET_BITVAL(sess->discovery_auth_optional, options, BIT_3); 367762306a36Sopenharmony_ci SET_BITVAL(sess->erl & BIT_1, options, BIT_1); 367862306a36Sopenharmony_ci SET_BITVAL(sess->erl & BIT_0, options, BIT_0); 367962306a36Sopenharmony_ci fw_ddb_entry->iscsi_options = cpu_to_le16(options); 368062306a36Sopenharmony_ci 368162306a36Sopenharmony_ci options = le16_to_cpu(fw_ddb_entry->tcp_options); 368262306a36Sopenharmony_ci SET_BITVAL(conn->tcp_timestamp_stat, options, BIT_6); 368362306a36Sopenharmony_ci SET_BITVAL(conn->tcp_nagle_disable, options, BIT_5); 368462306a36Sopenharmony_ci SET_BITVAL(conn->tcp_wsf_disable, options, BIT_4); 368562306a36Sopenharmony_ci SET_BITVAL(conn->tcp_timer_scale & BIT_2, options, BIT_3); 368662306a36Sopenharmony_ci SET_BITVAL(conn->tcp_timer_scale & BIT_1, options, BIT_2); 368762306a36Sopenharmony_ci SET_BITVAL(conn->tcp_timer_scale & BIT_0, options, BIT_1); 368862306a36Sopenharmony_ci SET_BITVAL(conn->tcp_timestamp_en, options, BIT_0); 368962306a36Sopenharmony_ci fw_ddb_entry->tcp_options = cpu_to_le16(options); 369062306a36Sopenharmony_ci 369162306a36Sopenharmony_ci options = le16_to_cpu(fw_ddb_entry->ip_options); 369262306a36Sopenharmony_ci SET_BITVAL(conn->fragment_disable, options, BIT_4); 369362306a36Sopenharmony_ci fw_ddb_entry->ip_options = cpu_to_le16(options); 369462306a36Sopenharmony_ci 369562306a36Sopenharmony_ci fw_ddb_entry->iscsi_max_outsnd_r2t = cpu_to_le16(sess->max_r2t); 369662306a36Sopenharmony_ci fw_ddb_entry->iscsi_max_rcv_data_seg_len = 369762306a36Sopenharmony_ci cpu_to_le16(conn->max_recv_dlength / BYTE_UNITS); 369862306a36Sopenharmony_ci fw_ddb_entry->iscsi_max_snd_data_seg_len = 369962306a36Sopenharmony_ci cpu_to_le16(conn->max_xmit_dlength / BYTE_UNITS); 370062306a36Sopenharmony_ci fw_ddb_entry->iscsi_first_burst_len = 370162306a36Sopenharmony_ci cpu_to_le16(sess->first_burst / BYTE_UNITS); 370262306a36Sopenharmony_ci fw_ddb_entry->iscsi_max_burst_len = cpu_to_le16(sess->max_burst / 370362306a36Sopenharmony_ci BYTE_UNITS); 370462306a36Sopenharmony_ci fw_ddb_entry->iscsi_def_time2wait = cpu_to_le16(sess->time2wait); 370562306a36Sopenharmony_ci fw_ddb_entry->iscsi_def_time2retain = cpu_to_le16(sess->time2retain); 370662306a36Sopenharmony_ci fw_ddb_entry->tgt_portal_grp = cpu_to_le16(sess->tpgt); 370762306a36Sopenharmony_ci fw_ddb_entry->mss = cpu_to_le16(conn->max_segment_size); 370862306a36Sopenharmony_ci fw_ddb_entry->tcp_xmt_wsf = (uint8_t) cpu_to_le32(conn->tcp_xmit_wsf); 370962306a36Sopenharmony_ci fw_ddb_entry->tcp_rcv_wsf = (uint8_t) cpu_to_le32(conn->tcp_recv_wsf); 371062306a36Sopenharmony_ci fw_ddb_entry->ipv6_flow_lbl = cpu_to_le16(conn->ipv6_flow_label); 371162306a36Sopenharmony_ci fw_ddb_entry->ka_timeout = cpu_to_le16(conn->keepalive_timeout); 371262306a36Sopenharmony_ci fw_ddb_entry->lcl_port = cpu_to_le16(conn->local_port); 371362306a36Sopenharmony_ci fw_ddb_entry->stat_sn = cpu_to_le32(conn->statsn); 371462306a36Sopenharmony_ci fw_ddb_entry->exp_stat_sn = cpu_to_le32(conn->exp_statsn); 371562306a36Sopenharmony_ci fw_ddb_entry->ddb_link = cpu_to_le16(sess->discovery_parent_idx); 371662306a36Sopenharmony_ci fw_ddb_entry->chap_tbl_idx = cpu_to_le16(sess->chap_out_idx); 371762306a36Sopenharmony_ci fw_ddb_entry->tsid = cpu_to_le16(sess->tsid); 371862306a36Sopenharmony_ci fw_ddb_entry->port = cpu_to_le16(conn->port); 371962306a36Sopenharmony_ci fw_ddb_entry->def_timeout = 372062306a36Sopenharmony_ci cpu_to_le16(sess->default_taskmgmt_timeout); 372162306a36Sopenharmony_ci 372262306a36Sopenharmony_ci if (!strncmp(sess->portal_type, PORTAL_TYPE_IPV6, 4)) 372362306a36Sopenharmony_ci fw_ddb_entry->ipv4_tos = conn->ipv6_traffic_class; 372462306a36Sopenharmony_ci else 372562306a36Sopenharmony_ci fw_ddb_entry->ipv4_tos = conn->ipv4_tos; 372662306a36Sopenharmony_ci 372762306a36Sopenharmony_ci if (conn->ipaddress) 372862306a36Sopenharmony_ci memcpy(fw_ddb_entry->ip_addr, conn->ipaddress, 372962306a36Sopenharmony_ci sizeof(fw_ddb_entry->ip_addr)); 373062306a36Sopenharmony_ci 373162306a36Sopenharmony_ci if (conn->redirect_ipaddr) 373262306a36Sopenharmony_ci memcpy(fw_ddb_entry->tgt_addr, conn->redirect_ipaddr, 373362306a36Sopenharmony_ci sizeof(fw_ddb_entry->tgt_addr)); 373462306a36Sopenharmony_ci 373562306a36Sopenharmony_ci if (conn->link_local_ipv6_addr) 373662306a36Sopenharmony_ci memcpy(fw_ddb_entry->link_local_ipv6_addr, 373762306a36Sopenharmony_ci conn->link_local_ipv6_addr, 373862306a36Sopenharmony_ci sizeof(fw_ddb_entry->link_local_ipv6_addr)); 373962306a36Sopenharmony_ci 374062306a36Sopenharmony_ci if (sess->targetname) 374162306a36Sopenharmony_ci memcpy(fw_ddb_entry->iscsi_name, sess->targetname, 374262306a36Sopenharmony_ci sizeof(fw_ddb_entry->iscsi_name)); 374362306a36Sopenharmony_ci 374462306a36Sopenharmony_ci if (sess->targetalias) 374562306a36Sopenharmony_ci memcpy(fw_ddb_entry->iscsi_alias, sess->targetalias, 374662306a36Sopenharmony_ci sizeof(fw_ddb_entry->iscsi_alias)); 374762306a36Sopenharmony_ci 374862306a36Sopenharmony_ci COPY_ISID(fw_ddb_entry->isid, sess->isid); 374962306a36Sopenharmony_ci 375062306a36Sopenharmony_ci return 0; 375162306a36Sopenharmony_ci} 375262306a36Sopenharmony_ci 375362306a36Sopenharmony_cistatic void qla4xxx_copy_to_sess_conn_params(struct iscsi_conn *conn, 375462306a36Sopenharmony_ci struct iscsi_session *sess, 375562306a36Sopenharmony_ci struct dev_db_entry *fw_ddb_entry) 375662306a36Sopenharmony_ci{ 375762306a36Sopenharmony_ci unsigned long options = 0; 375862306a36Sopenharmony_ci uint16_t ddb_link; 375962306a36Sopenharmony_ci uint16_t disc_parent; 376062306a36Sopenharmony_ci char ip_addr[DDB_IPADDR_LEN]; 376162306a36Sopenharmony_ci 376262306a36Sopenharmony_ci options = le16_to_cpu(fw_ddb_entry->options); 376362306a36Sopenharmony_ci conn->is_fw_assigned_ipv6 = test_bit(OPT_IS_FW_ASSIGNED_IPV6, &options); 376462306a36Sopenharmony_ci sess->auto_snd_tgt_disable = test_bit(OPT_AUTO_SENDTGTS_DISABLE, 376562306a36Sopenharmony_ci &options); 376662306a36Sopenharmony_ci sess->discovery_sess = test_bit(OPT_DISC_SESSION, &options); 376762306a36Sopenharmony_ci 376862306a36Sopenharmony_ci options = le16_to_cpu(fw_ddb_entry->iscsi_options); 376962306a36Sopenharmony_ci conn->hdrdgst_en = test_bit(ISCSIOPT_HEADER_DIGEST_EN, &options); 377062306a36Sopenharmony_ci conn->datadgst_en = test_bit(ISCSIOPT_DATA_DIGEST_EN, &options); 377162306a36Sopenharmony_ci sess->imm_data_en = test_bit(ISCSIOPT_IMMEDIATE_DATA_EN, &options); 377262306a36Sopenharmony_ci sess->initial_r2t_en = test_bit(ISCSIOPT_INITIAL_R2T_EN, &options); 377362306a36Sopenharmony_ci sess->dataseq_inorder_en = test_bit(ISCSIOPT_DATA_SEQ_IN_ORDER, 377462306a36Sopenharmony_ci &options); 377562306a36Sopenharmony_ci sess->pdu_inorder_en = test_bit(ISCSIOPT_DATA_PDU_IN_ORDER, &options); 377662306a36Sopenharmony_ci sess->chap_auth_en = test_bit(ISCSIOPT_CHAP_AUTH_EN, &options); 377762306a36Sopenharmony_ci sess->discovery_logout_en = test_bit(ISCSIOPT_DISCOVERY_LOGOUT_EN, 377862306a36Sopenharmony_ci &options); 377962306a36Sopenharmony_ci sess->bidi_chap_en = test_bit(ISCSIOPT_BIDI_CHAP_EN, &options); 378062306a36Sopenharmony_ci sess->discovery_auth_optional = 378162306a36Sopenharmony_ci test_bit(ISCSIOPT_DISCOVERY_AUTH_OPTIONAL, &options); 378262306a36Sopenharmony_ci if (test_bit(ISCSIOPT_ERL1, &options)) 378362306a36Sopenharmony_ci sess->erl |= BIT_1; 378462306a36Sopenharmony_ci if (test_bit(ISCSIOPT_ERL0, &options)) 378562306a36Sopenharmony_ci sess->erl |= BIT_0; 378662306a36Sopenharmony_ci 378762306a36Sopenharmony_ci options = le16_to_cpu(fw_ddb_entry->tcp_options); 378862306a36Sopenharmony_ci conn->tcp_timestamp_stat = test_bit(TCPOPT_TIMESTAMP_STAT, &options); 378962306a36Sopenharmony_ci conn->tcp_nagle_disable = test_bit(TCPOPT_NAGLE_DISABLE, &options); 379062306a36Sopenharmony_ci conn->tcp_wsf_disable = test_bit(TCPOPT_WSF_DISABLE, &options); 379162306a36Sopenharmony_ci if (test_bit(TCPOPT_TIMER_SCALE3, &options)) 379262306a36Sopenharmony_ci conn->tcp_timer_scale |= BIT_3; 379362306a36Sopenharmony_ci if (test_bit(TCPOPT_TIMER_SCALE2, &options)) 379462306a36Sopenharmony_ci conn->tcp_timer_scale |= BIT_2; 379562306a36Sopenharmony_ci if (test_bit(TCPOPT_TIMER_SCALE1, &options)) 379662306a36Sopenharmony_ci conn->tcp_timer_scale |= BIT_1; 379762306a36Sopenharmony_ci 379862306a36Sopenharmony_ci conn->tcp_timer_scale >>= 1; 379962306a36Sopenharmony_ci conn->tcp_timestamp_en = test_bit(TCPOPT_TIMESTAMP_EN, &options); 380062306a36Sopenharmony_ci 380162306a36Sopenharmony_ci options = le16_to_cpu(fw_ddb_entry->ip_options); 380262306a36Sopenharmony_ci conn->fragment_disable = test_bit(IPOPT_FRAGMENT_DISABLE, &options); 380362306a36Sopenharmony_ci 380462306a36Sopenharmony_ci conn->max_recv_dlength = BYTE_UNITS * 380562306a36Sopenharmony_ci le16_to_cpu(fw_ddb_entry->iscsi_max_rcv_data_seg_len); 380662306a36Sopenharmony_ci conn->max_xmit_dlength = BYTE_UNITS * 380762306a36Sopenharmony_ci le16_to_cpu(fw_ddb_entry->iscsi_max_snd_data_seg_len); 380862306a36Sopenharmony_ci sess->max_r2t = le16_to_cpu(fw_ddb_entry->iscsi_max_outsnd_r2t); 380962306a36Sopenharmony_ci sess->first_burst = BYTE_UNITS * 381062306a36Sopenharmony_ci le16_to_cpu(fw_ddb_entry->iscsi_first_burst_len); 381162306a36Sopenharmony_ci sess->max_burst = BYTE_UNITS * 381262306a36Sopenharmony_ci le16_to_cpu(fw_ddb_entry->iscsi_max_burst_len); 381362306a36Sopenharmony_ci sess->time2wait = le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait); 381462306a36Sopenharmony_ci sess->time2retain = le16_to_cpu(fw_ddb_entry->iscsi_def_time2retain); 381562306a36Sopenharmony_ci sess->tpgt = le32_to_cpu(fw_ddb_entry->tgt_portal_grp); 381662306a36Sopenharmony_ci conn->max_segment_size = le16_to_cpu(fw_ddb_entry->mss); 381762306a36Sopenharmony_ci conn->tcp_xmit_wsf = fw_ddb_entry->tcp_xmt_wsf; 381862306a36Sopenharmony_ci conn->tcp_recv_wsf = fw_ddb_entry->tcp_rcv_wsf; 381962306a36Sopenharmony_ci conn->ipv4_tos = fw_ddb_entry->ipv4_tos; 382062306a36Sopenharmony_ci conn->keepalive_tmo = le16_to_cpu(fw_ddb_entry->ka_timeout); 382162306a36Sopenharmony_ci conn->local_port = le16_to_cpu(fw_ddb_entry->lcl_port); 382262306a36Sopenharmony_ci conn->statsn = le32_to_cpu(fw_ddb_entry->stat_sn); 382362306a36Sopenharmony_ci conn->exp_statsn = le32_to_cpu(fw_ddb_entry->exp_stat_sn); 382462306a36Sopenharmony_ci sess->tsid = le16_to_cpu(fw_ddb_entry->tsid); 382562306a36Sopenharmony_ci COPY_ISID(sess->isid, fw_ddb_entry->isid); 382662306a36Sopenharmony_ci 382762306a36Sopenharmony_ci ddb_link = le16_to_cpu(fw_ddb_entry->ddb_link); 382862306a36Sopenharmony_ci if (ddb_link == DDB_ISNS) 382962306a36Sopenharmony_ci disc_parent = ISCSI_DISC_PARENT_ISNS; 383062306a36Sopenharmony_ci else if (ddb_link == DDB_NO_LINK) 383162306a36Sopenharmony_ci disc_parent = ISCSI_DISC_PARENT_UNKNOWN; 383262306a36Sopenharmony_ci else if (ddb_link < MAX_DDB_ENTRIES) 383362306a36Sopenharmony_ci disc_parent = ISCSI_DISC_PARENT_SENDTGT; 383462306a36Sopenharmony_ci else 383562306a36Sopenharmony_ci disc_parent = ISCSI_DISC_PARENT_UNKNOWN; 383662306a36Sopenharmony_ci 383762306a36Sopenharmony_ci iscsi_set_param(conn->cls_conn, ISCSI_PARAM_DISCOVERY_PARENT_TYPE, 383862306a36Sopenharmony_ci iscsi_get_discovery_parent_name(disc_parent), 0); 383962306a36Sopenharmony_ci 384062306a36Sopenharmony_ci iscsi_set_param(conn->cls_conn, ISCSI_PARAM_TARGET_ALIAS, 384162306a36Sopenharmony_ci (char *)fw_ddb_entry->iscsi_alias, 0); 384262306a36Sopenharmony_ci 384362306a36Sopenharmony_ci options = le16_to_cpu(fw_ddb_entry->options); 384462306a36Sopenharmony_ci if (options & DDB_OPT_IPV6_DEVICE) { 384562306a36Sopenharmony_ci memset(ip_addr, 0, sizeof(ip_addr)); 384662306a36Sopenharmony_ci sprintf(ip_addr, "%pI6", fw_ddb_entry->link_local_ipv6_addr); 384762306a36Sopenharmony_ci iscsi_set_param(conn->cls_conn, ISCSI_PARAM_LOCAL_IPADDR, 384862306a36Sopenharmony_ci (char *)ip_addr, 0); 384962306a36Sopenharmony_ci } 385062306a36Sopenharmony_ci} 385162306a36Sopenharmony_ci 385262306a36Sopenharmony_cistatic void qla4xxx_copy_fwddb_param(struct scsi_qla_host *ha, 385362306a36Sopenharmony_ci struct dev_db_entry *fw_ddb_entry, 385462306a36Sopenharmony_ci struct iscsi_cls_session *cls_sess, 385562306a36Sopenharmony_ci struct iscsi_cls_conn *cls_conn) 385662306a36Sopenharmony_ci{ 385762306a36Sopenharmony_ci int buflen = 0; 385862306a36Sopenharmony_ci struct iscsi_session *sess; 385962306a36Sopenharmony_ci struct ddb_entry *ddb_entry; 386062306a36Sopenharmony_ci struct ql4_chap_table chap_tbl; 386162306a36Sopenharmony_ci struct iscsi_conn *conn; 386262306a36Sopenharmony_ci char ip_addr[DDB_IPADDR_LEN]; 386362306a36Sopenharmony_ci uint16_t options = 0; 386462306a36Sopenharmony_ci 386562306a36Sopenharmony_ci sess = cls_sess->dd_data; 386662306a36Sopenharmony_ci ddb_entry = sess->dd_data; 386762306a36Sopenharmony_ci conn = cls_conn->dd_data; 386862306a36Sopenharmony_ci memset(&chap_tbl, 0, sizeof(chap_tbl)); 386962306a36Sopenharmony_ci 387062306a36Sopenharmony_ci ddb_entry->chap_tbl_idx = le16_to_cpu(fw_ddb_entry->chap_tbl_idx); 387162306a36Sopenharmony_ci 387262306a36Sopenharmony_ci qla4xxx_copy_to_sess_conn_params(conn, sess, fw_ddb_entry); 387362306a36Sopenharmony_ci 387462306a36Sopenharmony_ci sess->def_taskmgmt_tmo = le16_to_cpu(fw_ddb_entry->def_timeout); 387562306a36Sopenharmony_ci conn->persistent_port = le16_to_cpu(fw_ddb_entry->port); 387662306a36Sopenharmony_ci 387762306a36Sopenharmony_ci memset(ip_addr, 0, sizeof(ip_addr)); 387862306a36Sopenharmony_ci options = le16_to_cpu(fw_ddb_entry->options); 387962306a36Sopenharmony_ci if (options & DDB_OPT_IPV6_DEVICE) { 388062306a36Sopenharmony_ci iscsi_set_param(cls_conn, ISCSI_PARAM_PORTAL_TYPE, "ipv6", 4); 388162306a36Sopenharmony_ci 388262306a36Sopenharmony_ci memset(ip_addr, 0, sizeof(ip_addr)); 388362306a36Sopenharmony_ci sprintf(ip_addr, "%pI6", fw_ddb_entry->ip_addr); 388462306a36Sopenharmony_ci } else { 388562306a36Sopenharmony_ci iscsi_set_param(cls_conn, ISCSI_PARAM_PORTAL_TYPE, "ipv4", 4); 388662306a36Sopenharmony_ci sprintf(ip_addr, "%pI4", fw_ddb_entry->ip_addr); 388762306a36Sopenharmony_ci } 388862306a36Sopenharmony_ci 388962306a36Sopenharmony_ci iscsi_set_param(cls_conn, ISCSI_PARAM_PERSISTENT_ADDRESS, 389062306a36Sopenharmony_ci (char *)ip_addr, buflen); 389162306a36Sopenharmony_ci iscsi_set_param(cls_conn, ISCSI_PARAM_TARGET_NAME, 389262306a36Sopenharmony_ci (char *)fw_ddb_entry->iscsi_name, buflen); 389362306a36Sopenharmony_ci iscsi_set_param(cls_conn, ISCSI_PARAM_INITIATOR_NAME, 389462306a36Sopenharmony_ci (char *)ha->name_string, buflen); 389562306a36Sopenharmony_ci 389662306a36Sopenharmony_ci if (ddb_entry->chap_tbl_idx != INVALID_ENTRY) { 389762306a36Sopenharmony_ci if (!qla4xxx_get_uni_chap_at_index(ha, chap_tbl.name, 389862306a36Sopenharmony_ci chap_tbl.secret, 389962306a36Sopenharmony_ci ddb_entry->chap_tbl_idx)) { 390062306a36Sopenharmony_ci iscsi_set_param(cls_conn, ISCSI_PARAM_USERNAME, 390162306a36Sopenharmony_ci (char *)chap_tbl.name, 390262306a36Sopenharmony_ci strlen((char *)chap_tbl.name)); 390362306a36Sopenharmony_ci iscsi_set_param(cls_conn, ISCSI_PARAM_PASSWORD, 390462306a36Sopenharmony_ci (char *)chap_tbl.secret, 390562306a36Sopenharmony_ci chap_tbl.secret_len); 390662306a36Sopenharmony_ci } 390762306a36Sopenharmony_ci } 390862306a36Sopenharmony_ci} 390962306a36Sopenharmony_ci 391062306a36Sopenharmony_civoid qla4xxx_update_session_conn_fwddb_param(struct scsi_qla_host *ha, 391162306a36Sopenharmony_ci struct ddb_entry *ddb_entry) 391262306a36Sopenharmony_ci{ 391362306a36Sopenharmony_ci struct iscsi_cls_session *cls_sess; 391462306a36Sopenharmony_ci struct iscsi_cls_conn *cls_conn; 391562306a36Sopenharmony_ci uint32_t ddb_state; 391662306a36Sopenharmony_ci dma_addr_t fw_ddb_entry_dma; 391762306a36Sopenharmony_ci struct dev_db_entry *fw_ddb_entry; 391862306a36Sopenharmony_ci 391962306a36Sopenharmony_ci fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), 392062306a36Sopenharmony_ci &fw_ddb_entry_dma, GFP_KERNEL); 392162306a36Sopenharmony_ci if (!fw_ddb_entry) { 392262306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, 392362306a36Sopenharmony_ci "%s: Unable to allocate dma buffer\n", __func__); 392462306a36Sopenharmony_ci goto exit_session_conn_fwddb_param; 392562306a36Sopenharmony_ci } 392662306a36Sopenharmony_ci 392762306a36Sopenharmony_ci if (qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index, fw_ddb_entry, 392862306a36Sopenharmony_ci fw_ddb_entry_dma, NULL, NULL, &ddb_state, 392962306a36Sopenharmony_ci NULL, NULL, NULL) == QLA_ERROR) { 393062306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_ERR, ha, "scsi%ld: %s: failed " 393162306a36Sopenharmony_ci "get_ddb_entry for fw_ddb_index %d\n", 393262306a36Sopenharmony_ci ha->host_no, __func__, 393362306a36Sopenharmony_ci ddb_entry->fw_ddb_index)); 393462306a36Sopenharmony_ci goto exit_session_conn_fwddb_param; 393562306a36Sopenharmony_ci } 393662306a36Sopenharmony_ci 393762306a36Sopenharmony_ci cls_sess = ddb_entry->sess; 393862306a36Sopenharmony_ci 393962306a36Sopenharmony_ci cls_conn = ddb_entry->conn; 394062306a36Sopenharmony_ci 394162306a36Sopenharmony_ci /* Update params */ 394262306a36Sopenharmony_ci qla4xxx_copy_fwddb_param(ha, fw_ddb_entry, cls_sess, cls_conn); 394362306a36Sopenharmony_ci 394462306a36Sopenharmony_ciexit_session_conn_fwddb_param: 394562306a36Sopenharmony_ci if (fw_ddb_entry) 394662306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), 394762306a36Sopenharmony_ci fw_ddb_entry, fw_ddb_entry_dma); 394862306a36Sopenharmony_ci} 394962306a36Sopenharmony_ci 395062306a36Sopenharmony_civoid qla4xxx_update_session_conn_param(struct scsi_qla_host *ha, 395162306a36Sopenharmony_ci struct ddb_entry *ddb_entry) 395262306a36Sopenharmony_ci{ 395362306a36Sopenharmony_ci struct iscsi_cls_session *cls_sess; 395462306a36Sopenharmony_ci struct iscsi_cls_conn *cls_conn; 395562306a36Sopenharmony_ci struct iscsi_session *sess; 395662306a36Sopenharmony_ci struct iscsi_conn *conn; 395762306a36Sopenharmony_ci uint32_t ddb_state; 395862306a36Sopenharmony_ci dma_addr_t fw_ddb_entry_dma; 395962306a36Sopenharmony_ci struct dev_db_entry *fw_ddb_entry; 396062306a36Sopenharmony_ci 396162306a36Sopenharmony_ci fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), 396262306a36Sopenharmony_ci &fw_ddb_entry_dma, GFP_KERNEL); 396362306a36Sopenharmony_ci if (!fw_ddb_entry) { 396462306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, 396562306a36Sopenharmony_ci "%s: Unable to allocate dma buffer\n", __func__); 396662306a36Sopenharmony_ci goto exit_session_conn_param; 396762306a36Sopenharmony_ci } 396862306a36Sopenharmony_ci 396962306a36Sopenharmony_ci if (qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index, fw_ddb_entry, 397062306a36Sopenharmony_ci fw_ddb_entry_dma, NULL, NULL, &ddb_state, 397162306a36Sopenharmony_ci NULL, NULL, NULL) == QLA_ERROR) { 397262306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_ERR, ha, "scsi%ld: %s: failed " 397362306a36Sopenharmony_ci "get_ddb_entry for fw_ddb_index %d\n", 397462306a36Sopenharmony_ci ha->host_no, __func__, 397562306a36Sopenharmony_ci ddb_entry->fw_ddb_index)); 397662306a36Sopenharmony_ci goto exit_session_conn_param; 397762306a36Sopenharmony_ci } 397862306a36Sopenharmony_ci 397962306a36Sopenharmony_ci cls_sess = ddb_entry->sess; 398062306a36Sopenharmony_ci sess = cls_sess->dd_data; 398162306a36Sopenharmony_ci 398262306a36Sopenharmony_ci cls_conn = ddb_entry->conn; 398362306a36Sopenharmony_ci conn = cls_conn->dd_data; 398462306a36Sopenharmony_ci 398562306a36Sopenharmony_ci /* Update timers after login */ 398662306a36Sopenharmony_ci ddb_entry->default_relogin_timeout = 398762306a36Sopenharmony_ci (le16_to_cpu(fw_ddb_entry->def_timeout) > LOGIN_TOV) && 398862306a36Sopenharmony_ci (le16_to_cpu(fw_ddb_entry->def_timeout) < LOGIN_TOV * 10) ? 398962306a36Sopenharmony_ci le16_to_cpu(fw_ddb_entry->def_timeout) : LOGIN_TOV; 399062306a36Sopenharmony_ci ddb_entry->default_time2wait = 399162306a36Sopenharmony_ci le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait); 399262306a36Sopenharmony_ci 399362306a36Sopenharmony_ci /* Update params */ 399462306a36Sopenharmony_ci ddb_entry->chap_tbl_idx = le16_to_cpu(fw_ddb_entry->chap_tbl_idx); 399562306a36Sopenharmony_ci qla4xxx_copy_to_sess_conn_params(conn, sess, fw_ddb_entry); 399662306a36Sopenharmony_ci 399762306a36Sopenharmony_ci memcpy(sess->initiatorname, ha->name_string, 399862306a36Sopenharmony_ci min(sizeof(ha->name_string), sizeof(sess->initiatorname))); 399962306a36Sopenharmony_ci 400062306a36Sopenharmony_ciexit_session_conn_param: 400162306a36Sopenharmony_ci if (fw_ddb_entry) 400262306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), 400362306a36Sopenharmony_ci fw_ddb_entry, fw_ddb_entry_dma); 400462306a36Sopenharmony_ci} 400562306a36Sopenharmony_ci 400662306a36Sopenharmony_ci/* 400762306a36Sopenharmony_ci * Timer routines 400862306a36Sopenharmony_ci */ 400962306a36Sopenharmony_cistatic void qla4xxx_timer(struct timer_list *t); 401062306a36Sopenharmony_ci 401162306a36Sopenharmony_cistatic void qla4xxx_start_timer(struct scsi_qla_host *ha, 401262306a36Sopenharmony_ci unsigned long interval) 401362306a36Sopenharmony_ci{ 401462306a36Sopenharmony_ci DEBUG(printk("scsi: %s: Starting timer thread for adapter %d\n", 401562306a36Sopenharmony_ci __func__, ha->host->host_no)); 401662306a36Sopenharmony_ci timer_setup(&ha->timer, qla4xxx_timer, 0); 401762306a36Sopenharmony_ci ha->timer.expires = jiffies + interval * HZ; 401862306a36Sopenharmony_ci add_timer(&ha->timer); 401962306a36Sopenharmony_ci ha->timer_active = 1; 402062306a36Sopenharmony_ci} 402162306a36Sopenharmony_ci 402262306a36Sopenharmony_cistatic void qla4xxx_stop_timer(struct scsi_qla_host *ha) 402362306a36Sopenharmony_ci{ 402462306a36Sopenharmony_ci del_timer_sync(&ha->timer); 402562306a36Sopenharmony_ci ha->timer_active = 0; 402662306a36Sopenharmony_ci} 402762306a36Sopenharmony_ci 402862306a36Sopenharmony_ci/*** 402962306a36Sopenharmony_ci * qla4xxx_mark_device_missing - blocks the session 403062306a36Sopenharmony_ci * @cls_session: Pointer to the session to be blocked 403162306a36Sopenharmony_ci * @ddb_entry: Pointer to device database entry 403262306a36Sopenharmony_ci * 403362306a36Sopenharmony_ci * This routine marks a device missing and close connection. 403462306a36Sopenharmony_ci **/ 403562306a36Sopenharmony_civoid qla4xxx_mark_device_missing(struct iscsi_cls_session *cls_session) 403662306a36Sopenharmony_ci{ 403762306a36Sopenharmony_ci iscsi_block_session(cls_session); 403862306a36Sopenharmony_ci} 403962306a36Sopenharmony_ci 404062306a36Sopenharmony_ci/** 404162306a36Sopenharmony_ci * qla4xxx_mark_all_devices_missing - mark all devices as missing. 404262306a36Sopenharmony_ci * @ha: Pointer to host adapter structure. 404362306a36Sopenharmony_ci * 404462306a36Sopenharmony_ci * This routine marks a device missing and resets the relogin retry count. 404562306a36Sopenharmony_ci **/ 404662306a36Sopenharmony_civoid qla4xxx_mark_all_devices_missing(struct scsi_qla_host *ha) 404762306a36Sopenharmony_ci{ 404862306a36Sopenharmony_ci iscsi_host_for_each_session(ha->host, qla4xxx_mark_device_missing); 404962306a36Sopenharmony_ci} 405062306a36Sopenharmony_ci 405162306a36Sopenharmony_cistatic struct srb* qla4xxx_get_new_srb(struct scsi_qla_host *ha, 405262306a36Sopenharmony_ci struct ddb_entry *ddb_entry, 405362306a36Sopenharmony_ci struct scsi_cmnd *cmd) 405462306a36Sopenharmony_ci{ 405562306a36Sopenharmony_ci struct srb *srb; 405662306a36Sopenharmony_ci 405762306a36Sopenharmony_ci srb = mempool_alloc(ha->srb_mempool, GFP_ATOMIC); 405862306a36Sopenharmony_ci if (!srb) 405962306a36Sopenharmony_ci return srb; 406062306a36Sopenharmony_ci 406162306a36Sopenharmony_ci kref_init(&srb->srb_ref); 406262306a36Sopenharmony_ci srb->ha = ha; 406362306a36Sopenharmony_ci srb->ddb = ddb_entry; 406462306a36Sopenharmony_ci srb->cmd = cmd; 406562306a36Sopenharmony_ci srb->flags = 0; 406662306a36Sopenharmony_ci qla4xxx_cmd_priv(cmd)->srb = srb; 406762306a36Sopenharmony_ci 406862306a36Sopenharmony_ci return srb; 406962306a36Sopenharmony_ci} 407062306a36Sopenharmony_ci 407162306a36Sopenharmony_cistatic void qla4xxx_srb_free_dma(struct scsi_qla_host *ha, struct srb *srb) 407262306a36Sopenharmony_ci{ 407362306a36Sopenharmony_ci struct scsi_cmnd *cmd = srb->cmd; 407462306a36Sopenharmony_ci 407562306a36Sopenharmony_ci if (srb->flags & SRB_DMA_VALID) { 407662306a36Sopenharmony_ci scsi_dma_unmap(cmd); 407762306a36Sopenharmony_ci srb->flags &= ~SRB_DMA_VALID; 407862306a36Sopenharmony_ci } 407962306a36Sopenharmony_ci qla4xxx_cmd_priv(cmd)->srb = NULL; 408062306a36Sopenharmony_ci} 408162306a36Sopenharmony_ci 408262306a36Sopenharmony_civoid qla4xxx_srb_compl(struct kref *ref) 408362306a36Sopenharmony_ci{ 408462306a36Sopenharmony_ci struct srb *srb = container_of(ref, struct srb, srb_ref); 408562306a36Sopenharmony_ci struct scsi_cmnd *cmd = srb->cmd; 408662306a36Sopenharmony_ci struct scsi_qla_host *ha = srb->ha; 408762306a36Sopenharmony_ci 408862306a36Sopenharmony_ci qla4xxx_srb_free_dma(ha, srb); 408962306a36Sopenharmony_ci 409062306a36Sopenharmony_ci mempool_free(srb, ha->srb_mempool); 409162306a36Sopenharmony_ci 409262306a36Sopenharmony_ci scsi_done(cmd); 409362306a36Sopenharmony_ci} 409462306a36Sopenharmony_ci 409562306a36Sopenharmony_ci/** 409662306a36Sopenharmony_ci * qla4xxx_queuecommand - scsi layer issues scsi command to driver. 409762306a36Sopenharmony_ci * @host: scsi host 409862306a36Sopenharmony_ci * @cmd: Pointer to Linux's SCSI command structure 409962306a36Sopenharmony_ci * 410062306a36Sopenharmony_ci * Remarks: 410162306a36Sopenharmony_ci * This routine is invoked by Linux to send a SCSI command to the driver. 410262306a36Sopenharmony_ci * The mid-level driver tries to ensure that queuecommand never gets 410362306a36Sopenharmony_ci * invoked concurrently with itself or the interrupt handler (although 410462306a36Sopenharmony_ci * the interrupt handler may call this routine as part of request- 410562306a36Sopenharmony_ci * completion handling). Unfortunely, it sometimes calls the scheduler 410662306a36Sopenharmony_ci * in interrupt context which is a big NO! NO!. 410762306a36Sopenharmony_ci **/ 410862306a36Sopenharmony_cistatic int qla4xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) 410962306a36Sopenharmony_ci{ 411062306a36Sopenharmony_ci struct scsi_qla_host *ha = to_qla_host(host); 411162306a36Sopenharmony_ci struct ddb_entry *ddb_entry = cmd->device->hostdata; 411262306a36Sopenharmony_ci struct iscsi_cls_session *sess = ddb_entry->sess; 411362306a36Sopenharmony_ci struct srb *srb; 411462306a36Sopenharmony_ci int rval; 411562306a36Sopenharmony_ci 411662306a36Sopenharmony_ci if (test_bit(AF_EEH_BUSY, &ha->flags)) { 411762306a36Sopenharmony_ci if (test_bit(AF_PCI_CHANNEL_IO_PERM_FAILURE, &ha->flags)) 411862306a36Sopenharmony_ci cmd->result = DID_NO_CONNECT << 16; 411962306a36Sopenharmony_ci else 412062306a36Sopenharmony_ci cmd->result = DID_REQUEUE << 16; 412162306a36Sopenharmony_ci goto qc_fail_command; 412262306a36Sopenharmony_ci } 412362306a36Sopenharmony_ci 412462306a36Sopenharmony_ci if (!sess) { 412562306a36Sopenharmony_ci cmd->result = DID_IMM_RETRY << 16; 412662306a36Sopenharmony_ci goto qc_fail_command; 412762306a36Sopenharmony_ci } 412862306a36Sopenharmony_ci 412962306a36Sopenharmony_ci rval = iscsi_session_chkready(sess); 413062306a36Sopenharmony_ci if (rval) { 413162306a36Sopenharmony_ci cmd->result = rval; 413262306a36Sopenharmony_ci goto qc_fail_command; 413362306a36Sopenharmony_ci } 413462306a36Sopenharmony_ci 413562306a36Sopenharmony_ci if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) || 413662306a36Sopenharmony_ci test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags) || 413762306a36Sopenharmony_ci test_bit(DPC_RESET_HA, &ha->dpc_flags) || 413862306a36Sopenharmony_ci test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags) || 413962306a36Sopenharmony_ci test_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags) || 414062306a36Sopenharmony_ci !test_bit(AF_ONLINE, &ha->flags) || 414162306a36Sopenharmony_ci !test_bit(AF_LINK_UP, &ha->flags) || 414262306a36Sopenharmony_ci test_bit(AF_LOOPBACK, &ha->flags) || 414362306a36Sopenharmony_ci test_bit(DPC_POST_IDC_ACK, &ha->dpc_flags) || 414462306a36Sopenharmony_ci test_bit(DPC_RESTORE_ACB, &ha->dpc_flags) || 414562306a36Sopenharmony_ci test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags)) 414662306a36Sopenharmony_ci goto qc_host_busy; 414762306a36Sopenharmony_ci 414862306a36Sopenharmony_ci srb = qla4xxx_get_new_srb(ha, ddb_entry, cmd); 414962306a36Sopenharmony_ci if (!srb) 415062306a36Sopenharmony_ci goto qc_host_busy; 415162306a36Sopenharmony_ci 415262306a36Sopenharmony_ci rval = qla4xxx_send_command_to_isp(ha, srb); 415362306a36Sopenharmony_ci if (rval != QLA_SUCCESS) 415462306a36Sopenharmony_ci goto qc_host_busy_free_sp; 415562306a36Sopenharmony_ci 415662306a36Sopenharmony_ci return 0; 415762306a36Sopenharmony_ci 415862306a36Sopenharmony_ciqc_host_busy_free_sp: 415962306a36Sopenharmony_ci qla4xxx_srb_free_dma(ha, srb); 416062306a36Sopenharmony_ci mempool_free(srb, ha->srb_mempool); 416162306a36Sopenharmony_ci 416262306a36Sopenharmony_ciqc_host_busy: 416362306a36Sopenharmony_ci return SCSI_MLQUEUE_HOST_BUSY; 416462306a36Sopenharmony_ci 416562306a36Sopenharmony_ciqc_fail_command: 416662306a36Sopenharmony_ci scsi_done(cmd); 416762306a36Sopenharmony_ci 416862306a36Sopenharmony_ci return 0; 416962306a36Sopenharmony_ci} 417062306a36Sopenharmony_ci 417162306a36Sopenharmony_ci/** 417262306a36Sopenharmony_ci * qla4xxx_mem_free - frees memory allocated to adapter 417362306a36Sopenharmony_ci * @ha: Pointer to host adapter structure. 417462306a36Sopenharmony_ci * 417562306a36Sopenharmony_ci * Frees memory previously allocated by qla4xxx_mem_alloc 417662306a36Sopenharmony_ci **/ 417762306a36Sopenharmony_cistatic void qla4xxx_mem_free(struct scsi_qla_host *ha) 417862306a36Sopenharmony_ci{ 417962306a36Sopenharmony_ci if (ha->queues) 418062306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, ha->queues_len, ha->queues, 418162306a36Sopenharmony_ci ha->queues_dma); 418262306a36Sopenharmony_ci 418362306a36Sopenharmony_ci vfree(ha->fw_dump); 418462306a36Sopenharmony_ci 418562306a36Sopenharmony_ci ha->queues_len = 0; 418662306a36Sopenharmony_ci ha->queues = NULL; 418762306a36Sopenharmony_ci ha->queues_dma = 0; 418862306a36Sopenharmony_ci ha->request_ring = NULL; 418962306a36Sopenharmony_ci ha->request_dma = 0; 419062306a36Sopenharmony_ci ha->response_ring = NULL; 419162306a36Sopenharmony_ci ha->response_dma = 0; 419262306a36Sopenharmony_ci ha->shadow_regs = NULL; 419362306a36Sopenharmony_ci ha->shadow_regs_dma = 0; 419462306a36Sopenharmony_ci ha->fw_dump = NULL; 419562306a36Sopenharmony_ci ha->fw_dump_size = 0; 419662306a36Sopenharmony_ci 419762306a36Sopenharmony_ci /* Free srb pool. */ 419862306a36Sopenharmony_ci mempool_destroy(ha->srb_mempool); 419962306a36Sopenharmony_ci ha->srb_mempool = NULL; 420062306a36Sopenharmony_ci 420162306a36Sopenharmony_ci dma_pool_destroy(ha->chap_dma_pool); 420262306a36Sopenharmony_ci 420362306a36Sopenharmony_ci vfree(ha->chap_list); 420462306a36Sopenharmony_ci ha->chap_list = NULL; 420562306a36Sopenharmony_ci 420662306a36Sopenharmony_ci dma_pool_destroy(ha->fw_ddb_dma_pool); 420762306a36Sopenharmony_ci 420862306a36Sopenharmony_ci /* release io space registers */ 420962306a36Sopenharmony_ci if (is_qla8022(ha)) { 421062306a36Sopenharmony_ci if (ha->nx_pcibase) 421162306a36Sopenharmony_ci iounmap( 421262306a36Sopenharmony_ci (struct device_reg_82xx __iomem *)ha->nx_pcibase); 421362306a36Sopenharmony_ci } else if (is_qla8032(ha) || is_qla8042(ha)) { 421462306a36Sopenharmony_ci if (ha->nx_pcibase) 421562306a36Sopenharmony_ci iounmap( 421662306a36Sopenharmony_ci (struct device_reg_83xx __iomem *)ha->nx_pcibase); 421762306a36Sopenharmony_ci } else if (ha->reg) { 421862306a36Sopenharmony_ci iounmap(ha->reg); 421962306a36Sopenharmony_ci } 422062306a36Sopenharmony_ci 422162306a36Sopenharmony_ci vfree(ha->reset_tmplt.buff); 422262306a36Sopenharmony_ci 422362306a36Sopenharmony_ci pci_release_regions(ha->pdev); 422462306a36Sopenharmony_ci} 422562306a36Sopenharmony_ci 422662306a36Sopenharmony_ci/** 422762306a36Sopenharmony_ci * qla4xxx_mem_alloc - allocates memory for use by adapter. 422862306a36Sopenharmony_ci * @ha: Pointer to host adapter structure 422962306a36Sopenharmony_ci * 423062306a36Sopenharmony_ci * Allocates DMA memory for request and response queues. Also allocates memory 423162306a36Sopenharmony_ci * for srbs. 423262306a36Sopenharmony_ci **/ 423362306a36Sopenharmony_cistatic int qla4xxx_mem_alloc(struct scsi_qla_host *ha) 423462306a36Sopenharmony_ci{ 423562306a36Sopenharmony_ci unsigned long align; 423662306a36Sopenharmony_ci 423762306a36Sopenharmony_ci /* Allocate contiguous block of DMA memory for queues. */ 423862306a36Sopenharmony_ci ha->queues_len = ((REQUEST_QUEUE_DEPTH * QUEUE_SIZE) + 423962306a36Sopenharmony_ci (RESPONSE_QUEUE_DEPTH * QUEUE_SIZE) + 424062306a36Sopenharmony_ci sizeof(struct shadow_regs) + 424162306a36Sopenharmony_ci MEM_ALIGN_VALUE + 424262306a36Sopenharmony_ci (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1); 424362306a36Sopenharmony_ci ha->queues = dma_alloc_coherent(&ha->pdev->dev, ha->queues_len, 424462306a36Sopenharmony_ci &ha->queues_dma, GFP_KERNEL); 424562306a36Sopenharmony_ci if (ha->queues == NULL) { 424662306a36Sopenharmony_ci ql4_printk(KERN_WARNING, ha, 424762306a36Sopenharmony_ci "Memory Allocation failed - queues.\n"); 424862306a36Sopenharmony_ci 424962306a36Sopenharmony_ci goto mem_alloc_error_exit; 425062306a36Sopenharmony_ci } 425162306a36Sopenharmony_ci 425262306a36Sopenharmony_ci /* 425362306a36Sopenharmony_ci * As per RISC alignment requirements -- the bus-address must be a 425462306a36Sopenharmony_ci * multiple of the request-ring size (in bytes). 425562306a36Sopenharmony_ci */ 425662306a36Sopenharmony_ci align = 0; 425762306a36Sopenharmony_ci if ((unsigned long)ha->queues_dma & (MEM_ALIGN_VALUE - 1)) 425862306a36Sopenharmony_ci align = MEM_ALIGN_VALUE - ((unsigned long)ha->queues_dma & 425962306a36Sopenharmony_ci (MEM_ALIGN_VALUE - 1)); 426062306a36Sopenharmony_ci 426162306a36Sopenharmony_ci /* Update request and response queue pointers. */ 426262306a36Sopenharmony_ci ha->request_dma = ha->queues_dma + align; 426362306a36Sopenharmony_ci ha->request_ring = (struct queue_entry *) (ha->queues + align); 426462306a36Sopenharmony_ci ha->response_dma = ha->queues_dma + align + 426562306a36Sopenharmony_ci (REQUEST_QUEUE_DEPTH * QUEUE_SIZE); 426662306a36Sopenharmony_ci ha->response_ring = (struct queue_entry *) (ha->queues + align + 426762306a36Sopenharmony_ci (REQUEST_QUEUE_DEPTH * 426862306a36Sopenharmony_ci QUEUE_SIZE)); 426962306a36Sopenharmony_ci ha->shadow_regs_dma = ha->queues_dma + align + 427062306a36Sopenharmony_ci (REQUEST_QUEUE_DEPTH * QUEUE_SIZE) + 427162306a36Sopenharmony_ci (RESPONSE_QUEUE_DEPTH * QUEUE_SIZE); 427262306a36Sopenharmony_ci ha->shadow_regs = (struct shadow_regs *) (ha->queues + align + 427362306a36Sopenharmony_ci (REQUEST_QUEUE_DEPTH * 427462306a36Sopenharmony_ci QUEUE_SIZE) + 427562306a36Sopenharmony_ci (RESPONSE_QUEUE_DEPTH * 427662306a36Sopenharmony_ci QUEUE_SIZE)); 427762306a36Sopenharmony_ci 427862306a36Sopenharmony_ci /* Allocate memory for srb pool. */ 427962306a36Sopenharmony_ci ha->srb_mempool = mempool_create(SRB_MIN_REQ, mempool_alloc_slab, 428062306a36Sopenharmony_ci mempool_free_slab, srb_cachep); 428162306a36Sopenharmony_ci if (ha->srb_mempool == NULL) { 428262306a36Sopenharmony_ci ql4_printk(KERN_WARNING, ha, 428362306a36Sopenharmony_ci "Memory Allocation failed - SRB Pool.\n"); 428462306a36Sopenharmony_ci 428562306a36Sopenharmony_ci goto mem_alloc_error_exit; 428662306a36Sopenharmony_ci } 428762306a36Sopenharmony_ci 428862306a36Sopenharmony_ci ha->chap_dma_pool = dma_pool_create("ql4_chap", &ha->pdev->dev, 428962306a36Sopenharmony_ci CHAP_DMA_BLOCK_SIZE, 8, 0); 429062306a36Sopenharmony_ci 429162306a36Sopenharmony_ci if (ha->chap_dma_pool == NULL) { 429262306a36Sopenharmony_ci ql4_printk(KERN_WARNING, ha, 429362306a36Sopenharmony_ci "%s: chap_dma_pool allocation failed..\n", __func__); 429462306a36Sopenharmony_ci goto mem_alloc_error_exit; 429562306a36Sopenharmony_ci } 429662306a36Sopenharmony_ci 429762306a36Sopenharmony_ci ha->fw_ddb_dma_pool = dma_pool_create("ql4_fw_ddb", &ha->pdev->dev, 429862306a36Sopenharmony_ci DDB_DMA_BLOCK_SIZE, 8, 0); 429962306a36Sopenharmony_ci 430062306a36Sopenharmony_ci if (ha->fw_ddb_dma_pool == NULL) { 430162306a36Sopenharmony_ci ql4_printk(KERN_WARNING, ha, 430262306a36Sopenharmony_ci "%s: fw_ddb_dma_pool allocation failed..\n", 430362306a36Sopenharmony_ci __func__); 430462306a36Sopenharmony_ci goto mem_alloc_error_exit; 430562306a36Sopenharmony_ci } 430662306a36Sopenharmony_ci 430762306a36Sopenharmony_ci return QLA_SUCCESS; 430862306a36Sopenharmony_ci 430962306a36Sopenharmony_cimem_alloc_error_exit: 431062306a36Sopenharmony_ci return QLA_ERROR; 431162306a36Sopenharmony_ci} 431262306a36Sopenharmony_ci 431362306a36Sopenharmony_ci/** 431462306a36Sopenharmony_ci * qla4_8xxx_check_temp - Check the ISP82XX temperature. 431562306a36Sopenharmony_ci * @ha: adapter block pointer. 431662306a36Sopenharmony_ci * 431762306a36Sopenharmony_ci * Note: The caller should not hold the idc lock. 431862306a36Sopenharmony_ci **/ 431962306a36Sopenharmony_cistatic int qla4_8xxx_check_temp(struct scsi_qla_host *ha) 432062306a36Sopenharmony_ci{ 432162306a36Sopenharmony_ci uint32_t temp, temp_state, temp_val; 432262306a36Sopenharmony_ci int status = QLA_SUCCESS; 432362306a36Sopenharmony_ci 432462306a36Sopenharmony_ci temp = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_TEMP_STATE); 432562306a36Sopenharmony_ci 432662306a36Sopenharmony_ci temp_state = qla82xx_get_temp_state(temp); 432762306a36Sopenharmony_ci temp_val = qla82xx_get_temp_val(temp); 432862306a36Sopenharmony_ci 432962306a36Sopenharmony_ci if (temp_state == QLA82XX_TEMP_PANIC) { 433062306a36Sopenharmony_ci ql4_printk(KERN_WARNING, ha, "Device temperature %d degrees C" 433162306a36Sopenharmony_ci " exceeds maximum allowed. Hardware has been shut" 433262306a36Sopenharmony_ci " down.\n", temp_val); 433362306a36Sopenharmony_ci status = QLA_ERROR; 433462306a36Sopenharmony_ci } else if (temp_state == QLA82XX_TEMP_WARN) { 433562306a36Sopenharmony_ci if (ha->temperature == QLA82XX_TEMP_NORMAL) 433662306a36Sopenharmony_ci ql4_printk(KERN_WARNING, ha, "Device temperature %d" 433762306a36Sopenharmony_ci " degrees C exceeds operating range." 433862306a36Sopenharmony_ci " Immediate action needed.\n", temp_val); 433962306a36Sopenharmony_ci } else { 434062306a36Sopenharmony_ci if (ha->temperature == QLA82XX_TEMP_WARN) 434162306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "Device temperature is" 434262306a36Sopenharmony_ci " now %d degrees C in normal range.\n", 434362306a36Sopenharmony_ci temp_val); 434462306a36Sopenharmony_ci } 434562306a36Sopenharmony_ci ha->temperature = temp_state; 434662306a36Sopenharmony_ci return status; 434762306a36Sopenharmony_ci} 434862306a36Sopenharmony_ci 434962306a36Sopenharmony_ci/** 435062306a36Sopenharmony_ci * qla4_8xxx_check_fw_alive - Check firmware health 435162306a36Sopenharmony_ci * @ha: Pointer to host adapter structure. 435262306a36Sopenharmony_ci * 435362306a36Sopenharmony_ci * Context: Interrupt 435462306a36Sopenharmony_ci **/ 435562306a36Sopenharmony_cistatic int qla4_8xxx_check_fw_alive(struct scsi_qla_host *ha) 435662306a36Sopenharmony_ci{ 435762306a36Sopenharmony_ci uint32_t fw_heartbeat_counter; 435862306a36Sopenharmony_ci int status = QLA_SUCCESS; 435962306a36Sopenharmony_ci 436062306a36Sopenharmony_ci fw_heartbeat_counter = qla4_8xxx_rd_direct(ha, 436162306a36Sopenharmony_ci QLA8XXX_PEG_ALIVE_COUNTER); 436262306a36Sopenharmony_ci /* If PEG_ALIVE_COUNTER is 0xffffffff, AER/EEH is in progress, ignore */ 436362306a36Sopenharmony_ci if (fw_heartbeat_counter == 0xffffffff) { 436462306a36Sopenharmony_ci DEBUG2(printk(KERN_WARNING "scsi%ld: %s: Device in frozen " 436562306a36Sopenharmony_ci "state, QLA82XX_PEG_ALIVE_COUNTER is 0xffffffff\n", 436662306a36Sopenharmony_ci ha->host_no, __func__)); 436762306a36Sopenharmony_ci return status; 436862306a36Sopenharmony_ci } 436962306a36Sopenharmony_ci 437062306a36Sopenharmony_ci if (ha->fw_heartbeat_counter == fw_heartbeat_counter) { 437162306a36Sopenharmony_ci ha->seconds_since_last_heartbeat++; 437262306a36Sopenharmony_ci /* FW not alive after 2 seconds */ 437362306a36Sopenharmony_ci if (ha->seconds_since_last_heartbeat == 2) { 437462306a36Sopenharmony_ci ha->seconds_since_last_heartbeat = 0; 437562306a36Sopenharmony_ci qla4_8xxx_dump_peg_reg(ha); 437662306a36Sopenharmony_ci status = QLA_ERROR; 437762306a36Sopenharmony_ci } 437862306a36Sopenharmony_ci } else 437962306a36Sopenharmony_ci ha->seconds_since_last_heartbeat = 0; 438062306a36Sopenharmony_ci 438162306a36Sopenharmony_ci ha->fw_heartbeat_counter = fw_heartbeat_counter; 438262306a36Sopenharmony_ci return status; 438362306a36Sopenharmony_ci} 438462306a36Sopenharmony_ci 438562306a36Sopenharmony_cistatic void qla4_8xxx_process_fw_error(struct scsi_qla_host *ha) 438662306a36Sopenharmony_ci{ 438762306a36Sopenharmony_ci uint32_t halt_status; 438862306a36Sopenharmony_ci int halt_status_unrecoverable = 0; 438962306a36Sopenharmony_ci 439062306a36Sopenharmony_ci halt_status = qla4_8xxx_rd_direct(ha, QLA8XXX_PEG_HALT_STATUS1); 439162306a36Sopenharmony_ci 439262306a36Sopenharmony_ci if (is_qla8022(ha)) { 439362306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "%s: disabling pause transmit on port 0 & 1.\n", 439462306a36Sopenharmony_ci __func__); 439562306a36Sopenharmony_ci qla4_82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x98, 439662306a36Sopenharmony_ci CRB_NIU_XG_PAUSE_CTL_P0 | 439762306a36Sopenharmony_ci CRB_NIU_XG_PAUSE_CTL_P1); 439862306a36Sopenharmony_ci 439962306a36Sopenharmony_ci if (QLA82XX_FWERROR_CODE(halt_status) == 0x67) 440062306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: Firmware aborted with error code 0x00006700. Device is being reset\n", 440162306a36Sopenharmony_ci __func__); 440262306a36Sopenharmony_ci if (halt_status & HALT_STATUS_UNRECOVERABLE) 440362306a36Sopenharmony_ci halt_status_unrecoverable = 1; 440462306a36Sopenharmony_ci } else if (is_qla8032(ha) || is_qla8042(ha)) { 440562306a36Sopenharmony_ci if (halt_status & QLA83XX_HALT_STATUS_FW_RESET) 440662306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: Firmware error detected device is being reset\n", 440762306a36Sopenharmony_ci __func__); 440862306a36Sopenharmony_ci else if (halt_status & QLA83XX_HALT_STATUS_UNRECOVERABLE) 440962306a36Sopenharmony_ci halt_status_unrecoverable = 1; 441062306a36Sopenharmony_ci } 441162306a36Sopenharmony_ci 441262306a36Sopenharmony_ci /* 441362306a36Sopenharmony_ci * Since we cannot change dev_state in interrupt context, 441462306a36Sopenharmony_ci * set appropriate DPC flag then wakeup DPC 441562306a36Sopenharmony_ci */ 441662306a36Sopenharmony_ci if (halt_status_unrecoverable) { 441762306a36Sopenharmony_ci set_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags); 441862306a36Sopenharmony_ci } else { 441962306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "%s: detect abort needed!\n", 442062306a36Sopenharmony_ci __func__); 442162306a36Sopenharmony_ci set_bit(DPC_RESET_HA, &ha->dpc_flags); 442262306a36Sopenharmony_ci } 442362306a36Sopenharmony_ci qla4xxx_mailbox_premature_completion(ha); 442462306a36Sopenharmony_ci qla4xxx_wake_dpc(ha); 442562306a36Sopenharmony_ci} 442662306a36Sopenharmony_ci 442762306a36Sopenharmony_ci/** 442862306a36Sopenharmony_ci * qla4_8xxx_watchdog - Poll dev state 442962306a36Sopenharmony_ci * @ha: Pointer to host adapter structure. 443062306a36Sopenharmony_ci * 443162306a36Sopenharmony_ci * Context: Interrupt 443262306a36Sopenharmony_ci **/ 443362306a36Sopenharmony_civoid qla4_8xxx_watchdog(struct scsi_qla_host *ha) 443462306a36Sopenharmony_ci{ 443562306a36Sopenharmony_ci uint32_t dev_state; 443662306a36Sopenharmony_ci uint32_t idc_ctrl; 443762306a36Sopenharmony_ci 443862306a36Sopenharmony_ci if (is_qla8032(ha) && 443962306a36Sopenharmony_ci (qla4_83xx_is_detached(ha) == QLA_SUCCESS)) 444062306a36Sopenharmony_ci WARN_ONCE(1, "%s: iSCSI function %d marked invisible\n", 444162306a36Sopenharmony_ci __func__, ha->func_num); 444262306a36Sopenharmony_ci 444362306a36Sopenharmony_ci /* don't poll if reset is going on */ 444462306a36Sopenharmony_ci if (!(test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags) || 444562306a36Sopenharmony_ci test_bit(DPC_RESET_HA, &ha->dpc_flags) || 444662306a36Sopenharmony_ci test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags))) { 444762306a36Sopenharmony_ci dev_state = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DEV_STATE); 444862306a36Sopenharmony_ci 444962306a36Sopenharmony_ci if (qla4_8xxx_check_temp(ha)) { 445062306a36Sopenharmony_ci if (is_qla8022(ha)) { 445162306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "disabling pause transmit on port 0 & 1.\n"); 445262306a36Sopenharmony_ci qla4_82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x98, 445362306a36Sopenharmony_ci CRB_NIU_XG_PAUSE_CTL_P0 | 445462306a36Sopenharmony_ci CRB_NIU_XG_PAUSE_CTL_P1); 445562306a36Sopenharmony_ci } 445662306a36Sopenharmony_ci set_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags); 445762306a36Sopenharmony_ci qla4xxx_wake_dpc(ha); 445862306a36Sopenharmony_ci } else if (dev_state == QLA8XXX_DEV_NEED_RESET && 445962306a36Sopenharmony_ci !test_bit(DPC_RESET_HA, &ha->dpc_flags)) { 446062306a36Sopenharmony_ci 446162306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "%s: HW State: NEED RESET!\n", 446262306a36Sopenharmony_ci __func__); 446362306a36Sopenharmony_ci 446462306a36Sopenharmony_ci if (is_qla8032(ha) || is_qla8042(ha)) { 446562306a36Sopenharmony_ci idc_ctrl = qla4_83xx_rd_reg(ha, 446662306a36Sopenharmony_ci QLA83XX_IDC_DRV_CTRL); 446762306a36Sopenharmony_ci if (!(idc_ctrl & GRACEFUL_RESET_BIT1)) { 446862306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "%s: Graceful reset bit is not set\n", 446962306a36Sopenharmony_ci __func__); 447062306a36Sopenharmony_ci qla4xxx_mailbox_premature_completion( 447162306a36Sopenharmony_ci ha); 447262306a36Sopenharmony_ci } 447362306a36Sopenharmony_ci } 447462306a36Sopenharmony_ci 447562306a36Sopenharmony_ci if ((is_qla8032(ha) || is_qla8042(ha)) || 447662306a36Sopenharmony_ci (is_qla8022(ha) && !ql4xdontresethba)) { 447762306a36Sopenharmony_ci set_bit(DPC_RESET_HA, &ha->dpc_flags); 447862306a36Sopenharmony_ci qla4xxx_wake_dpc(ha); 447962306a36Sopenharmony_ci } 448062306a36Sopenharmony_ci } else if (dev_state == QLA8XXX_DEV_NEED_QUIESCENT && 448162306a36Sopenharmony_ci !test_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags)) { 448262306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "%s: HW State: NEED QUIES!\n", 448362306a36Sopenharmony_ci __func__); 448462306a36Sopenharmony_ci set_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags); 448562306a36Sopenharmony_ci qla4xxx_wake_dpc(ha); 448662306a36Sopenharmony_ci } else { 448762306a36Sopenharmony_ci /* Check firmware health */ 448862306a36Sopenharmony_ci if (qla4_8xxx_check_fw_alive(ha)) 448962306a36Sopenharmony_ci qla4_8xxx_process_fw_error(ha); 449062306a36Sopenharmony_ci } 449162306a36Sopenharmony_ci } 449262306a36Sopenharmony_ci} 449362306a36Sopenharmony_ci 449462306a36Sopenharmony_cistatic void qla4xxx_check_relogin_flash_ddb(struct iscsi_cls_session *cls_sess) 449562306a36Sopenharmony_ci{ 449662306a36Sopenharmony_ci struct iscsi_session *sess; 449762306a36Sopenharmony_ci struct ddb_entry *ddb_entry; 449862306a36Sopenharmony_ci struct scsi_qla_host *ha; 449962306a36Sopenharmony_ci 450062306a36Sopenharmony_ci sess = cls_sess->dd_data; 450162306a36Sopenharmony_ci ddb_entry = sess->dd_data; 450262306a36Sopenharmony_ci ha = ddb_entry->ha; 450362306a36Sopenharmony_ci 450462306a36Sopenharmony_ci if (!(ddb_entry->ddb_type == FLASH_DDB)) 450562306a36Sopenharmony_ci return; 450662306a36Sopenharmony_ci 450762306a36Sopenharmony_ci if (adapter_up(ha) && !test_bit(DF_RELOGIN, &ddb_entry->flags) && 450862306a36Sopenharmony_ci !iscsi_is_session_online(cls_sess)) { 450962306a36Sopenharmony_ci if (atomic_read(&ddb_entry->retry_relogin_timer) != 451062306a36Sopenharmony_ci INVALID_ENTRY) { 451162306a36Sopenharmony_ci if (atomic_read(&ddb_entry->retry_relogin_timer) == 451262306a36Sopenharmony_ci 0) { 451362306a36Sopenharmony_ci atomic_set(&ddb_entry->retry_relogin_timer, 451462306a36Sopenharmony_ci INVALID_ENTRY); 451562306a36Sopenharmony_ci set_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags); 451662306a36Sopenharmony_ci set_bit(DF_RELOGIN, &ddb_entry->flags); 451762306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 451862306a36Sopenharmony_ci "%s: index [%d] login device\n", 451962306a36Sopenharmony_ci __func__, ddb_entry->fw_ddb_index)); 452062306a36Sopenharmony_ci } else 452162306a36Sopenharmony_ci atomic_dec(&ddb_entry->retry_relogin_timer); 452262306a36Sopenharmony_ci } 452362306a36Sopenharmony_ci } 452462306a36Sopenharmony_ci 452562306a36Sopenharmony_ci /* Wait for relogin to timeout */ 452662306a36Sopenharmony_ci if (atomic_read(&ddb_entry->relogin_timer) && 452762306a36Sopenharmony_ci (atomic_dec_and_test(&ddb_entry->relogin_timer) != 0)) { 452862306a36Sopenharmony_ci /* 452962306a36Sopenharmony_ci * If the relogin times out and the device is 453062306a36Sopenharmony_ci * still NOT ONLINE then try and relogin again. 453162306a36Sopenharmony_ci */ 453262306a36Sopenharmony_ci if (!iscsi_is_session_online(cls_sess)) { 453362306a36Sopenharmony_ci /* Reset retry relogin timer */ 453462306a36Sopenharmony_ci atomic_inc(&ddb_entry->relogin_retry_count); 453562306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 453662306a36Sopenharmony_ci "%s: index[%d] relogin timed out-retrying" 453762306a36Sopenharmony_ci " relogin (%d), retry (%d)\n", __func__, 453862306a36Sopenharmony_ci ddb_entry->fw_ddb_index, 453962306a36Sopenharmony_ci atomic_read(&ddb_entry->relogin_retry_count), 454062306a36Sopenharmony_ci ddb_entry->default_time2wait + 4)); 454162306a36Sopenharmony_ci set_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags); 454262306a36Sopenharmony_ci atomic_set(&ddb_entry->retry_relogin_timer, 454362306a36Sopenharmony_ci ddb_entry->default_time2wait + 4); 454462306a36Sopenharmony_ci } 454562306a36Sopenharmony_ci } 454662306a36Sopenharmony_ci} 454762306a36Sopenharmony_ci 454862306a36Sopenharmony_ci/** 454962306a36Sopenharmony_ci * qla4xxx_timer - checks every second for work to do. 455062306a36Sopenharmony_ci * @t: Context to obtain pointer to host adapter structure. 455162306a36Sopenharmony_ci **/ 455262306a36Sopenharmony_cistatic void qla4xxx_timer(struct timer_list *t) 455362306a36Sopenharmony_ci{ 455462306a36Sopenharmony_ci struct scsi_qla_host *ha = from_timer(ha, t, timer); 455562306a36Sopenharmony_ci int start_dpc = 0; 455662306a36Sopenharmony_ci uint16_t w; 455762306a36Sopenharmony_ci 455862306a36Sopenharmony_ci iscsi_host_for_each_session(ha->host, qla4xxx_check_relogin_flash_ddb); 455962306a36Sopenharmony_ci 456062306a36Sopenharmony_ci /* If we are in the middle of AER/EEH processing 456162306a36Sopenharmony_ci * skip any processing and reschedule the timer 456262306a36Sopenharmony_ci */ 456362306a36Sopenharmony_ci if (test_bit(AF_EEH_BUSY, &ha->flags)) { 456462306a36Sopenharmony_ci mod_timer(&ha->timer, jiffies + HZ); 456562306a36Sopenharmony_ci return; 456662306a36Sopenharmony_ci } 456762306a36Sopenharmony_ci 456862306a36Sopenharmony_ci /* Hardware read to trigger an EEH error during mailbox waits. */ 456962306a36Sopenharmony_ci if (!pci_channel_offline(ha->pdev)) 457062306a36Sopenharmony_ci pci_read_config_word(ha->pdev, PCI_VENDOR_ID, &w); 457162306a36Sopenharmony_ci 457262306a36Sopenharmony_ci if (is_qla80XX(ha)) 457362306a36Sopenharmony_ci qla4_8xxx_watchdog(ha); 457462306a36Sopenharmony_ci 457562306a36Sopenharmony_ci if (is_qla40XX(ha)) { 457662306a36Sopenharmony_ci /* Check for heartbeat interval. */ 457762306a36Sopenharmony_ci if (ha->firmware_options & FWOPT_HEARTBEAT_ENABLE && 457862306a36Sopenharmony_ci ha->heartbeat_interval != 0) { 457962306a36Sopenharmony_ci ha->seconds_since_last_heartbeat++; 458062306a36Sopenharmony_ci if (ha->seconds_since_last_heartbeat > 458162306a36Sopenharmony_ci ha->heartbeat_interval + 2) 458262306a36Sopenharmony_ci set_bit(DPC_RESET_HA, &ha->dpc_flags); 458362306a36Sopenharmony_ci } 458462306a36Sopenharmony_ci } 458562306a36Sopenharmony_ci 458662306a36Sopenharmony_ci /* Process any deferred work. */ 458762306a36Sopenharmony_ci if (!list_empty(&ha->work_list)) 458862306a36Sopenharmony_ci start_dpc++; 458962306a36Sopenharmony_ci 459062306a36Sopenharmony_ci /* Wakeup the dpc routine for this adapter, if needed. */ 459162306a36Sopenharmony_ci if (start_dpc || 459262306a36Sopenharmony_ci test_bit(DPC_RESET_HA, &ha->dpc_flags) || 459362306a36Sopenharmony_ci test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags) || 459462306a36Sopenharmony_ci test_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags) || 459562306a36Sopenharmony_ci test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags) || 459662306a36Sopenharmony_ci test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) || 459762306a36Sopenharmony_ci test_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags) || 459862306a36Sopenharmony_ci test_bit(DPC_LINK_CHANGED, &ha->dpc_flags) || 459962306a36Sopenharmony_ci test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags) || 460062306a36Sopenharmony_ci test_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags) || 460162306a36Sopenharmony_ci test_bit(DPC_SYSFS_DDB_EXPORT, &ha->dpc_flags) || 460262306a36Sopenharmony_ci test_bit(DPC_AEN, &ha->dpc_flags)) { 460362306a36Sopenharmony_ci DEBUG2(printk("scsi%ld: %s: scheduling dpc routine" 460462306a36Sopenharmony_ci " - dpc flags = 0x%lx\n", 460562306a36Sopenharmony_ci ha->host_no, __func__, ha->dpc_flags)); 460662306a36Sopenharmony_ci qla4xxx_wake_dpc(ha); 460762306a36Sopenharmony_ci } 460862306a36Sopenharmony_ci 460962306a36Sopenharmony_ci /* Reschedule timer thread to call us back in one second */ 461062306a36Sopenharmony_ci mod_timer(&ha->timer, jiffies + HZ); 461162306a36Sopenharmony_ci 461262306a36Sopenharmony_ci DEBUG2(ha->seconds_since_last_intr++); 461362306a36Sopenharmony_ci} 461462306a36Sopenharmony_ci 461562306a36Sopenharmony_ci/** 461662306a36Sopenharmony_ci * qla4xxx_cmd_wait - waits for all outstanding commands to complete 461762306a36Sopenharmony_ci * @ha: Pointer to host adapter structure. 461862306a36Sopenharmony_ci * 461962306a36Sopenharmony_ci * This routine stalls the driver until all outstanding commands are returned. 462062306a36Sopenharmony_ci * Caller must release the Hardware Lock prior to calling this routine. 462162306a36Sopenharmony_ci **/ 462262306a36Sopenharmony_cistatic int qla4xxx_cmd_wait(struct scsi_qla_host *ha) 462362306a36Sopenharmony_ci{ 462462306a36Sopenharmony_ci uint32_t index = 0; 462562306a36Sopenharmony_ci unsigned long flags; 462662306a36Sopenharmony_ci struct scsi_cmnd *cmd; 462762306a36Sopenharmony_ci unsigned long wtime; 462862306a36Sopenharmony_ci uint32_t wtmo; 462962306a36Sopenharmony_ci 463062306a36Sopenharmony_ci if (is_qla40XX(ha)) 463162306a36Sopenharmony_ci wtmo = WAIT_CMD_TOV; 463262306a36Sopenharmony_ci else 463362306a36Sopenharmony_ci wtmo = ha->nx_reset_timeout / 2; 463462306a36Sopenharmony_ci 463562306a36Sopenharmony_ci wtime = jiffies + (wtmo * HZ); 463662306a36Sopenharmony_ci 463762306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 463862306a36Sopenharmony_ci "Wait up to %u seconds for cmds to complete\n", 463962306a36Sopenharmony_ci wtmo)); 464062306a36Sopenharmony_ci 464162306a36Sopenharmony_ci while (!time_after_eq(jiffies, wtime)) { 464262306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 464362306a36Sopenharmony_ci /* Find a command that hasn't completed. */ 464462306a36Sopenharmony_ci for (index = 0; index < ha->host->can_queue; index++) { 464562306a36Sopenharmony_ci cmd = scsi_host_find_tag(ha->host, index); 464662306a36Sopenharmony_ci /* 464762306a36Sopenharmony_ci * We cannot just check if the index is valid, 464862306a36Sopenharmony_ci * becase if we are run from the scsi eh, then 464962306a36Sopenharmony_ci * the scsi/block layer is going to prevent 465062306a36Sopenharmony_ci * the tag from being released. 465162306a36Sopenharmony_ci */ 465262306a36Sopenharmony_ci if (cmd != NULL && qla4xxx_cmd_priv(cmd)->srb) 465362306a36Sopenharmony_ci break; 465462306a36Sopenharmony_ci } 465562306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 465662306a36Sopenharmony_ci 465762306a36Sopenharmony_ci /* If No Commands are pending, wait is complete */ 465862306a36Sopenharmony_ci if (index == ha->host->can_queue) 465962306a36Sopenharmony_ci return QLA_SUCCESS; 466062306a36Sopenharmony_ci 466162306a36Sopenharmony_ci msleep(1000); 466262306a36Sopenharmony_ci } 466362306a36Sopenharmony_ci /* If we timed out on waiting for commands to come back 466462306a36Sopenharmony_ci * return ERROR. */ 466562306a36Sopenharmony_ci return QLA_ERROR; 466662306a36Sopenharmony_ci} 466762306a36Sopenharmony_ci 466862306a36Sopenharmony_ciint qla4xxx_hw_reset(struct scsi_qla_host *ha) 466962306a36Sopenharmony_ci{ 467062306a36Sopenharmony_ci uint32_t ctrl_status; 467162306a36Sopenharmony_ci unsigned long flags = 0; 467262306a36Sopenharmony_ci 467362306a36Sopenharmony_ci DEBUG2(printk(KERN_ERR "scsi%ld: %s\n", ha->host_no, __func__)); 467462306a36Sopenharmony_ci 467562306a36Sopenharmony_ci if (ql4xxx_lock_drvr_wait(ha) != QLA_SUCCESS) 467662306a36Sopenharmony_ci return QLA_ERROR; 467762306a36Sopenharmony_ci 467862306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 467962306a36Sopenharmony_ci 468062306a36Sopenharmony_ci /* 468162306a36Sopenharmony_ci * If the SCSI Reset Interrupt bit is set, clear it. 468262306a36Sopenharmony_ci * Otherwise, the Soft Reset won't work. 468362306a36Sopenharmony_ci */ 468462306a36Sopenharmony_ci ctrl_status = readw(&ha->reg->ctrl_status); 468562306a36Sopenharmony_ci if ((ctrl_status & CSR_SCSI_RESET_INTR) != 0) 468662306a36Sopenharmony_ci writel(set_rmask(CSR_SCSI_RESET_INTR), &ha->reg->ctrl_status); 468762306a36Sopenharmony_ci 468862306a36Sopenharmony_ci /* Issue Soft Reset */ 468962306a36Sopenharmony_ci writel(set_rmask(CSR_SOFT_RESET), &ha->reg->ctrl_status); 469062306a36Sopenharmony_ci readl(&ha->reg->ctrl_status); 469162306a36Sopenharmony_ci 469262306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 469362306a36Sopenharmony_ci return QLA_SUCCESS; 469462306a36Sopenharmony_ci} 469562306a36Sopenharmony_ci 469662306a36Sopenharmony_ci/** 469762306a36Sopenharmony_ci * qla4xxx_soft_reset - performs soft reset. 469862306a36Sopenharmony_ci * @ha: Pointer to host adapter structure. 469962306a36Sopenharmony_ci **/ 470062306a36Sopenharmony_ciint qla4xxx_soft_reset(struct scsi_qla_host *ha) 470162306a36Sopenharmony_ci{ 470262306a36Sopenharmony_ci uint32_t max_wait_time; 470362306a36Sopenharmony_ci unsigned long flags = 0; 470462306a36Sopenharmony_ci int status; 470562306a36Sopenharmony_ci uint32_t ctrl_status; 470662306a36Sopenharmony_ci 470762306a36Sopenharmony_ci status = qla4xxx_hw_reset(ha); 470862306a36Sopenharmony_ci if (status != QLA_SUCCESS) 470962306a36Sopenharmony_ci return status; 471062306a36Sopenharmony_ci 471162306a36Sopenharmony_ci status = QLA_ERROR; 471262306a36Sopenharmony_ci /* Wait until the Network Reset Intr bit is cleared */ 471362306a36Sopenharmony_ci max_wait_time = RESET_INTR_TOV; 471462306a36Sopenharmony_ci do { 471562306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 471662306a36Sopenharmony_ci ctrl_status = readw(&ha->reg->ctrl_status); 471762306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 471862306a36Sopenharmony_ci 471962306a36Sopenharmony_ci if ((ctrl_status & CSR_NET_RESET_INTR) == 0) 472062306a36Sopenharmony_ci break; 472162306a36Sopenharmony_ci 472262306a36Sopenharmony_ci msleep(1000); 472362306a36Sopenharmony_ci } while ((--max_wait_time)); 472462306a36Sopenharmony_ci 472562306a36Sopenharmony_ci if ((ctrl_status & CSR_NET_RESET_INTR) != 0) { 472662306a36Sopenharmony_ci DEBUG2(printk(KERN_WARNING 472762306a36Sopenharmony_ci "scsi%ld: Network Reset Intr not cleared by " 472862306a36Sopenharmony_ci "Network function, clearing it now!\n", 472962306a36Sopenharmony_ci ha->host_no)); 473062306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 473162306a36Sopenharmony_ci writel(set_rmask(CSR_NET_RESET_INTR), &ha->reg->ctrl_status); 473262306a36Sopenharmony_ci readl(&ha->reg->ctrl_status); 473362306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 473462306a36Sopenharmony_ci } 473562306a36Sopenharmony_ci 473662306a36Sopenharmony_ci /* Wait until the firmware tells us the Soft Reset is done */ 473762306a36Sopenharmony_ci max_wait_time = SOFT_RESET_TOV; 473862306a36Sopenharmony_ci do { 473962306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 474062306a36Sopenharmony_ci ctrl_status = readw(&ha->reg->ctrl_status); 474162306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 474262306a36Sopenharmony_ci 474362306a36Sopenharmony_ci if ((ctrl_status & CSR_SOFT_RESET) == 0) { 474462306a36Sopenharmony_ci status = QLA_SUCCESS; 474562306a36Sopenharmony_ci break; 474662306a36Sopenharmony_ci } 474762306a36Sopenharmony_ci 474862306a36Sopenharmony_ci msleep(1000); 474962306a36Sopenharmony_ci } while ((--max_wait_time)); 475062306a36Sopenharmony_ci 475162306a36Sopenharmony_ci /* 475262306a36Sopenharmony_ci * Also, make sure that the SCSI Reset Interrupt bit has been cleared 475362306a36Sopenharmony_ci * after the soft reset has taken place. 475462306a36Sopenharmony_ci */ 475562306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 475662306a36Sopenharmony_ci ctrl_status = readw(&ha->reg->ctrl_status); 475762306a36Sopenharmony_ci if ((ctrl_status & CSR_SCSI_RESET_INTR) != 0) { 475862306a36Sopenharmony_ci writel(set_rmask(CSR_SCSI_RESET_INTR), &ha->reg->ctrl_status); 475962306a36Sopenharmony_ci readl(&ha->reg->ctrl_status); 476062306a36Sopenharmony_ci } 476162306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 476262306a36Sopenharmony_ci 476362306a36Sopenharmony_ci /* If soft reset fails then most probably the bios on other 476462306a36Sopenharmony_ci * function is also enabled. 476562306a36Sopenharmony_ci * Since the initialization is sequential the other fn 476662306a36Sopenharmony_ci * wont be able to acknowledge the soft reset. 476762306a36Sopenharmony_ci * Issue a force soft reset to workaround this scenario. 476862306a36Sopenharmony_ci */ 476962306a36Sopenharmony_ci if (max_wait_time == 0) { 477062306a36Sopenharmony_ci /* Issue Force Soft Reset */ 477162306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 477262306a36Sopenharmony_ci writel(set_rmask(CSR_FORCE_SOFT_RESET), &ha->reg->ctrl_status); 477362306a36Sopenharmony_ci readl(&ha->reg->ctrl_status); 477462306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 477562306a36Sopenharmony_ci /* Wait until the firmware tells us the Soft Reset is done */ 477662306a36Sopenharmony_ci max_wait_time = SOFT_RESET_TOV; 477762306a36Sopenharmony_ci do { 477862306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 477962306a36Sopenharmony_ci ctrl_status = readw(&ha->reg->ctrl_status); 478062306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 478162306a36Sopenharmony_ci 478262306a36Sopenharmony_ci if ((ctrl_status & CSR_FORCE_SOFT_RESET) == 0) { 478362306a36Sopenharmony_ci status = QLA_SUCCESS; 478462306a36Sopenharmony_ci break; 478562306a36Sopenharmony_ci } 478662306a36Sopenharmony_ci 478762306a36Sopenharmony_ci msleep(1000); 478862306a36Sopenharmony_ci } while ((--max_wait_time)); 478962306a36Sopenharmony_ci } 479062306a36Sopenharmony_ci 479162306a36Sopenharmony_ci return status; 479262306a36Sopenharmony_ci} 479362306a36Sopenharmony_ci 479462306a36Sopenharmony_ci/** 479562306a36Sopenharmony_ci * qla4xxx_abort_active_cmds - returns all outstanding i/o requests to O.S. 479662306a36Sopenharmony_ci * @ha: Pointer to host adapter structure. 479762306a36Sopenharmony_ci * @res: returned scsi status 479862306a36Sopenharmony_ci * 479962306a36Sopenharmony_ci * This routine is called just prior to a HARD RESET to return all 480062306a36Sopenharmony_ci * outstanding commands back to the Operating System. 480162306a36Sopenharmony_ci * Caller should make sure that the following locks are released 480262306a36Sopenharmony_ci * before this calling routine: Hardware lock, and io_request_lock. 480362306a36Sopenharmony_ci **/ 480462306a36Sopenharmony_cistatic void qla4xxx_abort_active_cmds(struct scsi_qla_host *ha, int res) 480562306a36Sopenharmony_ci{ 480662306a36Sopenharmony_ci struct srb *srb; 480762306a36Sopenharmony_ci int i; 480862306a36Sopenharmony_ci unsigned long flags; 480962306a36Sopenharmony_ci 481062306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 481162306a36Sopenharmony_ci for (i = 0; i < ha->host->can_queue; i++) { 481262306a36Sopenharmony_ci srb = qla4xxx_del_from_active_array(ha, i); 481362306a36Sopenharmony_ci if (srb != NULL) { 481462306a36Sopenharmony_ci srb->cmd->result = res; 481562306a36Sopenharmony_ci kref_put(&srb->srb_ref, qla4xxx_srb_compl); 481662306a36Sopenharmony_ci } 481762306a36Sopenharmony_ci } 481862306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 481962306a36Sopenharmony_ci} 482062306a36Sopenharmony_ci 482162306a36Sopenharmony_civoid qla4xxx_dead_adapter_cleanup(struct scsi_qla_host *ha) 482262306a36Sopenharmony_ci{ 482362306a36Sopenharmony_ci clear_bit(AF_ONLINE, &ha->flags); 482462306a36Sopenharmony_ci 482562306a36Sopenharmony_ci /* Disable the board */ 482662306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "Disabling the board\n"); 482762306a36Sopenharmony_ci 482862306a36Sopenharmony_ci qla4xxx_abort_active_cmds(ha, DID_NO_CONNECT << 16); 482962306a36Sopenharmony_ci qla4xxx_mark_all_devices_missing(ha); 483062306a36Sopenharmony_ci clear_bit(AF_INIT_DONE, &ha->flags); 483162306a36Sopenharmony_ci} 483262306a36Sopenharmony_ci 483362306a36Sopenharmony_cistatic void qla4xxx_fail_session(struct iscsi_cls_session *cls_session) 483462306a36Sopenharmony_ci{ 483562306a36Sopenharmony_ci struct iscsi_session *sess; 483662306a36Sopenharmony_ci struct ddb_entry *ddb_entry; 483762306a36Sopenharmony_ci 483862306a36Sopenharmony_ci sess = cls_session->dd_data; 483962306a36Sopenharmony_ci ddb_entry = sess->dd_data; 484062306a36Sopenharmony_ci ddb_entry->fw_ddb_device_state = DDB_DS_SESSION_FAILED; 484162306a36Sopenharmony_ci 484262306a36Sopenharmony_ci if (ddb_entry->ddb_type == FLASH_DDB) 484362306a36Sopenharmony_ci iscsi_block_session(ddb_entry->sess); 484462306a36Sopenharmony_ci else 484562306a36Sopenharmony_ci iscsi_session_failure(cls_session->dd_data, 484662306a36Sopenharmony_ci ISCSI_ERR_CONN_FAILED); 484762306a36Sopenharmony_ci} 484862306a36Sopenharmony_ci 484962306a36Sopenharmony_ci/** 485062306a36Sopenharmony_ci * qla4xxx_recover_adapter - recovers adapter after a fatal error 485162306a36Sopenharmony_ci * @ha: Pointer to host adapter structure. 485262306a36Sopenharmony_ci **/ 485362306a36Sopenharmony_cistatic int qla4xxx_recover_adapter(struct scsi_qla_host *ha) 485462306a36Sopenharmony_ci{ 485562306a36Sopenharmony_ci int status = QLA_ERROR; 485662306a36Sopenharmony_ci uint8_t reset_chip = 0; 485762306a36Sopenharmony_ci uint32_t dev_state; 485862306a36Sopenharmony_ci unsigned long wait; 485962306a36Sopenharmony_ci 486062306a36Sopenharmony_ci /* Stall incoming I/O until we are done */ 486162306a36Sopenharmony_ci scsi_block_requests(ha->host); 486262306a36Sopenharmony_ci clear_bit(AF_ONLINE, &ha->flags); 486362306a36Sopenharmony_ci clear_bit(AF_LINK_UP, &ha->flags); 486462306a36Sopenharmony_ci 486562306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "%s: adapter OFFLINE\n", __func__)); 486662306a36Sopenharmony_ci 486762306a36Sopenharmony_ci set_bit(DPC_RESET_ACTIVE, &ha->dpc_flags); 486862306a36Sopenharmony_ci 486962306a36Sopenharmony_ci if ((is_qla8032(ha) || is_qla8042(ha)) && 487062306a36Sopenharmony_ci !test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags)) { 487162306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "%s: disabling pause transmit on port 0 & 1.\n", 487262306a36Sopenharmony_ci __func__); 487362306a36Sopenharmony_ci /* disable pause frame for ISP83xx */ 487462306a36Sopenharmony_ci qla4_83xx_disable_pause(ha); 487562306a36Sopenharmony_ci } 487662306a36Sopenharmony_ci 487762306a36Sopenharmony_ci iscsi_host_for_each_session(ha->host, qla4xxx_fail_session); 487862306a36Sopenharmony_ci 487962306a36Sopenharmony_ci if (test_bit(DPC_RESET_HA, &ha->dpc_flags)) 488062306a36Sopenharmony_ci reset_chip = 1; 488162306a36Sopenharmony_ci 488262306a36Sopenharmony_ci /* For the DPC_RESET_HA_INTR case (ISP-4xxx specific) 488362306a36Sopenharmony_ci * do not reset adapter, jump to initialize_adapter */ 488462306a36Sopenharmony_ci if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) { 488562306a36Sopenharmony_ci status = QLA_SUCCESS; 488662306a36Sopenharmony_ci goto recover_ha_init_adapter; 488762306a36Sopenharmony_ci } 488862306a36Sopenharmony_ci 488962306a36Sopenharmony_ci /* For the ISP-8xxx adapter, issue a stop_firmware if invoked 489062306a36Sopenharmony_ci * from eh_host_reset or ioctl module */ 489162306a36Sopenharmony_ci if (is_qla80XX(ha) && !reset_chip && 489262306a36Sopenharmony_ci test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags)) { 489362306a36Sopenharmony_ci 489462306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 489562306a36Sopenharmony_ci "scsi%ld: %s - Performing stop_firmware...\n", 489662306a36Sopenharmony_ci ha->host_no, __func__)); 489762306a36Sopenharmony_ci status = ha->isp_ops->reset_firmware(ha); 489862306a36Sopenharmony_ci if (status == QLA_SUCCESS) { 489962306a36Sopenharmony_ci ha->isp_ops->disable_intrs(ha); 490062306a36Sopenharmony_ci qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); 490162306a36Sopenharmony_ci qla4xxx_abort_active_cmds(ha, DID_RESET << 16); 490262306a36Sopenharmony_ci } else { 490362306a36Sopenharmony_ci /* If the stop_firmware fails then 490462306a36Sopenharmony_ci * reset the entire chip */ 490562306a36Sopenharmony_ci reset_chip = 1; 490662306a36Sopenharmony_ci clear_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags); 490762306a36Sopenharmony_ci set_bit(DPC_RESET_HA, &ha->dpc_flags); 490862306a36Sopenharmony_ci } 490962306a36Sopenharmony_ci } 491062306a36Sopenharmony_ci 491162306a36Sopenharmony_ci /* Issue full chip reset if recovering from a catastrophic error, 491262306a36Sopenharmony_ci * or if stop_firmware fails for ISP-8xxx. 491362306a36Sopenharmony_ci * This is the default case for ISP-4xxx */ 491462306a36Sopenharmony_ci if (is_qla40XX(ha) || reset_chip) { 491562306a36Sopenharmony_ci if (is_qla40XX(ha)) 491662306a36Sopenharmony_ci goto chip_reset; 491762306a36Sopenharmony_ci 491862306a36Sopenharmony_ci /* Check if 8XXX firmware is alive or not 491962306a36Sopenharmony_ci * We may have arrived here from NEED_RESET 492062306a36Sopenharmony_ci * detection only */ 492162306a36Sopenharmony_ci if (test_bit(AF_FW_RECOVERY, &ha->flags)) 492262306a36Sopenharmony_ci goto chip_reset; 492362306a36Sopenharmony_ci 492462306a36Sopenharmony_ci wait = jiffies + (FW_ALIVE_WAIT_TOV * HZ); 492562306a36Sopenharmony_ci while (time_before(jiffies, wait)) { 492662306a36Sopenharmony_ci if (qla4_8xxx_check_fw_alive(ha)) { 492762306a36Sopenharmony_ci qla4xxx_mailbox_premature_completion(ha); 492862306a36Sopenharmony_ci break; 492962306a36Sopenharmony_ci } 493062306a36Sopenharmony_ci 493162306a36Sopenharmony_ci set_current_state(TASK_UNINTERRUPTIBLE); 493262306a36Sopenharmony_ci schedule_timeout(HZ); 493362306a36Sopenharmony_ci } 493462306a36Sopenharmony_cichip_reset: 493562306a36Sopenharmony_ci if (!test_bit(AF_FW_RECOVERY, &ha->flags)) 493662306a36Sopenharmony_ci qla4xxx_cmd_wait(ha); 493762306a36Sopenharmony_ci 493862306a36Sopenharmony_ci qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); 493962306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 494062306a36Sopenharmony_ci "scsi%ld: %s - Performing chip reset..\n", 494162306a36Sopenharmony_ci ha->host_no, __func__)); 494262306a36Sopenharmony_ci status = ha->isp_ops->reset_chip(ha); 494362306a36Sopenharmony_ci qla4xxx_abort_active_cmds(ha, DID_RESET << 16); 494462306a36Sopenharmony_ci } 494562306a36Sopenharmony_ci 494662306a36Sopenharmony_ci /* Flush any pending ddb changed AENs */ 494762306a36Sopenharmony_ci qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); 494862306a36Sopenharmony_ci 494962306a36Sopenharmony_cirecover_ha_init_adapter: 495062306a36Sopenharmony_ci /* Upon successful firmware/chip reset, re-initialize the adapter */ 495162306a36Sopenharmony_ci if (status == QLA_SUCCESS) { 495262306a36Sopenharmony_ci /* For ISP-4xxx, force function 1 to always initialize 495362306a36Sopenharmony_ci * before function 3 to prevent both funcions from 495462306a36Sopenharmony_ci * stepping on top of the other */ 495562306a36Sopenharmony_ci if (is_qla40XX(ha) && (ha->mac_index == 3)) 495662306a36Sopenharmony_ci ssleep(6); 495762306a36Sopenharmony_ci 495862306a36Sopenharmony_ci /* NOTE: AF_ONLINE flag set upon successful completion of 495962306a36Sopenharmony_ci * qla4xxx_initialize_adapter */ 496062306a36Sopenharmony_ci status = qla4xxx_initialize_adapter(ha, RESET_ADAPTER); 496162306a36Sopenharmony_ci if (is_qla80XX(ha) && (status == QLA_ERROR)) { 496262306a36Sopenharmony_ci status = qla4_8xxx_check_init_adapter_retry(ha); 496362306a36Sopenharmony_ci if (status == QLA_ERROR) { 496462306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "scsi%ld: %s: Don't retry recover adapter\n", 496562306a36Sopenharmony_ci ha->host_no, __func__); 496662306a36Sopenharmony_ci qla4xxx_dead_adapter_cleanup(ha); 496762306a36Sopenharmony_ci clear_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags); 496862306a36Sopenharmony_ci clear_bit(DPC_RESET_HA, &ha->dpc_flags); 496962306a36Sopenharmony_ci clear_bit(DPC_RESET_HA_FW_CONTEXT, 497062306a36Sopenharmony_ci &ha->dpc_flags); 497162306a36Sopenharmony_ci goto exit_recover; 497262306a36Sopenharmony_ci } 497362306a36Sopenharmony_ci } 497462306a36Sopenharmony_ci } 497562306a36Sopenharmony_ci 497662306a36Sopenharmony_ci /* Retry failed adapter initialization, if necessary 497762306a36Sopenharmony_ci * Do not retry initialize_adapter for RESET_HA_INTR (ISP-4xxx specific) 497862306a36Sopenharmony_ci * case to prevent ping-pong resets between functions */ 497962306a36Sopenharmony_ci if (!test_bit(AF_ONLINE, &ha->flags) && 498062306a36Sopenharmony_ci !test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) { 498162306a36Sopenharmony_ci /* Adapter initialization failed, see if we can retry 498262306a36Sopenharmony_ci * resetting the ha. 498362306a36Sopenharmony_ci * Since we don't want to block the DPC for too long 498462306a36Sopenharmony_ci * with multiple resets in the same thread, 498562306a36Sopenharmony_ci * utilize DPC to retry */ 498662306a36Sopenharmony_ci if (is_qla80XX(ha)) { 498762306a36Sopenharmony_ci ha->isp_ops->idc_lock(ha); 498862306a36Sopenharmony_ci dev_state = qla4_8xxx_rd_direct(ha, 498962306a36Sopenharmony_ci QLA8XXX_CRB_DEV_STATE); 499062306a36Sopenharmony_ci ha->isp_ops->idc_unlock(ha); 499162306a36Sopenharmony_ci if (dev_state == QLA8XXX_DEV_FAILED) { 499262306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "%s: don't retry " 499362306a36Sopenharmony_ci "recover adapter. H/W is in Failed " 499462306a36Sopenharmony_ci "state\n", __func__); 499562306a36Sopenharmony_ci qla4xxx_dead_adapter_cleanup(ha); 499662306a36Sopenharmony_ci clear_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags); 499762306a36Sopenharmony_ci clear_bit(DPC_RESET_HA, &ha->dpc_flags); 499862306a36Sopenharmony_ci clear_bit(DPC_RESET_HA_FW_CONTEXT, 499962306a36Sopenharmony_ci &ha->dpc_flags); 500062306a36Sopenharmony_ci status = QLA_ERROR; 500162306a36Sopenharmony_ci 500262306a36Sopenharmony_ci goto exit_recover; 500362306a36Sopenharmony_ci } 500462306a36Sopenharmony_ci } 500562306a36Sopenharmony_ci 500662306a36Sopenharmony_ci if (!test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags)) { 500762306a36Sopenharmony_ci ha->retry_reset_ha_cnt = MAX_RESET_HA_RETRIES; 500862306a36Sopenharmony_ci DEBUG2(printk("scsi%ld: recover adapter - retrying " 500962306a36Sopenharmony_ci "(%d) more times\n", ha->host_no, 501062306a36Sopenharmony_ci ha->retry_reset_ha_cnt)); 501162306a36Sopenharmony_ci set_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags); 501262306a36Sopenharmony_ci status = QLA_ERROR; 501362306a36Sopenharmony_ci } else { 501462306a36Sopenharmony_ci if (ha->retry_reset_ha_cnt > 0) { 501562306a36Sopenharmony_ci /* Schedule another Reset HA--DPC will retry */ 501662306a36Sopenharmony_ci ha->retry_reset_ha_cnt--; 501762306a36Sopenharmony_ci DEBUG2(printk("scsi%ld: recover adapter - " 501862306a36Sopenharmony_ci "retry remaining %d\n", 501962306a36Sopenharmony_ci ha->host_no, 502062306a36Sopenharmony_ci ha->retry_reset_ha_cnt)); 502162306a36Sopenharmony_ci status = QLA_ERROR; 502262306a36Sopenharmony_ci } 502362306a36Sopenharmony_ci 502462306a36Sopenharmony_ci if (ha->retry_reset_ha_cnt == 0) { 502562306a36Sopenharmony_ci /* Recover adapter retries have been exhausted. 502662306a36Sopenharmony_ci * Adapter DEAD */ 502762306a36Sopenharmony_ci DEBUG2(printk("scsi%ld: recover adapter " 502862306a36Sopenharmony_ci "failed - board disabled\n", 502962306a36Sopenharmony_ci ha->host_no)); 503062306a36Sopenharmony_ci qla4xxx_dead_adapter_cleanup(ha); 503162306a36Sopenharmony_ci clear_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags); 503262306a36Sopenharmony_ci clear_bit(DPC_RESET_HA, &ha->dpc_flags); 503362306a36Sopenharmony_ci clear_bit(DPC_RESET_HA_FW_CONTEXT, 503462306a36Sopenharmony_ci &ha->dpc_flags); 503562306a36Sopenharmony_ci status = QLA_ERROR; 503662306a36Sopenharmony_ci } 503762306a36Sopenharmony_ci } 503862306a36Sopenharmony_ci } else { 503962306a36Sopenharmony_ci clear_bit(DPC_RESET_HA, &ha->dpc_flags); 504062306a36Sopenharmony_ci clear_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags); 504162306a36Sopenharmony_ci clear_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags); 504262306a36Sopenharmony_ci } 504362306a36Sopenharmony_ci 504462306a36Sopenharmony_ciexit_recover: 504562306a36Sopenharmony_ci ha->adapter_error_count++; 504662306a36Sopenharmony_ci 504762306a36Sopenharmony_ci if (test_bit(AF_ONLINE, &ha->flags)) 504862306a36Sopenharmony_ci ha->isp_ops->enable_intrs(ha); 504962306a36Sopenharmony_ci 505062306a36Sopenharmony_ci scsi_unblock_requests(ha->host); 505162306a36Sopenharmony_ci 505262306a36Sopenharmony_ci clear_bit(DPC_RESET_ACTIVE, &ha->dpc_flags); 505362306a36Sopenharmony_ci DEBUG2(printk("scsi%ld: recover adapter: %s\n", ha->host_no, 505462306a36Sopenharmony_ci status == QLA_ERROR ? "FAILED" : "SUCCEEDED")); 505562306a36Sopenharmony_ci 505662306a36Sopenharmony_ci return status; 505762306a36Sopenharmony_ci} 505862306a36Sopenharmony_ci 505962306a36Sopenharmony_cistatic void qla4xxx_relogin_devices(struct iscsi_cls_session *cls_session) 506062306a36Sopenharmony_ci{ 506162306a36Sopenharmony_ci struct iscsi_session *sess; 506262306a36Sopenharmony_ci struct ddb_entry *ddb_entry; 506362306a36Sopenharmony_ci struct scsi_qla_host *ha; 506462306a36Sopenharmony_ci 506562306a36Sopenharmony_ci sess = cls_session->dd_data; 506662306a36Sopenharmony_ci ddb_entry = sess->dd_data; 506762306a36Sopenharmony_ci ha = ddb_entry->ha; 506862306a36Sopenharmony_ci if (!iscsi_is_session_online(cls_session)) { 506962306a36Sopenharmony_ci if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) { 507062306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ddb[%d]" 507162306a36Sopenharmony_ci " unblock session\n", ha->host_no, __func__, 507262306a36Sopenharmony_ci ddb_entry->fw_ddb_index); 507362306a36Sopenharmony_ci iscsi_unblock_session(ddb_entry->sess); 507462306a36Sopenharmony_ci } else { 507562306a36Sopenharmony_ci /* Trigger relogin */ 507662306a36Sopenharmony_ci if (ddb_entry->ddb_type == FLASH_DDB) { 507762306a36Sopenharmony_ci if (!(test_bit(DF_RELOGIN, &ddb_entry->flags) || 507862306a36Sopenharmony_ci test_bit(DF_DISABLE_RELOGIN, 507962306a36Sopenharmony_ci &ddb_entry->flags))) 508062306a36Sopenharmony_ci qla4xxx_arm_relogin_timer(ddb_entry); 508162306a36Sopenharmony_ci } else 508262306a36Sopenharmony_ci iscsi_session_failure(cls_session->dd_data, 508362306a36Sopenharmony_ci ISCSI_ERR_CONN_FAILED); 508462306a36Sopenharmony_ci } 508562306a36Sopenharmony_ci } 508662306a36Sopenharmony_ci} 508762306a36Sopenharmony_ci 508862306a36Sopenharmony_ciint qla4xxx_unblock_flash_ddb(struct iscsi_cls_session *cls_session) 508962306a36Sopenharmony_ci{ 509062306a36Sopenharmony_ci struct iscsi_session *sess; 509162306a36Sopenharmony_ci struct ddb_entry *ddb_entry; 509262306a36Sopenharmony_ci struct scsi_qla_host *ha; 509362306a36Sopenharmony_ci 509462306a36Sopenharmony_ci sess = cls_session->dd_data; 509562306a36Sopenharmony_ci ddb_entry = sess->dd_data; 509662306a36Sopenharmony_ci ha = ddb_entry->ha; 509762306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ddb[%d]" 509862306a36Sopenharmony_ci " unblock session\n", ha->host_no, __func__, 509962306a36Sopenharmony_ci ddb_entry->fw_ddb_index); 510062306a36Sopenharmony_ci 510162306a36Sopenharmony_ci iscsi_unblock_session(ddb_entry->sess); 510262306a36Sopenharmony_ci 510362306a36Sopenharmony_ci /* Start scan target */ 510462306a36Sopenharmony_ci if (test_bit(AF_ONLINE, &ha->flags)) { 510562306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ddb[%d]" 510662306a36Sopenharmony_ci " start scan\n", ha->host_no, __func__, 510762306a36Sopenharmony_ci ddb_entry->fw_ddb_index); 510862306a36Sopenharmony_ci queue_work(ddb_entry->sess->workq, &ddb_entry->sess->scan_work); 510962306a36Sopenharmony_ci } 511062306a36Sopenharmony_ci return QLA_SUCCESS; 511162306a36Sopenharmony_ci} 511262306a36Sopenharmony_ci 511362306a36Sopenharmony_ciint qla4xxx_unblock_ddb(struct iscsi_cls_session *cls_session) 511462306a36Sopenharmony_ci{ 511562306a36Sopenharmony_ci struct iscsi_session *sess; 511662306a36Sopenharmony_ci struct ddb_entry *ddb_entry; 511762306a36Sopenharmony_ci struct scsi_qla_host *ha; 511862306a36Sopenharmony_ci int status = QLA_SUCCESS; 511962306a36Sopenharmony_ci 512062306a36Sopenharmony_ci sess = cls_session->dd_data; 512162306a36Sopenharmony_ci ddb_entry = sess->dd_data; 512262306a36Sopenharmony_ci ha = ddb_entry->ha; 512362306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ddb[%d]" 512462306a36Sopenharmony_ci " unblock user space session\n", ha->host_no, __func__, 512562306a36Sopenharmony_ci ddb_entry->fw_ddb_index); 512662306a36Sopenharmony_ci 512762306a36Sopenharmony_ci if (!iscsi_is_session_online(cls_session)) { 512862306a36Sopenharmony_ci iscsi_conn_start(ddb_entry->conn); 512962306a36Sopenharmony_ci iscsi_conn_login_event(ddb_entry->conn, 513062306a36Sopenharmony_ci ISCSI_CONN_STATE_LOGGED_IN); 513162306a36Sopenharmony_ci } else { 513262306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, 513362306a36Sopenharmony_ci "scsi%ld: %s: ddb[%d] session [%d] already logged in\n", 513462306a36Sopenharmony_ci ha->host_no, __func__, ddb_entry->fw_ddb_index, 513562306a36Sopenharmony_ci cls_session->sid); 513662306a36Sopenharmony_ci status = QLA_ERROR; 513762306a36Sopenharmony_ci } 513862306a36Sopenharmony_ci 513962306a36Sopenharmony_ci return status; 514062306a36Sopenharmony_ci} 514162306a36Sopenharmony_ci 514262306a36Sopenharmony_cistatic void qla4xxx_relogin_all_devices(struct scsi_qla_host *ha) 514362306a36Sopenharmony_ci{ 514462306a36Sopenharmony_ci iscsi_host_for_each_session(ha->host, qla4xxx_relogin_devices); 514562306a36Sopenharmony_ci} 514662306a36Sopenharmony_ci 514762306a36Sopenharmony_cistatic void qla4xxx_relogin_flash_ddb(struct iscsi_cls_session *cls_sess) 514862306a36Sopenharmony_ci{ 514962306a36Sopenharmony_ci uint16_t relogin_timer; 515062306a36Sopenharmony_ci struct iscsi_session *sess; 515162306a36Sopenharmony_ci struct ddb_entry *ddb_entry; 515262306a36Sopenharmony_ci struct scsi_qla_host *ha; 515362306a36Sopenharmony_ci 515462306a36Sopenharmony_ci sess = cls_sess->dd_data; 515562306a36Sopenharmony_ci ddb_entry = sess->dd_data; 515662306a36Sopenharmony_ci ha = ddb_entry->ha; 515762306a36Sopenharmony_ci 515862306a36Sopenharmony_ci relogin_timer = max(ddb_entry->default_relogin_timeout, 515962306a36Sopenharmony_ci (uint16_t)RELOGIN_TOV); 516062306a36Sopenharmony_ci atomic_set(&ddb_entry->relogin_timer, relogin_timer); 516162306a36Sopenharmony_ci 516262306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 516362306a36Sopenharmony_ci "scsi%ld: Relogin index [%d]. TOV=%d\n", ha->host_no, 516462306a36Sopenharmony_ci ddb_entry->fw_ddb_index, relogin_timer)); 516562306a36Sopenharmony_ci 516662306a36Sopenharmony_ci qla4xxx_login_flash_ddb(cls_sess); 516762306a36Sopenharmony_ci} 516862306a36Sopenharmony_ci 516962306a36Sopenharmony_cistatic void qla4xxx_dpc_relogin(struct iscsi_cls_session *cls_sess) 517062306a36Sopenharmony_ci{ 517162306a36Sopenharmony_ci struct iscsi_session *sess; 517262306a36Sopenharmony_ci struct ddb_entry *ddb_entry; 517362306a36Sopenharmony_ci struct scsi_qla_host *ha; 517462306a36Sopenharmony_ci 517562306a36Sopenharmony_ci sess = cls_sess->dd_data; 517662306a36Sopenharmony_ci ddb_entry = sess->dd_data; 517762306a36Sopenharmony_ci ha = ddb_entry->ha; 517862306a36Sopenharmony_ci 517962306a36Sopenharmony_ci if (!(ddb_entry->ddb_type == FLASH_DDB)) 518062306a36Sopenharmony_ci return; 518162306a36Sopenharmony_ci 518262306a36Sopenharmony_ci if (test_bit(DF_DISABLE_RELOGIN, &ddb_entry->flags)) 518362306a36Sopenharmony_ci return; 518462306a36Sopenharmony_ci 518562306a36Sopenharmony_ci if (test_and_clear_bit(DF_RELOGIN, &ddb_entry->flags) && 518662306a36Sopenharmony_ci !iscsi_is_session_online(cls_sess)) { 518762306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 518862306a36Sopenharmony_ci "relogin issued\n")); 518962306a36Sopenharmony_ci qla4xxx_relogin_flash_ddb(cls_sess); 519062306a36Sopenharmony_ci } 519162306a36Sopenharmony_ci} 519262306a36Sopenharmony_ci 519362306a36Sopenharmony_civoid qla4xxx_wake_dpc(struct scsi_qla_host *ha) 519462306a36Sopenharmony_ci{ 519562306a36Sopenharmony_ci if (ha->dpc_thread) 519662306a36Sopenharmony_ci queue_work(ha->dpc_thread, &ha->dpc_work); 519762306a36Sopenharmony_ci} 519862306a36Sopenharmony_ci 519962306a36Sopenharmony_cistatic struct qla4_work_evt * 520062306a36Sopenharmony_ciqla4xxx_alloc_work(struct scsi_qla_host *ha, uint32_t data_size, 520162306a36Sopenharmony_ci enum qla4_work_type type) 520262306a36Sopenharmony_ci{ 520362306a36Sopenharmony_ci struct qla4_work_evt *e; 520462306a36Sopenharmony_ci uint32_t size = sizeof(struct qla4_work_evt) + data_size; 520562306a36Sopenharmony_ci 520662306a36Sopenharmony_ci e = kzalloc(size, GFP_ATOMIC); 520762306a36Sopenharmony_ci if (!e) 520862306a36Sopenharmony_ci return NULL; 520962306a36Sopenharmony_ci 521062306a36Sopenharmony_ci INIT_LIST_HEAD(&e->list); 521162306a36Sopenharmony_ci e->type = type; 521262306a36Sopenharmony_ci return e; 521362306a36Sopenharmony_ci} 521462306a36Sopenharmony_ci 521562306a36Sopenharmony_cistatic void qla4xxx_post_work(struct scsi_qla_host *ha, 521662306a36Sopenharmony_ci struct qla4_work_evt *e) 521762306a36Sopenharmony_ci{ 521862306a36Sopenharmony_ci unsigned long flags; 521962306a36Sopenharmony_ci 522062306a36Sopenharmony_ci spin_lock_irqsave(&ha->work_lock, flags); 522162306a36Sopenharmony_ci list_add_tail(&e->list, &ha->work_list); 522262306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->work_lock, flags); 522362306a36Sopenharmony_ci qla4xxx_wake_dpc(ha); 522462306a36Sopenharmony_ci} 522562306a36Sopenharmony_ci 522662306a36Sopenharmony_ciint qla4xxx_post_aen_work(struct scsi_qla_host *ha, 522762306a36Sopenharmony_ci enum iscsi_host_event_code aen_code, 522862306a36Sopenharmony_ci uint32_t data_size, uint8_t *data) 522962306a36Sopenharmony_ci{ 523062306a36Sopenharmony_ci struct qla4_work_evt *e; 523162306a36Sopenharmony_ci 523262306a36Sopenharmony_ci e = qla4xxx_alloc_work(ha, data_size, QLA4_EVENT_AEN); 523362306a36Sopenharmony_ci if (!e) 523462306a36Sopenharmony_ci return QLA_ERROR; 523562306a36Sopenharmony_ci 523662306a36Sopenharmony_ci e->u.aen.code = aen_code; 523762306a36Sopenharmony_ci e->u.aen.data_size = data_size; 523862306a36Sopenharmony_ci memcpy(e->u.aen.data, data, data_size); 523962306a36Sopenharmony_ci 524062306a36Sopenharmony_ci qla4xxx_post_work(ha, e); 524162306a36Sopenharmony_ci 524262306a36Sopenharmony_ci return QLA_SUCCESS; 524362306a36Sopenharmony_ci} 524462306a36Sopenharmony_ci 524562306a36Sopenharmony_ciint qla4xxx_post_ping_evt_work(struct scsi_qla_host *ha, 524662306a36Sopenharmony_ci uint32_t status, uint32_t pid, 524762306a36Sopenharmony_ci uint32_t data_size, uint8_t *data) 524862306a36Sopenharmony_ci{ 524962306a36Sopenharmony_ci struct qla4_work_evt *e; 525062306a36Sopenharmony_ci 525162306a36Sopenharmony_ci e = qla4xxx_alloc_work(ha, data_size, QLA4_EVENT_PING_STATUS); 525262306a36Sopenharmony_ci if (!e) 525362306a36Sopenharmony_ci return QLA_ERROR; 525462306a36Sopenharmony_ci 525562306a36Sopenharmony_ci e->u.ping.status = status; 525662306a36Sopenharmony_ci e->u.ping.pid = pid; 525762306a36Sopenharmony_ci e->u.ping.data_size = data_size; 525862306a36Sopenharmony_ci memcpy(e->u.ping.data, data, data_size); 525962306a36Sopenharmony_ci 526062306a36Sopenharmony_ci qla4xxx_post_work(ha, e); 526162306a36Sopenharmony_ci 526262306a36Sopenharmony_ci return QLA_SUCCESS; 526362306a36Sopenharmony_ci} 526462306a36Sopenharmony_ci 526562306a36Sopenharmony_cistatic void qla4xxx_do_work(struct scsi_qla_host *ha) 526662306a36Sopenharmony_ci{ 526762306a36Sopenharmony_ci struct qla4_work_evt *e, *tmp; 526862306a36Sopenharmony_ci unsigned long flags; 526962306a36Sopenharmony_ci LIST_HEAD(work); 527062306a36Sopenharmony_ci 527162306a36Sopenharmony_ci spin_lock_irqsave(&ha->work_lock, flags); 527262306a36Sopenharmony_ci list_splice_init(&ha->work_list, &work); 527362306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->work_lock, flags); 527462306a36Sopenharmony_ci 527562306a36Sopenharmony_ci list_for_each_entry_safe(e, tmp, &work, list) { 527662306a36Sopenharmony_ci list_del_init(&e->list); 527762306a36Sopenharmony_ci 527862306a36Sopenharmony_ci switch (e->type) { 527962306a36Sopenharmony_ci case QLA4_EVENT_AEN: 528062306a36Sopenharmony_ci iscsi_post_host_event(ha->host_no, 528162306a36Sopenharmony_ci &qla4xxx_iscsi_transport, 528262306a36Sopenharmony_ci e->u.aen.code, 528362306a36Sopenharmony_ci e->u.aen.data_size, 528462306a36Sopenharmony_ci e->u.aen.data); 528562306a36Sopenharmony_ci break; 528662306a36Sopenharmony_ci case QLA4_EVENT_PING_STATUS: 528762306a36Sopenharmony_ci iscsi_ping_comp_event(ha->host_no, 528862306a36Sopenharmony_ci &qla4xxx_iscsi_transport, 528962306a36Sopenharmony_ci e->u.ping.status, 529062306a36Sopenharmony_ci e->u.ping.pid, 529162306a36Sopenharmony_ci e->u.ping.data_size, 529262306a36Sopenharmony_ci e->u.ping.data); 529362306a36Sopenharmony_ci break; 529462306a36Sopenharmony_ci default: 529562306a36Sopenharmony_ci ql4_printk(KERN_WARNING, ha, "event type: 0x%x not " 529662306a36Sopenharmony_ci "supported", e->type); 529762306a36Sopenharmony_ci } 529862306a36Sopenharmony_ci kfree(e); 529962306a36Sopenharmony_ci } 530062306a36Sopenharmony_ci} 530162306a36Sopenharmony_ci 530262306a36Sopenharmony_ci/** 530362306a36Sopenharmony_ci * qla4xxx_do_dpc - dpc routine 530462306a36Sopenharmony_ci * @work: Context to obtain pointer to host adapter structure. 530562306a36Sopenharmony_ci * 530662306a36Sopenharmony_ci * This routine is a task that is schedule by the interrupt handler 530762306a36Sopenharmony_ci * to perform the background processing for interrupts. We put it 530862306a36Sopenharmony_ci * on a task queue that is consumed whenever the scheduler runs; that's 530962306a36Sopenharmony_ci * so you can do anything (i.e. put the process to sleep etc). In fact, 531062306a36Sopenharmony_ci * the mid-level tries to sleep when it reaches the driver threshold 531162306a36Sopenharmony_ci * "host->can_queue". This can cause a panic if we were in our interrupt code. 531262306a36Sopenharmony_ci **/ 531362306a36Sopenharmony_cistatic void qla4xxx_do_dpc(struct work_struct *work) 531462306a36Sopenharmony_ci{ 531562306a36Sopenharmony_ci struct scsi_qla_host *ha = 531662306a36Sopenharmony_ci container_of(work, struct scsi_qla_host, dpc_work); 531762306a36Sopenharmony_ci int status = QLA_ERROR; 531862306a36Sopenharmony_ci 531962306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 532062306a36Sopenharmony_ci "scsi%ld: %s: DPC handler waking up. flags = 0x%08lx, dpc_flags = 0x%08lx\n", 532162306a36Sopenharmony_ci ha->host_no, __func__, ha->flags, ha->dpc_flags)); 532262306a36Sopenharmony_ci 532362306a36Sopenharmony_ci /* Initialization not yet finished. Don't do anything yet. */ 532462306a36Sopenharmony_ci if (!test_bit(AF_INIT_DONE, &ha->flags)) 532562306a36Sopenharmony_ci return; 532662306a36Sopenharmony_ci 532762306a36Sopenharmony_ci if (test_bit(AF_EEH_BUSY, &ha->flags)) { 532862306a36Sopenharmony_ci DEBUG2(printk(KERN_INFO "scsi%ld: %s: flags = %lx\n", 532962306a36Sopenharmony_ci ha->host_no, __func__, ha->flags)); 533062306a36Sopenharmony_ci return; 533162306a36Sopenharmony_ci } 533262306a36Sopenharmony_ci 533362306a36Sopenharmony_ci /* post events to application */ 533462306a36Sopenharmony_ci qla4xxx_do_work(ha); 533562306a36Sopenharmony_ci 533662306a36Sopenharmony_ci if (is_qla80XX(ha)) { 533762306a36Sopenharmony_ci if (test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags)) { 533862306a36Sopenharmony_ci if (is_qla8032(ha) || is_qla8042(ha)) { 533962306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "%s: disabling pause transmit on port 0 & 1.\n", 534062306a36Sopenharmony_ci __func__); 534162306a36Sopenharmony_ci /* disable pause frame for ISP83xx */ 534262306a36Sopenharmony_ci qla4_83xx_disable_pause(ha); 534362306a36Sopenharmony_ci } 534462306a36Sopenharmony_ci 534562306a36Sopenharmony_ci ha->isp_ops->idc_lock(ha); 534662306a36Sopenharmony_ci qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE, 534762306a36Sopenharmony_ci QLA8XXX_DEV_FAILED); 534862306a36Sopenharmony_ci ha->isp_ops->idc_unlock(ha); 534962306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "HW State: FAILED\n"); 535062306a36Sopenharmony_ci qla4_8xxx_device_state_handler(ha); 535162306a36Sopenharmony_ci } 535262306a36Sopenharmony_ci 535362306a36Sopenharmony_ci if (test_bit(DPC_POST_IDC_ACK, &ha->dpc_flags)) { 535462306a36Sopenharmony_ci if (is_qla8042(ha)) { 535562306a36Sopenharmony_ci if (ha->idc_info.info2 & 535662306a36Sopenharmony_ci ENABLE_INTERNAL_LOOPBACK) { 535762306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "%s: Disabling ACB\n", 535862306a36Sopenharmony_ci __func__); 535962306a36Sopenharmony_ci status = qla4_84xx_config_acb(ha, 536062306a36Sopenharmony_ci ACB_CONFIG_DISABLE); 536162306a36Sopenharmony_ci if (status != QLA_SUCCESS) { 536262306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "%s: ACB config failed\n", 536362306a36Sopenharmony_ci __func__); 536462306a36Sopenharmony_ci } 536562306a36Sopenharmony_ci } 536662306a36Sopenharmony_ci } 536762306a36Sopenharmony_ci qla4_83xx_post_idc_ack(ha); 536862306a36Sopenharmony_ci clear_bit(DPC_POST_IDC_ACK, &ha->dpc_flags); 536962306a36Sopenharmony_ci } 537062306a36Sopenharmony_ci 537162306a36Sopenharmony_ci if (is_qla8042(ha) && 537262306a36Sopenharmony_ci test_bit(DPC_RESTORE_ACB, &ha->dpc_flags)) { 537362306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "%s: Restoring ACB\n", 537462306a36Sopenharmony_ci __func__); 537562306a36Sopenharmony_ci if (qla4_84xx_config_acb(ha, ACB_CONFIG_SET) != 537662306a36Sopenharmony_ci QLA_SUCCESS) { 537762306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "%s: ACB config failed ", 537862306a36Sopenharmony_ci __func__); 537962306a36Sopenharmony_ci } 538062306a36Sopenharmony_ci clear_bit(DPC_RESTORE_ACB, &ha->dpc_flags); 538162306a36Sopenharmony_ci } 538262306a36Sopenharmony_ci 538362306a36Sopenharmony_ci if (test_and_clear_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags)) { 538462306a36Sopenharmony_ci qla4_8xxx_need_qsnt_handler(ha); 538562306a36Sopenharmony_ci } 538662306a36Sopenharmony_ci } 538762306a36Sopenharmony_ci 538862306a36Sopenharmony_ci if (!test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags) && 538962306a36Sopenharmony_ci (test_bit(DPC_RESET_HA, &ha->dpc_flags) || 539062306a36Sopenharmony_ci test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) || 539162306a36Sopenharmony_ci test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags))) { 539262306a36Sopenharmony_ci if ((is_qla8022(ha) && ql4xdontresethba) || 539362306a36Sopenharmony_ci ((is_qla8032(ha) || is_qla8042(ha)) && 539462306a36Sopenharmony_ci qla4_83xx_idc_dontreset(ha))) { 539562306a36Sopenharmony_ci DEBUG2(printk("scsi%ld: %s: Don't Reset HBA\n", 539662306a36Sopenharmony_ci ha->host_no, __func__)); 539762306a36Sopenharmony_ci clear_bit(DPC_RESET_HA, &ha->dpc_flags); 539862306a36Sopenharmony_ci clear_bit(DPC_RESET_HA_INTR, &ha->dpc_flags); 539962306a36Sopenharmony_ci clear_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags); 540062306a36Sopenharmony_ci goto dpc_post_reset_ha; 540162306a36Sopenharmony_ci } 540262306a36Sopenharmony_ci if (test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags) || 540362306a36Sopenharmony_ci test_bit(DPC_RESET_HA, &ha->dpc_flags)) 540462306a36Sopenharmony_ci qla4xxx_recover_adapter(ha); 540562306a36Sopenharmony_ci 540662306a36Sopenharmony_ci if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) { 540762306a36Sopenharmony_ci uint8_t wait_time = RESET_INTR_TOV; 540862306a36Sopenharmony_ci 540962306a36Sopenharmony_ci while ((readw(&ha->reg->ctrl_status) & 541062306a36Sopenharmony_ci (CSR_SOFT_RESET | CSR_FORCE_SOFT_RESET)) != 0) { 541162306a36Sopenharmony_ci if (--wait_time == 0) 541262306a36Sopenharmony_ci break; 541362306a36Sopenharmony_ci msleep(1000); 541462306a36Sopenharmony_ci } 541562306a36Sopenharmony_ci if (wait_time == 0) 541662306a36Sopenharmony_ci DEBUG2(printk("scsi%ld: %s: SR|FSR " 541762306a36Sopenharmony_ci "bit not cleared-- resetting\n", 541862306a36Sopenharmony_ci ha->host_no, __func__)); 541962306a36Sopenharmony_ci qla4xxx_abort_active_cmds(ha, DID_RESET << 16); 542062306a36Sopenharmony_ci if (ql4xxx_lock_drvr_wait(ha) == QLA_SUCCESS) { 542162306a36Sopenharmony_ci qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); 542262306a36Sopenharmony_ci status = qla4xxx_recover_adapter(ha); 542362306a36Sopenharmony_ci } 542462306a36Sopenharmony_ci clear_bit(DPC_RESET_HA_INTR, &ha->dpc_flags); 542562306a36Sopenharmony_ci if (status == QLA_SUCCESS) 542662306a36Sopenharmony_ci ha->isp_ops->enable_intrs(ha); 542762306a36Sopenharmony_ci } 542862306a36Sopenharmony_ci } 542962306a36Sopenharmony_ci 543062306a36Sopenharmony_cidpc_post_reset_ha: 543162306a36Sopenharmony_ci /* ---- process AEN? --- */ 543262306a36Sopenharmony_ci if (test_and_clear_bit(DPC_AEN, &ha->dpc_flags)) 543362306a36Sopenharmony_ci qla4xxx_process_aen(ha, PROCESS_ALL_AENS); 543462306a36Sopenharmony_ci 543562306a36Sopenharmony_ci /* ---- Get DHCP IP Address? --- */ 543662306a36Sopenharmony_ci if (test_and_clear_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags)) 543762306a36Sopenharmony_ci qla4xxx_get_dhcp_ip_address(ha); 543862306a36Sopenharmony_ci 543962306a36Sopenharmony_ci /* ---- relogin device? --- */ 544062306a36Sopenharmony_ci if (adapter_up(ha) && 544162306a36Sopenharmony_ci test_and_clear_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags)) { 544262306a36Sopenharmony_ci iscsi_host_for_each_session(ha->host, qla4xxx_dpc_relogin); 544362306a36Sopenharmony_ci } 544462306a36Sopenharmony_ci 544562306a36Sopenharmony_ci /* ---- link change? --- */ 544662306a36Sopenharmony_ci if (!test_bit(AF_LOOPBACK, &ha->flags) && 544762306a36Sopenharmony_ci test_and_clear_bit(DPC_LINK_CHANGED, &ha->dpc_flags)) { 544862306a36Sopenharmony_ci if (!test_bit(AF_LINK_UP, &ha->flags)) { 544962306a36Sopenharmony_ci /* ---- link down? --- */ 545062306a36Sopenharmony_ci qla4xxx_mark_all_devices_missing(ha); 545162306a36Sopenharmony_ci } else { 545262306a36Sopenharmony_ci /* ---- link up? --- * 545362306a36Sopenharmony_ci * F/W will auto login to all devices ONLY ONCE after 545462306a36Sopenharmony_ci * link up during driver initialization and runtime 545562306a36Sopenharmony_ci * fatal error recovery. Therefore, the driver must 545662306a36Sopenharmony_ci * manually relogin to devices when recovering from 545762306a36Sopenharmony_ci * connection failures, logouts, expired KATO, etc. */ 545862306a36Sopenharmony_ci if (test_and_clear_bit(AF_BUILD_DDB_LIST, &ha->flags)) { 545962306a36Sopenharmony_ci qla4xxx_build_ddb_list(ha, ha->is_reset); 546062306a36Sopenharmony_ci iscsi_host_for_each_session(ha->host, 546162306a36Sopenharmony_ci qla4xxx_login_flash_ddb); 546262306a36Sopenharmony_ci } else 546362306a36Sopenharmony_ci qla4xxx_relogin_all_devices(ha); 546462306a36Sopenharmony_ci } 546562306a36Sopenharmony_ci } 546662306a36Sopenharmony_ci if (test_and_clear_bit(DPC_SYSFS_DDB_EXPORT, &ha->dpc_flags)) { 546762306a36Sopenharmony_ci if (qla4xxx_sysfs_ddb_export(ha)) 546862306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: Error exporting ddb to sysfs\n", 546962306a36Sopenharmony_ci __func__); 547062306a36Sopenharmony_ci } 547162306a36Sopenharmony_ci} 547262306a36Sopenharmony_ci 547362306a36Sopenharmony_ci/** 547462306a36Sopenharmony_ci * qla4xxx_free_adapter - release the adapter 547562306a36Sopenharmony_ci * @ha: pointer to adapter structure 547662306a36Sopenharmony_ci **/ 547762306a36Sopenharmony_cistatic void qla4xxx_free_adapter(struct scsi_qla_host *ha) 547862306a36Sopenharmony_ci{ 547962306a36Sopenharmony_ci qla4xxx_abort_active_cmds(ha, DID_NO_CONNECT << 16); 548062306a36Sopenharmony_ci 548162306a36Sopenharmony_ci /* Turn-off interrupts on the card. */ 548262306a36Sopenharmony_ci ha->isp_ops->disable_intrs(ha); 548362306a36Sopenharmony_ci 548462306a36Sopenharmony_ci if (is_qla40XX(ha)) { 548562306a36Sopenharmony_ci writel(set_rmask(CSR_SCSI_PROCESSOR_INTR), 548662306a36Sopenharmony_ci &ha->reg->ctrl_status); 548762306a36Sopenharmony_ci readl(&ha->reg->ctrl_status); 548862306a36Sopenharmony_ci } else if (is_qla8022(ha)) { 548962306a36Sopenharmony_ci writel(0, &ha->qla4_82xx_reg->host_int); 549062306a36Sopenharmony_ci readl(&ha->qla4_82xx_reg->host_int); 549162306a36Sopenharmony_ci } else if (is_qla8032(ha) || is_qla8042(ha)) { 549262306a36Sopenharmony_ci writel(0, &ha->qla4_83xx_reg->risc_intr); 549362306a36Sopenharmony_ci readl(&ha->qla4_83xx_reg->risc_intr); 549462306a36Sopenharmony_ci } 549562306a36Sopenharmony_ci 549662306a36Sopenharmony_ci /* Remove timer thread, if present */ 549762306a36Sopenharmony_ci if (ha->timer_active) 549862306a36Sopenharmony_ci qla4xxx_stop_timer(ha); 549962306a36Sopenharmony_ci 550062306a36Sopenharmony_ci /* Kill the kernel thread for this host */ 550162306a36Sopenharmony_ci if (ha->dpc_thread) 550262306a36Sopenharmony_ci destroy_workqueue(ha->dpc_thread); 550362306a36Sopenharmony_ci 550462306a36Sopenharmony_ci /* Kill the kernel thread for this host */ 550562306a36Sopenharmony_ci if (ha->task_wq) 550662306a36Sopenharmony_ci destroy_workqueue(ha->task_wq); 550762306a36Sopenharmony_ci 550862306a36Sopenharmony_ci /* Put firmware in known state */ 550962306a36Sopenharmony_ci ha->isp_ops->reset_firmware(ha); 551062306a36Sopenharmony_ci 551162306a36Sopenharmony_ci if (is_qla80XX(ha)) { 551262306a36Sopenharmony_ci ha->isp_ops->idc_lock(ha); 551362306a36Sopenharmony_ci qla4_8xxx_clear_drv_active(ha); 551462306a36Sopenharmony_ci ha->isp_ops->idc_unlock(ha); 551562306a36Sopenharmony_ci } 551662306a36Sopenharmony_ci 551762306a36Sopenharmony_ci /* Detach interrupts */ 551862306a36Sopenharmony_ci qla4xxx_free_irqs(ha); 551962306a36Sopenharmony_ci 552062306a36Sopenharmony_ci /* free extra memory */ 552162306a36Sopenharmony_ci qla4xxx_mem_free(ha); 552262306a36Sopenharmony_ci} 552362306a36Sopenharmony_ci 552462306a36Sopenharmony_ciint qla4_8xxx_iospace_config(struct scsi_qla_host *ha) 552562306a36Sopenharmony_ci{ 552662306a36Sopenharmony_ci int status = 0; 552762306a36Sopenharmony_ci unsigned long mem_base, mem_len; 552862306a36Sopenharmony_ci struct pci_dev *pdev = ha->pdev; 552962306a36Sopenharmony_ci 553062306a36Sopenharmony_ci status = pci_request_regions(pdev, DRIVER_NAME); 553162306a36Sopenharmony_ci if (status) { 553262306a36Sopenharmony_ci printk(KERN_WARNING 553362306a36Sopenharmony_ci "scsi(%ld) Failed to reserve PIO regions (%s) " 553462306a36Sopenharmony_ci "status=%d\n", ha->host_no, pci_name(pdev), status); 553562306a36Sopenharmony_ci goto iospace_error_exit; 553662306a36Sopenharmony_ci } 553762306a36Sopenharmony_ci 553862306a36Sopenharmony_ci DEBUG2(printk(KERN_INFO "%s: revision-id=%d\n", 553962306a36Sopenharmony_ci __func__, pdev->revision)); 554062306a36Sopenharmony_ci ha->revision_id = pdev->revision; 554162306a36Sopenharmony_ci 554262306a36Sopenharmony_ci /* remap phys address */ 554362306a36Sopenharmony_ci mem_base = pci_resource_start(pdev, 0); /* 0 is for BAR 0 */ 554462306a36Sopenharmony_ci mem_len = pci_resource_len(pdev, 0); 554562306a36Sopenharmony_ci DEBUG2(printk(KERN_INFO "%s: ioremap from %lx a size of %lx\n", 554662306a36Sopenharmony_ci __func__, mem_base, mem_len)); 554762306a36Sopenharmony_ci 554862306a36Sopenharmony_ci /* mapping of pcibase pointer */ 554962306a36Sopenharmony_ci ha->nx_pcibase = (unsigned long)ioremap(mem_base, mem_len); 555062306a36Sopenharmony_ci if (!ha->nx_pcibase) { 555162306a36Sopenharmony_ci printk(KERN_ERR 555262306a36Sopenharmony_ci "cannot remap MMIO (%s), aborting\n", pci_name(pdev)); 555362306a36Sopenharmony_ci pci_release_regions(ha->pdev); 555462306a36Sopenharmony_ci goto iospace_error_exit; 555562306a36Sopenharmony_ci } 555662306a36Sopenharmony_ci 555762306a36Sopenharmony_ci /* Mapping of IO base pointer, door bell read and write pointer */ 555862306a36Sopenharmony_ci 555962306a36Sopenharmony_ci /* mapping of IO base pointer */ 556062306a36Sopenharmony_ci if (is_qla8022(ha)) { 556162306a36Sopenharmony_ci ha->qla4_82xx_reg = (struct device_reg_82xx __iomem *) 556262306a36Sopenharmony_ci ((uint8_t *)ha->nx_pcibase + 0xbc000 + 556362306a36Sopenharmony_ci (ha->pdev->devfn << 11)); 556462306a36Sopenharmony_ci ha->nx_db_wr_ptr = (ha->pdev->devfn == 4 ? QLA82XX_CAM_RAM_DB1 : 556562306a36Sopenharmony_ci QLA82XX_CAM_RAM_DB2); 556662306a36Sopenharmony_ci } else if (is_qla8032(ha) || is_qla8042(ha)) { 556762306a36Sopenharmony_ci ha->qla4_83xx_reg = (struct device_reg_83xx __iomem *) 556862306a36Sopenharmony_ci ((uint8_t *)ha->nx_pcibase); 556962306a36Sopenharmony_ci } 557062306a36Sopenharmony_ci 557162306a36Sopenharmony_ci return 0; 557262306a36Sopenharmony_ciiospace_error_exit: 557362306a36Sopenharmony_ci return -ENOMEM; 557462306a36Sopenharmony_ci} 557562306a36Sopenharmony_ci 557662306a36Sopenharmony_ci/*** 557762306a36Sopenharmony_ci * qla4xxx_iospace_config - maps registers 557862306a36Sopenharmony_ci * @ha: pointer to adapter structure 557962306a36Sopenharmony_ci * 558062306a36Sopenharmony_ci * This routines maps HBA's registers from the pci address space 558162306a36Sopenharmony_ci * into the kernel virtual address space for memory mapped i/o. 558262306a36Sopenharmony_ci **/ 558362306a36Sopenharmony_ciint qla4xxx_iospace_config(struct scsi_qla_host *ha) 558462306a36Sopenharmony_ci{ 558562306a36Sopenharmony_ci unsigned long pio, pio_len, pio_flags; 558662306a36Sopenharmony_ci unsigned long mmio, mmio_len, mmio_flags; 558762306a36Sopenharmony_ci 558862306a36Sopenharmony_ci pio = pci_resource_start(ha->pdev, 0); 558962306a36Sopenharmony_ci pio_len = pci_resource_len(ha->pdev, 0); 559062306a36Sopenharmony_ci pio_flags = pci_resource_flags(ha->pdev, 0); 559162306a36Sopenharmony_ci if (pio_flags & IORESOURCE_IO) { 559262306a36Sopenharmony_ci if (pio_len < MIN_IOBASE_LEN) { 559362306a36Sopenharmony_ci ql4_printk(KERN_WARNING, ha, 559462306a36Sopenharmony_ci "Invalid PCI I/O region size\n"); 559562306a36Sopenharmony_ci pio = 0; 559662306a36Sopenharmony_ci } 559762306a36Sopenharmony_ci } else { 559862306a36Sopenharmony_ci ql4_printk(KERN_WARNING, ha, "region #0 not a PIO resource\n"); 559962306a36Sopenharmony_ci pio = 0; 560062306a36Sopenharmony_ci } 560162306a36Sopenharmony_ci 560262306a36Sopenharmony_ci /* Use MMIO operations for all accesses. */ 560362306a36Sopenharmony_ci mmio = pci_resource_start(ha->pdev, 1); 560462306a36Sopenharmony_ci mmio_len = pci_resource_len(ha->pdev, 1); 560562306a36Sopenharmony_ci mmio_flags = pci_resource_flags(ha->pdev, 1); 560662306a36Sopenharmony_ci 560762306a36Sopenharmony_ci if (!(mmio_flags & IORESOURCE_MEM)) { 560862306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, 560962306a36Sopenharmony_ci "region #0 not an MMIO resource, aborting\n"); 561062306a36Sopenharmony_ci 561162306a36Sopenharmony_ci goto iospace_error_exit; 561262306a36Sopenharmony_ci } 561362306a36Sopenharmony_ci 561462306a36Sopenharmony_ci if (mmio_len < MIN_IOBASE_LEN) { 561562306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, 561662306a36Sopenharmony_ci "Invalid PCI mem region size, aborting\n"); 561762306a36Sopenharmony_ci goto iospace_error_exit; 561862306a36Sopenharmony_ci } 561962306a36Sopenharmony_ci 562062306a36Sopenharmony_ci if (pci_request_regions(ha->pdev, DRIVER_NAME)) { 562162306a36Sopenharmony_ci ql4_printk(KERN_WARNING, ha, 562262306a36Sopenharmony_ci "Failed to reserve PIO/MMIO regions\n"); 562362306a36Sopenharmony_ci 562462306a36Sopenharmony_ci goto iospace_error_exit; 562562306a36Sopenharmony_ci } 562662306a36Sopenharmony_ci 562762306a36Sopenharmony_ci ha->pio_address = pio; 562862306a36Sopenharmony_ci ha->pio_length = pio_len; 562962306a36Sopenharmony_ci ha->reg = ioremap(mmio, MIN_IOBASE_LEN); 563062306a36Sopenharmony_ci if (!ha->reg) { 563162306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, 563262306a36Sopenharmony_ci "cannot remap MMIO, aborting\n"); 563362306a36Sopenharmony_ci 563462306a36Sopenharmony_ci goto iospace_error_exit; 563562306a36Sopenharmony_ci } 563662306a36Sopenharmony_ci 563762306a36Sopenharmony_ci return 0; 563862306a36Sopenharmony_ci 563962306a36Sopenharmony_ciiospace_error_exit: 564062306a36Sopenharmony_ci return -ENOMEM; 564162306a36Sopenharmony_ci} 564262306a36Sopenharmony_ci 564362306a36Sopenharmony_cistatic struct isp_operations qla4xxx_isp_ops = { 564462306a36Sopenharmony_ci .iospace_config = qla4xxx_iospace_config, 564562306a36Sopenharmony_ci .pci_config = qla4xxx_pci_config, 564662306a36Sopenharmony_ci .disable_intrs = qla4xxx_disable_intrs, 564762306a36Sopenharmony_ci .enable_intrs = qla4xxx_enable_intrs, 564862306a36Sopenharmony_ci .start_firmware = qla4xxx_start_firmware, 564962306a36Sopenharmony_ci .intr_handler = qla4xxx_intr_handler, 565062306a36Sopenharmony_ci .interrupt_service_routine = qla4xxx_interrupt_service_routine, 565162306a36Sopenharmony_ci .reset_chip = qla4xxx_soft_reset, 565262306a36Sopenharmony_ci .reset_firmware = qla4xxx_hw_reset, 565362306a36Sopenharmony_ci .queue_iocb = qla4xxx_queue_iocb, 565462306a36Sopenharmony_ci .complete_iocb = qla4xxx_complete_iocb, 565562306a36Sopenharmony_ci .rd_shdw_req_q_out = qla4xxx_rd_shdw_req_q_out, 565662306a36Sopenharmony_ci .rd_shdw_rsp_q_in = qla4xxx_rd_shdw_rsp_q_in, 565762306a36Sopenharmony_ci .get_sys_info = qla4xxx_get_sys_info, 565862306a36Sopenharmony_ci .queue_mailbox_command = qla4xxx_queue_mbox_cmd, 565962306a36Sopenharmony_ci .process_mailbox_interrupt = qla4xxx_process_mbox_intr, 566062306a36Sopenharmony_ci}; 566162306a36Sopenharmony_ci 566262306a36Sopenharmony_cistatic struct isp_operations qla4_82xx_isp_ops = { 566362306a36Sopenharmony_ci .iospace_config = qla4_8xxx_iospace_config, 566462306a36Sopenharmony_ci .pci_config = qla4_8xxx_pci_config, 566562306a36Sopenharmony_ci .disable_intrs = qla4_82xx_disable_intrs, 566662306a36Sopenharmony_ci .enable_intrs = qla4_82xx_enable_intrs, 566762306a36Sopenharmony_ci .start_firmware = qla4_8xxx_load_risc, 566862306a36Sopenharmony_ci .restart_firmware = qla4_82xx_try_start_fw, 566962306a36Sopenharmony_ci .intr_handler = qla4_82xx_intr_handler, 567062306a36Sopenharmony_ci .interrupt_service_routine = qla4_82xx_interrupt_service_routine, 567162306a36Sopenharmony_ci .need_reset = qla4_8xxx_need_reset, 567262306a36Sopenharmony_ci .reset_chip = qla4_82xx_isp_reset, 567362306a36Sopenharmony_ci .reset_firmware = qla4_8xxx_stop_firmware, 567462306a36Sopenharmony_ci .queue_iocb = qla4_82xx_queue_iocb, 567562306a36Sopenharmony_ci .complete_iocb = qla4_82xx_complete_iocb, 567662306a36Sopenharmony_ci .rd_shdw_req_q_out = qla4_82xx_rd_shdw_req_q_out, 567762306a36Sopenharmony_ci .rd_shdw_rsp_q_in = qla4_82xx_rd_shdw_rsp_q_in, 567862306a36Sopenharmony_ci .get_sys_info = qla4_8xxx_get_sys_info, 567962306a36Sopenharmony_ci .rd_reg_direct = qla4_82xx_rd_32, 568062306a36Sopenharmony_ci .wr_reg_direct = qla4_82xx_wr_32, 568162306a36Sopenharmony_ci .rd_reg_indirect = qla4_82xx_md_rd_32, 568262306a36Sopenharmony_ci .wr_reg_indirect = qla4_82xx_md_wr_32, 568362306a36Sopenharmony_ci .idc_lock = qla4_82xx_idc_lock, 568462306a36Sopenharmony_ci .idc_unlock = qla4_82xx_idc_unlock, 568562306a36Sopenharmony_ci .rom_lock_recovery = qla4_82xx_rom_lock_recovery, 568662306a36Sopenharmony_ci .queue_mailbox_command = qla4_82xx_queue_mbox_cmd, 568762306a36Sopenharmony_ci .process_mailbox_interrupt = qla4_82xx_process_mbox_intr, 568862306a36Sopenharmony_ci}; 568962306a36Sopenharmony_ci 569062306a36Sopenharmony_cistatic struct isp_operations qla4_83xx_isp_ops = { 569162306a36Sopenharmony_ci .iospace_config = qla4_8xxx_iospace_config, 569262306a36Sopenharmony_ci .pci_config = qla4_8xxx_pci_config, 569362306a36Sopenharmony_ci .disable_intrs = qla4_83xx_disable_intrs, 569462306a36Sopenharmony_ci .enable_intrs = qla4_83xx_enable_intrs, 569562306a36Sopenharmony_ci .start_firmware = qla4_8xxx_load_risc, 569662306a36Sopenharmony_ci .restart_firmware = qla4_83xx_start_firmware, 569762306a36Sopenharmony_ci .intr_handler = qla4_83xx_intr_handler, 569862306a36Sopenharmony_ci .interrupt_service_routine = qla4_83xx_interrupt_service_routine, 569962306a36Sopenharmony_ci .need_reset = qla4_8xxx_need_reset, 570062306a36Sopenharmony_ci .reset_chip = qla4_83xx_isp_reset, 570162306a36Sopenharmony_ci .reset_firmware = qla4_8xxx_stop_firmware, 570262306a36Sopenharmony_ci .queue_iocb = qla4_83xx_queue_iocb, 570362306a36Sopenharmony_ci .complete_iocb = qla4_83xx_complete_iocb, 570462306a36Sopenharmony_ci .rd_shdw_req_q_out = qla4xxx_rd_shdw_req_q_out, 570562306a36Sopenharmony_ci .rd_shdw_rsp_q_in = qla4xxx_rd_shdw_rsp_q_in, 570662306a36Sopenharmony_ci .get_sys_info = qla4_8xxx_get_sys_info, 570762306a36Sopenharmony_ci .rd_reg_direct = qla4_83xx_rd_reg, 570862306a36Sopenharmony_ci .wr_reg_direct = qla4_83xx_wr_reg, 570962306a36Sopenharmony_ci .rd_reg_indirect = qla4_83xx_rd_reg_indirect, 571062306a36Sopenharmony_ci .wr_reg_indirect = qla4_83xx_wr_reg_indirect, 571162306a36Sopenharmony_ci .idc_lock = qla4_83xx_drv_lock, 571262306a36Sopenharmony_ci .idc_unlock = qla4_83xx_drv_unlock, 571362306a36Sopenharmony_ci .rom_lock_recovery = qla4_83xx_rom_lock_recovery, 571462306a36Sopenharmony_ci .queue_mailbox_command = qla4_83xx_queue_mbox_cmd, 571562306a36Sopenharmony_ci .process_mailbox_interrupt = qla4_83xx_process_mbox_intr, 571662306a36Sopenharmony_ci}; 571762306a36Sopenharmony_ci 571862306a36Sopenharmony_ciuint16_t qla4xxx_rd_shdw_req_q_out(struct scsi_qla_host *ha) 571962306a36Sopenharmony_ci{ 572062306a36Sopenharmony_ci return (uint16_t)le32_to_cpu(ha->shadow_regs->req_q_out); 572162306a36Sopenharmony_ci} 572262306a36Sopenharmony_ci 572362306a36Sopenharmony_ciuint16_t qla4_82xx_rd_shdw_req_q_out(struct scsi_qla_host *ha) 572462306a36Sopenharmony_ci{ 572562306a36Sopenharmony_ci return (uint16_t)le32_to_cpu(readl(&ha->qla4_82xx_reg->req_q_out)); 572662306a36Sopenharmony_ci} 572762306a36Sopenharmony_ci 572862306a36Sopenharmony_ciuint16_t qla4xxx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha) 572962306a36Sopenharmony_ci{ 573062306a36Sopenharmony_ci return (uint16_t)le32_to_cpu(ha->shadow_regs->rsp_q_in); 573162306a36Sopenharmony_ci} 573262306a36Sopenharmony_ci 573362306a36Sopenharmony_ciuint16_t qla4_82xx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha) 573462306a36Sopenharmony_ci{ 573562306a36Sopenharmony_ci return (uint16_t)le32_to_cpu(readl(&ha->qla4_82xx_reg->rsp_q_in)); 573662306a36Sopenharmony_ci} 573762306a36Sopenharmony_ci 573862306a36Sopenharmony_cistatic ssize_t qla4xxx_show_boot_eth_info(void *data, int type, char *buf) 573962306a36Sopenharmony_ci{ 574062306a36Sopenharmony_ci struct scsi_qla_host *ha = data; 574162306a36Sopenharmony_ci char *str = buf; 574262306a36Sopenharmony_ci int rc; 574362306a36Sopenharmony_ci 574462306a36Sopenharmony_ci switch (type) { 574562306a36Sopenharmony_ci case ISCSI_BOOT_ETH_FLAGS: 574662306a36Sopenharmony_ci rc = sprintf(str, "%d\n", (char)SYSFS_FLAG_FW_SEL_BOOT); 574762306a36Sopenharmony_ci break; 574862306a36Sopenharmony_ci case ISCSI_BOOT_ETH_INDEX: 574962306a36Sopenharmony_ci rc = sprintf(str, "0\n"); 575062306a36Sopenharmony_ci break; 575162306a36Sopenharmony_ci case ISCSI_BOOT_ETH_MAC: 575262306a36Sopenharmony_ci rc = sysfs_format_mac(str, ha->my_mac, 575362306a36Sopenharmony_ci MAC_ADDR_LEN); 575462306a36Sopenharmony_ci break; 575562306a36Sopenharmony_ci default: 575662306a36Sopenharmony_ci rc = -ENOSYS; 575762306a36Sopenharmony_ci break; 575862306a36Sopenharmony_ci } 575962306a36Sopenharmony_ci return rc; 576062306a36Sopenharmony_ci} 576162306a36Sopenharmony_ci 576262306a36Sopenharmony_cistatic umode_t qla4xxx_eth_get_attr_visibility(void *data, int type) 576362306a36Sopenharmony_ci{ 576462306a36Sopenharmony_ci int rc; 576562306a36Sopenharmony_ci 576662306a36Sopenharmony_ci switch (type) { 576762306a36Sopenharmony_ci case ISCSI_BOOT_ETH_FLAGS: 576862306a36Sopenharmony_ci case ISCSI_BOOT_ETH_MAC: 576962306a36Sopenharmony_ci case ISCSI_BOOT_ETH_INDEX: 577062306a36Sopenharmony_ci rc = S_IRUGO; 577162306a36Sopenharmony_ci break; 577262306a36Sopenharmony_ci default: 577362306a36Sopenharmony_ci rc = 0; 577462306a36Sopenharmony_ci break; 577562306a36Sopenharmony_ci } 577662306a36Sopenharmony_ci return rc; 577762306a36Sopenharmony_ci} 577862306a36Sopenharmony_ci 577962306a36Sopenharmony_cistatic ssize_t qla4xxx_show_boot_ini_info(void *data, int type, char *buf) 578062306a36Sopenharmony_ci{ 578162306a36Sopenharmony_ci struct scsi_qla_host *ha = data; 578262306a36Sopenharmony_ci char *str = buf; 578362306a36Sopenharmony_ci int rc; 578462306a36Sopenharmony_ci 578562306a36Sopenharmony_ci switch (type) { 578662306a36Sopenharmony_ci case ISCSI_BOOT_INI_INITIATOR_NAME: 578762306a36Sopenharmony_ci rc = sprintf(str, "%s\n", ha->name_string); 578862306a36Sopenharmony_ci break; 578962306a36Sopenharmony_ci default: 579062306a36Sopenharmony_ci rc = -ENOSYS; 579162306a36Sopenharmony_ci break; 579262306a36Sopenharmony_ci } 579362306a36Sopenharmony_ci return rc; 579462306a36Sopenharmony_ci} 579562306a36Sopenharmony_ci 579662306a36Sopenharmony_cistatic umode_t qla4xxx_ini_get_attr_visibility(void *data, int type) 579762306a36Sopenharmony_ci{ 579862306a36Sopenharmony_ci int rc; 579962306a36Sopenharmony_ci 580062306a36Sopenharmony_ci switch (type) { 580162306a36Sopenharmony_ci case ISCSI_BOOT_INI_INITIATOR_NAME: 580262306a36Sopenharmony_ci rc = S_IRUGO; 580362306a36Sopenharmony_ci break; 580462306a36Sopenharmony_ci default: 580562306a36Sopenharmony_ci rc = 0; 580662306a36Sopenharmony_ci break; 580762306a36Sopenharmony_ci } 580862306a36Sopenharmony_ci return rc; 580962306a36Sopenharmony_ci} 581062306a36Sopenharmony_ci 581162306a36Sopenharmony_cistatic ssize_t 581262306a36Sopenharmony_ciqla4xxx_show_boot_tgt_info(struct ql4_boot_session_info *boot_sess, int type, 581362306a36Sopenharmony_ci char *buf) 581462306a36Sopenharmony_ci{ 581562306a36Sopenharmony_ci struct ql4_conn_info *boot_conn = &boot_sess->conn_list[0]; 581662306a36Sopenharmony_ci char *str = buf; 581762306a36Sopenharmony_ci int rc; 581862306a36Sopenharmony_ci 581962306a36Sopenharmony_ci switch (type) { 582062306a36Sopenharmony_ci case ISCSI_BOOT_TGT_NAME: 582162306a36Sopenharmony_ci rc = sprintf(buf, "%s\n", (char *)&boot_sess->target_name); 582262306a36Sopenharmony_ci break; 582362306a36Sopenharmony_ci case ISCSI_BOOT_TGT_IP_ADDR: 582462306a36Sopenharmony_ci if (boot_sess->conn_list[0].dest_ipaddr.ip_type == 0x1) 582562306a36Sopenharmony_ci rc = sprintf(buf, "%pI4\n", 582662306a36Sopenharmony_ci &boot_conn->dest_ipaddr.ip_address); 582762306a36Sopenharmony_ci else 582862306a36Sopenharmony_ci rc = sprintf(str, "%pI6\n", 582962306a36Sopenharmony_ci &boot_conn->dest_ipaddr.ip_address); 583062306a36Sopenharmony_ci break; 583162306a36Sopenharmony_ci case ISCSI_BOOT_TGT_PORT: 583262306a36Sopenharmony_ci rc = sprintf(str, "%d\n", boot_conn->dest_port); 583362306a36Sopenharmony_ci break; 583462306a36Sopenharmony_ci case ISCSI_BOOT_TGT_CHAP_NAME: 583562306a36Sopenharmony_ci rc = sprintf(str, "%.*s\n", 583662306a36Sopenharmony_ci boot_conn->chap.target_chap_name_length, 583762306a36Sopenharmony_ci (char *)&boot_conn->chap.target_chap_name); 583862306a36Sopenharmony_ci break; 583962306a36Sopenharmony_ci case ISCSI_BOOT_TGT_CHAP_SECRET: 584062306a36Sopenharmony_ci rc = sprintf(str, "%.*s\n", 584162306a36Sopenharmony_ci boot_conn->chap.target_secret_length, 584262306a36Sopenharmony_ci (char *)&boot_conn->chap.target_secret); 584362306a36Sopenharmony_ci break; 584462306a36Sopenharmony_ci case ISCSI_BOOT_TGT_REV_CHAP_NAME: 584562306a36Sopenharmony_ci rc = sprintf(str, "%.*s\n", 584662306a36Sopenharmony_ci boot_conn->chap.intr_chap_name_length, 584762306a36Sopenharmony_ci (char *)&boot_conn->chap.intr_chap_name); 584862306a36Sopenharmony_ci break; 584962306a36Sopenharmony_ci case ISCSI_BOOT_TGT_REV_CHAP_SECRET: 585062306a36Sopenharmony_ci rc = sprintf(str, "%.*s\n", 585162306a36Sopenharmony_ci boot_conn->chap.intr_secret_length, 585262306a36Sopenharmony_ci (char *)&boot_conn->chap.intr_secret); 585362306a36Sopenharmony_ci break; 585462306a36Sopenharmony_ci case ISCSI_BOOT_TGT_FLAGS: 585562306a36Sopenharmony_ci rc = sprintf(str, "%d\n", (char)SYSFS_FLAG_FW_SEL_BOOT); 585662306a36Sopenharmony_ci break; 585762306a36Sopenharmony_ci case ISCSI_BOOT_TGT_NIC_ASSOC: 585862306a36Sopenharmony_ci rc = sprintf(str, "0\n"); 585962306a36Sopenharmony_ci break; 586062306a36Sopenharmony_ci default: 586162306a36Sopenharmony_ci rc = -ENOSYS; 586262306a36Sopenharmony_ci break; 586362306a36Sopenharmony_ci } 586462306a36Sopenharmony_ci return rc; 586562306a36Sopenharmony_ci} 586662306a36Sopenharmony_ci 586762306a36Sopenharmony_cistatic ssize_t qla4xxx_show_boot_tgt_pri_info(void *data, int type, char *buf) 586862306a36Sopenharmony_ci{ 586962306a36Sopenharmony_ci struct scsi_qla_host *ha = data; 587062306a36Sopenharmony_ci struct ql4_boot_session_info *boot_sess = &(ha->boot_tgt.boot_pri_sess); 587162306a36Sopenharmony_ci 587262306a36Sopenharmony_ci return qla4xxx_show_boot_tgt_info(boot_sess, type, buf); 587362306a36Sopenharmony_ci} 587462306a36Sopenharmony_ci 587562306a36Sopenharmony_cistatic ssize_t qla4xxx_show_boot_tgt_sec_info(void *data, int type, char *buf) 587662306a36Sopenharmony_ci{ 587762306a36Sopenharmony_ci struct scsi_qla_host *ha = data; 587862306a36Sopenharmony_ci struct ql4_boot_session_info *boot_sess = &(ha->boot_tgt.boot_sec_sess); 587962306a36Sopenharmony_ci 588062306a36Sopenharmony_ci return qla4xxx_show_boot_tgt_info(boot_sess, type, buf); 588162306a36Sopenharmony_ci} 588262306a36Sopenharmony_ci 588362306a36Sopenharmony_cistatic umode_t qla4xxx_tgt_get_attr_visibility(void *data, int type) 588462306a36Sopenharmony_ci{ 588562306a36Sopenharmony_ci int rc; 588662306a36Sopenharmony_ci 588762306a36Sopenharmony_ci switch (type) { 588862306a36Sopenharmony_ci case ISCSI_BOOT_TGT_NAME: 588962306a36Sopenharmony_ci case ISCSI_BOOT_TGT_IP_ADDR: 589062306a36Sopenharmony_ci case ISCSI_BOOT_TGT_PORT: 589162306a36Sopenharmony_ci case ISCSI_BOOT_TGT_CHAP_NAME: 589262306a36Sopenharmony_ci case ISCSI_BOOT_TGT_CHAP_SECRET: 589362306a36Sopenharmony_ci case ISCSI_BOOT_TGT_REV_CHAP_NAME: 589462306a36Sopenharmony_ci case ISCSI_BOOT_TGT_REV_CHAP_SECRET: 589562306a36Sopenharmony_ci case ISCSI_BOOT_TGT_NIC_ASSOC: 589662306a36Sopenharmony_ci case ISCSI_BOOT_TGT_FLAGS: 589762306a36Sopenharmony_ci rc = S_IRUGO; 589862306a36Sopenharmony_ci break; 589962306a36Sopenharmony_ci default: 590062306a36Sopenharmony_ci rc = 0; 590162306a36Sopenharmony_ci break; 590262306a36Sopenharmony_ci } 590362306a36Sopenharmony_ci return rc; 590462306a36Sopenharmony_ci} 590562306a36Sopenharmony_ci 590662306a36Sopenharmony_cistatic void qla4xxx_boot_release(void *data) 590762306a36Sopenharmony_ci{ 590862306a36Sopenharmony_ci struct scsi_qla_host *ha = data; 590962306a36Sopenharmony_ci 591062306a36Sopenharmony_ci scsi_host_put(ha->host); 591162306a36Sopenharmony_ci} 591262306a36Sopenharmony_ci 591362306a36Sopenharmony_cistatic int get_fw_boot_info(struct scsi_qla_host *ha, uint16_t ddb_index[]) 591462306a36Sopenharmony_ci{ 591562306a36Sopenharmony_ci dma_addr_t buf_dma; 591662306a36Sopenharmony_ci uint32_t addr, pri_addr, sec_addr; 591762306a36Sopenharmony_ci uint32_t offset; 591862306a36Sopenharmony_ci uint16_t func_num; 591962306a36Sopenharmony_ci uint8_t val; 592062306a36Sopenharmony_ci uint8_t *buf = NULL; 592162306a36Sopenharmony_ci size_t size = 13 * sizeof(uint8_t); 592262306a36Sopenharmony_ci int ret = QLA_SUCCESS; 592362306a36Sopenharmony_ci 592462306a36Sopenharmony_ci func_num = PCI_FUNC(ha->pdev->devfn); 592562306a36Sopenharmony_ci 592662306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "%s: Get FW boot info for 0x%x func %d\n", 592762306a36Sopenharmony_ci __func__, ha->pdev->device, func_num); 592862306a36Sopenharmony_ci 592962306a36Sopenharmony_ci if (is_qla40XX(ha)) { 593062306a36Sopenharmony_ci if (func_num == 1) { 593162306a36Sopenharmony_ci addr = NVRAM_PORT0_BOOT_MODE; 593262306a36Sopenharmony_ci pri_addr = NVRAM_PORT0_BOOT_PRI_TGT; 593362306a36Sopenharmony_ci sec_addr = NVRAM_PORT0_BOOT_SEC_TGT; 593462306a36Sopenharmony_ci } else if (func_num == 3) { 593562306a36Sopenharmony_ci addr = NVRAM_PORT1_BOOT_MODE; 593662306a36Sopenharmony_ci pri_addr = NVRAM_PORT1_BOOT_PRI_TGT; 593762306a36Sopenharmony_ci sec_addr = NVRAM_PORT1_BOOT_SEC_TGT; 593862306a36Sopenharmony_ci } else { 593962306a36Sopenharmony_ci ret = QLA_ERROR; 594062306a36Sopenharmony_ci goto exit_boot_info; 594162306a36Sopenharmony_ci } 594262306a36Sopenharmony_ci 594362306a36Sopenharmony_ci /* Check Boot Mode */ 594462306a36Sopenharmony_ci val = rd_nvram_byte(ha, addr); 594562306a36Sopenharmony_ci if (!(val & 0x07)) { 594662306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Adapter boot " 594762306a36Sopenharmony_ci "options : 0x%x\n", __func__, val)); 594862306a36Sopenharmony_ci ret = QLA_ERROR; 594962306a36Sopenharmony_ci goto exit_boot_info; 595062306a36Sopenharmony_ci } 595162306a36Sopenharmony_ci 595262306a36Sopenharmony_ci /* get primary valid target index */ 595362306a36Sopenharmony_ci val = rd_nvram_byte(ha, pri_addr); 595462306a36Sopenharmony_ci if (val & BIT_7) 595562306a36Sopenharmony_ci ddb_index[0] = (val & 0x7f); 595662306a36Sopenharmony_ci 595762306a36Sopenharmony_ci /* get secondary valid target index */ 595862306a36Sopenharmony_ci val = rd_nvram_byte(ha, sec_addr); 595962306a36Sopenharmony_ci if (val & BIT_7) 596062306a36Sopenharmony_ci ddb_index[1] = (val & 0x7f); 596162306a36Sopenharmony_ci goto exit_boot_info; 596262306a36Sopenharmony_ci } else if (is_qla80XX(ha)) { 596362306a36Sopenharmony_ci buf = dma_alloc_coherent(&ha->pdev->dev, size, 596462306a36Sopenharmony_ci &buf_dma, GFP_KERNEL); 596562306a36Sopenharmony_ci if (!buf) { 596662306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_ERR, ha, 596762306a36Sopenharmony_ci "%s: Unable to allocate dma buffer\n", 596862306a36Sopenharmony_ci __func__)); 596962306a36Sopenharmony_ci ret = QLA_ERROR; 597062306a36Sopenharmony_ci goto exit_boot_info; 597162306a36Sopenharmony_ci } 597262306a36Sopenharmony_ci 597362306a36Sopenharmony_ci if (ha->port_num == 0) 597462306a36Sopenharmony_ci offset = BOOT_PARAM_OFFSET_PORT0; 597562306a36Sopenharmony_ci else if (ha->port_num == 1) 597662306a36Sopenharmony_ci offset = BOOT_PARAM_OFFSET_PORT1; 597762306a36Sopenharmony_ci else { 597862306a36Sopenharmony_ci ret = QLA_ERROR; 597962306a36Sopenharmony_ci goto exit_boot_info_free; 598062306a36Sopenharmony_ci } 598162306a36Sopenharmony_ci addr = FLASH_RAW_ACCESS_ADDR + (ha->hw.flt_iscsi_param * 4) + 598262306a36Sopenharmony_ci offset; 598362306a36Sopenharmony_ci if (qla4xxx_get_flash(ha, buf_dma, addr, 598462306a36Sopenharmony_ci 13 * sizeof(uint8_t)) != QLA_SUCCESS) { 598562306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_ERR, ha, "scsi%ld: %s: Get Flash" 598662306a36Sopenharmony_ci " failed\n", ha->host_no, __func__)); 598762306a36Sopenharmony_ci ret = QLA_ERROR; 598862306a36Sopenharmony_ci goto exit_boot_info_free; 598962306a36Sopenharmony_ci } 599062306a36Sopenharmony_ci /* Check Boot Mode */ 599162306a36Sopenharmony_ci if (!(buf[1] & 0x07)) { 599262306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "Firmware boot options" 599362306a36Sopenharmony_ci " : 0x%x\n", buf[1])); 599462306a36Sopenharmony_ci ret = QLA_ERROR; 599562306a36Sopenharmony_ci goto exit_boot_info_free; 599662306a36Sopenharmony_ci } 599762306a36Sopenharmony_ci 599862306a36Sopenharmony_ci /* get primary valid target index */ 599962306a36Sopenharmony_ci if (buf[2] & BIT_7) 600062306a36Sopenharmony_ci ddb_index[0] = buf[2] & 0x7f; 600162306a36Sopenharmony_ci 600262306a36Sopenharmony_ci /* get secondary valid target index */ 600362306a36Sopenharmony_ci if (buf[11] & BIT_7) 600462306a36Sopenharmony_ci ddb_index[1] = buf[11] & 0x7f; 600562306a36Sopenharmony_ci } else { 600662306a36Sopenharmony_ci ret = QLA_ERROR; 600762306a36Sopenharmony_ci goto exit_boot_info; 600862306a36Sopenharmony_ci } 600962306a36Sopenharmony_ci 601062306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Primary target ID %d, Secondary" 601162306a36Sopenharmony_ci " target ID %d\n", __func__, ddb_index[0], 601262306a36Sopenharmony_ci ddb_index[1])); 601362306a36Sopenharmony_ci 601462306a36Sopenharmony_ciexit_boot_info_free: 601562306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, size, buf, buf_dma); 601662306a36Sopenharmony_ciexit_boot_info: 601762306a36Sopenharmony_ci ha->pri_ddb_idx = ddb_index[0]; 601862306a36Sopenharmony_ci ha->sec_ddb_idx = ddb_index[1]; 601962306a36Sopenharmony_ci return ret; 602062306a36Sopenharmony_ci} 602162306a36Sopenharmony_ci 602262306a36Sopenharmony_ci/** 602362306a36Sopenharmony_ci * qla4xxx_get_bidi_chap - Get a BIDI CHAP user and password 602462306a36Sopenharmony_ci * @ha: pointer to adapter structure 602562306a36Sopenharmony_ci * @username: CHAP username to be returned 602662306a36Sopenharmony_ci * @password: CHAP password to be returned 602762306a36Sopenharmony_ci * 602862306a36Sopenharmony_ci * If a boot entry has BIDI CHAP enabled then we need to set the BIDI CHAP 602962306a36Sopenharmony_ci * user and password in the sysfs entry in /sys/firmware/iscsi_boot#/. 603062306a36Sopenharmony_ci * So from the CHAP cache find the first BIDI CHAP entry and set it 603162306a36Sopenharmony_ci * to the boot record in sysfs. 603262306a36Sopenharmony_ci **/ 603362306a36Sopenharmony_cistatic int qla4xxx_get_bidi_chap(struct scsi_qla_host *ha, char *username, 603462306a36Sopenharmony_ci char *password) 603562306a36Sopenharmony_ci{ 603662306a36Sopenharmony_ci int i, ret = -EINVAL; 603762306a36Sopenharmony_ci int max_chap_entries = 0; 603862306a36Sopenharmony_ci struct ql4_chap_table *chap_table; 603962306a36Sopenharmony_ci 604062306a36Sopenharmony_ci if (is_qla80XX(ha)) 604162306a36Sopenharmony_ci max_chap_entries = (ha->hw.flt_chap_size / 2) / 604262306a36Sopenharmony_ci sizeof(struct ql4_chap_table); 604362306a36Sopenharmony_ci else 604462306a36Sopenharmony_ci max_chap_entries = MAX_CHAP_ENTRIES_40XX; 604562306a36Sopenharmony_ci 604662306a36Sopenharmony_ci if (!ha->chap_list) { 604762306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "Do not have CHAP table cache\n"); 604862306a36Sopenharmony_ci return ret; 604962306a36Sopenharmony_ci } 605062306a36Sopenharmony_ci 605162306a36Sopenharmony_ci mutex_lock(&ha->chap_sem); 605262306a36Sopenharmony_ci for (i = 0; i < max_chap_entries; i++) { 605362306a36Sopenharmony_ci chap_table = (struct ql4_chap_table *)ha->chap_list + i; 605462306a36Sopenharmony_ci if (chap_table->cookie != 605562306a36Sopenharmony_ci cpu_to_le16(CHAP_VALID_COOKIE)) { 605662306a36Sopenharmony_ci continue; 605762306a36Sopenharmony_ci } 605862306a36Sopenharmony_ci 605962306a36Sopenharmony_ci if (chap_table->flags & BIT_7) /* local */ 606062306a36Sopenharmony_ci continue; 606162306a36Sopenharmony_ci 606262306a36Sopenharmony_ci if (!(chap_table->flags & BIT_6)) /* Not BIDI */ 606362306a36Sopenharmony_ci continue; 606462306a36Sopenharmony_ci 606562306a36Sopenharmony_ci strscpy(password, chap_table->secret, QL4_CHAP_MAX_SECRET_LEN); 606662306a36Sopenharmony_ci strscpy(username, chap_table->name, QL4_CHAP_MAX_NAME_LEN); 606762306a36Sopenharmony_ci ret = 0; 606862306a36Sopenharmony_ci break; 606962306a36Sopenharmony_ci } 607062306a36Sopenharmony_ci mutex_unlock(&ha->chap_sem); 607162306a36Sopenharmony_ci 607262306a36Sopenharmony_ci return ret; 607362306a36Sopenharmony_ci} 607462306a36Sopenharmony_ci 607562306a36Sopenharmony_ci 607662306a36Sopenharmony_cistatic int qla4xxx_get_boot_target(struct scsi_qla_host *ha, 607762306a36Sopenharmony_ci struct ql4_boot_session_info *boot_sess, 607862306a36Sopenharmony_ci uint16_t ddb_index) 607962306a36Sopenharmony_ci{ 608062306a36Sopenharmony_ci struct ql4_conn_info *boot_conn = &boot_sess->conn_list[0]; 608162306a36Sopenharmony_ci struct dev_db_entry *fw_ddb_entry; 608262306a36Sopenharmony_ci dma_addr_t fw_ddb_entry_dma; 608362306a36Sopenharmony_ci uint16_t idx; 608462306a36Sopenharmony_ci uint16_t options; 608562306a36Sopenharmony_ci int ret = QLA_SUCCESS; 608662306a36Sopenharmony_ci 608762306a36Sopenharmony_ci fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), 608862306a36Sopenharmony_ci &fw_ddb_entry_dma, GFP_KERNEL); 608962306a36Sopenharmony_ci if (!fw_ddb_entry) { 609062306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_ERR, ha, 609162306a36Sopenharmony_ci "%s: Unable to allocate dma buffer.\n", 609262306a36Sopenharmony_ci __func__)); 609362306a36Sopenharmony_ci ret = QLA_ERROR; 609462306a36Sopenharmony_ci return ret; 609562306a36Sopenharmony_ci } 609662306a36Sopenharmony_ci 609762306a36Sopenharmony_ci if (qla4xxx_bootdb_by_index(ha, fw_ddb_entry, 609862306a36Sopenharmony_ci fw_ddb_entry_dma, ddb_index)) { 609962306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "%s: No Flash DDB found at " 610062306a36Sopenharmony_ci "index [%d]\n", __func__, ddb_index)); 610162306a36Sopenharmony_ci ret = QLA_ERROR; 610262306a36Sopenharmony_ci goto exit_boot_target; 610362306a36Sopenharmony_ci } 610462306a36Sopenharmony_ci 610562306a36Sopenharmony_ci /* Update target name and IP from DDB */ 610662306a36Sopenharmony_ci memcpy(boot_sess->target_name, fw_ddb_entry->iscsi_name, 610762306a36Sopenharmony_ci min(sizeof(boot_sess->target_name), 610862306a36Sopenharmony_ci sizeof(fw_ddb_entry->iscsi_name))); 610962306a36Sopenharmony_ci 611062306a36Sopenharmony_ci options = le16_to_cpu(fw_ddb_entry->options); 611162306a36Sopenharmony_ci if (options & DDB_OPT_IPV6_DEVICE) { 611262306a36Sopenharmony_ci memcpy(&boot_conn->dest_ipaddr.ip_address, 611362306a36Sopenharmony_ci &fw_ddb_entry->ip_addr[0], IPv6_ADDR_LEN); 611462306a36Sopenharmony_ci } else { 611562306a36Sopenharmony_ci boot_conn->dest_ipaddr.ip_type = 0x1; 611662306a36Sopenharmony_ci memcpy(&boot_conn->dest_ipaddr.ip_address, 611762306a36Sopenharmony_ci &fw_ddb_entry->ip_addr[0], IP_ADDR_LEN); 611862306a36Sopenharmony_ci } 611962306a36Sopenharmony_ci 612062306a36Sopenharmony_ci boot_conn->dest_port = le16_to_cpu(fw_ddb_entry->port); 612162306a36Sopenharmony_ci 612262306a36Sopenharmony_ci /* update chap information */ 612362306a36Sopenharmony_ci idx = __le16_to_cpu(fw_ddb_entry->chap_tbl_idx); 612462306a36Sopenharmony_ci 612562306a36Sopenharmony_ci if (BIT_7 & le16_to_cpu(fw_ddb_entry->iscsi_options)) { 612662306a36Sopenharmony_ci 612762306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "Setting chap\n")); 612862306a36Sopenharmony_ci 612962306a36Sopenharmony_ci ret = qla4xxx_get_chap(ha, (char *)&boot_conn->chap. 613062306a36Sopenharmony_ci target_chap_name, 613162306a36Sopenharmony_ci (char *)&boot_conn->chap.target_secret, 613262306a36Sopenharmony_ci idx); 613362306a36Sopenharmony_ci if (ret) { 613462306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "Failed to set chap\n"); 613562306a36Sopenharmony_ci ret = QLA_ERROR; 613662306a36Sopenharmony_ci goto exit_boot_target; 613762306a36Sopenharmony_ci } 613862306a36Sopenharmony_ci 613962306a36Sopenharmony_ci boot_conn->chap.target_chap_name_length = QL4_CHAP_MAX_NAME_LEN; 614062306a36Sopenharmony_ci boot_conn->chap.target_secret_length = QL4_CHAP_MAX_SECRET_LEN; 614162306a36Sopenharmony_ci } 614262306a36Sopenharmony_ci 614362306a36Sopenharmony_ci if (BIT_4 & le16_to_cpu(fw_ddb_entry->iscsi_options)) { 614462306a36Sopenharmony_ci 614562306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "Setting BIDI chap\n")); 614662306a36Sopenharmony_ci 614762306a36Sopenharmony_ci ret = qla4xxx_get_bidi_chap(ha, 614862306a36Sopenharmony_ci (char *)&boot_conn->chap.intr_chap_name, 614962306a36Sopenharmony_ci (char *)&boot_conn->chap.intr_secret); 615062306a36Sopenharmony_ci 615162306a36Sopenharmony_ci if (ret) { 615262306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "Failed to set BIDI chap\n"); 615362306a36Sopenharmony_ci ret = QLA_ERROR; 615462306a36Sopenharmony_ci goto exit_boot_target; 615562306a36Sopenharmony_ci } 615662306a36Sopenharmony_ci 615762306a36Sopenharmony_ci boot_conn->chap.intr_chap_name_length = QL4_CHAP_MAX_NAME_LEN; 615862306a36Sopenharmony_ci boot_conn->chap.intr_secret_length = QL4_CHAP_MAX_SECRET_LEN; 615962306a36Sopenharmony_ci } 616062306a36Sopenharmony_ci 616162306a36Sopenharmony_ciexit_boot_target: 616262306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), 616362306a36Sopenharmony_ci fw_ddb_entry, fw_ddb_entry_dma); 616462306a36Sopenharmony_ci return ret; 616562306a36Sopenharmony_ci} 616662306a36Sopenharmony_ci 616762306a36Sopenharmony_cistatic int qla4xxx_get_boot_info(struct scsi_qla_host *ha) 616862306a36Sopenharmony_ci{ 616962306a36Sopenharmony_ci uint16_t ddb_index[2]; 617062306a36Sopenharmony_ci int ret = QLA_ERROR; 617162306a36Sopenharmony_ci int rval; 617262306a36Sopenharmony_ci 617362306a36Sopenharmony_ci memset(ddb_index, 0, sizeof(ddb_index)); 617462306a36Sopenharmony_ci ddb_index[0] = 0xffff; 617562306a36Sopenharmony_ci ddb_index[1] = 0xffff; 617662306a36Sopenharmony_ci ret = get_fw_boot_info(ha, ddb_index); 617762306a36Sopenharmony_ci if (ret != QLA_SUCCESS) { 617862306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 617962306a36Sopenharmony_ci "%s: No boot target configured.\n", __func__)); 618062306a36Sopenharmony_ci return ret; 618162306a36Sopenharmony_ci } 618262306a36Sopenharmony_ci 618362306a36Sopenharmony_ci if (ql4xdisablesysfsboot) 618462306a36Sopenharmony_ci return QLA_SUCCESS; 618562306a36Sopenharmony_ci 618662306a36Sopenharmony_ci if (ddb_index[0] == 0xffff) 618762306a36Sopenharmony_ci goto sec_target; 618862306a36Sopenharmony_ci 618962306a36Sopenharmony_ci rval = qla4xxx_get_boot_target(ha, &(ha->boot_tgt.boot_pri_sess), 619062306a36Sopenharmony_ci ddb_index[0]); 619162306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 619262306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Primary boot target not " 619362306a36Sopenharmony_ci "configured\n", __func__)); 619462306a36Sopenharmony_ci } else 619562306a36Sopenharmony_ci ret = QLA_SUCCESS; 619662306a36Sopenharmony_ci 619762306a36Sopenharmony_cisec_target: 619862306a36Sopenharmony_ci if (ddb_index[1] == 0xffff) 619962306a36Sopenharmony_ci goto exit_get_boot_info; 620062306a36Sopenharmony_ci 620162306a36Sopenharmony_ci rval = qla4xxx_get_boot_target(ha, &(ha->boot_tgt.boot_sec_sess), 620262306a36Sopenharmony_ci ddb_index[1]); 620362306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 620462306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Secondary boot target not" 620562306a36Sopenharmony_ci " configured\n", __func__)); 620662306a36Sopenharmony_ci } else 620762306a36Sopenharmony_ci ret = QLA_SUCCESS; 620862306a36Sopenharmony_ci 620962306a36Sopenharmony_ciexit_get_boot_info: 621062306a36Sopenharmony_ci return ret; 621162306a36Sopenharmony_ci} 621262306a36Sopenharmony_ci 621362306a36Sopenharmony_cistatic int qla4xxx_setup_boot_info(struct scsi_qla_host *ha) 621462306a36Sopenharmony_ci{ 621562306a36Sopenharmony_ci struct iscsi_boot_kobj *boot_kobj; 621662306a36Sopenharmony_ci 621762306a36Sopenharmony_ci if (qla4xxx_get_boot_info(ha) != QLA_SUCCESS) 621862306a36Sopenharmony_ci return QLA_ERROR; 621962306a36Sopenharmony_ci 622062306a36Sopenharmony_ci if (ql4xdisablesysfsboot) { 622162306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, 622262306a36Sopenharmony_ci "%s: syfsboot disabled - driver will trigger login " 622362306a36Sopenharmony_ci "and publish session for discovery .\n", __func__); 622462306a36Sopenharmony_ci return QLA_SUCCESS; 622562306a36Sopenharmony_ci } 622662306a36Sopenharmony_ci 622762306a36Sopenharmony_ci 622862306a36Sopenharmony_ci ha->boot_kset = iscsi_boot_create_host_kset(ha->host->host_no); 622962306a36Sopenharmony_ci if (!ha->boot_kset) 623062306a36Sopenharmony_ci goto kset_free; 623162306a36Sopenharmony_ci 623262306a36Sopenharmony_ci if (!scsi_host_get(ha->host)) 623362306a36Sopenharmony_ci goto kset_free; 623462306a36Sopenharmony_ci boot_kobj = iscsi_boot_create_target(ha->boot_kset, 0, ha, 623562306a36Sopenharmony_ci qla4xxx_show_boot_tgt_pri_info, 623662306a36Sopenharmony_ci qla4xxx_tgt_get_attr_visibility, 623762306a36Sopenharmony_ci qla4xxx_boot_release); 623862306a36Sopenharmony_ci if (!boot_kobj) 623962306a36Sopenharmony_ci goto put_host; 624062306a36Sopenharmony_ci 624162306a36Sopenharmony_ci if (!scsi_host_get(ha->host)) 624262306a36Sopenharmony_ci goto kset_free; 624362306a36Sopenharmony_ci boot_kobj = iscsi_boot_create_target(ha->boot_kset, 1, ha, 624462306a36Sopenharmony_ci qla4xxx_show_boot_tgt_sec_info, 624562306a36Sopenharmony_ci qla4xxx_tgt_get_attr_visibility, 624662306a36Sopenharmony_ci qla4xxx_boot_release); 624762306a36Sopenharmony_ci if (!boot_kobj) 624862306a36Sopenharmony_ci goto put_host; 624962306a36Sopenharmony_ci 625062306a36Sopenharmony_ci if (!scsi_host_get(ha->host)) 625162306a36Sopenharmony_ci goto kset_free; 625262306a36Sopenharmony_ci boot_kobj = iscsi_boot_create_initiator(ha->boot_kset, 0, ha, 625362306a36Sopenharmony_ci qla4xxx_show_boot_ini_info, 625462306a36Sopenharmony_ci qla4xxx_ini_get_attr_visibility, 625562306a36Sopenharmony_ci qla4xxx_boot_release); 625662306a36Sopenharmony_ci if (!boot_kobj) 625762306a36Sopenharmony_ci goto put_host; 625862306a36Sopenharmony_ci 625962306a36Sopenharmony_ci if (!scsi_host_get(ha->host)) 626062306a36Sopenharmony_ci goto kset_free; 626162306a36Sopenharmony_ci boot_kobj = iscsi_boot_create_ethernet(ha->boot_kset, 0, ha, 626262306a36Sopenharmony_ci qla4xxx_show_boot_eth_info, 626362306a36Sopenharmony_ci qla4xxx_eth_get_attr_visibility, 626462306a36Sopenharmony_ci qla4xxx_boot_release); 626562306a36Sopenharmony_ci if (!boot_kobj) 626662306a36Sopenharmony_ci goto put_host; 626762306a36Sopenharmony_ci 626862306a36Sopenharmony_ci return QLA_SUCCESS; 626962306a36Sopenharmony_ci 627062306a36Sopenharmony_ciput_host: 627162306a36Sopenharmony_ci scsi_host_put(ha->host); 627262306a36Sopenharmony_cikset_free: 627362306a36Sopenharmony_ci iscsi_boot_destroy_kset(ha->boot_kset); 627462306a36Sopenharmony_ci return -ENOMEM; 627562306a36Sopenharmony_ci} 627662306a36Sopenharmony_ci 627762306a36Sopenharmony_ci 627862306a36Sopenharmony_cistatic void qla4xxx_get_param_ddb(struct ddb_entry *ddb_entry, 627962306a36Sopenharmony_ci struct ql4_tuple_ddb *tddb) 628062306a36Sopenharmony_ci{ 628162306a36Sopenharmony_ci struct iscsi_cls_session *cls_sess; 628262306a36Sopenharmony_ci struct iscsi_cls_conn *cls_conn; 628362306a36Sopenharmony_ci struct iscsi_session *sess; 628462306a36Sopenharmony_ci struct iscsi_conn *conn; 628562306a36Sopenharmony_ci 628662306a36Sopenharmony_ci DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); 628762306a36Sopenharmony_ci cls_sess = ddb_entry->sess; 628862306a36Sopenharmony_ci sess = cls_sess->dd_data; 628962306a36Sopenharmony_ci cls_conn = ddb_entry->conn; 629062306a36Sopenharmony_ci conn = cls_conn->dd_data; 629162306a36Sopenharmony_ci 629262306a36Sopenharmony_ci tddb->tpgt = sess->tpgt; 629362306a36Sopenharmony_ci tddb->port = conn->persistent_port; 629462306a36Sopenharmony_ci strscpy(tddb->iscsi_name, sess->targetname, ISCSI_NAME_SIZE); 629562306a36Sopenharmony_ci strscpy(tddb->ip_addr, conn->persistent_address, DDB_IPADDR_LEN); 629662306a36Sopenharmony_ci} 629762306a36Sopenharmony_ci 629862306a36Sopenharmony_cistatic void qla4xxx_convert_param_ddb(struct dev_db_entry *fw_ddb_entry, 629962306a36Sopenharmony_ci struct ql4_tuple_ddb *tddb, 630062306a36Sopenharmony_ci uint8_t *flash_isid) 630162306a36Sopenharmony_ci{ 630262306a36Sopenharmony_ci uint16_t options = 0; 630362306a36Sopenharmony_ci 630462306a36Sopenharmony_ci tddb->tpgt = le32_to_cpu(fw_ddb_entry->tgt_portal_grp); 630562306a36Sopenharmony_ci memcpy(&tddb->iscsi_name[0], &fw_ddb_entry->iscsi_name[0], 630662306a36Sopenharmony_ci min(sizeof(tddb->iscsi_name), sizeof(fw_ddb_entry->iscsi_name))); 630762306a36Sopenharmony_ci 630862306a36Sopenharmony_ci options = le16_to_cpu(fw_ddb_entry->options); 630962306a36Sopenharmony_ci if (options & DDB_OPT_IPV6_DEVICE) 631062306a36Sopenharmony_ci sprintf(tddb->ip_addr, "%pI6", fw_ddb_entry->ip_addr); 631162306a36Sopenharmony_ci else 631262306a36Sopenharmony_ci sprintf(tddb->ip_addr, "%pI4", fw_ddb_entry->ip_addr); 631362306a36Sopenharmony_ci 631462306a36Sopenharmony_ci tddb->port = le16_to_cpu(fw_ddb_entry->port); 631562306a36Sopenharmony_ci 631662306a36Sopenharmony_ci if (flash_isid == NULL) 631762306a36Sopenharmony_ci memcpy(&tddb->isid[0], &fw_ddb_entry->isid[0], 631862306a36Sopenharmony_ci sizeof(tddb->isid)); 631962306a36Sopenharmony_ci else 632062306a36Sopenharmony_ci memcpy(&tddb->isid[0], &flash_isid[0], sizeof(tddb->isid)); 632162306a36Sopenharmony_ci} 632262306a36Sopenharmony_ci 632362306a36Sopenharmony_cistatic int qla4xxx_compare_tuple_ddb(struct scsi_qla_host *ha, 632462306a36Sopenharmony_ci struct ql4_tuple_ddb *old_tddb, 632562306a36Sopenharmony_ci struct ql4_tuple_ddb *new_tddb, 632662306a36Sopenharmony_ci uint8_t is_isid_compare) 632762306a36Sopenharmony_ci{ 632862306a36Sopenharmony_ci if (strcmp(old_tddb->iscsi_name, new_tddb->iscsi_name)) 632962306a36Sopenharmony_ci return QLA_ERROR; 633062306a36Sopenharmony_ci 633162306a36Sopenharmony_ci if (strcmp(old_tddb->ip_addr, new_tddb->ip_addr)) 633262306a36Sopenharmony_ci return QLA_ERROR; 633362306a36Sopenharmony_ci 633462306a36Sopenharmony_ci if (old_tddb->port != new_tddb->port) 633562306a36Sopenharmony_ci return QLA_ERROR; 633662306a36Sopenharmony_ci 633762306a36Sopenharmony_ci /* For multi sessions, driver generates the ISID, so do not compare 633862306a36Sopenharmony_ci * ISID in reset path since it would be a comparison between the 633962306a36Sopenharmony_ci * driver generated ISID and firmware generated ISID. This could 634062306a36Sopenharmony_ci * lead to adding duplicated DDBs in the list as driver generated 634162306a36Sopenharmony_ci * ISID would not match firmware generated ISID. 634262306a36Sopenharmony_ci */ 634362306a36Sopenharmony_ci if (is_isid_compare) { 634462306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 634562306a36Sopenharmony_ci "%s: old ISID [%pmR] New ISID [%pmR]\n", 634662306a36Sopenharmony_ci __func__, old_tddb->isid, new_tddb->isid)); 634762306a36Sopenharmony_ci 634862306a36Sopenharmony_ci if (memcmp(&old_tddb->isid[0], &new_tddb->isid[0], 634962306a36Sopenharmony_ci sizeof(old_tddb->isid))) 635062306a36Sopenharmony_ci return QLA_ERROR; 635162306a36Sopenharmony_ci } 635262306a36Sopenharmony_ci 635362306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 635462306a36Sopenharmony_ci "Match Found, fw[%d,%d,%s,%s], [%d,%d,%s,%s]", 635562306a36Sopenharmony_ci old_tddb->port, old_tddb->tpgt, old_tddb->ip_addr, 635662306a36Sopenharmony_ci old_tddb->iscsi_name, new_tddb->port, new_tddb->tpgt, 635762306a36Sopenharmony_ci new_tddb->ip_addr, new_tddb->iscsi_name)); 635862306a36Sopenharmony_ci 635962306a36Sopenharmony_ci return QLA_SUCCESS; 636062306a36Sopenharmony_ci} 636162306a36Sopenharmony_ci 636262306a36Sopenharmony_cistatic int qla4xxx_is_session_exists(struct scsi_qla_host *ha, 636362306a36Sopenharmony_ci struct dev_db_entry *fw_ddb_entry, 636462306a36Sopenharmony_ci uint32_t *index) 636562306a36Sopenharmony_ci{ 636662306a36Sopenharmony_ci struct ddb_entry *ddb_entry; 636762306a36Sopenharmony_ci struct ql4_tuple_ddb *fw_tddb = NULL; 636862306a36Sopenharmony_ci struct ql4_tuple_ddb *tmp_tddb = NULL; 636962306a36Sopenharmony_ci int idx; 637062306a36Sopenharmony_ci int ret = QLA_ERROR; 637162306a36Sopenharmony_ci 637262306a36Sopenharmony_ci fw_tddb = vzalloc(sizeof(*fw_tddb)); 637362306a36Sopenharmony_ci if (!fw_tddb) { 637462306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_WARNING, ha, 637562306a36Sopenharmony_ci "Memory Allocation failed.\n")); 637662306a36Sopenharmony_ci ret = QLA_SUCCESS; 637762306a36Sopenharmony_ci goto exit_check; 637862306a36Sopenharmony_ci } 637962306a36Sopenharmony_ci 638062306a36Sopenharmony_ci tmp_tddb = vzalloc(sizeof(*tmp_tddb)); 638162306a36Sopenharmony_ci if (!tmp_tddb) { 638262306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_WARNING, ha, 638362306a36Sopenharmony_ci "Memory Allocation failed.\n")); 638462306a36Sopenharmony_ci ret = QLA_SUCCESS; 638562306a36Sopenharmony_ci goto exit_check; 638662306a36Sopenharmony_ci } 638762306a36Sopenharmony_ci 638862306a36Sopenharmony_ci qla4xxx_convert_param_ddb(fw_ddb_entry, fw_tddb, NULL); 638962306a36Sopenharmony_ci 639062306a36Sopenharmony_ci for (idx = 0; idx < MAX_DDB_ENTRIES; idx++) { 639162306a36Sopenharmony_ci ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx); 639262306a36Sopenharmony_ci if (ddb_entry == NULL) 639362306a36Sopenharmony_ci continue; 639462306a36Sopenharmony_ci 639562306a36Sopenharmony_ci qla4xxx_get_param_ddb(ddb_entry, tmp_tddb); 639662306a36Sopenharmony_ci if (!qla4xxx_compare_tuple_ddb(ha, fw_tddb, tmp_tddb, false)) { 639762306a36Sopenharmony_ci ret = QLA_SUCCESS; /* found */ 639862306a36Sopenharmony_ci if (index != NULL) 639962306a36Sopenharmony_ci *index = idx; 640062306a36Sopenharmony_ci goto exit_check; 640162306a36Sopenharmony_ci } 640262306a36Sopenharmony_ci } 640362306a36Sopenharmony_ci 640462306a36Sopenharmony_ciexit_check: 640562306a36Sopenharmony_ci vfree(fw_tddb); 640662306a36Sopenharmony_ci vfree(tmp_tddb); 640762306a36Sopenharmony_ci return ret; 640862306a36Sopenharmony_ci} 640962306a36Sopenharmony_ci 641062306a36Sopenharmony_ci/** 641162306a36Sopenharmony_ci * qla4xxx_check_existing_isid - check if target with same isid exist 641262306a36Sopenharmony_ci * in target list 641362306a36Sopenharmony_ci * @list_nt: list of target 641462306a36Sopenharmony_ci * @isid: isid to check 641562306a36Sopenharmony_ci * 641662306a36Sopenharmony_ci * This routine return QLA_SUCCESS if target with same isid exist 641762306a36Sopenharmony_ci **/ 641862306a36Sopenharmony_cistatic int qla4xxx_check_existing_isid(struct list_head *list_nt, uint8_t *isid) 641962306a36Sopenharmony_ci{ 642062306a36Sopenharmony_ci struct qla_ddb_index *nt_ddb_idx, *nt_ddb_idx_tmp; 642162306a36Sopenharmony_ci struct dev_db_entry *fw_ddb_entry; 642262306a36Sopenharmony_ci 642362306a36Sopenharmony_ci list_for_each_entry_safe(nt_ddb_idx, nt_ddb_idx_tmp, list_nt, list) { 642462306a36Sopenharmony_ci fw_ddb_entry = &nt_ddb_idx->fw_ddb; 642562306a36Sopenharmony_ci 642662306a36Sopenharmony_ci if (memcmp(&fw_ddb_entry->isid[0], &isid[0], 642762306a36Sopenharmony_ci sizeof(nt_ddb_idx->fw_ddb.isid)) == 0) { 642862306a36Sopenharmony_ci return QLA_SUCCESS; 642962306a36Sopenharmony_ci } 643062306a36Sopenharmony_ci } 643162306a36Sopenharmony_ci return QLA_ERROR; 643262306a36Sopenharmony_ci} 643362306a36Sopenharmony_ci 643462306a36Sopenharmony_ci/** 643562306a36Sopenharmony_ci * qla4xxx_update_isid - compare ddbs and updated isid 643662306a36Sopenharmony_ci * @ha: Pointer to host adapter structure. 643762306a36Sopenharmony_ci * @list_nt: list of nt target 643862306a36Sopenharmony_ci * @fw_ddb_entry: firmware ddb entry 643962306a36Sopenharmony_ci * 644062306a36Sopenharmony_ci * This routine update isid if ddbs have same iqn, same isid and 644162306a36Sopenharmony_ci * different IP addr. 644262306a36Sopenharmony_ci * Return QLA_SUCCESS if isid is updated. 644362306a36Sopenharmony_ci **/ 644462306a36Sopenharmony_cistatic int qla4xxx_update_isid(struct scsi_qla_host *ha, 644562306a36Sopenharmony_ci struct list_head *list_nt, 644662306a36Sopenharmony_ci struct dev_db_entry *fw_ddb_entry) 644762306a36Sopenharmony_ci{ 644862306a36Sopenharmony_ci uint8_t base_value, i; 644962306a36Sopenharmony_ci 645062306a36Sopenharmony_ci base_value = fw_ddb_entry->isid[1] & 0x1f; 645162306a36Sopenharmony_ci for (i = 0; i < 8; i++) { 645262306a36Sopenharmony_ci fw_ddb_entry->isid[1] = (base_value | (i << 5)); 645362306a36Sopenharmony_ci if (qla4xxx_check_existing_isid(list_nt, fw_ddb_entry->isid)) 645462306a36Sopenharmony_ci break; 645562306a36Sopenharmony_ci } 645662306a36Sopenharmony_ci 645762306a36Sopenharmony_ci if (!qla4xxx_check_existing_isid(list_nt, fw_ddb_entry->isid)) 645862306a36Sopenharmony_ci return QLA_ERROR; 645962306a36Sopenharmony_ci 646062306a36Sopenharmony_ci return QLA_SUCCESS; 646162306a36Sopenharmony_ci} 646262306a36Sopenharmony_ci 646362306a36Sopenharmony_ci/** 646462306a36Sopenharmony_ci * qla4xxx_should_update_isid - check if isid need to update 646562306a36Sopenharmony_ci * @ha: Pointer to host adapter structure. 646662306a36Sopenharmony_ci * @old_tddb: ddb tuple 646762306a36Sopenharmony_ci * @new_tddb: ddb tuple 646862306a36Sopenharmony_ci * 646962306a36Sopenharmony_ci * Return QLA_SUCCESS if different IP, different PORT, same iqn, 647062306a36Sopenharmony_ci * same isid 647162306a36Sopenharmony_ci **/ 647262306a36Sopenharmony_cistatic int qla4xxx_should_update_isid(struct scsi_qla_host *ha, 647362306a36Sopenharmony_ci struct ql4_tuple_ddb *old_tddb, 647462306a36Sopenharmony_ci struct ql4_tuple_ddb *new_tddb) 647562306a36Sopenharmony_ci{ 647662306a36Sopenharmony_ci if (strcmp(old_tddb->ip_addr, new_tddb->ip_addr) == 0) { 647762306a36Sopenharmony_ci /* Same ip */ 647862306a36Sopenharmony_ci if (old_tddb->port == new_tddb->port) 647962306a36Sopenharmony_ci return QLA_ERROR; 648062306a36Sopenharmony_ci } 648162306a36Sopenharmony_ci 648262306a36Sopenharmony_ci if (strcmp(old_tddb->iscsi_name, new_tddb->iscsi_name)) 648362306a36Sopenharmony_ci /* different iqn */ 648462306a36Sopenharmony_ci return QLA_ERROR; 648562306a36Sopenharmony_ci 648662306a36Sopenharmony_ci if (memcmp(&old_tddb->isid[0], &new_tddb->isid[0], 648762306a36Sopenharmony_ci sizeof(old_tddb->isid))) 648862306a36Sopenharmony_ci /* different isid */ 648962306a36Sopenharmony_ci return QLA_ERROR; 649062306a36Sopenharmony_ci 649162306a36Sopenharmony_ci return QLA_SUCCESS; 649262306a36Sopenharmony_ci} 649362306a36Sopenharmony_ci 649462306a36Sopenharmony_ci/** 649562306a36Sopenharmony_ci * qla4xxx_is_flash_ddb_exists - check if fw_ddb_entry already exists in list_nt 649662306a36Sopenharmony_ci * @ha: Pointer to host adapter structure. 649762306a36Sopenharmony_ci * @list_nt: list of nt target. 649862306a36Sopenharmony_ci * @fw_ddb_entry: firmware ddb entry. 649962306a36Sopenharmony_ci * 650062306a36Sopenharmony_ci * This routine check if fw_ddb_entry already exists in list_nt to avoid 650162306a36Sopenharmony_ci * duplicate ddb in list_nt. 650262306a36Sopenharmony_ci * Return QLA_SUCCESS if duplicate ddb exit in list_nl. 650362306a36Sopenharmony_ci * Note: This function also update isid of DDB if required. 650462306a36Sopenharmony_ci **/ 650562306a36Sopenharmony_ci 650662306a36Sopenharmony_cistatic int qla4xxx_is_flash_ddb_exists(struct scsi_qla_host *ha, 650762306a36Sopenharmony_ci struct list_head *list_nt, 650862306a36Sopenharmony_ci struct dev_db_entry *fw_ddb_entry) 650962306a36Sopenharmony_ci{ 651062306a36Sopenharmony_ci struct qla_ddb_index *nt_ddb_idx, *nt_ddb_idx_tmp; 651162306a36Sopenharmony_ci struct ql4_tuple_ddb *fw_tddb = NULL; 651262306a36Sopenharmony_ci struct ql4_tuple_ddb *tmp_tddb = NULL; 651362306a36Sopenharmony_ci int rval, ret = QLA_ERROR; 651462306a36Sopenharmony_ci 651562306a36Sopenharmony_ci fw_tddb = vzalloc(sizeof(*fw_tddb)); 651662306a36Sopenharmony_ci if (!fw_tddb) { 651762306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_WARNING, ha, 651862306a36Sopenharmony_ci "Memory Allocation failed.\n")); 651962306a36Sopenharmony_ci ret = QLA_SUCCESS; 652062306a36Sopenharmony_ci goto exit_check; 652162306a36Sopenharmony_ci } 652262306a36Sopenharmony_ci 652362306a36Sopenharmony_ci tmp_tddb = vzalloc(sizeof(*tmp_tddb)); 652462306a36Sopenharmony_ci if (!tmp_tddb) { 652562306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_WARNING, ha, 652662306a36Sopenharmony_ci "Memory Allocation failed.\n")); 652762306a36Sopenharmony_ci ret = QLA_SUCCESS; 652862306a36Sopenharmony_ci goto exit_check; 652962306a36Sopenharmony_ci } 653062306a36Sopenharmony_ci 653162306a36Sopenharmony_ci qla4xxx_convert_param_ddb(fw_ddb_entry, fw_tddb, NULL); 653262306a36Sopenharmony_ci 653362306a36Sopenharmony_ci list_for_each_entry_safe(nt_ddb_idx, nt_ddb_idx_tmp, list_nt, list) { 653462306a36Sopenharmony_ci qla4xxx_convert_param_ddb(&nt_ddb_idx->fw_ddb, tmp_tddb, 653562306a36Sopenharmony_ci nt_ddb_idx->flash_isid); 653662306a36Sopenharmony_ci ret = qla4xxx_compare_tuple_ddb(ha, fw_tddb, tmp_tddb, true); 653762306a36Sopenharmony_ci /* found duplicate ddb */ 653862306a36Sopenharmony_ci if (ret == QLA_SUCCESS) 653962306a36Sopenharmony_ci goto exit_check; 654062306a36Sopenharmony_ci } 654162306a36Sopenharmony_ci 654262306a36Sopenharmony_ci list_for_each_entry_safe(nt_ddb_idx, nt_ddb_idx_tmp, list_nt, list) { 654362306a36Sopenharmony_ci qla4xxx_convert_param_ddb(&nt_ddb_idx->fw_ddb, tmp_tddb, NULL); 654462306a36Sopenharmony_ci 654562306a36Sopenharmony_ci ret = qla4xxx_should_update_isid(ha, tmp_tddb, fw_tddb); 654662306a36Sopenharmony_ci if (ret == QLA_SUCCESS) { 654762306a36Sopenharmony_ci rval = qla4xxx_update_isid(ha, list_nt, fw_ddb_entry); 654862306a36Sopenharmony_ci if (rval == QLA_SUCCESS) 654962306a36Sopenharmony_ci ret = QLA_ERROR; 655062306a36Sopenharmony_ci else 655162306a36Sopenharmony_ci ret = QLA_SUCCESS; 655262306a36Sopenharmony_ci 655362306a36Sopenharmony_ci goto exit_check; 655462306a36Sopenharmony_ci } 655562306a36Sopenharmony_ci } 655662306a36Sopenharmony_ci 655762306a36Sopenharmony_ciexit_check: 655862306a36Sopenharmony_ci vfree(fw_tddb); 655962306a36Sopenharmony_ci vfree(tmp_tddb); 656062306a36Sopenharmony_ci return ret; 656162306a36Sopenharmony_ci} 656262306a36Sopenharmony_ci 656362306a36Sopenharmony_cistatic void qla4xxx_free_ddb_list(struct list_head *list_ddb) 656462306a36Sopenharmony_ci{ 656562306a36Sopenharmony_ci struct qla_ddb_index *ddb_idx, *ddb_idx_tmp; 656662306a36Sopenharmony_ci 656762306a36Sopenharmony_ci list_for_each_entry_safe(ddb_idx, ddb_idx_tmp, list_ddb, list) { 656862306a36Sopenharmony_ci list_del_init(&ddb_idx->list); 656962306a36Sopenharmony_ci vfree(ddb_idx); 657062306a36Sopenharmony_ci } 657162306a36Sopenharmony_ci} 657262306a36Sopenharmony_ci 657362306a36Sopenharmony_cistatic struct iscsi_endpoint *qla4xxx_get_ep_fwdb(struct scsi_qla_host *ha, 657462306a36Sopenharmony_ci struct dev_db_entry *fw_ddb_entry) 657562306a36Sopenharmony_ci{ 657662306a36Sopenharmony_ci struct iscsi_endpoint *ep; 657762306a36Sopenharmony_ci struct sockaddr_in *addr; 657862306a36Sopenharmony_ci struct sockaddr_in6 *addr6; 657962306a36Sopenharmony_ci struct sockaddr *t_addr; 658062306a36Sopenharmony_ci struct sockaddr_storage *dst_addr; 658162306a36Sopenharmony_ci char *ip; 658262306a36Sopenharmony_ci 658362306a36Sopenharmony_ci /* TODO: need to destroy on unload iscsi_endpoint*/ 658462306a36Sopenharmony_ci dst_addr = vmalloc(sizeof(*dst_addr)); 658562306a36Sopenharmony_ci if (!dst_addr) 658662306a36Sopenharmony_ci return NULL; 658762306a36Sopenharmony_ci 658862306a36Sopenharmony_ci if (fw_ddb_entry->options & DDB_OPT_IPV6_DEVICE) { 658962306a36Sopenharmony_ci t_addr = (struct sockaddr *)dst_addr; 659062306a36Sopenharmony_ci t_addr->sa_family = AF_INET6; 659162306a36Sopenharmony_ci addr6 = (struct sockaddr_in6 *)dst_addr; 659262306a36Sopenharmony_ci ip = (char *)&addr6->sin6_addr; 659362306a36Sopenharmony_ci memcpy(ip, fw_ddb_entry->ip_addr, IPv6_ADDR_LEN); 659462306a36Sopenharmony_ci addr6->sin6_port = htons(le16_to_cpu(fw_ddb_entry->port)); 659562306a36Sopenharmony_ci 659662306a36Sopenharmony_ci } else { 659762306a36Sopenharmony_ci t_addr = (struct sockaddr *)dst_addr; 659862306a36Sopenharmony_ci t_addr->sa_family = AF_INET; 659962306a36Sopenharmony_ci addr = (struct sockaddr_in *)dst_addr; 660062306a36Sopenharmony_ci ip = (char *)&addr->sin_addr; 660162306a36Sopenharmony_ci memcpy(ip, fw_ddb_entry->ip_addr, IP_ADDR_LEN); 660262306a36Sopenharmony_ci addr->sin_port = htons(le16_to_cpu(fw_ddb_entry->port)); 660362306a36Sopenharmony_ci } 660462306a36Sopenharmony_ci 660562306a36Sopenharmony_ci ep = qla4xxx_ep_connect(ha->host, (struct sockaddr *)dst_addr, 0); 660662306a36Sopenharmony_ci vfree(dst_addr); 660762306a36Sopenharmony_ci return ep; 660862306a36Sopenharmony_ci} 660962306a36Sopenharmony_ci 661062306a36Sopenharmony_cistatic int qla4xxx_verify_boot_idx(struct scsi_qla_host *ha, uint16_t idx) 661162306a36Sopenharmony_ci{ 661262306a36Sopenharmony_ci if (ql4xdisablesysfsboot) 661362306a36Sopenharmony_ci return QLA_SUCCESS; 661462306a36Sopenharmony_ci if (idx == ha->pri_ddb_idx || idx == ha->sec_ddb_idx) 661562306a36Sopenharmony_ci return QLA_ERROR; 661662306a36Sopenharmony_ci return QLA_SUCCESS; 661762306a36Sopenharmony_ci} 661862306a36Sopenharmony_ci 661962306a36Sopenharmony_cistatic void qla4xxx_setup_flash_ddb_entry(struct scsi_qla_host *ha, 662062306a36Sopenharmony_ci struct ddb_entry *ddb_entry, 662162306a36Sopenharmony_ci uint16_t idx) 662262306a36Sopenharmony_ci{ 662362306a36Sopenharmony_ci uint16_t def_timeout; 662462306a36Sopenharmony_ci 662562306a36Sopenharmony_ci ddb_entry->ddb_type = FLASH_DDB; 662662306a36Sopenharmony_ci ddb_entry->fw_ddb_index = INVALID_ENTRY; 662762306a36Sopenharmony_ci ddb_entry->fw_ddb_device_state = DDB_DS_NO_CONNECTION_ACTIVE; 662862306a36Sopenharmony_ci ddb_entry->ha = ha; 662962306a36Sopenharmony_ci ddb_entry->unblock_sess = qla4xxx_unblock_flash_ddb; 663062306a36Sopenharmony_ci ddb_entry->ddb_change = qla4xxx_flash_ddb_change; 663162306a36Sopenharmony_ci ddb_entry->chap_tbl_idx = INVALID_ENTRY; 663262306a36Sopenharmony_ci 663362306a36Sopenharmony_ci atomic_set(&ddb_entry->retry_relogin_timer, INVALID_ENTRY); 663462306a36Sopenharmony_ci atomic_set(&ddb_entry->relogin_timer, 0); 663562306a36Sopenharmony_ci atomic_set(&ddb_entry->relogin_retry_count, 0); 663662306a36Sopenharmony_ci def_timeout = le16_to_cpu(ddb_entry->fw_ddb_entry.def_timeout); 663762306a36Sopenharmony_ci ddb_entry->default_relogin_timeout = 663862306a36Sopenharmony_ci (def_timeout > LOGIN_TOV) && (def_timeout < LOGIN_TOV * 10) ? 663962306a36Sopenharmony_ci def_timeout : LOGIN_TOV; 664062306a36Sopenharmony_ci ddb_entry->default_time2wait = 664162306a36Sopenharmony_ci le16_to_cpu(ddb_entry->fw_ddb_entry.iscsi_def_time2wait); 664262306a36Sopenharmony_ci 664362306a36Sopenharmony_ci if (ql4xdisablesysfsboot && 664462306a36Sopenharmony_ci (idx == ha->pri_ddb_idx || idx == ha->sec_ddb_idx)) 664562306a36Sopenharmony_ci set_bit(DF_BOOT_TGT, &ddb_entry->flags); 664662306a36Sopenharmony_ci} 664762306a36Sopenharmony_ci 664862306a36Sopenharmony_cistatic void qla4xxx_wait_for_ip_configuration(struct scsi_qla_host *ha) 664962306a36Sopenharmony_ci{ 665062306a36Sopenharmony_ci uint32_t idx = 0; 665162306a36Sopenharmony_ci uint32_t ip_idx[IP_ADDR_COUNT] = {0, 1, 2, 3}; /* 4 IP interfaces */ 665262306a36Sopenharmony_ci uint32_t sts[MBOX_REG_COUNT]; 665362306a36Sopenharmony_ci uint32_t ip_state; 665462306a36Sopenharmony_ci unsigned long wtime; 665562306a36Sopenharmony_ci int ret; 665662306a36Sopenharmony_ci 665762306a36Sopenharmony_ci wtime = jiffies + (HZ * IP_CONFIG_TOV); 665862306a36Sopenharmony_ci do { 665962306a36Sopenharmony_ci for (idx = 0; idx < IP_ADDR_COUNT; idx++) { 666062306a36Sopenharmony_ci if (ip_idx[idx] == -1) 666162306a36Sopenharmony_ci continue; 666262306a36Sopenharmony_ci 666362306a36Sopenharmony_ci ret = qla4xxx_get_ip_state(ha, 0, ip_idx[idx], sts); 666462306a36Sopenharmony_ci 666562306a36Sopenharmony_ci if (ret == QLA_ERROR) { 666662306a36Sopenharmony_ci ip_idx[idx] = -1; 666762306a36Sopenharmony_ci continue; 666862306a36Sopenharmony_ci } 666962306a36Sopenharmony_ci 667062306a36Sopenharmony_ci ip_state = (sts[1] & IP_STATE_MASK) >> IP_STATE_SHIFT; 667162306a36Sopenharmony_ci 667262306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 667362306a36Sopenharmony_ci "Waiting for IP state for idx = %d, state = 0x%x\n", 667462306a36Sopenharmony_ci ip_idx[idx], ip_state)); 667562306a36Sopenharmony_ci if (ip_state == IP_ADDRSTATE_UNCONFIGURED || 667662306a36Sopenharmony_ci ip_state == IP_ADDRSTATE_INVALID || 667762306a36Sopenharmony_ci ip_state == IP_ADDRSTATE_PREFERRED || 667862306a36Sopenharmony_ci ip_state == IP_ADDRSTATE_DEPRICATED || 667962306a36Sopenharmony_ci ip_state == IP_ADDRSTATE_DISABLING) 668062306a36Sopenharmony_ci ip_idx[idx] = -1; 668162306a36Sopenharmony_ci } 668262306a36Sopenharmony_ci 668362306a36Sopenharmony_ci /* Break if all IP states checked */ 668462306a36Sopenharmony_ci if ((ip_idx[0] == -1) && 668562306a36Sopenharmony_ci (ip_idx[1] == -1) && 668662306a36Sopenharmony_ci (ip_idx[2] == -1) && 668762306a36Sopenharmony_ci (ip_idx[3] == -1)) 668862306a36Sopenharmony_ci break; 668962306a36Sopenharmony_ci schedule_timeout_uninterruptible(HZ); 669062306a36Sopenharmony_ci } while (time_after(wtime, jiffies)); 669162306a36Sopenharmony_ci} 669262306a36Sopenharmony_ci 669362306a36Sopenharmony_cistatic int qla4xxx_cmp_fw_stentry(struct dev_db_entry *fw_ddb_entry, 669462306a36Sopenharmony_ci struct dev_db_entry *flash_ddb_entry) 669562306a36Sopenharmony_ci{ 669662306a36Sopenharmony_ci uint16_t options = 0; 669762306a36Sopenharmony_ci size_t ip_len = IP_ADDR_LEN; 669862306a36Sopenharmony_ci 669962306a36Sopenharmony_ci options = le16_to_cpu(fw_ddb_entry->options); 670062306a36Sopenharmony_ci if (options & DDB_OPT_IPV6_DEVICE) 670162306a36Sopenharmony_ci ip_len = IPv6_ADDR_LEN; 670262306a36Sopenharmony_ci 670362306a36Sopenharmony_ci if (memcmp(fw_ddb_entry->ip_addr, flash_ddb_entry->ip_addr, ip_len)) 670462306a36Sopenharmony_ci return QLA_ERROR; 670562306a36Sopenharmony_ci 670662306a36Sopenharmony_ci if (memcmp(&fw_ddb_entry->isid[0], &flash_ddb_entry->isid[0], 670762306a36Sopenharmony_ci sizeof(fw_ddb_entry->isid))) 670862306a36Sopenharmony_ci return QLA_ERROR; 670962306a36Sopenharmony_ci 671062306a36Sopenharmony_ci if (memcmp(&fw_ddb_entry->port, &flash_ddb_entry->port, 671162306a36Sopenharmony_ci sizeof(fw_ddb_entry->port))) 671262306a36Sopenharmony_ci return QLA_ERROR; 671362306a36Sopenharmony_ci 671462306a36Sopenharmony_ci return QLA_SUCCESS; 671562306a36Sopenharmony_ci} 671662306a36Sopenharmony_ci 671762306a36Sopenharmony_cistatic int qla4xxx_find_flash_st_idx(struct scsi_qla_host *ha, 671862306a36Sopenharmony_ci struct dev_db_entry *fw_ddb_entry, 671962306a36Sopenharmony_ci uint32_t fw_idx, uint32_t *flash_index) 672062306a36Sopenharmony_ci{ 672162306a36Sopenharmony_ci struct dev_db_entry *flash_ddb_entry; 672262306a36Sopenharmony_ci dma_addr_t flash_ddb_entry_dma; 672362306a36Sopenharmony_ci uint32_t idx = 0; 672462306a36Sopenharmony_ci int max_ddbs; 672562306a36Sopenharmony_ci int ret = QLA_ERROR, status; 672662306a36Sopenharmony_ci 672762306a36Sopenharmony_ci max_ddbs = is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX : 672862306a36Sopenharmony_ci MAX_DEV_DB_ENTRIES; 672962306a36Sopenharmony_ci 673062306a36Sopenharmony_ci flash_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL, 673162306a36Sopenharmony_ci &flash_ddb_entry_dma); 673262306a36Sopenharmony_ci if (flash_ddb_entry == NULL || fw_ddb_entry == NULL) { 673362306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "Out of memory\n"); 673462306a36Sopenharmony_ci goto exit_find_st_idx; 673562306a36Sopenharmony_ci } 673662306a36Sopenharmony_ci 673762306a36Sopenharmony_ci status = qla4xxx_flashdb_by_index(ha, flash_ddb_entry, 673862306a36Sopenharmony_ci flash_ddb_entry_dma, fw_idx); 673962306a36Sopenharmony_ci if (status == QLA_SUCCESS) { 674062306a36Sopenharmony_ci status = qla4xxx_cmp_fw_stentry(fw_ddb_entry, flash_ddb_entry); 674162306a36Sopenharmony_ci if (status == QLA_SUCCESS) { 674262306a36Sopenharmony_ci *flash_index = fw_idx; 674362306a36Sopenharmony_ci ret = QLA_SUCCESS; 674462306a36Sopenharmony_ci goto exit_find_st_idx; 674562306a36Sopenharmony_ci } 674662306a36Sopenharmony_ci } 674762306a36Sopenharmony_ci 674862306a36Sopenharmony_ci for (idx = 0; idx < max_ddbs; idx++) { 674962306a36Sopenharmony_ci status = qla4xxx_flashdb_by_index(ha, flash_ddb_entry, 675062306a36Sopenharmony_ci flash_ddb_entry_dma, idx); 675162306a36Sopenharmony_ci if (status == QLA_ERROR) 675262306a36Sopenharmony_ci continue; 675362306a36Sopenharmony_ci 675462306a36Sopenharmony_ci status = qla4xxx_cmp_fw_stentry(fw_ddb_entry, flash_ddb_entry); 675562306a36Sopenharmony_ci if (status == QLA_SUCCESS) { 675662306a36Sopenharmony_ci *flash_index = idx; 675762306a36Sopenharmony_ci ret = QLA_SUCCESS; 675862306a36Sopenharmony_ci goto exit_find_st_idx; 675962306a36Sopenharmony_ci } 676062306a36Sopenharmony_ci } 676162306a36Sopenharmony_ci 676262306a36Sopenharmony_ci if (idx == max_ddbs) 676362306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "Failed to find ST [%d] in flash\n", 676462306a36Sopenharmony_ci fw_idx); 676562306a36Sopenharmony_ci 676662306a36Sopenharmony_ciexit_find_st_idx: 676762306a36Sopenharmony_ci if (flash_ddb_entry) 676862306a36Sopenharmony_ci dma_pool_free(ha->fw_ddb_dma_pool, flash_ddb_entry, 676962306a36Sopenharmony_ci flash_ddb_entry_dma); 677062306a36Sopenharmony_ci 677162306a36Sopenharmony_ci return ret; 677262306a36Sopenharmony_ci} 677362306a36Sopenharmony_ci 677462306a36Sopenharmony_cistatic void qla4xxx_build_st_list(struct scsi_qla_host *ha, 677562306a36Sopenharmony_ci struct list_head *list_st) 677662306a36Sopenharmony_ci{ 677762306a36Sopenharmony_ci struct qla_ddb_index *st_ddb_idx; 677862306a36Sopenharmony_ci int max_ddbs; 677962306a36Sopenharmony_ci int fw_idx_size; 678062306a36Sopenharmony_ci struct dev_db_entry *fw_ddb_entry; 678162306a36Sopenharmony_ci dma_addr_t fw_ddb_dma; 678262306a36Sopenharmony_ci int ret; 678362306a36Sopenharmony_ci uint32_t idx = 0, next_idx = 0; 678462306a36Sopenharmony_ci uint32_t state = 0, conn_err = 0; 678562306a36Sopenharmony_ci uint32_t flash_index = -1; 678662306a36Sopenharmony_ci uint16_t conn_id = 0; 678762306a36Sopenharmony_ci 678862306a36Sopenharmony_ci fw_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL, 678962306a36Sopenharmony_ci &fw_ddb_dma); 679062306a36Sopenharmony_ci if (fw_ddb_entry == NULL) { 679162306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_ERR, ha, "Out of memory\n")); 679262306a36Sopenharmony_ci goto exit_st_list; 679362306a36Sopenharmony_ci } 679462306a36Sopenharmony_ci 679562306a36Sopenharmony_ci max_ddbs = is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX : 679662306a36Sopenharmony_ci MAX_DEV_DB_ENTRIES; 679762306a36Sopenharmony_ci fw_idx_size = sizeof(struct qla_ddb_index); 679862306a36Sopenharmony_ci 679962306a36Sopenharmony_ci for (idx = 0; idx < max_ddbs; idx = next_idx) { 680062306a36Sopenharmony_ci ret = qla4xxx_get_fwddb_entry(ha, idx, fw_ddb_entry, fw_ddb_dma, 680162306a36Sopenharmony_ci NULL, &next_idx, &state, 680262306a36Sopenharmony_ci &conn_err, NULL, &conn_id); 680362306a36Sopenharmony_ci if (ret == QLA_ERROR) 680462306a36Sopenharmony_ci break; 680562306a36Sopenharmony_ci 680662306a36Sopenharmony_ci /* Ignore DDB if invalid state (unassigned) */ 680762306a36Sopenharmony_ci if (state == DDB_DS_UNASSIGNED) 680862306a36Sopenharmony_ci goto continue_next_st; 680962306a36Sopenharmony_ci 681062306a36Sopenharmony_ci /* Check if ST, add to the list_st */ 681162306a36Sopenharmony_ci if (strlen((char *) fw_ddb_entry->iscsi_name) != 0) 681262306a36Sopenharmony_ci goto continue_next_st; 681362306a36Sopenharmony_ci 681462306a36Sopenharmony_ci st_ddb_idx = vzalloc(fw_idx_size); 681562306a36Sopenharmony_ci if (!st_ddb_idx) 681662306a36Sopenharmony_ci break; 681762306a36Sopenharmony_ci 681862306a36Sopenharmony_ci ret = qla4xxx_find_flash_st_idx(ha, fw_ddb_entry, idx, 681962306a36Sopenharmony_ci &flash_index); 682062306a36Sopenharmony_ci if (ret == QLA_ERROR) { 682162306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, 682262306a36Sopenharmony_ci "No flash entry for ST at idx [%d]\n", idx); 682362306a36Sopenharmony_ci st_ddb_idx->flash_ddb_idx = idx; 682462306a36Sopenharmony_ci } else { 682562306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, 682662306a36Sopenharmony_ci "ST at idx [%d] is stored at flash [%d]\n", 682762306a36Sopenharmony_ci idx, flash_index); 682862306a36Sopenharmony_ci st_ddb_idx->flash_ddb_idx = flash_index; 682962306a36Sopenharmony_ci } 683062306a36Sopenharmony_ci 683162306a36Sopenharmony_ci st_ddb_idx->fw_ddb_idx = idx; 683262306a36Sopenharmony_ci 683362306a36Sopenharmony_ci list_add_tail(&st_ddb_idx->list, list_st); 683462306a36Sopenharmony_cicontinue_next_st: 683562306a36Sopenharmony_ci if (next_idx == 0) 683662306a36Sopenharmony_ci break; 683762306a36Sopenharmony_ci } 683862306a36Sopenharmony_ci 683962306a36Sopenharmony_ciexit_st_list: 684062306a36Sopenharmony_ci if (fw_ddb_entry) 684162306a36Sopenharmony_ci dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma); 684262306a36Sopenharmony_ci} 684362306a36Sopenharmony_ci 684462306a36Sopenharmony_ci/** 684562306a36Sopenharmony_ci * qla4xxx_remove_failed_ddb - Remove inactive or failed ddb from list 684662306a36Sopenharmony_ci * @ha: pointer to adapter structure 684762306a36Sopenharmony_ci * @list_ddb: List from which failed ddb to be removed 684862306a36Sopenharmony_ci * 684962306a36Sopenharmony_ci * Iterate over the list of DDBs and find and remove DDBs that are either in 685062306a36Sopenharmony_ci * no connection active state or failed state 685162306a36Sopenharmony_ci **/ 685262306a36Sopenharmony_cistatic void qla4xxx_remove_failed_ddb(struct scsi_qla_host *ha, 685362306a36Sopenharmony_ci struct list_head *list_ddb) 685462306a36Sopenharmony_ci{ 685562306a36Sopenharmony_ci struct qla_ddb_index *ddb_idx, *ddb_idx_tmp; 685662306a36Sopenharmony_ci uint32_t next_idx = 0; 685762306a36Sopenharmony_ci uint32_t state = 0, conn_err = 0; 685862306a36Sopenharmony_ci int ret; 685962306a36Sopenharmony_ci 686062306a36Sopenharmony_ci list_for_each_entry_safe(ddb_idx, ddb_idx_tmp, list_ddb, list) { 686162306a36Sopenharmony_ci ret = qla4xxx_get_fwddb_entry(ha, ddb_idx->fw_ddb_idx, 686262306a36Sopenharmony_ci NULL, 0, NULL, &next_idx, &state, 686362306a36Sopenharmony_ci &conn_err, NULL, NULL); 686462306a36Sopenharmony_ci if (ret == QLA_ERROR) 686562306a36Sopenharmony_ci continue; 686662306a36Sopenharmony_ci 686762306a36Sopenharmony_ci if (state == DDB_DS_NO_CONNECTION_ACTIVE || 686862306a36Sopenharmony_ci state == DDB_DS_SESSION_FAILED) { 686962306a36Sopenharmony_ci list_del_init(&ddb_idx->list); 687062306a36Sopenharmony_ci vfree(ddb_idx); 687162306a36Sopenharmony_ci } 687262306a36Sopenharmony_ci } 687362306a36Sopenharmony_ci} 687462306a36Sopenharmony_ci 687562306a36Sopenharmony_cistatic void qla4xxx_update_sess_disc_idx(struct scsi_qla_host *ha, 687662306a36Sopenharmony_ci struct ddb_entry *ddb_entry, 687762306a36Sopenharmony_ci struct dev_db_entry *fw_ddb_entry) 687862306a36Sopenharmony_ci{ 687962306a36Sopenharmony_ci struct iscsi_cls_session *cls_sess; 688062306a36Sopenharmony_ci struct iscsi_session *sess; 688162306a36Sopenharmony_ci uint32_t max_ddbs = 0; 688262306a36Sopenharmony_ci uint16_t ddb_link = -1; 688362306a36Sopenharmony_ci 688462306a36Sopenharmony_ci max_ddbs = is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX : 688562306a36Sopenharmony_ci MAX_DEV_DB_ENTRIES; 688662306a36Sopenharmony_ci 688762306a36Sopenharmony_ci cls_sess = ddb_entry->sess; 688862306a36Sopenharmony_ci sess = cls_sess->dd_data; 688962306a36Sopenharmony_ci 689062306a36Sopenharmony_ci ddb_link = le16_to_cpu(fw_ddb_entry->ddb_link); 689162306a36Sopenharmony_ci if (ddb_link < max_ddbs) 689262306a36Sopenharmony_ci sess->discovery_parent_idx = ddb_link; 689362306a36Sopenharmony_ci else 689462306a36Sopenharmony_ci sess->discovery_parent_idx = DDB_NO_LINK; 689562306a36Sopenharmony_ci} 689662306a36Sopenharmony_ci 689762306a36Sopenharmony_cistatic int qla4xxx_sess_conn_setup(struct scsi_qla_host *ha, 689862306a36Sopenharmony_ci struct dev_db_entry *fw_ddb_entry, 689962306a36Sopenharmony_ci int is_reset, uint16_t idx) 690062306a36Sopenharmony_ci{ 690162306a36Sopenharmony_ci struct iscsi_cls_session *cls_sess; 690262306a36Sopenharmony_ci struct iscsi_session *sess; 690362306a36Sopenharmony_ci struct iscsi_cls_conn *cls_conn; 690462306a36Sopenharmony_ci struct iscsi_endpoint *ep; 690562306a36Sopenharmony_ci uint16_t cmds_max = 32; 690662306a36Sopenharmony_ci uint16_t conn_id = 0; 690762306a36Sopenharmony_ci uint32_t initial_cmdsn = 0; 690862306a36Sopenharmony_ci int ret = QLA_SUCCESS; 690962306a36Sopenharmony_ci 691062306a36Sopenharmony_ci struct ddb_entry *ddb_entry = NULL; 691162306a36Sopenharmony_ci 691262306a36Sopenharmony_ci /* Create session object, with INVALID_ENTRY, 691362306a36Sopenharmony_ci * the targer_id would get set when we issue the login 691462306a36Sopenharmony_ci */ 691562306a36Sopenharmony_ci cls_sess = iscsi_session_setup(&qla4xxx_iscsi_transport, ha->host, 691662306a36Sopenharmony_ci cmds_max, sizeof(struct ddb_entry), 691762306a36Sopenharmony_ci sizeof(struct ql4_task_data), 691862306a36Sopenharmony_ci initial_cmdsn, INVALID_ENTRY); 691962306a36Sopenharmony_ci if (!cls_sess) { 692062306a36Sopenharmony_ci ret = QLA_ERROR; 692162306a36Sopenharmony_ci goto exit_setup; 692262306a36Sopenharmony_ci } 692362306a36Sopenharmony_ci 692462306a36Sopenharmony_ci /* 692562306a36Sopenharmony_ci * so calling module_put function to decrement the 692662306a36Sopenharmony_ci * reference count. 692762306a36Sopenharmony_ci **/ 692862306a36Sopenharmony_ci module_put(qla4xxx_iscsi_transport.owner); 692962306a36Sopenharmony_ci sess = cls_sess->dd_data; 693062306a36Sopenharmony_ci ddb_entry = sess->dd_data; 693162306a36Sopenharmony_ci ddb_entry->sess = cls_sess; 693262306a36Sopenharmony_ci 693362306a36Sopenharmony_ci cls_sess->recovery_tmo = ql4xsess_recovery_tmo; 693462306a36Sopenharmony_ci memcpy(&ddb_entry->fw_ddb_entry, fw_ddb_entry, 693562306a36Sopenharmony_ci sizeof(struct dev_db_entry)); 693662306a36Sopenharmony_ci 693762306a36Sopenharmony_ci qla4xxx_setup_flash_ddb_entry(ha, ddb_entry, idx); 693862306a36Sopenharmony_ci 693962306a36Sopenharmony_ci cls_conn = iscsi_conn_setup(cls_sess, sizeof(struct qla_conn), conn_id); 694062306a36Sopenharmony_ci 694162306a36Sopenharmony_ci if (!cls_conn) { 694262306a36Sopenharmony_ci ret = QLA_ERROR; 694362306a36Sopenharmony_ci goto exit_setup; 694462306a36Sopenharmony_ci } 694562306a36Sopenharmony_ci 694662306a36Sopenharmony_ci ddb_entry->conn = cls_conn; 694762306a36Sopenharmony_ci 694862306a36Sopenharmony_ci /* Setup ep, for displaying attributes in sysfs */ 694962306a36Sopenharmony_ci ep = qla4xxx_get_ep_fwdb(ha, fw_ddb_entry); 695062306a36Sopenharmony_ci if (ep) { 695162306a36Sopenharmony_ci ep->conn = cls_conn; 695262306a36Sopenharmony_ci cls_conn->ep = ep; 695362306a36Sopenharmony_ci } else { 695462306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_ERR, ha, "Unable to get ep\n")); 695562306a36Sopenharmony_ci ret = QLA_ERROR; 695662306a36Sopenharmony_ci goto exit_setup; 695762306a36Sopenharmony_ci } 695862306a36Sopenharmony_ci 695962306a36Sopenharmony_ci /* Update sess/conn params */ 696062306a36Sopenharmony_ci qla4xxx_copy_fwddb_param(ha, fw_ddb_entry, cls_sess, cls_conn); 696162306a36Sopenharmony_ci qla4xxx_update_sess_disc_idx(ha, ddb_entry, fw_ddb_entry); 696262306a36Sopenharmony_ci 696362306a36Sopenharmony_ci if (is_reset == RESET_ADAPTER) { 696462306a36Sopenharmony_ci iscsi_block_session(cls_sess); 696562306a36Sopenharmony_ci /* Use the relogin path to discover new devices 696662306a36Sopenharmony_ci * by short-circuiting the logic of setting 696762306a36Sopenharmony_ci * timer to relogin - instead set the flags 696862306a36Sopenharmony_ci * to initiate login right away. 696962306a36Sopenharmony_ci */ 697062306a36Sopenharmony_ci set_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags); 697162306a36Sopenharmony_ci set_bit(DF_RELOGIN, &ddb_entry->flags); 697262306a36Sopenharmony_ci } 697362306a36Sopenharmony_ci 697462306a36Sopenharmony_ciexit_setup: 697562306a36Sopenharmony_ci return ret; 697662306a36Sopenharmony_ci} 697762306a36Sopenharmony_ci 697862306a36Sopenharmony_cistatic void qla4xxx_update_fw_ddb_link(struct scsi_qla_host *ha, 697962306a36Sopenharmony_ci struct list_head *list_ddb, 698062306a36Sopenharmony_ci struct dev_db_entry *fw_ddb_entry) 698162306a36Sopenharmony_ci{ 698262306a36Sopenharmony_ci struct qla_ddb_index *ddb_idx, *ddb_idx_tmp; 698362306a36Sopenharmony_ci uint16_t ddb_link; 698462306a36Sopenharmony_ci 698562306a36Sopenharmony_ci ddb_link = le16_to_cpu(fw_ddb_entry->ddb_link); 698662306a36Sopenharmony_ci 698762306a36Sopenharmony_ci list_for_each_entry_safe(ddb_idx, ddb_idx_tmp, list_ddb, list) { 698862306a36Sopenharmony_ci if (ddb_idx->fw_ddb_idx == ddb_link) { 698962306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 699062306a36Sopenharmony_ci "Updating NT parent idx from [%d] to [%d]\n", 699162306a36Sopenharmony_ci ddb_link, ddb_idx->flash_ddb_idx)); 699262306a36Sopenharmony_ci fw_ddb_entry->ddb_link = 699362306a36Sopenharmony_ci cpu_to_le16(ddb_idx->flash_ddb_idx); 699462306a36Sopenharmony_ci return; 699562306a36Sopenharmony_ci } 699662306a36Sopenharmony_ci } 699762306a36Sopenharmony_ci} 699862306a36Sopenharmony_ci 699962306a36Sopenharmony_cistatic void qla4xxx_build_nt_list(struct scsi_qla_host *ha, 700062306a36Sopenharmony_ci struct list_head *list_nt, 700162306a36Sopenharmony_ci struct list_head *list_st, 700262306a36Sopenharmony_ci int is_reset) 700362306a36Sopenharmony_ci{ 700462306a36Sopenharmony_ci struct dev_db_entry *fw_ddb_entry; 700562306a36Sopenharmony_ci struct ddb_entry *ddb_entry = NULL; 700662306a36Sopenharmony_ci dma_addr_t fw_ddb_dma; 700762306a36Sopenharmony_ci int max_ddbs; 700862306a36Sopenharmony_ci int fw_idx_size; 700962306a36Sopenharmony_ci int ret; 701062306a36Sopenharmony_ci uint32_t idx = 0, next_idx = 0; 701162306a36Sopenharmony_ci uint32_t state = 0, conn_err = 0; 701262306a36Sopenharmony_ci uint32_t ddb_idx = -1; 701362306a36Sopenharmony_ci uint16_t conn_id = 0; 701462306a36Sopenharmony_ci uint16_t ddb_link = -1; 701562306a36Sopenharmony_ci struct qla_ddb_index *nt_ddb_idx; 701662306a36Sopenharmony_ci 701762306a36Sopenharmony_ci fw_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL, 701862306a36Sopenharmony_ci &fw_ddb_dma); 701962306a36Sopenharmony_ci if (fw_ddb_entry == NULL) { 702062306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_ERR, ha, "Out of memory\n")); 702162306a36Sopenharmony_ci goto exit_nt_list; 702262306a36Sopenharmony_ci } 702362306a36Sopenharmony_ci max_ddbs = is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX : 702462306a36Sopenharmony_ci MAX_DEV_DB_ENTRIES; 702562306a36Sopenharmony_ci fw_idx_size = sizeof(struct qla_ddb_index); 702662306a36Sopenharmony_ci 702762306a36Sopenharmony_ci for (idx = 0; idx < max_ddbs; idx = next_idx) { 702862306a36Sopenharmony_ci ret = qla4xxx_get_fwddb_entry(ha, idx, fw_ddb_entry, fw_ddb_dma, 702962306a36Sopenharmony_ci NULL, &next_idx, &state, 703062306a36Sopenharmony_ci &conn_err, NULL, &conn_id); 703162306a36Sopenharmony_ci if (ret == QLA_ERROR) 703262306a36Sopenharmony_ci break; 703362306a36Sopenharmony_ci 703462306a36Sopenharmony_ci if (qla4xxx_verify_boot_idx(ha, idx) != QLA_SUCCESS) 703562306a36Sopenharmony_ci goto continue_next_nt; 703662306a36Sopenharmony_ci 703762306a36Sopenharmony_ci /* Check if NT, then add to list it */ 703862306a36Sopenharmony_ci if (strlen((char *) fw_ddb_entry->iscsi_name) == 0) 703962306a36Sopenharmony_ci goto continue_next_nt; 704062306a36Sopenharmony_ci 704162306a36Sopenharmony_ci ddb_link = le16_to_cpu(fw_ddb_entry->ddb_link); 704262306a36Sopenharmony_ci if (ddb_link < max_ddbs) 704362306a36Sopenharmony_ci qla4xxx_update_fw_ddb_link(ha, list_st, fw_ddb_entry); 704462306a36Sopenharmony_ci 704562306a36Sopenharmony_ci if (!(state == DDB_DS_NO_CONNECTION_ACTIVE || 704662306a36Sopenharmony_ci state == DDB_DS_SESSION_FAILED) && 704762306a36Sopenharmony_ci (is_reset == INIT_ADAPTER)) 704862306a36Sopenharmony_ci goto continue_next_nt; 704962306a36Sopenharmony_ci 705062306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 705162306a36Sopenharmony_ci "Adding DDB to session = 0x%x\n", idx)); 705262306a36Sopenharmony_ci 705362306a36Sopenharmony_ci if (is_reset == INIT_ADAPTER) { 705462306a36Sopenharmony_ci nt_ddb_idx = vmalloc(fw_idx_size); 705562306a36Sopenharmony_ci if (!nt_ddb_idx) 705662306a36Sopenharmony_ci break; 705762306a36Sopenharmony_ci 705862306a36Sopenharmony_ci nt_ddb_idx->fw_ddb_idx = idx; 705962306a36Sopenharmony_ci 706062306a36Sopenharmony_ci /* Copy original isid as it may get updated in function 706162306a36Sopenharmony_ci * qla4xxx_update_isid(). We need original isid in 706262306a36Sopenharmony_ci * function qla4xxx_compare_tuple_ddb to find duplicate 706362306a36Sopenharmony_ci * target */ 706462306a36Sopenharmony_ci memcpy(&nt_ddb_idx->flash_isid[0], 706562306a36Sopenharmony_ci &fw_ddb_entry->isid[0], 706662306a36Sopenharmony_ci sizeof(nt_ddb_idx->flash_isid)); 706762306a36Sopenharmony_ci 706862306a36Sopenharmony_ci ret = qla4xxx_is_flash_ddb_exists(ha, list_nt, 706962306a36Sopenharmony_ci fw_ddb_entry); 707062306a36Sopenharmony_ci if (ret == QLA_SUCCESS) { 707162306a36Sopenharmony_ci /* free nt_ddb_idx and do not add to list_nt */ 707262306a36Sopenharmony_ci vfree(nt_ddb_idx); 707362306a36Sopenharmony_ci goto continue_next_nt; 707462306a36Sopenharmony_ci } 707562306a36Sopenharmony_ci 707662306a36Sopenharmony_ci /* Copy updated isid */ 707762306a36Sopenharmony_ci memcpy(&nt_ddb_idx->fw_ddb, fw_ddb_entry, 707862306a36Sopenharmony_ci sizeof(struct dev_db_entry)); 707962306a36Sopenharmony_ci 708062306a36Sopenharmony_ci list_add_tail(&nt_ddb_idx->list, list_nt); 708162306a36Sopenharmony_ci } else if (is_reset == RESET_ADAPTER) { 708262306a36Sopenharmony_ci ret = qla4xxx_is_session_exists(ha, fw_ddb_entry, 708362306a36Sopenharmony_ci &ddb_idx); 708462306a36Sopenharmony_ci if (ret == QLA_SUCCESS) { 708562306a36Sopenharmony_ci ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, 708662306a36Sopenharmony_ci ddb_idx); 708762306a36Sopenharmony_ci if (ddb_entry != NULL) 708862306a36Sopenharmony_ci qla4xxx_update_sess_disc_idx(ha, 708962306a36Sopenharmony_ci ddb_entry, 709062306a36Sopenharmony_ci fw_ddb_entry); 709162306a36Sopenharmony_ci goto continue_next_nt; 709262306a36Sopenharmony_ci } 709362306a36Sopenharmony_ci } 709462306a36Sopenharmony_ci 709562306a36Sopenharmony_ci ret = qla4xxx_sess_conn_setup(ha, fw_ddb_entry, is_reset, idx); 709662306a36Sopenharmony_ci if (ret == QLA_ERROR) 709762306a36Sopenharmony_ci goto exit_nt_list; 709862306a36Sopenharmony_ci 709962306a36Sopenharmony_cicontinue_next_nt: 710062306a36Sopenharmony_ci if (next_idx == 0) 710162306a36Sopenharmony_ci break; 710262306a36Sopenharmony_ci } 710362306a36Sopenharmony_ci 710462306a36Sopenharmony_ciexit_nt_list: 710562306a36Sopenharmony_ci if (fw_ddb_entry) 710662306a36Sopenharmony_ci dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma); 710762306a36Sopenharmony_ci} 710862306a36Sopenharmony_ci 710962306a36Sopenharmony_cistatic void qla4xxx_build_new_nt_list(struct scsi_qla_host *ha, 711062306a36Sopenharmony_ci struct list_head *list_nt, 711162306a36Sopenharmony_ci uint16_t target_id) 711262306a36Sopenharmony_ci{ 711362306a36Sopenharmony_ci struct dev_db_entry *fw_ddb_entry; 711462306a36Sopenharmony_ci dma_addr_t fw_ddb_dma; 711562306a36Sopenharmony_ci int max_ddbs; 711662306a36Sopenharmony_ci int fw_idx_size; 711762306a36Sopenharmony_ci int ret; 711862306a36Sopenharmony_ci uint32_t idx = 0, next_idx = 0; 711962306a36Sopenharmony_ci uint32_t state = 0, conn_err = 0; 712062306a36Sopenharmony_ci uint16_t conn_id = 0; 712162306a36Sopenharmony_ci struct qla_ddb_index *nt_ddb_idx; 712262306a36Sopenharmony_ci 712362306a36Sopenharmony_ci fw_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL, 712462306a36Sopenharmony_ci &fw_ddb_dma); 712562306a36Sopenharmony_ci if (fw_ddb_entry == NULL) { 712662306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_ERR, ha, "Out of memory\n")); 712762306a36Sopenharmony_ci goto exit_new_nt_list; 712862306a36Sopenharmony_ci } 712962306a36Sopenharmony_ci max_ddbs = is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX : 713062306a36Sopenharmony_ci MAX_DEV_DB_ENTRIES; 713162306a36Sopenharmony_ci fw_idx_size = sizeof(struct qla_ddb_index); 713262306a36Sopenharmony_ci 713362306a36Sopenharmony_ci for (idx = 0; idx < max_ddbs; idx = next_idx) { 713462306a36Sopenharmony_ci ret = qla4xxx_get_fwddb_entry(ha, idx, fw_ddb_entry, fw_ddb_dma, 713562306a36Sopenharmony_ci NULL, &next_idx, &state, 713662306a36Sopenharmony_ci &conn_err, NULL, &conn_id); 713762306a36Sopenharmony_ci if (ret == QLA_ERROR) 713862306a36Sopenharmony_ci break; 713962306a36Sopenharmony_ci 714062306a36Sopenharmony_ci /* Check if NT, then add it to list */ 714162306a36Sopenharmony_ci if (strlen((char *)fw_ddb_entry->iscsi_name) == 0) 714262306a36Sopenharmony_ci goto continue_next_new_nt; 714362306a36Sopenharmony_ci 714462306a36Sopenharmony_ci if (!(state == DDB_DS_NO_CONNECTION_ACTIVE)) 714562306a36Sopenharmony_ci goto continue_next_new_nt; 714662306a36Sopenharmony_ci 714762306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 714862306a36Sopenharmony_ci "Adding DDB to session = 0x%x\n", idx)); 714962306a36Sopenharmony_ci 715062306a36Sopenharmony_ci nt_ddb_idx = vmalloc(fw_idx_size); 715162306a36Sopenharmony_ci if (!nt_ddb_idx) 715262306a36Sopenharmony_ci break; 715362306a36Sopenharmony_ci 715462306a36Sopenharmony_ci nt_ddb_idx->fw_ddb_idx = idx; 715562306a36Sopenharmony_ci 715662306a36Sopenharmony_ci ret = qla4xxx_is_session_exists(ha, fw_ddb_entry, NULL); 715762306a36Sopenharmony_ci if (ret == QLA_SUCCESS) { 715862306a36Sopenharmony_ci /* free nt_ddb_idx and do not add to list_nt */ 715962306a36Sopenharmony_ci vfree(nt_ddb_idx); 716062306a36Sopenharmony_ci goto continue_next_new_nt; 716162306a36Sopenharmony_ci } 716262306a36Sopenharmony_ci 716362306a36Sopenharmony_ci if (target_id < max_ddbs) 716462306a36Sopenharmony_ci fw_ddb_entry->ddb_link = cpu_to_le16(target_id); 716562306a36Sopenharmony_ci 716662306a36Sopenharmony_ci list_add_tail(&nt_ddb_idx->list, list_nt); 716762306a36Sopenharmony_ci 716862306a36Sopenharmony_ci ret = qla4xxx_sess_conn_setup(ha, fw_ddb_entry, RESET_ADAPTER, 716962306a36Sopenharmony_ci idx); 717062306a36Sopenharmony_ci if (ret == QLA_ERROR) 717162306a36Sopenharmony_ci goto exit_new_nt_list; 717262306a36Sopenharmony_ci 717362306a36Sopenharmony_cicontinue_next_new_nt: 717462306a36Sopenharmony_ci if (next_idx == 0) 717562306a36Sopenharmony_ci break; 717662306a36Sopenharmony_ci } 717762306a36Sopenharmony_ci 717862306a36Sopenharmony_ciexit_new_nt_list: 717962306a36Sopenharmony_ci if (fw_ddb_entry) 718062306a36Sopenharmony_ci dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma); 718162306a36Sopenharmony_ci} 718262306a36Sopenharmony_ci 718362306a36Sopenharmony_ci/** 718462306a36Sopenharmony_ci * qla4xxx_sysfs_ddb_is_non_persistent - check for non-persistence of ddb entry 718562306a36Sopenharmony_ci * @dev: dev associated with the sysfs entry 718662306a36Sopenharmony_ci * @data: pointer to flashnode session object 718762306a36Sopenharmony_ci * 718862306a36Sopenharmony_ci * Returns: 718962306a36Sopenharmony_ci * 1: if flashnode entry is non-persistent 719062306a36Sopenharmony_ci * 0: if flashnode entry is persistent 719162306a36Sopenharmony_ci **/ 719262306a36Sopenharmony_cistatic int qla4xxx_sysfs_ddb_is_non_persistent(struct device *dev, void *data) 719362306a36Sopenharmony_ci{ 719462306a36Sopenharmony_ci struct iscsi_bus_flash_session *fnode_sess; 719562306a36Sopenharmony_ci 719662306a36Sopenharmony_ci if (!iscsi_flashnode_bus_match(dev, NULL)) 719762306a36Sopenharmony_ci return 0; 719862306a36Sopenharmony_ci 719962306a36Sopenharmony_ci fnode_sess = iscsi_dev_to_flash_session(dev); 720062306a36Sopenharmony_ci 720162306a36Sopenharmony_ci return (fnode_sess->flash_state == DEV_DB_NON_PERSISTENT); 720262306a36Sopenharmony_ci} 720362306a36Sopenharmony_ci 720462306a36Sopenharmony_ci/** 720562306a36Sopenharmony_ci * qla4xxx_sysfs_ddb_tgt_create - Create sysfs entry for target 720662306a36Sopenharmony_ci * @ha: pointer to host 720762306a36Sopenharmony_ci * @fw_ddb_entry: flash ddb data 720862306a36Sopenharmony_ci * @idx: target index 720962306a36Sopenharmony_ci * @user: if set then this call is made from userland else from kernel 721062306a36Sopenharmony_ci * 721162306a36Sopenharmony_ci * Returns: 721262306a36Sopenharmony_ci * On sucess: QLA_SUCCESS 721362306a36Sopenharmony_ci * On failure: QLA_ERROR 721462306a36Sopenharmony_ci * 721562306a36Sopenharmony_ci * This create separate sysfs entries for session and connection attributes of 721662306a36Sopenharmony_ci * the given fw ddb entry. 721762306a36Sopenharmony_ci * If this is invoked as a result of a userspace call then the entry is marked 721862306a36Sopenharmony_ci * as nonpersistent using flash_state field. 721962306a36Sopenharmony_ci **/ 722062306a36Sopenharmony_cistatic int qla4xxx_sysfs_ddb_tgt_create(struct scsi_qla_host *ha, 722162306a36Sopenharmony_ci struct dev_db_entry *fw_ddb_entry, 722262306a36Sopenharmony_ci uint16_t *idx, int user) 722362306a36Sopenharmony_ci{ 722462306a36Sopenharmony_ci struct iscsi_bus_flash_session *fnode_sess = NULL; 722562306a36Sopenharmony_ci struct iscsi_bus_flash_conn *fnode_conn = NULL; 722662306a36Sopenharmony_ci int rc = QLA_ERROR; 722762306a36Sopenharmony_ci 722862306a36Sopenharmony_ci fnode_sess = iscsi_create_flashnode_sess(ha->host, *idx, 722962306a36Sopenharmony_ci &qla4xxx_iscsi_transport, 0); 723062306a36Sopenharmony_ci if (!fnode_sess) { 723162306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, 723262306a36Sopenharmony_ci "%s: Unable to create session sysfs entry for flashnode %d of host%lu\n", 723362306a36Sopenharmony_ci __func__, *idx, ha->host_no); 723462306a36Sopenharmony_ci goto exit_tgt_create; 723562306a36Sopenharmony_ci } 723662306a36Sopenharmony_ci 723762306a36Sopenharmony_ci fnode_conn = iscsi_create_flashnode_conn(ha->host, fnode_sess, 723862306a36Sopenharmony_ci &qla4xxx_iscsi_transport, 0); 723962306a36Sopenharmony_ci if (!fnode_conn) { 724062306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, 724162306a36Sopenharmony_ci "%s: Unable to create conn sysfs entry for flashnode %d of host%lu\n", 724262306a36Sopenharmony_ci __func__, *idx, ha->host_no); 724362306a36Sopenharmony_ci goto free_sess; 724462306a36Sopenharmony_ci } 724562306a36Sopenharmony_ci 724662306a36Sopenharmony_ci if (user) { 724762306a36Sopenharmony_ci fnode_sess->flash_state = DEV_DB_NON_PERSISTENT; 724862306a36Sopenharmony_ci } else { 724962306a36Sopenharmony_ci fnode_sess->flash_state = DEV_DB_PERSISTENT; 725062306a36Sopenharmony_ci 725162306a36Sopenharmony_ci if (*idx == ha->pri_ddb_idx || *idx == ha->sec_ddb_idx) 725262306a36Sopenharmony_ci fnode_sess->is_boot_target = 1; 725362306a36Sopenharmony_ci else 725462306a36Sopenharmony_ci fnode_sess->is_boot_target = 0; 725562306a36Sopenharmony_ci } 725662306a36Sopenharmony_ci 725762306a36Sopenharmony_ci rc = qla4xxx_copy_from_fwddb_param(fnode_sess, fnode_conn, 725862306a36Sopenharmony_ci fw_ddb_entry); 725962306a36Sopenharmony_ci if (rc) 726062306a36Sopenharmony_ci goto free_sess; 726162306a36Sopenharmony_ci 726262306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "%s: sysfs entry %s created\n", 726362306a36Sopenharmony_ci __func__, fnode_sess->dev.kobj.name); 726462306a36Sopenharmony_ci 726562306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "%s: sysfs entry %s created\n", 726662306a36Sopenharmony_ci __func__, fnode_conn->dev.kobj.name); 726762306a36Sopenharmony_ci 726862306a36Sopenharmony_ci return QLA_SUCCESS; 726962306a36Sopenharmony_ci 727062306a36Sopenharmony_cifree_sess: 727162306a36Sopenharmony_ci iscsi_destroy_flashnode_sess(fnode_sess); 727262306a36Sopenharmony_ci 727362306a36Sopenharmony_ciexit_tgt_create: 727462306a36Sopenharmony_ci return QLA_ERROR; 727562306a36Sopenharmony_ci} 727662306a36Sopenharmony_ci 727762306a36Sopenharmony_ci/** 727862306a36Sopenharmony_ci * qla4xxx_sysfs_ddb_add - Add new ddb entry in flash 727962306a36Sopenharmony_ci * @shost: pointer to host 728062306a36Sopenharmony_ci * @buf: type of ddb entry (ipv4/ipv6) 728162306a36Sopenharmony_ci * @len: length of buf 728262306a36Sopenharmony_ci * 728362306a36Sopenharmony_ci * This creates new ddb entry in the flash by finding first free index and 728462306a36Sopenharmony_ci * storing default ddb there. And then create sysfs entry for the new ddb entry. 728562306a36Sopenharmony_ci **/ 728662306a36Sopenharmony_cistatic int qla4xxx_sysfs_ddb_add(struct Scsi_Host *shost, const char *buf, 728762306a36Sopenharmony_ci int len) 728862306a36Sopenharmony_ci{ 728962306a36Sopenharmony_ci struct scsi_qla_host *ha = to_qla_host(shost); 729062306a36Sopenharmony_ci struct dev_db_entry *fw_ddb_entry = NULL; 729162306a36Sopenharmony_ci dma_addr_t fw_ddb_entry_dma; 729262306a36Sopenharmony_ci struct device *dev; 729362306a36Sopenharmony_ci uint16_t idx = 0; 729462306a36Sopenharmony_ci uint16_t max_ddbs = 0; 729562306a36Sopenharmony_ci uint32_t options = 0; 729662306a36Sopenharmony_ci uint32_t rval = QLA_ERROR; 729762306a36Sopenharmony_ci 729862306a36Sopenharmony_ci if (strncasecmp(PORTAL_TYPE_IPV4, buf, 4) && 729962306a36Sopenharmony_ci strncasecmp(PORTAL_TYPE_IPV6, buf, 4)) { 730062306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_ERR, ha, "%s: Invalid portal type\n", 730162306a36Sopenharmony_ci __func__)); 730262306a36Sopenharmony_ci goto exit_ddb_add; 730362306a36Sopenharmony_ci } 730462306a36Sopenharmony_ci 730562306a36Sopenharmony_ci max_ddbs = is_qla40XX(ha) ? MAX_PRST_DEV_DB_ENTRIES : 730662306a36Sopenharmony_ci MAX_DEV_DB_ENTRIES; 730762306a36Sopenharmony_ci 730862306a36Sopenharmony_ci fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), 730962306a36Sopenharmony_ci &fw_ddb_entry_dma, GFP_KERNEL); 731062306a36Sopenharmony_ci if (!fw_ddb_entry) { 731162306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_ERR, ha, 731262306a36Sopenharmony_ci "%s: Unable to allocate dma buffer\n", 731362306a36Sopenharmony_ci __func__)); 731462306a36Sopenharmony_ci goto exit_ddb_add; 731562306a36Sopenharmony_ci } 731662306a36Sopenharmony_ci 731762306a36Sopenharmony_ci dev = iscsi_find_flashnode_sess(ha->host, NULL, 731862306a36Sopenharmony_ci qla4xxx_sysfs_ddb_is_non_persistent); 731962306a36Sopenharmony_ci if (dev) { 732062306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, 732162306a36Sopenharmony_ci "%s: A non-persistent entry %s found\n", 732262306a36Sopenharmony_ci __func__, dev->kobj.name); 732362306a36Sopenharmony_ci put_device(dev); 732462306a36Sopenharmony_ci goto exit_ddb_add; 732562306a36Sopenharmony_ci } 732662306a36Sopenharmony_ci 732762306a36Sopenharmony_ci /* Index 0 and 1 are reserved for boot target entries */ 732862306a36Sopenharmony_ci for (idx = 2; idx < max_ddbs; idx++) { 732962306a36Sopenharmony_ci if (qla4xxx_flashdb_by_index(ha, fw_ddb_entry, 733062306a36Sopenharmony_ci fw_ddb_entry_dma, idx)) 733162306a36Sopenharmony_ci break; 733262306a36Sopenharmony_ci } 733362306a36Sopenharmony_ci 733462306a36Sopenharmony_ci if (idx == max_ddbs) 733562306a36Sopenharmony_ci goto exit_ddb_add; 733662306a36Sopenharmony_ci 733762306a36Sopenharmony_ci if (!strncasecmp("ipv6", buf, 4)) 733862306a36Sopenharmony_ci options |= IPV6_DEFAULT_DDB_ENTRY; 733962306a36Sopenharmony_ci 734062306a36Sopenharmony_ci rval = qla4xxx_get_default_ddb(ha, options, fw_ddb_entry_dma); 734162306a36Sopenharmony_ci if (rval == QLA_ERROR) 734262306a36Sopenharmony_ci goto exit_ddb_add; 734362306a36Sopenharmony_ci 734462306a36Sopenharmony_ci rval = qla4xxx_sysfs_ddb_tgt_create(ha, fw_ddb_entry, &idx, 1); 734562306a36Sopenharmony_ci 734662306a36Sopenharmony_ciexit_ddb_add: 734762306a36Sopenharmony_ci if (fw_ddb_entry) 734862306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), 734962306a36Sopenharmony_ci fw_ddb_entry, fw_ddb_entry_dma); 735062306a36Sopenharmony_ci if (rval == QLA_SUCCESS) 735162306a36Sopenharmony_ci return idx; 735262306a36Sopenharmony_ci else 735362306a36Sopenharmony_ci return -EIO; 735462306a36Sopenharmony_ci} 735562306a36Sopenharmony_ci 735662306a36Sopenharmony_ci/** 735762306a36Sopenharmony_ci * qla4xxx_sysfs_ddb_apply - write the target ddb contents to Flash 735862306a36Sopenharmony_ci * @fnode_sess: pointer to session attrs of flash ddb entry 735962306a36Sopenharmony_ci * @fnode_conn: pointer to connection attrs of flash ddb entry 736062306a36Sopenharmony_ci * 736162306a36Sopenharmony_ci * This writes the contents of target ddb buffer to Flash with a valid cookie 736262306a36Sopenharmony_ci * value in order to make the ddb entry persistent. 736362306a36Sopenharmony_ci **/ 736462306a36Sopenharmony_cistatic int qla4xxx_sysfs_ddb_apply(struct iscsi_bus_flash_session *fnode_sess, 736562306a36Sopenharmony_ci struct iscsi_bus_flash_conn *fnode_conn) 736662306a36Sopenharmony_ci{ 736762306a36Sopenharmony_ci struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess); 736862306a36Sopenharmony_ci struct scsi_qla_host *ha = to_qla_host(shost); 736962306a36Sopenharmony_ci uint32_t dev_db_start_offset = FLASH_OFFSET_DB_INFO; 737062306a36Sopenharmony_ci struct dev_db_entry *fw_ddb_entry = NULL; 737162306a36Sopenharmony_ci dma_addr_t fw_ddb_entry_dma; 737262306a36Sopenharmony_ci uint32_t options = 0; 737362306a36Sopenharmony_ci int rval = 0; 737462306a36Sopenharmony_ci 737562306a36Sopenharmony_ci fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), 737662306a36Sopenharmony_ci &fw_ddb_entry_dma, GFP_KERNEL); 737762306a36Sopenharmony_ci if (!fw_ddb_entry) { 737862306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_ERR, ha, 737962306a36Sopenharmony_ci "%s: Unable to allocate dma buffer\n", 738062306a36Sopenharmony_ci __func__)); 738162306a36Sopenharmony_ci rval = -ENOMEM; 738262306a36Sopenharmony_ci goto exit_ddb_apply; 738362306a36Sopenharmony_ci } 738462306a36Sopenharmony_ci 738562306a36Sopenharmony_ci if (!strncasecmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4)) 738662306a36Sopenharmony_ci options |= IPV6_DEFAULT_DDB_ENTRY; 738762306a36Sopenharmony_ci 738862306a36Sopenharmony_ci rval = qla4xxx_get_default_ddb(ha, options, fw_ddb_entry_dma); 738962306a36Sopenharmony_ci if (rval == QLA_ERROR) 739062306a36Sopenharmony_ci goto exit_ddb_apply; 739162306a36Sopenharmony_ci 739262306a36Sopenharmony_ci dev_db_start_offset += (fnode_sess->target_id * 739362306a36Sopenharmony_ci sizeof(*fw_ddb_entry)); 739462306a36Sopenharmony_ci 739562306a36Sopenharmony_ci qla4xxx_copy_to_fwddb_param(fnode_sess, fnode_conn, fw_ddb_entry); 739662306a36Sopenharmony_ci fw_ddb_entry->cookie = DDB_VALID_COOKIE; 739762306a36Sopenharmony_ci 739862306a36Sopenharmony_ci rval = qla4xxx_set_flash(ha, fw_ddb_entry_dma, dev_db_start_offset, 739962306a36Sopenharmony_ci sizeof(*fw_ddb_entry), FLASH_OPT_RMW_COMMIT); 740062306a36Sopenharmony_ci 740162306a36Sopenharmony_ci if (rval == QLA_SUCCESS) { 740262306a36Sopenharmony_ci fnode_sess->flash_state = DEV_DB_PERSISTENT; 740362306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, 740462306a36Sopenharmony_ci "%s: flash node %u of host %lu written to flash\n", 740562306a36Sopenharmony_ci __func__, fnode_sess->target_id, ha->host_no); 740662306a36Sopenharmony_ci } else { 740762306a36Sopenharmony_ci rval = -EIO; 740862306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, 740962306a36Sopenharmony_ci "%s: Error while writing flash node %u of host %lu to flash\n", 741062306a36Sopenharmony_ci __func__, fnode_sess->target_id, ha->host_no); 741162306a36Sopenharmony_ci } 741262306a36Sopenharmony_ci 741362306a36Sopenharmony_ciexit_ddb_apply: 741462306a36Sopenharmony_ci if (fw_ddb_entry) 741562306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), 741662306a36Sopenharmony_ci fw_ddb_entry, fw_ddb_entry_dma); 741762306a36Sopenharmony_ci return rval; 741862306a36Sopenharmony_ci} 741962306a36Sopenharmony_ci 742062306a36Sopenharmony_cistatic ssize_t qla4xxx_sysfs_ddb_conn_open(struct scsi_qla_host *ha, 742162306a36Sopenharmony_ci struct dev_db_entry *fw_ddb_entry, 742262306a36Sopenharmony_ci uint16_t idx) 742362306a36Sopenharmony_ci{ 742462306a36Sopenharmony_ci struct dev_db_entry *ddb_entry = NULL; 742562306a36Sopenharmony_ci dma_addr_t ddb_entry_dma; 742662306a36Sopenharmony_ci unsigned long wtime; 742762306a36Sopenharmony_ci uint32_t mbx_sts = 0; 742862306a36Sopenharmony_ci uint32_t state = 0, conn_err = 0; 742962306a36Sopenharmony_ci uint16_t tmo = 0; 743062306a36Sopenharmony_ci int ret = 0; 743162306a36Sopenharmony_ci 743262306a36Sopenharmony_ci ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*ddb_entry), 743362306a36Sopenharmony_ci &ddb_entry_dma, GFP_KERNEL); 743462306a36Sopenharmony_ci if (!ddb_entry) { 743562306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_ERR, ha, 743662306a36Sopenharmony_ci "%s: Unable to allocate dma buffer\n", 743762306a36Sopenharmony_ci __func__)); 743862306a36Sopenharmony_ci return QLA_ERROR; 743962306a36Sopenharmony_ci } 744062306a36Sopenharmony_ci 744162306a36Sopenharmony_ci memcpy(ddb_entry, fw_ddb_entry, sizeof(*ddb_entry)); 744262306a36Sopenharmony_ci 744362306a36Sopenharmony_ci ret = qla4xxx_set_ddb_entry(ha, idx, ddb_entry_dma, &mbx_sts); 744462306a36Sopenharmony_ci if (ret != QLA_SUCCESS) { 744562306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_ERR, ha, 744662306a36Sopenharmony_ci "%s: Unable to set ddb entry for index %d\n", 744762306a36Sopenharmony_ci __func__, idx)); 744862306a36Sopenharmony_ci goto exit_ddb_conn_open; 744962306a36Sopenharmony_ci } 745062306a36Sopenharmony_ci 745162306a36Sopenharmony_ci qla4xxx_conn_open(ha, idx); 745262306a36Sopenharmony_ci 745362306a36Sopenharmony_ci /* To ensure that sendtargets is done, wait for at least 12 secs */ 745462306a36Sopenharmony_ci tmo = ((ha->def_timeout > LOGIN_TOV) && 745562306a36Sopenharmony_ci (ha->def_timeout < LOGIN_TOV * 10) ? 745662306a36Sopenharmony_ci ha->def_timeout : LOGIN_TOV); 745762306a36Sopenharmony_ci 745862306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 745962306a36Sopenharmony_ci "Default time to wait for login to ddb %d\n", tmo)); 746062306a36Sopenharmony_ci 746162306a36Sopenharmony_ci wtime = jiffies + (HZ * tmo); 746262306a36Sopenharmony_ci do { 746362306a36Sopenharmony_ci ret = qla4xxx_get_fwddb_entry(ha, idx, NULL, 0, NULL, 746462306a36Sopenharmony_ci NULL, &state, &conn_err, NULL, 746562306a36Sopenharmony_ci NULL); 746662306a36Sopenharmony_ci if (ret == QLA_ERROR) 746762306a36Sopenharmony_ci continue; 746862306a36Sopenharmony_ci 746962306a36Sopenharmony_ci if (state == DDB_DS_NO_CONNECTION_ACTIVE || 747062306a36Sopenharmony_ci state == DDB_DS_SESSION_FAILED) 747162306a36Sopenharmony_ci break; 747262306a36Sopenharmony_ci 747362306a36Sopenharmony_ci schedule_timeout_uninterruptible(HZ / 10); 747462306a36Sopenharmony_ci } while (time_after(wtime, jiffies)); 747562306a36Sopenharmony_ci 747662306a36Sopenharmony_ciexit_ddb_conn_open: 747762306a36Sopenharmony_ci if (ddb_entry) 747862306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, sizeof(*ddb_entry), 747962306a36Sopenharmony_ci ddb_entry, ddb_entry_dma); 748062306a36Sopenharmony_ci return ret; 748162306a36Sopenharmony_ci} 748262306a36Sopenharmony_ci 748362306a36Sopenharmony_cistatic int qla4xxx_ddb_login_st(struct scsi_qla_host *ha, 748462306a36Sopenharmony_ci struct dev_db_entry *fw_ddb_entry, 748562306a36Sopenharmony_ci uint16_t target_id) 748662306a36Sopenharmony_ci{ 748762306a36Sopenharmony_ci struct qla_ddb_index *ddb_idx, *ddb_idx_tmp; 748862306a36Sopenharmony_ci struct list_head list_nt; 748962306a36Sopenharmony_ci uint16_t ddb_index; 749062306a36Sopenharmony_ci int ret = 0; 749162306a36Sopenharmony_ci 749262306a36Sopenharmony_ci if (test_bit(AF_ST_DISCOVERY_IN_PROGRESS, &ha->flags)) { 749362306a36Sopenharmony_ci ql4_printk(KERN_WARNING, ha, 749462306a36Sopenharmony_ci "%s: A discovery already in progress!\n", __func__); 749562306a36Sopenharmony_ci return QLA_ERROR; 749662306a36Sopenharmony_ci } 749762306a36Sopenharmony_ci 749862306a36Sopenharmony_ci INIT_LIST_HEAD(&list_nt); 749962306a36Sopenharmony_ci 750062306a36Sopenharmony_ci set_bit(AF_ST_DISCOVERY_IN_PROGRESS, &ha->flags); 750162306a36Sopenharmony_ci 750262306a36Sopenharmony_ci ret = qla4xxx_get_ddb_index(ha, &ddb_index); 750362306a36Sopenharmony_ci if (ret == QLA_ERROR) 750462306a36Sopenharmony_ci goto exit_login_st_clr_bit; 750562306a36Sopenharmony_ci 750662306a36Sopenharmony_ci ret = qla4xxx_sysfs_ddb_conn_open(ha, fw_ddb_entry, ddb_index); 750762306a36Sopenharmony_ci if (ret == QLA_ERROR) 750862306a36Sopenharmony_ci goto exit_login_st; 750962306a36Sopenharmony_ci 751062306a36Sopenharmony_ci qla4xxx_build_new_nt_list(ha, &list_nt, target_id); 751162306a36Sopenharmony_ci 751262306a36Sopenharmony_ci list_for_each_entry_safe(ddb_idx, ddb_idx_tmp, &list_nt, list) { 751362306a36Sopenharmony_ci list_del_init(&ddb_idx->list); 751462306a36Sopenharmony_ci qla4xxx_clear_ddb_entry(ha, ddb_idx->fw_ddb_idx); 751562306a36Sopenharmony_ci vfree(ddb_idx); 751662306a36Sopenharmony_ci } 751762306a36Sopenharmony_ci 751862306a36Sopenharmony_ciexit_login_st: 751962306a36Sopenharmony_ci if (qla4xxx_clear_ddb_entry(ha, ddb_index) == QLA_ERROR) { 752062306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, 752162306a36Sopenharmony_ci "Unable to clear DDB index = 0x%x\n", ddb_index); 752262306a36Sopenharmony_ci } 752362306a36Sopenharmony_ci 752462306a36Sopenharmony_ci clear_bit(ddb_index, ha->ddb_idx_map); 752562306a36Sopenharmony_ci 752662306a36Sopenharmony_ciexit_login_st_clr_bit: 752762306a36Sopenharmony_ci clear_bit(AF_ST_DISCOVERY_IN_PROGRESS, &ha->flags); 752862306a36Sopenharmony_ci return ret; 752962306a36Sopenharmony_ci} 753062306a36Sopenharmony_ci 753162306a36Sopenharmony_cistatic int qla4xxx_ddb_login_nt(struct scsi_qla_host *ha, 753262306a36Sopenharmony_ci struct dev_db_entry *fw_ddb_entry, 753362306a36Sopenharmony_ci uint16_t idx) 753462306a36Sopenharmony_ci{ 753562306a36Sopenharmony_ci int ret = QLA_ERROR; 753662306a36Sopenharmony_ci 753762306a36Sopenharmony_ci ret = qla4xxx_is_session_exists(ha, fw_ddb_entry, NULL); 753862306a36Sopenharmony_ci if (ret != QLA_SUCCESS) 753962306a36Sopenharmony_ci ret = qla4xxx_sess_conn_setup(ha, fw_ddb_entry, RESET_ADAPTER, 754062306a36Sopenharmony_ci idx); 754162306a36Sopenharmony_ci else 754262306a36Sopenharmony_ci ret = -EPERM; 754362306a36Sopenharmony_ci 754462306a36Sopenharmony_ci return ret; 754562306a36Sopenharmony_ci} 754662306a36Sopenharmony_ci 754762306a36Sopenharmony_ci/** 754862306a36Sopenharmony_ci * qla4xxx_sysfs_ddb_login - Login to the specified target 754962306a36Sopenharmony_ci * @fnode_sess: pointer to session attrs of flash ddb entry 755062306a36Sopenharmony_ci * @fnode_conn: pointer to connection attrs of flash ddb entry 755162306a36Sopenharmony_ci * 755262306a36Sopenharmony_ci * This logs in to the specified target 755362306a36Sopenharmony_ci **/ 755462306a36Sopenharmony_cistatic int qla4xxx_sysfs_ddb_login(struct iscsi_bus_flash_session *fnode_sess, 755562306a36Sopenharmony_ci struct iscsi_bus_flash_conn *fnode_conn) 755662306a36Sopenharmony_ci{ 755762306a36Sopenharmony_ci struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess); 755862306a36Sopenharmony_ci struct scsi_qla_host *ha = to_qla_host(shost); 755962306a36Sopenharmony_ci struct dev_db_entry *fw_ddb_entry = NULL; 756062306a36Sopenharmony_ci dma_addr_t fw_ddb_entry_dma; 756162306a36Sopenharmony_ci uint32_t options = 0; 756262306a36Sopenharmony_ci int ret = 0; 756362306a36Sopenharmony_ci 756462306a36Sopenharmony_ci if (fnode_sess->flash_state == DEV_DB_NON_PERSISTENT) { 756562306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, 756662306a36Sopenharmony_ci "%s: Target info is not persistent\n", __func__); 756762306a36Sopenharmony_ci ret = -EIO; 756862306a36Sopenharmony_ci goto exit_ddb_login; 756962306a36Sopenharmony_ci } 757062306a36Sopenharmony_ci 757162306a36Sopenharmony_ci fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), 757262306a36Sopenharmony_ci &fw_ddb_entry_dma, GFP_KERNEL); 757362306a36Sopenharmony_ci if (!fw_ddb_entry) { 757462306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_ERR, ha, 757562306a36Sopenharmony_ci "%s: Unable to allocate dma buffer\n", 757662306a36Sopenharmony_ci __func__)); 757762306a36Sopenharmony_ci ret = -ENOMEM; 757862306a36Sopenharmony_ci goto exit_ddb_login; 757962306a36Sopenharmony_ci } 758062306a36Sopenharmony_ci 758162306a36Sopenharmony_ci if (!strncasecmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4)) 758262306a36Sopenharmony_ci options |= IPV6_DEFAULT_DDB_ENTRY; 758362306a36Sopenharmony_ci 758462306a36Sopenharmony_ci ret = qla4xxx_get_default_ddb(ha, options, fw_ddb_entry_dma); 758562306a36Sopenharmony_ci if (ret == QLA_ERROR) 758662306a36Sopenharmony_ci goto exit_ddb_login; 758762306a36Sopenharmony_ci 758862306a36Sopenharmony_ci qla4xxx_copy_to_fwddb_param(fnode_sess, fnode_conn, fw_ddb_entry); 758962306a36Sopenharmony_ci fw_ddb_entry->cookie = DDB_VALID_COOKIE; 759062306a36Sopenharmony_ci 759162306a36Sopenharmony_ci if (strlen((char *)fw_ddb_entry->iscsi_name) == 0) 759262306a36Sopenharmony_ci ret = qla4xxx_ddb_login_st(ha, fw_ddb_entry, 759362306a36Sopenharmony_ci fnode_sess->target_id); 759462306a36Sopenharmony_ci else 759562306a36Sopenharmony_ci ret = qla4xxx_ddb_login_nt(ha, fw_ddb_entry, 759662306a36Sopenharmony_ci fnode_sess->target_id); 759762306a36Sopenharmony_ci 759862306a36Sopenharmony_ci if (ret > 0) 759962306a36Sopenharmony_ci ret = -EIO; 760062306a36Sopenharmony_ci 760162306a36Sopenharmony_ciexit_ddb_login: 760262306a36Sopenharmony_ci if (fw_ddb_entry) 760362306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), 760462306a36Sopenharmony_ci fw_ddb_entry, fw_ddb_entry_dma); 760562306a36Sopenharmony_ci return ret; 760662306a36Sopenharmony_ci} 760762306a36Sopenharmony_ci 760862306a36Sopenharmony_ci/** 760962306a36Sopenharmony_ci * qla4xxx_sysfs_ddb_logout_sid - Logout session for the specified target 761062306a36Sopenharmony_ci * @cls_sess: pointer to session to be logged out 761162306a36Sopenharmony_ci * 761262306a36Sopenharmony_ci * This performs session log out from the specified target 761362306a36Sopenharmony_ci **/ 761462306a36Sopenharmony_cistatic int qla4xxx_sysfs_ddb_logout_sid(struct iscsi_cls_session *cls_sess) 761562306a36Sopenharmony_ci{ 761662306a36Sopenharmony_ci struct iscsi_session *sess; 761762306a36Sopenharmony_ci struct ddb_entry *ddb_entry = NULL; 761862306a36Sopenharmony_ci struct scsi_qla_host *ha; 761962306a36Sopenharmony_ci struct dev_db_entry *fw_ddb_entry = NULL; 762062306a36Sopenharmony_ci dma_addr_t fw_ddb_entry_dma; 762162306a36Sopenharmony_ci unsigned long flags; 762262306a36Sopenharmony_ci unsigned long wtime; 762362306a36Sopenharmony_ci uint32_t ddb_state; 762462306a36Sopenharmony_ci int options; 762562306a36Sopenharmony_ci int ret = 0; 762662306a36Sopenharmony_ci 762762306a36Sopenharmony_ci sess = cls_sess->dd_data; 762862306a36Sopenharmony_ci ddb_entry = sess->dd_data; 762962306a36Sopenharmony_ci ha = ddb_entry->ha; 763062306a36Sopenharmony_ci 763162306a36Sopenharmony_ci if (ddb_entry->ddb_type != FLASH_DDB) { 763262306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: Not a flash node session\n", 763362306a36Sopenharmony_ci __func__); 763462306a36Sopenharmony_ci ret = -ENXIO; 763562306a36Sopenharmony_ci goto exit_ddb_logout; 763662306a36Sopenharmony_ci } 763762306a36Sopenharmony_ci 763862306a36Sopenharmony_ci if (test_bit(DF_BOOT_TGT, &ddb_entry->flags)) { 763962306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, 764062306a36Sopenharmony_ci "%s: Logout from boot target entry is not permitted.\n", 764162306a36Sopenharmony_ci __func__); 764262306a36Sopenharmony_ci ret = -EPERM; 764362306a36Sopenharmony_ci goto exit_ddb_logout; 764462306a36Sopenharmony_ci } 764562306a36Sopenharmony_ci 764662306a36Sopenharmony_ci fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), 764762306a36Sopenharmony_ci &fw_ddb_entry_dma, GFP_KERNEL); 764862306a36Sopenharmony_ci if (!fw_ddb_entry) { 764962306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, 765062306a36Sopenharmony_ci "%s: Unable to allocate dma buffer\n", __func__); 765162306a36Sopenharmony_ci ret = -ENOMEM; 765262306a36Sopenharmony_ci goto exit_ddb_logout; 765362306a36Sopenharmony_ci } 765462306a36Sopenharmony_ci 765562306a36Sopenharmony_ci if (test_and_set_bit(DF_DISABLE_RELOGIN, &ddb_entry->flags)) 765662306a36Sopenharmony_ci goto ddb_logout_init; 765762306a36Sopenharmony_ci 765862306a36Sopenharmony_ci ret = qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index, 765962306a36Sopenharmony_ci fw_ddb_entry, fw_ddb_entry_dma, 766062306a36Sopenharmony_ci NULL, NULL, &ddb_state, NULL, 766162306a36Sopenharmony_ci NULL, NULL); 766262306a36Sopenharmony_ci if (ret == QLA_ERROR) 766362306a36Sopenharmony_ci goto ddb_logout_init; 766462306a36Sopenharmony_ci 766562306a36Sopenharmony_ci if (ddb_state == DDB_DS_SESSION_ACTIVE) 766662306a36Sopenharmony_ci goto ddb_logout_init; 766762306a36Sopenharmony_ci 766862306a36Sopenharmony_ci /* wait until next relogin is triggered using DF_RELOGIN and 766962306a36Sopenharmony_ci * clear DF_RELOGIN to avoid invocation of further relogin 767062306a36Sopenharmony_ci */ 767162306a36Sopenharmony_ci wtime = jiffies + (HZ * RELOGIN_TOV); 767262306a36Sopenharmony_ci do { 767362306a36Sopenharmony_ci if (test_and_clear_bit(DF_RELOGIN, &ddb_entry->flags)) 767462306a36Sopenharmony_ci goto ddb_logout_init; 767562306a36Sopenharmony_ci 767662306a36Sopenharmony_ci schedule_timeout_uninterruptible(HZ); 767762306a36Sopenharmony_ci } while ((time_after(wtime, jiffies))); 767862306a36Sopenharmony_ci 767962306a36Sopenharmony_ciddb_logout_init: 768062306a36Sopenharmony_ci atomic_set(&ddb_entry->retry_relogin_timer, INVALID_ENTRY); 768162306a36Sopenharmony_ci atomic_set(&ddb_entry->relogin_timer, 0); 768262306a36Sopenharmony_ci 768362306a36Sopenharmony_ci options = LOGOUT_OPTION_CLOSE_SESSION; 768462306a36Sopenharmony_ci qla4xxx_session_logout_ddb(ha, ddb_entry, options); 768562306a36Sopenharmony_ci 768662306a36Sopenharmony_ci memset(fw_ddb_entry, 0, sizeof(*fw_ddb_entry)); 768762306a36Sopenharmony_ci wtime = jiffies + (HZ * LOGOUT_TOV); 768862306a36Sopenharmony_ci do { 768962306a36Sopenharmony_ci ret = qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index, 769062306a36Sopenharmony_ci fw_ddb_entry, fw_ddb_entry_dma, 769162306a36Sopenharmony_ci NULL, NULL, &ddb_state, NULL, 769262306a36Sopenharmony_ci NULL, NULL); 769362306a36Sopenharmony_ci if (ret == QLA_ERROR) 769462306a36Sopenharmony_ci goto ddb_logout_clr_sess; 769562306a36Sopenharmony_ci 769662306a36Sopenharmony_ci if ((ddb_state == DDB_DS_NO_CONNECTION_ACTIVE) || 769762306a36Sopenharmony_ci (ddb_state == DDB_DS_SESSION_FAILED)) 769862306a36Sopenharmony_ci goto ddb_logout_clr_sess; 769962306a36Sopenharmony_ci 770062306a36Sopenharmony_ci schedule_timeout_uninterruptible(HZ); 770162306a36Sopenharmony_ci } while ((time_after(wtime, jiffies))); 770262306a36Sopenharmony_ci 770362306a36Sopenharmony_ciddb_logout_clr_sess: 770462306a36Sopenharmony_ci qla4xxx_clear_ddb_entry(ha, ddb_entry->fw_ddb_index); 770562306a36Sopenharmony_ci /* 770662306a36Sopenharmony_ci * we have decremented the reference count of the driver 770762306a36Sopenharmony_ci * when we setup the session to have the driver unload 770862306a36Sopenharmony_ci * to be seamless without actually destroying the 770962306a36Sopenharmony_ci * session 771062306a36Sopenharmony_ci **/ 771162306a36Sopenharmony_ci try_module_get(qla4xxx_iscsi_transport.owner); 771262306a36Sopenharmony_ci iscsi_destroy_endpoint(ddb_entry->conn->ep); 771362306a36Sopenharmony_ci 771462306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 771562306a36Sopenharmony_ci qla4xxx_free_ddb(ha, ddb_entry); 771662306a36Sopenharmony_ci clear_bit(ddb_entry->fw_ddb_index, ha->ddb_idx_map); 771762306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 771862306a36Sopenharmony_ci 771962306a36Sopenharmony_ci iscsi_session_teardown(ddb_entry->sess); 772062306a36Sopenharmony_ci 772162306a36Sopenharmony_ci clear_bit(DF_DISABLE_RELOGIN, &ddb_entry->flags); 772262306a36Sopenharmony_ci ret = QLA_SUCCESS; 772362306a36Sopenharmony_ci 772462306a36Sopenharmony_ciexit_ddb_logout: 772562306a36Sopenharmony_ci if (fw_ddb_entry) 772662306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), 772762306a36Sopenharmony_ci fw_ddb_entry, fw_ddb_entry_dma); 772862306a36Sopenharmony_ci return ret; 772962306a36Sopenharmony_ci} 773062306a36Sopenharmony_ci 773162306a36Sopenharmony_ci/** 773262306a36Sopenharmony_ci * qla4xxx_sysfs_ddb_logout - Logout from the specified target 773362306a36Sopenharmony_ci * @fnode_sess: pointer to session attrs of flash ddb entry 773462306a36Sopenharmony_ci * @fnode_conn: pointer to connection attrs of flash ddb entry 773562306a36Sopenharmony_ci * 773662306a36Sopenharmony_ci * This performs log out from the specified target 773762306a36Sopenharmony_ci **/ 773862306a36Sopenharmony_cistatic int qla4xxx_sysfs_ddb_logout(struct iscsi_bus_flash_session *fnode_sess, 773962306a36Sopenharmony_ci struct iscsi_bus_flash_conn *fnode_conn) 774062306a36Sopenharmony_ci{ 774162306a36Sopenharmony_ci struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess); 774262306a36Sopenharmony_ci struct scsi_qla_host *ha = to_qla_host(shost); 774362306a36Sopenharmony_ci struct ql4_tuple_ddb *flash_tddb = NULL; 774462306a36Sopenharmony_ci struct ql4_tuple_ddb *tmp_tddb = NULL; 774562306a36Sopenharmony_ci struct dev_db_entry *fw_ddb_entry = NULL; 774662306a36Sopenharmony_ci struct ddb_entry *ddb_entry = NULL; 774762306a36Sopenharmony_ci dma_addr_t fw_ddb_dma; 774862306a36Sopenharmony_ci uint32_t next_idx = 0; 774962306a36Sopenharmony_ci uint32_t state = 0, conn_err = 0; 775062306a36Sopenharmony_ci uint16_t conn_id = 0; 775162306a36Sopenharmony_ci int idx, index; 775262306a36Sopenharmony_ci int status, ret = 0; 775362306a36Sopenharmony_ci 775462306a36Sopenharmony_ci fw_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL, 775562306a36Sopenharmony_ci &fw_ddb_dma); 775662306a36Sopenharmony_ci if (fw_ddb_entry == NULL) { 775762306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s:Out of memory\n", __func__); 775862306a36Sopenharmony_ci ret = -ENOMEM; 775962306a36Sopenharmony_ci goto exit_ddb_logout; 776062306a36Sopenharmony_ci } 776162306a36Sopenharmony_ci 776262306a36Sopenharmony_ci flash_tddb = vzalloc(sizeof(*flash_tddb)); 776362306a36Sopenharmony_ci if (!flash_tddb) { 776462306a36Sopenharmony_ci ql4_printk(KERN_WARNING, ha, 776562306a36Sopenharmony_ci "%s:Memory Allocation failed.\n", __func__); 776662306a36Sopenharmony_ci ret = -ENOMEM; 776762306a36Sopenharmony_ci goto exit_ddb_logout; 776862306a36Sopenharmony_ci } 776962306a36Sopenharmony_ci 777062306a36Sopenharmony_ci tmp_tddb = vzalloc(sizeof(*tmp_tddb)); 777162306a36Sopenharmony_ci if (!tmp_tddb) { 777262306a36Sopenharmony_ci ql4_printk(KERN_WARNING, ha, 777362306a36Sopenharmony_ci "%s:Memory Allocation failed.\n", __func__); 777462306a36Sopenharmony_ci ret = -ENOMEM; 777562306a36Sopenharmony_ci goto exit_ddb_logout; 777662306a36Sopenharmony_ci } 777762306a36Sopenharmony_ci 777862306a36Sopenharmony_ci if (!fnode_sess->targetname) { 777962306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, 778062306a36Sopenharmony_ci "%s:Cannot logout from SendTarget entry\n", 778162306a36Sopenharmony_ci __func__); 778262306a36Sopenharmony_ci ret = -EPERM; 778362306a36Sopenharmony_ci goto exit_ddb_logout; 778462306a36Sopenharmony_ci } 778562306a36Sopenharmony_ci 778662306a36Sopenharmony_ci if (fnode_sess->is_boot_target) { 778762306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, 778862306a36Sopenharmony_ci "%s: Logout from boot target entry is not permitted.\n", 778962306a36Sopenharmony_ci __func__); 779062306a36Sopenharmony_ci ret = -EPERM; 779162306a36Sopenharmony_ci goto exit_ddb_logout; 779262306a36Sopenharmony_ci } 779362306a36Sopenharmony_ci 779462306a36Sopenharmony_ci strscpy(flash_tddb->iscsi_name, fnode_sess->targetname, 779562306a36Sopenharmony_ci ISCSI_NAME_SIZE); 779662306a36Sopenharmony_ci 779762306a36Sopenharmony_ci if (!strncmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4)) 779862306a36Sopenharmony_ci sprintf(flash_tddb->ip_addr, "%pI6", fnode_conn->ipaddress); 779962306a36Sopenharmony_ci else 780062306a36Sopenharmony_ci sprintf(flash_tddb->ip_addr, "%pI4", fnode_conn->ipaddress); 780162306a36Sopenharmony_ci 780262306a36Sopenharmony_ci flash_tddb->tpgt = fnode_sess->tpgt; 780362306a36Sopenharmony_ci flash_tddb->port = fnode_conn->port; 780462306a36Sopenharmony_ci 780562306a36Sopenharmony_ci COPY_ISID(flash_tddb->isid, fnode_sess->isid); 780662306a36Sopenharmony_ci 780762306a36Sopenharmony_ci for (idx = 0; idx < MAX_DDB_ENTRIES; idx++) { 780862306a36Sopenharmony_ci ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx); 780962306a36Sopenharmony_ci if (ddb_entry == NULL) 781062306a36Sopenharmony_ci continue; 781162306a36Sopenharmony_ci 781262306a36Sopenharmony_ci if (ddb_entry->ddb_type != FLASH_DDB) 781362306a36Sopenharmony_ci continue; 781462306a36Sopenharmony_ci 781562306a36Sopenharmony_ci index = ddb_entry->sess->target_id; 781662306a36Sopenharmony_ci status = qla4xxx_get_fwddb_entry(ha, index, fw_ddb_entry, 781762306a36Sopenharmony_ci fw_ddb_dma, NULL, &next_idx, 781862306a36Sopenharmony_ci &state, &conn_err, NULL, 781962306a36Sopenharmony_ci &conn_id); 782062306a36Sopenharmony_ci if (status == QLA_ERROR) { 782162306a36Sopenharmony_ci ret = -ENOMEM; 782262306a36Sopenharmony_ci break; 782362306a36Sopenharmony_ci } 782462306a36Sopenharmony_ci 782562306a36Sopenharmony_ci qla4xxx_convert_param_ddb(fw_ddb_entry, tmp_tddb, NULL); 782662306a36Sopenharmony_ci 782762306a36Sopenharmony_ci status = qla4xxx_compare_tuple_ddb(ha, flash_tddb, tmp_tddb, 782862306a36Sopenharmony_ci true); 782962306a36Sopenharmony_ci if (status == QLA_SUCCESS) { 783062306a36Sopenharmony_ci ret = qla4xxx_sysfs_ddb_logout_sid(ddb_entry->sess); 783162306a36Sopenharmony_ci break; 783262306a36Sopenharmony_ci } 783362306a36Sopenharmony_ci } 783462306a36Sopenharmony_ci 783562306a36Sopenharmony_ci if (idx == MAX_DDB_ENTRIES) 783662306a36Sopenharmony_ci ret = -ESRCH; 783762306a36Sopenharmony_ci 783862306a36Sopenharmony_ciexit_ddb_logout: 783962306a36Sopenharmony_ci vfree(flash_tddb); 784062306a36Sopenharmony_ci vfree(tmp_tddb); 784162306a36Sopenharmony_ci if (fw_ddb_entry) 784262306a36Sopenharmony_ci dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma); 784362306a36Sopenharmony_ci 784462306a36Sopenharmony_ci return ret; 784562306a36Sopenharmony_ci} 784662306a36Sopenharmony_ci 784762306a36Sopenharmony_cistatic int 784862306a36Sopenharmony_ciqla4xxx_sysfs_ddb_get_param(struct iscsi_bus_flash_session *fnode_sess, 784962306a36Sopenharmony_ci int param, char *buf) 785062306a36Sopenharmony_ci{ 785162306a36Sopenharmony_ci struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess); 785262306a36Sopenharmony_ci struct scsi_qla_host *ha = to_qla_host(shost); 785362306a36Sopenharmony_ci struct iscsi_bus_flash_conn *fnode_conn; 785462306a36Sopenharmony_ci struct ql4_chap_table chap_tbl; 785562306a36Sopenharmony_ci struct device *dev; 785662306a36Sopenharmony_ci int parent_type; 785762306a36Sopenharmony_ci int rc = 0; 785862306a36Sopenharmony_ci 785962306a36Sopenharmony_ci dev = iscsi_find_flashnode_conn(fnode_sess); 786062306a36Sopenharmony_ci if (!dev) 786162306a36Sopenharmony_ci return -EIO; 786262306a36Sopenharmony_ci 786362306a36Sopenharmony_ci fnode_conn = iscsi_dev_to_flash_conn(dev); 786462306a36Sopenharmony_ci 786562306a36Sopenharmony_ci switch (param) { 786662306a36Sopenharmony_ci case ISCSI_FLASHNODE_IS_FW_ASSIGNED_IPV6: 786762306a36Sopenharmony_ci rc = sprintf(buf, "%u\n", fnode_conn->is_fw_assigned_ipv6); 786862306a36Sopenharmony_ci break; 786962306a36Sopenharmony_ci case ISCSI_FLASHNODE_PORTAL_TYPE: 787062306a36Sopenharmony_ci rc = sprintf(buf, "%s\n", fnode_sess->portal_type); 787162306a36Sopenharmony_ci break; 787262306a36Sopenharmony_ci case ISCSI_FLASHNODE_AUTO_SND_TGT_DISABLE: 787362306a36Sopenharmony_ci rc = sprintf(buf, "%u\n", fnode_sess->auto_snd_tgt_disable); 787462306a36Sopenharmony_ci break; 787562306a36Sopenharmony_ci case ISCSI_FLASHNODE_DISCOVERY_SESS: 787662306a36Sopenharmony_ci rc = sprintf(buf, "%u\n", fnode_sess->discovery_sess); 787762306a36Sopenharmony_ci break; 787862306a36Sopenharmony_ci case ISCSI_FLASHNODE_ENTRY_EN: 787962306a36Sopenharmony_ci rc = sprintf(buf, "%u\n", fnode_sess->entry_state); 788062306a36Sopenharmony_ci break; 788162306a36Sopenharmony_ci case ISCSI_FLASHNODE_HDR_DGST_EN: 788262306a36Sopenharmony_ci rc = sprintf(buf, "%u\n", fnode_conn->hdrdgst_en); 788362306a36Sopenharmony_ci break; 788462306a36Sopenharmony_ci case ISCSI_FLASHNODE_DATA_DGST_EN: 788562306a36Sopenharmony_ci rc = sprintf(buf, "%u\n", fnode_conn->datadgst_en); 788662306a36Sopenharmony_ci break; 788762306a36Sopenharmony_ci case ISCSI_FLASHNODE_IMM_DATA_EN: 788862306a36Sopenharmony_ci rc = sprintf(buf, "%u\n", fnode_sess->imm_data_en); 788962306a36Sopenharmony_ci break; 789062306a36Sopenharmony_ci case ISCSI_FLASHNODE_INITIAL_R2T_EN: 789162306a36Sopenharmony_ci rc = sprintf(buf, "%u\n", fnode_sess->initial_r2t_en); 789262306a36Sopenharmony_ci break; 789362306a36Sopenharmony_ci case ISCSI_FLASHNODE_DATASEQ_INORDER: 789462306a36Sopenharmony_ci rc = sprintf(buf, "%u\n", fnode_sess->dataseq_inorder_en); 789562306a36Sopenharmony_ci break; 789662306a36Sopenharmony_ci case ISCSI_FLASHNODE_PDU_INORDER: 789762306a36Sopenharmony_ci rc = sprintf(buf, "%u\n", fnode_sess->pdu_inorder_en); 789862306a36Sopenharmony_ci break; 789962306a36Sopenharmony_ci case ISCSI_FLASHNODE_CHAP_AUTH_EN: 790062306a36Sopenharmony_ci rc = sprintf(buf, "%u\n", fnode_sess->chap_auth_en); 790162306a36Sopenharmony_ci break; 790262306a36Sopenharmony_ci case ISCSI_FLASHNODE_SNACK_REQ_EN: 790362306a36Sopenharmony_ci rc = sprintf(buf, "%u\n", fnode_conn->snack_req_en); 790462306a36Sopenharmony_ci break; 790562306a36Sopenharmony_ci case ISCSI_FLASHNODE_DISCOVERY_LOGOUT_EN: 790662306a36Sopenharmony_ci rc = sprintf(buf, "%u\n", fnode_sess->discovery_logout_en); 790762306a36Sopenharmony_ci break; 790862306a36Sopenharmony_ci case ISCSI_FLASHNODE_BIDI_CHAP_EN: 790962306a36Sopenharmony_ci rc = sprintf(buf, "%u\n", fnode_sess->bidi_chap_en); 791062306a36Sopenharmony_ci break; 791162306a36Sopenharmony_ci case ISCSI_FLASHNODE_DISCOVERY_AUTH_OPTIONAL: 791262306a36Sopenharmony_ci rc = sprintf(buf, "%u\n", fnode_sess->discovery_auth_optional); 791362306a36Sopenharmony_ci break; 791462306a36Sopenharmony_ci case ISCSI_FLASHNODE_ERL: 791562306a36Sopenharmony_ci rc = sprintf(buf, "%u\n", fnode_sess->erl); 791662306a36Sopenharmony_ci break; 791762306a36Sopenharmony_ci case ISCSI_FLASHNODE_TCP_TIMESTAMP_STAT: 791862306a36Sopenharmony_ci rc = sprintf(buf, "%u\n", fnode_conn->tcp_timestamp_stat); 791962306a36Sopenharmony_ci break; 792062306a36Sopenharmony_ci case ISCSI_FLASHNODE_TCP_NAGLE_DISABLE: 792162306a36Sopenharmony_ci rc = sprintf(buf, "%u\n", fnode_conn->tcp_nagle_disable); 792262306a36Sopenharmony_ci break; 792362306a36Sopenharmony_ci case ISCSI_FLASHNODE_TCP_WSF_DISABLE: 792462306a36Sopenharmony_ci rc = sprintf(buf, "%u\n", fnode_conn->tcp_wsf_disable); 792562306a36Sopenharmony_ci break; 792662306a36Sopenharmony_ci case ISCSI_FLASHNODE_TCP_TIMER_SCALE: 792762306a36Sopenharmony_ci rc = sprintf(buf, "%u\n", fnode_conn->tcp_timer_scale); 792862306a36Sopenharmony_ci break; 792962306a36Sopenharmony_ci case ISCSI_FLASHNODE_TCP_TIMESTAMP_EN: 793062306a36Sopenharmony_ci rc = sprintf(buf, "%u\n", fnode_conn->tcp_timestamp_en); 793162306a36Sopenharmony_ci break; 793262306a36Sopenharmony_ci case ISCSI_FLASHNODE_IP_FRAG_DISABLE: 793362306a36Sopenharmony_ci rc = sprintf(buf, "%u\n", fnode_conn->fragment_disable); 793462306a36Sopenharmony_ci break; 793562306a36Sopenharmony_ci case ISCSI_FLASHNODE_MAX_RECV_DLENGTH: 793662306a36Sopenharmony_ci rc = sprintf(buf, "%u\n", fnode_conn->max_recv_dlength); 793762306a36Sopenharmony_ci break; 793862306a36Sopenharmony_ci case ISCSI_FLASHNODE_MAX_XMIT_DLENGTH: 793962306a36Sopenharmony_ci rc = sprintf(buf, "%u\n", fnode_conn->max_xmit_dlength); 794062306a36Sopenharmony_ci break; 794162306a36Sopenharmony_ci case ISCSI_FLASHNODE_FIRST_BURST: 794262306a36Sopenharmony_ci rc = sprintf(buf, "%u\n", fnode_sess->first_burst); 794362306a36Sopenharmony_ci break; 794462306a36Sopenharmony_ci case ISCSI_FLASHNODE_DEF_TIME2WAIT: 794562306a36Sopenharmony_ci rc = sprintf(buf, "%u\n", fnode_sess->time2wait); 794662306a36Sopenharmony_ci break; 794762306a36Sopenharmony_ci case ISCSI_FLASHNODE_DEF_TIME2RETAIN: 794862306a36Sopenharmony_ci rc = sprintf(buf, "%u\n", fnode_sess->time2retain); 794962306a36Sopenharmony_ci break; 795062306a36Sopenharmony_ci case ISCSI_FLASHNODE_MAX_R2T: 795162306a36Sopenharmony_ci rc = sprintf(buf, "%u\n", fnode_sess->max_r2t); 795262306a36Sopenharmony_ci break; 795362306a36Sopenharmony_ci case ISCSI_FLASHNODE_KEEPALIVE_TMO: 795462306a36Sopenharmony_ci rc = sprintf(buf, "%u\n", fnode_conn->keepalive_timeout); 795562306a36Sopenharmony_ci break; 795662306a36Sopenharmony_ci case ISCSI_FLASHNODE_ISID: 795762306a36Sopenharmony_ci rc = sprintf(buf, "%pm\n", fnode_sess->isid); 795862306a36Sopenharmony_ci break; 795962306a36Sopenharmony_ci case ISCSI_FLASHNODE_TSID: 796062306a36Sopenharmony_ci rc = sprintf(buf, "%u\n", fnode_sess->tsid); 796162306a36Sopenharmony_ci break; 796262306a36Sopenharmony_ci case ISCSI_FLASHNODE_PORT: 796362306a36Sopenharmony_ci rc = sprintf(buf, "%d\n", fnode_conn->port); 796462306a36Sopenharmony_ci break; 796562306a36Sopenharmony_ci case ISCSI_FLASHNODE_MAX_BURST: 796662306a36Sopenharmony_ci rc = sprintf(buf, "%u\n", fnode_sess->max_burst); 796762306a36Sopenharmony_ci break; 796862306a36Sopenharmony_ci case ISCSI_FLASHNODE_DEF_TASKMGMT_TMO: 796962306a36Sopenharmony_ci rc = sprintf(buf, "%u\n", 797062306a36Sopenharmony_ci fnode_sess->default_taskmgmt_timeout); 797162306a36Sopenharmony_ci break; 797262306a36Sopenharmony_ci case ISCSI_FLASHNODE_IPADDR: 797362306a36Sopenharmony_ci if (!strncmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4)) 797462306a36Sopenharmony_ci rc = sprintf(buf, "%pI6\n", fnode_conn->ipaddress); 797562306a36Sopenharmony_ci else 797662306a36Sopenharmony_ci rc = sprintf(buf, "%pI4\n", fnode_conn->ipaddress); 797762306a36Sopenharmony_ci break; 797862306a36Sopenharmony_ci case ISCSI_FLASHNODE_ALIAS: 797962306a36Sopenharmony_ci if (fnode_sess->targetalias) 798062306a36Sopenharmony_ci rc = sprintf(buf, "%s\n", fnode_sess->targetalias); 798162306a36Sopenharmony_ci else 798262306a36Sopenharmony_ci rc = sprintf(buf, "\n"); 798362306a36Sopenharmony_ci break; 798462306a36Sopenharmony_ci case ISCSI_FLASHNODE_REDIRECT_IPADDR: 798562306a36Sopenharmony_ci if (!strncmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4)) 798662306a36Sopenharmony_ci rc = sprintf(buf, "%pI6\n", 798762306a36Sopenharmony_ci fnode_conn->redirect_ipaddr); 798862306a36Sopenharmony_ci else 798962306a36Sopenharmony_ci rc = sprintf(buf, "%pI4\n", 799062306a36Sopenharmony_ci fnode_conn->redirect_ipaddr); 799162306a36Sopenharmony_ci break; 799262306a36Sopenharmony_ci case ISCSI_FLASHNODE_MAX_SEGMENT_SIZE: 799362306a36Sopenharmony_ci rc = sprintf(buf, "%u\n", fnode_conn->max_segment_size); 799462306a36Sopenharmony_ci break; 799562306a36Sopenharmony_ci case ISCSI_FLASHNODE_LOCAL_PORT: 799662306a36Sopenharmony_ci rc = sprintf(buf, "%u\n", fnode_conn->local_port); 799762306a36Sopenharmony_ci break; 799862306a36Sopenharmony_ci case ISCSI_FLASHNODE_IPV4_TOS: 799962306a36Sopenharmony_ci rc = sprintf(buf, "%u\n", fnode_conn->ipv4_tos); 800062306a36Sopenharmony_ci break; 800162306a36Sopenharmony_ci case ISCSI_FLASHNODE_IPV6_TC: 800262306a36Sopenharmony_ci if (!strncmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4)) 800362306a36Sopenharmony_ci rc = sprintf(buf, "%u\n", 800462306a36Sopenharmony_ci fnode_conn->ipv6_traffic_class); 800562306a36Sopenharmony_ci else 800662306a36Sopenharmony_ci rc = sprintf(buf, "\n"); 800762306a36Sopenharmony_ci break; 800862306a36Sopenharmony_ci case ISCSI_FLASHNODE_IPV6_FLOW_LABEL: 800962306a36Sopenharmony_ci rc = sprintf(buf, "%u\n", fnode_conn->ipv6_flow_label); 801062306a36Sopenharmony_ci break; 801162306a36Sopenharmony_ci case ISCSI_FLASHNODE_LINK_LOCAL_IPV6: 801262306a36Sopenharmony_ci if (!strncmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4)) 801362306a36Sopenharmony_ci rc = sprintf(buf, "%pI6\n", 801462306a36Sopenharmony_ci fnode_conn->link_local_ipv6_addr); 801562306a36Sopenharmony_ci else 801662306a36Sopenharmony_ci rc = sprintf(buf, "\n"); 801762306a36Sopenharmony_ci break; 801862306a36Sopenharmony_ci case ISCSI_FLASHNODE_DISCOVERY_PARENT_IDX: 801962306a36Sopenharmony_ci rc = sprintf(buf, "%u\n", fnode_sess->discovery_parent_idx); 802062306a36Sopenharmony_ci break; 802162306a36Sopenharmony_ci case ISCSI_FLASHNODE_DISCOVERY_PARENT_TYPE: 802262306a36Sopenharmony_ci if (fnode_sess->discovery_parent_type == DDB_ISNS) 802362306a36Sopenharmony_ci parent_type = ISCSI_DISC_PARENT_ISNS; 802462306a36Sopenharmony_ci else if (fnode_sess->discovery_parent_type == DDB_NO_LINK) 802562306a36Sopenharmony_ci parent_type = ISCSI_DISC_PARENT_UNKNOWN; 802662306a36Sopenharmony_ci else if (fnode_sess->discovery_parent_type < MAX_DDB_ENTRIES) 802762306a36Sopenharmony_ci parent_type = ISCSI_DISC_PARENT_SENDTGT; 802862306a36Sopenharmony_ci else 802962306a36Sopenharmony_ci parent_type = ISCSI_DISC_PARENT_UNKNOWN; 803062306a36Sopenharmony_ci 803162306a36Sopenharmony_ci rc = sprintf(buf, "%s\n", 803262306a36Sopenharmony_ci iscsi_get_discovery_parent_name(parent_type)); 803362306a36Sopenharmony_ci break; 803462306a36Sopenharmony_ci case ISCSI_FLASHNODE_NAME: 803562306a36Sopenharmony_ci if (fnode_sess->targetname) 803662306a36Sopenharmony_ci rc = sprintf(buf, "%s\n", fnode_sess->targetname); 803762306a36Sopenharmony_ci else 803862306a36Sopenharmony_ci rc = sprintf(buf, "\n"); 803962306a36Sopenharmony_ci break; 804062306a36Sopenharmony_ci case ISCSI_FLASHNODE_TPGT: 804162306a36Sopenharmony_ci rc = sprintf(buf, "%u\n", fnode_sess->tpgt); 804262306a36Sopenharmony_ci break; 804362306a36Sopenharmony_ci case ISCSI_FLASHNODE_TCP_XMIT_WSF: 804462306a36Sopenharmony_ci rc = sprintf(buf, "%u\n", fnode_conn->tcp_xmit_wsf); 804562306a36Sopenharmony_ci break; 804662306a36Sopenharmony_ci case ISCSI_FLASHNODE_TCP_RECV_WSF: 804762306a36Sopenharmony_ci rc = sprintf(buf, "%u\n", fnode_conn->tcp_recv_wsf); 804862306a36Sopenharmony_ci break; 804962306a36Sopenharmony_ci case ISCSI_FLASHNODE_CHAP_OUT_IDX: 805062306a36Sopenharmony_ci rc = sprintf(buf, "%u\n", fnode_sess->chap_out_idx); 805162306a36Sopenharmony_ci break; 805262306a36Sopenharmony_ci case ISCSI_FLASHNODE_USERNAME: 805362306a36Sopenharmony_ci if (fnode_sess->chap_auth_en) { 805462306a36Sopenharmony_ci qla4xxx_get_uni_chap_at_index(ha, 805562306a36Sopenharmony_ci chap_tbl.name, 805662306a36Sopenharmony_ci chap_tbl.secret, 805762306a36Sopenharmony_ci fnode_sess->chap_out_idx); 805862306a36Sopenharmony_ci rc = sprintf(buf, "%s\n", chap_tbl.name); 805962306a36Sopenharmony_ci } else { 806062306a36Sopenharmony_ci rc = sprintf(buf, "\n"); 806162306a36Sopenharmony_ci } 806262306a36Sopenharmony_ci break; 806362306a36Sopenharmony_ci case ISCSI_FLASHNODE_PASSWORD: 806462306a36Sopenharmony_ci if (fnode_sess->chap_auth_en) { 806562306a36Sopenharmony_ci qla4xxx_get_uni_chap_at_index(ha, 806662306a36Sopenharmony_ci chap_tbl.name, 806762306a36Sopenharmony_ci chap_tbl.secret, 806862306a36Sopenharmony_ci fnode_sess->chap_out_idx); 806962306a36Sopenharmony_ci rc = sprintf(buf, "%s\n", chap_tbl.secret); 807062306a36Sopenharmony_ci } else { 807162306a36Sopenharmony_ci rc = sprintf(buf, "\n"); 807262306a36Sopenharmony_ci } 807362306a36Sopenharmony_ci break; 807462306a36Sopenharmony_ci case ISCSI_FLASHNODE_STATSN: 807562306a36Sopenharmony_ci rc = sprintf(buf, "%u\n", fnode_conn->statsn); 807662306a36Sopenharmony_ci break; 807762306a36Sopenharmony_ci case ISCSI_FLASHNODE_EXP_STATSN: 807862306a36Sopenharmony_ci rc = sprintf(buf, "%u\n", fnode_conn->exp_statsn); 807962306a36Sopenharmony_ci break; 808062306a36Sopenharmony_ci case ISCSI_FLASHNODE_IS_BOOT_TGT: 808162306a36Sopenharmony_ci rc = sprintf(buf, "%u\n", fnode_sess->is_boot_target); 808262306a36Sopenharmony_ci break; 808362306a36Sopenharmony_ci default: 808462306a36Sopenharmony_ci rc = -ENOSYS; 808562306a36Sopenharmony_ci break; 808662306a36Sopenharmony_ci } 808762306a36Sopenharmony_ci 808862306a36Sopenharmony_ci put_device(dev); 808962306a36Sopenharmony_ci return rc; 809062306a36Sopenharmony_ci} 809162306a36Sopenharmony_ci 809262306a36Sopenharmony_ci/** 809362306a36Sopenharmony_ci * qla4xxx_sysfs_ddb_set_param - Set parameter for firmware DDB entry 809462306a36Sopenharmony_ci * @fnode_sess: pointer to session attrs of flash ddb entry 809562306a36Sopenharmony_ci * @fnode_conn: pointer to connection attrs of flash ddb entry 809662306a36Sopenharmony_ci * @data: Parameters and their values to update 809762306a36Sopenharmony_ci * @len: len of data 809862306a36Sopenharmony_ci * 809962306a36Sopenharmony_ci * This sets the parameter of flash ddb entry and writes them to flash 810062306a36Sopenharmony_ci **/ 810162306a36Sopenharmony_cistatic int 810262306a36Sopenharmony_ciqla4xxx_sysfs_ddb_set_param(struct iscsi_bus_flash_session *fnode_sess, 810362306a36Sopenharmony_ci struct iscsi_bus_flash_conn *fnode_conn, 810462306a36Sopenharmony_ci void *data, int len) 810562306a36Sopenharmony_ci{ 810662306a36Sopenharmony_ci struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess); 810762306a36Sopenharmony_ci struct scsi_qla_host *ha = to_qla_host(shost); 810862306a36Sopenharmony_ci struct iscsi_flashnode_param_info *fnode_param; 810962306a36Sopenharmony_ci struct ql4_chap_table chap_tbl; 811062306a36Sopenharmony_ci struct nlattr *attr; 811162306a36Sopenharmony_ci uint16_t chap_out_idx = INVALID_ENTRY; 811262306a36Sopenharmony_ci int rc = QLA_ERROR; 811362306a36Sopenharmony_ci uint32_t rem = len; 811462306a36Sopenharmony_ci 811562306a36Sopenharmony_ci memset((void *)&chap_tbl, 0, sizeof(chap_tbl)); 811662306a36Sopenharmony_ci nla_for_each_attr(attr, data, len, rem) { 811762306a36Sopenharmony_ci if (nla_len(attr) < sizeof(*fnode_param)) { 811862306a36Sopenharmony_ci rc = -EINVAL; 811962306a36Sopenharmony_ci goto exit_set_param; 812062306a36Sopenharmony_ci } 812162306a36Sopenharmony_ci 812262306a36Sopenharmony_ci fnode_param = nla_data(attr); 812362306a36Sopenharmony_ci 812462306a36Sopenharmony_ci switch (fnode_param->param) { 812562306a36Sopenharmony_ci case ISCSI_FLASHNODE_IS_FW_ASSIGNED_IPV6: 812662306a36Sopenharmony_ci fnode_conn->is_fw_assigned_ipv6 = fnode_param->value[0]; 812762306a36Sopenharmony_ci break; 812862306a36Sopenharmony_ci case ISCSI_FLASHNODE_PORTAL_TYPE: 812962306a36Sopenharmony_ci memcpy(fnode_sess->portal_type, fnode_param->value, 813062306a36Sopenharmony_ci strlen(fnode_sess->portal_type)); 813162306a36Sopenharmony_ci break; 813262306a36Sopenharmony_ci case ISCSI_FLASHNODE_AUTO_SND_TGT_DISABLE: 813362306a36Sopenharmony_ci fnode_sess->auto_snd_tgt_disable = 813462306a36Sopenharmony_ci fnode_param->value[0]; 813562306a36Sopenharmony_ci break; 813662306a36Sopenharmony_ci case ISCSI_FLASHNODE_DISCOVERY_SESS: 813762306a36Sopenharmony_ci fnode_sess->discovery_sess = fnode_param->value[0]; 813862306a36Sopenharmony_ci break; 813962306a36Sopenharmony_ci case ISCSI_FLASHNODE_ENTRY_EN: 814062306a36Sopenharmony_ci fnode_sess->entry_state = fnode_param->value[0]; 814162306a36Sopenharmony_ci break; 814262306a36Sopenharmony_ci case ISCSI_FLASHNODE_HDR_DGST_EN: 814362306a36Sopenharmony_ci fnode_conn->hdrdgst_en = fnode_param->value[0]; 814462306a36Sopenharmony_ci break; 814562306a36Sopenharmony_ci case ISCSI_FLASHNODE_DATA_DGST_EN: 814662306a36Sopenharmony_ci fnode_conn->datadgst_en = fnode_param->value[0]; 814762306a36Sopenharmony_ci break; 814862306a36Sopenharmony_ci case ISCSI_FLASHNODE_IMM_DATA_EN: 814962306a36Sopenharmony_ci fnode_sess->imm_data_en = fnode_param->value[0]; 815062306a36Sopenharmony_ci break; 815162306a36Sopenharmony_ci case ISCSI_FLASHNODE_INITIAL_R2T_EN: 815262306a36Sopenharmony_ci fnode_sess->initial_r2t_en = fnode_param->value[0]; 815362306a36Sopenharmony_ci break; 815462306a36Sopenharmony_ci case ISCSI_FLASHNODE_DATASEQ_INORDER: 815562306a36Sopenharmony_ci fnode_sess->dataseq_inorder_en = fnode_param->value[0]; 815662306a36Sopenharmony_ci break; 815762306a36Sopenharmony_ci case ISCSI_FLASHNODE_PDU_INORDER: 815862306a36Sopenharmony_ci fnode_sess->pdu_inorder_en = fnode_param->value[0]; 815962306a36Sopenharmony_ci break; 816062306a36Sopenharmony_ci case ISCSI_FLASHNODE_CHAP_AUTH_EN: 816162306a36Sopenharmony_ci fnode_sess->chap_auth_en = fnode_param->value[0]; 816262306a36Sopenharmony_ci /* Invalidate chap index if chap auth is disabled */ 816362306a36Sopenharmony_ci if (!fnode_sess->chap_auth_en) 816462306a36Sopenharmony_ci fnode_sess->chap_out_idx = INVALID_ENTRY; 816562306a36Sopenharmony_ci 816662306a36Sopenharmony_ci break; 816762306a36Sopenharmony_ci case ISCSI_FLASHNODE_SNACK_REQ_EN: 816862306a36Sopenharmony_ci fnode_conn->snack_req_en = fnode_param->value[0]; 816962306a36Sopenharmony_ci break; 817062306a36Sopenharmony_ci case ISCSI_FLASHNODE_DISCOVERY_LOGOUT_EN: 817162306a36Sopenharmony_ci fnode_sess->discovery_logout_en = fnode_param->value[0]; 817262306a36Sopenharmony_ci break; 817362306a36Sopenharmony_ci case ISCSI_FLASHNODE_BIDI_CHAP_EN: 817462306a36Sopenharmony_ci fnode_sess->bidi_chap_en = fnode_param->value[0]; 817562306a36Sopenharmony_ci break; 817662306a36Sopenharmony_ci case ISCSI_FLASHNODE_DISCOVERY_AUTH_OPTIONAL: 817762306a36Sopenharmony_ci fnode_sess->discovery_auth_optional = 817862306a36Sopenharmony_ci fnode_param->value[0]; 817962306a36Sopenharmony_ci break; 818062306a36Sopenharmony_ci case ISCSI_FLASHNODE_ERL: 818162306a36Sopenharmony_ci fnode_sess->erl = fnode_param->value[0]; 818262306a36Sopenharmony_ci break; 818362306a36Sopenharmony_ci case ISCSI_FLASHNODE_TCP_TIMESTAMP_STAT: 818462306a36Sopenharmony_ci fnode_conn->tcp_timestamp_stat = fnode_param->value[0]; 818562306a36Sopenharmony_ci break; 818662306a36Sopenharmony_ci case ISCSI_FLASHNODE_TCP_NAGLE_DISABLE: 818762306a36Sopenharmony_ci fnode_conn->tcp_nagle_disable = fnode_param->value[0]; 818862306a36Sopenharmony_ci break; 818962306a36Sopenharmony_ci case ISCSI_FLASHNODE_TCP_WSF_DISABLE: 819062306a36Sopenharmony_ci fnode_conn->tcp_wsf_disable = fnode_param->value[0]; 819162306a36Sopenharmony_ci break; 819262306a36Sopenharmony_ci case ISCSI_FLASHNODE_TCP_TIMER_SCALE: 819362306a36Sopenharmony_ci fnode_conn->tcp_timer_scale = fnode_param->value[0]; 819462306a36Sopenharmony_ci break; 819562306a36Sopenharmony_ci case ISCSI_FLASHNODE_TCP_TIMESTAMP_EN: 819662306a36Sopenharmony_ci fnode_conn->tcp_timestamp_en = fnode_param->value[0]; 819762306a36Sopenharmony_ci break; 819862306a36Sopenharmony_ci case ISCSI_FLASHNODE_IP_FRAG_DISABLE: 819962306a36Sopenharmony_ci fnode_conn->fragment_disable = fnode_param->value[0]; 820062306a36Sopenharmony_ci break; 820162306a36Sopenharmony_ci case ISCSI_FLASHNODE_MAX_RECV_DLENGTH: 820262306a36Sopenharmony_ci fnode_conn->max_recv_dlength = 820362306a36Sopenharmony_ci *(unsigned *)fnode_param->value; 820462306a36Sopenharmony_ci break; 820562306a36Sopenharmony_ci case ISCSI_FLASHNODE_MAX_XMIT_DLENGTH: 820662306a36Sopenharmony_ci fnode_conn->max_xmit_dlength = 820762306a36Sopenharmony_ci *(unsigned *)fnode_param->value; 820862306a36Sopenharmony_ci break; 820962306a36Sopenharmony_ci case ISCSI_FLASHNODE_FIRST_BURST: 821062306a36Sopenharmony_ci fnode_sess->first_burst = 821162306a36Sopenharmony_ci *(unsigned *)fnode_param->value; 821262306a36Sopenharmony_ci break; 821362306a36Sopenharmony_ci case ISCSI_FLASHNODE_DEF_TIME2WAIT: 821462306a36Sopenharmony_ci fnode_sess->time2wait = *(uint16_t *)fnode_param->value; 821562306a36Sopenharmony_ci break; 821662306a36Sopenharmony_ci case ISCSI_FLASHNODE_DEF_TIME2RETAIN: 821762306a36Sopenharmony_ci fnode_sess->time2retain = 821862306a36Sopenharmony_ci *(uint16_t *)fnode_param->value; 821962306a36Sopenharmony_ci break; 822062306a36Sopenharmony_ci case ISCSI_FLASHNODE_MAX_R2T: 822162306a36Sopenharmony_ci fnode_sess->max_r2t = 822262306a36Sopenharmony_ci *(uint16_t *)fnode_param->value; 822362306a36Sopenharmony_ci break; 822462306a36Sopenharmony_ci case ISCSI_FLASHNODE_KEEPALIVE_TMO: 822562306a36Sopenharmony_ci fnode_conn->keepalive_timeout = 822662306a36Sopenharmony_ci *(uint16_t *)fnode_param->value; 822762306a36Sopenharmony_ci break; 822862306a36Sopenharmony_ci case ISCSI_FLASHNODE_ISID: 822962306a36Sopenharmony_ci memcpy(fnode_sess->isid, fnode_param->value, 823062306a36Sopenharmony_ci sizeof(fnode_sess->isid)); 823162306a36Sopenharmony_ci break; 823262306a36Sopenharmony_ci case ISCSI_FLASHNODE_TSID: 823362306a36Sopenharmony_ci fnode_sess->tsid = *(uint16_t *)fnode_param->value; 823462306a36Sopenharmony_ci break; 823562306a36Sopenharmony_ci case ISCSI_FLASHNODE_PORT: 823662306a36Sopenharmony_ci fnode_conn->port = *(uint16_t *)fnode_param->value; 823762306a36Sopenharmony_ci break; 823862306a36Sopenharmony_ci case ISCSI_FLASHNODE_MAX_BURST: 823962306a36Sopenharmony_ci fnode_sess->max_burst = *(unsigned *)fnode_param->value; 824062306a36Sopenharmony_ci break; 824162306a36Sopenharmony_ci case ISCSI_FLASHNODE_DEF_TASKMGMT_TMO: 824262306a36Sopenharmony_ci fnode_sess->default_taskmgmt_timeout = 824362306a36Sopenharmony_ci *(uint16_t *)fnode_param->value; 824462306a36Sopenharmony_ci break; 824562306a36Sopenharmony_ci case ISCSI_FLASHNODE_IPADDR: 824662306a36Sopenharmony_ci memcpy(fnode_conn->ipaddress, fnode_param->value, 824762306a36Sopenharmony_ci IPv6_ADDR_LEN); 824862306a36Sopenharmony_ci break; 824962306a36Sopenharmony_ci case ISCSI_FLASHNODE_ALIAS: 825062306a36Sopenharmony_ci rc = iscsi_switch_str_param(&fnode_sess->targetalias, 825162306a36Sopenharmony_ci (char *)fnode_param->value); 825262306a36Sopenharmony_ci break; 825362306a36Sopenharmony_ci case ISCSI_FLASHNODE_REDIRECT_IPADDR: 825462306a36Sopenharmony_ci memcpy(fnode_conn->redirect_ipaddr, fnode_param->value, 825562306a36Sopenharmony_ci IPv6_ADDR_LEN); 825662306a36Sopenharmony_ci break; 825762306a36Sopenharmony_ci case ISCSI_FLASHNODE_MAX_SEGMENT_SIZE: 825862306a36Sopenharmony_ci fnode_conn->max_segment_size = 825962306a36Sopenharmony_ci *(unsigned *)fnode_param->value; 826062306a36Sopenharmony_ci break; 826162306a36Sopenharmony_ci case ISCSI_FLASHNODE_LOCAL_PORT: 826262306a36Sopenharmony_ci fnode_conn->local_port = 826362306a36Sopenharmony_ci *(uint16_t *)fnode_param->value; 826462306a36Sopenharmony_ci break; 826562306a36Sopenharmony_ci case ISCSI_FLASHNODE_IPV4_TOS: 826662306a36Sopenharmony_ci fnode_conn->ipv4_tos = fnode_param->value[0]; 826762306a36Sopenharmony_ci break; 826862306a36Sopenharmony_ci case ISCSI_FLASHNODE_IPV6_TC: 826962306a36Sopenharmony_ci fnode_conn->ipv6_traffic_class = fnode_param->value[0]; 827062306a36Sopenharmony_ci break; 827162306a36Sopenharmony_ci case ISCSI_FLASHNODE_IPV6_FLOW_LABEL: 827262306a36Sopenharmony_ci fnode_conn->ipv6_flow_label = fnode_param->value[0]; 827362306a36Sopenharmony_ci break; 827462306a36Sopenharmony_ci case ISCSI_FLASHNODE_NAME: 827562306a36Sopenharmony_ci rc = iscsi_switch_str_param(&fnode_sess->targetname, 827662306a36Sopenharmony_ci (char *)fnode_param->value); 827762306a36Sopenharmony_ci break; 827862306a36Sopenharmony_ci case ISCSI_FLASHNODE_TPGT: 827962306a36Sopenharmony_ci fnode_sess->tpgt = *(uint16_t *)fnode_param->value; 828062306a36Sopenharmony_ci break; 828162306a36Sopenharmony_ci case ISCSI_FLASHNODE_LINK_LOCAL_IPV6: 828262306a36Sopenharmony_ci memcpy(fnode_conn->link_local_ipv6_addr, 828362306a36Sopenharmony_ci fnode_param->value, IPv6_ADDR_LEN); 828462306a36Sopenharmony_ci break; 828562306a36Sopenharmony_ci case ISCSI_FLASHNODE_DISCOVERY_PARENT_IDX: 828662306a36Sopenharmony_ci fnode_sess->discovery_parent_idx = 828762306a36Sopenharmony_ci *(uint16_t *)fnode_param->value; 828862306a36Sopenharmony_ci break; 828962306a36Sopenharmony_ci case ISCSI_FLASHNODE_TCP_XMIT_WSF: 829062306a36Sopenharmony_ci fnode_conn->tcp_xmit_wsf = 829162306a36Sopenharmony_ci *(uint8_t *)fnode_param->value; 829262306a36Sopenharmony_ci break; 829362306a36Sopenharmony_ci case ISCSI_FLASHNODE_TCP_RECV_WSF: 829462306a36Sopenharmony_ci fnode_conn->tcp_recv_wsf = 829562306a36Sopenharmony_ci *(uint8_t *)fnode_param->value; 829662306a36Sopenharmony_ci break; 829762306a36Sopenharmony_ci case ISCSI_FLASHNODE_STATSN: 829862306a36Sopenharmony_ci fnode_conn->statsn = *(uint32_t *)fnode_param->value; 829962306a36Sopenharmony_ci break; 830062306a36Sopenharmony_ci case ISCSI_FLASHNODE_EXP_STATSN: 830162306a36Sopenharmony_ci fnode_conn->exp_statsn = 830262306a36Sopenharmony_ci *(uint32_t *)fnode_param->value; 830362306a36Sopenharmony_ci break; 830462306a36Sopenharmony_ci case ISCSI_FLASHNODE_CHAP_OUT_IDX: 830562306a36Sopenharmony_ci chap_out_idx = *(uint16_t *)fnode_param->value; 830662306a36Sopenharmony_ci if (!qla4xxx_get_uni_chap_at_index(ha, 830762306a36Sopenharmony_ci chap_tbl.name, 830862306a36Sopenharmony_ci chap_tbl.secret, 830962306a36Sopenharmony_ci chap_out_idx)) { 831062306a36Sopenharmony_ci fnode_sess->chap_out_idx = chap_out_idx; 831162306a36Sopenharmony_ci /* Enable chap auth if chap index is valid */ 831262306a36Sopenharmony_ci fnode_sess->chap_auth_en = QL4_PARAM_ENABLE; 831362306a36Sopenharmony_ci } 831462306a36Sopenharmony_ci break; 831562306a36Sopenharmony_ci default: 831662306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, 831762306a36Sopenharmony_ci "%s: No such sysfs attribute\n", __func__); 831862306a36Sopenharmony_ci rc = -ENOSYS; 831962306a36Sopenharmony_ci goto exit_set_param; 832062306a36Sopenharmony_ci } 832162306a36Sopenharmony_ci } 832262306a36Sopenharmony_ci 832362306a36Sopenharmony_ci rc = qla4xxx_sysfs_ddb_apply(fnode_sess, fnode_conn); 832462306a36Sopenharmony_ci 832562306a36Sopenharmony_ciexit_set_param: 832662306a36Sopenharmony_ci return rc; 832762306a36Sopenharmony_ci} 832862306a36Sopenharmony_ci 832962306a36Sopenharmony_ci/** 833062306a36Sopenharmony_ci * qla4xxx_sysfs_ddb_delete - Delete firmware DDB entry 833162306a36Sopenharmony_ci * @fnode_sess: pointer to session attrs of flash ddb entry 833262306a36Sopenharmony_ci * 833362306a36Sopenharmony_ci * This invalidates the flash ddb entry at the given index 833462306a36Sopenharmony_ci **/ 833562306a36Sopenharmony_cistatic int qla4xxx_sysfs_ddb_delete(struct iscsi_bus_flash_session *fnode_sess) 833662306a36Sopenharmony_ci{ 833762306a36Sopenharmony_ci struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess); 833862306a36Sopenharmony_ci struct scsi_qla_host *ha = to_qla_host(shost); 833962306a36Sopenharmony_ci uint32_t dev_db_start_offset; 834062306a36Sopenharmony_ci uint32_t dev_db_end_offset; 834162306a36Sopenharmony_ci struct dev_db_entry *fw_ddb_entry = NULL; 834262306a36Sopenharmony_ci dma_addr_t fw_ddb_entry_dma; 834362306a36Sopenharmony_ci uint16_t *ddb_cookie = NULL; 834462306a36Sopenharmony_ci size_t ddb_size = 0; 834562306a36Sopenharmony_ci void *pddb = NULL; 834662306a36Sopenharmony_ci int target_id; 834762306a36Sopenharmony_ci int rc = 0; 834862306a36Sopenharmony_ci 834962306a36Sopenharmony_ci if (fnode_sess->is_boot_target) { 835062306a36Sopenharmony_ci rc = -EPERM; 835162306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_ERR, ha, 835262306a36Sopenharmony_ci "%s: Deletion of boot target entry is not permitted.\n", 835362306a36Sopenharmony_ci __func__)); 835462306a36Sopenharmony_ci goto exit_ddb_del; 835562306a36Sopenharmony_ci } 835662306a36Sopenharmony_ci 835762306a36Sopenharmony_ci if (fnode_sess->flash_state == DEV_DB_NON_PERSISTENT) 835862306a36Sopenharmony_ci goto sysfs_ddb_del; 835962306a36Sopenharmony_ci 836062306a36Sopenharmony_ci if (is_qla40XX(ha)) { 836162306a36Sopenharmony_ci dev_db_start_offset = FLASH_OFFSET_DB_INFO; 836262306a36Sopenharmony_ci dev_db_end_offset = FLASH_OFFSET_DB_END; 836362306a36Sopenharmony_ci dev_db_start_offset += (fnode_sess->target_id * 836462306a36Sopenharmony_ci sizeof(*fw_ddb_entry)); 836562306a36Sopenharmony_ci ddb_size = sizeof(*fw_ddb_entry); 836662306a36Sopenharmony_ci } else { 836762306a36Sopenharmony_ci dev_db_start_offset = FLASH_RAW_ACCESS_ADDR + 836862306a36Sopenharmony_ci (ha->hw.flt_region_ddb << 2); 836962306a36Sopenharmony_ci /* flt_ddb_size is DDB table size for both ports 837062306a36Sopenharmony_ci * so divide it by 2 to calculate the offset for second port 837162306a36Sopenharmony_ci */ 837262306a36Sopenharmony_ci if (ha->port_num == 1) 837362306a36Sopenharmony_ci dev_db_start_offset += (ha->hw.flt_ddb_size / 2); 837462306a36Sopenharmony_ci 837562306a36Sopenharmony_ci dev_db_end_offset = dev_db_start_offset + 837662306a36Sopenharmony_ci (ha->hw.flt_ddb_size / 2); 837762306a36Sopenharmony_ci 837862306a36Sopenharmony_ci dev_db_start_offset += (fnode_sess->target_id * 837962306a36Sopenharmony_ci sizeof(*fw_ddb_entry)); 838062306a36Sopenharmony_ci dev_db_start_offset += offsetof(struct dev_db_entry, cookie); 838162306a36Sopenharmony_ci 838262306a36Sopenharmony_ci ddb_size = sizeof(*ddb_cookie); 838362306a36Sopenharmony_ci } 838462306a36Sopenharmony_ci 838562306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_ERR, ha, "%s: start offset=%u, end offset=%u\n", 838662306a36Sopenharmony_ci __func__, dev_db_start_offset, dev_db_end_offset)); 838762306a36Sopenharmony_ci 838862306a36Sopenharmony_ci if (dev_db_start_offset > dev_db_end_offset) { 838962306a36Sopenharmony_ci rc = -EIO; 839062306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_ERR, ha, "%s:Invalid DDB index %u\n", 839162306a36Sopenharmony_ci __func__, fnode_sess->target_id)); 839262306a36Sopenharmony_ci goto exit_ddb_del; 839362306a36Sopenharmony_ci } 839462306a36Sopenharmony_ci 839562306a36Sopenharmony_ci pddb = dma_alloc_coherent(&ha->pdev->dev, ddb_size, 839662306a36Sopenharmony_ci &fw_ddb_entry_dma, GFP_KERNEL); 839762306a36Sopenharmony_ci if (!pddb) { 839862306a36Sopenharmony_ci rc = -ENOMEM; 839962306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_ERR, ha, 840062306a36Sopenharmony_ci "%s: Unable to allocate dma buffer\n", 840162306a36Sopenharmony_ci __func__)); 840262306a36Sopenharmony_ci goto exit_ddb_del; 840362306a36Sopenharmony_ci } 840462306a36Sopenharmony_ci 840562306a36Sopenharmony_ci if (is_qla40XX(ha)) { 840662306a36Sopenharmony_ci fw_ddb_entry = pddb; 840762306a36Sopenharmony_ci memset(fw_ddb_entry, 0, ddb_size); 840862306a36Sopenharmony_ci ddb_cookie = &fw_ddb_entry->cookie; 840962306a36Sopenharmony_ci } else { 841062306a36Sopenharmony_ci ddb_cookie = pddb; 841162306a36Sopenharmony_ci } 841262306a36Sopenharmony_ci 841362306a36Sopenharmony_ci /* invalidate the cookie */ 841462306a36Sopenharmony_ci *ddb_cookie = 0xFFEE; 841562306a36Sopenharmony_ci qla4xxx_set_flash(ha, fw_ddb_entry_dma, dev_db_start_offset, 841662306a36Sopenharmony_ci ddb_size, FLASH_OPT_RMW_COMMIT); 841762306a36Sopenharmony_ci 841862306a36Sopenharmony_cisysfs_ddb_del: 841962306a36Sopenharmony_ci target_id = fnode_sess->target_id; 842062306a36Sopenharmony_ci iscsi_destroy_flashnode_sess(fnode_sess); 842162306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, 842262306a36Sopenharmony_ci "%s: session and conn entries for flashnode %u of host %lu deleted\n", 842362306a36Sopenharmony_ci __func__, target_id, ha->host_no); 842462306a36Sopenharmony_ciexit_ddb_del: 842562306a36Sopenharmony_ci if (pddb) 842662306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, ddb_size, pddb, 842762306a36Sopenharmony_ci fw_ddb_entry_dma); 842862306a36Sopenharmony_ci return rc; 842962306a36Sopenharmony_ci} 843062306a36Sopenharmony_ci 843162306a36Sopenharmony_ci/** 843262306a36Sopenharmony_ci * qla4xxx_sysfs_ddb_export - Create sysfs entries for firmware DDBs 843362306a36Sopenharmony_ci * @ha: pointer to adapter structure 843462306a36Sopenharmony_ci * 843562306a36Sopenharmony_ci * Export the firmware DDB for all send targets and normal targets to sysfs. 843662306a36Sopenharmony_ci **/ 843762306a36Sopenharmony_ciint qla4xxx_sysfs_ddb_export(struct scsi_qla_host *ha) 843862306a36Sopenharmony_ci{ 843962306a36Sopenharmony_ci struct dev_db_entry *fw_ddb_entry = NULL; 844062306a36Sopenharmony_ci dma_addr_t fw_ddb_entry_dma; 844162306a36Sopenharmony_ci uint16_t max_ddbs; 844262306a36Sopenharmony_ci uint16_t idx = 0; 844362306a36Sopenharmony_ci int ret = QLA_SUCCESS; 844462306a36Sopenharmony_ci 844562306a36Sopenharmony_ci fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, 844662306a36Sopenharmony_ci sizeof(*fw_ddb_entry), 844762306a36Sopenharmony_ci &fw_ddb_entry_dma, GFP_KERNEL); 844862306a36Sopenharmony_ci if (!fw_ddb_entry) { 844962306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_ERR, ha, 845062306a36Sopenharmony_ci "%s: Unable to allocate dma buffer\n", 845162306a36Sopenharmony_ci __func__)); 845262306a36Sopenharmony_ci return -ENOMEM; 845362306a36Sopenharmony_ci } 845462306a36Sopenharmony_ci 845562306a36Sopenharmony_ci max_ddbs = is_qla40XX(ha) ? MAX_PRST_DEV_DB_ENTRIES : 845662306a36Sopenharmony_ci MAX_DEV_DB_ENTRIES; 845762306a36Sopenharmony_ci 845862306a36Sopenharmony_ci for (idx = 0; idx < max_ddbs; idx++) { 845962306a36Sopenharmony_ci if (qla4xxx_flashdb_by_index(ha, fw_ddb_entry, fw_ddb_entry_dma, 846062306a36Sopenharmony_ci idx)) 846162306a36Sopenharmony_ci continue; 846262306a36Sopenharmony_ci 846362306a36Sopenharmony_ci ret = qla4xxx_sysfs_ddb_tgt_create(ha, fw_ddb_entry, &idx, 0); 846462306a36Sopenharmony_ci if (ret) { 846562306a36Sopenharmony_ci ret = -EIO; 846662306a36Sopenharmony_ci break; 846762306a36Sopenharmony_ci } 846862306a36Sopenharmony_ci } 846962306a36Sopenharmony_ci 847062306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), fw_ddb_entry, 847162306a36Sopenharmony_ci fw_ddb_entry_dma); 847262306a36Sopenharmony_ci 847362306a36Sopenharmony_ci return ret; 847462306a36Sopenharmony_ci} 847562306a36Sopenharmony_ci 847662306a36Sopenharmony_cistatic void qla4xxx_sysfs_ddb_remove(struct scsi_qla_host *ha) 847762306a36Sopenharmony_ci{ 847862306a36Sopenharmony_ci iscsi_destroy_all_flashnode(ha->host); 847962306a36Sopenharmony_ci} 848062306a36Sopenharmony_ci 848162306a36Sopenharmony_ci/** 848262306a36Sopenharmony_ci * qla4xxx_build_ddb_list - Build ddb list and setup sessions 848362306a36Sopenharmony_ci * @ha: pointer to adapter structure 848462306a36Sopenharmony_ci * @is_reset: Is this init path or reset path 848562306a36Sopenharmony_ci * 848662306a36Sopenharmony_ci * Create a list of sendtargets (st) from firmware DDBs, issue send targets 848762306a36Sopenharmony_ci * using connection open, then create the list of normal targets (nt) 848862306a36Sopenharmony_ci * from firmware DDBs. Based on the list of nt setup session and connection 848962306a36Sopenharmony_ci * objects. 849062306a36Sopenharmony_ci **/ 849162306a36Sopenharmony_civoid qla4xxx_build_ddb_list(struct scsi_qla_host *ha, int is_reset) 849262306a36Sopenharmony_ci{ 849362306a36Sopenharmony_ci uint16_t tmo = 0; 849462306a36Sopenharmony_ci struct list_head list_st, list_nt; 849562306a36Sopenharmony_ci struct qla_ddb_index *st_ddb_idx, *st_ddb_idx_tmp; 849662306a36Sopenharmony_ci unsigned long wtime; 849762306a36Sopenharmony_ci 849862306a36Sopenharmony_ci if (!test_bit(AF_LINK_UP, &ha->flags)) { 849962306a36Sopenharmony_ci set_bit(AF_BUILD_DDB_LIST, &ha->flags); 850062306a36Sopenharmony_ci ha->is_reset = is_reset; 850162306a36Sopenharmony_ci return; 850262306a36Sopenharmony_ci } 850362306a36Sopenharmony_ci 850462306a36Sopenharmony_ci INIT_LIST_HEAD(&list_st); 850562306a36Sopenharmony_ci INIT_LIST_HEAD(&list_nt); 850662306a36Sopenharmony_ci 850762306a36Sopenharmony_ci qla4xxx_build_st_list(ha, &list_st); 850862306a36Sopenharmony_ci 850962306a36Sopenharmony_ci /* Before issuing conn open mbox, ensure all IPs states are configured 851062306a36Sopenharmony_ci * Note, conn open fails if IPs are not configured 851162306a36Sopenharmony_ci */ 851262306a36Sopenharmony_ci qla4xxx_wait_for_ip_configuration(ha); 851362306a36Sopenharmony_ci 851462306a36Sopenharmony_ci /* Go thru the STs and fire the sendtargets by issuing conn open mbx */ 851562306a36Sopenharmony_ci list_for_each_entry_safe(st_ddb_idx, st_ddb_idx_tmp, &list_st, list) { 851662306a36Sopenharmony_ci qla4xxx_conn_open(ha, st_ddb_idx->fw_ddb_idx); 851762306a36Sopenharmony_ci } 851862306a36Sopenharmony_ci 851962306a36Sopenharmony_ci /* Wait to ensure all sendtargets are done for min 12 sec wait */ 852062306a36Sopenharmony_ci tmo = ((ha->def_timeout > LOGIN_TOV) && 852162306a36Sopenharmony_ci (ha->def_timeout < LOGIN_TOV * 10) ? 852262306a36Sopenharmony_ci ha->def_timeout : LOGIN_TOV); 852362306a36Sopenharmony_ci 852462306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 852562306a36Sopenharmony_ci "Default time to wait for build ddb %d\n", tmo)); 852662306a36Sopenharmony_ci 852762306a36Sopenharmony_ci wtime = jiffies + (HZ * tmo); 852862306a36Sopenharmony_ci do { 852962306a36Sopenharmony_ci if (list_empty(&list_st)) 853062306a36Sopenharmony_ci break; 853162306a36Sopenharmony_ci 853262306a36Sopenharmony_ci qla4xxx_remove_failed_ddb(ha, &list_st); 853362306a36Sopenharmony_ci schedule_timeout_uninterruptible(HZ / 10); 853462306a36Sopenharmony_ci } while (time_after(wtime, jiffies)); 853562306a36Sopenharmony_ci 853662306a36Sopenharmony_ci 853762306a36Sopenharmony_ci qla4xxx_build_nt_list(ha, &list_nt, &list_st, is_reset); 853862306a36Sopenharmony_ci 853962306a36Sopenharmony_ci qla4xxx_free_ddb_list(&list_st); 854062306a36Sopenharmony_ci qla4xxx_free_ddb_list(&list_nt); 854162306a36Sopenharmony_ci 854262306a36Sopenharmony_ci qla4xxx_free_ddb_index(ha); 854362306a36Sopenharmony_ci} 854462306a36Sopenharmony_ci 854562306a36Sopenharmony_ci/** 854662306a36Sopenharmony_ci * qla4xxx_wait_login_resp_boot_tgt - Wait for iSCSI boot target login 854762306a36Sopenharmony_ci * response. 854862306a36Sopenharmony_ci * @ha: pointer to adapter structure 854962306a36Sopenharmony_ci * 855062306a36Sopenharmony_ci * When the boot entry is normal iSCSI target then DF_BOOT_TGT flag will be 855162306a36Sopenharmony_ci * set in DDB and we will wait for login response of boot targets during 855262306a36Sopenharmony_ci * probe. 855362306a36Sopenharmony_ci **/ 855462306a36Sopenharmony_cistatic void qla4xxx_wait_login_resp_boot_tgt(struct scsi_qla_host *ha) 855562306a36Sopenharmony_ci{ 855662306a36Sopenharmony_ci struct ddb_entry *ddb_entry; 855762306a36Sopenharmony_ci struct dev_db_entry *fw_ddb_entry = NULL; 855862306a36Sopenharmony_ci dma_addr_t fw_ddb_entry_dma; 855962306a36Sopenharmony_ci unsigned long wtime; 856062306a36Sopenharmony_ci uint32_t ddb_state; 856162306a36Sopenharmony_ci int max_ddbs, idx, ret; 856262306a36Sopenharmony_ci 856362306a36Sopenharmony_ci max_ddbs = is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX : 856462306a36Sopenharmony_ci MAX_DEV_DB_ENTRIES; 856562306a36Sopenharmony_ci 856662306a36Sopenharmony_ci fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), 856762306a36Sopenharmony_ci &fw_ddb_entry_dma, GFP_KERNEL); 856862306a36Sopenharmony_ci if (!fw_ddb_entry) { 856962306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, 857062306a36Sopenharmony_ci "%s: Unable to allocate dma buffer\n", __func__); 857162306a36Sopenharmony_ci goto exit_login_resp; 857262306a36Sopenharmony_ci } 857362306a36Sopenharmony_ci 857462306a36Sopenharmony_ci wtime = jiffies + (HZ * BOOT_LOGIN_RESP_TOV); 857562306a36Sopenharmony_ci 857662306a36Sopenharmony_ci for (idx = 0; idx < max_ddbs; idx++) { 857762306a36Sopenharmony_ci ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx); 857862306a36Sopenharmony_ci if (ddb_entry == NULL) 857962306a36Sopenharmony_ci continue; 858062306a36Sopenharmony_ci 858162306a36Sopenharmony_ci if (test_bit(DF_BOOT_TGT, &ddb_entry->flags)) { 858262306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 858362306a36Sopenharmony_ci "%s: DDB index [%d]\n", __func__, 858462306a36Sopenharmony_ci ddb_entry->fw_ddb_index)); 858562306a36Sopenharmony_ci do { 858662306a36Sopenharmony_ci ret = qla4xxx_get_fwddb_entry(ha, 858762306a36Sopenharmony_ci ddb_entry->fw_ddb_index, 858862306a36Sopenharmony_ci fw_ddb_entry, fw_ddb_entry_dma, 858962306a36Sopenharmony_ci NULL, NULL, &ddb_state, NULL, 859062306a36Sopenharmony_ci NULL, NULL); 859162306a36Sopenharmony_ci if (ret == QLA_ERROR) 859262306a36Sopenharmony_ci goto exit_login_resp; 859362306a36Sopenharmony_ci 859462306a36Sopenharmony_ci if ((ddb_state == DDB_DS_SESSION_ACTIVE) || 859562306a36Sopenharmony_ci (ddb_state == DDB_DS_SESSION_FAILED)) 859662306a36Sopenharmony_ci break; 859762306a36Sopenharmony_ci 859862306a36Sopenharmony_ci schedule_timeout_uninterruptible(HZ); 859962306a36Sopenharmony_ci 860062306a36Sopenharmony_ci } while ((time_after(wtime, jiffies))); 860162306a36Sopenharmony_ci 860262306a36Sopenharmony_ci if (!time_after(wtime, jiffies)) { 860362306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 860462306a36Sopenharmony_ci "%s: Login response wait timer expired\n", 860562306a36Sopenharmony_ci __func__)); 860662306a36Sopenharmony_ci goto exit_login_resp; 860762306a36Sopenharmony_ci } 860862306a36Sopenharmony_ci } 860962306a36Sopenharmony_ci } 861062306a36Sopenharmony_ci 861162306a36Sopenharmony_ciexit_login_resp: 861262306a36Sopenharmony_ci if (fw_ddb_entry) 861362306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), 861462306a36Sopenharmony_ci fw_ddb_entry, fw_ddb_entry_dma); 861562306a36Sopenharmony_ci} 861662306a36Sopenharmony_ci 861762306a36Sopenharmony_ci/** 861862306a36Sopenharmony_ci * qla4xxx_probe_adapter - callback function to probe HBA 861962306a36Sopenharmony_ci * @pdev: pointer to pci_dev structure 862062306a36Sopenharmony_ci * @ent: pointer to pci_device entry 862162306a36Sopenharmony_ci * 862262306a36Sopenharmony_ci * This routine will probe for Qlogic 4xxx iSCSI host adapters. 862362306a36Sopenharmony_ci * It returns zero if successful. It also initializes all data necessary for 862462306a36Sopenharmony_ci * the driver. 862562306a36Sopenharmony_ci **/ 862662306a36Sopenharmony_cistatic int qla4xxx_probe_adapter(struct pci_dev *pdev, 862762306a36Sopenharmony_ci const struct pci_device_id *ent) 862862306a36Sopenharmony_ci{ 862962306a36Sopenharmony_ci int ret = -ENODEV, status; 863062306a36Sopenharmony_ci struct Scsi_Host *host; 863162306a36Sopenharmony_ci struct scsi_qla_host *ha; 863262306a36Sopenharmony_ci uint8_t init_retry_count = 0; 863362306a36Sopenharmony_ci char buf[34]; 863462306a36Sopenharmony_ci struct qla4_8xxx_legacy_intr_set *nx_legacy_intr; 863562306a36Sopenharmony_ci uint32_t dev_state; 863662306a36Sopenharmony_ci 863762306a36Sopenharmony_ci if (pci_enable_device(pdev)) 863862306a36Sopenharmony_ci return -1; 863962306a36Sopenharmony_ci 864062306a36Sopenharmony_ci host = iscsi_host_alloc(&qla4xxx_driver_template, sizeof(*ha), 0); 864162306a36Sopenharmony_ci if (host == NULL) { 864262306a36Sopenharmony_ci printk(KERN_WARNING 864362306a36Sopenharmony_ci "qla4xxx: Couldn't allocate host from scsi layer!\n"); 864462306a36Sopenharmony_ci goto probe_disable_device; 864562306a36Sopenharmony_ci } 864662306a36Sopenharmony_ci 864762306a36Sopenharmony_ci /* Clear our data area */ 864862306a36Sopenharmony_ci ha = to_qla_host(host); 864962306a36Sopenharmony_ci memset(ha, 0, sizeof(*ha)); 865062306a36Sopenharmony_ci 865162306a36Sopenharmony_ci /* Save the information from PCI BIOS. */ 865262306a36Sopenharmony_ci ha->pdev = pdev; 865362306a36Sopenharmony_ci ha->host = host; 865462306a36Sopenharmony_ci ha->host_no = host->host_no; 865562306a36Sopenharmony_ci ha->func_num = PCI_FUNC(ha->pdev->devfn); 865662306a36Sopenharmony_ci 865762306a36Sopenharmony_ci /* Setup Runtime configurable options */ 865862306a36Sopenharmony_ci if (is_qla8022(ha)) { 865962306a36Sopenharmony_ci ha->isp_ops = &qla4_82xx_isp_ops; 866062306a36Sopenharmony_ci ha->reg_tbl = (uint32_t *) qla4_82xx_reg_tbl; 866162306a36Sopenharmony_ci ha->qdr_sn_window = -1; 866262306a36Sopenharmony_ci ha->ddr_mn_window = -1; 866362306a36Sopenharmony_ci ha->curr_window = 255; 866462306a36Sopenharmony_ci nx_legacy_intr = &legacy_intr[ha->func_num]; 866562306a36Sopenharmony_ci ha->nx_legacy_intr.int_vec_bit = nx_legacy_intr->int_vec_bit; 866662306a36Sopenharmony_ci ha->nx_legacy_intr.tgt_status_reg = 866762306a36Sopenharmony_ci nx_legacy_intr->tgt_status_reg; 866862306a36Sopenharmony_ci ha->nx_legacy_intr.tgt_mask_reg = nx_legacy_intr->tgt_mask_reg; 866962306a36Sopenharmony_ci ha->nx_legacy_intr.pci_int_reg = nx_legacy_intr->pci_int_reg; 867062306a36Sopenharmony_ci } else if (is_qla8032(ha) || is_qla8042(ha)) { 867162306a36Sopenharmony_ci ha->isp_ops = &qla4_83xx_isp_ops; 867262306a36Sopenharmony_ci ha->reg_tbl = (uint32_t *)qla4_83xx_reg_tbl; 867362306a36Sopenharmony_ci } else { 867462306a36Sopenharmony_ci ha->isp_ops = &qla4xxx_isp_ops; 867562306a36Sopenharmony_ci } 867662306a36Sopenharmony_ci 867762306a36Sopenharmony_ci if (is_qla80XX(ha)) { 867862306a36Sopenharmony_ci rwlock_init(&ha->hw_lock); 867962306a36Sopenharmony_ci ha->pf_bit = ha->func_num << 16; 868062306a36Sopenharmony_ci /* Set EEH reset type to fundamental if required by hba */ 868162306a36Sopenharmony_ci pdev->needs_freset = 1; 868262306a36Sopenharmony_ci } 868362306a36Sopenharmony_ci 868462306a36Sopenharmony_ci /* Configure PCI I/O space. */ 868562306a36Sopenharmony_ci ret = ha->isp_ops->iospace_config(ha); 868662306a36Sopenharmony_ci if (ret) 868762306a36Sopenharmony_ci goto probe_failed_ioconfig; 868862306a36Sopenharmony_ci 868962306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "Found an ISP%04x, irq %d, iobase 0x%p\n", 869062306a36Sopenharmony_ci pdev->device, pdev->irq, ha->reg); 869162306a36Sopenharmony_ci 869262306a36Sopenharmony_ci qla4xxx_config_dma_addressing(ha); 869362306a36Sopenharmony_ci 869462306a36Sopenharmony_ci /* Initialize lists and spinlocks. */ 869562306a36Sopenharmony_ci INIT_LIST_HEAD(&ha->free_srb_q); 869662306a36Sopenharmony_ci 869762306a36Sopenharmony_ci mutex_init(&ha->mbox_sem); 869862306a36Sopenharmony_ci mutex_init(&ha->chap_sem); 869962306a36Sopenharmony_ci init_completion(&ha->mbx_intr_comp); 870062306a36Sopenharmony_ci init_completion(&ha->disable_acb_comp); 870162306a36Sopenharmony_ci init_completion(&ha->idc_comp); 870262306a36Sopenharmony_ci init_completion(&ha->link_up_comp); 870362306a36Sopenharmony_ci 870462306a36Sopenharmony_ci spin_lock_init(&ha->hardware_lock); 870562306a36Sopenharmony_ci spin_lock_init(&ha->work_lock); 870662306a36Sopenharmony_ci 870762306a36Sopenharmony_ci /* Initialize work list */ 870862306a36Sopenharmony_ci INIT_LIST_HEAD(&ha->work_list); 870962306a36Sopenharmony_ci 871062306a36Sopenharmony_ci /* Allocate dma buffers */ 871162306a36Sopenharmony_ci if (qla4xxx_mem_alloc(ha)) { 871262306a36Sopenharmony_ci ql4_printk(KERN_WARNING, ha, 871362306a36Sopenharmony_ci "[ERROR] Failed to allocate memory for adapter\n"); 871462306a36Sopenharmony_ci 871562306a36Sopenharmony_ci ret = -ENOMEM; 871662306a36Sopenharmony_ci goto probe_failed; 871762306a36Sopenharmony_ci } 871862306a36Sopenharmony_ci 871962306a36Sopenharmony_ci host->cmd_per_lun = 3; 872062306a36Sopenharmony_ci host->max_channel = 0; 872162306a36Sopenharmony_ci host->max_lun = MAX_LUNS - 1; 872262306a36Sopenharmony_ci host->max_id = MAX_TARGETS; 872362306a36Sopenharmony_ci host->max_cmd_len = IOCB_MAX_CDB_LEN; 872462306a36Sopenharmony_ci host->can_queue = MAX_SRBS ; 872562306a36Sopenharmony_ci host->transportt = qla4xxx_scsi_transport; 872662306a36Sopenharmony_ci 872762306a36Sopenharmony_ci pci_set_drvdata(pdev, ha); 872862306a36Sopenharmony_ci 872962306a36Sopenharmony_ci ret = scsi_add_host(host, &pdev->dev); 873062306a36Sopenharmony_ci if (ret) 873162306a36Sopenharmony_ci goto probe_failed; 873262306a36Sopenharmony_ci 873362306a36Sopenharmony_ci if (is_qla80XX(ha)) 873462306a36Sopenharmony_ci qla4_8xxx_get_flash_info(ha); 873562306a36Sopenharmony_ci 873662306a36Sopenharmony_ci if (is_qla8032(ha) || is_qla8042(ha)) { 873762306a36Sopenharmony_ci qla4_83xx_read_reset_template(ha); 873862306a36Sopenharmony_ci /* 873962306a36Sopenharmony_ci * NOTE: If ql4dontresethba==1, set IDC_CTRL DONTRESET_BIT0. 874062306a36Sopenharmony_ci * If DONRESET_BIT0 is set, drivers should not set dev_state 874162306a36Sopenharmony_ci * to NEED_RESET. But if NEED_RESET is set, drivers should 874262306a36Sopenharmony_ci * should honor the reset. 874362306a36Sopenharmony_ci */ 874462306a36Sopenharmony_ci if (ql4xdontresethba == 1) 874562306a36Sopenharmony_ci qla4_83xx_set_idc_dontreset(ha); 874662306a36Sopenharmony_ci } 874762306a36Sopenharmony_ci 874862306a36Sopenharmony_ci /* 874962306a36Sopenharmony_ci * Initialize the Host adapter request/response queues and 875062306a36Sopenharmony_ci * firmware 875162306a36Sopenharmony_ci * NOTE: interrupts enabled upon successful completion 875262306a36Sopenharmony_ci */ 875362306a36Sopenharmony_ci status = qla4xxx_initialize_adapter(ha, INIT_ADAPTER); 875462306a36Sopenharmony_ci 875562306a36Sopenharmony_ci /* Dont retry adapter initialization if IRQ allocation failed */ 875662306a36Sopenharmony_ci if (is_qla80XX(ha) && (status == QLA_ERROR)) 875762306a36Sopenharmony_ci goto skip_retry_init; 875862306a36Sopenharmony_ci 875962306a36Sopenharmony_ci while ((!test_bit(AF_ONLINE, &ha->flags)) && 876062306a36Sopenharmony_ci init_retry_count++ < MAX_INIT_RETRIES) { 876162306a36Sopenharmony_ci 876262306a36Sopenharmony_ci if (is_qla80XX(ha)) { 876362306a36Sopenharmony_ci ha->isp_ops->idc_lock(ha); 876462306a36Sopenharmony_ci dev_state = qla4_8xxx_rd_direct(ha, 876562306a36Sopenharmony_ci QLA8XXX_CRB_DEV_STATE); 876662306a36Sopenharmony_ci ha->isp_ops->idc_unlock(ha); 876762306a36Sopenharmony_ci if (dev_state == QLA8XXX_DEV_FAILED) { 876862306a36Sopenharmony_ci ql4_printk(KERN_WARNING, ha, "%s: don't retry " 876962306a36Sopenharmony_ci "initialize adapter. H/W is in failed state\n", 877062306a36Sopenharmony_ci __func__); 877162306a36Sopenharmony_ci break; 877262306a36Sopenharmony_ci } 877362306a36Sopenharmony_ci } 877462306a36Sopenharmony_ci DEBUG2(printk("scsi: %s: retrying adapter initialization " 877562306a36Sopenharmony_ci "(%d)\n", __func__, init_retry_count)); 877662306a36Sopenharmony_ci 877762306a36Sopenharmony_ci if (ha->isp_ops->reset_chip(ha) == QLA_ERROR) 877862306a36Sopenharmony_ci continue; 877962306a36Sopenharmony_ci 878062306a36Sopenharmony_ci status = qla4xxx_initialize_adapter(ha, INIT_ADAPTER); 878162306a36Sopenharmony_ci if (is_qla80XX(ha) && (status == QLA_ERROR)) { 878262306a36Sopenharmony_ci if (qla4_8xxx_check_init_adapter_retry(ha) == QLA_ERROR) 878362306a36Sopenharmony_ci goto skip_retry_init; 878462306a36Sopenharmony_ci } 878562306a36Sopenharmony_ci } 878662306a36Sopenharmony_ci 878762306a36Sopenharmony_ciskip_retry_init: 878862306a36Sopenharmony_ci if (!test_bit(AF_ONLINE, &ha->flags)) { 878962306a36Sopenharmony_ci ql4_printk(KERN_WARNING, ha, "Failed to initialize adapter\n"); 879062306a36Sopenharmony_ci 879162306a36Sopenharmony_ci if ((is_qla8022(ha) && ql4xdontresethba) || 879262306a36Sopenharmony_ci ((is_qla8032(ha) || is_qla8042(ha)) && 879362306a36Sopenharmony_ci qla4_83xx_idc_dontreset(ha))) { 879462306a36Sopenharmony_ci /* Put the device in failed state. */ 879562306a36Sopenharmony_ci DEBUG2(printk(KERN_ERR "HW STATE: FAILED\n")); 879662306a36Sopenharmony_ci ha->isp_ops->idc_lock(ha); 879762306a36Sopenharmony_ci qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE, 879862306a36Sopenharmony_ci QLA8XXX_DEV_FAILED); 879962306a36Sopenharmony_ci ha->isp_ops->idc_unlock(ha); 880062306a36Sopenharmony_ci } 880162306a36Sopenharmony_ci ret = -ENODEV; 880262306a36Sopenharmony_ci goto remove_host; 880362306a36Sopenharmony_ci } 880462306a36Sopenharmony_ci 880562306a36Sopenharmony_ci /* Startup the kernel thread for this host adapter. */ 880662306a36Sopenharmony_ci DEBUG2(printk("scsi: %s: Starting kernel thread for " 880762306a36Sopenharmony_ci "qla4xxx_dpc\n", __func__)); 880862306a36Sopenharmony_ci sprintf(buf, "qla4xxx_%lu_dpc", ha->host_no); 880962306a36Sopenharmony_ci ha->dpc_thread = create_singlethread_workqueue(buf); 881062306a36Sopenharmony_ci if (!ha->dpc_thread) { 881162306a36Sopenharmony_ci ql4_printk(KERN_WARNING, ha, "Unable to start DPC thread!\n"); 881262306a36Sopenharmony_ci ret = -ENODEV; 881362306a36Sopenharmony_ci goto remove_host; 881462306a36Sopenharmony_ci } 881562306a36Sopenharmony_ci INIT_WORK(&ha->dpc_work, qla4xxx_do_dpc); 881662306a36Sopenharmony_ci 881762306a36Sopenharmony_ci ha->task_wq = alloc_workqueue("qla4xxx_%lu_task", WQ_MEM_RECLAIM, 1, 881862306a36Sopenharmony_ci ha->host_no); 881962306a36Sopenharmony_ci if (!ha->task_wq) { 882062306a36Sopenharmony_ci ql4_printk(KERN_WARNING, ha, "Unable to start task thread!\n"); 882162306a36Sopenharmony_ci ret = -ENODEV; 882262306a36Sopenharmony_ci goto remove_host; 882362306a36Sopenharmony_ci } 882462306a36Sopenharmony_ci 882562306a36Sopenharmony_ci /* 882662306a36Sopenharmony_ci * For ISP-8XXX, request_irqs is called in qla4_8xxx_load_risc 882762306a36Sopenharmony_ci * (which is called indirectly by qla4xxx_initialize_adapter), 882862306a36Sopenharmony_ci * so that irqs will be registered after crbinit but before 882962306a36Sopenharmony_ci * mbx_intr_enable. 883062306a36Sopenharmony_ci */ 883162306a36Sopenharmony_ci if (is_qla40XX(ha)) { 883262306a36Sopenharmony_ci ret = qla4xxx_request_irqs(ha); 883362306a36Sopenharmony_ci if (ret) { 883462306a36Sopenharmony_ci ql4_printk(KERN_WARNING, ha, "Failed to reserve " 883562306a36Sopenharmony_ci "interrupt %d already in use.\n", pdev->irq); 883662306a36Sopenharmony_ci goto remove_host; 883762306a36Sopenharmony_ci } 883862306a36Sopenharmony_ci } 883962306a36Sopenharmony_ci 884062306a36Sopenharmony_ci pci_save_state(ha->pdev); 884162306a36Sopenharmony_ci ha->isp_ops->enable_intrs(ha); 884262306a36Sopenharmony_ci 884362306a36Sopenharmony_ci /* Start timer thread. */ 884462306a36Sopenharmony_ci qla4xxx_start_timer(ha, 1); 884562306a36Sopenharmony_ci 884662306a36Sopenharmony_ci set_bit(AF_INIT_DONE, &ha->flags); 884762306a36Sopenharmony_ci 884862306a36Sopenharmony_ci qla4_8xxx_alloc_sysfs_attr(ha); 884962306a36Sopenharmony_ci 885062306a36Sopenharmony_ci printk(KERN_INFO 885162306a36Sopenharmony_ci " QLogic iSCSI HBA Driver version: %s\n" 885262306a36Sopenharmony_ci " QLogic ISP%04x @ %s, host#=%ld, fw=%02d.%02d.%02d.%02d\n", 885362306a36Sopenharmony_ci qla4xxx_version_str, ha->pdev->device, pci_name(ha->pdev), 885462306a36Sopenharmony_ci ha->host_no, ha->fw_info.fw_major, ha->fw_info.fw_minor, 885562306a36Sopenharmony_ci ha->fw_info.fw_patch, ha->fw_info.fw_build); 885662306a36Sopenharmony_ci 885762306a36Sopenharmony_ci /* Set the driver version */ 885862306a36Sopenharmony_ci if (is_qla80XX(ha)) 885962306a36Sopenharmony_ci qla4_8xxx_set_param(ha, SET_DRVR_VERSION); 886062306a36Sopenharmony_ci 886162306a36Sopenharmony_ci if (qla4xxx_setup_boot_info(ha)) 886262306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, 886362306a36Sopenharmony_ci "%s: No iSCSI boot target configured\n", __func__); 886462306a36Sopenharmony_ci 886562306a36Sopenharmony_ci set_bit(DPC_SYSFS_DDB_EXPORT, &ha->dpc_flags); 886662306a36Sopenharmony_ci /* Perform the build ddb list and login to each */ 886762306a36Sopenharmony_ci qla4xxx_build_ddb_list(ha, INIT_ADAPTER); 886862306a36Sopenharmony_ci iscsi_host_for_each_session(ha->host, qla4xxx_login_flash_ddb); 886962306a36Sopenharmony_ci qla4xxx_wait_login_resp_boot_tgt(ha); 887062306a36Sopenharmony_ci 887162306a36Sopenharmony_ci qla4xxx_create_chap_list(ha); 887262306a36Sopenharmony_ci 887362306a36Sopenharmony_ci qla4xxx_create_ifaces(ha); 887462306a36Sopenharmony_ci return 0; 887562306a36Sopenharmony_ci 887662306a36Sopenharmony_ciremove_host: 887762306a36Sopenharmony_ci scsi_remove_host(ha->host); 887862306a36Sopenharmony_ci 887962306a36Sopenharmony_ciprobe_failed: 888062306a36Sopenharmony_ci qla4xxx_free_adapter(ha); 888162306a36Sopenharmony_ci 888262306a36Sopenharmony_ciprobe_failed_ioconfig: 888362306a36Sopenharmony_ci scsi_host_put(ha->host); 888462306a36Sopenharmony_ci 888562306a36Sopenharmony_ciprobe_disable_device: 888662306a36Sopenharmony_ci pci_disable_device(pdev); 888762306a36Sopenharmony_ci 888862306a36Sopenharmony_ci return ret; 888962306a36Sopenharmony_ci} 889062306a36Sopenharmony_ci 889162306a36Sopenharmony_ci/** 889262306a36Sopenharmony_ci * qla4xxx_prevent_other_port_reinit - prevent other port from re-initialize 889362306a36Sopenharmony_ci * @ha: pointer to adapter structure 889462306a36Sopenharmony_ci * 889562306a36Sopenharmony_ci * Mark the other ISP-4xxx port to indicate that the driver is being removed, 889662306a36Sopenharmony_ci * so that the other port will not re-initialize while in the process of 889762306a36Sopenharmony_ci * removing the ha due to driver unload or hba hotplug. 889862306a36Sopenharmony_ci **/ 889962306a36Sopenharmony_cistatic void qla4xxx_prevent_other_port_reinit(struct scsi_qla_host *ha) 890062306a36Sopenharmony_ci{ 890162306a36Sopenharmony_ci struct scsi_qla_host *other_ha = NULL; 890262306a36Sopenharmony_ci struct pci_dev *other_pdev = NULL; 890362306a36Sopenharmony_ci int fn = ISP4XXX_PCI_FN_2; 890462306a36Sopenharmony_ci 890562306a36Sopenharmony_ci /*iscsi function numbers for ISP4xxx is 1 and 3*/ 890662306a36Sopenharmony_ci if (PCI_FUNC(ha->pdev->devfn) & BIT_1) 890762306a36Sopenharmony_ci fn = ISP4XXX_PCI_FN_1; 890862306a36Sopenharmony_ci 890962306a36Sopenharmony_ci other_pdev = 891062306a36Sopenharmony_ci pci_get_domain_bus_and_slot(pci_domain_nr(ha->pdev->bus), 891162306a36Sopenharmony_ci ha->pdev->bus->number, PCI_DEVFN(PCI_SLOT(ha->pdev->devfn), 891262306a36Sopenharmony_ci fn)); 891362306a36Sopenharmony_ci 891462306a36Sopenharmony_ci /* Get other_ha if other_pdev is valid and state is enable*/ 891562306a36Sopenharmony_ci if (other_pdev) { 891662306a36Sopenharmony_ci if (atomic_read(&other_pdev->enable_cnt)) { 891762306a36Sopenharmony_ci other_ha = pci_get_drvdata(other_pdev); 891862306a36Sopenharmony_ci if (other_ha) { 891962306a36Sopenharmony_ci set_bit(AF_HA_REMOVAL, &other_ha->flags); 892062306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "%s: " 892162306a36Sopenharmony_ci "Prevent %s reinit\n", __func__, 892262306a36Sopenharmony_ci dev_name(&other_ha->pdev->dev))); 892362306a36Sopenharmony_ci } 892462306a36Sopenharmony_ci } 892562306a36Sopenharmony_ci pci_dev_put(other_pdev); 892662306a36Sopenharmony_ci } 892762306a36Sopenharmony_ci} 892862306a36Sopenharmony_ci 892962306a36Sopenharmony_cistatic void qla4xxx_destroy_ddb(struct scsi_qla_host *ha, 893062306a36Sopenharmony_ci struct ddb_entry *ddb_entry) 893162306a36Sopenharmony_ci{ 893262306a36Sopenharmony_ci struct dev_db_entry *fw_ddb_entry = NULL; 893362306a36Sopenharmony_ci dma_addr_t fw_ddb_entry_dma; 893462306a36Sopenharmony_ci unsigned long wtime; 893562306a36Sopenharmony_ci uint32_t ddb_state; 893662306a36Sopenharmony_ci int options; 893762306a36Sopenharmony_ci int status; 893862306a36Sopenharmony_ci 893962306a36Sopenharmony_ci options = LOGOUT_OPTION_CLOSE_SESSION; 894062306a36Sopenharmony_ci if (qla4xxx_session_logout_ddb(ha, ddb_entry, options) == QLA_ERROR) { 894162306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: Logout failed\n", __func__); 894262306a36Sopenharmony_ci goto clear_ddb; 894362306a36Sopenharmony_ci } 894462306a36Sopenharmony_ci 894562306a36Sopenharmony_ci fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), 894662306a36Sopenharmony_ci &fw_ddb_entry_dma, GFP_KERNEL); 894762306a36Sopenharmony_ci if (!fw_ddb_entry) { 894862306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, 894962306a36Sopenharmony_ci "%s: Unable to allocate dma buffer\n", __func__); 895062306a36Sopenharmony_ci goto clear_ddb; 895162306a36Sopenharmony_ci } 895262306a36Sopenharmony_ci 895362306a36Sopenharmony_ci wtime = jiffies + (HZ * LOGOUT_TOV); 895462306a36Sopenharmony_ci do { 895562306a36Sopenharmony_ci status = qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index, 895662306a36Sopenharmony_ci fw_ddb_entry, fw_ddb_entry_dma, 895762306a36Sopenharmony_ci NULL, NULL, &ddb_state, NULL, 895862306a36Sopenharmony_ci NULL, NULL); 895962306a36Sopenharmony_ci if (status == QLA_ERROR) 896062306a36Sopenharmony_ci goto free_ddb; 896162306a36Sopenharmony_ci 896262306a36Sopenharmony_ci if ((ddb_state == DDB_DS_NO_CONNECTION_ACTIVE) || 896362306a36Sopenharmony_ci (ddb_state == DDB_DS_SESSION_FAILED)) 896462306a36Sopenharmony_ci goto free_ddb; 896562306a36Sopenharmony_ci 896662306a36Sopenharmony_ci schedule_timeout_uninterruptible(HZ); 896762306a36Sopenharmony_ci } while ((time_after(wtime, jiffies))); 896862306a36Sopenharmony_ci 896962306a36Sopenharmony_cifree_ddb: 897062306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), 897162306a36Sopenharmony_ci fw_ddb_entry, fw_ddb_entry_dma); 897262306a36Sopenharmony_ciclear_ddb: 897362306a36Sopenharmony_ci qla4xxx_clear_ddb_entry(ha, ddb_entry->fw_ddb_index); 897462306a36Sopenharmony_ci} 897562306a36Sopenharmony_ci 897662306a36Sopenharmony_cistatic void qla4xxx_destroy_fw_ddb_session(struct scsi_qla_host *ha) 897762306a36Sopenharmony_ci{ 897862306a36Sopenharmony_ci struct ddb_entry *ddb_entry; 897962306a36Sopenharmony_ci int idx; 898062306a36Sopenharmony_ci 898162306a36Sopenharmony_ci for (idx = 0; idx < MAX_DDB_ENTRIES; idx++) { 898262306a36Sopenharmony_ci 898362306a36Sopenharmony_ci ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx); 898462306a36Sopenharmony_ci if ((ddb_entry != NULL) && 898562306a36Sopenharmony_ci (ddb_entry->ddb_type == FLASH_DDB)) { 898662306a36Sopenharmony_ci 898762306a36Sopenharmony_ci qla4xxx_destroy_ddb(ha, ddb_entry); 898862306a36Sopenharmony_ci /* 898962306a36Sopenharmony_ci * we have decremented the reference count of the driver 899062306a36Sopenharmony_ci * when we setup the session to have the driver unload 899162306a36Sopenharmony_ci * to be seamless without actually destroying the 899262306a36Sopenharmony_ci * session 899362306a36Sopenharmony_ci **/ 899462306a36Sopenharmony_ci try_module_get(qla4xxx_iscsi_transport.owner); 899562306a36Sopenharmony_ci iscsi_destroy_endpoint(ddb_entry->conn->ep); 899662306a36Sopenharmony_ci qla4xxx_free_ddb(ha, ddb_entry); 899762306a36Sopenharmony_ci iscsi_session_teardown(ddb_entry->sess); 899862306a36Sopenharmony_ci } 899962306a36Sopenharmony_ci } 900062306a36Sopenharmony_ci} 900162306a36Sopenharmony_ci/** 900262306a36Sopenharmony_ci * qla4xxx_remove_adapter - callback function to remove adapter. 900362306a36Sopenharmony_ci * @pdev: PCI device pointer 900462306a36Sopenharmony_ci **/ 900562306a36Sopenharmony_cistatic void qla4xxx_remove_adapter(struct pci_dev *pdev) 900662306a36Sopenharmony_ci{ 900762306a36Sopenharmony_ci struct scsi_qla_host *ha; 900862306a36Sopenharmony_ci 900962306a36Sopenharmony_ci /* 901062306a36Sopenharmony_ci * If the PCI device is disabled then it means probe_adapter had 901162306a36Sopenharmony_ci * failed and resources already cleaned up on probe_adapter exit. 901262306a36Sopenharmony_ci */ 901362306a36Sopenharmony_ci if (!pci_is_enabled(pdev)) 901462306a36Sopenharmony_ci return; 901562306a36Sopenharmony_ci 901662306a36Sopenharmony_ci ha = pci_get_drvdata(pdev); 901762306a36Sopenharmony_ci 901862306a36Sopenharmony_ci if (is_qla40XX(ha)) 901962306a36Sopenharmony_ci qla4xxx_prevent_other_port_reinit(ha); 902062306a36Sopenharmony_ci 902162306a36Sopenharmony_ci /* destroy iface from sysfs */ 902262306a36Sopenharmony_ci qla4xxx_destroy_ifaces(ha); 902362306a36Sopenharmony_ci 902462306a36Sopenharmony_ci if ((!ql4xdisablesysfsboot) && ha->boot_kset) 902562306a36Sopenharmony_ci iscsi_boot_destroy_kset(ha->boot_kset); 902662306a36Sopenharmony_ci 902762306a36Sopenharmony_ci qla4xxx_destroy_fw_ddb_session(ha); 902862306a36Sopenharmony_ci qla4_8xxx_free_sysfs_attr(ha); 902962306a36Sopenharmony_ci 903062306a36Sopenharmony_ci qla4xxx_sysfs_ddb_remove(ha); 903162306a36Sopenharmony_ci scsi_remove_host(ha->host); 903262306a36Sopenharmony_ci 903362306a36Sopenharmony_ci qla4xxx_free_adapter(ha); 903462306a36Sopenharmony_ci 903562306a36Sopenharmony_ci scsi_host_put(ha->host); 903662306a36Sopenharmony_ci 903762306a36Sopenharmony_ci pci_disable_device(pdev); 903862306a36Sopenharmony_ci} 903962306a36Sopenharmony_ci 904062306a36Sopenharmony_ci/** 904162306a36Sopenharmony_ci * qla4xxx_config_dma_addressing() - Configure OS DMA addressing method. 904262306a36Sopenharmony_ci * @ha: HA context 904362306a36Sopenharmony_ci */ 904462306a36Sopenharmony_cistatic void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha) 904562306a36Sopenharmony_ci{ 904662306a36Sopenharmony_ci /* Update our PCI device dma_mask for full 64 bit mask */ 904762306a36Sopenharmony_ci if (dma_set_mask_and_coherent(&ha->pdev->dev, DMA_BIT_MASK(64))) { 904862306a36Sopenharmony_ci dev_dbg(&ha->pdev->dev, 904962306a36Sopenharmony_ci "Failed to set 64 bit PCI consistent mask; " 905062306a36Sopenharmony_ci "using 32 bit.\n"); 905162306a36Sopenharmony_ci dma_set_mask_and_coherent(&ha->pdev->dev, DMA_BIT_MASK(32)); 905262306a36Sopenharmony_ci } 905362306a36Sopenharmony_ci} 905462306a36Sopenharmony_ci 905562306a36Sopenharmony_cistatic int qla4xxx_slave_alloc(struct scsi_device *sdev) 905662306a36Sopenharmony_ci{ 905762306a36Sopenharmony_ci struct iscsi_cls_session *cls_sess; 905862306a36Sopenharmony_ci struct iscsi_session *sess; 905962306a36Sopenharmony_ci struct ddb_entry *ddb; 906062306a36Sopenharmony_ci int queue_depth = QL4_DEF_QDEPTH; 906162306a36Sopenharmony_ci 906262306a36Sopenharmony_ci cls_sess = starget_to_session(sdev->sdev_target); 906362306a36Sopenharmony_ci sess = cls_sess->dd_data; 906462306a36Sopenharmony_ci ddb = sess->dd_data; 906562306a36Sopenharmony_ci 906662306a36Sopenharmony_ci sdev->hostdata = ddb; 906762306a36Sopenharmony_ci 906862306a36Sopenharmony_ci if (ql4xmaxqdepth != 0 && ql4xmaxqdepth <= 0xffffU) 906962306a36Sopenharmony_ci queue_depth = ql4xmaxqdepth; 907062306a36Sopenharmony_ci 907162306a36Sopenharmony_ci scsi_change_queue_depth(sdev, queue_depth); 907262306a36Sopenharmony_ci return 0; 907362306a36Sopenharmony_ci} 907462306a36Sopenharmony_ci 907562306a36Sopenharmony_ci/** 907662306a36Sopenharmony_ci * qla4xxx_del_from_active_array - returns an active srb 907762306a36Sopenharmony_ci * @ha: Pointer to host adapter structure. 907862306a36Sopenharmony_ci * @index: index into the active_array 907962306a36Sopenharmony_ci * 908062306a36Sopenharmony_ci * This routine removes and returns the srb at the specified index 908162306a36Sopenharmony_ci **/ 908262306a36Sopenharmony_cistruct srb *qla4xxx_del_from_active_array(struct scsi_qla_host *ha, 908362306a36Sopenharmony_ci uint32_t index) 908462306a36Sopenharmony_ci{ 908562306a36Sopenharmony_ci struct srb *srb = NULL; 908662306a36Sopenharmony_ci struct scsi_cmnd *cmd = NULL; 908762306a36Sopenharmony_ci 908862306a36Sopenharmony_ci cmd = scsi_host_find_tag(ha->host, index); 908962306a36Sopenharmony_ci if (!cmd) 909062306a36Sopenharmony_ci return srb; 909162306a36Sopenharmony_ci 909262306a36Sopenharmony_ci srb = qla4xxx_cmd_priv(cmd)->srb; 909362306a36Sopenharmony_ci if (!srb) 909462306a36Sopenharmony_ci return srb; 909562306a36Sopenharmony_ci 909662306a36Sopenharmony_ci /* update counters */ 909762306a36Sopenharmony_ci if (srb->flags & SRB_DMA_VALID) { 909862306a36Sopenharmony_ci ha->iocb_cnt -= srb->iocb_cnt; 909962306a36Sopenharmony_ci if (srb->cmd) 910062306a36Sopenharmony_ci srb->cmd->host_scribble = 910162306a36Sopenharmony_ci (unsigned char *)(unsigned long) MAX_SRBS; 910262306a36Sopenharmony_ci } 910362306a36Sopenharmony_ci return srb; 910462306a36Sopenharmony_ci} 910562306a36Sopenharmony_ci 910662306a36Sopenharmony_ci/** 910762306a36Sopenharmony_ci * qla4xxx_eh_wait_on_command - waits for command to be returned by firmware 910862306a36Sopenharmony_ci * @ha: Pointer to host adapter structure. 910962306a36Sopenharmony_ci * @cmd: Scsi Command to wait on. 911062306a36Sopenharmony_ci * 911162306a36Sopenharmony_ci * This routine waits for the command to be returned by the Firmware 911262306a36Sopenharmony_ci * for some max time. 911362306a36Sopenharmony_ci **/ 911462306a36Sopenharmony_cistatic int qla4xxx_eh_wait_on_command(struct scsi_qla_host *ha, 911562306a36Sopenharmony_ci struct scsi_cmnd *cmd) 911662306a36Sopenharmony_ci{ 911762306a36Sopenharmony_ci int done = 0; 911862306a36Sopenharmony_ci struct srb *rp; 911962306a36Sopenharmony_ci uint32_t max_wait_time = EH_WAIT_CMD_TOV; 912062306a36Sopenharmony_ci int ret = SUCCESS; 912162306a36Sopenharmony_ci 912262306a36Sopenharmony_ci /* Dont wait on command if PCI error is being handled 912362306a36Sopenharmony_ci * by PCI AER driver 912462306a36Sopenharmony_ci */ 912562306a36Sopenharmony_ci if (unlikely(pci_channel_offline(ha->pdev)) || 912662306a36Sopenharmony_ci (test_bit(AF_EEH_BUSY, &ha->flags))) { 912762306a36Sopenharmony_ci ql4_printk(KERN_WARNING, ha, "scsi%ld: Return from %s\n", 912862306a36Sopenharmony_ci ha->host_no, __func__); 912962306a36Sopenharmony_ci return ret; 913062306a36Sopenharmony_ci } 913162306a36Sopenharmony_ci 913262306a36Sopenharmony_ci do { 913362306a36Sopenharmony_ci /* Checking to see if its returned to OS */ 913462306a36Sopenharmony_ci rp = qla4xxx_cmd_priv(cmd)->srb; 913562306a36Sopenharmony_ci if (rp == NULL) { 913662306a36Sopenharmony_ci done++; 913762306a36Sopenharmony_ci break; 913862306a36Sopenharmony_ci } 913962306a36Sopenharmony_ci 914062306a36Sopenharmony_ci msleep(2000); 914162306a36Sopenharmony_ci } while (max_wait_time--); 914262306a36Sopenharmony_ci 914362306a36Sopenharmony_ci return done; 914462306a36Sopenharmony_ci} 914562306a36Sopenharmony_ci 914662306a36Sopenharmony_ci/** 914762306a36Sopenharmony_ci * qla4xxx_wait_for_hba_online - waits for HBA to come online 914862306a36Sopenharmony_ci * @ha: Pointer to host adapter structure 914962306a36Sopenharmony_ci **/ 915062306a36Sopenharmony_cistatic int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha) 915162306a36Sopenharmony_ci{ 915262306a36Sopenharmony_ci unsigned long wait_online; 915362306a36Sopenharmony_ci 915462306a36Sopenharmony_ci wait_online = jiffies + (HBA_ONLINE_TOV * HZ); 915562306a36Sopenharmony_ci while (time_before(jiffies, wait_online)) { 915662306a36Sopenharmony_ci 915762306a36Sopenharmony_ci if (adapter_up(ha)) 915862306a36Sopenharmony_ci return QLA_SUCCESS; 915962306a36Sopenharmony_ci 916062306a36Sopenharmony_ci msleep(2000); 916162306a36Sopenharmony_ci } 916262306a36Sopenharmony_ci 916362306a36Sopenharmony_ci return QLA_ERROR; 916462306a36Sopenharmony_ci} 916562306a36Sopenharmony_ci 916662306a36Sopenharmony_ci/** 916762306a36Sopenharmony_ci * qla4xxx_eh_wait_for_commands - wait for active cmds to finish. 916862306a36Sopenharmony_ci * @ha: pointer to HBA 916962306a36Sopenharmony_ci * @stgt: pointer to SCSI target 917062306a36Sopenharmony_ci * @sdev: pointer to SCSI device 917162306a36Sopenharmony_ci * 917262306a36Sopenharmony_ci * This function waits for all outstanding commands to a lun to complete. It 917362306a36Sopenharmony_ci * returns 0 if all pending commands are returned and 1 otherwise. 917462306a36Sopenharmony_ci **/ 917562306a36Sopenharmony_cistatic int qla4xxx_eh_wait_for_commands(struct scsi_qla_host *ha, 917662306a36Sopenharmony_ci struct scsi_target *stgt, 917762306a36Sopenharmony_ci struct scsi_device *sdev) 917862306a36Sopenharmony_ci{ 917962306a36Sopenharmony_ci int cnt; 918062306a36Sopenharmony_ci int status = 0; 918162306a36Sopenharmony_ci struct scsi_cmnd *cmd; 918262306a36Sopenharmony_ci 918362306a36Sopenharmony_ci /* 918462306a36Sopenharmony_ci * Waiting for all commands for the designated target or dev 918562306a36Sopenharmony_ci * in the active array 918662306a36Sopenharmony_ci */ 918762306a36Sopenharmony_ci for (cnt = 0; cnt < ha->host->can_queue; cnt++) { 918862306a36Sopenharmony_ci cmd = scsi_host_find_tag(ha->host, cnt); 918962306a36Sopenharmony_ci if (cmd && stgt == scsi_target(cmd->device) && 919062306a36Sopenharmony_ci (!sdev || sdev == cmd->device)) { 919162306a36Sopenharmony_ci if (!qla4xxx_eh_wait_on_command(ha, cmd)) { 919262306a36Sopenharmony_ci status++; 919362306a36Sopenharmony_ci break; 919462306a36Sopenharmony_ci } 919562306a36Sopenharmony_ci } 919662306a36Sopenharmony_ci } 919762306a36Sopenharmony_ci return status; 919862306a36Sopenharmony_ci} 919962306a36Sopenharmony_ci 920062306a36Sopenharmony_ci/** 920162306a36Sopenharmony_ci * qla4xxx_eh_abort - callback for abort task. 920262306a36Sopenharmony_ci * @cmd: Pointer to Linux's SCSI command structure 920362306a36Sopenharmony_ci * 920462306a36Sopenharmony_ci * This routine is called by the Linux OS to abort the specified 920562306a36Sopenharmony_ci * command. 920662306a36Sopenharmony_ci **/ 920762306a36Sopenharmony_cistatic int qla4xxx_eh_abort(struct scsi_cmnd *cmd) 920862306a36Sopenharmony_ci{ 920962306a36Sopenharmony_ci struct scsi_qla_host *ha = to_qla_host(cmd->device->host); 921062306a36Sopenharmony_ci unsigned int id = cmd->device->id; 921162306a36Sopenharmony_ci uint64_t lun = cmd->device->lun; 921262306a36Sopenharmony_ci unsigned long flags; 921362306a36Sopenharmony_ci struct srb *srb = NULL; 921462306a36Sopenharmony_ci int ret = SUCCESS; 921562306a36Sopenharmony_ci int wait = 0; 921662306a36Sopenharmony_ci int rval; 921762306a36Sopenharmony_ci 921862306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "scsi%ld:%d:%llu: Abort command issued cmd=%p, cdb=0x%x\n", 921962306a36Sopenharmony_ci ha->host_no, id, lun, cmd, cmd->cmnd[0]); 922062306a36Sopenharmony_ci 922162306a36Sopenharmony_ci rval = qla4xxx_isp_check_reg(ha); 922262306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 922362306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "PCI/Register disconnect, exiting.\n"); 922462306a36Sopenharmony_ci return FAILED; 922562306a36Sopenharmony_ci } 922662306a36Sopenharmony_ci 922762306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 922862306a36Sopenharmony_ci srb = qla4xxx_cmd_priv(cmd)->srb; 922962306a36Sopenharmony_ci if (!srb) { 923062306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 923162306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "scsi%ld:%d:%llu: Specified command has already completed.\n", 923262306a36Sopenharmony_ci ha->host_no, id, lun); 923362306a36Sopenharmony_ci return SUCCESS; 923462306a36Sopenharmony_ci } 923562306a36Sopenharmony_ci kref_get(&srb->srb_ref); 923662306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 923762306a36Sopenharmony_ci 923862306a36Sopenharmony_ci if (qla4xxx_abort_task(ha, srb) != QLA_SUCCESS) { 923962306a36Sopenharmony_ci DEBUG3(printk("scsi%ld:%d:%llu: Abort_task mbx failed.\n", 924062306a36Sopenharmony_ci ha->host_no, id, lun)); 924162306a36Sopenharmony_ci ret = FAILED; 924262306a36Sopenharmony_ci } else { 924362306a36Sopenharmony_ci DEBUG3(printk("scsi%ld:%d:%llu: Abort_task mbx success.\n", 924462306a36Sopenharmony_ci ha->host_no, id, lun)); 924562306a36Sopenharmony_ci wait = 1; 924662306a36Sopenharmony_ci } 924762306a36Sopenharmony_ci 924862306a36Sopenharmony_ci kref_put(&srb->srb_ref, qla4xxx_srb_compl); 924962306a36Sopenharmony_ci 925062306a36Sopenharmony_ci /* Wait for command to complete */ 925162306a36Sopenharmony_ci if (wait) { 925262306a36Sopenharmony_ci if (!qla4xxx_eh_wait_on_command(ha, cmd)) { 925362306a36Sopenharmony_ci DEBUG2(printk("scsi%ld:%d:%llu: Abort handler timed out\n", 925462306a36Sopenharmony_ci ha->host_no, id, lun)); 925562306a36Sopenharmony_ci ret = FAILED; 925662306a36Sopenharmony_ci } 925762306a36Sopenharmony_ci } 925862306a36Sopenharmony_ci 925962306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, 926062306a36Sopenharmony_ci "scsi%ld:%d:%llu: Abort command - %s\n", 926162306a36Sopenharmony_ci ha->host_no, id, lun, (ret == SUCCESS) ? "succeeded" : "failed"); 926262306a36Sopenharmony_ci 926362306a36Sopenharmony_ci return ret; 926462306a36Sopenharmony_ci} 926562306a36Sopenharmony_ci 926662306a36Sopenharmony_ci/** 926762306a36Sopenharmony_ci * qla4xxx_eh_device_reset - callback for target reset. 926862306a36Sopenharmony_ci * @cmd: Pointer to Linux's SCSI command structure 926962306a36Sopenharmony_ci * 927062306a36Sopenharmony_ci * This routine is called by the Linux OS to reset all luns on the 927162306a36Sopenharmony_ci * specified target. 927262306a36Sopenharmony_ci **/ 927362306a36Sopenharmony_cistatic int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd) 927462306a36Sopenharmony_ci{ 927562306a36Sopenharmony_ci struct scsi_qla_host *ha = to_qla_host(cmd->device->host); 927662306a36Sopenharmony_ci struct ddb_entry *ddb_entry = cmd->device->hostdata; 927762306a36Sopenharmony_ci int ret = FAILED, stat; 927862306a36Sopenharmony_ci int rval; 927962306a36Sopenharmony_ci 928062306a36Sopenharmony_ci if (!ddb_entry) 928162306a36Sopenharmony_ci return ret; 928262306a36Sopenharmony_ci 928362306a36Sopenharmony_ci ret = iscsi_block_scsi_eh(cmd); 928462306a36Sopenharmony_ci if (ret) 928562306a36Sopenharmony_ci return ret; 928662306a36Sopenharmony_ci ret = FAILED; 928762306a36Sopenharmony_ci 928862306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, 928962306a36Sopenharmony_ci "scsi%ld:%d:%d:%llu: DEVICE RESET ISSUED.\n", ha->host_no, 929062306a36Sopenharmony_ci cmd->device->channel, cmd->device->id, cmd->device->lun); 929162306a36Sopenharmony_ci 929262306a36Sopenharmony_ci DEBUG2(printk(KERN_INFO 929362306a36Sopenharmony_ci "scsi%ld: DEVICE_RESET cmd=%p jiffies = 0x%lx, to=%x," 929462306a36Sopenharmony_ci "dpc_flags=%lx, status=%x allowed=%d\n", ha->host_no, 929562306a36Sopenharmony_ci cmd, jiffies, scsi_cmd_to_rq(cmd)->timeout / HZ, 929662306a36Sopenharmony_ci ha->dpc_flags, cmd->result, cmd->allowed)); 929762306a36Sopenharmony_ci 929862306a36Sopenharmony_ci rval = qla4xxx_isp_check_reg(ha); 929962306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 930062306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "PCI/Register disconnect, exiting.\n"); 930162306a36Sopenharmony_ci return FAILED; 930262306a36Sopenharmony_ci } 930362306a36Sopenharmony_ci 930462306a36Sopenharmony_ci /* FIXME: wait for hba to go online */ 930562306a36Sopenharmony_ci stat = qla4xxx_reset_lun(ha, ddb_entry, cmd->device->lun); 930662306a36Sopenharmony_ci if (stat != QLA_SUCCESS) { 930762306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "DEVICE RESET FAILED. %d\n", stat); 930862306a36Sopenharmony_ci goto eh_dev_reset_done; 930962306a36Sopenharmony_ci } 931062306a36Sopenharmony_ci 931162306a36Sopenharmony_ci if (qla4xxx_eh_wait_for_commands(ha, scsi_target(cmd->device), 931262306a36Sopenharmony_ci cmd->device)) { 931362306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, 931462306a36Sopenharmony_ci "DEVICE RESET FAILED - waiting for " 931562306a36Sopenharmony_ci "commands.\n"); 931662306a36Sopenharmony_ci goto eh_dev_reset_done; 931762306a36Sopenharmony_ci } 931862306a36Sopenharmony_ci 931962306a36Sopenharmony_ci /* Send marker. */ 932062306a36Sopenharmony_ci if (qla4xxx_send_marker_iocb(ha, ddb_entry, cmd->device->lun, 932162306a36Sopenharmony_ci MM_LUN_RESET) != QLA_SUCCESS) 932262306a36Sopenharmony_ci goto eh_dev_reset_done; 932362306a36Sopenharmony_ci 932462306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, 932562306a36Sopenharmony_ci "scsi(%ld:%d:%d:%llu): DEVICE RESET SUCCEEDED.\n", 932662306a36Sopenharmony_ci ha->host_no, cmd->device->channel, cmd->device->id, 932762306a36Sopenharmony_ci cmd->device->lun); 932862306a36Sopenharmony_ci 932962306a36Sopenharmony_ci ret = SUCCESS; 933062306a36Sopenharmony_ci 933162306a36Sopenharmony_cieh_dev_reset_done: 933262306a36Sopenharmony_ci 933362306a36Sopenharmony_ci return ret; 933462306a36Sopenharmony_ci} 933562306a36Sopenharmony_ci 933662306a36Sopenharmony_ci/** 933762306a36Sopenharmony_ci * qla4xxx_eh_target_reset - callback for target reset. 933862306a36Sopenharmony_ci * @cmd: Pointer to Linux's SCSI command structure 933962306a36Sopenharmony_ci * 934062306a36Sopenharmony_ci * This routine is called by the Linux OS to reset the target. 934162306a36Sopenharmony_ci **/ 934262306a36Sopenharmony_cistatic int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd) 934362306a36Sopenharmony_ci{ 934462306a36Sopenharmony_ci struct scsi_qla_host *ha = to_qla_host(cmd->device->host); 934562306a36Sopenharmony_ci struct ddb_entry *ddb_entry = cmd->device->hostdata; 934662306a36Sopenharmony_ci int stat, ret; 934762306a36Sopenharmony_ci int rval; 934862306a36Sopenharmony_ci 934962306a36Sopenharmony_ci if (!ddb_entry) 935062306a36Sopenharmony_ci return FAILED; 935162306a36Sopenharmony_ci 935262306a36Sopenharmony_ci ret = iscsi_block_scsi_eh(cmd); 935362306a36Sopenharmony_ci if (ret) 935462306a36Sopenharmony_ci return ret; 935562306a36Sopenharmony_ci 935662306a36Sopenharmony_ci starget_printk(KERN_INFO, scsi_target(cmd->device), 935762306a36Sopenharmony_ci "WARM TARGET RESET ISSUED.\n"); 935862306a36Sopenharmony_ci 935962306a36Sopenharmony_ci DEBUG2(printk(KERN_INFO 936062306a36Sopenharmony_ci "scsi%ld: TARGET_DEVICE_RESET cmd=%p jiffies = 0x%lx, " 936162306a36Sopenharmony_ci "to=%x,dpc_flags=%lx, status=%x allowed=%d\n", 936262306a36Sopenharmony_ci ha->host_no, cmd, jiffies, scsi_cmd_to_rq(cmd)->timeout / HZ, 936362306a36Sopenharmony_ci ha->dpc_flags, cmd->result, cmd->allowed)); 936462306a36Sopenharmony_ci 936562306a36Sopenharmony_ci rval = qla4xxx_isp_check_reg(ha); 936662306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 936762306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "PCI/Register disconnect, exiting.\n"); 936862306a36Sopenharmony_ci return FAILED; 936962306a36Sopenharmony_ci } 937062306a36Sopenharmony_ci 937162306a36Sopenharmony_ci stat = qla4xxx_reset_target(ha, ddb_entry); 937262306a36Sopenharmony_ci if (stat != QLA_SUCCESS) { 937362306a36Sopenharmony_ci starget_printk(KERN_INFO, scsi_target(cmd->device), 937462306a36Sopenharmony_ci "WARM TARGET RESET FAILED.\n"); 937562306a36Sopenharmony_ci return FAILED; 937662306a36Sopenharmony_ci } 937762306a36Sopenharmony_ci 937862306a36Sopenharmony_ci if (qla4xxx_eh_wait_for_commands(ha, scsi_target(cmd->device), 937962306a36Sopenharmony_ci NULL)) { 938062306a36Sopenharmony_ci starget_printk(KERN_INFO, scsi_target(cmd->device), 938162306a36Sopenharmony_ci "WARM TARGET DEVICE RESET FAILED - " 938262306a36Sopenharmony_ci "waiting for commands.\n"); 938362306a36Sopenharmony_ci return FAILED; 938462306a36Sopenharmony_ci } 938562306a36Sopenharmony_ci 938662306a36Sopenharmony_ci /* Send marker. */ 938762306a36Sopenharmony_ci if (qla4xxx_send_marker_iocb(ha, ddb_entry, cmd->device->lun, 938862306a36Sopenharmony_ci MM_TGT_WARM_RESET) != QLA_SUCCESS) { 938962306a36Sopenharmony_ci starget_printk(KERN_INFO, scsi_target(cmd->device), 939062306a36Sopenharmony_ci "WARM TARGET DEVICE RESET FAILED - " 939162306a36Sopenharmony_ci "marker iocb failed.\n"); 939262306a36Sopenharmony_ci return FAILED; 939362306a36Sopenharmony_ci } 939462306a36Sopenharmony_ci 939562306a36Sopenharmony_ci starget_printk(KERN_INFO, scsi_target(cmd->device), 939662306a36Sopenharmony_ci "WARM TARGET RESET SUCCEEDED.\n"); 939762306a36Sopenharmony_ci return SUCCESS; 939862306a36Sopenharmony_ci} 939962306a36Sopenharmony_ci 940062306a36Sopenharmony_ci/** 940162306a36Sopenharmony_ci * qla4xxx_is_eh_active - check if error handler is running 940262306a36Sopenharmony_ci * @shost: Pointer to SCSI Host struct 940362306a36Sopenharmony_ci * 940462306a36Sopenharmony_ci * This routine finds that if reset host is called in EH 940562306a36Sopenharmony_ci * scenario or from some application like sg_reset 940662306a36Sopenharmony_ci **/ 940762306a36Sopenharmony_cistatic int qla4xxx_is_eh_active(struct Scsi_Host *shost) 940862306a36Sopenharmony_ci{ 940962306a36Sopenharmony_ci if (shost->shost_state == SHOST_RECOVERY) 941062306a36Sopenharmony_ci return 1; 941162306a36Sopenharmony_ci return 0; 941262306a36Sopenharmony_ci} 941362306a36Sopenharmony_ci 941462306a36Sopenharmony_ci/** 941562306a36Sopenharmony_ci * qla4xxx_eh_host_reset - kernel callback 941662306a36Sopenharmony_ci * @cmd: Pointer to Linux's SCSI command structure 941762306a36Sopenharmony_ci * 941862306a36Sopenharmony_ci * This routine is invoked by the Linux kernel to perform fatal error 941962306a36Sopenharmony_ci * recovery on the specified adapter. 942062306a36Sopenharmony_ci **/ 942162306a36Sopenharmony_cistatic int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd) 942262306a36Sopenharmony_ci{ 942362306a36Sopenharmony_ci int return_status = FAILED; 942462306a36Sopenharmony_ci struct scsi_qla_host *ha; 942562306a36Sopenharmony_ci int rval; 942662306a36Sopenharmony_ci 942762306a36Sopenharmony_ci ha = to_qla_host(cmd->device->host); 942862306a36Sopenharmony_ci 942962306a36Sopenharmony_ci rval = qla4xxx_isp_check_reg(ha); 943062306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 943162306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "PCI/Register disconnect, exiting.\n"); 943262306a36Sopenharmony_ci return FAILED; 943362306a36Sopenharmony_ci } 943462306a36Sopenharmony_ci 943562306a36Sopenharmony_ci if ((is_qla8032(ha) || is_qla8042(ha)) && ql4xdontresethba) 943662306a36Sopenharmony_ci qla4_83xx_set_idc_dontreset(ha); 943762306a36Sopenharmony_ci 943862306a36Sopenharmony_ci /* 943962306a36Sopenharmony_ci * For ISP8324 and ISP8042, if IDC_CTRL DONTRESET_BIT0 is set by other 944062306a36Sopenharmony_ci * protocol drivers, we should not set device_state to NEED_RESET 944162306a36Sopenharmony_ci */ 944262306a36Sopenharmony_ci if (ql4xdontresethba || 944362306a36Sopenharmony_ci ((is_qla8032(ha) || is_qla8042(ha)) && 944462306a36Sopenharmony_ci qla4_83xx_idc_dontreset(ha))) { 944562306a36Sopenharmony_ci DEBUG2(printk("scsi%ld: %s: Don't Reset HBA\n", 944662306a36Sopenharmony_ci ha->host_no, __func__)); 944762306a36Sopenharmony_ci 944862306a36Sopenharmony_ci /* Clear outstanding srb in queues */ 944962306a36Sopenharmony_ci if (qla4xxx_is_eh_active(cmd->device->host)) 945062306a36Sopenharmony_ci qla4xxx_abort_active_cmds(ha, DID_ABORT << 16); 945162306a36Sopenharmony_ci 945262306a36Sopenharmony_ci return FAILED; 945362306a36Sopenharmony_ci } 945462306a36Sopenharmony_ci 945562306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, 945662306a36Sopenharmony_ci "scsi(%ld:%d:%d:%llu): HOST RESET ISSUED.\n", ha->host_no, 945762306a36Sopenharmony_ci cmd->device->channel, cmd->device->id, cmd->device->lun); 945862306a36Sopenharmony_ci 945962306a36Sopenharmony_ci if (qla4xxx_wait_for_hba_online(ha) != QLA_SUCCESS) { 946062306a36Sopenharmony_ci DEBUG2(printk("scsi%ld:%d: %s: Unable to reset host. Adapter " 946162306a36Sopenharmony_ci "DEAD.\n", ha->host_no, cmd->device->channel, 946262306a36Sopenharmony_ci __func__)); 946362306a36Sopenharmony_ci 946462306a36Sopenharmony_ci return FAILED; 946562306a36Sopenharmony_ci } 946662306a36Sopenharmony_ci 946762306a36Sopenharmony_ci if (!test_bit(DPC_RESET_HA, &ha->dpc_flags)) { 946862306a36Sopenharmony_ci if (is_qla80XX(ha)) 946962306a36Sopenharmony_ci set_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags); 947062306a36Sopenharmony_ci else 947162306a36Sopenharmony_ci set_bit(DPC_RESET_HA, &ha->dpc_flags); 947262306a36Sopenharmony_ci } 947362306a36Sopenharmony_ci 947462306a36Sopenharmony_ci if (qla4xxx_recover_adapter(ha) == QLA_SUCCESS) 947562306a36Sopenharmony_ci return_status = SUCCESS; 947662306a36Sopenharmony_ci 947762306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "HOST RESET %s.\n", 947862306a36Sopenharmony_ci return_status == FAILED ? "FAILED" : "SUCCEEDED"); 947962306a36Sopenharmony_ci 948062306a36Sopenharmony_ci return return_status; 948162306a36Sopenharmony_ci} 948262306a36Sopenharmony_ci 948362306a36Sopenharmony_cistatic int qla4xxx_context_reset(struct scsi_qla_host *ha) 948462306a36Sopenharmony_ci{ 948562306a36Sopenharmony_ci uint32_t mbox_cmd[MBOX_REG_COUNT]; 948662306a36Sopenharmony_ci uint32_t mbox_sts[MBOX_REG_COUNT]; 948762306a36Sopenharmony_ci struct addr_ctrl_blk_def *acb = NULL; 948862306a36Sopenharmony_ci uint32_t acb_len = sizeof(struct addr_ctrl_blk_def); 948962306a36Sopenharmony_ci int rval = QLA_SUCCESS; 949062306a36Sopenharmony_ci dma_addr_t acb_dma; 949162306a36Sopenharmony_ci 949262306a36Sopenharmony_ci acb = dma_alloc_coherent(&ha->pdev->dev, 949362306a36Sopenharmony_ci sizeof(struct addr_ctrl_blk_def), 949462306a36Sopenharmony_ci &acb_dma, GFP_KERNEL); 949562306a36Sopenharmony_ci if (!acb) { 949662306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: Unable to alloc acb\n", 949762306a36Sopenharmony_ci __func__); 949862306a36Sopenharmony_ci rval = -ENOMEM; 949962306a36Sopenharmony_ci goto exit_port_reset; 950062306a36Sopenharmony_ci } 950162306a36Sopenharmony_ci 950262306a36Sopenharmony_ci memset(acb, 0, acb_len); 950362306a36Sopenharmony_ci 950462306a36Sopenharmony_ci rval = qla4xxx_get_acb(ha, acb_dma, PRIMARI_ACB, acb_len); 950562306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 950662306a36Sopenharmony_ci rval = -EIO; 950762306a36Sopenharmony_ci goto exit_free_acb; 950862306a36Sopenharmony_ci } 950962306a36Sopenharmony_ci 951062306a36Sopenharmony_ci rval = qla4xxx_disable_acb(ha); 951162306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 951262306a36Sopenharmony_ci rval = -EIO; 951362306a36Sopenharmony_ci goto exit_free_acb; 951462306a36Sopenharmony_ci } 951562306a36Sopenharmony_ci 951662306a36Sopenharmony_ci wait_for_completion_timeout(&ha->disable_acb_comp, 951762306a36Sopenharmony_ci DISABLE_ACB_TOV * HZ); 951862306a36Sopenharmony_ci 951962306a36Sopenharmony_ci rval = qla4xxx_set_acb(ha, &mbox_cmd[0], &mbox_sts[0], acb_dma); 952062306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 952162306a36Sopenharmony_ci rval = -EIO; 952262306a36Sopenharmony_ci goto exit_free_acb; 952362306a36Sopenharmony_ci } 952462306a36Sopenharmony_ci 952562306a36Sopenharmony_ciexit_free_acb: 952662306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, sizeof(struct addr_ctrl_blk_def), 952762306a36Sopenharmony_ci acb, acb_dma); 952862306a36Sopenharmony_ciexit_port_reset: 952962306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "%s %s\n", __func__, 953062306a36Sopenharmony_ci rval == QLA_SUCCESS ? "SUCCEEDED" : "FAILED")); 953162306a36Sopenharmony_ci return rval; 953262306a36Sopenharmony_ci} 953362306a36Sopenharmony_ci 953462306a36Sopenharmony_cistatic int qla4xxx_host_reset(struct Scsi_Host *shost, int reset_type) 953562306a36Sopenharmony_ci{ 953662306a36Sopenharmony_ci struct scsi_qla_host *ha = to_qla_host(shost); 953762306a36Sopenharmony_ci int rval = QLA_SUCCESS; 953862306a36Sopenharmony_ci uint32_t idc_ctrl; 953962306a36Sopenharmony_ci 954062306a36Sopenharmony_ci if (ql4xdontresethba) { 954162306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Don't Reset HBA\n", 954262306a36Sopenharmony_ci __func__)); 954362306a36Sopenharmony_ci rval = -EPERM; 954462306a36Sopenharmony_ci goto exit_host_reset; 954562306a36Sopenharmony_ci } 954662306a36Sopenharmony_ci 954762306a36Sopenharmony_ci if (test_bit(DPC_RESET_HA, &ha->dpc_flags)) 954862306a36Sopenharmony_ci goto recover_adapter; 954962306a36Sopenharmony_ci 955062306a36Sopenharmony_ci switch (reset_type) { 955162306a36Sopenharmony_ci case SCSI_ADAPTER_RESET: 955262306a36Sopenharmony_ci set_bit(DPC_RESET_HA, &ha->dpc_flags); 955362306a36Sopenharmony_ci break; 955462306a36Sopenharmony_ci case SCSI_FIRMWARE_RESET: 955562306a36Sopenharmony_ci if (!test_bit(DPC_RESET_HA, &ha->dpc_flags)) { 955662306a36Sopenharmony_ci if (is_qla80XX(ha)) 955762306a36Sopenharmony_ci /* set firmware context reset */ 955862306a36Sopenharmony_ci set_bit(DPC_RESET_HA_FW_CONTEXT, 955962306a36Sopenharmony_ci &ha->dpc_flags); 956062306a36Sopenharmony_ci else { 956162306a36Sopenharmony_ci rval = qla4xxx_context_reset(ha); 956262306a36Sopenharmony_ci goto exit_host_reset; 956362306a36Sopenharmony_ci } 956462306a36Sopenharmony_ci } 956562306a36Sopenharmony_ci break; 956662306a36Sopenharmony_ci } 956762306a36Sopenharmony_ci 956862306a36Sopenharmony_cirecover_adapter: 956962306a36Sopenharmony_ci /* For ISP8324 and ISP8042 set graceful reset bit in IDC_DRV_CTRL if 957062306a36Sopenharmony_ci * reset is issued by application */ 957162306a36Sopenharmony_ci if ((is_qla8032(ha) || is_qla8042(ha)) && 957262306a36Sopenharmony_ci test_bit(DPC_RESET_HA, &ha->dpc_flags)) { 957362306a36Sopenharmony_ci idc_ctrl = qla4_83xx_rd_reg(ha, QLA83XX_IDC_DRV_CTRL); 957462306a36Sopenharmony_ci qla4_83xx_wr_reg(ha, QLA83XX_IDC_DRV_CTRL, 957562306a36Sopenharmony_ci (idc_ctrl | GRACEFUL_RESET_BIT1)); 957662306a36Sopenharmony_ci } 957762306a36Sopenharmony_ci 957862306a36Sopenharmony_ci rval = qla4xxx_recover_adapter(ha); 957962306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 958062306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "%s: recover adapter fail\n", 958162306a36Sopenharmony_ci __func__)); 958262306a36Sopenharmony_ci rval = -EIO; 958362306a36Sopenharmony_ci } 958462306a36Sopenharmony_ci 958562306a36Sopenharmony_ciexit_host_reset: 958662306a36Sopenharmony_ci return rval; 958762306a36Sopenharmony_ci} 958862306a36Sopenharmony_ci 958962306a36Sopenharmony_ci/* PCI AER driver recovers from all correctable errors w/o 959062306a36Sopenharmony_ci * driver intervention. For uncorrectable errors PCI AER 959162306a36Sopenharmony_ci * driver calls the following device driver's callbacks 959262306a36Sopenharmony_ci * 959362306a36Sopenharmony_ci * - Fatal Errors - link_reset 959462306a36Sopenharmony_ci * - Non-Fatal Errors - driver's error_detected() which 959562306a36Sopenharmony_ci * returns CAN_RECOVER, NEED_RESET or DISCONNECT. 959662306a36Sopenharmony_ci * 959762306a36Sopenharmony_ci * PCI AER driver calls 959862306a36Sopenharmony_ci * CAN_RECOVER - driver's mmio_enabled(), mmio_enabled() 959962306a36Sopenharmony_ci * returns RECOVERED or NEED_RESET if fw_hung 960062306a36Sopenharmony_ci * NEED_RESET - driver's slot_reset() 960162306a36Sopenharmony_ci * DISCONNECT - device is dead & cannot recover 960262306a36Sopenharmony_ci * RECOVERED - driver's resume() 960362306a36Sopenharmony_ci */ 960462306a36Sopenharmony_cistatic pci_ers_result_t 960562306a36Sopenharmony_ciqla4xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) 960662306a36Sopenharmony_ci{ 960762306a36Sopenharmony_ci struct scsi_qla_host *ha = pci_get_drvdata(pdev); 960862306a36Sopenharmony_ci 960962306a36Sopenharmony_ci ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: error detected:state %x\n", 961062306a36Sopenharmony_ci ha->host_no, __func__, state); 961162306a36Sopenharmony_ci 961262306a36Sopenharmony_ci if (!is_aer_supported(ha)) 961362306a36Sopenharmony_ci return PCI_ERS_RESULT_NONE; 961462306a36Sopenharmony_ci 961562306a36Sopenharmony_ci switch (state) { 961662306a36Sopenharmony_ci case pci_channel_io_normal: 961762306a36Sopenharmony_ci clear_bit(AF_EEH_BUSY, &ha->flags); 961862306a36Sopenharmony_ci return PCI_ERS_RESULT_CAN_RECOVER; 961962306a36Sopenharmony_ci case pci_channel_io_frozen: 962062306a36Sopenharmony_ci set_bit(AF_EEH_BUSY, &ha->flags); 962162306a36Sopenharmony_ci qla4xxx_mailbox_premature_completion(ha); 962262306a36Sopenharmony_ci qla4xxx_free_irqs(ha); 962362306a36Sopenharmony_ci pci_disable_device(pdev); 962462306a36Sopenharmony_ci /* Return back all IOs */ 962562306a36Sopenharmony_ci qla4xxx_abort_active_cmds(ha, DID_RESET << 16); 962662306a36Sopenharmony_ci return PCI_ERS_RESULT_NEED_RESET; 962762306a36Sopenharmony_ci case pci_channel_io_perm_failure: 962862306a36Sopenharmony_ci set_bit(AF_EEH_BUSY, &ha->flags); 962962306a36Sopenharmony_ci set_bit(AF_PCI_CHANNEL_IO_PERM_FAILURE, &ha->flags); 963062306a36Sopenharmony_ci qla4xxx_abort_active_cmds(ha, DID_NO_CONNECT << 16); 963162306a36Sopenharmony_ci return PCI_ERS_RESULT_DISCONNECT; 963262306a36Sopenharmony_ci } 963362306a36Sopenharmony_ci return PCI_ERS_RESULT_NEED_RESET; 963462306a36Sopenharmony_ci} 963562306a36Sopenharmony_ci 963662306a36Sopenharmony_ci/** 963762306a36Sopenharmony_ci * qla4xxx_pci_mmio_enabled() - gets called if 963862306a36Sopenharmony_ci * qla4xxx_pci_error_detected() returns PCI_ERS_RESULT_CAN_RECOVER 963962306a36Sopenharmony_ci * and read/write to the device still works. 964062306a36Sopenharmony_ci * @pdev: PCI device pointer 964162306a36Sopenharmony_ci **/ 964262306a36Sopenharmony_cistatic pci_ers_result_t 964362306a36Sopenharmony_ciqla4xxx_pci_mmio_enabled(struct pci_dev *pdev) 964462306a36Sopenharmony_ci{ 964562306a36Sopenharmony_ci struct scsi_qla_host *ha = pci_get_drvdata(pdev); 964662306a36Sopenharmony_ci 964762306a36Sopenharmony_ci if (!is_aer_supported(ha)) 964862306a36Sopenharmony_ci return PCI_ERS_RESULT_NONE; 964962306a36Sopenharmony_ci 965062306a36Sopenharmony_ci return PCI_ERS_RESULT_RECOVERED; 965162306a36Sopenharmony_ci} 965262306a36Sopenharmony_ci 965362306a36Sopenharmony_cistatic uint32_t qla4_8xxx_error_recovery(struct scsi_qla_host *ha) 965462306a36Sopenharmony_ci{ 965562306a36Sopenharmony_ci uint32_t rval = QLA_ERROR; 965662306a36Sopenharmony_ci int fn; 965762306a36Sopenharmony_ci struct pci_dev *other_pdev = NULL; 965862306a36Sopenharmony_ci 965962306a36Sopenharmony_ci ql4_printk(KERN_WARNING, ha, "scsi%ld: In %s\n", ha->host_no, __func__); 966062306a36Sopenharmony_ci 966162306a36Sopenharmony_ci set_bit(DPC_RESET_ACTIVE, &ha->dpc_flags); 966262306a36Sopenharmony_ci 966362306a36Sopenharmony_ci if (test_bit(AF_ONLINE, &ha->flags)) { 966462306a36Sopenharmony_ci clear_bit(AF_ONLINE, &ha->flags); 966562306a36Sopenharmony_ci clear_bit(AF_LINK_UP, &ha->flags); 966662306a36Sopenharmony_ci iscsi_host_for_each_session(ha->host, qla4xxx_fail_session); 966762306a36Sopenharmony_ci qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); 966862306a36Sopenharmony_ci } 966962306a36Sopenharmony_ci 967062306a36Sopenharmony_ci fn = PCI_FUNC(ha->pdev->devfn); 967162306a36Sopenharmony_ci if (is_qla8022(ha)) { 967262306a36Sopenharmony_ci while (fn > 0) { 967362306a36Sopenharmony_ci fn--; 967462306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "scsi%ld: %s: Finding PCI device at func %x\n", 967562306a36Sopenharmony_ci ha->host_no, __func__, fn); 967662306a36Sopenharmony_ci /* Get the pci device given the domain, bus, 967762306a36Sopenharmony_ci * slot/function number */ 967862306a36Sopenharmony_ci other_pdev = pci_get_domain_bus_and_slot( 967962306a36Sopenharmony_ci pci_domain_nr(ha->pdev->bus), 968062306a36Sopenharmony_ci ha->pdev->bus->number, 968162306a36Sopenharmony_ci PCI_DEVFN(PCI_SLOT(ha->pdev->devfn), 968262306a36Sopenharmony_ci fn)); 968362306a36Sopenharmony_ci 968462306a36Sopenharmony_ci if (!other_pdev) 968562306a36Sopenharmony_ci continue; 968662306a36Sopenharmony_ci 968762306a36Sopenharmony_ci if (atomic_read(&other_pdev->enable_cnt)) { 968862306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "scsi%ld: %s: Found PCI func in enabled state%x\n", 968962306a36Sopenharmony_ci ha->host_no, __func__, fn); 969062306a36Sopenharmony_ci pci_dev_put(other_pdev); 969162306a36Sopenharmony_ci break; 969262306a36Sopenharmony_ci } 969362306a36Sopenharmony_ci pci_dev_put(other_pdev); 969462306a36Sopenharmony_ci } 969562306a36Sopenharmony_ci } else { 969662306a36Sopenharmony_ci /* this case is meant for ISP83xx/ISP84xx only */ 969762306a36Sopenharmony_ci if (qla4_83xx_can_perform_reset(ha)) { 969862306a36Sopenharmony_ci /* reset fn as iSCSI is going to perform the reset */ 969962306a36Sopenharmony_ci fn = 0; 970062306a36Sopenharmony_ci } 970162306a36Sopenharmony_ci } 970262306a36Sopenharmony_ci 970362306a36Sopenharmony_ci /* The first function on the card, the reset owner will 970462306a36Sopenharmony_ci * start & initialize the firmware. The other functions 970562306a36Sopenharmony_ci * on the card will reset the firmware context 970662306a36Sopenharmony_ci */ 970762306a36Sopenharmony_ci if (!fn) { 970862306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "scsi%ld: %s: devfn being reset " 970962306a36Sopenharmony_ci "0x%x is the owner\n", ha->host_no, __func__, 971062306a36Sopenharmony_ci ha->pdev->devfn); 971162306a36Sopenharmony_ci 971262306a36Sopenharmony_ci ha->isp_ops->idc_lock(ha); 971362306a36Sopenharmony_ci qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE, 971462306a36Sopenharmony_ci QLA8XXX_DEV_COLD); 971562306a36Sopenharmony_ci ha->isp_ops->idc_unlock(ha); 971662306a36Sopenharmony_ci 971762306a36Sopenharmony_ci rval = qla4_8xxx_update_idc_reg(ha); 971862306a36Sopenharmony_ci if (rval == QLA_ERROR) { 971962306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "scsi%ld: %s: HW State: FAILED\n", 972062306a36Sopenharmony_ci ha->host_no, __func__); 972162306a36Sopenharmony_ci ha->isp_ops->idc_lock(ha); 972262306a36Sopenharmony_ci qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE, 972362306a36Sopenharmony_ci QLA8XXX_DEV_FAILED); 972462306a36Sopenharmony_ci ha->isp_ops->idc_unlock(ha); 972562306a36Sopenharmony_ci goto exit_error_recovery; 972662306a36Sopenharmony_ci } 972762306a36Sopenharmony_ci 972862306a36Sopenharmony_ci clear_bit(AF_FW_RECOVERY, &ha->flags); 972962306a36Sopenharmony_ci rval = qla4xxx_initialize_adapter(ha, RESET_ADAPTER); 973062306a36Sopenharmony_ci 973162306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 973262306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "scsi%ld: %s: HW State: " 973362306a36Sopenharmony_ci "FAILED\n", ha->host_no, __func__); 973462306a36Sopenharmony_ci qla4xxx_free_irqs(ha); 973562306a36Sopenharmony_ci ha->isp_ops->idc_lock(ha); 973662306a36Sopenharmony_ci qla4_8xxx_clear_drv_active(ha); 973762306a36Sopenharmony_ci qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE, 973862306a36Sopenharmony_ci QLA8XXX_DEV_FAILED); 973962306a36Sopenharmony_ci ha->isp_ops->idc_unlock(ha); 974062306a36Sopenharmony_ci } else { 974162306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "scsi%ld: %s: HW State: " 974262306a36Sopenharmony_ci "READY\n", ha->host_no, __func__); 974362306a36Sopenharmony_ci ha->isp_ops->idc_lock(ha); 974462306a36Sopenharmony_ci qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE, 974562306a36Sopenharmony_ci QLA8XXX_DEV_READY); 974662306a36Sopenharmony_ci /* Clear driver state register */ 974762306a36Sopenharmony_ci qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DRV_STATE, 0); 974862306a36Sopenharmony_ci qla4_8xxx_set_drv_active(ha); 974962306a36Sopenharmony_ci ha->isp_ops->idc_unlock(ha); 975062306a36Sopenharmony_ci ha->isp_ops->enable_intrs(ha); 975162306a36Sopenharmony_ci } 975262306a36Sopenharmony_ci } else { 975362306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "scsi%ld: %s: devfn 0x%x is not " 975462306a36Sopenharmony_ci "the reset owner\n", ha->host_no, __func__, 975562306a36Sopenharmony_ci ha->pdev->devfn); 975662306a36Sopenharmony_ci if ((qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DEV_STATE) == 975762306a36Sopenharmony_ci QLA8XXX_DEV_READY)) { 975862306a36Sopenharmony_ci clear_bit(AF_FW_RECOVERY, &ha->flags); 975962306a36Sopenharmony_ci rval = qla4xxx_initialize_adapter(ha, RESET_ADAPTER); 976062306a36Sopenharmony_ci if (rval == QLA_SUCCESS) 976162306a36Sopenharmony_ci ha->isp_ops->enable_intrs(ha); 976262306a36Sopenharmony_ci else 976362306a36Sopenharmony_ci qla4xxx_free_irqs(ha); 976462306a36Sopenharmony_ci 976562306a36Sopenharmony_ci ha->isp_ops->idc_lock(ha); 976662306a36Sopenharmony_ci qla4_8xxx_set_drv_active(ha); 976762306a36Sopenharmony_ci ha->isp_ops->idc_unlock(ha); 976862306a36Sopenharmony_ci } 976962306a36Sopenharmony_ci } 977062306a36Sopenharmony_ciexit_error_recovery: 977162306a36Sopenharmony_ci clear_bit(DPC_RESET_ACTIVE, &ha->dpc_flags); 977262306a36Sopenharmony_ci return rval; 977362306a36Sopenharmony_ci} 977462306a36Sopenharmony_ci 977562306a36Sopenharmony_cistatic pci_ers_result_t 977662306a36Sopenharmony_ciqla4xxx_pci_slot_reset(struct pci_dev *pdev) 977762306a36Sopenharmony_ci{ 977862306a36Sopenharmony_ci pci_ers_result_t ret = PCI_ERS_RESULT_DISCONNECT; 977962306a36Sopenharmony_ci struct scsi_qla_host *ha = pci_get_drvdata(pdev); 978062306a36Sopenharmony_ci int rc; 978162306a36Sopenharmony_ci 978262306a36Sopenharmony_ci ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: slot_reset\n", 978362306a36Sopenharmony_ci ha->host_no, __func__); 978462306a36Sopenharmony_ci 978562306a36Sopenharmony_ci if (!is_aer_supported(ha)) 978662306a36Sopenharmony_ci return PCI_ERS_RESULT_NONE; 978762306a36Sopenharmony_ci 978862306a36Sopenharmony_ci /* Restore the saved state of PCIe device - 978962306a36Sopenharmony_ci * BAR registers, PCI Config space, PCIX, MSI, 979062306a36Sopenharmony_ci * IOV states 979162306a36Sopenharmony_ci */ 979262306a36Sopenharmony_ci pci_restore_state(pdev); 979362306a36Sopenharmony_ci 979462306a36Sopenharmony_ci /* pci_restore_state() clears the saved_state flag of the device 979562306a36Sopenharmony_ci * save restored state which resets saved_state flag 979662306a36Sopenharmony_ci */ 979762306a36Sopenharmony_ci pci_save_state(pdev); 979862306a36Sopenharmony_ci 979962306a36Sopenharmony_ci /* Initialize device or resume if in suspended state */ 980062306a36Sopenharmony_ci rc = pci_enable_device(pdev); 980162306a36Sopenharmony_ci if (rc) { 980262306a36Sopenharmony_ci ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: Can't re-enable " 980362306a36Sopenharmony_ci "device after reset\n", ha->host_no, __func__); 980462306a36Sopenharmony_ci goto exit_slot_reset; 980562306a36Sopenharmony_ci } 980662306a36Sopenharmony_ci 980762306a36Sopenharmony_ci ha->isp_ops->disable_intrs(ha); 980862306a36Sopenharmony_ci 980962306a36Sopenharmony_ci if (is_qla80XX(ha)) { 981062306a36Sopenharmony_ci if (qla4_8xxx_error_recovery(ha) == QLA_SUCCESS) { 981162306a36Sopenharmony_ci ret = PCI_ERS_RESULT_RECOVERED; 981262306a36Sopenharmony_ci goto exit_slot_reset; 981362306a36Sopenharmony_ci } else 981462306a36Sopenharmony_ci goto exit_slot_reset; 981562306a36Sopenharmony_ci } 981662306a36Sopenharmony_ci 981762306a36Sopenharmony_ciexit_slot_reset: 981862306a36Sopenharmony_ci ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: Return=%x\n" 981962306a36Sopenharmony_ci "device after reset\n", ha->host_no, __func__, ret); 982062306a36Sopenharmony_ci return ret; 982162306a36Sopenharmony_ci} 982262306a36Sopenharmony_ci 982362306a36Sopenharmony_cistatic void 982462306a36Sopenharmony_ciqla4xxx_pci_resume(struct pci_dev *pdev) 982562306a36Sopenharmony_ci{ 982662306a36Sopenharmony_ci struct scsi_qla_host *ha = pci_get_drvdata(pdev); 982762306a36Sopenharmony_ci int ret; 982862306a36Sopenharmony_ci 982962306a36Sopenharmony_ci ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: pci_resume\n", 983062306a36Sopenharmony_ci ha->host_no, __func__); 983162306a36Sopenharmony_ci 983262306a36Sopenharmony_ci ret = qla4xxx_wait_for_hba_online(ha); 983362306a36Sopenharmony_ci if (ret != QLA_SUCCESS) { 983462306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "scsi%ld: %s: the device failed to " 983562306a36Sopenharmony_ci "resume I/O from slot/link_reset\n", ha->host_no, 983662306a36Sopenharmony_ci __func__); 983762306a36Sopenharmony_ci } 983862306a36Sopenharmony_ci 983962306a36Sopenharmony_ci clear_bit(AF_EEH_BUSY, &ha->flags); 984062306a36Sopenharmony_ci} 984162306a36Sopenharmony_ci 984262306a36Sopenharmony_cistatic const struct pci_error_handlers qla4xxx_err_handler = { 984362306a36Sopenharmony_ci .error_detected = qla4xxx_pci_error_detected, 984462306a36Sopenharmony_ci .mmio_enabled = qla4xxx_pci_mmio_enabled, 984562306a36Sopenharmony_ci .slot_reset = qla4xxx_pci_slot_reset, 984662306a36Sopenharmony_ci .resume = qla4xxx_pci_resume, 984762306a36Sopenharmony_ci}; 984862306a36Sopenharmony_ci 984962306a36Sopenharmony_cistatic struct pci_device_id qla4xxx_pci_tbl[] = { 985062306a36Sopenharmony_ci { 985162306a36Sopenharmony_ci .vendor = PCI_VENDOR_ID_QLOGIC, 985262306a36Sopenharmony_ci .device = PCI_DEVICE_ID_QLOGIC_ISP4010, 985362306a36Sopenharmony_ci .subvendor = PCI_ANY_ID, 985462306a36Sopenharmony_ci .subdevice = PCI_ANY_ID, 985562306a36Sopenharmony_ci }, 985662306a36Sopenharmony_ci { 985762306a36Sopenharmony_ci .vendor = PCI_VENDOR_ID_QLOGIC, 985862306a36Sopenharmony_ci .device = PCI_DEVICE_ID_QLOGIC_ISP4022, 985962306a36Sopenharmony_ci .subvendor = PCI_ANY_ID, 986062306a36Sopenharmony_ci .subdevice = PCI_ANY_ID, 986162306a36Sopenharmony_ci }, 986262306a36Sopenharmony_ci { 986362306a36Sopenharmony_ci .vendor = PCI_VENDOR_ID_QLOGIC, 986462306a36Sopenharmony_ci .device = PCI_DEVICE_ID_QLOGIC_ISP4032, 986562306a36Sopenharmony_ci .subvendor = PCI_ANY_ID, 986662306a36Sopenharmony_ci .subdevice = PCI_ANY_ID, 986762306a36Sopenharmony_ci }, 986862306a36Sopenharmony_ci { 986962306a36Sopenharmony_ci .vendor = PCI_VENDOR_ID_QLOGIC, 987062306a36Sopenharmony_ci .device = PCI_DEVICE_ID_QLOGIC_ISP8022, 987162306a36Sopenharmony_ci .subvendor = PCI_ANY_ID, 987262306a36Sopenharmony_ci .subdevice = PCI_ANY_ID, 987362306a36Sopenharmony_ci }, 987462306a36Sopenharmony_ci { 987562306a36Sopenharmony_ci .vendor = PCI_VENDOR_ID_QLOGIC, 987662306a36Sopenharmony_ci .device = PCI_DEVICE_ID_QLOGIC_ISP8324, 987762306a36Sopenharmony_ci .subvendor = PCI_ANY_ID, 987862306a36Sopenharmony_ci .subdevice = PCI_ANY_ID, 987962306a36Sopenharmony_ci }, 988062306a36Sopenharmony_ci { 988162306a36Sopenharmony_ci .vendor = PCI_VENDOR_ID_QLOGIC, 988262306a36Sopenharmony_ci .device = PCI_DEVICE_ID_QLOGIC_ISP8042, 988362306a36Sopenharmony_ci .subvendor = PCI_ANY_ID, 988462306a36Sopenharmony_ci .subdevice = PCI_ANY_ID, 988562306a36Sopenharmony_ci }, 988662306a36Sopenharmony_ci {0, 0}, 988762306a36Sopenharmony_ci}; 988862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, qla4xxx_pci_tbl); 988962306a36Sopenharmony_ci 989062306a36Sopenharmony_cistatic struct pci_driver qla4xxx_pci_driver = { 989162306a36Sopenharmony_ci .name = DRIVER_NAME, 989262306a36Sopenharmony_ci .id_table = qla4xxx_pci_tbl, 989362306a36Sopenharmony_ci .probe = qla4xxx_probe_adapter, 989462306a36Sopenharmony_ci .remove = qla4xxx_remove_adapter, 989562306a36Sopenharmony_ci .err_handler = &qla4xxx_err_handler, 989662306a36Sopenharmony_ci}; 989762306a36Sopenharmony_ci 989862306a36Sopenharmony_cistatic int __init qla4xxx_module_init(void) 989962306a36Sopenharmony_ci{ 990062306a36Sopenharmony_ci int ret; 990162306a36Sopenharmony_ci 990262306a36Sopenharmony_ci if (ql4xqfulltracking) 990362306a36Sopenharmony_ci qla4xxx_driver_template.track_queue_depth = 1; 990462306a36Sopenharmony_ci 990562306a36Sopenharmony_ci /* Allocate cache for SRBs. */ 990662306a36Sopenharmony_ci srb_cachep = kmem_cache_create("qla4xxx_srbs", sizeof(struct srb), 0, 990762306a36Sopenharmony_ci SLAB_HWCACHE_ALIGN, NULL); 990862306a36Sopenharmony_ci if (srb_cachep == NULL) { 990962306a36Sopenharmony_ci printk(KERN_ERR 991062306a36Sopenharmony_ci "%s: Unable to allocate SRB cache..." 991162306a36Sopenharmony_ci "Failing load!\n", DRIVER_NAME); 991262306a36Sopenharmony_ci ret = -ENOMEM; 991362306a36Sopenharmony_ci goto no_srp_cache; 991462306a36Sopenharmony_ci } 991562306a36Sopenharmony_ci 991662306a36Sopenharmony_ci /* Derive version string. */ 991762306a36Sopenharmony_ci strcpy(qla4xxx_version_str, QLA4XXX_DRIVER_VERSION); 991862306a36Sopenharmony_ci if (ql4xextended_error_logging) 991962306a36Sopenharmony_ci strcat(qla4xxx_version_str, "-debug"); 992062306a36Sopenharmony_ci 992162306a36Sopenharmony_ci qla4xxx_scsi_transport = 992262306a36Sopenharmony_ci iscsi_register_transport(&qla4xxx_iscsi_transport); 992362306a36Sopenharmony_ci if (!qla4xxx_scsi_transport){ 992462306a36Sopenharmony_ci ret = -ENODEV; 992562306a36Sopenharmony_ci goto release_srb_cache; 992662306a36Sopenharmony_ci } 992762306a36Sopenharmony_ci 992862306a36Sopenharmony_ci ret = pci_register_driver(&qla4xxx_pci_driver); 992962306a36Sopenharmony_ci if (ret) 993062306a36Sopenharmony_ci goto unregister_transport; 993162306a36Sopenharmony_ci 993262306a36Sopenharmony_ci printk(KERN_INFO "QLogic iSCSI HBA Driver\n"); 993362306a36Sopenharmony_ci return 0; 993462306a36Sopenharmony_ci 993562306a36Sopenharmony_ciunregister_transport: 993662306a36Sopenharmony_ci iscsi_unregister_transport(&qla4xxx_iscsi_transport); 993762306a36Sopenharmony_cirelease_srb_cache: 993862306a36Sopenharmony_ci kmem_cache_destroy(srb_cachep); 993962306a36Sopenharmony_cino_srp_cache: 994062306a36Sopenharmony_ci return ret; 994162306a36Sopenharmony_ci} 994262306a36Sopenharmony_ci 994362306a36Sopenharmony_cistatic void __exit qla4xxx_module_exit(void) 994462306a36Sopenharmony_ci{ 994562306a36Sopenharmony_ci pci_unregister_driver(&qla4xxx_pci_driver); 994662306a36Sopenharmony_ci iscsi_unregister_transport(&qla4xxx_iscsi_transport); 994762306a36Sopenharmony_ci kmem_cache_destroy(srb_cachep); 994862306a36Sopenharmony_ci} 994962306a36Sopenharmony_ci 995062306a36Sopenharmony_cimodule_init(qla4xxx_module_init); 995162306a36Sopenharmony_cimodule_exit(qla4xxx_module_exit); 995262306a36Sopenharmony_ci 995362306a36Sopenharmony_ciMODULE_AUTHOR("QLogic Corporation"); 995462306a36Sopenharmony_ciMODULE_DESCRIPTION("QLogic iSCSI HBA Driver"); 995562306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 995662306a36Sopenharmony_ciMODULE_VERSION(QLA4XXX_DRIVER_VERSION); 9957