mpt2/mpt3sas lock reduction for scsi-mq
Subsystems (3)
RFC PATCH 1/1 mpt2/mpt3sas lock reduction for scsi-mq
Hi,
There's some "low" hanging fruit in the lsi mpt drivers for further lock reduction, when running in scsi-mq mode. For each IO, they have to lock/{get,put}/unlock a scsiio_tracker structure that is associated with the IO. In scsi-mq mode, we can ask for some payload for each command, so we don't have to store and manage this tracker structure separately.
In some testing on mpt2sas, this roughly cuts the locking time in half at just 100K IOPS. Compared to scsi-mq not being enabled, the locking time with the patchset is reduced from ~47% to just ~4%.
Signature · 1 line
Jens Axboe
PATCH 1/7 blk-mq: allow the callback to blk_mq_tag_busy_iter() to stop looping
Currently blk_mq_tag_busy_iter() loops all busy tags for a given hardware queue. But sometimes we are looking for a specific request, and when we find it, we don't have to keep looking over the rest of them. Change the busy_iter_fn callback to return a bool, where a true return will break out of the search.
Update current callers (blk-mq timeout and NVMe IO cancel).
--- block/blk-mq-tag.c | 6 ++++-- block/blk-mq.c | 10 ++++++---- drivers/block/nvme-core.c | 7 ++++--- include/linux/blk-mq.h | 2 +- 4 files changed, 15 insertions(+), 10 deletions(-)
block/blk-mq-tag.c +4 -2
@@ -430,8 +430,10 @@ static void bt_for_each(struct blk_mq_hw_ctx *hctx, bit < bm->depth; bit = find_next_bit(&bm->word, bm->depth, bit + 1)) { rq =blk_mq_tag_to_rq (hctx->tags, off + bit); -if (rq->q == hctx->queue) -fn (hctx, rq, data, reserved); +if (rq->q != hctx->queue) +continue ; +if (fn (hctx, rq, data, reserved)) +break ; } off += (1 << bt->bits_per_word);
block/blk-mq.c +6 -4
@@ -622,8 +622,8 @@ void blk_mq_rq_timed_out(struct request *req, bool reserved) } } -static void blk_mq_check_expired (struct blk_mq_hw_ctx *hctx, -struct request *rq,void *priv,bool reserved) +static bool blk_mq_check_expired (struct blk_mq_hw_ctx *hctx,struct request *rq, +void *priv,bool reserved) {struct blk_mq_timeout_data *data = priv;
@@ -636,10 +636,10 @@ static void blk_mq_check_expired(struct blk_mq_hw_ctx *hctx, rq->errors = -EIO ;blk_mq_complete_request (rq); } -return ; +return false; }if (rq->cmd_flags &REQ_NO_TIMEOUT ) -return ; +return false;if (time_after_eq (jiffies, rq->deadline)) {if (!blk_mark_rq_complete (rq))
@@ -648,6 +648,8 @@ static void blk_mq_check_expired(struct blk_mq_hw_ctx *hctx, data->next = rq->deadline; data->next_set =1 ; } + +return false; }static void blk_mq_rq_timer (unsigned long priv)
drivers/block/nvme-core.c +4 -3
@@ -1260,7 +1260,7 @@ static void nvme_abort_req(struct request *req) } } -static void nvme_cancel_queue_ios (struct blk_mq_hw_ctx *hctx, +static bool nvme_cancel_queue_ios (struct blk_mq_hw_ctx *hctx,struct request *req,void *data,bool reserved) {struct nvme_queue *nvmeq = data;
@@ -1270,12 +1270,12 @@ static void nvme_cancel_queue_ios(struct blk_mq_hw_ctx *hctx,struct nvme_completion cqe;if (!blk_mq_request_started (req)) -return ; +return false; cmd =blk_mq_rq_to_pdu (req);if (cmd->ctx ==CMD_CTX_CANCELLED ) -return ; +return false;if (blk_queue_dying (req->q)) cqe.status =cpu_to_le16 ((NVME_SC_ABORT_REQ |NVME_SC_DNR ) <<1 );
@@ -1287,6 +1287,7 @@ static void nvme_cancel_queue_ios(struct blk_mq_hw_ctx *hctx, req->tag, nvmeq->qid); ctx =cancel_cmd_info (cmd, &fn);fn (nvmeq, ctx, &cqe); +return false; }static enum blk_eh_timer_return nvme_timeout (struct request *req,bool reserved)
include/linux/blk-mq.h +1 -1
@@ -94,7 +94,7 @@ typedef int (init_request_fn)(void *, struct request *, unsigned int,typedef void (exit_request_fn )(void *,struct request *,unsigned int ,unsigned int ); -typedef void (busy_iter_fn )(struct blk_mq_hw_ctx *,struct request *,void *, +typedef bool (busy_iter_fn )(struct blk_mq_hw_ctx *,struct request *,void *,bool );struct blk_mq_ops {
Signature · 1 line
1.9.1
PATCH 2/7 blk-mq: add helper to iterate all busy tags on all hardware queues
In reply to Jens AxboeThe current iter helper function deals with a hardware queue. Some callers want to access all queues, like the internal blk-mq timeout handling does. So add a helper for that.
--- block/blk-mq.c | 35 +++++++++++++++++++++++------------ include/linux/blk-mq.h | 2 ++ 2 files changed, 25 insertions(+), 12 deletions(-)
block/blk-mq.c +23 -12
@@ -561,6 +561,25 @@ void blk_mq_abort_requeue_list(struct request_queue *q) }EXPORT_SYMBOL (blk_mq_abort_requeue_list); +void blk_mq_queue_busy_iter (struct request_queue *q,busy_iter_fn *fn, +void *priv) +{ +struct blk_mq_hw_ctx *hctx; +int i; + +queue_for_each_hw_ctx (q, hctx, i) { +/* +* If no software queues are currently mapped to this +* hardware queue, there's nothing to check +*/ +if (!blk_mq_hw_queue_mapped (hctx)) +continue ; + +blk_mq_tag_busy_iter (hctx, fn, priv); + } +} +EXPORT_SYMBOL_GPL (blk_mq_queue_busy_iter); +static inline bool is_flush_request (struct request *rq,struct blk_flush_queue *fq,unsigned int tag) {
@@ -659,24 +678,16 @@ static void blk_mq_rq_timer(unsigned long priv) .next = 0, .next_set = 0, }; -struct blk_mq_hw_ctx *hctx; -int i; -queue_for_each_hw_ctx (q, hctx, i) { -/* -* If not software queues are currently mapped to this -* hardware queue, there's nothing to check -*/ -if (!blk_mq_hw_queue_mapped (hctx)) -continue ; - -blk_mq_tag_busy_iter (hctx, blk_mq_check_expired, &data); - } +blk_mq_queue_busy_iter (q, blk_mq_check_expired, &data);if (data.next_set) { data.next =blk_rq_timeout (round_jiffies_up (data.next));mod_timer (&q->timeout, data.next); }else { +struct blk_mq_hw_ctx *hctx; +int i; +queue_for_each_hw_ctx (q, hctx, i)blk_mq_tag_idle (hctx); }
include/linux/blk-mq.h +2 -0
@@ -219,6 +219,8 @@ void blk_mq_stop_hw_queues(struct request_queue *q);void blk_mq_start_hw_queues (struct request_queue *q);void blk_mq_start_stopped_hw_queues (struct request_queue *q,bool async);void blk_mq_delay_queue (struct blk_mq_hw_ctx *hctx,unsigned long msecs); +void blk_mq_queue_busy_iter (struct request_queue *q,busy_iter_fn *fn, +void *priv);void blk_mq_tag_busy_iter (struct blk_mq_hw_ctx *hctx,busy_iter_fn *fn,void *priv);void blk_mq_freeze_queue (struct request_queue *q);
Signature · 1 line
1.9.1
PATCH 3/7 scsi: add scsi-mq helpers to retrieve pdu and check started state
In reply to Jens Axboescsi_mq_scmd_to_pdu() returns the LLD pdu associated with a struct scsi_cmnd.
scsi_mq_scmd_start() returns whether or not a given scsi command has been started or not.
--- include/scsi/scsi_cmnd.h | 11 +++++++++++ 1 file changed, 11 insertions(+)
include/scsi/scsi_cmnd.h +11 -0
@@ -8,6 +8,7 @@#include <linux/timer.h> #include <linux/scatterlist.h> #include <scsi/scsi_device.h> +#include <linux/blk-mq.h> struct Scsi_Host ;struct scsi_driver ;
@@ -155,6 +156,16 @@ static inline struct scsi_driver *scsi_cmd_to_driver(struct scsi_cmnd *cmd)return *(struct scsi_driver **)cmd->request->rq_disk->private_data; } +static inline void *scsi_mq_scmd_to_pdu (struct scsi_cmnd *scmd) +{ +return blk_mq_rq_to_pdu (scmd->request) +sizeof (*scmd); +} + +static inline bool scsi_mq_scmd_started (struct scsi_cmnd *scmd) +{ +return blk_mq_request_started (scmd->request); +} +extern struct scsi_cmnd *scsi_get_command (struct scsi_device *,gfp_t );extern void scsi_put_command (struct scsi_cmnd *);extern void scsi_finish_command (struct scsi_cmnd *cmd);
Signature · 1 line
1.9.1
Re: [PATCH 3/7] scsi: add scsi-mq helpers to retrieve pdu and check started state
include/scsi/scsi_cmnd.h static inline struct scsi_driver *scsi_cmd_to_driver(struct scsi_cmnd *cmd) · line 162
Quoted 4 lines · Jens Axboe
include/scsi/scsi_cmnd.h +4
-0+static inline void *scsi_mq_scmd_to_pdu (struct scsi_cmnd *scmd) +{ +return blk_mq_rq_to_pdu (scmd->request) +sizeof (*scmd); +}
We've already got scsi_cmd_priv to cover this.
include/scsi/scsi_cmnd.h static inline struct scsi_driver *scsi_cmd_to_driver(struct scsi_cmnd *cmd) · line 167
Quoted 4 lines
include/scsi/scsi_cmnd.h +4
-0+static inline bool scsi_mq_scmd_started (struct scsi_cmnd *scmd) +{ +return blk_mq_request_started (scmd->request); +}
I don't really think we want to expose this functionality, but more on that in my reply to the mpt2 patch.
PATCH 4/7 scsi: add scsi-mq helper for iterating over busy commands
In reply to Jens AxboeThis is basically just a wrapper around blk_mq_queue_busy_iter(), so that LLDs don't have to deal with or worry about blk-mq hardware queues.
--- drivers/scsi/scsi_lib.c | 25 +++++++++++++++++++++++++ include/scsi/scsi_device.h | 3 +++ 2 files changed, 28 insertions(+)
drivers/scsi/scsi_lib.c +25 -0
@@ -648,6 +648,31 @@ static void scsi_mq_uninit_cmd(struct scsi_cmnd *cmd) } } +struct scsi_mq_iter_data { +scsi_scmd_iter *fn; +void *priv; +}; + +static bool scsi_mq_iter_fn (struct blk_mq_hw_ctx *hctx,struct request *rq, +void *priv,bool reserved) +{ +struct scsi_mq_iter_data *data = priv; +struct scsi_cmnd *scmd = rq->special; + +return data->fn (scmd, data->priv); +} + +void scsi_mq_scmd_busy_iter (struct scsi_device *sdev,scsi_scmd_iter *fn, +void *priv) +{ +struct scsi_mq_iter_data data; + + data.fn = fn; + data.priv = priv; +blk_mq_queue_busy_iter (sdev->request_queue, scsi_mq_iter_fn, &data); +} +EXPORT_SYMBOL (scsi_mq_scmd_busy_iter); +/* * Function: scsi_release_buffers() *
include/scsi/scsi_device.h +3 -0
@@ -536,4 +536,7 @@ static inline int scsi_device_tpgs(struct scsi_device *sdev) MODULE_ALIAS("scsi:t-" __stringify(type) "*") #define SCSI_DEVICE_MODALIAS_FMT "scsi:t-0x%02x" +typedef bool (scsi_scmd_iter)(struct scsi_cmnd *, void *); +void scsi_mq_scmd_busy_iter(struct scsi_device *sdev, scsi_scmd_iter *fn, void *priv); + #endif /* _SCSI_SCSI_DEVICE_H */
Signature · 1 line
1.9.1
Re: [PATCH 4/7] scsi: add scsi-mq helper for iterating over busy commands
Quoted 3 lines · Jens Axboe
This is basically just a wrapper around
blk_mq_queue_busy_iter(), so that LLDs don't have to deal with or worry about blk-mq hardware queues.
I'd prefer not to expose this to drivers, but if we do it needs to work for the !mq case.
PATCH 5/7 scsi: add host template init/exit_command hooks
In reply to Jens AxboeIf a LLD has hardware commands in the request pdu, then we need some helper hooks to help the driver initialize state at load time, and potentially to tear down state at rmmod time. Add a host template ->init_command() and ->exit_command() hook to help with that.
--- drivers/scsi/scsi_lib.c | 16 ++++++++++++++++ include/scsi/scsi_host.h | 6 +++++- 2 files changed, 21 insertions(+), 1 deletion(-)
drivers/scsi/scsi_lib.c +16 -0
@@ -2081,11 +2081,23 @@ static int scsi_init_request(void *data, struct request *rq, unsigned int numa_node) {struct scsi_cmnd *cmd =blk_mq_rq_to_pdu (rq); +struct Scsi_Host *shost = data; cmd->sense_buffer =kzalloc_node (SCSI_SENSE_BUFFERSIZE ,GFP_KERNEL , numa_node);if (!cmd->sense_buffer)return -ENOMEM ; + +if (shost->hostt->init_command) { +int ret; + + ret = shost->hostt->init_command (shost, cmd, request_idx); +if (ret) { +kfree (cmd->sense_buffer); +return ret; + } + } +return 0 ; }
@@ -2093,8 +2105,12 @@ static void scsi_exit_request(void *data, struct request *rq, unsigned int hctx_idx, unsigned int request_idx) { struct scsi_cmnd *cmd = blk_mq_rq_to_pdu(rq); +struct Scsi_Host *shost = data;kfree (cmd->sense_buffer); + +if (shost->hostt->exit_command) + shost->hostt->exit_command (shost, cmd); }static u64 scsi_calculate_bounce_limit (struct Scsi_Host *shost)
include/scsi/scsi_host.h +5 -1
@@ -496,10 +496,14 @@ struct scsi_host_template {u64 vendor_id;/* -* Additional per-command data allocated for the driver. +* Additional per-command data allocated for the driver, along +* with init/exit helper hooks. */ unsigned int cmd_size;struct scsi_host_cmd_pool *cmd_pool; +int (*init_command)(struct Scsi_Host *,struct scsi_cmnd *, +unsigned int ); +void (*exit_command)(struct Scsi_Host *,struct scsi_cmnd *);/* temporary flag to disable blk-mq I/O path */ bool disable_blk_mq;
Signature · 1 line
1.9.1
Re: [PATCH 5/7] scsi: add host template init/exit_command hooks
Quoted 6 lines · Jens Axboe
If a LLD has hardware commands in the request pdu, then we need some helper hooks to help the driver initialize state at load time, and potentially to tear down state at rmmod time. Add a host template ->init_command() and ->exit_command() hook to help with that.
Signed-off-by Jens Axboe <[email protected]>
Looks good in general, but please ensure these callsbacks also get invoked in the !mq case.
PATCH 6/7 mpt2sas: store scsi io tracker data in the scsi command / request
In reply to Jens AxboeInstead of storing the IO tracker structure in a separate list that we need to pop/push to on every submit and complete (and lock), store it in the pdu associated with a request. This is possible on scsi-mq only, and further cuts the spinlock associated time for higher IOPS IO workloads. At 100K IOPS, this effectively cuts the locking time in half.
--- drivers/scsi/mpt2sas/mpt2sas_base.c | 194 +++++++++++++++++++++++++---------- drivers/scsi/mpt2sas/mpt2sas_base.h | 3 + drivers/scsi/mpt2sas/mpt2sas_ctl.c | 119 ++++++++++++++++----- drivers/scsi/mpt2sas/mpt2sas_scsih.c | 89 ++++++++++++---- 4 files changed, 307 insertions(+), 98 deletions(-)
drivers/scsi/mpt2sas/mpt2sas_base.c +139 -55
@@ -828,6 +828,20 @@ _base_async_event(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, u32 reply)return ; } +struct scsiio_tracker * +mpt2sas_get_st_from_smid (struct MPT2SAS_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
@@ -842,8 +856,10 @@ _base_get_cb_idx(struct MPT2SAS_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 =mpt2sas_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;
@@ -962,18 +978,17 @@ _base_interrupt(int irq, void *bus_id) goto next;if (smid) { cb_idx =_base_get_cb_idx (ioc, smid); -if ((likely (cb_idx <MPT_MAX_CALLBACKS )) +if ((likely (cb_idx <MPT_MAX_CALLBACKS )) && (likely (mpt_callbacks[cb_idx] !=NULL ))) { rc = mpt_callbacks[cb_idx](ioc, smid, msix_index, reply); -if (reply) -_base_display_reply_info (ioc, smid, - msix_index, reply); -if (rc) -mpt2sas_base_free_smid (ioc, smid); +if (reply) +_base_display_reply_info (ioc, smid, + msix_index, reply); +if (rc) +mpt2sas_base_free_smid (ioc, smid); } - } -if (!smid) + }else _base_async_event (ioc, msix_index, reply);/* reply free queue handling */
@@ -1724,6 +1739,18 @@ mpt2sas_base_get_smid_scsiio(struct MPT2SAS_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 mpt2sas_base_get_smid_hpr (ioc, cb_idx); + + request =scsi_mq_scmd_to_pdu (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);
@@ -1771,6 +1798,31 @@ mpt2sas_base_get_smid_hpr(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx)return smid; } +static void +_base_recovery_check (struct MPT2SAS_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 MPT2SAS_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); + } +}/** * mpt2sas_base_free_smid - put smid back on free_list
@@ -1784,20 +1836,32 @@ mpt2sas_base_free_smid(struct MPT2SAS_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 =mpt2sas_get_st_from_smid (ioc, smid); +if (!st) +return ; + + st->direct_io =0 ; + +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 ; ioc->scsi_lookup[i].direct_io =0 ;
@@ -1805,15 +1869,7 @@ mpt2sas_base_free_smid(struct MPT2SAS_ADAPTER *ioc, u16 smid) &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 */
@@ -2723,14 +2779,23 @@ _base_allocate_memory_pools(struct MPT2SAS_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) { -printk (MPT2SAS_ERR_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) { +printk (MPT2SAS_ERR_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, printk(MPT2SAS_INFO_FMT "scsiio(0x%p): "
@@ -4299,15 +4364,17 @@ _base_make_ioc_operational(struct MPT2SAS_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 ; - ioc->scsi_lookup[i].direct_io =0 ; -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 ; + ioc->scsi_lookup[i].direct_io =0 ; +list_add_tail (&ioc->scsi_lookup[i].tracker_list, + &ioc->free_list); + } }/* hi-priority queue */
@@ -4772,7 +4839,7 @@ _wait_for_commands_to_complete(struct MPT2SAS_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 )
@@ -4783,17 +4850,34 @@ _wait_for_commands_to_complete(struct MPT2SAS_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 =mpt2sas_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 ; + + ioc->pending_io_count =1 ; -/* 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 ); }/**
drivers/scsi/mpt2sas/mpt2sas_base.h +3 -0
@@ -1045,6 +1045,9 @@ u16 mpt2sas_base_get_smid_hpr(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx);u16 mpt2sas_base_get_smid_scsiio (struct MPT2SAS_ADAPTER *ioc,u8 cb_idx,struct scsi_cmnd *scmd); + +struct scsiio_tracker *mpt2sas_get_st_from_smid (struct MPT2SAS_ADAPTER *ioc, +u16 smid);u16 mpt2sas_base_get_smid (struct MPT2SAS_ADAPTER *ioc,u8 cb_idx);void mpt2sas_base_free_smid (struct MPT2SAS_ADAPTER *ioc,u16 smid); void mpt2sas_base_put_smid_scsi_io(struct MPT2SAS_ADAPTER *ioc, u16 smid,
drivers/scsi/mpt2sas/mpt2sas_ctl.c +94 -25
145 lines not on this page · raw message
drivers/scsi/mpt2sas/mpt2sas_scsih.c +71 -18
180 lines not on this page · raw message
Signature · 1 line
1.9.1
Re: [PATCH 6/7] mpt2sas: store scsi io tracker data in the scsi command / request
drivers/scsi/mpt2sas/mpt2sas_base.c _base_async_event(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, u32 reply) · line 843
Quoted 13 lines · Jens Axboe
drivers/scsi/mpt2sas/mpt2sas_base.c +13
-0+struct scsiio_tracker * +mpt2sas_get_st_from_smid (struct MPT2SAS_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 ]; +}
The mq case will also work for the !mq case when you callscsi_host_find_tag and scsi_cmd_priv. In general all the mq-specific
codepathes you add should become the default and only one, even if this requires a lit bit of additional core work.
drivers/scsi/mpt2sas/mpt2sas_base.c mpt2sas_base_get_smid_scsiio(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx, · line 1748
Quoted 11 lines
drivers/scsi/mpt2sas/mpt2sas_base.c +7
-0@@ -1724,6 +1739,18 @@ mpt2sas_base_get_smid_scsiio(struct MPT2SAS_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 mpt2sas_base_get_smid_hpr (ioc, cb_idx);
Seems like _ctl_do_mpt_command should be changed to just call mpt2sas_base_get_smid_hpr unconditionally instead of adding this hack Preferably as a standalone preparatory patch.
Quoted 8 lines
drivers/scsi/mpt2sas/mpt2sas_base.c +5
-1unsigned 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 =mpt2sas_get_st_from_smid (ioc, smid);
drivers/scsi/mpt2sas/mpt2sas_base.c mpt2sas_base_free_smid(struct MPT2SAS_ADAPTER *ioc, u16 smid) · line 1853
Quoted 10 lines
drivers/scsi/mpt2sas/mpt2sas_base.c +10
-0+if (!st) +return ; + + st->direct_io =0 ; + +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); + }
This whole chain list thing looks bonkers to me. We always allocated a fixed multiple of the queue depth in ->chain_lookup, but then do this required list manipulation at least once per I/O submission and completion.
Seems like we should instead add an array of (cpu address, dma address) tuples to the scsiio_tracker and avoid all the chain_lookup / chain_list lookups entirely.
drivers/scsi/mpt2sas/mpt2sas_base.c _wait_for_commands_to_complete(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) · line 4864
Quoted 4 lines
drivers/scsi/mpt2sas/mpt2sas_base.c +4
-0+if (shost_use_blk_mq (ioc->shost)) { + scmd =scsi_mq_find_tag (ioc->shost, i); +if (scsi_mq_scmd_started (scmd)) + pending++;
Ok, I guess we should move the request_started check into the _find_tag helpers, as tags that aren't started aren't something that driver should ever lookup.
drivers/scsi/mpt2sas/mpt2sas_ctl.c _ctl_poll(struct file *filep, poll_table *wait) · line 539
Quoted 8 lines
drivers/scsi/mpt2sas/mpt2sas_ctl.c +8
-0+static bool +_scmd_match (struct scsi_cmnd *scmd,u16 handle,u32 lun) +{ +struct MPT2SAS_DEVICE *priv_data; + +if (scmd ==NULL || scmd->device ==NULL || + scmd->device->hostdata ==NULL ) +return false;
If the queue is started this can't ever happen.
Review
Quoted 2 lines
(quoted diff) +2
-0+ if (lun != scmd->device->lun) + return false;
If you pass in a specific scsi_device and thus request_queue this can't happen.
drivers/scsi/mpt2sas/mpt2sas_ctl.c _ctl_poll(struct file *filep, poll_table *wait) · line 618
Quoted 8 lines
drivers/scsi/mpt2sas/mpt2sas_ctl.c +8
-0+static u16 +_ctl_find_smid (struct MPT2SAS_ADAPTER *ioc,u16 handle,u32 lun) +{ +if (shost_use_blk_mq (ioc->shost)) +return _ctl_find_smid_mq (ioc, handle, lun); +else +return _ctl_find_smid_legacy (ioc, handle, lun); +}
The caller of this looks entirely broken. It's a driver specific API to submit task management commands, duplicating the mid level code, and it doesn't even allow which task to target. I think we should just return a error when invoking MPI2_FUNCTION_SCSI_TASK_MGMT instead of digging us an even deeper grave here. If someone complains we'll have to find a way to redirect it to the generic EH ioctls.
Jens Axboe
maintainerRe: [PATCH 6/7] mpt2sas: store scsi io tracker data in the scsi command / request
Quoted 11 lines · Christoph Hellwig
Quoted 10 lines · Jens Axboe
drivers/scsi/mpt2sas/mpt2sas_base.c +10
-0+struct scsiio_tracker * +mpt2sas_get_st_from_smid (struct MPT2SAS_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);
Quoted 8 lines
drivers/scsi/mpt2sas/mpt2sas_base.c _base_async_event(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, u32 reply) · line 843
Quoted 3 lines
drivers/scsi/mpt2sas/mpt2sas_base.c +3
-0+ }else +return &ioc->scsi_lookup[smid -1 ]; +}The mq case will also work for the !mq case when you call
scsi_host_find_tagandscsi_cmd_priv. In general all the mq-specific
codepathes you add should become the default and only one, even if this requires a lit bit of additional core work.
For the core code, I definitely agree. But for this case, in scsi-mq mode, we know that tag == smid - 1. That's not the case if we are not using scsi-mq.
In general, it'd be great if we could "convert" drivers and not have to support both scsi-mq and legacy mode. Then I could just rip the old code.
Quoted 4 lines
Quoted 4 lines
drivers/scsi/mpt2sas/mpt2sas_base.c +0
-0@@ -1724,6 +1739,18 @@ mpt2sas_base_get_smid_scsiio(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx,struct scsiio_tracker *request;u16 smid;
Quoted 11 lines
drivers/scsi/mpt2sas/mpt2sas_base.c mpt2sas_base_get_smid_scsiio(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx, · line 1748
Quoted 7 lines
drivers/scsi/mpt2sas/mpt2sas_base.c +7
-0+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 mpt2sas_base_get_smid_hpr (ioc, cb_idx);Seems like
_ctl_do_mpt_commandshould be changed to just callmpt2sas_base_get_smid_hprunconditionally instead of adding this hack Preferably as a standalone preparatory patch.
Sounds reasonable, I'll do that.
Quoted 14 lines
Quoted 14 lines
drivers/scsi/mpt2sas/mpt2sas_base.c +11
-1unsigned 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 =mpt2sas_get_st_from_smid (ioc, smid); +if (!st) +return ; + + st->direct_io =0 ; + +if (!list_empty (&st->chain_list)) {
Quoted 8 lines
drivers/scsi/mpt2sas/mpt2sas_base.c mpt2sas_base_free_smid(struct MPT2SAS_ADAPTER *ioc, u16 smid) · line 1853
Quoted 4 lines
drivers/scsi/mpt2sas/mpt2sas_base.c +4
-0+spin_lock_irqsave (&ioc->scsi_lookup_lock, flags); +_dechain_st (ioc, st); +spin_unlock_irqrestore (&ioc->scsi_lookup_lock, flags); + }This whole chain list thing looks bonkers to me. We always allocated a fixed multiple of the queue depth in ->chain_lookup, but then do this required list manipulation at least once per I/O submission and completion.
It is completely crazy, and very suboptimal. The only thing that "saves" it is that we only need to do it multiple times for larger IOs, where a larger per-IO hit can be accepted. But yes, it really should just die a horrible death.
Quoted 3 lines
Seems like we should instead add an array of (cpu address, dma address) tuples to the
scsiio_trackerand avoid all thechain_lookup/chain_listlookups entirely.
Agree.
Quoted 8 lines
drivers/scsi/mpt2sas/mpt2sas_base.c _wait_for_commands_to_complete(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) · line 4864
Quoted 4 lines
drivers/scsi/mpt2sas/mpt2sas_base.c +4
-0+if (shost_use_blk_mq (ioc->shost)) { + scmd =scsi_mq_find_tag (ioc->shost, i); +if (scsi_mq_scmd_started (scmd)) + pending++;Ok, I guess we should move the
request_startedcheck into the_find_taghelpers, as tags that aren't started aren't something that driver should ever lookup.
I'll move it in there.
Quoted 17 lines
drivers/scsi/mpt2sas/mpt2sas_ctl.c _ctl_poll(struct file *filep, poll_table *wait) · line 539
Quoted 8 lines
drivers/scsi/mpt2sas/mpt2sas_ctl.c +8
-0+static bool +_scmd_match (struct scsi_cmnd *scmd,u16 handle,u32 lun) +{ +struct MPT2SAS_DEVICE *priv_data; + +if (scmd ==NULL || scmd->device ==NULL || + scmd->device->hostdata ==NULL ) +return false;If the queue is started this can't ever happen.
Review
Quoted 2 lines
(quoted diff) +2
-0+ if (lun != scmd->device->lun) + return false;If you pass in a specific
scsi_deviceand thusrequest_queuethis can't happen.
Quoted 15 lines
drivers/scsi/mpt2sas/mpt2sas_ctl.c _ctl_poll(struct file *filep, poll_table *wait) · line 618
Quoted 8 lines
drivers/scsi/mpt2sas/mpt2sas_ctl.c +8
-0+static u16 +_ctl_find_smid (struct MPT2SAS_ADAPTER *ioc,u16 handle,u32 lun) +{ +if (shost_use_blk_mq (ioc->shost)) +return _ctl_find_smid_mq (ioc, handle, lun); +else +return _ctl_find_smid_legacy (ioc, handle, lun); +}The caller of this looks entirely broken. It's a driver specific API to submit task management commands, duplicating the mid level code, and it doesn't even allow which task to target. I think we should just return a error when invoking
MPI2_FUNCTION_SCSI_TASK_MGMTinstead of digging us an even deeper grave here. If someone complains we'll have to find a way to redirect it to the generic EH ioctls.
Sounds fine to me, will make my life a lot easier and we can kill this horrible lookup mess.
Signature · 1 line
Jens Axboe
Re: [PATCH 6/7] mpt2sas: store scsi io tracker data in the scsi command / request
Quoted 8 lines · Jens Axboe
Quoted 4 lines
The mq case will also work for the !mq case when you call
scsi_host_find_tagandscsi_cmd_priv. In general all the mq-specific
codepathes you add should become the default and only one, even if this requires a lit bit of additional core work.For the core code, I definitely agree. But for this case, in scsi-mq mode, we know that tag == smid - 1. That's not the case if we are not using scsi-mq.
It is if you use the old block tagging code with host-wide tags. I guess you'll need to tell mpt2 and mpt3 to use that firs, though.
Quoted 2 lines
In general, it'd be great if we could "convert" drivers and not have to support both scsi-mq and legacy mode. Then I could just rip the old code.
Well, the whole point is that you should be able to write a driver like your mq version and it should just work. Even better would be if we could get rid of the old case entirely for scsi, but for that we need a I/O scheduler for blk-mq first :)
Jens Axboe
maintainerRe: [PATCH 6/7] mpt2sas: store scsi io tracker data in the scsi command / request
Quoted 6 lines · Christoph Hellwig
Quoted 5 lines · Jens Axboe
Quoted 4 lines
The mq case will also work for the !mq case when you call
scsi_host_find_tagandscsi_cmd_priv. In general all the mq-specific
codepathes you add should become the default and only one, even if this requires a lit bit of additional core work.
Quoted 6 lines
Quoted 3 lines
For the core code, I definitely agree. But for this case, in scsi-mq mode, we know that tag == smid - 1. That's not the case if we are not using scsi-mq.
It is if you use the old block tagging code with host-wide tags. I guess you'll need to tell mpt2 and mpt3 to use that firs, though.
Yup
Quoted 5 lines
Quoted 2 lines
In general, it'd be great if we could "convert" drivers and not have to support both scsi-mq and legacy mode. Then I could just rip the old code.
Well, the whole point is that you should be able to write a driver like your mq version and it should just work. Even better would be if we
It'd be nice to have a host template flag that says "I only run scsi-mq", so we didn't have to cater to both cases. Or maybe that already exists and I just didn't look hard enough.
Quoted 2 lines
could get rid of the old case entirely for scsi, but for that we need a I/O scheduler for blk-mq first :)
I hear ya :)
Signature · 1 line
Jens Axboe
PATCH 7/7 mpt3sas: store scsi io tracker data in the scsi command / request
In reply to Jens AxboeInstead of storing the IO tracker structure in a separate list that we need to pop/push to on every submit and complete (and lock), store it in the pdu associated with a request. This is possible on scsi-mq only, and further cuts the spinlock associated time for higher IOPS IO workloads. At 100K IOPS, this effectively cuts the locking time in half.
--- drivers/scsi/mpt3sas/mpt3sas_base.c | 180 +++++++++++++++++++++++++---------- drivers/scsi/mpt3sas/mpt3sas_base.h | 2 + drivers/scsi/mpt3sas/mpt3sas_ctl.c | 119 ++++++++++++++++++----- drivers/scsi/mpt3sas/mpt3sas_scsih.c | 71 +++++++++++--- 4 files changed, 288 insertions(+), 84 deletions(-)
drivers/scsi/mpt3sas/mpt3sas_base.c +132 -48
@@ -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 ); }/**
drivers/scsi/mpt3sas/mpt3sas_base.h +2 -0
@@ -986,6 +986,8 @@ u16 mpt3sas_base_get_smid_hpr(struct MPT3SAS_ADAPTER *ioc, u8 cb_idx);u16 mpt3sas_base_get_smid_scsiio (struct MPT3SAS_ADAPTER *ioc,u8 cb_idx,struct scsi_cmnd *scmd); +struct scsiio_tracker *mpt3sas_get_st_from_smid (struct MPT3SAS_ADAPTER *ioc, +u16 smid);u16 mpt3sas_base_get_smid (struct MPT3SAS_ADAPTER *ioc,u8 cb_idx);void mpt3sas_base_free_smid (struct MPT3SAS_ADAPTER *ioc,u16 smid); void mpt3sas_base_put_smid_scsi_io(struct MPT3SAS_ADAPTER *ioc, u16 smid,
drivers/scsi/mpt3sas/mpt3sas_ctl.c +94 -25
145 lines not on this page · raw message
drivers/scsi/mpt3sas/mpt3sas_scsih.c +60 -11
131 lines not on this page · raw message
Signature · 1 line
1.9.1