Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4fdfefe5 authored by Andrew Vasquez's avatar Andrew Vasquez Committed by James Bottomley
Browse files

[SCSI] qla2xxx: Add support to dynamically enable/disable ZIO.



ISP23xx and ISP24xx chips have support for an adaptive
method of posting SCSI command completions for multiple SCSI
commands during a single system interrupt.

SCSI commands are placed on the system response queue
without interrupting the host until 1) a delay timer
expires; or 2) a SCSI command completes with an error.

As long as the host software (qla2xxx) services the response
queue for completions (this polling is done during
queuecommand()) within the 'delay timer' period, the
firmware will not generate system interrupt.

Signed-off-by: default avatarAndrew Vasquez <andrew.vasquez@qlogic.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@SteelEye.com>
parent 0eedfcf0
Loading
Loading
Loading
Loading
+83 −0
Original line number Diff line number Diff line
@@ -319,6 +319,83 @@ qla2x00_state_show(struct class_device *cdev, char *buf)
	return len;
}

static ssize_t
qla2x00_zio_show(struct class_device *cdev, char *buf)
{
	scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
	int len = 0;

	switch (ha->zio_mode) {
	case QLA_ZIO_MODE_5:
		len += snprintf(buf + len, PAGE_SIZE-len, "Mode 5\n");
		break;
	case QLA_ZIO_MODE_6:
		len += snprintf(buf + len, PAGE_SIZE-len, "Mode 6\n");
		break;
	case QLA_ZIO_DISABLED:
		len += snprintf(buf + len, PAGE_SIZE-len, "Disabled\n");
		break;
	}
	return len;
}

static ssize_t
qla2x00_zio_store(struct class_device *cdev, const char *buf, size_t count)
{
	scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
	int val = 0;
	uint16_t zio_mode;

	if (sscanf(buf, "%d", &val) != 1)
		return -EINVAL;

	switch (val) {
	case 1:
		zio_mode = QLA_ZIO_MODE_5;
		break;
	case 2:
		zio_mode = QLA_ZIO_MODE_6;
		break;
	default:
		zio_mode = QLA_ZIO_DISABLED;
		break;
	}

	/* Update per-hba values and queue a reset. */
	if (zio_mode != QLA_ZIO_DISABLED || ha->zio_mode != QLA_ZIO_DISABLED) {
		ha->zio_mode = zio_mode;
		set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
	}
	return strlen(buf);
}

static ssize_t
qla2x00_zio_timer_show(struct class_device *cdev, char *buf)
{
	scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));

	return snprintf(buf, PAGE_SIZE, "%d us\n", ha->zio_timer * 100);
}

static ssize_t
qla2x00_zio_timer_store(struct class_device *cdev, const char *buf,
    size_t count)
{
	scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
	int val = 0;
	uint16_t zio_timer;

	if (sscanf(buf, "%d", &val) != 1)
		return -EINVAL;
	if (val > 25500 || val < 100)
		return -ERANGE;

	zio_timer = (uint16_t)(val / 100);
	ha->zio_timer = zio_timer;

	return strlen(buf);
}

static CLASS_DEVICE_ATTR(driver_version, S_IRUGO, qla2x00_drvr_version_show,
	NULL);
static CLASS_DEVICE_ATTR(fw_version, S_IRUGO, qla2x00_fw_version_show, NULL);
@@ -329,6 +406,10 @@ static CLASS_DEVICE_ATTR(model_name, S_IRUGO, qla2x00_model_name_show, NULL);
static CLASS_DEVICE_ATTR(model_desc, S_IRUGO, qla2x00_model_desc_show, NULL);
static CLASS_DEVICE_ATTR(pci_info, S_IRUGO, qla2x00_pci_info_show, NULL);
static CLASS_DEVICE_ATTR(state, S_IRUGO, qla2x00_state_show, NULL);
static CLASS_DEVICE_ATTR(zio, S_IRUGO | S_IWUSR, qla2x00_zio_show,
    qla2x00_zio_store);
