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:
Linus Torvalds 2008-03-05 17:49:59 -08:00
commit 103926c689
28 changed files with 385 additions and 327 deletions

View file

@ -109,4 +109,10 @@
** 8.replace pci_alloc_consistent()/pci_free_consistent() with kmalloc()/kfree() in arcmsr_iop_message_xfer() ** 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() ** 9. fix the release of dma memory for type B in arcmsr_free_ccb_pool()
** 10.fix the arcmsr_polling_hbb_ccbdone() ** 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>
************************************************************************** **************************************************************************

View file

@ -1701,6 +1701,11 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
if (error) if (error)
goto out_free_consistent; goto out_free_consistent;
if (!buffer->NumPhys) {
error = -ENODEV;
goto out_free_consistent;
}
/* save config data */ /* save config data */
port_info->num_phys = buffer->NumPhys; port_info->num_phys = buffer->NumPhys;
port_info->phy_info = kcalloc(port_info->num_phys, port_info->phy_info = kcalloc(port_info->num_phys,

View file

@ -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_aca(struct domain_device *, u8 *lun);
int asd_clear_task_set(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_lu_reset(struct domain_device *, u8 *lun);
int asd_I_T_nexus_reset(struct domain_device *dev);
int asd_query_task(struct sas_task *); int asd_query_task(struct sas_task *);
/* ---------- Adapter and Port management ---------- */ /* ---------- Adapter and Port management ---------- */

View file

@ -140,7 +140,7 @@ struct asd_ascb {
/* internally generated command */ /* internally generated command */
struct timer_list timer; struct timer_list timer;
struct completion completion; struct completion *completion;
u8 tag_valid:1; u8 tag_valid:1;
__be16 tag; /* error recovery only */ __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; ascb->timer.function = NULL;
init_timer(&ascb->timer); init_timer(&ascb->timer);
ascb->tc_index = -1; ascb->tc_index = -1;
init_completion(&ascb->completion);
} }
/* Must be called with the tc_index_lock held! /* Must be called with the tc_index_lock held!

View file

@ -1003,7 +1003,7 @@ static struct sas_domain_function_template aic94xx_transport_functions = {
.lldd_abort_task_set = asd_abort_task_set, .lldd_abort_task_set = asd_abort_task_set,
.lldd_clear_aca = asd_clear_aca, .lldd_clear_aca = asd_clear_aca,
.lldd_clear_task_set = asd_clear_task_set, .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_lu_reset = asd_lu_reset,
.lldd_query_task = asd_query_task, .lldd_query_task = asd_query_task,

View file

@ -343,11 +343,13 @@ Again:
task->task_state_flags &= ~SAS_TASK_AT_INITIATOR; task->task_state_flags &= ~SAS_TASK_AT_INITIATOR;
task->task_state_flags |= SAS_TASK_STATE_DONE; task->task_state_flags |= SAS_TASK_STATE_DONE;
if (unlikely((task->task_state_flags & SAS_TASK_STATE_ABORTED))) { if (unlikely((task->task_state_flags & SAS_TASK_STATE_ABORTED))) {
struct completion *completion = ascb->completion;
spin_unlock_irqrestore(&task->task_state_lock, flags); spin_unlock_irqrestore(&task->task_state_lock, flags);
ASD_DPRINTK("task 0x%p done with opcode 0x%x resp 0x%x " ASD_DPRINTK("task 0x%p done with opcode 0x%x resp 0x%x "
"stat 0x%x but aborted by upper layer!\n", "stat 0x%x but aborted by upper layer!\n",
task, opcode, ts->resp, ts->stat); task, opcode, ts->resp, ts->stat);
complete(&ascb->completion); if (completion)
complete(completion);
} else { } else {
spin_unlock_irqrestore(&task->task_state_lock, flags); spin_unlock_irqrestore(&task->task_state_lock, flags);
task->lldd_task = NULL; task->lldd_task = NULL;

View file

@ -53,50 +53,64 @@ static int asd_enqueue_internal(struct asd_ascb *ascb,
return res; 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 ---------- */ /* ---------- 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, static void asd_clear_nexus_tasklet_complete(struct asd_ascb *ascb,
struct done_list_struct *dl) struct done_list_struct *dl)
{ {
struct tasklet_completion_status *tcs = ascb->uldd_task;
ASD_DPRINTK("%s: here\n", __FUNCTION__); ASD_DPRINTK("%s: here\n", __FUNCTION__);
if (!del_timer(&ascb->timer)) { if (!del_timer(&ascb->timer)) {
ASD_DPRINTK("%s: couldn't delete timer\n", __FUNCTION__); ASD_DPRINTK("%s: couldn't delete timer\n", __FUNCTION__);
return; return;
} }
ASD_DPRINTK("%s: opcode: 0x%x\n", __FUNCTION__, dl->opcode); ASD_DPRINTK("%s: opcode: 0x%x\n", __FUNCTION__, dl->opcode);
ascb->uldd_task = (void *) (unsigned long) dl->opcode; tcs->dl_opcode = dl->opcode;
complete(&ascb->completion); complete(ascb->completion);
asd_ascb_free(ascb);
} }
static void asd_clear_nexus_timedout(unsigned long data) 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_DPRINTK("%s: here\n", __FUNCTION__);
asd_timedout_common(data); tcs->dl_opcode = TMF_RESP_FUNC_FAILED;
ascb->uldd_task = (void *) TMF_RESP_FUNC_FAILED; complete(ascb->completion);
complete(&ascb->completion);
} }
#define CLEAR_NEXUS_PRE \ #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__); \ ASD_DPRINTK("%s: PRE\n", __FUNCTION__); \
res = 1; \ res = 1; \
ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL); \ ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL); \
if (!ascb) \ if (!ascb) \
return -ENOMEM; \ return -ENOMEM; \
\ \
ascb->completion = &completion; \
ascb->uldd_task = &tcs; \
scb = ascb->scb; \ scb = ascb->scb; \
scb->header.opcode = CLEAR_NEXUS scb->header.opcode = CLEAR_NEXUS
@ -107,10 +121,11 @@ static void asd_clear_nexus_timedout(unsigned long data)
if (res) \ if (res) \
goto out_err; \ goto out_err; \
ASD_DPRINTK("%s: clear nexus posted, waiting...\n", __FUNCTION__); \ ASD_DPRINTK("%s: clear nexus posted, waiting...\n", __FUNCTION__); \
wait_for_completion(&ascb->completion); \ wait_for_completion(&completion); \
res = (int) (unsigned long) ascb->uldd_task; \ res = tcs.dl_opcode; \
if (res == TC_NO_ERROR) \ if (res == TC_NO_ERROR) \
res = TMF_RESP_FUNC_COMPLETE; \ res = TMF_RESP_FUNC_COMPLETE; \
return res; \
out_err: \ out_err: \
asd_ascb_free(ascb); \ asd_ascb_free(ascb); \
return res return res
@ -118,9 +133,6 @@ out_err: \
int asd_clear_nexus_ha(struct sas_ha_struct *sas_ha) int asd_clear_nexus_ha(struct sas_ha_struct *sas_ha)
{ {
struct asd_ha_struct *asd_ha = sas_ha->lldd_ha; struct asd_ha_struct *asd_ha = sas_ha->lldd_ha;
struct asd_ascb *ascb;
struct scb *scb;
int res;
CLEAR_NEXUS_PRE; CLEAR_NEXUS_PRE;
scb->clear_nexus.nexus = NEXUS_ADAPTER; 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) int asd_clear_nexus_port(struct asd_sas_port *port)
{ {
struct asd_ha_struct *asd_ha = port->ha->lldd_ha; struct asd_ha_struct *asd_ha = port->ha->lldd_ha;
struct asd_ascb *ascb;
struct scb *scb;
int res;
CLEAR_NEXUS_PRE; CLEAR_NEXUS_PRE;
scb->clear_nexus.nexus = NEXUS_PORT; scb->clear_nexus.nexus = NEXUS_PORT;
@ -140,29 +149,73 @@ int asd_clear_nexus_port(struct asd_sas_port *port)
CLEAR_NEXUS_POST; CLEAR_NEXUS_POST;
} }
#if 0 enum clear_nexus_phase {
static int asd_clear_nexus_I_T(struct domain_device *dev) 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_ha_struct *asd_ha = dev->port->ha->lldd_ha;
struct asd_ascb *ascb;
struct scb *scb;
int res;
CLEAR_NEXUS_PRE; CLEAR_NEXUS_PRE;
scb->clear_nexus.nexus = NEXUS_I_T; 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) scb->clear_nexus.conn_handle = cpu_to_le16((u16)(unsigned long)
dev->lldd_dev); dev->lldd_dev);
CLEAR_NEXUS_POST; 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) 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_ha_struct *asd_ha = dev->port->ha->lldd_ha;
struct asd_ascb *ascb;
struct scb *scb;
int res;
CLEAR_NEXUS_PRE; CLEAR_NEXUS_PRE;
scb->clear_nexus.nexus = NEXUS_I_T_L; 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_ha_struct *asd_ha = task->dev->port->ha->lldd_ha;
struct asd_ascb *tascb = task->lldd_task; struct asd_ascb *tascb = task->lldd_task;
struct asd_ascb *ascb;
struct scb *scb;
int res;
CLEAR_NEXUS_PRE; CLEAR_NEXUS_PRE;
scb->clear_nexus.nexus = NEXUS_TAG; 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_ha_struct *asd_ha = task->dev->port->ha->lldd_ha;
struct asd_ascb *tascb = task->lldd_task; struct asd_ascb *tascb = task->lldd_task;
struct asd_ascb *ascb;
struct scb *scb;
int res;
CLEAR_NEXUS_PRE; CLEAR_NEXUS_PRE;
scb->clear_nexus.nexus = NEXUS_TRANS_CX; 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) static void asd_tmf_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("tmf timed out\n"); ASD_DPRINTK("tmf timed out\n");
asd_timedout_common(data); tcs->tmf_state = TMF_RESP_FUNC_FAILED;
ascb->uldd_task = (void *) TMF_RESP_FUNC_FAILED; complete(ascb->completion);
complete(&ascb->completion);
} }
static int asd_get_tmf_resp_tasklet(struct asd_ascb *ascb, 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, static void asd_tmf_tasklet_complete(struct asd_ascb *ascb,
struct done_list_struct *dl) struct done_list_struct *dl)
{ {
struct tasklet_completion_status *tcs;
if (!del_timer(&ascb->timer)) if (!del_timer(&ascb->timer))
return; return;
tcs = ascb->uldd_task;
ASD_DPRINTK("tmf tasklet complete\n"); ASD_DPRINTK("tmf tasklet complete\n");
if (dl->opcode == TC_SSP_RESP) tcs->dl_opcode = dl->opcode;
ascb->uldd_task = (void *) (unsigned long)
asd_get_tmf_resp_tasklet(ascb, dl);
else
ascb->uldd_task = (void *) 0xFF00 + (unsigned long) 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) 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 res = TMF_RESP_FUNC_FAILED;
int leftover; int leftover;
struct asd_ascb *tascb = task->lldd_task; struct asd_ascb *tascb = task->lldd_task;
DECLARE_COMPLETION_ONSTACK(completion);
unsigned long flags; unsigned long flags;
tascb->completion = &completion;
ASD_DPRINTK("task not done, clearing nexus\n"); ASD_DPRINTK("task not done, clearing nexus\n");
if (tascb->tag_valid) if (tascb->tag_valid)
res = asd_clear_nexus_tag(task); res = asd_clear_nexus_tag(task);
else else
res = asd_clear_nexus_index(task); res = asd_clear_nexus_index(task);
leftover = wait_for_completion_timeout(&tascb->completion, leftover = wait_for_completion_timeout(&completion,
AIC94XX_SCB_TIMEOUT); AIC94XX_SCB_TIMEOUT);
tascb->completion = NULL;
ASD_DPRINTK("came back from clear nexus\n"); ASD_DPRINTK("came back from clear nexus\n");
spin_lock_irqsave(&task->task_state_lock, flags); spin_lock_irqsave(&task->task_state_lock, flags);
if (leftover < 1) if (leftover < 1)
@ -350,6 +407,11 @@ int asd_abort_task(struct sas_task *task)
struct asd_ascb *ascb = NULL; struct asd_ascb *ascb = NULL;
struct scb *scb; struct scb *scb;
int leftover; 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); spin_lock_irqsave(&task->task_state_lock, flags);
if (task->task_state_flags & SAS_TASK_STATE_DONE) { 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); ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL);
if (!ascb) if (!ascb)
return -ENOMEM; return -ENOMEM;
scb = ascb->scb;
ascb->uldd_task = &tcs;
ascb->completion = &completion;
scb = ascb->scb;
scb->header.opcode = SCB_ABORT_TASK; scb->header.opcode = SCB_ABORT_TASK;
switch (task->task_proto) { 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, res = asd_enqueue_internal(ascb, asd_tmf_tasklet_complete,
asd_tmf_timedout); asd_tmf_timedout);
if (res) if (res)
goto out; goto out_free;
wait_for_completion(&ascb->completion); wait_for_completion(&completion);
ASD_DPRINTK("tmf came back\n"); ASD_DPRINTK("tmf came back\n");
res = (int) (unsigned long) ascb->uldd_task; tascb->tag = tcs.tag;
tascb->tag = ascb->tag; tascb->tag_valid = tcs.tag_valid;
tascb->tag_valid = ascb->tag_valid;
spin_lock_irqsave(&task->task_state_lock, flags); spin_lock_irqsave(&task->task_state_lock, flags);
if (task->task_state_flags & SAS_TASK_STATE_DONE) { 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); spin_unlock_irqrestore(&task->task_state_lock, flags);
switch (res) { if (tcs.dl_opcode == TC_SSP_RESP) {
/* The task to be aborted has been sent to the device. /* The task to be aborted has been sent to the device.
* We got a Response IU for the ABORT TASK TMF. */ * We got a Response IU for the ABORT TASK TMF. */
case TC_NO_ERROR + 0xFF00: if (tcs.tmf_state == TMF_RESP_FUNC_COMPLETE)
case TMF_RESP_FUNC_COMPLETE: res = asd_clear_nexus(task);
case TMF_RESP_FUNC_FAILED: else
res = asd_clear_nexus(task); res = tcs.tmf_state;
break; } else if (tcs.dl_opcode == TC_NO_ERROR &&
case TMF_RESP_INVALID_FRAME: tcs.tmf_state == TMF_RESP_FUNC_FAILED) {
case TMF_RESP_OVERLAPPED_TAG: /* timeout */
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 */
res = TMF_RESP_FUNC_FAILED; res = TMF_RESP_FUNC_FAILED;
leftover = wait_for_completion_timeout(&tascb->completion, } else {
AIC94XX_SCB_TIMEOUT); /* In the following we assume that the managing layer
spin_lock_irqsave(&task->task_state_lock, flags); * will _never_ make a mistake, when issuing ABORT
if (leftover < 1) * 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; 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; res = TMF_RESP_FUNC_COMPLETE;
spin_unlock_irqrestore(&task->task_state_lock, flags); break;
goto out_done; case TF_TMF_NO_CTX: /* not in seq, or proto != SSP */
case TF_TMF_NO_TAG + 0xFF00: res = TMF_RESP_FUNC_ESUPP;
case TF_TMF_TAG_FREE + 0xFF00: /* the tag is in the free list */ break;
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;
} }
out_done: out_done:
tascb->completion = NULL;
if (res == TMF_RESP_FUNC_COMPLETE) { if (res == TMF_RESP_FUNC_COMPLETE) {
task->lldd_task = NULL; task->lldd_task = NULL;
mb(); mb();
asd_ascb_free(tascb); 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_ascb_free(ascb);
ASD_DPRINTK("task 0x%p aborted, res: 0x%x\n", task, res); ASD_DPRINTK("task 0x%p aborted, res: 0x%x\n", task, res);
return res; return res;
@ -507,6 +575,8 @@ static int asd_initiate_ssp_tmf(struct domain_device *dev, u8 *lun,
struct asd_ascb *ascb; struct asd_ascb *ascb;
int res = 1; int res = 1;
struct scb *scb; struct scb *scb;
DECLARE_COMPLETION_ONSTACK(completion);
DECLARE_TCS(tcs);
if (!(dev->tproto & SAS_PROTOCOL_SSP)) if (!(dev->tproto & SAS_PROTOCOL_SSP))
return TMF_RESP_FUNC_ESUPP; 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); ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL);
if (!ascb) if (!ascb)
return -ENOMEM; return -ENOMEM;
ascb->completion = &completion;
ascb->uldd_task = &tcs;
scb = ascb->scb; scb = ascb->scb;
if (tmf == TMF_QUERY_TASK) if (tmf == TMF_QUERY_TASK)
@ -546,31 +619,32 @@ static int asd_initiate_ssp_tmf(struct domain_device *dev, u8 *lun,
asd_tmf_timedout); asd_tmf_timedout);
if (res) if (res)
goto out_err; goto out_err;
wait_for_completion(&ascb->completion); wait_for_completion(&completion);
res = (int) (unsigned long) ascb->uldd_task;
switch (res) { switch (tcs.dl_opcode) {
case TC_NO_ERROR + 0xFF00: case TC_NO_ERROR:
res = TMF_RESP_FUNC_COMPLETE; res = TMF_RESP_FUNC_COMPLETE;
break; break;
case TF_NAK_RECV + 0xFF00: case TF_NAK_RECV:
res = TMF_RESP_INVALID_FRAME; res = TMF_RESP_INVALID_FRAME;
break; break;
case TF_TMF_TASK_DONE + 0xFF00: case TF_TMF_TASK_DONE:
res = TMF_RESP_FUNC_FAILED; res = TMF_RESP_FUNC_FAILED;
break; break;
case TF_TMF_NO_TAG + 0xFF00: case TF_TMF_NO_TAG:
case TF_TMF_TAG_FREE + 0xFF00: /* the tag is in the free list */ case TF_TMF_TAG_FREE: /* the tag is in the free list */
case TF_TMF_NO_CONN_HANDLE + 0xFF00: /* no such device */ case TF_TMF_NO_CONN_HANDLE: /* no such device */
res = TMF_RESP_FUNC_COMPLETE; res = TMF_RESP_FUNC_COMPLETE;
break; 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; res = TMF_RESP_FUNC_ESUPP;
break; break;
default: default:
/* Allow TMF response codes to propagate upwards */ /* Allow TMF response codes to propagate upwards */
res = tcs.dl_opcode;
break; break;
} }
return res;
out_err: out_err:
asd_ascb_free(ascb); asd_ascb_free(ascb);
return res; return res;

