#include <scsi/scsi_tcq.h>
#include <scsi/scsicam.h>
-#include <scsi/iscsi_proto.h>
-#include <scsi/scsi_eh.h>
#include "ql4_def.h"
#include "ql4_version.h"
/*
* Driver version
*/
-char qla4xxx_version_str[40];
-EXPORT_SYMBOL_GPL(qla4xxx_version_str);
-
-/*
- * List of host adapters
- */
-struct klist qla4xxx_hostlist;
-
-struct klist *qla4xxx_hostlist_ptr = &qla4xxx_hostlist;
-EXPORT_SYMBOL_GPL(qla4xxx_hostlist_ptr);
-
-static atomic_t qla4xxx_hba_count;
+static char qla4xxx_version_str[40];
/*
* SRB allocation cache
.slave_configure = qla4xxx_slave_configure,
.slave_alloc = qla4xxx_slave_alloc,
.slave_destroy = qla4xxx_slave_destroy,
- .target_destroy = NULL,
.scan_finished = iscsi_scan_finished,
.scan_start = qla4xxx_scan_start,
if (!ddb_entry->sess)
return;
- if (ddb_entry->conn)
+ if (ddb_entry->conn) {
+ atomic_set(&ddb_entry->state, DDB_STATE_DEAD);
iscsi_remove_session(ddb_entry->sess);
+ }
iscsi_free_session(ddb_entry->sess);
}
ddb_entry->fw_ddb_index));
iscsi_block_session(ddb_entry->sess);
iscsi_conn_error_event(ddb_entry->conn, ISCSI_ERR_CONN_FAILED);
- set_bit(DF_NO_RELOGIN, &ddb_entry->flags);
}
-/***
- * qla4xxx_get_new_srb - Allocate memory for a local srb.
- * @ha: Pointer to host adapter structure.
- * @ddb_entry: Pointer to device database entry
- * @cmd: Pointer to Linux's SCSI command structure
- * @done: Pointer to Linux's SCSI mid-layer done function
- *
- * NOTE: Sets te ref_count for non-NULL srb to one,
- * and initializes some fields.
- **/
static struct srb* qla4xxx_get_new_srb(struct scsi_qla_host *ha,
struct ddb_entry *ddb_entry,
struct scsi_cmnd *cmd,
if (!srb)
return srb;
- atomic_set(&srb->ref_count, 1);
+ kref_init(&srb->srb_ref);
srb->ha = ha;
srb->ddb = ddb_entry;
srb->cmd = cmd;
srb->flags = 0;
- cmd->SCp.ptr = (void *)srb;
+ CMD_SP(cmd) = (void *)srb;
cmd->scsi_done = done;
return srb;
scsi_dma_unmap(cmd);
srb->flags &= ~SRB_DMA_VALID;
}
- cmd->SCp.ptr = NULL;
+ CMD_SP(cmd) = NULL;
}
-void qla4xxx_srb_compl(struct scsi_qla_host *ha, struct srb *srb)
+void qla4xxx_srb_compl(struct kref *ref)
{
+ struct srb *srb = container_of(ref, struct srb, srb_ref);
struct scsi_cmnd *cmd = srb->cmd;
+ struct scsi_qla_host *ha = srb->ha;
qla4xxx_srb_free_dma(ha, srb);
}
/**
- * sp_put - Decrement reference count and call callback.
- * @ha: Pointer to host adapter structure.
- * @sp: Pointer to srb structure
- **/
-void sp_put(struct scsi_qla_host *ha, struct srb *sp)
-{
- if (atomic_read(&sp->ref_count) == 0) {
- DEBUG2(printk("%s: SP->ref_count ZERO\n", __func__));
- DEBUG2(BUG());
- return;
- }
- if (!atomic_dec_and_test(&sp->ref_count)) {
- return;
- }
- qla4xxx_srb_compl(ha, sp);
-}
-
-/**
- * sp_get - Increment reference count of the specified sp.
- * @sp: Pointer to srb structure
- **/
-void sp_get(struct srb *sp)
-{
- atomic_inc(&sp->ref_count);
-}
-
-/**
* qla4xxx_queuecommand - scsi layer issues scsi command to driver.
* @cmd: Pointer to Linux's SCSI command structure
* @done_fn: Function that the driver calls to notify the SCSI mid-layer
}
if (atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE) {
- if ((atomic_read(&ddb_entry->state) == DDB_STATE_DEAD)) {
+ if (atomic_read(&ddb_entry->state) == DDB_STATE_DEAD) {
cmd->result = DID_NO_CONNECT << 16;
goto qc_fail_command;
}
**/
static void qla4xxx_mem_free(struct scsi_qla_host *ha)
{
- struct list_head *ptr;
- struct async_msg_pdu_iocb *apdu_iocb;
-
if (ha->queues)
dma_free_coherent(&ha->pdev->dev, ha->queues_len, ha->queues,
ha->queues_dma);
- if (ha->gen_req_rsp_iocb)
- dma_free_coherent(&ha->pdev->dev, PAGE_SIZE,
- ha->gen_req_rsp_iocb, ha->gen_req_rsp_iocb_dma);
-
- while (!list_empty(&ha->async_iocb_list)) {
- ptr = ha->async_iocb_list.next;
- apdu_iocb = list_entry(ptr, struct async_msg_pdu_iocb, list);
- list_del_init(&apdu_iocb->list);
- kfree(apdu_iocb);
- }
-
ha->queues_len = 0;
ha->queues = NULL;
ha->queues_dma = 0;
goto mem_alloc_error_exit;
}
- ha->gen_req_rsp_iocb = dma_alloc_coherent(&ha->pdev->dev, PAGE_SIZE,
- &ha->gen_req_rsp_iocb_dma, GFP_KERNEL);
- if (ha->gen_req_rsp_iocb == NULL) {
- dev_warn(&ha->pdev->dev,
- "Memory Allocation failed - gen_req_rsp_iocb.\n");
-
- goto mem_alloc_error_exit;
- }
-
return QLA_SUCCESS;
mem_alloc_error_exit:
/* Search for relogin's to time-out and port down retry. */
list_for_each_entry_safe(ddb_entry, dtemp, &ha->ddb_list, list) {
- /* First check to see if the device has exhausted the
- * port down retry count */
- if (atomic_read(&ddb_entry->state) == DDB_STATE_MISSING) {
- if (atomic_read(&ddb_entry->port_down_timer) == 0)
- continue;
-
- if (atomic_dec_and_test(&ddb_entry->port_down_timer)) {
- DEBUG2(printk("scsi%ld: %s: index [%d] "
- "port down retry count of (%d) secs "
- "exhausted.\n",
- ha->host_no, __func__,
- ddb_entry->fw_ddb_index,
- ha->port_down_retry_count);)
-
- atomic_set(&ddb_entry->state, DDB_STATE_DEAD);
- start_dpc++;
- }
- }
/* Count down time between sending relogins */
if (adapter_up(ha) &&
!test_bit(DF_RELOGIN, &ddb_entry->flags) &&
if (atomic_read(&ddb_entry->state) !=
DDB_STATE_ONLINE &&
ddb_entry->fw_ddb_device_state ==
- DDB_DS_SESSION_FAILED &&
- !test_bit(DF_NO_RELOGIN, &ddb_entry->flags)) {
+ DDB_DS_SESSION_FAILED) {
/* Reset retry relogin timer */
atomic_inc(&ddb_entry->relogin_retry_count);
DEBUG2(printk("scsi%ld: index[%d] relogin"
test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags) ||
test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) ||
test_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags) ||
- test_bit(DPC_REMOVE_DEVICE, &ha->dpc_flags) ||
test_bit(DPC_LINK_CHANGED, &ha->dpc_flags) ||
- test_bit(DPC_ASYNC_MSG_PDU, &ha->dpc_flags) ||
test_bit(DPC_AEN, &ha->dpc_flags)) &&
ha->dpc_thread) {
DEBUG2(printk("scsi%ld: %s: scheduling dpc routine"
uint32_t index = 0;
int stat = QLA_SUCCESS;
unsigned long flags;
+ struct scsi_cmnd *cmd;
int wait_cnt = WAIT_CMD_TOV; /*
* Initialized for 30 seconds as we
* expect all commands to retuned
while (wait_cnt) {
spin_lock_irqsave(&ha->hardware_lock, flags);
/* Find a command that hasn't completed. */
- for (index = 1; index < MAX_SRBS; index++) {
- if (ha->active_srb_array[index] != NULL)
+ for (index = 0; index < ha->host->can_queue; index++) {
+ cmd = scsi_host_find_tag(ha->host, index);
+ if (cmd != NULL)
break;
}
spin_unlock_irqrestore(&ha->hardware_lock, flags);
unsigned long flags;
spin_lock_irqsave(&ha->hardware_lock, flags);
- for (i = 1; i < MAX_SRBS; i++) {
- if ((srb = ha->active_srb_array[i]) != NULL) {
- qla4xxx_del_from_active_array(ha, i);
+ for (i = 0; i < ha->host->can_queue; i++) {
+ srb = qla4xxx_del_from_active_array(ha, i);
+ if (srb != NULL) {
srb->cmd->result = DID_RESET << 16;
- sp_put(ha, srb);
+ kref_put(&srb->srb_ref, qla4xxx_srb_compl);
}
}
spin_unlock_irqrestore(&ha->hardware_lock, flags);
-
}
/**
return status;
}
-/*
- * qla4xxx_async_iocbs - processes ASYNC PDU IOCBS, if they are greater in
- * length than 48 bytes (i.e., more than just the iscsi header). Used for
- * unsolicited pdus received from target.
- */
-static void qla4xxx_async_iocbs(struct scsi_qla_host *ha,
- struct async_msg_pdu_iocb *amsg_pdu_iocb)
-{
- struct iscsi_hdr *hdr;
- struct async_pdu_iocb *apdu;
- uint32_t len;
- void *buf_addr;
- dma_addr_t buf_addr_dma;
- uint32_t offset;
- struct passthru0 *pthru0_iocb;
- struct ddb_entry *ddb_entry = NULL;
- ASYNC_PDU_SENSE *pdu_sense;
-
- uint8_t using_prealloc = 1;
- uint8_t async_event_type;
-
- apdu = (struct async_pdu_iocb *)amsg_pdu_iocb->iocb;
- hdr = (struct iscsi_hdr *)apdu->iscsi_pdu_hdr;
- len = hdr->hlength + hdr->dlength[2] +
- (hdr->dlength[1]<<8) + (hdr->dlength[0]<<16);
-
- offset = sizeof(struct passthru0) + sizeof(struct passthru_status);
- if (len <= (PAGE_SIZE - offset)) {
- buf_addr_dma = ha->gen_req_rsp_iocb_dma + offset;
- buf_addr = (uint8_t *)ha->gen_req_rsp_iocb + offset;
- } else {
- using_prealloc = 0;
- buf_addr = dma_alloc_coherent(&ha->pdev->dev, len,
- &buf_addr_dma, GFP_KERNEL);
- if (!buf_addr) {
- dev_info(&ha->pdev->dev,
- "%s: dma_alloc_coherent failed\n", __func__);
- return;
- }
- }
- /* Create the pass-thru0 iocb */
- pthru0_iocb = ha->gen_req_rsp_iocb;
- memset(pthru0_iocb, 0, offset);
- pthru0_iocb->hdr.entryType = ET_PASSTHRU0;
- pthru0_iocb->hdr.entryCount = 1;
- pthru0_iocb->target = cpu_to_le16(apdu->target_id);
- pthru0_iocb->controlFlags =
- cpu_to_le16(PT_FLAG_ISCSI_PDU | PT_FLAG_WAIT_4_RESPONSE);
- pthru0_iocb->timeout = cpu_to_le16(PT_DEFAULT_TIMEOUT);
- pthru0_iocb->inDataSeg64.base.addrHigh =
- cpu_to_le32(MSDW(buf_addr_dma));
- pthru0_iocb->inDataSeg64.base.addrLow =
- cpu_to_le32(LSDW(buf_addr_dma));
- pthru0_iocb->inDataSeg64.count = cpu_to_le32(len);
- pthru0_iocb->async_pdu_handle = cpu_to_le32(apdu->async_pdu_handle);
-
- dev_info(&ha->pdev->dev,
- "%s: qla4xxx_issue_iocb\n", __func__);
-
- if (qla4xxx_issue_iocb(ha, sizeof(struct passthru0),
- ha->gen_req_rsp_iocb_dma) != QLA_SUCCESS) {
- dev_info(&ha->pdev->dev,
- "%s: qla4xxx_issue_iocb failed\n", __func__);
- goto exit_async_pdu_iocb;
- }
-
- async_event_type = ((struct iscsi_async *)hdr)->async_event;
- pdu_sense = (ASYNC_PDU_SENSE *)buf_addr;
-
- switch (async_event_type) {
- case ISCSI_ASYNC_MSG_SCSI_EVENT:
- dev_info(&ha->pdev->dev,
- "%s: async msg event 0x%x processed\n"
- , __func__, async_event_type);
-
- qla4xxx_dump_buffer(buf_addr, len);
-
- if (pdu_sense->sense_data[12] == 0x3F) {
- if (pdu_sense->sense_data[13] == 0x0E) {
- /* reported luns data has changed */
- uint16_t fw_index = apdu->target_id;
-
- ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, fw_index);
- if (ddb_entry == NULL) {
- dev_info(&ha->pdev->dev,
- "%s: No DDB entry for index [%d]\n"
- , __func__, fw_index);
- goto exit_async_pdu_iocb;
- }
- if (ddb_entry->fw_ddb_device_state != DDB_DS_SESSION_ACTIVE) {
- dev_info(&ha->pdev->dev,
- "scsi%ld: %s: No Active Session for index [%d]\n",
- ha->host_no, __func__, fw_index);
- goto exit_async_pdu_iocb;
- }
-
- /* report new lun to kernel */
- scsi_scan_target(&ddb_entry->sess->dev, 0,
- ddb_entry->sess->target_id,
- SCAN_WILD_CARD, 0);
- }
- }
-
- break;
- case ISCSI_ASYNC_MSG_REQUEST_LOGOUT:
- case ISCSI_ASYNC_MSG_DROPPING_CONNECTION:
- case ISCSI_ASYNC_MSG_DROPPING_ALL_CONNECTIONS:
- case ISCSI_ASYNC_MSG_PARAM_NEGOTIATION:
- dev_info(&ha->pdev->dev,
- "%s: async msg event 0x%x processed\n"
- , __func__, async_event_type);
- qla4xxx_conn_close_sess_logout(ha, apdu->target_id, 0, 0);
- break;
- default:
- dev_info(&ha->pdev->dev,
- "%s: async msg event 0x%x not processed\n",
- __func__, async_event_type);
- break;
- };
-
- exit_async_pdu_iocb:
- if (!using_prealloc)
- dma_free_coherent(&ha->pdev->dev, len,
- buf_addr, buf_addr_dma);
-
- return;
-}
-
/**
* qla4xxx_do_dpc - dpc routine
* @data: in our case pointer to adapter structure
struct scsi_qla_host *ha =
container_of(work, struct scsi_qla_host, dpc_work);
struct ddb_entry *ddb_entry, *dtemp;
- struct async_msg_pdu_iocb *apdu_iocb, *apdu_iocb_tmp;
int status = QLA_ERROR;
DEBUG2(printk("scsi%ld: %s: DPC handler waking up."
if (test_and_clear_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags))
qla4xxx_get_dhcp_ip_address(ha);
- qla4xxx_remove_device(ha);
+ /* ---- link change? --- */
+ if (test_and_clear_bit(DPC_LINK_CHANGED, &ha->dpc_flags)) {
+ if (!test_bit(AF_LINK_UP, &ha->flags)) {
+ /* ---- link down? --- */
+ list_for_each_entry_safe(ddb_entry, dtemp,
+ &ha->ddb_list, list) {
+ if (atomic_read(&ddb_entry->state) ==
+ DDB_STATE_ONLINE)
+ qla4xxx_mark_device_missing(ha,
+ ddb_entry);
+ }
+ } else {
+ /* ---- link up? --- *
+ * F/W will auto login to all devices ONLY ONCE after
+ * link up during driver initialization and runtime
+ * fatal error recovery. Therefore, the driver must
+ * manually relogin to devices when recovering from
+ * connection failures, logouts, expired KATO, etc. */
+
+ list_for_each_entry_safe(ddb_entry, dtemp,
+ &ha->ddb_list, list) {
+ if ((atomic_read(&ddb_entry->state) ==
+ DDB_STATE_MISSING) ||
+ (atomic_read(&ddb_entry->state) ==
+ DDB_STATE_DEAD)) {
+ if (ddb_entry->fw_ddb_device_state ==
+ DDB_DS_SESSION_ACTIVE) {
+ atomic_set(&ddb_entry->state,
+ DDB_STATE_ONLINE);
+ dev_info(&ha->pdev->dev,
+ "scsi%ld: %s: ddb[%d]"
+ " os[%d] marked"
+ " ONLINE\n",
+ ha->host_no, __func__,
+ ddb_entry->fw_ddb_index,
+ ddb_entry->os_target_id);
+
+ iscsi_unblock_session(
+ ddb_entry->sess);
+ } else
+ qla4xxx_relogin_device(
+ ha, ddb_entry);
+ }
+
+ }
+ }
+ }
/* ---- relogin device? --- */
if (adapter_up(ha) &&
test_and_clear_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags)) {
list_for_each_entry_safe(ddb_entry, dtemp,
&ha->ddb_list, list) {
- if ((test_and_clear_bit(DF_RELOGIN, &ddb_entry->flags)) &&
- (!test_bit(DF_NO_RELOGIN, &ddb_entry->flags)) &&
- (atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE))
+ if (test_and_clear_bit(DF_RELOGIN, &ddb_entry->flags) &&
+ atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE)
qla4xxx_relogin_device(ha, ddb_entry);
/*
}
}
}
-
- if (test_and_clear_bit(DPC_LINK_CHANGED, &ha->dpc_flags)) {
- if (!test_bit(AF_LINK_UP, &ha->flags)) {
- /* ---- link down? --- */
- list_for_each_entry_safe(ddb_entry, dtemp, &ha->ddb_list, list) {
- if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE)
- qla4xxx_mark_device_missing(ha, ddb_entry);
- }
- }
- }
-
- /* Check for ASYNC PDU IOCBs */
- if (adapter_up(ha) &&
- test_bit(DPC_ASYNC_MSG_PDU, &ha->dpc_flags)) {
-
- list_for_each_entry_safe(apdu_iocb, apdu_iocb_tmp,
- &ha->async_iocb_list, list) {
- qla4xxx_async_iocbs(ha, apdu_iocb);
- list_del_init(&apdu_iocb->list);
- kfree(apdu_iocb);
- }
- clear_bit(DPC_ASYNC_MSG_PDU, &ha->dpc_flags);
- }
}
/**
/* Initialize lists and spinlocks. */
INIT_LIST_HEAD(&ha->ddb_list);
INIT_LIST_HEAD(&ha->free_srb_q);
- INIT_LIST_HEAD(&ha->async_iocb_list);
mutex_init(&ha->mbox_sem);
/* Start timer thread. */
qla4xxx_start_timer(ha, qla4xxx_timer, 1);
+ set_bit(AF_INIT_DONE, &ha->flags);
+
pci_set_drvdata(pdev, ha);
ret = scsi_add_host(host, &pdev->dev);
qla4xxx_version_str, ha->pdev->device, pci_name(ha->pdev),
ha->host_no, ha->firmware_version[0], ha->firmware_version[1],
ha->patch_number, ha->build_number);
-
scsi_scan_host(host);
-
- /* Insert new entry into the list of adapters. */
- klist_add_tail(&ha->node, &qla4xxx_hostlist);
- ha->instance = atomic_inc_return(&qla4xxx_hba_count) - 1;
-
- if (qla4xxx_ioctl_init(ha)) {
- dev_info(&ha->pdev->dev, "ioctl init failed\n");
- goto remove_host;
- }
-
- set_bit(AF_INIT_DONE, &ha->flags);
- dev_info(&ha->pdev->dev, "%s: AF_INIT_DONE\n", __func__);
-
return 0;
-remove_host:
- qla4xxx_free_ddb_list(ha);
- scsi_remove_host(host);
-
probe_failed:
qla4xxx_free_adapter(ha);
scsi_host_put(ha->host);
while (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags))
ssleep(1);
- klist_remove(&ha->node);
- atomic_dec(&qla4xxx_hba_count);
-
/* remove devs from iscsi_sessions to scsi_devices */
qla4xxx_free_ddb_list(ha);
scsi_remove_host(ha->host);
- qla4xxx_ioctl_exit(ha);
-
qla4xxx_free_adapter(ha);
scsi_host_put(ha->host);
struct srb * qla4xxx_del_from_active_array(struct scsi_qla_host *ha, uint32_t index)
{
struct srb *srb = NULL;
+ struct scsi_cmnd *cmd = NULL;
- /* validate handle and remove from active array */
- if (index >= MAX_SRBS)
+ cmd = scsi_host_find_tag(ha->host, index);
+ if (!cmd)
return srb;
- srb = ha->active_srb_array[index];
- ha->active_srb_array[index] = NULL;
+ srb = (struct srb *)CMD_SP(cmd);
if (!srb)
return srb;
ha->req_q_count += srb->iocb_cnt;
ha->iocb_cnt -= srb->iocb_cnt;
if (srb->cmd)
- srb->cmd->host_scribble = NULL;
+ srb->cmd->host_scribble =
+ (unsigned char *)(unsigned long) MAX_SRBS;
}
return srb;
}
/**
* qla4xxx_eh_wait_on_command - waits for command to be returned by firmware
- * @ha: actual ha whose done queue will contain the comd returned by firmware.
+ * @ha: Pointer to host adapter structure.
* @cmd: Scsi Command to wait on.
- * @got_ref: Additional reference retrieved by caller.
*
* This routine waits for the command to be returned by the Firmware
* for some max time.
**/
static int qla4xxx_eh_wait_on_command(struct scsi_qla_host *ha,
- struct scsi_cmnd *cmd, int got_ref)
+ struct scsi_cmnd *cmd)
{
-#define ABORT_POLLING_PERIOD 1000
-#define ABORT_WAIT_ITER 1
-
int done = 0;
struct srb *rp;
- unsigned long wait_iter = ABORT_WAIT_ITER;
+ uint32_t max_wait_time = EH_WAIT_CMD_TOV;
do {
/* Checking to see if its returned to OS */
- rp = (struct srb *) cmd->SCp.ptr;
+ rp = (struct srb *) CMD_SP(cmd);
if (rp == NULL) {
done++;
break;
}
- if (got_ref && (atomic_read(&rp->ref_count) == 1)) {
- done++;
- break;
- }
-
- msleep(ABORT_POLLING_PERIOD);
- } while (!(--wait_iter));
+ msleep(2000);
+ } while (max_wait_time--);
return done;
}
{
int cnt;
int status = 0;
- struct srb *sp;
struct scsi_cmnd *cmd;
- unsigned long flags;
/*
* Waiting for all commands for the designated target or dev
* in the active array
*/
- for (cnt = 1; cnt < MAX_SRBS; cnt++) {
- spin_lock_irqsave(&ha->hardware_lock, flags);
- sp = ha->active_srb_array[cnt];
- if (sp) {
- cmd = sp->cmd;
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
- if (cmd && stgt == scsi_target(cmd->device) &&
- (!sdev || sdev == cmd->device)) {
- if (!qla4xxx_eh_wait_on_command(ha, cmd, 0)) {
- status++;
- break;
- }
+ for (cnt = 0; cnt < ha->host->can_queue; cnt++) {
+ cmd = scsi_host_find_tag(ha->host, cnt);
+ if (cmd && stgt == scsi_target(cmd->device) &&
+ (!sdev || sdev == cmd->device)) {
+ if (!qla4xxx_eh_wait_on_command(ha, cmd)) {
+ status++;
+ break;
}
- } else {
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
}
}
return status;
**/
static int qla4xxx_eh_abort(struct scsi_cmnd *cmd)
{
- struct scsi_qla_host *ha;
+ struct scsi_qla_host *ha = to_qla_host(cmd->device->host);
+ unsigned int id = cmd->device->id;
+ unsigned int lun = cmd->device->lun;
+ unsigned long serial = cmd->serial_number;
struct srb *srb = NULL;
- struct ddb_entry *ddb_entry;
int ret = SUCCESS;
- unsigned int channel;
- unsigned int id;
- unsigned int lun;
- unsigned long serial;
- unsigned long flags = 0;
- int i = 0;
- int got_ref = 0;
- unsigned long wait_online;
-
- if (cmd == NULL) {
- DEBUG2(printk("ABORT - **** SCSI mid-layer passing in NULL cmd\n"));
- return SUCCESS;
- }
-
- ha = to_qla_host(cmd->device->host);
- ddb_entry = cmd->device->hostdata;
- channel = cmd->device->channel;
- id = cmd->device->id;
- lun = cmd->device->lun;
- serial = cmd->serial_number;
-
- if (!ddb_entry) {
- DEBUG2(printk("scsi%ld: ABORT - NULL ddb entry.\n", ha->host_no));
- return FAILED;
- }
-
- if (!cmd->SCp.ptr) {
- DEBUG2(printk("scsi%ld: ABORT - cmd already completed.\n",
- ha->host_no));
- return ret;
- }
-
+ int wait = 0;
+ dev_info(&ha->pdev->dev,
+ "scsi%ld:%d:%d: Abort command issued cmd=%p, pid=%ld\n",
+ ha->host_no, id, lun, cmd, serial);
- srb = (struct srb *) cmd->SCp.ptr;
+ srb = (struct srb *) CMD_SP(cmd);
- dev_info(&ha->pdev->dev, "scsi%ld:%d:%d:%d: ABORT ISSUED "
- "cmd=%p, pid=%ld, ref=%d\n", ha->host_no, channel, id, lun,
- cmd, serial, atomic_read(&srb->ref_count));
+ if (!srb)
+ return SUCCESS;
- if (qla4xxx_wait_for_hba_online(ha) != QLA_SUCCESS) {
- DEBUG2(printk("scsi%ld:%d: %s: Unable to abort task. Adapter "
- "DEAD.\n", ha->host_no, cmd->device->channel
- , __func__));
+ kref_get(&srb->srb_ref);
- return FAILED;
+ if (qla4xxx_abort_task(ha, srb) != QLA_SUCCESS) {
+ DEBUG3(printk("scsi%ld:%d:%d: Abort_task mbx failed.\n",
+ ha->host_no, id, lun));
+ ret = FAILED;
+ } else {
+ DEBUG3(printk("scsi%ld:%d:%d: Abort_task mbx success.\n",
+ ha->host_no, id, lun));
+ wait = 1;
}
- /* Check active list for command */
- spin_lock_irqsave(&ha->hardware_lock, flags);
- for (i = 1; i < MAX_SRBS; i++) {
- srb = ha->active_srb_array[i];
-
- if (srb == NULL)
- continue;
-
- if (srb->cmd != cmd)
- continue;
-
- DEBUG2(printk("scsi%ld:%d:%d:%d %s: aborting srb %p from RISC. "
- "pid=%ld.\n", ha->host_no, channel, id, lun,
- __func__, srb, serial));
- DEBUG3(qla4xxx_print_scsi_cmd(cmd));
-
- /* Get a reference to the sp and drop the lock.*/
- sp_get(srb);
- got_ref++;
-
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
-
- /*
- * If device is not online wait for 10 sec for device to come online,
- * else return error and do not issue abort task.
- */
- if (atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE) {
- wait_online = jiffies + (DEVICE_ONLINE_TOV * HZ);
- while (time_before(jiffies, wait_online)) {
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(HZ);
- if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE)
- break;
- }
- if (atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE) {
- DEBUG2(printk("scsi%ld:%d: %s: Unable to abort task."
- "Device is not online.\n", ha->host_no
- , cmd->device->channel, __func__));
-
- return FAILED;
- }
- }
-
- if (qla4xxx_abort_task(ha, srb) != QLA_SUCCESS) {
- dev_info(&ha->pdev->dev,
- "scsi%ld:%d:%d:%d: ABORT TASK - FAILED.\n",
- ha->host_no, channel, id, lun);
- } else {
- dev_info(&ha->pdev->dev,
- "scsi%ld:%d:%d:%d: ABORT TASK - mbx success.\n",
- ha->host_no, channel, id, lun);
- }
- spin_lock_irqsave(&ha->hardware_lock, flags);
- break;
- }
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ kref_put(&srb->srb_ref, qla4xxx_srb_compl);
/* Wait for command to complete */
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
- if (qla4xxx_eh_wait_on_command(ha, cmd, got_ref)) {
- dev_info(&ha->pdev->dev,
- "scsi%ld:%d:%d:%d: ABORT SUCCEEDED - "
- "cmd returned back to OS.\n",
- ha->host_no, channel, id, lun);
- ret = SUCCESS;
+ if (wait) {
+ if (!qla4xxx_eh_wait_on_command(ha, cmd)) {
+ DEBUG2(printk("scsi%ld:%d:%d: Abort handler timed out\n",
+ ha->host_no, id, lun));
+ ret = FAILED;
+ }
}
- if (got_ref)
- sp_put(ha, srb);
-
- DEBUG2(printk("scsi%ld:%d:%d:%d: ABORT cmd=%p, pid=%ld, ref=%d, "
- "ret=%x\n", ha->host_no, channel, id, lun, cmd,
- serial, atomic_read(&srb->ref_count), ret));
+ dev_info(&ha->pdev->dev,
+ "scsi%ld:%d:%d: Abort command - %s\n",
+ ha->host_no, id, lun, (ret == SUCCESS) ? "succeded" : "failed");
return ret;
}
-
-
-
/**
* qla4xxx_eh_device_reset - callback for target reset.
* @cmd: Pointer to Linux's SCSI command structure
**/
static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd)
{
- struct scsi_qla_host *ha;
- struct ddb_entry *ddb_entry;
+ struct scsi_qla_host *ha = to_qla_host(cmd->device->host);
+ struct ddb_entry *ddb_entry = cmd->device->hostdata;
int ret = FAILED, stat;
- struct Scsi_Host *h;
- unsigned int b, t, l;
-
- if (cmd == NULL) {
- DEBUG2(printk("%s: **** SCSI mid-layer passing in NULL cmd"
- "DEVICE RESET - cmd already completed.\n",
- __func__));
- return SUCCESS;
- }
-
- h = cmd->device->host;
- b = cmd->device->channel;
- t = cmd->device->id;
- l = cmd->device->lun;
- ha = to_qla_host(h);
- ddb_entry = cmd->device->hostdata;
- if (!ddb_entry) {
- DEBUG2(printk("scsi%ld: DEVICE RESET - NULL ddb entry.\n"
- , ha->host_no));
+ if (!ddb_entry)
return ret;
- }
- dev_info(&ha->pdev->dev, "scsi%ld:%d:%d:%d: DEVICE RESET ISSUED.\n"
- , ha->host_no, b, t, l);
+ dev_info(&ha->pdev->dev,
+ "scsi%ld:%d:%d:%d: DEVICE RESET ISSUED.\n", ha->host_no,
+ cmd->device->channel, cmd->device->id, cmd->device->lun);
DEBUG2(printk(KERN_INFO
"scsi%ld: DEVICE_RESET cmd=%p jiffies = 0x%lx, to=%x,"
cmd, jiffies, cmd->request->timeout / HZ,
ha->dpc_flags, cmd->result, cmd->allowed));
- /* wait for hba to go online */
- if (qla4xxx_wait_for_hba_online(ha) != QLA_SUCCESS) {
- dev_info(&ha->pdev->dev, "%s: DEVICE RESET."
- "Adapter Offline.\n", __func__);
- return FAILED;
- }
- stat = qla4xxx_reset_lun(ha, ddb_entry, l);
+ /* FIXME: wait for hba to go online */
+ stat = qla4xxx_reset_lun(ha, ddb_entry, cmd->device->lun);
if (stat != QLA_SUCCESS) {
dev_info(&ha->pdev->dev, "DEVICE RESET FAILED. %d\n", stat);
goto eh_dev_reset_done;
}
/* Send marker. */
- if (qla4xxx_send_marker_iocb(ha, ddb_entry, l, MM_LUN_RESET)
- != QLA_SUCCESS)
+ if (qla4xxx_send_marker_iocb(ha, ddb_entry, cmd->device->lun,
+ MM_LUN_RESET) != QLA_SUCCESS)
goto eh_dev_reset_done;
dev_info(&ha->pdev->dev,
"scsi(%ld:%d:%d:%d): DEVICE RESET SUCCEEDED.\n",
- ha->host_no, b, t, l);
+ ha->host_no, cmd->device->channel, cmd->device->id,
+ cmd->device->lun);
ret = SUCCESS;
int return_status = FAILED;
struct scsi_qla_host *ha;
- if (cmd == NULL) {
- DEBUG2(printk("%s: **** SCSI mid-layer passing in NULL cmd"
- "HOST RESET - cmd already completed.\n",
- __func__));
- return SUCCESS;
- }
-
ha = (struct scsi_qla_host *) cmd->device->host->hostdata;
dev_info(&ha->pdev->dev,
{
int ret;
- atomic_set(&qla4xxx_hba_count, 0);
- klist_init(&qla4xxx_hostlist, NULL, NULL);
-
/* Allocate cache for SRBs. */
srb_cachep = kmem_cache_create("qla4xxx_srbs", sizeof(struct srb), 0,
SLAB_HWCACHE_ALIGN, NULL);