static CLASS_DEVICE_ATTR(zio_timer, S_IRUGO | S_IWUSR, qla2x00_zio_timer_show,
    qla2x00_zio_timer_store);

struct class_device_attribute *qla2x00_host_attrs[] = {
	&class_device_attr_driver_version,
@@ -340,6 +421,8 @@ struct class_device_attribute *qla2x00_host_attrs[] = {
	&class_device_attr_model_desc,
	&class_device_attr_pci_info,
	&class_device_attr_state,
	&class_device_attr_zio,
	&class_device_attr_zio_timer,
	NULL,
};

+8 −0
Original line number Diff line number Diff line
@@ -823,6 +823,11 @@ typedef struct {
#define PD_STATE_WAIT_PORT_LOGOUT_ACK		11


#define QLA_ZIO_MODE_5		(BIT_2 | BIT_0)
#define QLA_ZIO_MODE_6		(BIT_2 | BIT_1)
#define QLA_ZIO_DISABLED	0
#define QLA_ZIO_DEFAULT_TIMER	2

/*
 * ISP Initialization Control Block.
 * Little endian except where noted.
@@ -2470,6 +2475,9 @@ typedef struct scsi_qla_host {
	/* Needed for BEACON */
	uint16_t	beacon_blink_led;
	uint16_t	beacon_green_on;

	uint16_t	zio_mode;
	uint16_t	zio_timer;
} scsi_qla_host_t;


+1 −2
Original line number Diff line number Diff line
@@ -76,8 +76,6 @@ extern char qla2x00_version_str[];
extern int ql2xlogintimeout;
extern int qlport_down_retry;
extern int ql2xplogiabsentdevice;
extern int ql2xenablezio;
extern int ql2xintrdelaytimer;
extern int ql2xloginretrycount;
extern int ql2xfdmienable;

@@ -223,6 +221,7 @@ extern irqreturn_t qla2100_intr_handler(int, void *, struct pt_regs *);
extern irqreturn_t qla2300_intr_handler(int, void *, struct pt_regs *);
extern irqreturn_t qla24xx_intr_handler(int, void *, struct pt_regs *);
extern void qla2x00_process_response_queue(struct scsi_qla_host *);
extern void qla24xx_process_response_queue(struct scsi_qla_host *);

/*
 * Global Function Prototypes in qla_sup.c source file.
+40 −13
Original line number Diff line number Diff line
@@ -1372,7 +1372,6 @@ qla2x00_nvram_config(scsi_qla_host_t *ha)
	nvram_t         *nv = (nvram_t *)ha->request_ring;
	uint8_t         *ptr = (uint8_t *)ha->request_ring;
	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
	uint8_t         timer_mode;

	rval = QLA_SUCCESS;

@@ -1650,22 +1649,26 @@ qla2x00_nvram_config(scsi_qla_host_t *ha)

		ha->flags.process_response_queue = 1;
	} else {
		/* Enable ZIO -- Support mode 5 only. */
		timer_mode = icb->add_firmware_options[0] &
		/* Enable ZIO. */
		if (!ha->flags.init_done) {
			ha->zio_mode = icb->add_firmware_options[0] &
			    (BIT_3 | BIT_2 | BIT_1 | BIT_0);
			ha->zio_timer = icb->interrupt_delay_timer ?
			    icb->interrupt_delay_timer: 2;
		}
		icb->add_firmware_options[0] &=
		    ~(BIT_3 | BIT_2 | BIT_1 | BIT_0);
		if (ql2xenablezio)
			timer_mode = BIT_2 | BIT_0;
		if (timer_mode == (BIT_2 | BIT_0)) {
			DEBUG2(printk("scsi(%ld): ZIO enabled; timer delay "
			    "(%d).\n", ha->host_no, ql2xintrdelaytimer));
		ha->flags.process_response_queue = 0;
		if (ha->zio_mode != QLA_ZIO_DISABLED) {
			DEBUG2(printk("scsi(%ld): ZIO mode %d enabled; timer "
			    "delay (%d us).\n", ha->host_no, ha->zio_mode,
			    ha->zio_timer * 100));
			qla_printk(KERN_INFO, ha,
			    "ZIO enabled; timer delay (%d).\n",
			    ql2xintrdelaytimer);
			    "ZIO mode %d enabled; timer delay (%d us).\n",
			    ha->zio_mode, ha->zio_timer * 100);

			icb->add_firmware_options[0] |= timer_mode;
			icb->interrupt_delay_timer = ql2xintrdelaytimer;
			icb->add_firmware_options[0] |= (uint8_t)ha->zio_mode;
			icb->interrupt_delay_timer = (uint8_t)ha->zio_timer;
			ha->flags.process_response_queue = 1;
		}
	}
