mirror of
https://github.com/torvalds/linux.git
synced 2024-12-28 13:51:44 +00:00
Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-rc-fixes-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-rc-fixes-2.6: (27 commits) [SCSI] mpt fusion: don't oops if NumPhys==0 [SCSI] iscsi class: regression - fix races with state manipulation and blocking/unblocking [SCSI] qla4xxx: regression - add start scan callout [SCSI] qla4xxx: fix host reset dpc race [SCSI] tgt: fix build errors when dprintk is defined [SCSI] tgt: set the data length properly [SCSI] tgt: stop zero'ing scsi_cmnd [SCSI] ibmvstgt: set up scsi_host properly before __scsi_alloc_queue [SCSI] docbook: fix fusion source files [SCSI] docbook: fix scsi source file [SCSI] qla2xxx: Update version number to 8.02.00-k9. [SCSI] qla2xxx: Correct usage of inconsistent timeout values while issuing ELS commands. [SCSI] qla2xxx: Correct discrepancies during OVERRUN handling on FWI2-capable cards. [SCSI] qla2xxx: Correct needless clean-up resets during shutdown. [SCSI] arcmsr: update version and changelog [SCSI] ps3rom: disable clustering [SCSI] ps3rom: fix wrong resid calculation bug [SCSI] mvsas: fix phy sas address [SCSI] gdth: fix to internal commands execution [SCSI] gdth: bugfix for the at-exit problems ...
This commit is contained in:
commit
103926c689
@ -109,4 +109,10 @@
|
||||
** 8.replace pci_alloc_consistent()/pci_free_consistent() with kmalloc()/kfree() in arcmsr_iop_message_xfer()
|
||||
** 9. fix the release of dma memory for type B in arcmsr_free_ccb_pool()
|
||||
** 10.fix the arcmsr_polling_hbb_ccbdone()
|
||||
** 1.20.00.15 02/27/2008 Erich Chen & Nick Cheng
|
||||
** 1.arcmsr_iop_message_xfer() is called from atomic context under the
|
||||
** queuecommand scsi_host_template handler. James Bottomley pointed out
|
||||
** that the current GFP_KERNEL|GFP_DMA flags are wrong: firstly we are in
|
||||
** atomic context, secondly this memory is not used for DMA.
|
||||
** Also removed some unneeded casts. Thanks to Daniel Drake <dsd@gentoo.org>
|
||||
**************************************************************************
|
||||
|
@ -1701,6 +1701,11 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
|
||||
if (error)
|
||||
goto out_free_consistent;
|
||||
|
||||
if (!buffer->NumPhys) {
|
||||
error = -ENODEV;
|
||||
goto out_free_consistent;
|
||||
}
|
||||
|
||||
/* save config data */
|
||||
port_info->num_phys = buffer->NumPhys;
|
||||
port_info->phy_info = kcalloc(port_info->num_phys,
|
||||
|
@ -102,6 +102,7 @@ int asd_abort_task_set(struct domain_device *, u8 *lun);
|
||||
int asd_clear_aca(struct domain_device *, u8 *lun);
|
||||
int asd_clear_task_set(struct domain_device *, u8 *lun);
|
||||
int asd_lu_reset(struct domain_device *, u8 *lun);
|
||||
int asd_I_T_nexus_reset(struct domain_device *dev);
|
||||
int asd_query_task(struct sas_task *);
|
||||
|
||||
/* ---------- Adapter and Port management ---------- */
|
||||
|
@ -140,7 +140,7 @@ struct asd_ascb {
|
||||
|
||||
/* internally generated command */
|
||||
struct timer_list timer;
|
||||
struct completion completion;
|
||||
struct completion *completion;
|
||||
u8 tag_valid:1;
|
||||
__be16 tag; /* error recovery only */
|
||||
|
||||
@ -294,7 +294,6 @@ static inline void asd_init_ascb(struct asd_ha_struct *asd_ha,
|
||||
ascb->timer.function = NULL;
|
||||
init_timer(&ascb->timer);
|
||||
ascb->tc_index = -1;
|
||||
init_completion(&ascb->completion);
|
||||
}
|
||||
|
||||
/* Must be called with the tc_index_lock held!
|
||||
|
@ -1003,7 +1003,7 @@ static struct sas_domain_function_template aic94xx_transport_functions = {
|
||||
.lldd_abort_task_set = asd_abort_task_set,
|
||||
.lldd_clear_aca = asd_clear_aca,
|
||||
.lldd_clear_task_set = asd_clear_task_set,
|
||||
.lldd_I_T_nexus_reset = NULL,
|
||||
.lldd_I_T_nexus_reset = asd_I_T_nexus_reset,
|
||||
.lldd_lu_reset = asd_lu_reset,
|
||||
.lldd_query_task = asd_query_task,
|
||||
|
||||
|
@ -343,11 +343,13 @@ Again:
|
||||
task->task_state_flags &= ~SAS_TASK_AT_INITIATOR;
|
||||
task->task_state_flags |= SAS_TASK_STATE_DONE;
|
||||
if (unlikely((task->task_state_flags & SAS_TASK_STATE_ABORTED))) {
|
||||
struct completion *completion = ascb->completion;
|
||||
spin_unlock_irqrestore(&task->task_state_lock, flags);
|
||||
ASD_DPRINTK("task 0x%p done with opcode 0x%x resp 0x%x "
|
||||
"stat 0x%x but aborted by upper layer!\n",
|
||||
task, opcode, ts->resp, ts->stat);
|
||||
complete(&ascb->completion);
|
||||
if (completion)
|
||||
complete(completion);
|
||||
} else {
|
||||
spin_unlock_irqrestore(&task->task_state_lock, flags);
|
||||
task->lldd_task = NULL;
|
||||
|
@ -53,50 +53,64 @@ static int asd_enqueue_internal(struct asd_ascb *ascb,
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline void asd_timedout_common(unsigned long data)
|
||||
{
|
||||
struct asd_ascb *ascb = (void *) data;
|
||||
struct asd_seq_data *seq = &ascb->ha->seq;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&seq->pend_q_lock, flags);
|
||||
seq->pending--;
|
||||
list_del_init(&ascb->list);
|
||||
spin_unlock_irqrestore(&seq->pend_q_lock, flags);
|
||||
}
|
||||
|
||||
/* ---------- CLEAR NEXUS ---------- */
|
||||
|
||||
struct tasklet_completion_status {
|
||||
int dl_opcode;
|
||||
int tmf_state;
|
||||
u8 tag_valid:1;
|
||||
__be16 tag;
|
||||
};
|
||||
|
||||
#define DECLARE_TCS(tcs) \
|
||||
struct tasklet_completion_status tcs = { \
|
||||
.dl_opcode = 0, \
|
||||
.tmf_state = 0, \
|
||||
.tag_valid = 0, \
|
||||
.tag = 0, \
|
||||
}
|
||||
|
||||
|
||||
static void asd_clear_nexus_tasklet_complete(struct asd_ascb *ascb,
|
||||
struct done_list_struct *dl)
|
||||
{
|
||||
struct tasklet_completion_status *tcs = ascb->uldd_task;
|
||||
ASD_DPRINTK("%s: here\n", __FUNCTION__);
|
||||
if (!del_timer(&ascb->timer)) {
|
||||
ASD_DPRINTK("%s: couldn't delete timer\n", __FUNCTION__);
|
||||
return;
|
||||
}
|
||||
ASD_DPRINTK("%s: opcode: 0x%x\n", __FUNCTION__, dl->opcode);
|
||||
ascb->uldd_task = (void *) (unsigned long) dl->opcode;
|
||||
complete(&ascb->completion);
|
||||
tcs->dl_opcode = dl->opcode;
|
||||
complete(ascb->completion);
|
||||
asd_ascb_free(ascb);
|
||||
}
|
||||
|
||||
static void asd_clear_nexus_timedout(unsigned long data)
|
||||
{
|
||||
struct asd_ascb *ascb = (void *) data;
|
||||
struct asd_ascb *ascb = (void *)data;
|
||||
struct tasklet_completion_status *tcs = ascb->uldd_task;
|
||||
|
||||
ASD_DPRINTK("%s: here\n", __FUNCTION__);
|
||||
asd_timedout_common(data);
|
||||
ascb->uldd_task = (void *) TMF_RESP_FUNC_FAILED;
|
||||
complete(&ascb->completion);
|
||||
tcs->dl_opcode = TMF_RESP_FUNC_FAILED;
|
||||
complete(ascb->completion);
|
||||
}
|
||||
|
||||
#define CLEAR_NEXUS_PRE \
|
||||
struct asd_ascb *ascb; \
|
||||
struct scb *scb; \
|
||||
int res; \
|
||||
DECLARE_COMPLETION_ONSTACK(completion); \
|
||||
DECLARE_TCS(tcs); \
|
||||
\
|
||||
ASD_DPRINTK("%s: PRE\n", __FUNCTION__); \
|
||||
res = 1; \
|
||||
ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL); \
|
||||
if (!ascb) \
|
||||
return -ENOMEM; \
|
||||
\
|
||||
ascb->completion = &completion; \
|
||||
ascb->uldd_task = &tcs; \
|
||||
scb = ascb->scb; \
|
||||
scb->header.opcode = CLEAR_NEXUS
|
||||
|
||||
@ -107,10 +121,11 @@ static void asd_clear_nexus_timedout(unsigned long data)
|
||||
if (res) \
|
||||
goto out_err; \
|
||||
ASD_DPRINTK("%s: clear nexus posted, waiting...\n", __FUNCTION__); \
|
||||
wait_for_completion(&ascb->completion); \
|
||||
res = (int) (unsigned long) ascb->uldd_task; \
|
||||
wait_for_completion(&completion); \
|
||||
res = tcs.dl_opcode; \
|
||||
if (res == TC_NO_ERROR) \
|
||||
res = TMF_RESP_FUNC_COMPLETE; \
|
||||
return res; \
|
||||
out_err: \
|
||||
asd_ascb_free(ascb); \
|
||||
return res
|
||||
@ -118,9 +133,6 @@ out_err: \
|
||||
int asd_clear_nexus_ha(struct sas_ha_struct *sas_ha)
|
||||
{
|
||||
struct asd_ha_struct *asd_ha = sas_ha->lldd_ha;
|
||||
struct asd_ascb *ascb;
|
||||
struct scb *scb;
|
||||
int res;
|
||||
|
||||
CLEAR_NEXUS_PRE;
|
||||
scb->clear_nexus.nexus = NEXUS_ADAPTER;
|
||||
@ -130,9 +142,6 @@ int asd_clear_nexus_ha(struct sas_ha_struct *sas_ha)
|
||||
int asd_clear_nexus_port(struct asd_sas_port *port)
|
||||
{
|
||||
struct asd_ha_struct *asd_ha = port->ha->lldd_ha;
|
||||
struct asd_ascb *ascb;
|
||||
struct scb *scb;
|
||||
int res;
|
||||
|
||||
CLEAR_NEXUS_PRE;
|
||||
scb->clear_nexus.nexus = NEXUS_PORT;
|
||||
@ -140,29 +149,73 @@ int asd_clear_nexus_port(struct asd_sas_port *port)
|
||||
CLEAR_NEXUS_POST;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int asd_clear_nexus_I_T(struct domain_device *dev)
|
||||
enum clear_nexus_phase {
|
||||
NEXUS_PHASE_PRE,
|
||||
NEXUS_PHASE_POST,
|
||||
NEXUS_PHASE_RESUME,
|
||||
};
|
||||
|
||||
static int asd_clear_nexus_I_T(struct domain_device *dev,
|
||||
enum clear_nexus_phase phase)
|
||||
{
|
||||
struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
|
||||
struct asd_ascb *ascb;
|
||||
struct scb *scb;
|
||||
int res;
|
||||
|
||||
CLEAR_NEXUS_PRE;
|
||||
scb->clear_nexus.nexus = NEXUS_I_T;
|
||||
scb->clear_nexus.flags = SEND_Q | EXEC_Q | NOTINQ;
|
||||
switch (phase) {
|
||||
case NEXUS_PHASE_PRE:
|
||||
scb->clear_nexus.flags = EXEC_Q | SUSPEND_TX;
|
||||
break;
|
||||
case NEXUS_PHASE_POST:
|
||||
scb->clear_nexus.flags = SEND_Q | NOTINQ;
|
||||
break;
|
||||
case NEXUS_PHASE_RESUME:
|
||||
scb->clear_nexus.flags = RESUME_TX;
|
||||
}
|
||||
scb->clear_nexus.conn_handle = cpu_to_le16((u16)(unsigned long)
|
||||
dev->lldd_dev);
|
||||
CLEAR_NEXUS_POST;
|
||||
}
|
||||
#endif
|
||||
|
||||
int asd_I_T_nexus_reset(struct domain_device *dev)
|
||||
{
|
||||
int res, tmp_res, i;
|
||||
struct sas_phy *phy = sas_find_local_phy(dev);
|
||||
/* Standard mandates link reset for ATA (type 0) and
|
||||
* hard reset for SSP (type 1) */
|
||||
int reset_type = (dev->dev_type == SATA_DEV ||
|
||||
(dev->tproto & SAS_PROTOCOL_STP)) ? 0 : 1;
|
||||
|
||||
asd_clear_nexus_I_T(dev, NEXUS_PHASE_PRE);
|
||||
/* send a hard reset */
|
||||
ASD_DPRINTK("sending %s reset to %s\n",
|
||||
reset_type ? "hard" : "soft", phy->dev.bus_id);
|
||||
res = sas_phy_reset(phy, reset_type);
|
||||
if (res == TMF_RESP_FUNC_COMPLETE) {
|
||||
/* wait for the maximum settle time */
|
||||
msleep(500);
|
||||
/* clear all outstanding commands (keep nexus suspended) */
|
||||
asd_clear_nexus_I_T(dev, NEXUS_PHASE_POST);
|
||||
}
|
||||
for (i = 0 ; i < 3; i++) {
|
||||
tmp_res = asd_clear_nexus_I_T(dev, NEXUS_PHASE_RESUME);
|
||||
if (tmp_res == TC_RESUME)
|
||||
return res;
|
||||
msleep(500);
|
||||
}
|
||||
|
||||
/* This is a bit of a problem: the sequencer is still suspended
|
||||
* and is refusing to resume. Hope it will resume on a bigger hammer
|
||||
* or the disk is lost */
|
||||
dev_printk(KERN_ERR, &phy->dev,
|
||||
"Failed to resume nexus after reset 0x%x\n", tmp_res);
|
||||
|
||||
return TMF_RESP_FUNC_FAILED;
|
||||
}
|
||||
|
||||
static int asd_clear_nexus_I_T_L(struct domain_device *dev, u8 *lun)
|
||||
{
|
||||
struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
|
||||
struct asd_ascb *ascb;
|
||||
struct scb *scb;
|
||||
int res;
|
||||
|
||||
CLEAR_NEXUS_PRE;
|
||||
scb->clear_nexus.nexus = NEXUS_I_T_L;
|
||||
@ -177,9 +230,6 @@ static int asd_clear_nexus_tag(struct sas_task *task)
|
||||
{
|
||||
struct asd_ha_struct *asd_ha = task->dev->port->ha->lldd_ha;
|
||||
struct asd_ascb *tascb = task->lldd_task;
|
||||
struct asd_ascb *ascb;
|
||||
struct scb *scb;
|
||||
int res;
|
||||
|
||||
CLEAR_NEXUS_PRE;
|
||||
scb->clear_nexus.nexus = NEXUS_TAG;
|
||||
@ -195,9 +245,6 @@ static int asd_clear_nexus_index(struct sas_task *task)
|
||||
{
|
||||
struct asd_ha_struct *asd_ha = task->dev->port->ha->lldd_ha;
|
||||
struct asd_ascb *tascb = task->lldd_task;
|
||||
struct asd_ascb *ascb;
|
||||
struct scb *scb;
|
||||
int res;
|
||||
|
||||
CLEAR_NEXUS_PRE;
|
||||
scb->clear_nexus.nexus = NEXUS_TRANS_CX;
|
||||
@ -213,11 +260,11 @@ static int asd_clear_nexus_index(struct sas_task *task)
|
||||
static void asd_tmf_timedout(unsigned long data)
|
||||
{
|
||||
struct asd_ascb *ascb = (void *) data;
|
||||
struct tasklet_completion_status *tcs = ascb->uldd_task;
|
||||
|
||||
ASD_DPRINTK("tmf timed out\n");
|
||||
asd_timedout_common(data);
|
||||
ascb->uldd_task = (void *) TMF_RESP_FUNC_FAILED;
|
||||
complete(&ascb->completion);
|
||||
tcs->tmf_state = TMF_RESP_FUNC_FAILED;
|
||||
complete(ascb->completion);
|
||||
}
|
||||
|
||||
static int asd_get_tmf_resp_tasklet(struct asd_ascb *ascb,
|
||||
@ -269,18 +316,24 @@ static int asd_get_tmf_resp_tasklet(struct asd_ascb *ascb,
|
||||
static void asd_tmf_tasklet_complete(struct asd_ascb *ascb,
|
||||
struct done_list_struct *dl)
|
||||
{
|
||||
struct tasklet_completion_status *tcs;
|
||||
|
||||
if (!del_timer(&ascb->timer))
|
||||
return;
|
||||
|
||||
tcs = ascb->uldd_task;
|
||||
ASD_DPRINTK("tmf tasklet complete\n");
|
||||
|
||||
if (dl->opcode == TC_SSP_RESP)
|
||||
ascb->uldd_task = (void *) (unsigned long)
|
||||
asd_get_tmf_resp_tasklet(ascb, dl);
|
||||
else
|
||||
ascb->uldd_task = (void *) 0xFF00 + (unsigned long) dl->opcode;
|
||||
tcs->dl_opcode = dl->opcode;
|
||||
|
||||
complete(&ascb->completion);
|
||||
if (dl->opcode == TC_SSP_RESP) {
|
||||
tcs->tmf_state = asd_get_tmf_resp_tasklet(ascb, dl);
|
||||
tcs->tag_valid = ascb->tag_valid;
|
||||
tcs->tag = ascb->tag;
|
||||
}
|
||||
|
||||
complete(ascb->completion);
|
||||
asd_ascb_free(ascb);
|
||||
}
|
||||
|
||||
static inline int asd_clear_nexus(struct sas_task *task)
|
||||
@ -288,15 +341,19 @@ static inline int asd_clear_nexus(struct sas_task *task)
|
||||
int res = TMF_RESP_FUNC_FAILED;
|
||||
int leftover;
|
||||
struct asd_ascb *tascb = task->lldd_task;
|
||||
DECLARE_COMPLETION_ONSTACK(completion);
|
||||
unsigned long flags;
|
||||
|
||||
tascb->completion = &completion;
|
||||
|
||||
ASD_DPRINTK("task not done, clearing nexus\n");
|
||||
if (tascb->tag_valid)
|
||||
res = asd_clear_nexus_tag(task);
|
||||
else
|
||||
res = asd_clear_nexus_index(task);
|
||||
leftover = wait_for_completion_timeout(&tascb->completion,
|
||||
leftover = wait_for_completion_timeout(&completion,
|
||||
AIC94XX_SCB_TIMEOUT);
|
||||
tascb->completion = NULL;
|
||||
ASD_DPRINTK("came back from clear nexus\n");
|
||||
spin_lock_irqsave(&task->task_state_lock, flags);
|
||||
if (leftover < 1)
|
||||
@ -350,6 +407,11 @@ int asd_abort_task(struct sas_task *task)
|
||||
struct asd_ascb *ascb = NULL;
|
||||
struct scb *scb;
|
||||
int leftover;
|
||||
DECLARE_TCS(tcs);
|
||||
DECLARE_COMPLETION_ONSTACK(completion);
|
||||
DECLARE_COMPLETION_ONSTACK(tascb_completion);
|
||||
|
||||
tascb->completion = &tascb_completion;
|
||||
|
||||
spin_lock_irqsave(&task->task_state_lock, flags);
|
||||
if (task->task_state_flags & SAS_TASK_STATE_DONE) {
|
||||
@ -363,8 +425,10 @@ int asd_abort_task(struct sas_task *task)
|
||||
ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL);
|
||||
if (!ascb)
|
||||
return -ENOMEM;
|
||||
scb = ascb->scb;
|
||||
|
||||
ascb->uldd_task = &tcs;
|
||||
ascb->completion = &completion;
|
||||
scb = ascb->scb;
|
||||
scb->header.opcode = SCB_ABORT_TASK;
|
||||
|
||||
switch (task->task_proto) {
|
||||
@ -406,13 +470,12 @@ int asd_abort_task(struct sas_task *task)
|
||||
res = asd_enqueue_internal(ascb, asd_tmf_tasklet_complete,
|
||||
asd_tmf_timedout);
|
||||
if (res)
|
||||
goto out;
|
||||
wait_for_completion(&ascb->completion);
|
||||
goto out_free;
|
||||
wait_for_completion(&completion);
|
||||
ASD_DPRINTK("tmf came back\n");
|
||||
|
||||
res = (int) (unsigned long) ascb->uldd_task;
|
||||
tascb->tag = ascb->tag;
|
||||
tascb->tag_valid = ascb->tag_valid;
|
||||
tascb->tag = tcs.tag;
|
||||
tascb->tag_valid = tcs.tag_valid;
|
||||
|
||||
spin_lock_irqsave(&task->task_state_lock, flags);
|
||||
if (task->task_state_flags & SAS_TASK_STATE_DONE) {
|
||||
@ -423,63 +486,68 @@ int asd_abort_task(struct sas_task *task)
|
||||
}
|
||||
spin_unlock_irqrestore(&task->task_state_lock, flags);
|
||||
|
||||
switch (res) {
|
||||
/* The task to be aborted has been sent to the device.
|
||||
* We got a Response IU for the ABORT TASK TMF. */
|
||||
case TC_NO_ERROR + 0xFF00:
|
||||
case TMF_RESP_FUNC_COMPLETE:
|
||||
case TMF_RESP_FUNC_FAILED:
|
||||
res = asd_clear_nexus(task);
|
||||
break;
|
||||
case TMF_RESP_INVALID_FRAME:
|
||||
case TMF_RESP_OVERLAPPED_TAG:
|
||||
case TMF_RESP_FUNC_ESUPP:
|
||||
case TMF_RESP_NO_LUN:
|
||||
goto out_done; break;
|
||||
}
|
||||
/* In the following we assume that the managing layer
|
||||
* will _never_ make a mistake, when issuing ABORT TASK.
|
||||
*/
|
||||
switch (res) {
|
||||
default:
|
||||
res = asd_clear_nexus(task);
|
||||
/* fallthrough */
|
||||
case TC_NO_ERROR + 0xFF00:
|
||||
case TMF_RESP_FUNC_COMPLETE:
|
||||
break;
|
||||
/* The task hasn't been sent to the device xor we never got
|
||||
* a (sane) Response IU for the ABORT TASK TMF.
|
||||
*/
|
||||
case TF_NAK_RECV + 0xFF00:
|
||||
res = TMF_RESP_INVALID_FRAME;
|
||||
break;
|
||||
case TF_TMF_TASK_DONE + 0xFF00: /* done but not reported yet */
|
||||
if (tcs.dl_opcode == TC_SSP_RESP) {
|
||||
/* The task to be aborted has been sent to the device.
|
||||
* We got a Response IU for the ABORT TASK TMF. */
|
||||
if (tcs.tmf_state == TMF_RESP_FUNC_COMPLETE)
|
||||
res = asd_clear_nexus(task);
|
||||
else
|
||||
res = tcs.tmf_state;
|
||||
} else if (tcs.dl_opcode == TC_NO_ERROR &&
|
||||
tcs.tmf_state == TMF_RESP_FUNC_FAILED) {
|
||||
/* timeout */
|
||||
res = TMF_RESP_FUNC_FAILED;
|
||||
leftover = wait_for_completion_timeout(&tascb->completion,
|
||||
AIC94XX_SCB_TIMEOUT);
|
||||
spin_lock_irqsave(&task->task_state_lock, flags);
|
||||
if (leftover < 1)
|
||||
} else {
|
||||
/* In the following we assume that the managing layer
|
||||
* will _never_ make a mistake, when issuing ABORT
|
||||
* TASK.
|
||||
*/
|
||||
switch (tcs.dl_opcode) {
|
||||
default:
|
||||
res = asd_clear_nexus(task);
|
||||
/* fallthrough */
|
||||
case TC_NO_ERROR:
|
||||
break;
|
||||
/* The task hasn't been sent to the device xor
|
||||
* we never got a (sane) Response IU for the
|
||||
* ABORT TASK TMF.
|
||||
*/
|
||||
case TF_NAK_RECV:
|
||||
res = TMF_RESP_INVALID_FRAME;
|
||||
break;
|
||||
case TF_TMF_TASK_DONE: /* done but not reported yet */
|
||||
res = TMF_RESP_FUNC_FAILED;
|
||||
if (task->task_state_flags & SAS_TASK_STATE_DONE)
|
||||
leftover =
|
||||
wait_for_completion_timeout(&tascb_completion,
|
||||
AIC94XX_SCB_TIMEOUT);
|
||||
spin_lock_irqsave(&task->task_state_lock, flags);
|
||||
if (leftover < 1)
|
||||
res = TMF_RESP_FUNC_FAILED;
|
||||
if (task->task_state_flags & SAS_TASK_STATE_DONE)
|
||||
res = TMF_RESP_FUNC_COMPLETE;
|
||||
spin_unlock_irqrestore(&task->task_state_lock, flags);
|
||||
break;
|
||||
case TF_TMF_NO_TAG:
|
||||
case TF_TMF_TAG_FREE: /* the tag is in the free list */
|
||||
case TF_TMF_NO_CONN_HANDLE: /* no such device */
|
||||
res = TMF_RESP_FUNC_COMPLETE;
|
||||
spin_unlock_irqrestore(&task->task_state_lock, flags);
|
||||
goto out_done;
|
||||
case TF_TMF_NO_TAG + 0xFF00:
|
||||
case TF_TMF_TAG_FREE + 0xFF00: /* the tag is in the free list */
|
||||
case TF_TMF_NO_CONN_HANDLE + 0xFF00: /* no such device */
|
||||
res = TMF_RESP_FUNC_COMPLETE;
|
||||
goto out_done;
|
||||
case TF_TMF_NO_CTX + 0xFF00: /* not in seq, or proto != SSP */
|
||||
res = TMF_RESP_FUNC_ESUPP;
|
||||
goto out;
|
||||
break;
|
||||
case TF_TMF_NO_CTX: /* not in seq, or proto != SSP */
|
||||
res = TMF_RESP_FUNC_ESUPP;
|
||||
break;
|
||||
}
|
||||
}
|
||||
out_done:
|
||||
out_done:
|
||||
tascb->completion = NULL;
|
||||
if (res == TMF_RESP_FUNC_COMPLETE) {
|
||||
task->lldd_task = NULL;
|
||||
mb();
|
||||
asd_ascb_free(tascb);
|
||||
}
|
||||
out:
|
||||
ASD_DPRINTK("task 0x%p aborted, res: 0x%x\n", task, res);
|
||||
return res;
|
||||
|
||||
out_free:
|
||||
asd_ascb_free(ascb);
|
||||
ASD_DPRINTK("task 0x%p aborted, res: 0x%x\n", task, res);
|
||||
return res;
|
||||
@ -507,6 +575,8 @@ static int asd_initiate_ssp_tmf(struct domain_device *dev, u8 *lun,
|
||||
struct asd_ascb *ascb;
|
||||
int res = 1;
|
||||
struct scb *scb;
|
||||
DECLARE_COMPLETION_ONSTACK(completion);
|
||||
DECLARE_TCS(tcs);
|
||||
|
||||
if (!(dev->tproto & SAS_PROTOCOL_SSP))
|
||||
return TMF_RESP_FUNC_ESUPP;
|
||||
@ -514,6 +584,9 @@ static int asd_initiate_ssp_tmf(struct domain_device *dev, u8 *lun,
|
||||
ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL);
|
||||
if (!ascb)
|
||||
return -ENOMEM;
|
||||
|
||||
ascb->completion = &completion;
|
||||
ascb->uldd_task = &tcs;
|
||||
scb = ascb->scb;
|
||||
|
||||
if (tmf == TMF_QUERY_TASK)
|
||||
@ -546,31 +619,32 @@ static int asd_initiate_ssp_tmf(struct domain_device *dev, u8 *lun,
|
||||
asd_tmf_timedout);
|
||||
if (res)
|
||||
goto out_err;
|
||||
wait_for_completion(&ascb->completion);
|
||||
res = (int) (unsigned long) ascb->uldd_task;
|
||||
wait_for_completion(&completion);
|
||||
|
||||
switch (res) {
|
||||
case TC_NO_ERROR + 0xFF00:
|
||||
switch (tcs.dl_opcode) {
|
||||
case TC_NO_ERROR:
|
||||
res = TMF_RESP_FUNC_COMPLETE;
|
||||
break;
|
||||
case TF_NAK_RECV + 0xFF00:
|
||||
case TF_NAK_RECV:
|
||||
res = TMF_RESP_INVALID_FRAME;
|
||||
break;
|
||||
case TF_TMF_TASK_DONE + 0xFF00:
|
||||
case TF_TMF_TASK_DONE:
|
||||
res = TMF_RESP_FUNC_FAILED;
|
||||
break;
|
||||
case TF_TMF_NO_TAG + 0xFF00:
|
||||
case TF_TMF_TAG_FREE + 0xFF00: /* the tag is in the free list */
|
||||
case TF_TMF_NO_CONN_HANDLE + 0xFF00: /* no such device */
|
||||
case TF_TMF_NO_TAG:
|
||||
case TF_TMF_TAG_FREE: /* the tag is in the free list */
|
||||
case TF_TMF_NO_CONN_HANDLE: /* no such device */
|
||||
res = TMF_RESP_FUNC_COMPLETE;
|
||||
break;
|
||||
case TF_TMF_NO_CTX + 0xFF00: /* not in seq, or proto != SSP */
|
||||
case TF_TMF_NO_CTX: /* not in seq, or proto != SSP */
|
||||
res = TMF_RESP_FUNC_ESUPP;
|
||||
break;
|
||||
default:
|
||||
/* Allow TMF response codes to propagate upwards */
|
||||
res = tcs.dl_opcode;
|
||||
break;
|
||||
}
|
||||
return res;
|
||||
out_err:
|
||||
asd_ascb_free(ascb);
|
||||
return res;
|
||||
|
@ -48,7 +48,7 @@ struct class_device_attribute;
|
||||
/*The limit of outstanding scsi command that firmware can handle*/
|
||||
#define ARCMSR_MAX_OUTSTANDING_CMD 256
|
||||
#define ARCMSR_MAX_FREECCB_NUM 320
|
||||
#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.15 2007/12/24"
|
||||
#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.15 2008/02/27"
|
||||
#define ARCMSR_SCSI_INITIATOR_ID 255
|
||||
#define ARCMSR_MAX_XFER_SECTORS 512
|
||||
#define ARCMSR_MAX_XFER_SECTORS_B 4096
|
||||
|
@ -160,7 +160,7 @@ static void gdth_readapp_event(gdth_ha_str *ha, unchar application,
|
||||
static void gdth_clear_events(void);
|
||||
|
||||
static void gdth_copy_internal_data(gdth_ha_str *ha, Scsi_Cmnd *scp,
|
||||
char *buffer, ushort count, int to_buffer);
|
||||
char *buffer, ushort count);
|
||||
static int gdth_internal_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp);
|
||||
static int gdth_fill_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, ushort hdrive);
|
||||
|
||||
@ -182,7 +182,6 @@ static int gdth_ioctl(struct inode *inode, struct file *filep,
|
||||
unsigned int cmd, unsigned long arg);
|
||||
|
||||
static void gdth_flush(gdth_ha_str *ha);
|
||||
static int gdth_halt(struct notifier_block *nb, ulong event, void *buf);
|
||||
static int gdth_queuecommand(Scsi_Cmnd *scp,void (*done)(Scsi_Cmnd *));
|
||||
static int __gdth_queuecommand(gdth_ha_str *ha, struct scsi_cmnd *scp,
|
||||
struct gdth_cmndinfo *cmndinfo);
|
||||
@ -417,12 +416,6 @@ static inline void gdth_set_sglist(struct scsi_cmnd *cmd,
|
||||
#include "gdth_proc.h"
|
||||
#include "gdth_proc.c"
|
||||
|
||||
/* notifier block to get a notify on system shutdown/halt/reboot */
|
||||
static struct notifier_block gdth_notifier = {
|
||||
gdth_halt, NULL, 0
|
||||
};
|
||||
static int notifier_disabled = 0;
|
||||
|
||||
static gdth_ha_str *gdth_find_ha(int hanum)
|
||||
{
|
||||
gdth_ha_str *ha;
|
||||
@ -445,8 +438,8 @@ static struct gdth_cmndinfo *gdth_get_cmndinfo(gdth_ha_str *ha)
|
||||
for (i=0; i<GDTH_MAXCMDS; ++i) {
|
||||
if (ha->cmndinfo[i].index == 0) {
|
||||
priv = &ha->cmndinfo[i];
|
||||
priv->index = i+1;
|
||||
memset(priv, 0, sizeof(*priv));
|
||||
priv->index = i+1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -493,7 +486,6 @@ int __gdth_execute(struct scsi_device *sdev, gdth_cmd_str *gdtcmd, char *cmnd,
|
||||
gdth_ha_str *ha = shost_priv(sdev->host);
|
||||
Scsi_Cmnd *scp;
|
||||
struct gdth_cmndinfo cmndinfo;
|
||||
struct scatterlist one_sg;
|
||||
DECLARE_COMPLETION_ONSTACK(wait);
|
||||
int rval;
|
||||
|
||||
@ -507,13 +499,10 @@ int __gdth_execute(struct scsi_device *sdev, gdth_cmd_str *gdtcmd, char *cmnd,
|
||||
/* use request field to save the ptr. to completion struct. */
|
||||
scp->request = (struct request *)&wait;
|
||||
scp->timeout_per_command = timeout*HZ;
|
||||
sg_init_one(&one_sg, gdtcmd, sizeof(*gdtcmd));
|
||||
gdth_set_sglist(scp, &one_sg);
|
||||
gdth_set_sg_count(scp, 1);
|
||||
gdth_set_bufflen(scp, sizeof(*gdtcmd));
|
||||
scp->cmd_len = 12;
|
||||
memcpy(scp->cmnd, cmnd, 12);
|
||||
cmndinfo.priority = IOCTL_PRI;
|
||||
cmndinfo.internal_cmd_str = gdtcmd;
|
||||
cmndinfo.internal_command = 1;
|
||||
|
||||
TRACE(("__gdth_execute() cmd 0x%x\n", scp->cmnd[0]));
|
||||
@ -2355,7 +2344,7 @@ static void gdth_next(gdth_ha_str *ha)
|
||||
* buffers, kmap_atomic() as needed.
|
||||
*/
|
||||
static void gdth_copy_internal_data(gdth_ha_str *ha, Scsi_Cmnd *scp,
|
||||
char *buffer, ushort count, int to_buffer)
|
||||
char *buffer, ushort count)
|
||||
{
|
||||
ushort cpcount,i, max_sg = gdth_sg_count(scp);
|
||||
ushort cpsum,cpnow;
|
||||
@ -2381,10 +2370,7 @@ static void gdth_copy_internal_data(gdth_ha_str *ha, Scsi_Cmnd *scp,
|
||||
}
|
||||
local_irq_save(flags);
|
||||
address = kmap_atomic(sg_page(sl), KM_BIO_SRC_IRQ) + sl->offset;
|
||||
if (to_buffer)
|
||||
memcpy(buffer, address, cpnow);
|
||||
else
|
||||
memcpy(address, buffer, cpnow);
|
||||
memcpy(address, buffer, cpnow);
|
||||
flush_dcache_page(sg_page(sl));
|
||||
kunmap_atomic(address, KM_BIO_SRC_IRQ);
|
||||
local_irq_restore(flags);
|
||||
@ -2438,7 +2424,7 @@ static int gdth_internal_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp)
|
||||
strcpy(inq.vendor,ha->oem_name);
|
||||
sprintf(inq.product,"Host Drive #%02d",t);
|
||||
strcpy(inq.revision," ");
|
||||
gdth_copy_internal_data(ha, scp, (char*)&inq, sizeof(gdth_inq_data), 0);
|
||||
gdth_copy_internal_data(ha, scp, (char*)&inq, sizeof(gdth_inq_data));
|
||||
break;
|
||||
|
||||
case REQUEST_SENSE:
|
||||
@ -2448,7 +2434,7 @@ static int gdth_internal_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp)
|
||||
sd.key = NO_SENSE;
|
||||
sd.info = 0;
|
||||
sd.add_length= 0;
|
||||
gdth_copy_internal_data(ha, scp, (char*)&sd, sizeof(gdth_sense_data), 0);
|
||||
gdth_copy_internal_data(ha, scp, (char*)&sd, sizeof(gdth_sense_data));
|
||||
break;
|
||||
|
||||
case MODE_SENSE:
|
||||
@ -2460,7 +2446,7 @@ static int gdth_internal_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp)
|
||||
mpd.bd.block_length[0] = (SECTOR_SIZE & 0x00ff0000) >> 16;
|
||||
mpd.bd.block_length[1] = (SECTOR_SIZE & 0x0000ff00) >> 8;
|
||||
mpd.bd.block_length[2] = (SECTOR_SIZE & 0x000000ff);
|
||||
gdth_copy_internal_data(ha, scp, (char*)&mpd, sizeof(gdth_modep_data), 0);
|
||||
gdth_copy_internal_data(ha, scp, (char*)&mpd, sizeof(gdth_modep_data));
|
||||
break;
|
||||
|
||||
case READ_CAPACITY:
|
||||
@ -2470,7 +2456,7 @@ static int gdth_internal_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp)
|
||||
else
|
||||
rdc.last_block_no = cpu_to_be32(ha->hdr[t].size-1);
|
||||
rdc.block_length = cpu_to_be32(SECTOR_SIZE);
|
||||
gdth_copy_internal_data(ha, scp, (char*)&rdc, sizeof(gdth_rdcap_data), 0);
|
||||
gdth_copy_internal_data(ha, scp, (char*)&rdc, sizeof(gdth_rdcap_data));
|
||||
break;
|
||||
|
||||
case SERVICE_ACTION_IN:
|
||||
@ -2482,7 +2468,7 @@ static int gdth_internal_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp)
|
||||
rdc16.last_block_no = cpu_to_be64(ha->hdr[t].size-1);
|
||||
rdc16.block_length = cpu_to_be32(SECTOR_SIZE);
|
||||
gdth_copy_internal_data(ha, scp, (char*)&rdc16,
|
||||
sizeof(gdth_rdcap16_data), 0);
|
||||
sizeof(gdth_rdcap16_data));
|
||||
} else {
|
||||
scp->result = DID_ABORT << 16;
|
||||
}
|
||||
@ -2852,6 +2838,7 @@ static int gdth_fill_raw_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, unchar b)
|
||||
static int gdth_special_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp)
|
||||
{
|
||||
register gdth_cmd_str *cmdp;
|
||||
struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp);
|
||||
int cmd_index;
|
||||
|
||||
cmdp= ha->pccb;
|
||||
@ -2860,7 +2847,7 @@ static int gdth_special_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp)
|
||||
if (ha->type==GDT_EISA && ha->cmd_cnt>0)
|
||||
return 0;
|
||||
|
||||
gdth_copy_internal_data(ha, scp, (char *)cmdp, sizeof(gdth_cmd_str), 1);
|
||||
*cmdp = *cmndinfo->internal_cmd_str;
|
||||
cmdp->RequestBuffer = scp;
|
||||
|
||||
/* search free command index */
|
||||
@ -3794,6 +3781,8 @@ static void gdth_timeout(ulong data)
|
||||
gdth_ha_str *ha;
|
||||
ulong flags;
|
||||
|
||||
BUG_ON(list_empty(&gdth_instances));
|
||||
|
||||
ha = list_first_entry(&gdth_instances, gdth_ha_str, list);
|
||||
spin_lock_irqsave(&ha->smp_lock, flags);
|
||||
|
||||
@ -4669,45 +4658,6 @@ static void gdth_flush(gdth_ha_str *ha)
|
||||
}
|
||||
}
|
||||
|
||||
/* shutdown routine */
|
||||
static int gdth_halt(struct notifier_block *nb, ulong event, void *buf)
|
||||
{
|
||||
gdth_ha_str *ha;
|
||||
#ifndef __alpha__
|
||||
gdth_cmd_str gdtcmd;
|
||||
char cmnd[MAX_COMMAND_SIZE];
|
||||
#endif
|
||||
|
||||
if (notifier_disabled)
|
||||
return NOTIFY_OK;
|
||||
|
||||
TRACE2(("gdth_halt() event %d\n",(int)event));
|
||||
if (event != SYS_RESTART && event != SYS_HALT && event != SYS_POWER_OFF)
|
||||
return NOTIFY_DONE;
|
||||
|
||||
notifier_disabled = 1;
|
||||
printk("GDT-HA: Flushing all host drives .. ");
|
||||
list_for_each_entry(ha, &gdth_instances, list) {
|
||||
gdth_flush(ha);
|
||||
|
||||
#ifndef __alpha__
|
||||
/* controller reset */
|
||||
memset(cmnd, 0xff, MAX_COMMAND_SIZE);
|
||||
gdtcmd.BoardNode = LOCALBOARD;
|
||||
gdtcmd.Service = CACHESERVICE;
|
||||
gdtcmd.OpCode = GDT_RESET;
|
||||
TRACE2(("gdth_halt(): reset controller %d\n", ha->hanum));
|
||||
gdth_execute(ha->shost, &gdtcmd, cmnd, 10, NULL);
|
||||
#endif
|
||||
}
|
||||
printk("Done.\n");
|
||||
|
||||
#ifdef GDTH_STATISTICS
|
||||
del_timer(&gdth_timer);
|
||||
#endif
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
/* configure lun */
|
||||
static int gdth_slave_configure(struct scsi_device *sdev)
|
||||
{
|
||||
@ -5142,13 +5092,13 @@ static void gdth_remove_one(gdth_ha_str *ha)
|
||||
|
||||
scsi_remove_host(shp);
|
||||
|
||||
gdth_flush(ha);
|
||||
|
||||
if (ha->sdev) {
|
||||
scsi_free_host_dev(ha->sdev);
|
||||
ha->sdev = NULL;
|
||||
}
|
||||
|
||||
gdth_flush(ha);
|
||||
|
||||
if (shp->irq)
|
||||
free_irq(shp->irq,ha);
|
||||
|
||||
@ -5174,6 +5124,24 @@ static void gdth_remove_one(gdth_ha_str *ha)
|
||||
scsi_host_put(shp);
|
||||
}
|
||||
|
||||
static int gdth_halt(struct notifier_block *nb, ulong event, void *buf)
|
||||
{
|
||||
gdth_ha_str *ha;
|
||||
|
||||
TRACE2(("gdth_halt() event %d\n", (int)event));
|
||||
if (event != SYS_RESTART && event != SYS_HALT && event != SYS_POWER_OFF)
|
||||
return NOTIFY_DONE;
|
||||
|
||||
list_for_each_entry(ha, &gdth_instances, list)
|
||||
gdth_flush(ha);
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static struct notifier_block gdth_notifier = {
|
||||
gdth_halt, NULL, 0
|
||||
};
|
||||
|
||||
static int __init gdth_init(void)
|
||||
{
|
||||
if (disable) {
|
||||
@ -5236,7 +5204,6 @@ static int __init gdth_init(void)
|
||||
add_timer(&gdth_timer);
|
||||
#endif
|
||||
major = register_chrdev(0,"gdth", &gdth_fops);
|
||||
notifier_disabled = 0;
|
||||
register_reboot_notifier(&gdth_notifier);
|
||||
gdth_polling = FALSE;
|
||||
return 0;
|
||||
@ -5246,14 +5213,15 @@ static void __exit gdth_exit(void)
|
||||
{
|
||||
gdth_ha_str *ha;
|
||||
|
||||
list_for_each_entry(ha, &gdth_instances, list)
|
||||
gdth_remove_one(ha);
|
||||
unregister_chrdev(major, "gdth");
|
||||
unregister_reboot_notifier(&gdth_notifier);
|
||||
|
||||
#ifdef GDTH_STATISTICS
|
||||
del_timer(&gdth_timer);
|
||||
del_timer_sync(&gdth_timer);
|
||||
#endif
|
||||
unregister_chrdev(major,"gdth");
|
||||
unregister_reboot_notifier(&gdth_notifier);
|
||||
|
||||
list_for_each_entry(ha, &gdth_instances, list)
|
||||
gdth_remove_one(ha);
|
||||
}
|
||||
|
||||
module_init(gdth_init);
|
||||
|
@ -915,6 +915,7 @@ typedef struct {
|
||||
struct gdth_cmndinfo { /* per-command private info */
|
||||
int index;
|
||||
int internal_command; /* don't call scsi_done */
|
||||
gdth_cmd_str *internal_cmd_str; /* crier for internal messages*/
|
||||
dma_addr_t sense_paddr; /* sense dma-addr */
|
||||
unchar priority;
|
||||
int timeout;
|
||||
|
@ -290,7 +290,7 @@ static int ibmvstgt_cmd_done(struct scsi_cmnd *sc,
|
||||
int err = 0;
|
||||
|
||||
dprintk("%p %p %x %u\n", iue, target, vio_iu(iue)->srp.cmd.cdb[0],
|
||||
cmd->usg_sg);
|
||||
scsi_sg_count(sc));
|
||||
|
||||
if (scsi_sg_count(sc))
|
||||
err = srp_transfer_data(sc, &vio_iu(iue)->srp.cmd, ibmvstgt_rdma, 1, 1);
|
||||
@ -838,9 +838,6 @@ static int ibmvstgt_probe(struct vio_dev *dev, const struct vio_device_id *id)
|
||||
if (!shost)
|
||||
goto free_vport;
|
||||
shost->transportt = ibmvstgt_transport_template;
|
||||
err = scsi_tgt_alloc_queue(shost);
|
||||
if (err)
|
||||
goto put_host;
|
||||
|
||||
target = host_to_srp_target(shost);
|
||||
target->shost = shost;
|
||||
@ -872,6 +869,10 @@ static int ibmvstgt_probe(struct vio_dev *dev, const struct vio_device_id *id)
|
||||
if (err)
|
||||
goto destroy_queue;
|
||||
|
||||
err = scsi_tgt_alloc_queue(shost);
|
||||
if (err)
|
||||
goto destroy_queue;
|
||||
|
||||
return 0;
|
||||
destroy_queue:
|
||||
crq_queue_destroy(target);
|
||||
|
@ -1708,8 +1708,8 @@ iscsi_session_setup(struct iscsi_transport *iscsit,
|
||||
qdepth = ISCSI_DEF_CMD_PER_LUN;
|
||||
}
|
||||
|
||||
if (!is_power_of_2(cmds_max) ||
|
||||
cmds_max >= ISCSI_MGMT_ITT_OFFSET) {
|
||||
if (!is_power_of_2(cmds_max) || cmds_max >= ISCSI_MGMT_ITT_OFFSET ||
|
||||
cmds_max < 2) {
|
||||
if (cmds_max != 0)
|
||||
printk(KERN_ERR "iscsi: invalid can_queue of %d. "
|
||||
"can_queue must be a power of 2 and between "
|
||||
|
@ -236,12 +236,12 @@ static void sas_ata_phy_reset(struct ata_port *ap)
|
||||
struct domain_device *dev = ap->private_data;
|
||||
struct sas_internal *i =
|
||||
to_sas_internal(dev->port->ha->core.shost->transportt);
|
||||
int res = 0;
|
||||
int res = TMF_RESP_FUNC_FAILED;
|
||||
|
||||
if (i->dft->lldd_I_T_nexus_reset)
|
||||
res = i->dft->lldd_I_T_nexus_reset(dev);
|
||||
|
||||
if (res)
|
||||
if (res != TMF_RESP_FUNC_COMPLETE)
|
||||
SAS_DPRINTK("%s: Unable to reset I T nexus?\n", __FUNCTION__);
|
||||
|
||||
switch (dev->sata_dev.command_set) {
|
||||
@ -656,21 +656,6 @@ out:
|
||||
return res;
|
||||
}
|
||||
|
||||
static void sas_sata_propagate_sas_addr(struct domain_device *dev)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct asd_sas_port *port = dev->port;
|
||||
struct asd_sas_phy *phy;
|
||||
|
||||
BUG_ON(dev->parent);
|
||||
|
||||
memcpy(port->attached_sas_addr, dev->sas_addr, SAS_ADDR_SIZE);
|
||||
spin_lock_irqsave(&port->phy_list_lock, flags);
|
||||
list_for_each_entry(phy, &port->phy_list, port_phy_el)
|
||||
memcpy(phy->attached_sas_addr, dev->sas_addr, SAS_ADDR_SIZE);
|
||||
spin_unlock_irqrestore(&port->phy_list_lock, flags);
|
||||
}
|
||||
|
||||
#define ATA_IDENTIFY_DEV 0xEC
|
||||
#define ATA_IDENTIFY_PACKET_DEV 0xA1
|
||||
#define ATA_SET_FEATURES 0xEF
|
||||
@ -728,26 +713,6 @@ static int sas_discover_sata_dev(struct domain_device *dev)
|
||||
goto out_err;
|
||||
}
|
||||
cont1:
|
||||
/* Get WWN */
|
||||
if (dev->port->oob_mode != SATA_OOB_MODE) {
|
||||
memcpy(dev->sas_addr, dev->sata_dev.rps_resp.rps.stp_sas_addr,
|
||||
SAS_ADDR_SIZE);
|
||||
} else if (dev->sata_dev.command_set == ATA_COMMAND_SET &&
|
||||
(le16_to_cpu(dev->sata_dev.identify_device[108]) & 0xF000)
|
||||
== 0x5000) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
dev->sas_addr[2*i] =
|
||||
(le16_to_cpu(dev->sata_dev.identify_device[108+i]) & 0xFF00) >> 8;
|
||||
dev->sas_addr[2*i+1] =
|
||||
le16_to_cpu(dev->sata_dev.identify_device[108+i]) & 0x00FF;
|
||||
}
|
||||
}
|
||||
sas_hash_addr(dev->hashed_sas_addr, dev->sas_addr);
|
||||
if (!dev->parent)
|
||||
sas_sata_propagate_sas_addr(dev);
|
||||
|
||||
/* XXX Hint: register this SATA device with SATL.
|
||||
When this returns, dev->sata_dev->lu is alive and
|
||||
present.
|
||||
|
@ -92,9 +92,6 @@ static void sas_form_port(struct asd_sas_phy *phy)
|
||||
if (!port->phy)
|
||||
port->phy = phy->phy;
|
||||
|
||||
SAS_DPRINTK("phy%d added to port%d, phy_mask:0x%x\n", phy->id,
|
||||
port->id, port->phy_mask);
|
||||
|
||||
if (*(u64 *)port->attached_sas_addr == 0) {
|
||||
port->class = phy->class;
|
||||
memcpy(port->attached_sas_addr, phy->attached_sas_addr,
|
||||
@ -115,6 +112,11 @@ static void sas_form_port(struct asd_sas_phy *phy)
|
||||
}
|
||||
sas_port_add_phy(port->port, phy->phy);
|
||||
|
||||
SAS_DPRINTK("%s added to %s, phy_mask:0x%x (%16llx)\n",
|
||||
phy->phy->dev.bus_id,port->port->dev.bus_id,
|
||||
port->phy_mask,
|
||||
SAS_ADDR(port->attached_sas_addr));
|
||||
|
||||
if (port->port_dev)
|
||||
port->port_dev->pathways = port->num_phys;
|
||||
|
||||
@ -255,12 +257,11 @@ void sas_porte_hard_reset(struct work_struct *work)
|
||||
static void sas_init_port(struct asd_sas_port *port,
|
||||
struct sas_ha_struct *sas_ha, int i)
|
||||
{
|
||||
memset(port, 0, sizeof(*port));
|
||||
port->id = i;
|
||||
INIT_LIST_HEAD(&port->dev_list);
|
||||
spin_lock_init(&port->phy_list_lock);
|
||||
INIT_LIST_HEAD(&port->phy_list);
|
||||
port->num_phys = 0;
|
||||
port->phy_mask = 0;
|
||||
port->ha = sas_ha;
|
||||
|
||||
spin_lock_init(&port->dev_list_lock);
|
||||
|
@ -434,7 +434,7 @@ static int sas_recover_I_T(struct domain_device *dev)
|
||||
}
|
||||
|
||||
/* Find the sas_phy that's attached to this device */
|
||||
static struct sas_phy *find_local_sas_phy(struct domain_device *dev)
|
||||
struct sas_phy *sas_find_local_phy(struct domain_device *dev)
|
||||
{
|
||||
struct domain_device *pdev = dev->parent;
|
||||
struct ex_phy *exphy = NULL;
|
||||
@ -456,6 +456,7 @@ static struct sas_phy *find_local_sas_phy(struct domain_device *dev)
|
||||
BUG_ON(!exphy);
|
||||
return exphy->phy;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sas_find_local_phy);
|
||||
|
||||
/* Attempt to send a LUN reset message to a device */
|
||||
int sas_eh_device_reset_handler(struct scsi_cmnd *cmd)
|
||||
@ -482,7 +483,7 @@ int sas_eh_device_reset_handler(struct scsi_cmnd *cmd)
|
||||
int sas_eh_bus_reset_handler(struct scsi_cmnd *cmd)
|
||||
{
|
||||
struct domain_device *dev = cmd_to_domain_dev(cmd);
|
||||
struct sas_phy *phy = find_local_sas_phy(dev);
|
||||
struct sas_phy *phy = sas_find_local_phy(dev);
|
||||
int res;
|
||||
|
||||
res = sas_phy_reset(phy, 1);
|
||||
@ -497,10 +498,10 @@ int sas_eh_bus_reset_handler(struct scsi_cmnd *cmd)
|
||||
}
|
||||
|
||||
/* Try to reset a device */
|
||||
static int try_to_reset_cmd_device(struct Scsi_Host *shost,
|
||||
struct scsi_cmnd *cmd)
|
||||
static int try_to_reset_cmd_device(struct scsi_cmnd *cmd)
|
||||
{
|
||||
int res;
|
||||
struct Scsi_Host *shost = cmd->device->host;
|
||||
|
||||
if (!shost->hostt->eh_device_reset_handler)
|
||||
goto try_bus_reset;
|
||||
@ -540,6 +541,12 @@ Again:
|
||||
need_reset = task->task_state_flags & SAS_TASK_NEED_DEV_RESET;
|
||||
spin_unlock_irqrestore(&task->task_state_lock, flags);
|
||||
|
||||
if (need_reset) {
|
||||
SAS_DPRINTK("%s: task 0x%p requests reset\n",
|
||||
__FUNCTION__, task);
|
||||
goto reset;
|
||||
}
|
||||
|
||||
SAS_DPRINTK("trying to find task 0x%p\n", task);
|
||||
res = sas_scsi_find_task(task);
|
||||
|
||||
@ -550,18 +557,15 @@ Again:
|
||||
SAS_DPRINTK("%s: task 0x%p is done\n", __FUNCTION__,
|
||||
task);
|
||||
sas_eh_finish_cmd(cmd);
|
||||
if (need_reset)
|
||||
try_to_reset_cmd_device(shost, cmd);
|
||||
continue;
|
||||
case TASK_IS_ABORTED:
|
||||
SAS_DPRINTK("%s: task 0x%p is aborted\n",
|
||||
__FUNCTION__, task);
|
||||
sas_eh_finish_cmd(cmd);
|
||||
if (need_reset)
|
||||
try_to_reset_cmd_device(shost, cmd);
|
||||
continue;
|
||||
case TASK_IS_AT_LU:
|
||||
SAS_DPRINTK("task 0x%p is at LU: lu recover\n", task);
|
||||
reset:
|
||||
tmf_resp = sas_recover_lu(task->dev, cmd);
|
||||
if (tmf_resp == TMF_RESP_FUNC_COMPLETE) {
|
||||
SAS_DPRINTK("dev %016llx LU %x is "
|
||||
@ -569,8 +573,6 @@ Again:
|
||||
SAS_ADDR(task->dev),
|
||||
cmd->device->lun);
|
||||
sas_eh_finish_cmd(cmd);
|
||||
if (need_reset)
|
||||
try_to_reset_cmd_device(shost, cmd);
|
||||
sas_scsi_clear_queue_lu(work_q, cmd);
|
||||
goto Again;
|
||||
}
|
||||
@ -581,15 +583,15 @@ Again:
|
||||
task);
|
||||
tmf_resp = sas_recover_I_T(task->dev);
|
||||
if (tmf_resp == TMF_RESP_FUNC_COMPLETE) {
|
||||
struct domain_device *dev = task->dev;
|
||||
SAS_DPRINTK("I_T %016llx recovered\n",
|
||||
SAS_ADDR(task->dev->sas_addr));
|
||||
sas_eh_finish_cmd(cmd);
|
||||
if (need_reset)
|
||||
try_to_reset_cmd_device(shost, cmd);
|
||||
sas_scsi_clear_queue_I_T(work_q, task->dev);
|
||||
sas_scsi_clear_queue_I_T(work_q, dev);
|
||||
goto Again;
|
||||
}
|
||||
/* Hammer time :-) */
|
||||
try_to_reset_cmd_device(cmd);
|
||||
if (i->dft->lldd_clear_nexus_port) {
|
||||
struct asd_sas_port *port = task->dev->port;
|
||||
SAS_DPRINTK("clearing nexus for port:%d\n",
|
||||
@ -599,8 +601,6 @@ Again:
|
||||
SAS_DPRINTK("clear nexus port:%d "
|
||||
"succeeded\n", port->id);
|
||||
sas_eh_finish_cmd(cmd);
|
||||
if (need_reset)
|
||||
try_to_reset_cmd_device(shost, cmd);
|
||||
sas_scsi_clear_queue_port(work_q,
|
||||
port);
|
||||
goto Again;
|
||||
@ -613,8 +613,6 @@ Again:
|
||||
SAS_DPRINTK("clear nexus ha "
|
||||
"succeeded\n");
|
||||
sas_eh_finish_cmd(cmd);
|
||||
if (need_reset)
|
||||
try_to_reset_cmd_device(shost, cmd);
|
||||
goto clear_q;
|
||||
}
|
||||
}
|
||||
@ -628,8 +626,6 @@ Again:
|
||||
cmd->device->lun);
|
||||
|
||||
sas_eh_finish_cmd(cmd);
|
||||
if (need_reset)
|
||||
try_to_reset_cmd_device(shost, cmd);
|
||||
goto clear_q;
|
||||
}
|
||||
}
|
||||
|
@ -40,7 +40,7 @@
|
||||
#include <asm/io.h>
|
||||
|
||||
#define DRV_NAME "mvsas"
|
||||
#define DRV_VERSION "0.5"
|
||||
#define DRV_VERSION "0.5.1"
|
||||
#define _MV_DUMP 0
|
||||
#define MVS_DISABLE_NVRAM
|
||||
#define MVS_DISABLE_MSI
|
||||
@ -1005,7 +1005,7 @@ err_out:
|
||||
return rc;
|
||||
#else
|
||||
/* FIXME , For SAS target mode */
|
||||
memcpy(buf, "\x00\x00\xab\x11\x30\x04\x05\x50", 8);
|
||||
memcpy(buf, "\x50\x05\x04\x30\x11\xab\x00\x00", 8);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
@ -1330,7 +1330,7 @@ static int mvs_int_rx(struct mvs_info *mvi, bool self_clear)
|
||||
|
||||
mvs_hba_cq_dump(mvi);
|
||||
|
||||
if (unlikely(rx_desc & RXQ_DONE))
|
||||
if (likely(rx_desc & RXQ_DONE))
|
||||
mvs_slot_complete(mvi, rx_desc);
|
||||
if (rx_desc & RXQ_ATTN) {
|
||||
attn = true;
|
||||
@ -2720,9 +2720,8 @@ static int __devinit mvs_hw_init(struct mvs_info *mvi)
|
||||
msleep(100);
|
||||
/* init and reset phys */
|
||||
for (i = 0; i < mvi->chip->n_phy; i++) {
|
||||
/* FIXME: is this the correct dword order? */
|
||||
u32 lo = *((u32 *)&mvi->sas_addr[0]);
|
||||
u32 hi = *((u32 *)&mvi->sas_addr[4]);
|
||||
u32 lo = be32_to_cpu(*(u32 *)&mvi->sas_addr[4]);
|
||||
u32 hi = be32_to_cpu(*(u32 *)&mvi->sas_addr[0]);
|
||||
|
||||
mvs_detect_porttype(mvi, i);
|
||||
|
||||
|
@ -124,7 +124,7 @@ static int fill_from_dev_buffer(struct scsi_cmnd *cmd, const void *buf)
|
||||
}
|
||||
req_len += sgpnt->length;
|
||||
}
|
||||
scsi_set_resid(cmd, req_len - act_len);
|
||||
scsi_set_resid(cmd, buflen - act_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -427,7 +427,7 @@ static struct scsi_host_template ps3rom_host_template = {
|
||||
.cmd_per_lun = 1,
|
||||
.emulated = 1, /* only sg driver uses this */
|
||||
.max_sectors = PS3ROM_MAX_SECTORS,
|
||||
.use_clustering = ENABLE_CLUSTERING,
|
||||
.use_clustering = DISABLE_CLUSTERING,
|
||||
.module = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
@ -39,7 +39,7 @@ qla2x00_prep_ms_iocb(scsi_qla_host_t *ha, uint32_t req_size, uint32_t rsp_size)
|
||||
ms_pkt->entry_count = 1;
|
||||
SET_TARGET_ID(ha, ms_pkt->loop_id, SIMPLE_NAME_SERVER);
|
||||
ms_pkt->control_flags = __constant_cpu_to_le16(CF_READ | CF_HEAD_TAG);
|
||||
ms_pkt->timeout = __constant_cpu_to_le16(25);
|
||||
ms_pkt->timeout = cpu_to_le16(ha->r_a_tov / 10 * 2);
|
||||
ms_pkt->cmd_dsd_count = __constant_cpu_to_le16(1);
|
||||
ms_pkt->total_dsd_count = __constant_cpu_to_le16(2);
|
||||
ms_pkt->rsp_bytecount = cpu_to_le32(rsp_size);
|
||||
@ -75,7 +75,7 @@ qla24xx_prep_ms_iocb(scsi_qla_host_t *ha, uint32_t req_size, uint32_t rsp_size)
|
||||
ct_pkt->entry_type = CT_IOCB_TYPE;
|
||||
ct_pkt->entry_count = 1;
|
||||
ct_pkt->nport_handle = __constant_cpu_to_le16(NPH_SNS);
|
||||
ct_pkt->timeout = __constant_cpu_to_le16(25);
|
||||
ct_pkt->timeout = cpu_to_le16(ha->r_a_tov / 10 * 2);
|
||||
ct_pkt->cmd_dsd_count = __constant_cpu_to_le16(1);
|
||||
ct_pkt->rsp_dsd_count = __constant_cpu_to_le16(1);
|
||||
ct_pkt->rsp_byte_count = cpu_to_le32(rsp_size);
|
||||
@ -1144,7 +1144,7 @@ qla2x00_prep_ms_fdmi_iocb(scsi_qla_host_t *ha, uint32_t req_size,
|
||||
ms_pkt->entry_count = 1;
|
||||
SET_TARGET_ID(ha, ms_pkt->loop_id, ha->mgmt_svr_loop_id);
|
||||
ms_pkt->control_flags = __constant_cpu_to_le16(CF_READ | CF_HEAD_TAG);
|
||||
ms_pkt->timeout = __constant_cpu_to_le16(59);
|
||||
ms_pkt->timeout = cpu_to_le16(ha->r_a_tov / 10 * 2);
|
||||
ms_pkt->cmd_dsd_count = __constant_cpu_to_le16(1);
|
||||
ms_pkt->total_dsd_count = __constant_cpu_to_le16(2);
|
||||
ms_pkt->rsp_bytecount = cpu_to_le32(rsp_size);
|
||||
@ -1181,7 +1181,7 @@ qla24xx_prep_ms_fdmi_iocb(scsi_qla_host_t *ha, uint32_t req_size,
|
||||
ct_pkt->entry_type = CT_IOCB_TYPE;
|
||||
ct_pkt->entry_count = 1;
|
||||
ct_pkt->nport_handle = cpu_to_le16(ha->mgmt_svr_loop_id);
|
||||
ct_pkt->timeout = __constant_cpu_to_le16(59);
|
||||
ct_pkt->timeout = cpu_to_le16(ha->r_a_tov / 10 * 2);
|
||||
ct_pkt->cmd_dsd_count = __constant_cpu_to_le16(1);
|
||||
ct_pkt->rsp_dsd_count = __constant_cpu_to_le16(1);
|
||||
ct_pkt->rsp_byte_count = cpu_to_le32(rsp_size);
|
||||
@ -1761,7 +1761,7 @@ qla24xx_prep_ms_fm_iocb(scsi_qla_host_t *ha, uint32_t req_size,
|
||||
ct_pkt->entry_type = CT_IOCB_TYPE;
|
||||
ct_pkt->entry_count = 1;
|
||||
ct_pkt->nport_handle = cpu_to_le16(ha->mgmt_svr_loop_id);
|
||||
ct_pkt->timeout = __constant_cpu_to_le16(59);
|
||||
ct_pkt->timeout = cpu_to_le16(ha->r_a_tov / 10 * 2);
|
||||
ct_pkt->cmd_dsd_count = __constant_cpu_to_le16(1);
|
||||
ct_pkt->rsp_dsd_count = __constant_cpu_to_le16(1);
|
||||
ct_pkt->rsp_byte_count = cpu_to_le32(rsp_size);
|
||||
|
@ -1733,8 +1733,8 @@ qla2x00_nvram_config(scsi_qla_host_t *ha)
|
||||
ha->login_timeout = nv->login_timeout;
|
||||
icb->login_timeout = nv->login_timeout;
|
||||
|
||||
/* Set minimum RATOV to 200 tenths of a second. */
|
||||
ha->r_a_tov = 200;
|
||||
/* Set minimum RATOV to 100 tenths of a second. */
|
||||
ha->r_a_tov = 100;
|
||||
|
||||
ha->loop_reset_delay = nv->reset_delay;
|
||||
|
||||
@ -3645,8 +3645,8 @@ qla24xx_nvram_config(scsi_qla_host_t *ha)
|
||||
ha->login_timeout = le16_to_cpu(nv->login_timeout);
|
||||
icb->login_timeout = cpu_to_le16(nv->login_timeout);
|
||||
|
||||
/* Set minimum RATOV to 200 tenths of a second. */
|
||||
ha->r_a_tov = 200;
|
||||
/* Set minimum RATOV to 100 tenths of a second. */
|
||||
ha->r_a_tov = 100;
|
||||
|
||||
ha->loop_reset_delay = nv->reset_delay;
|
||||
|
||||
@ -4022,7 +4022,8 @@ qla2x00_try_to_stop_firmware(scsi_qla_host_t *ha)
|
||||
return;
|
||||
|
||||
ret = qla2x00_stop_firmware(ha);
|
||||
for (retries = 5; ret != QLA_SUCCESS && retries ; retries--) {
|
||||
for (retries = 5; ret != QLA_SUCCESS && ret != QLA_FUNCTION_TIMEOUT &&
|
||||
retries ; retries--) {
|
||||
qla2x00_reset_chip(ha);
|
||||
if (qla2x00_chip_diag(ha) != QLA_SUCCESS)
|
||||
continue;
|
||||
|
@ -958,6 +958,11 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for overrun. */
|
||||
if (IS_FWI2_CAPABLE(ha) && comp_status == CS_COMPLETE &&
|
||||
scsi_status & SS_RESIDUAL_OVER)
|
||||
comp_status = CS_DATA_OVERRUN;
|
||||
|
||||
/*
|
||||
* Based on Host and scsi status generate status code for Linux
|
||||
*/
|
||||
|
@ -2206,7 +2206,7 @@ qla24xx_abort_target(fc_port_t *fcport)
|
||||
tsk->p.tsk.entry_type = TSK_MGMT_IOCB_TYPE;
|
||||
tsk->p.tsk.entry_count = 1;
|
||||
tsk->p.tsk.nport_handle = cpu_to_le16(fcport->loop_id);
|
||||
tsk->p.tsk.timeout = __constant_cpu_to_le16(25);
|
||||
tsk->p.tsk.timeout = cpu_to_le16(ha->r_a_tov / 10 * 2);
|
||||
tsk->p.tsk.control_flags = __constant_cpu_to_le32(TCF_TARGET_RESET);
|
||||
tsk->p.tsk.port_id[0] = fcport->d_id.b.al_pa;
|
||||
tsk->p.tsk.port_id[1] = fcport->d_id.b.area;
|
||||
|
@ -7,7 +7,7 @@
|
||||
/*
|
||||
* Driver version
|
||||
*/
|
||||
#define QLA2XXX_VERSION "8.02.00-k8"
|
||||
#define QLA2XXX_VERSION "8.02.00-k9"
|
||||
|
||||
#define QLA_DRIVER_MAJOR_VER 8
|
||||
#define QLA_DRIVER_MINOR_VER 2
|
||||
|
@ -1299,9 +1299,9 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha,
|
||||
ddb_entry->fw_ddb_device_state = state;
|
||||
/* Device is back online. */
|
||||
if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) {
|
||||
atomic_set(&ddb_entry->state, DDB_STATE_ONLINE);
|
||||
atomic_set(&ddb_entry->port_down_timer,
|
||||
ha->port_down_retry_count);
|
||||
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);
|
||||
|
@ -75,6 +75,7 @@ static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd);
|
||||
static int qla4xxx_slave_alloc(struct scsi_device *device);
|
||||
static int qla4xxx_slave_configure(struct scsi_device *device);
|
||||
static void qla4xxx_slave_destroy(struct scsi_device *sdev);
|
||||
static void qla4xxx_scan_start(struct Scsi_Host *shost);
|
||||
|
||||
static struct scsi_host_template qla4xxx_driver_template = {
|
||||
.module = THIS_MODULE,
|
||||
@ -90,6 +91,7 @@ static struct scsi_host_template qla4xxx_driver_template = {
|
||||
.slave_destroy = qla4xxx_slave_destroy,
|
||||
|
||||
.scan_finished = iscsi_scan_finished,
|
||||
.scan_start = qla4xxx_scan_start,
|
||||
|
||||
.this_id = -1,
|
||||
.cmd_per_lun = 3,
|
||||
@ -299,6 +301,18 @@ struct ddb_entry *qla4xxx_alloc_sess(struct scsi_qla_host *ha)
|
||||
return ddb_entry;
|
||||
}
|
||||
|
||||
static void qla4xxx_scan_start(struct Scsi_Host *shost)
|
||||
{
|
||||
struct scsi_qla_host *ha = shost_priv(shost);
|
||||
struct ddb_entry *ddb_entry, *ddbtemp;
|
||||
|
||||
/* finish setup of sessions that were already setup in firmware */
|
||||
list_for_each_entry_safe(ddb_entry, ddbtemp, &ha->ddb_list, list) {
|
||||
if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE)
|
||||
qla4xxx_add_sess(ddb_entry);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Timer routines
|
||||
*/
|
||||
@ -864,8 +878,9 @@ static void qla4xxx_flush_active_srbs(struct scsi_qla_host *ha)
|
||||
* qla4xxx_recover_adapter - recovers adapter after a fatal error
|
||||
* @ha: Pointer to host adapter structure.
|
||||
* @renew_ddb_list: Indicates what to do with the adapter's ddb list
|
||||
* after adapter recovery has completed.
|
||||
* 0=preserve ddb list, 1=destroy and rebuild ddb list
|
||||
*
|
||||
* renew_ddb_list value can be 0=preserve ddb list, 1=destroy and rebuild
|
||||
* ddb list.
|
||||
**/
|
||||
static int qla4xxx_recover_adapter(struct scsi_qla_host *ha,
|
||||
uint8_t renew_ddb_list)
|
||||
@ -874,6 +889,7 @@ static int qla4xxx_recover_adapter(struct scsi_qla_host *ha,
|
||||
|
||||
/* Stall incoming I/O until we are done */
|
||||
clear_bit(AF_ONLINE, &ha->flags);
|
||||
|
||||
DEBUG2(printk("scsi%ld: %s calling qla4xxx_cmd_wait\n", ha->host_no,
|
||||
__func__));
|
||||
|
||||
@ -1176,7 +1192,6 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev,
|
||||
int ret = -ENODEV, status;
|
||||
struct Scsi_Host *host;
|
||||
struct scsi_qla_host *ha;
|
||||
struct ddb_entry *ddb_entry, *ddbtemp;
|
||||
uint8_t init_retry_count = 0;
|
||||
char buf[34];
|
||||
|
||||
@ -1295,13 +1310,6 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev,
|
||||
if (ret)
|
||||
goto probe_failed;
|
||||
|
||||
/* Update transport device information for all devices. */
|
||||
list_for_each_entry_safe(ddb_entry, ddbtemp, &ha->ddb_list, list) {
|
||||
if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE)
|
||||
if (qla4xxx_add_sess(ddb_entry))
|
||||
goto remove_host;
|
||||
}
|
||||
|
||||
printk(KERN_INFO
|
||||
" QLogic iSCSI HBA Driver version: %s\n"
|
||||
" QLogic ISP%04x @ %s, host#=%ld, fw=%02d.%02d.%02d.%02d\n",
|
||||
@ -1311,10 +1319,6 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev,
|
||||
scsi_scan_host(host);
|
||||
return 0;
|
||||
|
||||
remove_host:
|
||||
qla4xxx_free_ddb_list(ha);
|
||||
scsi_remove_host(host);
|
||||
|
||||
probe_failed:
|
||||
qla4xxx_free_adapter(ha);
|
||||
scsi_host_put(ha->host);
|
||||
@ -1600,9 +1604,12 @@ static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd)
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
if (qla4xxx_recover_adapter(ha, PRESERVE_DDB_LIST) == QLA_SUCCESS) {
|
||||
/* make sure the dpc thread is stopped while we reset the hba */
|
||||
clear_bit(AF_ONLINE, &ha->flags);
|
||||
flush_workqueue(ha->dpc_thread);
|
||||
|
||||
if (qla4xxx_recover_adapter(ha, PRESERVE_DDB_LIST) == QLA_SUCCESS)
|
||||
return_status = SUCCESS;
|
||||
}
|
||||
|
||||
dev_info(&ha->pdev->dev, "HOST RESET %s.\n",
|
||||
return_status == FAILED ? "FAILED" : "SUCCEDED");
|
||||
|
@ -103,7 +103,6 @@ struct scsi_cmnd *scsi_host_get_command(struct Scsi_Host *shost,
|
||||
if (!cmd)
|
||||
goto release_rq;
|
||||
|
||||
memset(cmd, 0, sizeof(*cmd));
|
||||
cmd->sc_data_direction = data_dir;
|
||||
cmd->jiffies_at_alloc = jiffies;
|
||||
cmd->request = rq;
|
||||
@ -382,6 +381,11 @@ static int scsi_map_user_pages(struct scsi_tgt_cmd *tcmd, struct scsi_cmnd *cmd,
|
||||
scsi_release_buffers(cmd);
|
||||
goto unmap_rq;
|
||||
}
|
||||
/*
|
||||
* we use REQ_TYPE_BLOCK_PC so scsi_init_io doesn't set the
|
||||
* length for us.
|
||||
*/
|
||||
cmd->sdb.length = rq->data_len;
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -33,7 +33,7 @@
|
||||
#define ISCSI_SESSION_ATTRS 19
|
||||
#define ISCSI_CONN_ATTRS 13
|
||||
#define ISCSI_HOST_ATTRS 4
|
||||
#define ISCSI_TRANSPORT_VERSION "2.0-868"
|
||||
#define ISCSI_TRANSPORT_VERSION "2.0-869"
|
||||
|
||||
struct iscsi_internal {
|
||||
int daemon_pid;
|
||||
@ -373,24 +373,25 @@ static void session_recovery_timedout(struct work_struct *work)
|
||||
scsi_target_unblock(&session->dev);
|
||||
}
|
||||
|
||||
static void __iscsi_unblock_session(struct iscsi_cls_session *session)
|
||||
{
|
||||
if (!cancel_delayed_work(&session->recovery_work))
|
||||
flush_workqueue(iscsi_eh_timer_workq);
|
||||
scsi_target_unblock(&session->dev);
|
||||
}
|
||||
|
||||
void iscsi_unblock_session(struct iscsi_cls_session *session)
|
||||
static void __iscsi_unblock_session(struct work_struct *work)
|
||||
{
|
||||
struct iscsi_cls_session *session =
|
||||
container_of(work, struct iscsi_cls_session,
|
||||
unblock_work);
|
||||
struct Scsi_Host *shost = iscsi_session_to_shost(session);
|
||||
struct iscsi_host *ihost = shost->shost_data;
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* The recovery and unblock work get run from the same workqueue,
|
||||
* so try to cancel it if it was going to run after this unblock.
|
||||
*/
|
||||
cancel_delayed_work(&session->recovery_work);
|
||||
spin_lock_irqsave(&session->lock, flags);
|
||||
session->state = ISCSI_SESSION_LOGGED_IN;
|
||||
spin_unlock_irqrestore(&session->lock, flags);
|
||||
|
||||
__iscsi_unblock_session(session);
|
||||
/* start IO */
|
||||
scsi_target_unblock(&session->dev);
|
||||
/*
|
||||
* Only do kernel scanning if the driver is properly hooked into
|
||||
* the async scanning code (drivers like iscsi_tcp do login and
|
||||
@ -401,20 +402,43 @@ void iscsi_unblock_session(struct iscsi_cls_session *session)
|
||||
atomic_inc(&ihost->nr_scans);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* iscsi_unblock_session - set a session as logged in and start IO.
|
||||
* @session: iscsi session
|
||||
*
|
||||
* Mark a session as ready to accept IO.
|
||||
*/
|
||||
void iscsi_unblock_session(struct iscsi_cls_session *session)
|
||||
{
|
||||
queue_work(iscsi_eh_timer_workq, &session->unblock_work);
|
||||
/*
|
||||
* make sure all the events have completed before tell the driver
|
||||
* it is safe
|
||||
*/
|
||||
flush_workqueue(iscsi_eh_timer_workq);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iscsi_unblock_session);
|
||||
|
||||
void iscsi_block_session(struct iscsi_cls_session *session)
|
||||
static void __iscsi_block_session(struct work_struct *work)
|
||||
{
|
||||
struct iscsi_cls_session *session =
|
||||
container_of(work, struct iscsi_cls_session,
|
||||
block_work);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&session->lock, flags);
|
||||
session->state = ISCSI_SESSION_FAILED;
|
||||
spin_unlock_irqrestore(&session->lock, flags);
|
||||
|
||||
scsi_target_block(&session->dev);
|
||||
queue_delayed_work(iscsi_eh_timer_workq, &session->recovery_work,
|
||||
session->recovery_tmo * HZ);
|
||||
}
|
||||
|
||||
void iscsi_block_session(struct iscsi_cls_session *session)
|
||||
{
|
||||
queue_work(iscsi_eh_timer_workq, &session->block_work);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iscsi_block_session);
|
||||
|
||||
static void __iscsi_unbind_session(struct work_struct *work)
|
||||
@ -463,6 +487,8 @@ iscsi_alloc_session(struct Scsi_Host *shost,
|
||||
INIT_DELAYED_WORK(&session->recovery_work, session_recovery_timedout);
|
||||
INIT_LIST_HEAD(&session->host_list);
|
||||
INIT_LIST_HEAD(&session->sess_list);
|
||||
INIT_WORK(&session->unblock_work, __iscsi_unblock_session);
|
||||
INIT_WORK(&session->block_work, __iscsi_block_session);
|
||||
INIT_WORK(&session->unbind_work, __iscsi_unbind_session);
|
||||
INIT_WORK(&session->scan_work, iscsi_scan_session);
|
||||
spin_lock_init(&session->lock);
|
||||
@ -575,24 +601,25 @@ void iscsi_remove_session(struct iscsi_cls_session *session)
|
||||
list_del(&session->sess_list);
|
||||
spin_unlock_irqrestore(&sesslock, flags);
|
||||
|
||||
/* make sure there are no blocks/unblocks queued */
|
||||
flush_workqueue(iscsi_eh_timer_workq);
|
||||
/* make sure the timedout callout is not running */
|
||||
if (!cancel_delayed_work(&session->recovery_work))
|
||||
flush_workqueue(iscsi_eh_timer_workq);
|
||||
/*
|
||||
* If we are blocked let commands flow again. The lld or iscsi
|
||||
* layer should set up the queuecommand to fail commands.
|
||||
* We assume that LLD will not be calling block/unblock while
|
||||
* removing the session.
|
||||
*/
|
||||
spin_lock_irqsave(&session->lock, flags);
|
||||
session->state = ISCSI_SESSION_FREE;
|
||||
spin_unlock_irqrestore(&session->lock, flags);
|
||||
__iscsi_unblock_session(session);
|
||||
__iscsi_unbind_session(&session->unbind_work);
|
||||
|
||||
/* flush running scans */
|
||||
scsi_target_unblock(&session->dev);
|
||||
/* flush running scans then delete devices */
|
||||
flush_workqueue(ihost->scan_workq);
|
||||
/*
|
||||
* If the session dropped while removing devices then we need to make
|
||||
* sure it is not blocked
|
||||
*/
|
||||
if (!cancel_delayed_work(&session->recovery_work))
|
||||
flush_workqueue(iscsi_eh_timer_workq);
|
||||
__iscsi_unbind_session(&session->unbind_work);
|
||||
|
||||
/* hw iscsi may not have removed all connections from session */
|
||||
err = device_for_each_child(&session->dev, NULL,
|
||||
@ -802,23 +829,16 @@ EXPORT_SYMBOL_GPL(iscsi_recv_pdu);
|
||||
|
||||
void iscsi_conn_error(struct iscsi_cls_conn *conn, enum iscsi_err error)
|
||||
{
|
||||
struct iscsi_cls_session *session = iscsi_conn_to_session(conn);
|
||||
struct nlmsghdr *nlh;
|
||||
struct sk_buff *skb;
|
||||
struct iscsi_uevent *ev;
|
||||
struct iscsi_internal *priv;
|
||||
int len = NLMSG_SPACE(sizeof(*ev));
|
||||
unsigned long flags;
|
||||
|
||||
priv = iscsi_if_transport_lookup(conn->transport);
|
||||
if (!priv)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&session->lock, flags);
|
||||
if (session->state == ISCSI_SESSION_LOGGED_IN)
|
||||
session->state = ISCSI_SESSION_FAILED;
|
||||
spin_unlock_irqrestore(&session->lock, flags);
|
||||
|
||||
skb = alloc_skb(len, GFP_ATOMIC);
|
||||
if (!skb) {
|
||||
iscsi_cls_conn_printk(KERN_ERR, conn, "gracefully ignored "
|
||||
|
@ -675,5 +675,6 @@ extern int sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
|
||||
|
||||
extern void sas_ssp_task_response(struct device *dev, struct sas_task *task,
|
||||
struct ssp_response_iu *iu);
|
||||
struct sas_phy *sas_find_local_phy(struct domain_device *dev);
|
||||
|
||||
#endif /* _SASLIB_H_ */
|
||||
|
@ -177,6 +177,8 @@ struct iscsi_cls_session {
|
||||
struct list_head host_list;
|
||||
struct iscsi_transport *transport;
|
||||
spinlock_t lock;
|
||||
struct work_struct block_work;
|
||||
struct work_struct unblock_work;
|
||||
struct work_struct scan_work;
|
||||
struct work_struct unbind_work;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user