View file

@ -48,7 +48,7 @@ struct class_device_attribute;
/*The limit of outstanding scsi command that firmware can handle*/ /*The limit of outstanding scsi command that firmware can handle*/
#define ARCMSR_MAX_OUTSTANDING_CMD 256 #define ARCMSR_MAX_OUTSTANDING_CMD 256
#define ARCMSR_MAX_FREECCB_NUM 320 #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_SCSI_INITIATOR_ID 255
#define ARCMSR_MAX_XFER_SECTORS 512 #define ARCMSR_MAX_XFER_SECTORS 512
#define ARCMSR_MAX_XFER_SECTORS_B 4096 #define ARCMSR_MAX_XFER_SECTORS_B 4096

View file

@ -160,7 +160,7 @@ static void gdth_readapp_event(gdth_ha_str *ha, unchar application,
static void gdth_clear_events(void); static void gdth_clear_events(void);
static void gdth_copy_internal_data(gdth_ha_str *ha, Scsi_Cmnd *scp, 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_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); 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); unsigned int cmd, unsigned long arg);
static void gdth_flush(gdth_ha_str *ha); 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(Scsi_Cmnd *scp,void (*done)(Scsi_Cmnd *));
static int __gdth_queuecommand(gdth_ha_str *ha, struct scsi_cmnd *scp, static int __gdth_queuecommand(gdth_ha_str *ha, struct scsi_cmnd *scp,
struct gdth_cmndinfo *cmndinfo); 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.h"
#include "gdth_proc.c" #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) static gdth_ha_str *gdth_find_ha(int hanum)
{ {
gdth_ha_str *ha; 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) { for (i=0; i<GDTH_MAXCMDS; ++i) {
if (ha->cmndinfo[i].index == 0) { if (ha->cmndinfo[i].index == 0) {
priv = &ha->cmndinfo[i]; priv = &ha->cmndinfo[i];
priv->index = i+1;
memset(priv, 0, sizeof(*priv)); memset(priv, 0, sizeof(*priv));
priv->index = i+1;
break; 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); gdth_ha_str *ha = shost_priv(sdev->host);
Scsi_Cmnd *scp; Scsi_Cmnd *scp;
struct gdth_cmndinfo cmndinfo; struct gdth_cmndinfo cmndinfo;
struct scatterlist one_sg;
DECLARE_COMPLETION_ONSTACK(wait); DECLARE_COMPLETION_ONSTACK(wait);
int rval; 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. */ /* use request field to save the ptr. to completion struct. */
scp->request = (struct request *)&wait; scp->request = (struct request *)&wait;
scp->timeout_per_command = timeout*HZ; 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; scp->cmd_len = 12;
memcpy(scp->cmnd, cmnd, 12); memcpy(scp->cmnd, cmnd, 12);
cmndinfo.priority = IOCTL_PRI; cmndinfo.priority = IOCTL_PRI;
cmndinfo.internal_cmd_str = gdtcmd;
cmndinfo.internal_command = 1; cmndinfo.internal_command = 1;
TRACE(("__gdth_execute() cmd 0x%x\n", scp->cmnd[0])); 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. * buffers, kmap_atomic() as needed.
*/ */
static void gdth_copy_internal_data(gdth_ha_str *ha, Scsi_Cmnd *scp, 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 cpcount,i, max_sg = gdth_sg_count(scp);
ushort cpsum,cpnow; ushort cpsum,cpnow;
@ -2381,10 +2370,7 @@ static void gdth_copy_internal_data(gdth_ha_str *ha, Scsi_Cmnd *scp,
} }
local_irq_save(flags); local_irq_save(flags);
address = kmap_atomic(sg_page(sl), KM_BIO_SRC_IRQ) + sl->offset; address = kmap_atomic(sg_page(sl), KM_BIO_SRC_IRQ) + sl->offset;
if (to_buffer) memcpy(address, buffer, cpnow);
memcpy(buffer, address, cpnow);
else
memcpy(address, buffer, cpnow);
flush_dcache_page(sg_page(sl)); flush_dcache_page(sg_page(sl));
kunmap_atomic(address, KM_BIO_SRC_IRQ); kunmap_atomic(address, KM_BIO_SRC_IRQ);
local_irq_restore(flags); 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); strcpy(inq.vendor,ha->oem_name);
sprintf(inq.product,"Host Drive #%02d",t); sprintf(inq.product,"Host Drive #%02d",t);
strcpy(inq.revision," "); 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; break;
case REQUEST_SENSE: 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.key = NO_SENSE;
sd.info = 0; sd.info = 0;
sd.add_length= 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; break;
case MODE_SENSE: 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[0] = (SECTOR_SIZE & 0x00ff0000) >> 16;
mpd.bd.block_length[1] = (SECTOR_SIZE & 0x0000ff00) >> 8; mpd.bd.block_length[1] = (SECTOR_SIZE & 0x0000ff00) >> 8;
mpd.bd.block_length[2] = (SECTOR_SIZE & 0x000000ff); 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; break;
case READ_CAPACITY: case READ_CAPACITY:
@ -2470,7 +2456,7 @@ static int gdth_internal_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp)
else else
rdc.last_block_no = cpu_to_be32(ha->hdr[t].size-1); rdc.last_block_no = cpu_to_be32(ha->hdr[t].size-1);
rdc.block_length = cpu_to_be32(SECTOR_SIZE); 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; break;
case SERVICE_ACTION_IN: 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.last_block_no = cpu_to_be64(ha->hdr[t].size-1);
rdc16.block_length = cpu_to_be32(SECTOR_SIZE); rdc16.block_length = cpu_to_be32(SECTOR_SIZE);
gdth_copy_internal_data(ha, scp, (char*)&rdc16, gdth_copy_internal_data(ha, scp, (char*)&rdc16,
sizeof(gdth_rdcap16_data), 0); sizeof(gdth_rdcap16_data));
} else { } else {
scp->result = DID_ABORT << 16; 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) static int gdth_special_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp)
{ {
register gdth_cmd_str *cmdp; register gdth_cmd_str *cmdp;
struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp);
int cmd_index; int cmd_index;
cmdp= ha->pccb; 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) if (ha->type==GDT_EISA && ha->cmd_cnt>0)
return 0; return 0;
gdth_copy_internal_data(ha, scp, (char *)cmdp, sizeof(gdth_cmd_str), 1); *cmdp = *cmndinfo->internal_cmd_str;
cmdp->RequestBuffer = scp; cmdp->RequestBuffer = scp;
/* search free command index */ /* search free command index */
@ -3794,6 +3781,8 @@ static void gdth_timeout(ulong data)
gdth_ha_str *ha; gdth_ha_str *ha;
ulong flags; ulong flags;
BUG_ON(list_empty(&gdth_instances));
ha = list_first_entry(&gdth_instances, gdth_ha_str, list); ha = list_first_entry(&gdth_instances, gdth_ha_str, list);
spin_lock_irqsave(&ha->smp_lock, flags); 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 */ /* configure lun */
static int gdth_slave_configure(struct scsi_device *sdev) 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); scsi_remove_host(shp);
gdth_flush(ha);
if (ha->sdev) { if (ha->sdev) {
scsi_free_host_dev(ha->sdev); scsi_free_host_dev(ha->sdev);
ha->sdev = NULL; ha->sdev = NULL;
} }
gdth_flush(ha);
if (shp->irq) if (shp->irq)
free_irq(shp->irq,ha); free_irq(shp->irq,ha);
@ -5174,6 +5124,24 @@ static void gdth_remove_one(gdth_ha_str *ha)
scsi_host_put(shp); 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) static int __init gdth_init(void)
{ {
if (disable) { if (disable) {
@ -5236,7 +5204,6 @@ static int __init gdth_init(void)
add_timer(&gdth_timer); add_timer(&gdth_timer);
#endif #endif
major = register_chrdev(0,"gdth", &gdth_fops); major = register_chrdev(0,"gdth", &gdth_fops);
notifier_disabled = 0;
register_reboot_notifier(&gdth_notifier); register_reboot_notifier(&gdth_notifier);
gdth_polling = FALSE; gdth_polling = FALSE;
return 0; return 0;
@ -5246,14 +5213,15 @@ static void __exit gdth_exit(void)
{ {
gdth_ha_str *ha; gdth_ha_str *ha;
list_for_each_entry(ha, &gdth_instances, list) unregister_chrdev(major, "gdth");
gdth_remove_one(ha); unregister_reboot_notifier(&gdth_notifier);
#ifdef GDTH_STATISTICS #ifdef GDTH_STATISTICS
del_timer(&gdth_timer); del_timer_sync(&gdth_timer);
#endif #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); module_init(gdth_init);

View file

@ -915,6 +915,7 @@ typedef struct {
struct gdth_cmndinfo { /* per-command private info */ struct gdth_cmndinfo { /* per-command private info */
int index; int index;
int internal_command; /* don't call scsi_done */ 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 */ dma_addr_t sense_paddr; /* sense dma-addr */
unchar priority; unchar priority;
int timeout; int timeout;

View file

@ -290,7 +290,7 @@ static int ibmvstgt_cmd_done(struct scsi_cmnd *sc,
int err = 0; int err = 0;
dprintk("%p %p %x %u\n", iue, target, vio_iu(iue)->srp.cmd.cdb[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)) if (scsi_sg_count(sc))
err = srp_transfer_data(sc, &vio_iu(iue)->srp.cmd, ibmvstgt_rdma, 1, 1); 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) if (!shost)
goto free_vport; goto free_vport;
shost->transportt = ibmvstgt_transport_template; shost->transportt = ibmvstgt_transport_template;
err = scsi_tgt_alloc_queue(shost);
if (err)
goto put_host;
target = host_to_srp_target(shost); target = host_to_srp_target(shost);
target->shost = shost; target->shost = shost;
@ -872,6 +869,10 @@ static int ibmvstgt_probe(struct vio_dev *dev, const struct vio_device_id *id)
if (err) if (err)
goto destroy_queue; goto destroy_queue;
err = scsi_tgt_alloc_queue(shost);
if (err)
goto destroy_queue;
return 0; return 0;
destroy_queue: destroy_queue:
crq_queue_destroy(target); crq_queue_destroy(target);

View file

@ -1708,8 +1708,8 @@ iscsi_session_setup(struct iscsi_transport *iscsit,
qdepth = ISCSI_DEF_CMD_PER_LUN; qdepth = ISCSI_DEF_CMD_PER_LUN;
} }
if (!is_power_of_2(cmds_max) || if (!is_power_of_2(cmds_max) || cmds_max >= ISCSI_MGMT_ITT_OFFSET ||
cmds_max >= ISCSI_MGMT_ITT_OFFSET) { cmds_max < 2) {
if (cmds_max != 0) if (cmds_max != 0)
printk(KERN_ERR "iscsi: invalid can_queue of %d. " printk(KERN_ERR "iscsi: invalid can_queue of %d. "
"can_queue must be a power of 2 and between " "can_queue must be a power of 2 and between "

View file

@ -236,12 +236,12 @@ static void sas_ata_phy_reset(struct ata_port *ap)
struct domain_device *dev = ap->private_data; struct domain_device *dev = ap->private_data;
struct sas_internal *i = struct sas_internal *i =
to_sas_internal(dev->port->ha->core.shost->transportt); 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) if (i->dft->lldd_I_T_nexus_reset)
res = i->dft->lldd_I_T_nexus_reset(dev); 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__); SAS_DPRINTK("%s: Unable to reset I T nexus?\n", __FUNCTION__);
switch (dev->sata_dev.command_set) { switch (dev->sata_dev.command_set) {
@ -656,21 +656,6 @@ out:
return res; 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_DEV 0xEC
#define ATA_IDENTIFY_PACKET_DEV 0xA1 #define ATA_IDENTIFY_PACKET_DEV 0xA1
#define ATA_SET_FEATURES 0xEF #define ATA_SET_FEATURES 0xEF
@ -728,26 +713,6 @@ static int sas_discover_sata_dev(struct domain_device *dev)
goto out_err; goto out_err;
} }
cont1: 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. /* XXX Hint: register this SATA device with SATL.
When this returns, dev->sata_dev->lu is alive and When this returns, dev->sata_dev->lu is alive and
present. present.

View file

@ -92,9 +92,6 @@ static void sas_form_port(struct asd_sas_phy *phy)
if (!port->phy) if (!port->phy)
port->phy = phy->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) { if (*(u64 *)port->attached_sas_addr == 0) {
port->class = phy->class; port->class = phy->class;
memcpy(port->attached_sas_addr, phy->attached_sas_addr, 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_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) if (port->port_dev)
port->port_dev->pathways = port->num_phys; 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, static void sas_init_port(struct asd_sas_port *port,
struct sas_ha_struct *sas_ha, int i) struct sas_ha_struct *sas_ha, int i)
{ {
memset(port, 0, sizeof(*port));
port->id = i; port->id = i;
INIT_LIST_HEAD(&port->dev_list); INIT_LIST_HEAD(&port->dev_list);
spin_lock_init(&port->phy_list_lock); spin_lock_init(&port->phy_list_lock);
INIT_LIST_HEAD(&port->phy_list); INIT_LIST_HEAD(&port->phy_list);
port->num_phys = 0;
port->phy_mask = 0;
port->ha = sas_ha; port->ha = sas_ha;
spin_lock_init(&port->dev_list_lock); spin_lock_init(&port->dev_list_lock);

View file

@ -434,7 +434,7 @@ static int sas_recover_I_T(struct domain_device *dev)
} }
/* Find the sas_phy that's attached to this device */ /* 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 domain_device *pdev = dev->parent;
struct ex_phy *exphy = NULL; struct ex_phy *exphy = NULL;
@ -456,6 +456,7 @@ static struct sas_phy *find_local_sas_phy(struct domain_device *dev)
BUG_ON(!exphy); BUG_ON(!exphy);
return exphy->phy; return exphy->phy;
} }
EXPORT_SYMBOL_GPL(sas_find_local_phy);
/* Attempt to send a LUN reset message to a device */ /* Attempt to send a LUN reset message to a device */
int sas_eh_device_reset_handler(struct scsi_cmnd *cmd) 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) int sas_eh_bus_reset_handler(struct scsi_cmnd *cmd)
{ {
struct domain_device *dev = cmd_to_domain_dev(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; int res;
res = sas_phy_reset(phy, 1); 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 */ /* Try to reset a device */
static int try_to_reset_cmd_device(struct Scsi_Host *shost, static int try_to_reset_cmd_device(struct scsi_cmnd *cmd)
struct scsi_cmnd *cmd)
{ {
int res; int res;
struct Scsi_Host *shost = cmd->device->host;
if (!shost->hostt->eh_device_reset_handler) if (!shost->hostt->eh_device_reset_handler)
goto try_bus_reset; goto try_bus_reset;
@ -540,6 +541,12 @@ Again:
need_reset = task->task_state_flags & SAS_TASK_NEED_DEV_RESET; need_reset = task->task_state_flags & SAS_TASK_NEED_DEV_RESET;
spin_unlock_irqrestore(&task->task_state_lock, flags); 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); SAS_DPRINTK("trying to find task 0x%p\n", task);
res = sas_scsi_find_task(task); res = sas_scsi_find_task(task);
@ -550,18 +557,15 @@ Again:
SAS_DPRINTK("%s: task 0x%p is done\n", __FUNCTION__, SAS_DPRINTK("%s: task 0x%p is done\n", __FUNCTION__,
task); task);
sas_eh_finish_cmd(cmd); sas_eh_finish_cmd(cmd);
if (need_reset)
try_to_reset_cmd_device(shost, cmd);
continue; continue;
case TASK_IS_ABORTED: case TASK_IS_ABORTED:
SAS_DPRINTK("%s: task 0x%p is aborted\n", SAS_DPRINTK("%s: task 0x%p is aborted\n",
__FUNCTION__, task); __FUNCTION__, task);
sas_eh_finish_cmd(cmd); sas_eh_finish_cmd(cmd);
if (need_reset)
try_to_reset_cmd_device(shost, cmd);
continue; continue;
case TASK_IS_AT_LU: case TASK_IS_AT_LU:
SAS_DPRINTK("task 0x%p is at LU: lu recover\n", task); SAS_DPRINTK("task 0x%p is at LU: lu recover\n", task);
reset:
tmf_resp = sas_recover_lu(task->dev, cmd); tmf_resp = sas_recover_lu(task->dev, cmd);
if (tmf_resp == TMF_RESP_FUNC_COMPLETE) { if (tmf_resp == TMF_RESP_FUNC_COMPLETE) {
SAS_DPRINTK("dev %016llx LU %x is " SAS_DPRINTK("dev %016llx LU %x is "
@ -569,8 +573,6 @@ Again:
SAS_ADDR(task->dev), SAS_ADDR(task->dev),
cmd->device->lun); cmd->device->lun);
sas_eh_finish_cmd(cmd); sas_eh_finish_cmd(cmd);
if (need_reset)
try_to_reset_cmd_device(shost, cmd);
sas_scsi_clear_queue_lu(work_q, cmd); sas_scsi_clear_queue_lu(work_q, cmd);
goto Again; goto Again;
} }
@ -581,15 +583,15 @@ Again:
task); task);
tmf_resp = sas_recover_I_T(task->dev); tmf_resp = sas_recover_I_T(task->dev);
if (tmf_resp == TMF_RESP_FUNC_COMPLETE) { if (tmf_resp == TMF_RESP_FUNC_COMPLETE) {
struct domain_device *dev = task->dev;
SAS_DPRINTK("I_T %016llx recovered\n", SAS_DPRINTK("I_T %016llx recovered\n",
SAS_ADDR(task->dev->sas_addr)); SAS_ADDR(task->dev->sas_addr));
sas_eh_finish_cmd(cmd); sas_eh_finish_cmd(cmd);
if (need_reset) sas_scsi_clear_queue_I_T(work_q, dev);
try_to_reset_cmd_device(shost, cmd);
sas_scsi_clear_queue_I_T(work_q, task->dev);
goto Again; goto Again;
} }
/* Hammer time :-) */ /* Hammer time :-) */
try_to_reset_cmd_device(cmd);
if (i->dft->lldd_clear_nexus_port) { if (i->dft->lldd_clear_nexus_port) {
struct asd_sas_port *port = task->dev->port; struct asd_sas_port *port = task->dev->port;
SAS_DPRINTK("clearing nexus for port:%d\n", SAS_DPRINTK("clearing nexus for port:%d\n",
@ -599,8 +601,6 @@ Again:
SAS_DPRINTK("clear nexus port:%d " SAS_DPRINTK("clear nexus port:%d "
"succeeded\n", port->id); "succeeded\n", port->id);
sas_eh_finish_cmd(cmd); sas_eh_finish_cmd(cmd);
if (need_reset)
try_to_reset_cmd_device(shost, cmd);
sas_scsi_clear_queue_port(work_q, sas_scsi_clear_queue_port(work_q,
port); port);
goto Again; goto Again;
@ -613,8 +613,6 @@ Again:
SAS_DPRINTK("clear nexus ha " SAS_DPRINTK("clear nexus ha "
"succeeded\n"); "succeeded\n");
sas_eh_finish_cmd(cmd); sas_eh_finish_cmd(cmd);
if (need_reset)
try_to_reset_cmd_device(shost, cmd);
goto clear_q; goto clear_q;
} }
} }
@ -628,8 +626,6 @@ Again:
cmd->device->lun); cmd->device->lun);
sas_eh_finish_cmd(cmd); sas_eh_finish_cmd(cmd);
if (need_reset)
try_to_reset_cmd_device(shost, cmd);
goto clear_q; goto clear_q;
} }
} }

View file

@ -40,7 +40,7 @@
#include <asm/io.h> #include <asm/io.h>
#define DRV_NAME "mvsas" #define DRV_NAME "mvsas"
#define DRV_VERSION "0.5" #define DRV_VERSION "0.5.1"
#define _MV_DUMP 0 #define _MV_DUMP 0
#define MVS_DISABLE_NVRAM #define MVS_DISABLE_NVRAM
#define MVS_DISABLE_MSI #define MVS_DISABLE_MSI
@ -1005,7 +1005,7 @@ err_out:
return rc; return rc;
#else #else
/* FIXME , For SAS target mode */ /* 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; return 0;
#endif #endif
} }
@ -1330,7 +1330,7 @@ static int mvs_int_rx(struct mvs_info *mvi, bool self_clear)
mvs_hba_cq_dump(mvi); mvs_hba_cq_dump(mvi);
if (unlikely(rx_desc & RXQ_DONE)) if (likely(rx_desc & RXQ_DONE))
mvs_slot_complete(mvi, rx_desc); mvs_slot_complete(mvi, rx_desc);
if (rx_desc & RXQ_ATTN) { if (rx_desc & RXQ_ATTN) {
attn = true; attn = true;
@ -2720,9 +2720,8 @@ static int __devinit mvs_hw_init(struct mvs_info *mvi)
msleep(100); msleep(100);
/* init and reset phys */ /* init and reset phys */
for (i = 0; i < mvi->chip->n_phy; i++) { for (i = 0; i < mvi->chip->n_phy; i++) {
/* FIXME: is this the correct dword order? */ u32 lo = be32_to_cpu(*(u32 *)&mvi->sas_addr[4]);
u32 lo = *((u32 *)&mvi->sas_addr[0]); u32 hi = be32_to_cpu(*(u32 *)&mvi->sas_addr[0]);
u32 hi = *((u32 *)&mvi->sas_addr[4]);
mvs_detect_porttype(mvi, i); mvs_detect_porttype(mvi, i);

View file

@ -124,7 +124,7 @@ static int fill_from_dev_buffer(struct scsi_cmnd *cmd, const void *buf)
} }
req_len += sgpnt->length; req_len += sgpnt->length;
} }
scsi_set_resid(cmd, req_len - act_len); scsi_set_resid(cmd, buflen - act_len);
return 0; return 0;
} }
@ -427,7 +427,7 @@ static struct scsi_host_template ps3rom_host_template = {
.cmd_per_lun = 1, .cmd_per_lun = 1,
.emulated = 1, /* only sg driver uses this */ .emulated = 1, /* only sg driver uses this */
.max_sectors = PS3ROM_MAX_SECTORS, .max_sectors = PS3ROM_MAX_SECTORS,
.use_clustering = ENABLE_CLUSTERING, .use_clustering = DISABLE_CLUSTERING,
.module = THIS_MODULE, .module = THIS_MODULE,
}; };

