Commit df7baa50 authored by Andrew Vasquez's avatar Andrew Vasquez Committed by James Bottomley

[SCSI] qla2xxx: Correct QUEUE_FULL handling.

- Drop queue-depths across all luns for a given fcport
  during TASK_SET_FULL statuses.
- Ramp-up I/Os after throttling.
- Consolidate completion-status handling of CS_QUEUE_FULL with
  CS_COMPLETE as ISP24xx firmware no longer reports
  CS_QUEUE_FULL.
Signed-off-by: default avatarAndrew Vasquez <andrew.vasquez@qlogic.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@SteelEye.com>
parent 18c6c127
...@@ -1545,6 +1545,9 @@ typedef struct fc_port { ...@@ -1545,6 +1545,9 @@ typedef struct fc_port {
spinlock_t rport_lock; spinlock_t rport_lock;
struct fc_rport *rport, *drport; struct fc_rport *rport, *drport;
u32 supported_classes; u32 supported_classes;
unsigned long last_queue_full;
unsigned long last_ramp_up;
} fc_port_t; } fc_port_t;
/* /*
...@@ -2255,6 +2258,7 @@ typedef struct scsi_qla_host { ...@@ -2255,6 +2258,7 @@ typedef struct scsi_qla_host {
uint16_t mgmt_svr_loop_id; uint16_t mgmt_svr_loop_id;
uint32_t login_retry_count; uint32_t login_retry_count;
int max_q_depth;
/* Fibre Channel Device List. */ /* Fibre Channel Device List. */
struct list_head fcports; struct list_head fcports;
......
...@@ -62,6 +62,7 @@ extern int ql2xloginretrycount; ...@@ -62,6 +62,7 @@ extern int ql2xloginretrycount;
extern int ql2xfdmienable; extern int ql2xfdmienable;
extern int ql2xallocfwdump; extern int ql2xallocfwdump;
extern int ql2xextended_error_logging; extern int ql2xextended_error_logging;
extern int ql2xqfullrampup;
extern void qla2x00_sp_compl(scsi_qla_host_t *, srb_t *); extern void qla2x00_sp_compl(scsi_qla_host_t *, srb_t *);
......
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
*/ */
#include "qla_def.h" #include "qla_def.h"
#include <scsi/scsi_tcq.h>
static void qla2x00_mbx_completion(scsi_qla_host_t *, uint16_t); static void qla2x00_mbx_completion(scsi_qla_host_t *, uint16_t);
static void qla2x00_async_event(scsi_qla_host_t *, uint16_t *); static void qla2x00_async_event(scsi_qla_host_t *, uint16_t *);
static void qla2x00_process_completed_request(struct scsi_qla_host *, uint32_t); static void qla2x00_process_completed_request(struct scsi_qla_host *, uint32_t);
...@@ -593,6 +595,67 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) ...@@ -593,6 +595,67 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
} }
} }
static void
qla2x00_adjust_sdev_qdepth_up(struct scsi_device *sdev, void *data)
{
fc_port_t *fcport = data;
if (fcport->ha->max_q_depth <= sdev->queue_depth)
return;
if (sdev->ordered_tags)
scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG,
sdev->queue_depth + 1);
else
scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG,
sdev->queue_depth + 1);
fcport->last_ramp_up = jiffies;
DEBUG2(qla_printk(KERN_INFO, fcport->ha,
"scsi(%ld:%d:%d:%d): Queue depth adjusted-up to %d.\n",
fcport->ha->host_no, sdev->channel, sdev->id, sdev->lun,
sdev->queue_depth));
}
static void
qla2x00_adjust_sdev_qdepth_down(struct scsi_device *sdev, void *data)
{
fc_port_t *fcport = data;
if (!scsi_track_queue_full(sdev, sdev->queue_depth - 1))
return;
DEBUG2(qla_printk(KERN_INFO, fcport->ha,
"scsi(%ld:%d:%d:%d): Queue depth adjusted-down to %d.\n",
fcport->ha->host_no, sdev->channel, sdev->id, sdev->lun,
sdev->queue_depth));
}
static inline void
qla2x00_ramp_up_queue_depth(scsi_qla_host_t *ha, srb_t *sp)
{
fc_port_t *fcport;
struct scsi_device *sdev;
sdev = sp->cmd->device;
if (sdev->queue_depth >= ha->max_q_depth)
return;
fcport = sp->fcport;
if (time_before(jiffies,
fcport->last_ramp_up + ql2xqfullrampup * HZ))
return;
if (time_before(jiffies,
fcport->last_queue_full + ql2xqfullrampup * HZ))
return;
spin_unlock_irq(&ha->hardware_lock);
starget_for_each_device(sdev->sdev_target, fcport,
qla2x00_adjust_sdev_qdepth_up);
spin_lock_irq(&ha->hardware_lock);
}
/** /**
* qla2x00_process_completed_request() - Process a Fast Post response. * qla2x00_process_completed_request() - Process a Fast Post response.
* @ha: SCSI driver HA context * @ha: SCSI driver HA context
...@@ -624,6 +687,8 @@ qla2x00_process_completed_request(struct scsi_qla_host *ha, uint32_t index) ...@@ -624,6 +687,8 @@ qla2x00_process_completed_request(struct scsi_qla_host *ha, uint32_t index)
/* Save ISP completion status */ /* Save ISP completion status */
sp->cmd->result = DID_OK << 16; sp->cmd->result = DID_OK << 16;
qla2x00_ramp_up_queue_depth(ha, sp);
qla2x00_sp_compl(ha, sp); qla2x00_sp_compl(ha, sp);
} else { } else {
DEBUG2(printk("scsi(%ld): Invalid ISP SCSI completion handle\n", DEBUG2(printk("scsi(%ld): Invalid ISP SCSI completion handle\n",
...@@ -823,6 +888,7 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt) ...@@ -823,6 +888,7 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
*/ */
switch (comp_status) { switch (comp_status) {
case CS_COMPLETE: case CS_COMPLETE:
case CS_QUEUE_FULL:
if (scsi_status == 0) { if (scsi_status == 0) {
cp->result = DID_OK << 16; cp->result = DID_OK << 16;
break; break;
...@@ -849,6 +915,20 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt) ...@@ -849,6 +915,20 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
} }
cp->result = DID_OK << 16 | lscsi_status; cp->result = DID_OK << 16 | lscsi_status;
if (lscsi_status == SAM_STAT_TASK_SET_FULL) {
DEBUG2(printk(KERN_INFO
"scsi(%ld): QUEUE FULL status detected "
"0x%x-0x%x.\n", ha->host_no, comp_status,
scsi_status));
/* Adjust queue depth for all luns on the port. */
fcport->last_queue_full = jiffies;
spin_unlock_irq(&ha->hardware_lock);
starget_for_each_device(cp->device->sdev_target,
fcport, qla2x00_adjust_sdev_qdepth_down);
spin_lock_irq(&ha->hardware_lock);
break;
}
if (lscsi_status != SS_CHECK_CONDITION) if (lscsi_status != SS_CHECK_CONDITION)
break; break;
...@@ -1066,17 +1146,6 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt) ...@@ -1066,17 +1146,6 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
qla2x00_mark_device_lost(ha, fcport, 1, 1); qla2x00_mark_device_lost(ha, fcport, 1, 1);
break; break;
case CS_QUEUE_FULL:
DEBUG2(printk(KERN_INFO
"scsi(%ld): QUEUE FULL status detected 0x%x-0x%x.\n",
ha->host_no, comp_status, scsi_status));
/* SCSI Mid-Layer handles device queue full */
cp->result = DID_OK << 16 | lscsi_status;
break;
default: default:
DEBUG3(printk("scsi(%ld): Error detected (unknown status) " DEBUG3(printk("scsi(%ld): Error detected (unknown status) "
"0x%x-0x%x.\n", ha->host_no, comp_status, scsi_status)); "0x%x-0x%x.\n", ha->host_no, comp_status, scsi_status));
......
...@@ -77,6 +77,19 @@ MODULE_PARM_DESC(ql2xfdmienable, ...@@ -77,6 +77,19 @@ MODULE_PARM_DESC(ql2xfdmienable,
"Enables FDMI registratons " "Enables FDMI registratons "
"Default is 0 - no FDMI. 1 - perfom FDMI."); "Default is 0 - no FDMI. 1 - perfom FDMI.");
#define MAX_Q_DEPTH 32
static int ql2xmaxqdepth = MAX_Q_DEPTH;
module_param(ql2xmaxqdepth, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(ql2xmaxqdepth,
"Maximum queue depth to report for target devices.");
int ql2xqfullrampup = 120;
module_param(ql2xqfullrampup, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(ql2xqfullrampup,
"Number of seconds to wait to begin to ramp-up the queue "
"depth for a device after a queue-full condition has been "
"detected. Default is 120 seconds.");
/* /*
* SCSI host template entry points * SCSI host template entry points
*/ */
...@@ -1104,9 +1117,9 @@ qla2xxx_slave_configure(struct scsi_device *sdev) ...@@ -1104,9 +1117,9 @@ qla2xxx_slave_configure(struct scsi_device *sdev)
struct fc_rport *rport = starget_to_rport(sdev->sdev_target); struct fc_rport *rport = starget_to_rport(sdev->sdev_target);
if (sdev->tagged_supported) if (sdev->tagged_supported)
scsi_activate_tcq(sdev, 32); scsi_activate_tcq(sdev, ha->max_q_depth);
else else
scsi_deactivate_tcq(sdev, 32); scsi_deactivate_tcq(sdev, ha->max_q_depth);
rport->dev_loss_tmo = ha->port_down_retry_count + 5; rport->dev_loss_tmo = ha->port_down_retry_count + 5;
...@@ -1413,6 +1426,10 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) ...@@ -1413,6 +1426,10 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->link_data_rate = PORT_SPEED_UNKNOWN; ha->link_data_rate = PORT_SPEED_UNKNOWN;
ha->optrom_size = OPTROM_SIZE_2300; ha->optrom_size = OPTROM_SIZE_2300;
ha->max_q_depth = MAX_Q_DEPTH;
if (ql2xmaxqdepth != 0 && ql2xmaxqdepth <= 0xffffU)
ha->max_q_depth = ql2xmaxqdepth;
/* Assign ISP specific operations. */ /* Assign ISP specific operations. */
ha->isp_ops.pci_config = qla2100_pci_config; ha->isp_ops.pci_config = qla2100_pci_config;
ha->isp_ops.reset_chip = qla2x00_reset_chip; ha->isp_ops.reset_chip = qla2x00_reset_chip;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment