diff options
Diffstat (limited to 'drivers/scsi/qla2xxx')
-rw-r--r-- | drivers/scsi/qla2xxx/qla_attr.c | 51 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_dbg.h | 14 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_def.h | 4 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_gbl.h | 4 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_init.c | 23 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_isr.c | 91 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_os.c | 35 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_version.h | 2 |
8 files changed, 175 insertions, 49 deletions
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index ee75a71f3c66..285c8e8ff1a0 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -379,21 +379,37 @@ static struct bin_attribute sysfs_sfp_attr = { .read = qla2x00_sysfs_read_sfp, }; +static struct sysfs_entry { + char *name; + struct bin_attribute *attr; + int is4GBp_only; +} bin_file_entries[] = { + { "fw_dump", &sysfs_fw_dump_attr, }, + { "nvram", &sysfs_nvram_attr, }, + { "optrom", &sysfs_optrom_attr, }, + { "optrom_ctl", &sysfs_optrom_ctl_attr, }, + { "vpd", &sysfs_vpd_attr, 1 }, + { "sfp", &sysfs_sfp_attr, 1 }, + { 0 }, +}; + void qla2x00_alloc_sysfs_attr(scsi_qla_host_t *ha) { struct Scsi_Host *host = ha->host; + struct sysfs_entry *iter; + int ret; - sysfs_create_bin_file(&host->shost_gendev.kobj, &sysfs_fw_dump_attr); - sysfs_create_bin_file(&host->shost_gendev.kobj, &sysfs_nvram_attr); - sysfs_create_bin_file(&host->shost_gendev.kobj, &sysfs_optrom_attr); - sysfs_create_bin_file(&host->shost_gendev.kobj, - &sysfs_optrom_ctl_attr); - if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) { - sysfs_create_bin_file(&host->shost_gendev.kobj, - &sysfs_vpd_attr); - sysfs_create_bin_file(&host->shost_gendev.kobj, - &sysfs_sfp_attr); + for (iter = bin_file_entries; iter->name; iter++) { + if (iter->is4GBp_only && (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))) + continue; + + ret = sysfs_create_bin_file(&host->shost_gendev.kobj, + iter->attr); + if (ret) + qla_printk(KERN_INFO, ha, + "Unable to create sysfs %s binary attribute " + "(%d).\n", iter->name, ret); } } @@ -401,17 +417,14 @@ void qla2x00_free_sysfs_attr(scsi_qla_host_t *ha) { struct Scsi_Host *host = ha->host; + struct sysfs_entry *iter; + + for (iter = bin_file_entries; iter->name; iter++) { + if (iter->is4GBp_only && (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))) + continue; - sysfs_remove_bin_file(&host->shost_gendev.kobj, &sysfs_fw_dump_attr); - sysfs_remove_bin_file(&host->shost_gendev.kobj, &sysfs_nvram_attr); - sysfs_remove_bin_file(&host->shost_gendev.kobj, &sysfs_optrom_attr); - sysfs_remove_bin_file(&host->shost_gendev.kobj, - &sysfs_optrom_ctl_attr); - if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) { - sysfs_remove_bin_file(&host->shost_gendev.kobj, - &sysfs_vpd_attr); sysfs_remove_bin_file(&host->shost_gendev.kobj, - &sysfs_sfp_attr); + iter->attr); } if (ha->beacon_blink_led == 1) diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h index 90dad7e88985..5b12278968e0 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.h +++ b/drivers/scsi/qla2xxx/qla_dbg.h @@ -38,7 +38,7 @@ * Macros use for debugging the driver. */ -#define DEBUG(x) do { if (qla2_extended_error_logging) { x; } } while (0) +#define DEBUG(x) do { if (ql2xextended_error_logging) { x; } } while (0) #if defined(QL_DEBUG_LEVEL_1) #define DEBUG1(x) do {x;} while (0) @@ -46,12 +46,12 @@ #define DEBUG1(x) do {} while (0) #endif -#define DEBUG2(x) do { if (qla2_extended_error_logging) { x; } } while (0) -#define DEBUG2_3(x) do { if (qla2_extended_error_logging) { x; } } while (0) -#define DEBUG2_3_11(x) do { if (qla2_extended_error_logging) { x; } } while (0) -#define DEBUG2_9_10(x) do { if (qla2_extended_error_logging) { x; } } while (0) -#define DEBUG2_11(x) do { if (qla2_extended_error_logging) { x; } } while (0) -#define DEBUG2_13(x) do { if (qla2_extended_error_logging) { x; } } while (0) +#define DEBUG2(x) do { if (ql2xextended_error_logging) { x; } } while (0) +#define DEBUG2_3(x) do { if (ql2xextended_error_logging) { x; } } while (0) +#define DEBUG2_3_11(x) do { if (ql2xextended_error_logging) { x; } } while (0) +#define DEBUG2_9_10(x) do { if (ql2xextended_error_logging) { x; } } while (0) +#define DEBUG2_11(x) do { if (ql2xextended_error_logging) { x; } } while (0) +#define DEBUG2_13(x) do { if (ql2xextended_error_logging) { x; } } while (0) #if defined(QL_DEBUG_LEVEL_3) #define DEBUG3(x) do {x;} while (0) diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index bab33f6d0bdb..c4fc40f8e8ca 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -1545,6 +1545,9 @@ typedef struct fc_port { spinlock_t rport_lock; struct fc_rport *rport, *drport; u32 supported_classes; + + unsigned long last_queue_full; + unsigned long last_ramp_up; } fc_port_t; /* @@ -2255,6 +2258,7 @@ typedef struct scsi_qla_host { uint16_t mgmt_svr_loop_id; uint32_t login_retry_count; + int max_q_depth; /* Fibre Channel Device List. */ struct list_head fcports; diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 7da69832d74c..32ebeec45ff0 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -48,6 +48,7 @@ extern void qla2x00_update_fcport(scsi_qla_host_t *, fc_port_t *); extern void qla2x00_reg_remote_port(scsi_qla_host_t *, fc_port_t *); extern void qla2x00_alloc_fw_dump(scsi_qla_host_t *); +extern void qla2x00_try_to_stop_firmware(scsi_qla_host_t *); /* * Global Data in qla_os.c source file. @@ -60,7 +61,8 @@ extern int ql2xplogiabsentdevice; extern int ql2xloginretrycount; extern int ql2xfdmienable; extern int ql2xallocfwdump; -extern int qla2_extended_error_logging; +extern int ql2xextended_error_logging; +extern int ql2xqfullrampup; extern void qla2x00_sp_compl(scsi_qla_host_t *, srb_t *); diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 833b93085fd3..08cb5e3fb553 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -1644,7 +1644,7 @@ qla2x00_nvram_config(scsi_qla_host_t *ha) * Set host adapter parameters. */ if (nv->host_p[0] & BIT_7) - qla2_extended_error_logging = 1; + ql2xextended_error_logging = 1; ha->flags.disable_risc_code_load = ((nv->host_p[0] & BIT_4) ? 1 : 0); /* Always load RISC code on non ISP2[12]00 chips. */ if (!IS_QLA2100(ha) && !IS_QLA2200(ha)) @@ -3948,3 +3948,24 @@ qla24xx_load_risc(scsi_qla_host_t *ha, uint32_t *srisc_addr) fail_fw_integrity: return QLA_FUNCTION_FAILED; } + +void +qla2x00_try_to_stop_firmware(scsi_qla_host_t *ha) +{ + int ret, retries; + + if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha)) + return; + + ret = qla2x00_stop_firmware(ha); + for (retries = 5; ret != QLA_SUCCESS && retries ; retries--) { + qla2x00_reset_chip(ha); + if (qla2x00_chip_diag(ha) != QLA_SUCCESS) + continue; + if (qla2x00_setup_chip(ha) != QLA_SUCCESS) + continue; + qla_printk(KERN_INFO, ha, + "Attempting retry of stop-firmware command...\n"); + ret = qla2x00_stop_firmware(ha); + } +} diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 626c7178a434..d3b6df4d55c8 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -6,6 +6,8 @@ */ #include "qla_def.h" +#include <scsi/scsi_tcq.h> + 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_process_completed_request(struct scsi_qla_host *, uint32_t); @@ -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. * @ha: SCSI driver HA context @@ -624,6 +687,8 @@ qla2x00_process_completed_request(struct scsi_qla_host *ha, uint32_t index) /* Save ISP completion status */ sp->cmd->result = DID_OK << 16; + + qla2x00_ramp_up_queue_depth(ha, sp); qla2x00_sp_compl(ha, sp); } else { DEBUG2(printk("scsi(%ld): Invalid ISP SCSI completion handle\n", @@ -823,6 +888,7 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt) */ switch (comp_status) { case CS_COMPLETE: + case CS_QUEUE_FULL: if (scsi_status == 0) { cp->result = DID_OK << 16; break; @@ -849,6 +915,20 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt) } 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) break; @@ -1066,17 +1146,6 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt) qla2x00_mark_device_lost(ha, fcport, 1, 1); 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: DEBUG3(printk("scsi(%ld): Error detected (unknown status) " "0x%x-0x%x.\n", ha->host_no, comp_status, scsi_status)); diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 5e70c49fdf84..3eb4cd2cbc78 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -61,9 +61,9 @@ MODULE_PARM_DESC(ql2xallocfwdump, "during HBA initialization. Memory allocation requirements " "vary by ISP type. Default is 1 - allocate memory."); -int qla2_extended_error_logging; -module_param(qla2_extended_error_logging, int, S_IRUGO|S_IRUSR); -MODULE_PARM_DESC(qla2_extended_error_logging, +int ql2xextended_error_logging; +module_param(ql2xextended_error_logging, int, S_IRUGO|S_IRUSR); +MODULE_PARM_DESC(ql2xextended_error_logging, "Option to enable extended error logging, " "Default is 0 - no logging. 1 - log errors."); @@ -77,6 +77,19 @@ MODULE_PARM_DESC(ql2xfdmienable, "Enables FDMI registratons " "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 */ @@ -1104,9 +1117,9 @@ qla2xxx_slave_configure(struct scsi_device *sdev) struct fc_rport *rport = starget_to_rport(sdev->sdev_target); if (sdev->tagged_supported) - scsi_activate_tcq(sdev, 32); + scsi_activate_tcq(sdev, ha->max_q_depth); else - scsi_deactivate_tcq(sdev, 32); + scsi_deactivate_tcq(sdev, ha->max_q_depth); 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) ha->link_data_rate = PORT_SPEED_UNKNOWN; 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. */ ha->isp_ops.pci_config = qla2100_pci_config; ha->isp_ops.reset_chip = qla2x00_reset_chip; @@ -1712,8 +1729,10 @@ qla2x00_free_device(scsi_qla_host_t *ha) if (ha->eft) qla2x00_trace_control(ha, TC_DISABLE, 0, 0); + ha->flags.online = 0; + /* Stop currently executing firmware. */ - qla2x00_stop_firmware(ha); + qla2x00_try_to_stop_firmware(ha); /* turn-off interrupts on the card */ if (ha->interrupts_on) @@ -1721,8 +1740,6 @@ qla2x00_free_device(scsi_qla_host_t *ha) qla2x00_mem_free(ha); - ha->flags.online = 0; - /* Detach interrupts */ if (ha->host->irq) free_irq(ha->host->irq, ha); @@ -2697,7 +2714,7 @@ qla2x00_module_init(void) /* Derive version string. */ strcpy(qla2x00_version_str, QLA2XXX_VERSION); - if (qla2_extended_error_logging) + if (ql2xextended_error_logging) strcat(qla2x00_version_str, "-debug"); qla2xxx_transport_template = diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index e57bf45a3393..1fa0bce6b24e 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -7,7 +7,7 @@ /* * Driver version */ -#define QLA2XXX_VERSION "8.01.07-k2" +#define QLA2XXX_VERSION "8.01.07-k3" #define QLA_DRIVER_MAJOR_VER 8 #define QLA_DRIVER_MINOR_VER 1 |