View file

@ -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; ms_pkt->entry_count = 1;
SET_TARGET_ID(ha, ms_pkt->loop_id, SIMPLE_NAME_SERVER); 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->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->cmd_dsd_count = __constant_cpu_to_le16(1);
ms_pkt->total_dsd_count = __constant_cpu_to_le16(2); ms_pkt->total_dsd_count = __constant_cpu_to_le16(2);
ms_pkt->rsp_bytecount = cpu_to_le32(rsp_size); 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_type = CT_IOCB_TYPE;
ct_pkt->entry_count = 1; ct_pkt->entry_count = 1;
ct_pkt->nport_handle = __constant_cpu_to_le16(NPH_SNS); 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->cmd_dsd_count = __constant_cpu_to_le16(1);
ct_pkt->rsp_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); 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; ms_pkt->entry_count = 1;
SET_TARGET_ID(ha, ms_pkt->loop_id, ha->mgmt_svr_loop_id); 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->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->cmd_dsd_count = __constant_cpu_to_le16(1);
ms_pkt->total_dsd_count = __constant_cpu_to_le16(2); ms_pkt->total_dsd_count = __constant_cpu_to_le16(2);
ms_pkt->rsp_bytecount = cpu_to_le32(rsp_size); 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_type = CT_IOCB_TYPE;
ct_pkt->entry_count = 1; ct_pkt->entry_count = 1;
ct_pkt->nport_handle = cpu_to_le16(ha->mgmt_svr_loop_id); 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->cmd_dsd_count = __constant_cpu_to_le16(1);
ct_pkt->rsp_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); 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_type = CT_IOCB_TYPE;
ct_pkt->entry_count = 1; ct_pkt->entry_count = 1;
ct_pkt->nport_handle = cpu_to_le16(ha->mgmt_svr_loop_id); 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->cmd_dsd_count = __constant_cpu_to_le16(1);
ct_pkt->rsp_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); ct_pkt->rsp_byte_count = cpu_to_le32(rsp_size);

View file

@ -1733,8 +1733,8 @@ qla2x00_nvram_config(scsi_qla_host_t *ha)
ha->login_timeout = nv->login_timeout; ha->login_timeout = nv->login_timeout;
icb->login_timeout = nv->login_timeout; icb->login_timeout = nv->login_timeout;
/* Set minimum RATOV to 200 tenths of a second. */ /* Set minimum RATOV to 100 tenths of a second. */
ha->r_a_tov = 200; ha->r_a_tov = 100;
ha->loop_reset_delay = nv->reset_delay; 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); ha->login_timeout = le16_to_cpu(nv->login_timeout);
icb->login_timeout = cpu_to_le16(nv->login_timeout); icb->login_timeout = cpu_to_le16(nv->login_timeout);
/* Set minimum RATOV to 200 tenths of a second. */ /* Set minimum RATOV to 100 tenths of a second. */
ha->r_a_tov = 200; ha->r_a_tov = 100;
ha->loop_reset_delay = nv->reset_delay; ha->loop_reset_delay = nv->reset_delay;
@ -4022,7 +4022,8 @@ qla2x00_try_to_stop_firmware(scsi_qla_host_t *ha)
return; return;
ret = qla2x00_stop_firmware(ha); 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); qla2x00_reset_chip(ha);
if (qla2x00_chip_diag(ha) != QLA_SUCCESS) if (qla2x00_chip_diag(ha) != QLA_SUCCESS)
continue; continue;

