Commit b3a271a9 authored by Manish Rangankar's avatar Manish Rangankar Committed by James Bottomley

[SCSI] qla4xxx: support iscsiadm session mgmt

Add scsi_transport_iscsi hooks in qla4xxx to support
iSCSI session management using iscsiadm.

This patch is based on discussion here
http://groups.google.com/group/open-iscsi/browse_thread/thread/e89fd888baf656a0#

Now users can use iscsiadm to do target discovery and do login/logout to
individual targets using the qla4xxx iSCSI class interface.

This patch leaves some dead code, but to make it easier to review
we are leaving and in the next patch we will remove that old code.

V2 - NOTE: Added code to avoid waiting for AEN during login/logout
in the driver, instead added a kernel to user event
to notify iscsid about login status. Because of this
iscsid will not get blocked.
Signed-off-by: default avatarManish Rangankar <manish.rangankar@qlogic.com>
Signed-off-by: default avatarLalit Chandivade <lalit.chandivade@qlogic.com>
Signed-off-by: default avatarMike Christie <michaelc@cs.wisc.edu>
Signed-off-by: default avatarJames Bottomley <JBottomley@Parallels.com>
parent 17fa575e
......@@ -36,9 +36,12 @@
#include <scsi/scsi_transport_iscsi.h>
#include <scsi/scsi_bsg_iscsi.h>
#include <scsi/scsi_netlink.h>
#include <scsi/libiscsi.h>
#include "ql4_dbg.h"
#include "ql4_nx.h"
#include "ql4_fw.h"
#include "ql4_nvram.h"
#ifndef PCI_DEVICE_ID_QLOGIC_ISP4010
#define PCI_DEVICE_ID_QLOGIC_ISP4010 0x4010
......@@ -112,7 +115,7 @@
#define MAX_BUSES 1
#define MAX_TARGETS MAX_DEV_DB_ENTRIES
#define MAX_LUNS 0xffff
#define MAX_AEN_ENTRIES 256 /* should be > EXT_DEF_MAX_AEN_QUEUE */
#define MAX_AEN_ENTRIES MAX_DEV_DB_ENTRIES
#define MAX_DDB_ENTRIES MAX_DEV_DB_ENTRIES
#define MAX_PDU_ENTRIES 32
#define INVALID_ENTRY 0xFFFF
......@@ -296,8 +299,6 @@ struct ddb_entry {
#define DF_FO_MASKED 3
#include "ql4_fw.h"
#include "ql4_nvram.h"
struct ql82xx_hw_data {
/* Offsets for flash/nvram access (set to ~0 if not used). */
......@@ -607,6 +608,33 @@ struct scsi_qla_host {
#define QLFLASH_WAITING 0
#define QLFLASH_READING 1
#define QLFLASH_WRITING 2
struct dma_pool *chap_dma_pool;
#define CHAP_DMA_BLOCK_SIZE 512
struct workqueue_struct *task_wq;
unsigned long ddb_idx_map[MAX_DDB_ENTRIES / BITS_PER_LONG];
};
struct ql4_task_data {
struct scsi_qla_host *ha;
uint8_t iocb_req_cnt;
dma_addr_t data_dma;
void *req_buffer;
dma_addr_t req_dma;
void *resp_buffer;
dma_addr_t resp_dma;
uint32_t resp_len;
struct iscsi_task *task;
struct passthru_status sts;
struct work_struct task_work;
};
struct qla_endpoint {
struct Scsi_Host *host;
struct sockaddr dst_addr;
};
struct qla_conn {
struct qla_endpoint *qla_ep;
};
static inline int is_ipv4_enabled(struct scsi_qla_host *ha)
......@@ -657,7 +685,7 @@ static inline int adapter_up(struct scsi_qla_host *ha)
static inline struct scsi_qla_host* to_qla_host(struct Scsi_Host *shost)
{
return (struct scsi_qla_host *)shost->hostdata;
return (struct scsi_qla_host *)iscsi_host_priv(shost);
}
static inline void __iomem* isp_semaphore(struct scsi_qla_host *ha)
......
......@@ -331,9 +331,11 @@ struct qla_flt_region {
#define MBOX_CMD_WRITE_FLASH 0x0025
#define MBOX_CMD_READ_FLASH 0x0026
#define MBOX_CMD_CLEAR_DATABASE_ENTRY 0x0031
#define MBOX_CMD_CONN_OPEN 0x0074
#define MBOX_CMD_CONN_CLOSE_SESS_LOGOUT 0x0056
#define LOGOUT_OPTION_CLOSE_SESSION 0x01
#define LOGOUT_OPTION_RELOGIN 0x02
#define LOGOUT_OPTION_CLOSE_SESSION 0x0002
#define LOGOUT_OPTION_RELOGIN 0x0004
#define LOGOUT_OPTION_FREE_DDB 0x0008
#define MBOX_CMD_EXECUTE_IOCB_A64 0x005A
#define MBOX_CMD_INITIALIZE_FIRMWARE 0x0060
#define MBOX_CMD_GET_INIT_FW_CTRL_BLOCK 0x0061
......@@ -342,6 +344,7 @@ struct qla_flt_region {
#define MBOX_CMD_GET_DATABASE_ENTRY 0x0064
#define DDB_DS_UNASSIGNED 0x00
#define DDB_DS_NO_CONNECTION_ACTIVE 0x01
#define DDB_DS_DISCOVERY 0x02
#define DDB_DS_SESSION_ACTIVE 0x04
#define DDB_DS_SESSION_FAILED 0x06
#define DDB_DS_LOGIN_IN_PROCESS 0x07
......@@ -375,7 +378,10 @@ struct qla_flt_region {
#define FW_ADDSTATE_DHCPv4_LEASE_EXPIRED 0x0008
#define FW_ADDSTATE_LINK_UP 0x0010
#define FW_ADDSTATE_ISNS_SVC_ENABLED 0x0020
#define MBOX_CMD_GET_DATABASE_ENTRY_DEFAULTS 0x006B
#define IPV6_DEFAULT_DDB_ENTRY 0x0001
#define MBOX_CMD_CONN_OPEN_SESS_LOGIN 0x0074
#define MBOX_CMD_GET_CRASH_RECORD 0x0076 /* 4010 only */
#define MBOX_CMD_GET_CONN_EVENT_LOG 0x0077
......@@ -463,7 +469,8 @@ struct addr_ctrl_blk {
uint8_t res0; /* 07 */
uint16_t eth_mtu_size; /* 08-09 */
uint16_t add_fw_options; /* 0A-0B */
#define SERIALIZE_TASK_MGMT 0x0400
#define ADFWOPT_SERIALIZE_TASK_MGMT 0x0400
#define ADFWOPT_AUTOCONN_DISABLE 0x0002
uint8_t hb_interval; /* 0C */
uint8_t inst_num; /* 0D */
......@@ -655,11 +662,30 @@ struct addr_ctrl_blk_def {
/*************************************************************************/
#define MAX_CHAP_ENTRIES_40XX 128
#define MAX_CHAP_ENTRIES_82XX 1024
struct ql4_chap_table {
uint16_t link;
uint8_t flags;
uint8_t secret_len;
#define MIN_CHAP_SECRET_LEN 12
#define MAX_CHAP_SECRET_LEN 100
uint8_t secret[MAX_CHAP_SECRET_LEN];
#define MAX_CHAP_NAME_LEN 256
uint8_t name[MAX_CHAP_NAME_LEN];
uint16_t reserved;
#define CHAP_VALID_COOKIE 0x4092
#define CHAP_INVALID_COOKIE 0xFFEE
uint16_t cookie;
};
struct dev_db_entry {
uint16_t options; /* 00-01 */
#define DDB_OPT_DISC_SESSION 0x10
#define DDB_OPT_TARGET 0x02 /* device is a target */
#define DDB_OPT_IPV6_DEVICE 0x100
#define DDB_OPT_AUTO_SENDTGTS_DISABLE 0x40
#define DDB_OPT_IPV6_NULL_LINK_LOCAL 0x800 /* post connection */
#define DDB_OPT_IPV6_FW_DEFINED_LINK_LOCAL 0x800 /* pre connection */
......@@ -670,6 +696,7 @@ struct dev_db_entry {
uint16_t tcp_options; /* 0A-0B */
uint16_t ip_options; /* 0C-0D */
uint16_t iscsi_max_rcv_data_seg_len; /* 0E-0F */
#define BYTE_UNITS 512
uint32_t res1; /* 10-13 */
uint16_t iscsi_max_snd_data_seg_len; /* 14-15 */
uint16_t iscsi_first_burst_len; /* 16-17 */
......@@ -853,6 +880,7 @@ struct qla4_header {
uint8_t entryStatus;
uint8_t systemDefined;
#define SD_ISCSI_PDU 0x01
uint8_t entryCount;
/* SyetemDefined definition */
......@@ -1010,21 +1038,22 @@ struct passthru0 {
struct qla4_header hdr; /* 00-03 */
uint32_t handle; /* 04-07 */
uint16_t target; /* 08-09 */
uint16_t connectionID; /* 0A-0B */
uint16_t connection_id; /* 0A-0B */
#define ISNS_DEFAULT_SERVER_CONN_ID ((uint16_t)0x8000)
uint16_t controlFlags; /* 0C-0D */
uint16_t control_flags; /* 0C-0D */
#define PT_FLAG_ETHERNET_FRAME 0x8000
#define PT_FLAG_ISNS_PDU 0x8000
#define PT_FLAG_SEND_BUFFER 0x0200
#define PT_FLAG_WAIT_4_RESPONSE 0x0100
#define PT_FLAG_ISCSI_PDU 0x1000
uint16_t timeout; /* 0E-0F */
#define PT_DEFAULT_TIMEOUT 30 /* seconds */
struct data_seg_a64 outDataSeg64; /* 10-1B */
struct data_seg_a64 out_dsd; /* 10-1B */
uint32_t res1; /* 1C-1F */
struct data_seg_a64 inDataSeg64; /* 20-2B */
struct data_seg_a64 in_dsd; /* 20-2B */
uint8_t res2[20]; /* 2C-3F */
};
......@@ -1057,4 +1086,43 @@ struct response {
#define RESPONSE_PROCESSED 0xDEADDEAD /* Signature */
};
struct ql_iscsi_stats {
uint8_t reserved1[656]; /* 0000-028F */
uint32_t tx_cmd_pdu; /* 0290-0293 */
uint32_t tx_resp_pdu; /* 0294-0297 */
uint32_t rx_cmd_pdu; /* 0298-029B */
uint32_t rx_resp_pdu; /* 029C-029F */
uint64_t tx_data_octets; /* 02A0-02A7 */
uint64_t rx_data_octets; /* 02A8-02AF */
uint32_t hdr_digest_err; /* 02B0–02B3 */
uint32_t data_digest_err; /* 02B4–02B7 */
uint32_t conn_timeout_err; /* 02B8–02BB */
uint32_t framing_err; /* 02BC–02BF */
uint32_t tx_nopout_pdus; /* 02C0–02C3 */
uint32_t tx_scsi_cmd_pdus; /* 02C4–02C7 */
uint32_t tx_tmf_cmd_pdus; /* 02C8–02CB */
uint32_t tx_login_cmd_pdus; /* 02CC–02CF */
uint32_t tx_text_cmd_pdus; /* 02D0–02D3 */
uint32_t tx_scsi_write_pdus; /* 02D4–02D7 */
uint32_t tx_logout_cmd_pdus; /* 02D8–02DB */
uint32_t tx_snack_req_pdus; /* 02DC–02DF */
uint32_t rx_nopin_pdus; /* 02E0–02E3 */
uint32_t rx_scsi_resp_pdus; /* 02E4–02E7 */
uint32_t rx_tmf_resp_pdus; /* 02E8–02EB */
uint32_t rx_login_resp_pdus; /* 02EC–02EF */
uint32_t rx_text_resp_pdus; /* 02F0–02F3 */
uint32_t rx_scsi_read_pdus; /* 02F4–02F7 */
uint32_t rx_logout_resp_pdus; /* 02F8–02FB */
uint32_t rx_r2t_pdus; /* 02FC–02FF */
uint32_t rx_async_pdus; /* 0300–0303 */
uint32_t rx_reject_pdus; /* 0304–0307 */
uint8_t reserved2[264]; /* 0x0308 - 0x040F */
};
#endif /* _QLA4X_FW_H */
......@@ -51,7 +51,7 @@ int qla4xxx_get_fwddb_entry(struct scsi_qla_host *ha,
uint16_t *connection_id);
int qla4xxx_set_ddb_entry(struct scsi_qla_host * ha, uint16_t fw_ddb_index,
dma_addr_t fw_ddb_entry_dma);
dma_addr_t fw_ddb_entry_dma, uint32_t *mbx_sts);
uint8_t qla4xxx_get_ifcb(struct scsi_qla_host *ha, uint32_t *mbox_cmd,
uint32_t *mbox_sts, dma_addr_t init_fw_cb_dma);
int qla4xxx_conn_close_sess_logout(struct scsi_qla_host *ha,
......@@ -63,8 +63,7 @@ int qla4xxx_set_acb(struct scsi_qla_host *ha, uint32_t *mbox_cmd,
uint32_t *mbox_sts, dma_addr_t acb_dma);
int qla4xxx_get_acb(struct scsi_qla_host *ha, uint32_t *mbox_cmd,
uint32_t *mbox_sts, dma_addr_t acb_dma);
void qla4xxx_mark_device_missing(struct scsi_qla_host *ha,
struct ddb_entry *ddb_entry);
void qla4xxx_mark_device_missing(struct iscsi_cls_session *cls_session);
u16 rd_nvram_word(struct scsi_qla_host *ha, int offset);
void qla4xxx_get_crash_record(struct scsi_qla_host *ha);
struct ddb_entry *qla4xxx_alloc_sess(struct scsi_qla_host *ha);
......@@ -150,7 +149,21 @@ int qla4_8xxx_device_state_handler(struct scsi_qla_host *ha);
void qla4_8xxx_need_qsnt_handler(struct scsi_qla_host *ha);
void qla4_8xxx_clear_drv_active(struct scsi_qla_host *ha);
void qla4_8xxx_set_drv_active(struct scsi_qla_host *ha);
int qla4xxx_conn_open(struct scsi_qla_host *ha, uint16_t fw_ddb_index);
int qla4xxx_set_param_ddbentry(struct scsi_qla_host *ha,
struct ddb_entry *ddb_entry,
struct iscsi_cls_conn *cls_conn,
uint32_t *mbx_sts);
int qla4xxx_session_logout_ddb(struct scsi_qla_host *ha,
struct ddb_entry *ddb_entry, int options);
int qla4xxx_req_ddb_entry(struct scsi_qla_host *ha, uint32_t fw_ddb_index,
uint32_t *mbx_sts);
int qla4xxx_clear_ddb_entry(struct scsi_qla_host *ha, uint32_t fw_ddb_index);
int qla4xxx_send_passthru0(struct iscsi_task *task);
int qla4xxx_get_mgmt_data(struct scsi_qla_host *ha, uint16_t fw_ddb_index,
uint16_t stats_size, dma_addr_t stats_dma);
void qla4xxx_update_session_conn_param(struct scsi_qla_host *ha,
struct ddb_entry *ddb_entry);
/* BSG Functions */
int qla4xxx_bsg_request(struct bsg_job *bsg_job);
int qla4xxx_process_vendor_specific(struct bsg_job *bsg_job);
......
......@@ -48,22 +48,15 @@ static void ql4xxx_set_mac_number(struct scsi_qla_host *ha)
* @ha: pointer to host adapter structure.
* @ddb_entry: pointer to device database entry
*
* This routine deallocates and unlinks the specified ddb_entry from the
* adapter's
* This routine marks a DDB entry INVALID
**/
void qla4xxx_free_ddb(struct scsi_qla_host *ha,
struct ddb_entry *ddb_entry)
{
/* Remove device entry from list */
list_del_init(&ddb_entry->list);
/* Remove device pointer from index mapping arrays */
ha->fw_ddb_index_map[ddb_entry->fw_ddb_index] =
(struct ddb_entry *) INVALID_ENTRY;
ha->tot_ddbs--;
/* Free memory and scsi-ml struct for device entry */
qla4xxx_destroy_sess(ddb_entry);
}
/**
......@@ -820,7 +813,8 @@ static int qla4xxx_build_ddb_list(struct scsi_qla_host *ha)
((!ipv6_device &&
*((uint32_t *)fw_ddb_entry->ip_addr))
|| ipv6_device)) {
qla4xxx_set_ddb_entry(ha, fw_ddb_index, 0);
qla4xxx_set_ddb_entry(ha, fw_ddb_index, 0,
NULL);
if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index,
NULL, 0, NULL,
&next_fw_ddb_index,
......@@ -927,7 +921,7 @@ int qla4xxx_reinitialize_ddb_list(struct scsi_qla_host *ha)
ddb_entry->fw_ddb_index));
iscsi_unblock_session(ddb_entry->sess);
} else if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE)
qla4xxx_mark_device_missing(ha, ddb_entry);
qla4xxx_mark_device_missing(ddb_entry->sess);
}
return status;
}
......@@ -952,7 +946,7 @@ int qla4xxx_relogin_device(struct scsi_qla_host *ha,
DEBUG2(printk("scsi%ld: Relogin ddb [%d]. TOV=%d\n", ha->host_no,
ddb_entry->fw_ddb_index, relogin_timer));
qla4xxx_set_ddb_entry(ha, ddb_entry->fw_ddb_index, 0);
qla4xxx_set_ddb_entry(ha, ddb_entry->fw_ddb_index, 0, NULL);
return QLA_SUCCESS;
}
......@@ -1418,88 +1412,66 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, uint32_t fw_ddb_index,
uint32_t state, uint32_t conn_err)
{
struct ddb_entry * ddb_entry;
uint32_t old_fw_ddb_device_state;
int status = QLA_ERROR;
/* check for out of range index */
if (fw_ddb_index >= MAX_DDB_ENTRIES)
return QLA_ERROR;
goto exit_ddb_event;
/* Get the corresponging ddb entry */
ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, fw_ddb_index);
/* Device does not currently exist in our database. */
if (ddb_entry == NULL) {
if (state == DDB_DS_SESSION_ACTIVE)
qla4xxx_add_device_dynamically(ha, fw_ddb_index);
return QLA_SUCCESS;
ql4_printk(KERN_ERR, ha, "%s: No ddb_entry at FW index [%d]\n",
__func__, fw_ddb_index);
goto exit_ddb_event;
}
/* Device already exists in our database. */
DEBUG2(printk("scsi%ld: %s DDB - old state= 0x%x, new state=0x%x for "
"index [%d]\n", ha->host_no, __func__,
old_fw_ddb_device_state = ddb_entry->fw_ddb_device_state;
DEBUG2(ql4_printk(KERN_INFO, ha,
"%s: DDB - old state = 0x%x, new state = 0x%x for "
"index [%d]\n", __func__,
ddb_entry->fw_ddb_device_state, state, fw_ddb_index));
ddb_entry->fw_ddb_device_state = state;
/* Device is back online. */
if ((ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) &&
(atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE)) {
atomic_set(&ddb_entry->state, DDB_STATE_ONLINE);
atomic_set(&ddb_entry->relogin_retry_count, 0);
atomic_set(&ddb_entry->relogin_timer, 0);
clear_bit(DF_RELOGIN, &ddb_entry->flags);
iscsi_unblock_session(ddb_entry->sess);
iscsi_session_event(ddb_entry->sess,
ISCSI_KEVENT_CREATE_SESSION);
/*
* Change the lun state to READY in case the lun TIMEOUT before
* the device came back.
*/
} else if (ddb_entry->fw_ddb_device_state != DDB_DS_SESSION_ACTIVE) {
/* Device went away, mark device missing */
if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE) {
DEBUG2(ql4_printk(KERN_INFO, ha, "%s mark missing "
"ddb_entry 0x%p sess 0x%p conn 0x%p\n",
__func__, ddb_entry,
ddb_entry->sess, ddb_entry->conn));
qla4xxx_mark_device_missing(ha, ddb_entry);
}
switch (old_fw_ddb_device_state) {
case DDB_DS_LOGIN_IN_PROCESS:
switch (state) {
case DDB_DS_SESSION_ACTIVE:
case DDB_DS_DISCOVERY:
iscsi_conn_login_event(ddb_entry->conn,
ISCSI_CONN_STATE_LOGGED_IN);
qla4xxx_update_session_conn_param(ha, ddb_entry);
status = QLA_SUCCESS;
break;
case DDB_DS_SESSION_FAILED:
case DDB_DS_NO_CONNECTION_ACTIVE:
iscsi_conn_login_event(ddb_entry->conn,
ISCSI_CONN_STATE_FREE);
status = QLA_SUCCESS;
break;
}
break;
case DDB_DS_SESSION_ACTIVE:
if (state == DDB_DS_SESSION_FAILED) {
/*
* Relogin if device state changed to a not active state.
* However, do not relogin if a RELOGIN is in process, or
* we are not allowed to relogin to this DDB.
*/
if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_FAILED &&
!test_bit(DF_RELOGIN, &ddb_entry->flags) &&
qla4_is_relogin_allowed(ha, conn_err)) {
/*
* This triggers a relogin. After the relogin_timer
* expires, the relogin gets scheduled. We must wait a
* minimum amount of time since receiving an 0x8014 AEN
* with failed device_state or a logout response before
* we can issue another relogin.
* iscsi_session failure will cause userspace to
* stop the connection which in turn would block the
* iscsi_session and start relogin
*/
/* Firmware pads this timeout: (time2wait +1).
* Driver retry to login should be longer than F/W.
* Otherwise F/W will fail
* set_ddb() mbx cmd with 0x4005 since it still
* counting down its time2wait.
*/
atomic_set(&ddb_entry->relogin_timer, 0);
atomic_set(&ddb_entry->retry_relogin_timer,
ddb_entry->default_time2wait + 4);
DEBUG(printk("scsi%ld: %s: ddb[%d] "
"initiate relogin after %d seconds\n",
ha->host_no, __func__,
ddb_entry->fw_ddb_index,
ddb_entry->default_time2wait + 4));
} else {
DEBUG(printk("scsi%ld: %s: ddb[%d] "
"relogin not initiated, state = %d, "
"ddb_entry->flags = 0x%lx\n",
ha->host_no, __func__,
ddb_entry->fw_ddb_index,
ddb_entry->fw_ddb_device_state,
ddb_entry->flags));
iscsi_session_failure(ddb_entry->sess->dd_data,
ISCSI_ERR_CONN_FAILED);
status = QLA_SUCCESS;
}
break;
default:
DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Unknown Event\n",
__func__));
break;
}
return QLA_SUCCESS;
exit_ddb_event:
return status;
}
......@@ -381,3 +381,69 @@ int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb)
return QLA_ERROR;
}
int qla4xxx_send_passthru0(struct iscsi_task *task)
{
struct passthru0 *passthru_iocb;
struct iscsi_session *sess = task->conn->session;
struct ddb_entry *ddb_entry = sess->dd_data;
struct scsi_qla_host *ha = ddb_entry->ha;
struct ql4_task_data *task_data = task->dd_data;
uint16_t ctrl_flags = 0;
unsigned long flags;
int ret = QLA_ERROR;
spin_lock_irqsave(&ha->hardware_lock, flags);
task_data->iocb_req_cnt = 1;
/* Put the IOCB on the request queue */
if (!qla4xxx_space_in_req_ring(ha, task_data->iocb_req_cnt))
goto queuing_error;
passthru_iocb = (struct passthru0 *) ha->request_ptr;
memset(passthru_iocb, 0, sizeof(struct passthru0));
passthru_iocb->hdr.entryType = ET_PASSTHRU0;
passthru_iocb->hdr.systemDefined = SD_ISCSI_PDU;
passthru_iocb->hdr.entryCount = task_data->iocb_req_cnt;
passthru_iocb->handle = task->itt;
passthru_iocb->target = cpu_to_le16(ddb_entry->fw_ddb_index);
passthru_iocb->timeout = cpu_to_le16(PT_DEFAULT_TIMEOUT);
/* Setup the out & in DSDs */
if (task->data_count) {
memcpy((uint8_t *)task_data->req_buffer +
sizeof(struct iscsi_hdr), task->data, task->data_count);
ctrl_flags |= PT_FLAG_SEND_BUFFER;
passthru_iocb->out_dsd.base.addrLow =
cpu_to_le32(LSDW(task_data->req_dma));
passthru_iocb->out_dsd.base.addrHigh =
cpu_to_le32(MSDW(task_data->req_dma));
passthru_iocb->out_dsd.count =
cpu_to_le32(task->data_count +
sizeof(struct iscsi_hdr));
}
if (task_data->resp_len) {
passthru_iocb->in_dsd.base.addrLow =
cpu_to_le32(LSDW(task_data->resp_dma));
passthru_iocb->in_dsd.base.addrHigh =
cpu_to_le32(MSDW(task_data->resp_dma));
passthru_iocb->in_dsd.count =
cpu_to_le32(task_data->resp_len);
}
ctrl_flags |= (PT_FLAG_ISCSI_PDU | PT_FLAG_WAIT_4_RESPONSE);
passthru_iocb->control_flags = cpu_to_le16(ctrl_flags);
/* Update the request pointer */
qla4xxx_advance_req_ring_ptr(ha);
wmb();
/* Track IOCB used */
ha->iocb_cnt += task_data->iocb_req_cnt;
ha->req_q_count -= task_data->iocb_req_cnt;
ha->isp_ops->queue_iocb(ha);
ret = QLA_SUCCESS;
queuing_error:
spin_unlock_irqrestore(&ha->hardware_lock, flags);
return ret;
}
......@@ -224,8 +224,8 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,
* I/O to this device. We should get a ddb state change
* AEN soon.
*/
if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE)
qla4xxx_mark_device_missing(ha, ddb_entry);
if (iscsi_is_session_online(ddb_entry->sess))
qla4xxx_mark_device_missing(ddb_entry->sess);
break;
case SCS_DATA_UNDERRUN:
......@@ -306,8 +306,8 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,
* send I/O to this device. We should get a ddb
* state change AEN soon.
*/
if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE)
qla4xxx_mark_device_missing(ha, ddb_entry);
if (iscsi_is_session_online(ddb_entry->sess))
qla4xxx_mark_device_missing(ddb_entry->sess);
cmd->result = DID_TRANSPORT_DISRUPTED << 16;
break;
......@@ -340,6 +340,51 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,
kref_put(&srb->srb_ref, qla4xxx_srb_compl);
}
/**
* qla4xxx_passthru_status_entry - processes passthru status IOCBs (0x3C)
* @ha: Pointer to host adapter structure.
* @sts_entry: Pointer to status entry structure.
**/
static void qla4xxx_passthru_status_entry(struct scsi_qla_host *ha,
struct passthru_status *sts_entry)
{
struct iscsi_task *task;
struct ddb_entry *ddb_entry;
struct ql4_task_data *task_data;
struct iscsi_cls_conn *cls_conn;
struct iscsi_conn *conn;
itt_t itt;
uint32_t fw_ddb_index;
itt = sts_entry->handle;
fw_ddb_index = le32_to_cpu(sts_entry->target);
ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, fw_ddb_index);
if (ddb_entry == NULL) {
ql4_printk(KERN_ERR, ha, "%s: Invalid target index = 0x%x\n",
__func__, sts_entry->target);
return;
}
cls_conn = ddb_entry->conn;
conn = cls_conn->dd_data;
spin_lock(&conn->session->lock);
task = iscsi_itt_to_task(conn, itt);
spin_unlock(&conn->session->lock);
if (task == NULL) {
ql4_printk(KERN_ERR, ha, "%s: Task is NULL\n", __func__);
return;
}
task_data = task->dd_data;
memcpy(&task_data->sts, sts_entry, sizeof(struct passthru_status));
ha->req_q_count += task_data->iocb_req_cnt;
ha->iocb_cnt -= task_data->iocb_req_cnt;
queue_work(ha->task_wq, &task_data->task_work);
}
/**
* qla4xxx_process_response_queue - process response queue completions
* @ha: Pointer to host adapter structure.
......@@ -375,6 +420,14 @@ void qla4xxx_process_response_queue(struct scsi_qla_host *ha)
break;
case ET_PASSTHRU_STATUS:
if (sts_entry->hdr.systemDefined == SD_ISCSI_PDU)
qla4xxx_passthru_status_entry(ha,
(struct passthru_status *)sts_entry);
else
ql4_printk(KERN_ERR, ha,
"%s: Invalid status received\n",
__func__);
break;
case ET_STATUS_CONTINUATION:
......@@ -1009,24 +1062,24 @@ void qla4xxx_process_aen(struct scsi_qla_host * ha, uint8_t process_aen)
switch (mbox_sts[0]) {
case MBOX_ASTS_DATABASE_CHANGED:
if (process_aen == FLUSH_DDB_CHANGED_AENS) {
switch (process_aen) {
case FLUSH_DDB_CHANGED_AENS:
DEBUG2(printk("scsi%ld: AEN[%d] %04x, index "
"[%d] state=%04x FLUSHED!\n",
ha->host_no, ha->aen_out,
mbox_sts[0], mbox_sts[2],
mbox_sts[3]));
break;
}
case PROCESS_ALL_AENS:
default:
if (mbox_sts[1] == 0) { /* Global DB change. */
qla4xxx_reinitialize_ddb_list(ha);
} else if (mbox_sts[1] == 1) { /* Specific device. */
qla4xxx_process_ddb_changed(ha, mbox_sts[2],
mbox_sts[3], mbox_sts[4]);
}
/* Specific device. */
if (mbox_sts[1] == 1)
qla4xxx_process_ddb_changed(ha,
mbox_sts[2], mbox_sts[3],
mbox_sts[4]);
break;
}
}
spin_lock_irqsave(&ha->hardware_lock, flags);
}
spin_unlock_irqrestore(&ha->hardware_lock, flags);
......
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment