Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 360254
b: refs/heads/master
c: a0bf1ca
h: refs/heads/master
v: v3
  • Loading branch information
Hiral Patel authored and James Bottomley committed Feb 22, 2013
1 parent 6f9b538 commit f8ec690
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 8 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: cfe16d5da88896fc78d008c96d639cf9c90850a0
refs/heads/master: a0bf1ca27b644c1c4b1f0ea2d81f99471b2549e8
2 changes: 2 additions & 0 deletions trunk/drivers/scsi/fnic/fnic.h
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,8 @@ const char *fnic_state_to_str(unsigned int state);
void fnic_log_q_error(struct fnic *fnic);
void fnic_handle_link_event(struct fnic *fnic);

int fnic_is_abts_pending(struct fnic *, struct scsi_cmnd *);

static inline int
fnic_chk_state_flags_locked(struct fnic *fnic, unsigned long st_flags)
{
Expand Down
121 changes: 114 additions & 7 deletions trunk/drivers/scsi/fnic/fnic_scsi.c
Original file line number Diff line number Diff line change
Expand Up @@ -1271,7 +1271,8 @@ static void fnic_rport_exch_reset(struct fnic *fnic, u32 port_id)
spin_unlock_irqrestore(io_lock, flags);
} else {
spin_lock_irqsave(io_lock, flags);
CMD_FLAGS(sc) |= FNIC_DEV_RST_TERM_ISSUED;
if (CMD_FLAGS(sc) & FNIC_DEVICE_RESET)
CMD_FLAGS(sc) |= FNIC_DEV_RST_TERM_ISSUED;
spin_unlock_irqrestore(io_lock, flags);
}
}
Expand Down Expand Up @@ -1379,7 +1380,8 @@ void fnic_terminate_rport_io(struct fc_rport *rport)
spin_unlock_irqrestore(io_lock, flags);
} else {
spin_lock_irqsave(io_lock, flags);
CMD_FLAGS(sc) |= FNIC_DEV_RST_TERM_ISSUED;
if (CMD_FLAGS(sc) & FNIC_DEVICE_RESET)
CMD_FLAGS(sc) |= FNIC_DEV_RST_TERM_ISSUED;
spin_unlock_irqrestore(io_lock, flags);
}
}
Expand Down Expand Up @@ -1592,7 +1594,7 @@ static inline int fnic_queue_dr_io_req(struct fnic *fnic,
static int fnic_clean_pending_aborts(struct fnic *fnic,
struct scsi_cmnd *lr_sc)
{
int tag;
int tag, abt_tag;
struct fnic_io_req *io_req;
spinlock_t *io_lock;
unsigned long flags;
Expand All @@ -1601,6 +1603,7 @@ static int fnic_clean_pending_aborts(struct fnic *fnic,
struct scsi_lun fc_lun;
struct scsi_device *lun_dev = lr_sc->device;
DECLARE_COMPLETION_ONSTACK(tm_done);
enum fnic_ioreq_state old_ioreq_state;

for (tag = 0; tag < FNIC_MAX_IO_REQ; tag++) {
sc = scsi_host_find_tag(fnic->lport->host, tag);
Expand Down Expand Up @@ -1629,7 +1632,41 @@ static int fnic_clean_pending_aborts(struct fnic *fnic,
"Found IO in %s on lun\n",
fnic_ioreq_state_to_str(CMD_STATE(sc)));

BUG_ON(CMD_STATE(sc) != FNIC_IOREQ_ABTS_PENDING);
if (CMD_STATE(sc) == FNIC_IOREQ_ABTS_PENDING) {
spin_unlock_irqrestore(io_lock, flags);
continue;
}
if ((CMD_FLAGS(sc) & FNIC_DEVICE_RESET) &&
(!(CMD_FLAGS(sc) & FNIC_DEV_RST_PENDING))) {
FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host,
"%s dev rst not pending sc 0x%p\n", __func__,
sc);
spin_unlock_irqrestore(io_lock, flags);
continue;
}
old_ioreq_state = CMD_STATE(sc);
/*
* Any pending IO issued prior to reset is expected to be
* in abts pending state, if not we need to set
* FNIC_IOREQ_ABTS_PENDING to indicate the IO is abort pending.
* When IO is completed, the IO will be handed over and
* handled in this function.
*/
CMD_STATE(sc) = FNIC_IOREQ_ABTS_PENDING;

if (io_req->abts_done)
shost_printk(KERN_ERR, fnic->lport->host,
"%s: io_req->abts_done is set state is %s\n",
__func__, fnic_ioreq_state_to_str(CMD_STATE(sc)));

BUG_ON(io_req->abts_done);

abt_tag = tag;
if (CMD_FLAGS(sc) & FNIC_DEVICE_RESET) {
abt_tag |= FNIC_TAG_DEV_RST;
FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host,
"%s: dev rst sc 0x%p\n", __func__, sc);
}

CMD_ABTS_STATUS(sc) = FCPIO_INVALID_CODE;
io_req->abts_done = &tm_done;
Expand All @@ -1638,16 +1675,23 @@ static int fnic_clean_pending_aborts(struct fnic *fnic,
/* Now queue the abort command to firmware */
int_to_scsilun(sc->device->lun, &fc_lun);

if (fnic_queue_abort_io_req(fnic, tag,
if (fnic_queue_abort_io_req(fnic, abt_tag,
FCPIO_ITMF_ABT_TASK_TERM,
fc_lun.scsi_lun, io_req)) {
spin_lock_irqsave(io_lock, flags);
io_req = (struct fnic_io_req *)CMD_SP(sc);
if (io_req)
io_req->abts_done = NULL;
if (CMD_STATE(sc) == FNIC_IOREQ_ABTS_PENDING)
CMD_STATE(sc) = old_ioreq_state;
spin_unlock_irqrestore(io_lock, flags);
ret = 1;
goto clean_pending_aborts_end;
} else {
spin_lock_irqsave(io_lock, flags);
if (CMD_FLAGS(sc) & FNIC_DEVICE_RESET)
CMD_FLAGS(sc) |= FNIC_DEV_RST_TERM_ISSUED;
spin_unlock_irqrestore(io_lock, flags);
}

wait_for_completion_timeout(&tm_done,
Expand All @@ -1659,8 +1703,7 @@ static int fnic_clean_pending_aborts(struct fnic *fnic,
io_req = (struct fnic_io_req *)CMD_SP(sc);
if (!io_req) {
spin_unlock_irqrestore(io_lock, flags);
ret = 1;
goto clean_pending_aborts_end;
continue;
}

io_req->abts_done = NULL;
Expand All @@ -1678,6 +1721,12 @@ static int fnic_clean_pending_aborts(struct fnic *fnic,
mempool_free(io_req, fnic->io_req_pool);
}

schedule_timeout(msecs_to_jiffies(2 * fnic->config.ed_tov));

/* walk again to check, if IOs are still pending in fw */
if (fnic_is_abts_pending(fnic, lr_sc))
ret = FAILED;

clean_pending_aborts_end:
return ret;
}
Expand Down Expand Up @@ -2142,3 +2191,61 @@ void fnic_exch_mgr_reset(struct fc_lport *lp, u32 sid, u32 did)
fc_exch_mgr_reset(lp, sid, did);

}

/*
* fnic_is_abts_pending() is a helper function that
* walks through tag map to check if there is any IOs pending,if there is one,
* then it returns 1 (true), otherwise 0 (false)
* if @lr_sc is non NULL, then it checks IOs specific to particular LUN,
* otherwise, it checks for all IOs.
*/
int fnic_is_abts_pending(struct fnic *fnic, struct scsi_cmnd *lr_sc)
{
int tag;
struct fnic_io_req *io_req;
spinlock_t *io_lock;
unsigned long flags;
int ret = 0;
struct scsi_cmnd *sc;
struct scsi_device *lun_dev = NULL;

if (lr_sc)
lun_dev = lr_sc->device;

/* walk again to check, if IOs are still pending in fw */
for (tag = 0; tag < FNIC_MAX_IO_REQ; tag++) {
sc = scsi_host_find_tag(fnic->lport->host, tag);
/*
* ignore this lun reset cmd or cmds that do not belong to
* this lun
*/
if (!sc || (lr_sc && (sc->device != lun_dev || sc == lr_sc)))
continue;

io_lock = fnic_io_lock_hash(fnic, sc);
spin_lock_irqsave(io_lock, flags);

io_req = (struct fnic_io_req *)CMD_SP(sc);

if (!io_req || sc->device != lun_dev) {
spin_unlock_irqrestore(io_lock, flags);
continue;
}

/*
* Found IO that is still pending with firmware and
* belongs to the LUN that we are resetting
*/
FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host,
"Found IO in %s on lun\n",
fnic_ioreq_state_to_str(CMD_STATE(sc)));

if (CMD_STATE(sc) == FNIC_IOREQ_ABTS_PENDING) {
spin_unlock_irqrestore(io_lock, flags);
ret = 1;
continue;
}
}

return ret;
}

0 comments on commit f8ec690

Please sign in to comment.