@@ -3442,6 +3445,30 @@ qla24xx_nvram_config(scsi_qla_host_t *ha)
	if (ql2xloginretrycount)
		ha->login_retry_count = ql2xloginretrycount;

	/* Enable ZIO. */
	if (!ha->flags.init_done) {
		ha->zio_mode = le32_to_cpu(icb->firmware_options_2) &
		    (BIT_3 | BIT_2 | BIT_1 | BIT_0);
		ha->zio_timer = le16_to_cpu(icb->interrupt_delay_timer) ?
		    le16_to_cpu(icb->interrupt_delay_timer): 2;
	}
	icb->firmware_options_2 &= __constant_cpu_to_le32(
	    ~(BIT_3 | BIT_2 | BIT_1 | BIT_0));
	ha->flags.process_response_queue = 0;
	if (ha->zio_mode != QLA_ZIO_DISABLED) {
		DEBUG2(printk("scsi(%ld): ZIO mode %d enabled; timer delay "
		    "(%d us).\n", ha->host_no, ha->zio_mode,
		    ha->zio_timer * 100));
		qla_printk(KERN_INFO, ha,
		    "ZIO mode %d enabled; timer delay (%d us).\n",
		    ha->zio_mode, ha->zio_timer * 100);

		icb->firmware_options_2 |= cpu_to_le32(
		    (uint32_t)ha->zio_mode);
		icb->interrupt_delay_timer = cpu_to_le16(ha->zio_timer);
		ha->flags.process_response_queue = 1;
	}

	if (rval) {
		DEBUG2_3(printk(KERN_WARNING
		    "scsi(%ld): NVRAM configuration failed!\n", ha->host_no));
+10 −0
Original line number Diff line number Diff line
@@ -440,6 +440,11 @@ qla2x00_start_scsi(srb_t *sp)
	WRT_REG_WORD(ISP_REQ_Q_IN(ha, reg), ha->req_ring_index);
	RD_REG_WORD_RELAXED(ISP_REQ_Q_IN(ha, reg));	/* PCI Posting. */

	/* Manage unprocessed RIO/ZIO commands in response queue. */
	if (ha->flags.process_response_queue &&
	    ha->response_ring_ptr->signature != RESPONSE_PROCESSED)
		qla2x00_process_response_queue(ha);

	spin_unlock_irqrestore(&ha->hardware_lock, flags);
	return (QLA_SUCCESS);

@@ -877,6 +882,11 @@ qla24xx_start_scsi(srb_t *sp)
	WRT_REG_DWORD(&reg->req_q_in, ha->req_ring_index);
	RD_REG_DWORD_RELAXED(&reg->req_q_in);		/* PCI Posting. */

	/* Manage unprocessed RIO/ZIO commands in response queue. */
	if (ha->flags.process_response_queue &&
	    ha->response_ring_ptr->signature != RESPONSE_PROCESSED)
		qla24xx_process_response_queue(ha);

	spin_unlock_irqrestore(&ha->hardware_lock, flags);
	return QLA_SUCCESS;

Loading