View file

@ -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 * Based on Host and scsi status generate status code for Linux
*/ */

View file

@ -2206,7 +2206,7 @@ qla24xx_abort_target(fc_port_t *fcport)
tsk->p.tsk.entry_type = TSK_MGMT_IOCB_TYPE; tsk->p.tsk.entry_type = TSK_MGMT_IOCB_TYPE;
tsk->p.tsk.entry_count = 1; tsk->p.tsk.entry_count = 1;
tsk->p.tsk.nport_handle = cpu_to_le16(fcport->loop_id); 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.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[0] = fcport->d_id.b.al_pa;
tsk->p.tsk.port_id[1] = fcport->d_id.b.area; tsk->p.tsk.port_id[1] = fcport->d_id.b.area;

View file

@ -7,7 +7,7 @@
/* /*
* Driver version * 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_MAJOR_VER 8
#define QLA_DRIVER_MINOR_VER 2 #define QLA_DRIVER_MINOR_VER 2

View file

@ -1299,9 +1299,9 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha,
ddb_entry->fw_ddb_device_state = state; ddb_entry->fw_ddb_device_state = state;
/* Device is back online. */ /* Device is back online. */
if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) { 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, atomic_set(&ddb_entry->port_down_timer,
ha->port_down_retry_count); 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_retry_count, 0);
atomic_set(&ddb_entry->relogin_timer, 0); atomic_set(&ddb_entry->relogin_timer, 0);
clear_bit(DF_RELOGIN, &ddb_entry->flags); clear_bit(DF_RELOGIN, &ddb_entry->flags);

