diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 6cc91f83aa69..9acfce3bbe78 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3222,6 +3222,36 @@ static void check_ioctl_unit_attention(struct ctlr_info *h, c->err_info->ScsiStatus != SAM_STAT_CHECK_CONDITION) (void) check_for_unit_attention(h, c); } + +static int increment_passthru_count(struct ctlr_info *h) +{ + unsigned long flags; + + spin_lock_irqsave(&h->passthru_count_lock, flags); + if (h->passthru_count >= HPSA_MAX_CONCURRENT_PASSTHRUS) { + spin_unlock_irqrestore(&h->passthru_count_lock, flags); + return -1; + } + h->passthru_count++; + spin_unlock_irqrestore(&h->passthru_count_lock, flags); + return 0; +} + +static void decrement_passthru_count(struct ctlr_info *h) +{ + unsigned long flags; + + spin_lock_irqsave(&h->passthru_count_lock, flags); + if (h->passthru_count <= 0) { + spin_unlock_irqrestore(&h->passthru_count_lock, flags); + /* not expecting to get here. */ + dev_warn(&h->pdev->dev, "Bug detected, passthru_count seems to be incorrect.\n"); + return; + } + h->passthru_count--; + spin_unlock_irqrestore(&h->passthru_count_lock, flags); +} + /* * ioctl */ @@ -3229,6 +3259,7 @@ static int hpsa_ioctl(struct scsi_device *dev, int cmd, void *arg) { struct ctlr_info *h; void __user *argp = (void __user *)arg; + int rc; h = sdev_to_hba(dev); @@ -3243,9 +3274,17 @@ static int hpsa_ioctl(struct scsi_device *dev, int cmd, void *arg) case CCISS_GETDRIVVER: return hpsa_getdrivver_ioctl(h, argp); case CCISS_PASSTHRU: - return hpsa_passthru_ioctl(h, argp); + if (increment_passthru_count(h)) + return -EAGAIN; + rc = hpsa_passthru_ioctl(h, argp); + decrement_passthru_count(h); + return rc; case CCISS_BIG_PASSTHRU: - return hpsa_big_passthru_ioctl(h, argp); + if (increment_passthru_count(h)) + return -EAGAIN; + rc = hpsa_big_passthru_ioctl(h, argp); + decrement_passthru_count(h); + return rc; default: return -ENOTTY; } @@ -4835,6 +4874,7 @@ reinit_after_soft_reset: INIT_LIST_HEAD(&h->reqQ); spin_lock_init(&h->lock); spin_lock_init(&h->scan_lock); + spin_lock_init(&h->passthru_count_lock); rc = hpsa_pci_init(h); if (rc != 0) goto clean1; diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index bc85e7244f40..6eabf08ca672 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -114,6 +114,11 @@ struct ctlr_info { struct TransTable_struct *transtable; unsigned long transMethod; + /* cap concurrent passthrus at some reasonable maximum */ +#define HPSA_MAX_CONCURRENT_PASSTHRUS (20) + spinlock_t passthru_count_lock; /* protects passthru_count */ + int passthru_count; + /* * Performant mode completion buffers */