@@ -1345,6 +1345,8 @@ struct pqi_ctrl_info {
struct work_struct ofa_quiesce_work;
u32 ofa_bytes_requested;
u16 ofa_cancel_reason;
+
+ atomic_t total_scmds_outstanding;
};
enum pqi_ctrl_mode {
@@ -5509,6 +5509,8 @@ static inline bool pqi_is_bypass_eligible_request(struct scsi_cmnd *scmd)
void pqi_prep_for_scsi_done(struct scsi_cmnd *scmd)
{
struct pqi_scsi_dev *device;
+ struct pqi_ctrl_info *ctrl_info;
+ struct Scsi_Host *shost;
if (!scmd->device) {
set_host_byte(scmd, DID_NO_CONNECT);
@@ -5521,7 +5523,11 @@ void pqi_prep_for_scsi_done(struct scsi_cmnd *scmd)
return;
}
+ shost = scmd->device->host;
+ ctrl_info = shost_to_hba(shost);
+
atomic_dec(&device->scsi_cmds_outstanding);
+ atomic_dec(&ctrl_info->total_scmds_outstanding);
}
static bool pqi_is_parity_write_stream(struct pqi_ctrl_info *ctrl_info,
@@ -5609,6 +5615,7 @@ static int pqi_scsi_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scm
bool raid_bypassed;
device = scmd->device->hostdata;
+ ctrl_info = shost_to_hba(shost);
if (!device) {
set_host_byte(scmd, DID_NO_CONNECT);
@@ -5617,8 +5624,11 @@ static int pqi_scsi_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scm
}
atomic_inc(&device->scsi_cmds_outstanding);
-
- ctrl_info = shost_to_hba(shost);
+ if (atomic_inc_return(&ctrl_info->total_scmds_outstanding) >
+ ctrl_info->scsi_ml_can_queue) {
+ rc = SCSI_MLQUEUE_HOST_BUSY;
+ goto out;
+ }
if (pqi_ctrl_offline(ctrl_info) || pqi_device_in_remove(device)) {
set_host_byte(scmd, DID_NO_CONNECT);
@@ -5661,8 +5671,10 @@ static int pqi_scsi_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scm
}
out:
- if (rc)
+ if (rc) {
atomic_dec(&device->scsi_cmds_outstanding);
+ atomic_dec(&ctrl_info->total_scmds_outstanding);
+ }
return rc;
}
@@ -7985,6 +7997,7 @@ static struct pqi_ctrl_info *pqi_alloc_ctrl_info(int numa_node)
INIT_WORK(&ctrl_info->event_work, pqi_event_worker);
atomic_set(&ctrl_info->num_interrupts, 0);
+ atomic_set(&ctrl_info->total_scmds_outstanding, 0);
INIT_DELAYED_WORK(&ctrl_info->rescan_work, pqi_rescan_worker);
INIT_DELAYED_WORK(&ctrl_info->update_time_work, pqi_update_time_worker);