View file

@ -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_alloc(struct scsi_device *device);
static int qla4xxx_slave_configure(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_slave_destroy(struct scsi_device *sdev);
static void qla4xxx_scan_start(struct Scsi_Host *shost);
static struct scsi_host_template qla4xxx_driver_template = { static struct scsi_host_template qla4xxx_driver_template = {
.module = THIS_MODULE, .module = THIS_MODULE,
@ -90,6 +91,7 @@ static struct scsi_host_template qla4xxx_driver_template = {
.slave_destroy = qla4xxx_slave_destroy, .slave_destroy = qla4xxx_slave_destroy,
.scan_finished = iscsi_scan_finished, .scan_finished = iscsi_scan_finished,
.scan_start = qla4xxx_scan_start,
.this_id = -1, .this_id = -1,
.cmd_per_lun = 3, .cmd_per_lun = 3,
@ -299,6 +301,18 @@ struct ddb_entry *qla4xxx_alloc_sess(struct scsi_qla_host *ha)
return ddb_entry; 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 * 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 * qla4xxx_recover_adapter - recovers adapter after a fatal error
* @ha: Pointer to host adapter structure. * @ha: Pointer to host adapter structure.
* @renew_ddb_list: Indicates what to do with the adapter's ddb list * @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, static int qla4xxx_recover_adapter(struct scsi_qla_host *ha,
uint8_t renew_ddb_list) 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 */ /* Stall incoming I/O until we are done */
clear_bit(AF_ONLINE, &ha->flags); clear_bit(AF_ONLINE, &ha->flags);
DEBUG2(printk("scsi%ld: %s calling qla4xxx_cmd_wait\n", ha->host_no, DEBUG2(printk("scsi%ld: %s calling qla4xxx_cmd_wait\n", ha->host_no,
__func__)); __func__));
@ -1176,7 +1192,6 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev,
int ret = -ENODEV, status; int ret = -ENODEV, status;
struct Scsi_Host *host; struct Scsi_Host *host;
struct scsi_qla_host *ha; struct scsi_qla_host *ha;
struct ddb_entry *ddb_entry, *ddbtemp;
uint8_t init_retry_count = 0; uint8_t init_retry_count = 0;
char buf[34]; char buf[34];
@ -1295,13 +1310,6 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev,
if (ret) if (ret)
goto probe_failed; 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 printk(KERN_INFO
" QLogic iSCSI HBA Driver version: %s\n" " QLogic iSCSI HBA Driver version: %s\n"
" QLogic ISP%04x @ %s, host#=%ld, fw=%02d.%02d.%02d.%02d\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); scsi_scan_host(host);
return 0; return 0;
remove_host:
qla4xxx_free_ddb_list(ha);
scsi_remove_host(host);
probe_failed: probe_failed:
qla4xxx_free_adapter(ha); qla4xxx_free_adapter(ha);
scsi_host_put(ha->host); scsi_host_put(ha->host);
@ -1600,9 +1604,12 @@ static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd)
return FAILED; 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; return_status = SUCCESS;
}
dev_info(&ha->pdev->dev, "HOST RESET %s.\n", dev_info(&ha->pdev->dev, "HOST RESET %s.\n",
return_status == FAILED ? "FAILED" : "SUCCEDED"); return_status == FAILED ? "FAILED" : "SUCCEDED");

View file

@ -103,7 +103,6 @@ struct scsi_cmnd *scsi_host_get_command(struct Scsi_Host *shost,
if (!cmd) if (!cmd)
goto release_rq; goto release_rq;
memset(cmd, 0, sizeof(*cmd));
cmd->sc_data_direction = data_dir; cmd->sc_data_direction = data_dir;
cmd->jiffies_at_alloc = jiffies; cmd->jiffies_at_alloc = jiffies;
cmd->request = rq; 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); scsi_release_buffers(cmd);
goto unmap_rq; 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; return 0;

View file

@ -33,7 +33,7 @@
#define ISCSI_SESSION_ATTRS 19 #define ISCSI_SESSION_ATTRS 19
#define ISCSI_CONN_ATTRS 13 #define ISCSI_CONN_ATTRS 13
#define ISCSI_HOST_ATTRS 4 #define ISCSI_HOST_ATTRS 4
#define ISCSI_TRANSPORT_VERSION "2.0-868" #define ISCSI_TRANSPORT_VERSION "2.0-869"
struct iscsi_internal { struct iscsi_internal {
int daemon_pid; int daemon_pid;
@ -373,24 +373,25 @@ static void session_recovery_timedout(struct work_struct *work)
scsi_target_unblock(&session->dev); scsi_target_unblock(&session->dev);
} }
static void __iscsi_unblock_session(struct iscsi_cls_session *session) static void __iscsi_unblock_session(struct work_struct *work)
{
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)
{ {
struct iscsi_cls_session *session =
container_of(work, struct iscsi_cls_session,
unblock_work);
struct Scsi_Host *shost = iscsi_session_to_shost(session); struct Scsi_Host *shost = iscsi_session_to_shost(session);
struct iscsi_host *ihost = shost->shost_data; struct iscsi_host *ihost = shost->shost_data;
unsigned long flags; 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); spin_lock_irqsave(&session->lock, flags);
session->state = ISCSI_SESSION_LOGGED_IN; session->state = ISCSI_SESSION_LOGGED_IN;
spin_unlock_irqrestore(&session->lock, flags); spin_unlock_irqrestore(&session->lock, flags);
/* start IO */
__iscsi_unblock_session(session); scsi_target_unblock(&session->dev);
/* /*
* Only do kernel scanning if the driver is properly hooked into * Only do kernel scanning if the driver is properly hooked into
* the async scanning code (drivers like iscsi_tcp do login and * 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); 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); 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; unsigned long flags;
spin_lock_irqsave(&session->lock, flags); spin_lock_irqsave(&session->lock, flags);
session->state = ISCSI_SESSION_FAILED; session->state = ISCSI_SESSION_FAILED;
spin_unlock_irqrestore(&session->lock, flags); spin_unlock_irqrestore(&session->lock, flags);
scsi_target_block(&session->dev); scsi_target_block(&session->dev);
queue_delayed_work(iscsi_eh_timer_workq, &session->recovery_work, queue_delayed_work(iscsi_eh_timer_workq, &session->recovery_work,
session->recovery_tmo * HZ); 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); EXPORT_SYMBOL_GPL(iscsi_block_session);
static void __iscsi_unbind_session(struct work_struct *work) 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_DELAYED_WORK(&session->recovery_work, session_recovery_timedout);
INIT_LIST_HEAD(&session->host_list); INIT_LIST_HEAD(&session->host_list);
INIT_LIST_HEAD(&session->sess_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->unbind_work, __iscsi_unbind_session);
INIT_WORK(&session->scan_work, iscsi_scan_session); INIT_WORK(&session->scan_work, iscsi_scan_session);
spin_lock_init(&session->lock); spin_lock_init(&session->lock);
@ -575,24 +601,25 @@ void iscsi_remove_session(struct iscsi_cls_session *session)
list_del(&session->sess_list); list_del(&session->sess_list);
spin_unlock_irqrestore(&sesslock, flags); 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 * If we are blocked let commands flow again. The lld or iscsi
* layer should set up the queuecommand to fail commands. * 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); spin_lock_irqsave(&session->lock, flags);
session->state = ISCSI_SESSION_FREE; session->state = ISCSI_SESSION_FREE;
spin_unlock_irqrestore(&session->lock, flags); 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); flush_workqueue(ihost->scan_workq);
/* __iscsi_unbind_session(&session->unbind_work);
* 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);
/* hw iscsi may not have removed all connections from session */ /* hw iscsi may not have removed all connections from session */
err = device_for_each_child(&session->dev, NULL, 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) 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 nlmsghdr *nlh;
struct sk_buff *skb; struct sk_buff *skb;
struct iscsi_uevent *ev; struct iscsi_uevent *ev;
struct iscsi_internal *priv; struct iscsi_internal *priv;
int len = NLMSG_SPACE(sizeof(*ev)); int len = NLMSG_SPACE(sizeof(*ev));
unsigned long flags;
priv = iscsi_if_transport_lookup(conn->transport); priv = iscsi_if_transport_lookup(conn->transport);
if (!priv) if (!priv)
return; 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); skb = alloc_skb(len, GFP_ATOMIC);
if (!skb) { if (!skb) {
iscsi_cls_conn_printk(KERN_ERR, conn, "gracefully ignored " iscsi_cls_conn_printk(KERN_ERR, conn, "gracefully ignored "

View file

@ -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, extern void sas_ssp_task_response(struct device *dev, struct sas_task *task,
struct ssp_response_iu *iu); struct ssp_response_iu *iu);
struct sas_phy *sas_find_local_phy(struct domain_device *dev);
#endif /* _SASLIB_H_ */ #endif /* _SASLIB_H_ */

View file

@ -177,6 +177,8 @@ struct iscsi_cls_session {
struct list_head host_list; struct list_head host_list;
struct iscsi_transport *transport; struct iscsi_transport *transport;
spinlock_t lock; spinlock_t lock;
struct work_struct block_work;
struct work_struct unblock_work;
struct work_struct scan_work; struct work_struct scan_work;
struct work_struct unbind_work; struct work_struct unbind_work;