diff options
Diffstat (limited to 'drivers/scsi/mpt3sas/mpt3sas_base.c')
-rw-r--r-- | drivers/scsi/mpt3sas/mpt3sas_base.c | 180 |
1 files changed, 132 insertions, 48 deletions
diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index 14a781b6b88d..a4d287b7418b 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -815,6 +815,20 @@ _base_async_event(struct MPT3SAS_ADAPTER *ioc, u8 msix_index, u32 reply) return 1; } +struct scsiio_tracker * +mpt3sas_get_st_from_smid(struct MPT3SAS_ADAPTER *ioc, u16 smid) +{ + if (shost_use_blk_mq(ioc->shost)) { + struct scsi_cmnd *scmd; + + scmd = scsi_mq_find_tag(ioc->shost, smid - 1); + if (!scmd) + return NULL; + return scsi_mq_scmd_to_pdu(scmd); + } else + return &ioc->scsi_lookup[smid - 1]; +} + /** * _base_get_cb_idx - obtain the callback index * @ioc: per adapter object @@ -829,8 +843,10 @@ _base_get_cb_idx(struct MPT3SAS_ADAPTER *ioc, u16 smid) u8 cb_idx; if (smid < ioc->hi_priority_smid) { - i = smid - 1; - cb_idx = ioc->scsi_lookup[i].cb_idx; + struct scsiio_tracker *st; + + st = mpt3sas_get_st_from_smid(ioc, smid); + cb_idx = st->cb_idx; } else if (smid < ioc->internal_smid) { i = smid - ioc->hi_priority_smid; cb_idx = ioc->hpr_lookup[i].cb_idx; @@ -1176,6 +1192,7 @@ static struct chain_tracker * _base_get_chain_buffer_tracker(struct MPT3SAS_ADAPTER *ioc, u16 smid) { struct chain_tracker *chain_req; + struct scsiio_tracker *st; unsigned long flags; spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); @@ -1188,8 +1205,8 @@ _base_get_chain_buffer_tracker(struct MPT3SAS_ADAPTER *ioc, u16 smid) chain_req = list_entry(ioc->free_chain_list.next, struct chain_tracker, tracker_list); list_del_init(&chain_req->tracker_list); - list_add_tail(&chain_req->tracker_list, - &ioc->scsi_lookup[smid - 1].chain_list); + st = mpt3sas_get_st_from_smid(ioc, smid); + list_add_tail(&chain_req->tracker_list, &st->chain_list); spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); return chain_req; } @@ -2006,6 +2023,18 @@ mpt3sas_base_get_smid_scsiio(struct MPT3SAS_ADAPTER *ioc, u8 cb_idx, struct scsiio_tracker *request; u16 smid; + if (shost_use_blk_mq(ioc->shost)) { + /* + * If we don't have a SCSI command associated with this smid, + * bump it to high-prio + */ + if (!scmd) + return mpt3sas_base_get_smid_hpr(ioc, cb_idx); + + request = blk_mq_rq_to_pdu(scmd->request) + sizeof(*scmd); + return request->smid; + } + spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); if (list_empty(&ioc->free_list)) { spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); @@ -2053,6 +2082,32 @@ mpt3sas_base_get_smid_hpr(struct MPT3SAS_ADAPTER *ioc, u8 cb_idx) return smid; } +static void +_base_recovery_check(struct MPT3SAS_ADAPTER *ioc) +{ + /* + * See _wait_for_commands_to_complete() call with regards to this code. + */ + if (ioc->shost_recovery && ioc->pending_io_count) { + if (ioc->pending_io_count == 1) + wake_up(&ioc->reset_wq); + ioc->pending_io_count = 0; + } +} + +static void +_dechain_st(struct MPT3SAS_ADAPTER *ioc, struct scsiio_tracker *st) +{ + struct chain_tracker *chain_req; + + while (!list_empty(&st->chain_list)) { + chain_req = list_first_entry(&st->chain_list, + struct chain_tracker, + tracker_list); + list_move(&chain_req->tracker_list, &ioc->free_chain_list); + } +} + /** * mpt3sas_base_free_smid - put smid back on free_list * @ioc: per adapter object @@ -2065,34 +2120,36 @@ mpt3sas_base_free_smid(struct MPT3SAS_ADAPTER *ioc, u16 smid) { unsigned long flags; int i; - struct chain_tracker *chain_req, *next; + + if (shost_use_blk_mq(ioc->shost) && smid < ioc->hi_priority_smid) { + struct scsiio_tracker *st; + + st = mpt3sas_get_st_from_smid(ioc, smid); + if (!st) + return; + + if (!list_empty(&st->chain_list)) { + spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); + _dechain_st(ioc, st); + spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); + } + + _base_recovery_check(ioc); + return; + } spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); if (smid < ioc->hi_priority_smid) { /* scsiio queue */ i = smid - 1; - if (!list_empty(&ioc->scsi_lookup[i].chain_list)) { - list_for_each_entry_safe(chain_req, next, - &ioc->scsi_lookup[i].chain_list, tracker_list) { - list_del_init(&chain_req->tracker_list); - list_add(&chain_req->tracker_list, - &ioc->free_chain_list); - } - } + if (!list_empty(&ioc->scsi_lookup[i].chain_list)) + _dechain_st(ioc, &ioc->scsi_lookup[i]); ioc->scsi_lookup[i].cb_idx = 0xFF; ioc->scsi_lookup[i].scmd = NULL; list_add(&ioc->scsi_lookup[i].tracker_list, &ioc->free_list); spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - /* - * See _wait_for_commands_to_complete() call with regards - * to this code. - */ - if (ioc->shost_recovery && ioc->pending_io_count) { - if (ioc->pending_io_count == 1) - wake_up(&ioc->reset_wq); - ioc->pending_io_count--; - } + _base_recovery_check(ioc); return; } else if (smid < ioc->internal_smid) { /* hi-priority */ @@ -2896,14 +2953,23 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc, int sleep_flag) ioc->name, (unsigned long long) ioc->request_dma)); total_sz += sz; - sz = ioc->scsiio_depth * sizeof(struct scsiio_tracker); - ioc->scsi_lookup_pages = get_order(sz); - ioc->scsi_lookup = (struct scsiio_tracker *)__get_free_pages( - GFP_KERNEL, ioc->scsi_lookup_pages); - if (!ioc->scsi_lookup) { - pr_err(MPT3SAS_FMT "scsi_lookup: get_free_pages failed, sz(%d)\n", - ioc->name, (int)sz); - goto out; + /* + * Don't need to allocate memory for scsiio_tracker array if we + * are using scsi-mq, we embed it in the scsi_cmnd for that case. + */ + if (!shost_use_blk_mq(ioc->shost)) { + sz = ioc->scsiio_depth * sizeof(struct scsiio_tracker); + ioc->scsi_lookup_pages = get_order(sz); + ioc->scsi_lookup = (struct scsiio_tracker *)__get_free_pages( + GFP_KERNEL, ioc->scsi_lookup_pages); + if (!ioc->scsi_lookup) { + pr_err(MPT3SAS_FMT "scsi_lookup: get_free_pages " + "failed, sz(%d)\n", ioc->name, (int)sz); + goto out; + } + } else { + ioc->scsi_lookup_pages = 0; + ioc->scsi_lookup = NULL; } dinitprintk(ioc, pr_info(MPT3SAS_FMT "scsiio(0x%p): depth(%d)\n", @@ -4439,14 +4505,17 @@ _base_make_ioc_operational(struct MPT3SAS_ADAPTER *ioc, int sleep_flag) /* initialize the scsi lookup free list */ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); INIT_LIST_HEAD(&ioc->free_list); - smid = 1; - for (i = 0; i < ioc->scsiio_depth; i++, smid++) { - INIT_LIST_HEAD(&ioc->scsi_lookup[i].chain_list); - ioc->scsi_lookup[i].cb_idx = 0xFF; - ioc->scsi_lookup[i].smid = smid; - ioc->scsi_lookup[i].scmd = NULL; - list_add_tail(&ioc->scsi_lookup[i].tracker_list, - &ioc->free_list); + + if (!shost_use_blk_mq(ioc->shost)) { + smid = 1; + for (i = 0; i < ioc->scsiio_depth; i++, smid++) { + INIT_LIST_HEAD(&ioc->scsi_lookup[i].chain_list); + ioc->scsi_lookup[i].cb_idx = 0xFF; + ioc->scsi_lookup[i].smid = smid; + ioc->scsi_lookup[i].scmd = NULL; + list_add_tail(&ioc->scsi_lookup[i].tracker_list, + &ioc->free_list); + } } /* hi-priority queue */ @@ -4895,7 +4964,7 @@ _wait_for_commands_to_complete(struct MPT3SAS_ADAPTER *ioc, int sleep_flag) { u32 ioc_state; unsigned long flags; - u16 i; + u16 i, pending, loops; ioc->pending_io_count = 0; if (sleep_flag != CAN_SLEEP) @@ -4906,17 +4975,32 @@ _wait_for_commands_to_complete(struct MPT3SAS_ADAPTER *ioc, int sleep_flag) return; /* pending command count */ - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - for (i = 0; i < ioc->scsiio_depth; i++) - if (ioc->scsi_lookup[i].cb_idx != 0xFF) - ioc->pending_io_count++; - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); + loops = 0; + do { + pending = 0; + spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); + for (i = 0; i < ioc->scsiio_depth; i++) { + struct scsiio_tracker *st; + struct scsi_cmnd *scmd; + + if (shost_use_blk_mq(ioc->shost)) { + scmd = scsi_mq_find_tag(ioc->shost, i); + if (scsi_mq_scmd_started(scmd)) + pending++; + } else { + st = mpt3sas_get_st_from_smid(ioc, i + 1); + if (st->cb_idx != 0xFF) + pending++; + } + } + spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - if (!ioc->pending_io_count) - return; + if (!pending) + break; - /* wait for pending commands to complete */ - wait_event_timeout(ioc->reset_wq, ioc->pending_io_count == 0, 10 * HZ); + /* wait for pending commands to complete */ + wait_event_timeout(ioc->reset_wq, ioc->pending_io_count == 0, HZ); + } while (++loops <= 10); } /** |