diff options
-rw-r--r-- | drivers/scsi/fnic/fnic.h | 2 | ||||
-rw-r--r-- | drivers/scsi/fnic/fnic_scsi.c | 121 |
2 files changed, 116 insertions, 7 deletions
diff --git a/drivers/scsi/fnic/fnic.h b/drivers/scsi/fnic/fnic.h index 63b35c8e40bd..b8e6644ad237 100644 --- a/drivers/scsi/fnic/fnic.h +++ b/drivers/scsi/fnic/fnic.h | |||
@@ -303,6 +303,8 @@ const char *fnic_state_to_str(unsigned int state); | |||
303 | void fnic_log_q_error(struct fnic *fnic); | 303 | void fnic_log_q_error(struct fnic *fnic); |
304 | void fnic_handle_link_event(struct fnic *fnic); | 304 | void fnic_handle_link_event(struct fnic *fnic); |
305 | 305 | ||
306 | int fnic_is_abts_pending(struct fnic *, struct scsi_cmnd *); | ||
307 | |||
306 | static inline int | 308 | static inline int |
307 | fnic_chk_state_flags_locked(struct fnic *fnic, unsigned long st_flags) | 309 | fnic_chk_state_flags_locked(struct fnic *fnic, unsigned long st_flags) |
308 | { | 310 | { |
diff --git a/drivers/scsi/fnic/fnic_scsi.c b/drivers/scsi/fnic/fnic_scsi.c index 2f46509f5b5a..64830814da0d 100644 --- a/drivers/scsi/fnic/fnic_scsi.c +++ b/drivers/scsi/fnic/fnic_scsi.c | |||
@@ -1271,7 +1271,8 @@ static void fnic_rport_exch_reset(struct fnic *fnic, u32 port_id) | |||
1271 | spin_unlock_irqrestore(io_lock, flags); | 1271 | spin_unlock_irqrestore(io_lock, flags); |
1272 | } else { | 1272 | } else { |
1273 | spin_lock_irqsave(io_lock, flags); | 1273 | spin_lock_irqsave(io_lock, flags); |
1274 | CMD_FLAGS(sc) |= FNIC_DEV_RST_TERM_ISSUED; | 1274 | if (CMD_FLAGS(sc) & FNIC_DEVICE_RESET) |
1275 | CMD_FLAGS(sc) |= FNIC_DEV_RST_TERM_ISSUED; | ||
1275 | spin_unlock_irqrestore(io_lock, flags); | 1276 | spin_unlock_irqrestore(io_lock, flags); |
1276 | } | 1277 | } |
1277 | } | 1278 | } |
@@ -1379,7 +1380,8 @@ void fnic_terminate_rport_io(struct fc_rport *rport) | |||
1379 | spin_unlock_irqrestore(io_lock, flags); | 1380 | spin_unlock_irqrestore(io_lock, flags); |
1380 | } else { | 1381 | } else { |
1381 | spin_lock_irqsave(io_lock, flags); | 1382 | spin_lock_irqsave(io_lock, flags); |
1382 | CMD_FLAGS(sc) |= FNIC_DEV_RST_TERM_ISSUED; | 1383 | if (CMD_FLAGS(sc) & FNIC_DEVICE_RESET) |
1384 | CMD_FLAGS(sc) |= FNIC_DEV_RST_TERM_ISSUED; | ||
1383 | spin_unlock_irqrestore(io_lock, flags); | 1385 | spin_unlock_irqrestore(io_lock, flags); |
1384 | } | 1386 | } |
1385 | } | 1387 | } |
@@ -1592,7 +1594,7 @@ lr_io_req_end: | |||
1592 | static int fnic_clean_pending_aborts(struct fnic *fnic, | 1594 | static int fnic_clean_pending_aborts(struct fnic *fnic, |
1593 | struct scsi_cmnd *lr_sc) | 1595 | struct scsi_cmnd *lr_sc) |
1594 | { | 1596 | { |
1595 | int tag; | 1597 | int tag, abt_tag; |
1596 | struct fnic_io_req *io_req; | 1598 | struct fnic_io_req *io_req; |
1597 | spinlock_t *io_lock; | 1599 | spinlock_t *io_lock; |
1598 | unsigned long flags; | 1600 | unsigned long flags; |
@@ -1601,6 +1603,7 @@ static int fnic_clean_pending_aborts(struct fnic *fnic, | |||
1601 | struct scsi_lun fc_lun; | 1603 | struct scsi_lun fc_lun; |
1602 | struct scsi_device *lun_dev = lr_sc->device; | 1604 | struct scsi_device *lun_dev = lr_sc->device; |
1603 | DECLARE_COMPLETION_ONSTACK(tm_done); | 1605 | DECLARE_COMPLETION_ONSTACK(tm_done); |
1606 | enum fnic_ioreq_state old_ioreq_state; | ||
1604 | 1607 | ||
1605 | for (tag = 0; tag < FNIC_MAX_IO_REQ; tag++) { | 1608 | for (tag = 0; tag < FNIC_MAX_IO_REQ; tag++) { |
1606 | sc = scsi_host_find_tag(fnic->lport->host, tag); | 1609 | sc = scsi_host_find_tag(fnic->lport->host, tag); |
@@ -1629,7 +1632,41 @@ static int fnic_clean_pending_aborts(struct fnic *fnic, | |||
1629 | "Found IO in %s on lun\n", | 1632 | "Found IO in %s on lun\n", |
1630 | fnic_ioreq_state_to_str(CMD_STATE(sc))); | 1633 | fnic_ioreq_state_to_str(CMD_STATE(sc))); |
1631 | 1634 | ||
1632 | BUG_ON(CMD_STATE(sc) != FNIC_IOREQ_ABTS_PENDING); | 1635 | if (CMD_STATE(sc) == FNIC_IOREQ_ABTS_PENDING) { |
1636 | spin_unlock_irqrestore(io_lock, flags); | ||
1637 | continue; | ||
1638 | } | ||
1639 | if ((CMD_FLAGS(sc) & FNIC_DEVICE_RESET) && | ||
1640 | (!(CMD_FLAGS(sc) & FNIC_DEV_RST_PENDING))) { | ||
1641 | FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host, | ||
1642 | "%s dev rst not pending sc 0x%p\n", __func__, | ||
1643 | sc); | ||
1644 | spin_unlock_irqrestore(io_lock, flags); | ||
1645 | continue; | ||
1646 | } | ||
1647 | old_ioreq_state = CMD_STATE(sc); | ||
1648 | /* | ||
1649 | * Any pending IO issued prior to reset is expected to be | ||
1650 | * in abts pending state, if not we need to set | ||
1651 | * FNIC_IOREQ_ABTS_PENDING to indicate the IO is abort pending. | ||
1652 | * When IO is completed, the IO will be handed over and | ||
1653 | * handled in this function. | ||
1654 | */ | ||
1655 | CMD_STATE(sc) = FNIC_IOREQ_ABTS_PENDING; | ||
1656 | |||
1657 | if (io_req->abts_done) | ||
1658 | shost_printk(KERN_ERR, fnic->lport->host, | ||
1659 | "%s: io_req->abts_done is set state is %s\n", | ||
1660 | __func__, fnic_ioreq_state_to_str(CMD_STATE(sc))); | ||
1661 | |||
1662 | BUG_ON(io_req->abts_done); | ||
1663 | |||
1664 | abt_tag = tag; | ||
1665 | if (CMD_FLAGS(sc) & FNIC_DEVICE_RESET) { | ||
1666 | abt_tag |= FNIC_TAG_DEV_RST; | ||
1667 | FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host, | ||
1668 | "%s: dev rst sc 0x%p\n", __func__, sc); | ||
1669 | } | ||
1633 | 1670 | ||
1634 | CMD_ABTS_STATUS(sc) = FCPIO_INVALID_CODE; | 1671 | CMD_ABTS_STATUS(sc) = FCPIO_INVALID_CODE; |
1635 | io_req->abts_done = &tm_done; | 1672 | io_req->abts_done = &tm_done; |
@@ -1638,16 +1675,23 @@ static int fnic_clean_pending_aborts(struct fnic *fnic, | |||
1638 | /* Now queue the abort command to firmware */ | 1675 | /* Now queue the abort command to firmware */ |
1639 | int_to_scsilun(sc->device->lun, &fc_lun); | 1676 | int_to_scsilun(sc->device->lun, &fc_lun); |
1640 | 1677 | ||
1641 | if (fnic_queue_abort_io_req(fnic, tag, | 1678 | if (fnic_queue_abort_io_req(fnic, abt_tag, |
1642 | FCPIO_ITMF_ABT_TASK_TERM, | 1679 | FCPIO_ITMF_ABT_TASK_TERM, |
1643 | fc_lun.scsi_lun, io_req)) { | 1680 | fc_lun.scsi_lun, io_req)) { |
1644 | spin_lock_irqsave(io_lock, flags); | 1681 | spin_lock_irqsave(io_lock, flags); |
1645 | io_req = (struct fnic_io_req *)CMD_SP(sc); | 1682 | io_req = (struct fnic_io_req *)CMD_SP(sc); |
1646 | if (io_req) | 1683 | if (io_req) |
1647 | io_req->abts_done = NULL; | 1684 | io_req->abts_done = NULL; |
1685 | if (CMD_STATE(sc) == FNIC_IOREQ_ABTS_PENDING) | ||
1686 | CMD_STATE(sc) = old_ioreq_state; | ||
1648 | spin_unlock_irqrestore(io_lock, flags); | 1687 | spin_unlock_irqrestore(io_lock, flags); |
1649 | ret = 1; | 1688 | ret = 1; |
1650 | goto clean_pending_aborts_end; | 1689 | goto clean_pending_aborts_end; |
1690 | } else { | ||
1691 | spin_lock_irqsave(io_lock, flags); | ||
1692 | if (CMD_FLAGS(sc) & FNIC_DEVICE_RESET) | ||
1693 | CMD_FLAGS(sc) |= FNIC_DEV_RST_TERM_ISSUED; | ||
1694 | spin_unlock_irqrestore(io_lock, flags); | ||
1651 | } | 1695 | } |
1652 | 1696 | ||
1653 | wait_for_completion_timeout(&tm_done, | 1697 | wait_for_completion_timeout(&tm_done, |
@@ -1659,8 +1703,7 @@ static int fnic_clean_pending_aborts(struct fnic *fnic, | |||
1659 | io_req = (struct fnic_io_req *)CMD_SP(sc); | 1703 | io_req = (struct fnic_io_req *)CMD_SP(sc); |
1660 | if (!io_req) { | 1704 | if (!io_req) { |
1661 | spin_unlock_irqrestore(io_lock, flags); | 1705 | spin_unlock_irqrestore(io_lock, flags); |
1662 | ret = 1; | 1706 | continue; |
1663 | goto clean_pending_aborts_end; | ||
1664 | } | 1707 | } |
1665 | 1708 | ||
1666 | io_req->abts_done = NULL; | 1709 | io_req->abts_done = NULL; |
@@ -1678,6 +1721,12 @@ static int fnic_clean_pending_aborts(struct fnic *fnic, | |||
1678 | mempool_free(io_req, fnic->io_req_pool); | 1721 | mempool_free(io_req, fnic->io_req_pool); |
1679 | } | 1722 | } |
1680 | 1723 | ||
1724 | schedule_timeout(msecs_to_jiffies(2 * fnic->config.ed_tov)); | ||
1725 | |||
1726 | /* walk again to check, if IOs are still pending in fw */ | ||
1727 | if (fnic_is_abts_pending(fnic, lr_sc)) | ||
1728 | ret = FAILED; | ||
1729 | |||
1681 | clean_pending_aborts_end: | 1730 | clean_pending_aborts_end: |
1682 | return ret; | 1731 | return ret; |
1683 | } | 1732 | } |
@@ -2142,3 +2191,61 @@ call_fc_exch_mgr_reset: | |||
2142 | fc_exch_mgr_reset(lp, sid, did); | 2191 | fc_exch_mgr_reset(lp, sid, did); |
2143 | 2192 | ||
2144 | } | 2193 | } |
2194 | |||
2195 | /* | ||
2196 | * fnic_is_abts_pending() is a helper function that | ||
2197 | * walks through tag map to check if there is any IOs pending,if there is one, | ||
2198 | * then it returns 1 (true), otherwise 0 (false) | ||
2199 | * if @lr_sc is non NULL, then it checks IOs specific to particular LUN, | ||
2200 | * otherwise, it checks for all IOs. | ||
2201 | */ | ||
2202 | int fnic_is_abts_pending(struct fnic *fnic, struct scsi_cmnd *lr_sc) | ||
2203 | { | ||
2204 | int tag; | ||
2205 | struct fnic_io_req *io_req; | ||
2206 | spinlock_t *io_lock; | ||
2207 | unsigned long flags; | ||
2208 | int ret = 0; | ||
2209 | struct scsi_cmnd *sc; | ||
2210 | struct scsi_device *lun_dev = NULL; | ||
2211 | |||
2212 | if (lr_sc) | ||
2213 | lun_dev = lr_sc->device; | ||
2214 | |||
2215 | /* walk again to check, if IOs are still pending in fw */ | ||
2216 | for (tag = 0; tag < FNIC_MAX_IO_REQ; tag++) { | ||
2217 | sc = scsi_host_find_tag(fnic->lport->host, tag); | ||
2218 | /* | ||
2219 | * ignore this lun reset cmd or cmds that do not belong to | ||
2220 | * this lun | ||
2221 | */ | ||
2222 | if (!sc || (lr_sc && (sc->device != lun_dev || sc == lr_sc))) | ||
2223 | continue; | ||
2224 | |||
2225 | io_lock = fnic_io_lock_hash(fnic, sc); | ||
2226 | spin_lock_irqsave(io_lock, flags); | ||
2227 | |||
2228 | io_req = (struct fnic_io_req *)CMD_SP(sc); | ||
2229 | |||
2230 | if (!io_req || sc->device != lun_dev) { | ||
2231 | spin_unlock_irqrestore(io_lock, flags); | ||
2232 | continue; | ||
2233 | } | ||
2234 | |||
2235 | /* | ||
2236 | * Found IO that is still pending with firmware and | ||
2237 | * belongs to the LUN that we are resetting | ||
2238 | */ | ||
2239 | FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host, | ||
2240 | "Found IO in %s on lun\n", | ||
2241 | fnic_ioreq_state_to_str(CMD_STATE(sc))); | ||
2242 | |||
2243 | if (CMD_STATE(sc) == FNIC_IOREQ_ABTS_PENDING) { | ||
2244 | spin_unlock_irqrestore(io_lock, flags); | ||
2245 | ret = 1; | ||
2246 | continue; | ||
2247 | } | ||
2248 | } | ||
2249 | |||
2250 | return ret; | ||
2251 | } | ||