/*
* SRB allocation cache
*/
-static kmem_cache_t *srb_cachep;
+static struct kmem_cache *srb_cachep;
/*
* Ioctl related information.
"during HBA initialization. Memory allocation requirements "
"vary by ISP type. Default is 1 - allocate memory.");
-int extended_error_logging;
-module_param(extended_error_logging, int, S_IRUGO|S_IRUSR);
-MODULE_PARM_DESC(extended_error_logging,
+int ql2xextended_error_logging;
+module_param(ql2xextended_error_logging, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(ql2xextended_error_logging,
"Option to enable extended error logging, "
"Default is 0 - no logging. 1 - log errors.");
"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
*/
static int qla2xxx_slave_configure(struct scsi_device * device);
static int qla2xxx_slave_alloc(struct scsi_device *);
+static int qla2xxx_scan_finished(struct Scsi_Host *, unsigned long time);
+static void qla2xxx_scan_start(struct Scsi_Host *);
static void qla2xxx_slave_destroy(struct scsi_device *);
static int qla2x00_queuecommand(struct scsi_cmnd *cmd,
void (*fn)(struct scsi_cmnd *));
.slave_alloc = qla2xxx_slave_alloc,
.slave_destroy = qla2xxx_slave_destroy,
+ .scan_finished = qla2xxx_scan_finished,
+ .scan_start = qla2xxx_scan_start,
.change_queue_depth = qla2x00_change_queue_depth,
.change_queue_type = qla2x00_change_queue_type,
.this_id = -1,
.slave_alloc = qla2xxx_slave_alloc,
.slave_destroy = qla2xxx_slave_destroy,
+ .scan_finished = qla2xxx_scan_finished,
+ .scan_start = qla2xxx_scan_start,
.change_queue_depth = qla2x00_change_queue_depth,
.change_queue_type = qla2x00_change_queue_type,
.this_id = -1,
return str;
}
-char *
+static char *
qla2x00_fw_version_str(struct scsi_qla_host *ha, char *str)
{
char un_str[10];
return (str);
}
-char *
+static char *
qla24xx_fw_version_str(struct scsi_qla_host *ha, char *str)
{
sprintf(str, "%d.%02d.%02d ", ha->fw_major_version,
return (return_status);
}
+static void
+qla2x00_block_error_handler(struct scsi_cmnd *cmnd)
+{
+ struct Scsi_Host *shost = cmnd->device->host;
+ struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device));
+ unsigned long flags;
+
+ spin_lock_irqsave(shost->host_lock, flags);
+ while (rport->port_state == FC_PORTSTATE_BLOCKED) {
+ spin_unlock_irqrestore(shost->host_lock, flags);
+ msleep(1000);
+ spin_lock_irqsave(shost->host_lock, flags);
+ }
+ spin_unlock_irqrestore(shost->host_lock, flags);
+ return;
+}
+
/**************************************************************************
* qla2xxx_eh_abort
*
* Note:
* Only return FAILED if command not returned by firmware.
**************************************************************************/
-int
+static int
qla2xxx_eh_abort(struct scsi_cmnd *cmd)
{
scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
unsigned long flags;
int wait = 0;
+ qla2x00_block_error_handler(cmd);
+
if (!CMD_SP(cmd))
return SUCCESS;
* SUCCESS/FAILURE (defined as macro in scsi.h).
*
**************************************************************************/
-int
+static int
qla2xxx_eh_device_reset(struct scsi_cmnd *cmd)
{
scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
- srb_t *sp;
int ret;
unsigned int id, lun;
unsigned long serial;
+ qla2x00_block_error_handler(cmd);
+
ret = FAILED;
id = cmd->device->id;
lun = cmd->device->lun;
serial = cmd->serial_number;
- sp = (srb_t *) CMD_SP(cmd);
- if (!sp || !fcport)
+ if (!fcport)
return ret;
qla_printk(KERN_INFO, ha,
* SUCCESS/FAILURE (defined as macro in scsi.h).
*
**************************************************************************/
-int
+static int
qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd)
{
scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
- srb_t *sp;
int ret;
unsigned int id, lun;
unsigned long serial;
+ qla2x00_block_error_handler(cmd);
+
ret = FAILED;
id = cmd->device->id;
lun = cmd->device->lun;
serial = cmd->serial_number;
- sp = (srb_t *) CMD_SP(cmd);
- if (!sp || !fcport)
+ if (!fcport)
return ret;
qla_printk(KERN_INFO, ha,
*
* Note:
**************************************************************************/
-int
+static int
qla2xxx_eh_host_reset(struct scsi_cmnd *cmd)
{
scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
- srb_t *sp;
int ret;
unsigned int id, lun;
unsigned long serial;
+ qla2x00_block_error_handler(cmd);
+
ret = FAILED;
id = cmd->device->id;
lun = cmd->device->lun;
serial = cmd->serial_number;
- sp = (srb_t *) CMD_SP(cmd);
- if (!sp || !fcport)
+ if (!fcport)
return ret;
qla_printk(KERN_INFO, ha,
static int
qla2x00_loop_reset(scsi_qla_host_t *ha)
{
- int status = QLA_SUCCESS;
+ int ret;
struct fc_port *fcport;
+ if (ha->flags.enable_lip_full_login) {
+ ret = qla2x00_full_login_lip(ha);
+ if (ret != QLA_SUCCESS) {
+ DEBUG2_3(printk("%s(%ld): bus_reset failed: "
+ "full_login_lip=%d.\n", __func__, ha->host_no,
+ ret));
+ }
+ atomic_set(&ha->loop_state, LOOP_DOWN);
+ atomic_set(&ha->loop_down_timer, LOOP_DOWN_TIME);
+ qla2x00_mark_all_devices_lost(ha, 0);
+ qla2x00_wait_for_loop_ready(ha);
+ }
+
if (ha->flags.enable_lip_reset) {
- status = qla2x00_lip_reset(ha);
+ ret = qla2x00_lip_reset(ha);
+ if (ret != QLA_SUCCESS) {
+ DEBUG2_3(printk("%s(%ld): bus_reset failed: "
+ "lip_reset=%d.\n", __func__, ha->host_no, ret));
+ }
+ qla2x00_wait_for_loop_ready(ha);
}
- if (status == QLA_SUCCESS && ha->flags.enable_target_reset) {
+ if (ha->flags.enable_target_reset) {
list_for_each_entry(fcport, &ha->fcports, list) {
if (fcport->port_type != FCT_TARGET)
continue;
- status = qla2x00_device_reset(ha, fcport);
- if (status != QLA_SUCCESS)
- break;
+ ret = qla2x00_device_reset(ha, fcport);
+ if (ret != QLA_SUCCESS) {
+ DEBUG2_3(printk("%s(%ld): bus_reset failed: "
+ "target_reset=%d d_id=%x.\n", __func__,
+ ha->host_no, ret, fcport->d_id.b24));
+ }
}
}
- if (status == QLA_SUCCESS &&
- ((!ha->flags.enable_target_reset &&
- !ha->flags.enable_lip_reset) ||
- ha->flags.enable_lip_full_login)) {
-
- status = qla2x00_full_login_lip(ha);
- }
-
/* Issue marker command only when we are going to start the I/O */
ha->marker_needed = 1;
- if (status) {
- /* Empty */
- DEBUG2_3(printk("%s(%ld): **** FAILED ****\n",
- __func__,
- ha->host_no));
- } else {
- /* Empty */
- DEBUG3(printk("%s(%ld): exiting normally.\n",
- __func__,
- ha->host_no));
- }
-
- return(status);
+ return QLA_SUCCESS;
}
/*
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;
spin_unlock_irqrestore(&ha->hardware_lock, flags);
}
+static void
+qla2xxx_scan_start(struct Scsi_Host *shost)
+{
+ scsi_qla_host_t *ha = (scsi_qla_host_t *)shost->hostdata;
+
+ set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
+ set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags);
+ set_bit(RSCN_UPDATE, &ha->dpc_flags);
+}
+
+static int
+qla2xxx_scan_finished(struct Scsi_Host *shost, unsigned long time)
+{
+ scsi_qla_host_t *ha = (scsi_qla_host_t *)shost->hostdata;
+
+ if (!ha->host)
+ return 1;
+ if (time > ha->loop_reset_delay * HZ)
+ return 1;
+
+ return atomic_read(&ha->loop_state) == LOOP_READY;
+}
+
/*
* PCI driver interface
*/
struct Scsi_Host *host;
scsi_qla_host_t *ha;
unsigned long flags = 0;
- unsigned long wait_switch = 0;
char pci_info[20];
char fw_str[30];
- fc_port_t *fcport;
struct scsi_host_template *sht;
if (pci_enable_device(pdev))
sht = &qla2x00_driver_template;
if (pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2422 ||
- pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2432)
+ pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2432 ||
+ pdev->device == PCI_DEVICE_ID_QLOGIC_ISP5422 ||
+ pdev->device == PCI_DEVICE_ID_QLOGIC_ISP5432)
sht = &qla24xx_driver_template;
host = scsi_host_alloc(sht, sizeof(scsi_qla_host_t));
if (host == NULL) {
ha->prev_topology = 0;
ha->init_cb_size = sizeof(init_cb_t);
ha->mgmt_svr_loop_id = MANAGEMENT_SERVER;
- ha->link_data_rate = LDR_UNKNOWN;
+ 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;
ha->isp_ops.fw_dump = qla2100_fw_dump;
ha->isp_ops.read_optrom = qla2x00_read_optrom_data;
ha->isp_ops.write_optrom = qla2x00_write_optrom_data;
+ ha->isp_ops.get_flash_version = qla2x00_get_flash_version;
if (IS_QLA2100(ha)) {
host->max_id = MAX_TARGETS_2100;
ha->mbx_count = MAILBOX_REGISTER_COUNT_2100;
ha->isp_ops.beacon_on = qla24xx_beacon_on;
ha->isp_ops.beacon_off = qla24xx_beacon_off;
ha->isp_ops.beacon_blink = qla24xx_beacon_blink;
+ ha->isp_ops.get_flash_version = qla24xx_get_flash_version;
ha->gid_list_info_size = 8;
ha->optrom_size = OPTROM_SIZE_24XX;
}
INIT_LIST_HEAD(&ha->list);
INIT_LIST_HEAD(&ha->fcports);
- /*
- * These locks are used to prevent more than one CPU
- * from modifying the queue at the same time. The
- * higher level "host_lock" will reduce most
- * contention for these locks.
- */
- spin_lock_init(&ha->mbx_reg_lock);
-
qla2x00_config_dma_addressing(ha);
if (qla2x00_mem_alloc(ha)) {
qla_printk(KERN_WARNING, ha,
host->max_lun = MAX_LUNS;
host->transportt = qla2xxx_transport_template;
- ret = request_irq(pdev->irq, ha->isp_ops.intr_handler,
- IRQF_DISABLED|IRQF_SHARED, QLA2XXX_DRIVER_NAME, ha);
- if (ret) {
- qla_printk(KERN_WARNING, ha,
- "Failed to reserve interrupt %d already in use.\n",
- pdev->irq);
+ ret = qla2x00_request_irqs(ha);
+ if (ret)
goto probe_failed;
- }
- host->irq = pdev->irq;
/* Initialized the timer */
qla2x00_start_timer(ha, qla2x00_timer, WATCH_INTERVAL);
ha->isp_ops.enable_intrs(ha);
- /* v2.19.5b6 */
- /*
- * Wait around max loop_reset_delay secs for the devices to come
- * on-line. We don't want Linux scanning before we are ready.
- *
- */
- for (wait_switch = jiffies + (ha->loop_reset_delay * HZ);
- time_before(jiffies,wait_switch) &&
- !(ha->device_flags & (DFLG_NO_CABLE | DFLG_FABRIC_DEVICES))
- && (ha->device_flags & SWITCH_FOUND) ;) {
-
- qla2x00_check_fabric_devices(ha);
-
- msleep(10);
- }
-
pci_set_drvdata(pdev, ha);
+
ha->flags.init_done = 1;
+ ha->flags.online = 1;
+
num_hosts++;
ret = scsi_add_host(host, &pdev->dev);
if (ret)
goto probe_failed;
+ scsi_scan_host(host);
+
qla2x00_alloc_sysfs_attr(ha);
qla2x00_init_host_attr(ha);
ha->flags.enable_64bit_addressing ? '+': '-', ha->host_no,
ha->isp_ops.fw_version_str(ha, fw_str));
- /* Go with fc_rport registration. */
- list_for_each_entry(fcport, &ha->fcports, list)
- qla2x00_reg_remote_port(ha, fcport);
-
return 0;
probe_failed:
scsi_host_put(ha->host);
+ pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
}
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)
qla2x00_mem_free(ha);
- ha->flags.online = 0;
-
- /* Detach interrupts */
- if (ha->host->irq)
- free_irq(ha->host->irq, ha);
+ qla2x00_free_irqs(ha);
/* release io space registers */
if (ha->iobase)
iounmap(ha->iobase);
pci_release_regions(ha->pdev);
-
- pci_disable_device(ha->pdev);
}
static inline void
next_loopid = 0;
list_for_each_entry(fcport, &ha->fcports, list) {
- if (fcport->port_type != FCT_TARGET)
- continue;
-
/*
* If the port is not ONLINE then try to login
* to it if we haven't run out of retries.
#define FW_ISP2322 3
#define FW_ISP24XX 4
+#define FW_FILE_ISP21XX "ql2100_fw.bin"
+#define FW_FILE_ISP22XX "ql2200_fw.bin"
+#define FW_FILE_ISP2300 "ql2300_fw.bin"
+#define FW_FILE_ISP2322 "ql2322_fw.bin"
+#define FW_FILE_ISP24XX "ql2400_fw.bin"
+
static DECLARE_MUTEX(qla_fw_lock);
static struct fw_blob qla_fw_blobs[FW_BLOBS] = {
- { .name = "ql2100_fw.bin", .segs = { 0x1000, 0 }, },
- { .name = "ql2200_fw.bin", .segs = { 0x1000, 0 }, },
- { .name = "ql2300_fw.bin", .segs = { 0x800, 0 }, },
- { .name = "ql2322_fw.bin", .segs = { 0x800, 0x1c000, 0x1e000, 0 }, },
- { .name = "ql2400_fw.bin", },
+ { .name = FW_FILE_ISP21XX, .segs = { 0x1000, 0 }, },
+ { .name = FW_FILE_ISP22XX, .segs = { 0x1000, 0 }, },
+ { .name = FW_FILE_ISP2300, .segs = { 0x800, 0 }, },
+ { .name = FW_FILE_ISP2322, .segs = { 0x800, 0x1c000, 0x1e000, 0 }, },
+ { .name = FW_FILE_ISP24XX, },
};
struct fw_blob *
/* Derive version string. */
strcpy(qla2x00_version_str, QLA2XXX_VERSION);
- if (extended_error_logging)
+ if (ql2xextended_error_logging)
strcat(qla2x00_version_str, "-debug");
qla2xxx_transport_template =
MODULE_DESCRIPTION("QLogic Fibre Channel HBA Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(QLA2XXX_VERSION);
+MODULE_FIRMWARE(FW_FILE_ISP21XX);
+MODULE_FIRMWARE(FW_FILE_ISP22XX);
+MODULE_FIRMWARE(FW_FILE_ISP2300);
+MODULE_FIRMWARE(FW_FILE_ISP2322);
+MODULE_FIRMWARE(FW_FILE_ISP24XX);