diff options
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/lpfc/lpfc.h | 3 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_disc.h | 2 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_scsi.c | 58 |
3 files changed, 62 insertions, 1 deletions
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 1f3873ae9d6..38ffa8d6e62 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -29,9 +29,10 @@ struct lpfc_sli2_slim; #define LPFC_LC_HBA_Q_DEPTH 1024 /* max cmds per low cost hba */ #define LPFC_LP101_HBA_Q_DEPTH 128 /* max cmds per low cost hba */ -#define LPFC_CMD_PER_LUN 30 /* max outstanding cmds per lun */ +#define LPFC_CMD_PER_LUN 3 /* max outstanding cmds per lun */ #define LPFC_SG_SEG_CNT 64 /* sg element count per scsi cmnd */ #define LPFC_IOCB_LIST_CNT 2250 /* list of IOCBs for fast-path usage. */ +#define LPFC_Q_RAMP_UP_INTERVAL 120 /* lun q_depth ramp up interval */ /* Define macros for 64 bit support */ #define putPaddrLow(addr) ((uint32_t) (0xffffffff & (u64)(addr))) diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h index 084e7628ce1..ed6c81660e0 100644 --- a/drivers/scsi/lpfc/lpfc_disc.h +++ b/drivers/scsi/lpfc/lpfc_disc.h @@ -73,6 +73,8 @@ struct lpfc_nodelist { struct lpfc_hba *nlp_phba; struct lpfc_work_evt nodev_timeout_evt; struct lpfc_work_evt els_retry_evt; + unsigned long last_ramp_up_time; /* jiffy of last ramp up */ + unsigned long last_q_full_time; /* jiffy of last queue full */ }; /* Defines for nlp_flag (uint32) */ diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index c422220db0a..9ee8218404c 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -409,6 +409,9 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, struct lpfc_rport_data *rdata = lpfc_cmd->rdata; struct lpfc_nodelist *pnode = rdata->pnode; struct scsi_cmnd *cmd = lpfc_cmd->pCmd; + int result; + struct scsi_device *sdev, *tmp_sdev; + int depth = 0; lpfc_cmd->result = pIocbOut->iocb.un.ulpWord[4]; lpfc_cmd->status = pIocbOut->iocb.ulpStatus; @@ -460,8 +463,63 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, *lp, *(lp + 3), cmd->retries, cmd->resid); } + result = cmd->result; + sdev = cmd->device; cmd->scsi_done(cmd); + if (!result && + ((jiffies - pnode->last_ramp_up_time) > + LPFC_Q_RAMP_UP_INTERVAL * HZ) && + ((jiffies - pnode->last_q_full_time) > + LPFC_Q_RAMP_UP_INTERVAL * HZ) && + (phba->cfg_lun_queue_depth > sdev->queue_depth)) { + shost_for_each_device(tmp_sdev, sdev->host) { + if (phba->cfg_lun_queue_depth > tmp_sdev->queue_depth) { + if (tmp_sdev->id != sdev->id) + continue; + if (tmp_sdev->ordered_tags) + scsi_adjust_queue_depth(tmp_sdev, + MSG_ORDERED_TAG, + tmp_sdev->queue_depth+1); + else + scsi_adjust_queue_depth(tmp_sdev, + MSG_SIMPLE_TAG, + tmp_sdev->queue_depth+1); + + pnode->last_ramp_up_time = jiffies; + } + } + } + + /* + * Check for queue full. If the lun is reporting queue full, then + * back off the lun queue depth to prevent target overloads. + */ + if (result == SAM_STAT_TASK_SET_FULL) { + pnode->last_q_full_time = jiffies; + + shost_for_each_device(tmp_sdev, sdev->host) { + if (tmp_sdev->id != sdev->id) + continue; + depth = scsi_track_queue_full(tmp_sdev, + tmp_sdev->queue_depth - 1); + } + /* + * The queue depth cannot be lowered any more. + * Modify the returned error code to store + * the final depth value set by + * scsi_track_queue_full. + */ + if (depth == -1) + depth = sdev->host->cmd_per_lun; + + if (depth) { + lpfc_printf_log(phba, KERN_WARNING, LOG_FCP, + "%d:0711 detected queue full - lun queue depth " + " adjusted to %d.\n", phba->brd_no, depth); + } + } + lpfc_release_scsi_buf(phba, lpfc_cmd); } |