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

Commit 854165f4 authored by Andrew Vasquez's avatar Andrew Vasquez Committed by
Browse files

[SCSI] qla2xxx: Add support to retrieve/update HBA option-rom.

parent 1b3f6365
Loading
Loading
Loading
Loading
+135 −0
Original line number Diff line number Diff line
@@ -179,6 +179,135 @@ static struct bin_attribute sysfs_nvram_attr = {
	.write = qla2x00_sysfs_write_nvram,
};

static ssize_t
qla2x00_sysfs_read_optrom(struct kobject *kobj, char *buf, loff_t off,
    size_t count)
{
	struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
	    struct device, kobj)));

	if (ha->optrom_state != QLA_SREADING)
		return 0;
	if (off > ha->optrom_size)
		return 0;
	if (off + count > ha->optrom_size)
		count = ha->optrom_size - off;

	memcpy(buf, &ha->optrom_buffer[off], count);

	return count;
}

static ssize_t
qla2x00_sysfs_write_optrom(struct kobject *kobj, char *buf, loff_t off,
    size_t count)
{
	struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
	    struct device, kobj)));

	if (ha->optrom_state != QLA_SWRITING)
		return -EINVAL;
	if (off > ha->optrom_size)
		return -ERANGE;
	if (off + count > ha->optrom_size)
		count = ha->optrom_size - off;

	memcpy(&ha->optrom_buffer[off], buf, count);

	return count;
}

static struct bin_attribute sysfs_optrom_attr = {
	.attr = {
		.name = "optrom",
		.mode = S_IRUSR | S_IWUSR,
		.owner = THIS_MODULE,
	},
	.size = OPTROM_SIZE_24XX,
	.read = qla2x00_sysfs_read_optrom,
	.write = qla2x00_sysfs_write_optrom,
};

static ssize_t
qla2x00_sysfs_write_optrom_ctl(struct kobject *kobj, char *buf, loff_t off,
    size_t count)
{
	struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
	    struct device, kobj)));
	int val;

	if (off)
		return 0;

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

	switch (val) {
	case 0:
		if (ha->optrom_state != QLA_SREADING &&
		    ha->optrom_state != QLA_SWRITING)
			break;

		ha->optrom_state = QLA_SWAITING;
		vfree(ha->optrom_buffer);
		ha->optrom_buffer = NULL;
		break;
	case 1:
		if (ha->optrom_state != QLA_SWAITING)
			break;

		ha->optrom_state = QLA_SREADING;
		ha->optrom_buffer = (uint8_t *)vmalloc(ha->optrom_size);
		if (ha->optrom_buffer == NULL) {
			qla_printk(KERN_WARNING, ha,
			    "Unable to allocate memory for optrom retrieval "
			    "(%x).\n", ha->optrom_size);

			ha->optrom_state = QLA_SWAITING;
			return count;
		}

		memset(ha->optrom_buffer, 0, ha->optrom_size);
		ha->isp_ops.read_optrom(ha, ha->optrom_buffer, 0,
		    ha->optrom_size);
		break;
	case 2:
		if (ha->optrom_state != QLA_SWAITING)
			break;

		ha->optrom_state = QLA_SWRITING;
		ha->optrom_buffer = (uint8_t *)vmalloc(ha->optrom_size);
		if (ha->optrom_buffer == NULL) {
			qla_printk(KERN_WARNING, ha,
			    "Unable to allocate memory for optrom update "
			    "(%x).\n", ha->optrom_size);

			ha->optrom_state = QLA_SWAITING;
			return count;
		}
		memset(ha->optrom_buffer, 0, ha->optrom_size);
		break;
	case 3:
		if (ha->optrom_state != QLA_SWRITING)
			break;

		ha->isp_ops.write_optrom(ha, ha->optrom_buffer, 0,
		    ha->optrom_size);
		break;
	}
	return count;
}

static struct bin_attribute sysfs_optrom_ctl_attr = {
	.attr = {
		.name = "optrom_ctl",
		.mode = S_IWUSR,
		.owner = THIS_MODULE,
	},
	.size = 0,
	.write = qla2x00_sysfs_write_optrom_ctl,
};

void
qla2x00_alloc_sysfs_attr(scsi_qla_host_t *ha)
{
@@ -186,6 +315,9 @@ qla2x00_alloc_sysfs_attr(scsi_qla_host_t *ha)

	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);
}

void
@@ -195,6 +327,9 @@ qla2x00_free_sysfs_attr(scsi_qla_host_t *ha)

	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 (ha->beacon_blink_led == 1)
		ha->isp_ops.beacon_off(ha);
+16 −1
Original line number Diff line number Diff line
@@ -2214,6 +2214,11 @@ struct isp_operations {
	int (*beacon_on) (struct scsi_qla_host *);
	int (*beacon_off) (struct scsi_qla_host *);
	void (*beacon_blink) (struct scsi_qla_host *);

	uint8_t * (*read_optrom) (struct scsi_qla_host *, uint8_t *,
		uint32_t, uint32_t);
	int (*write_optrom) (struct scsi_qla_host *, uint8_t *, uint32_t,
		uint32_t);
};

/*
@@ -2505,6 +2510,14 @@ typedef struct scsi_qla_host {
	uint8_t		*port_name;
	uint32_t    isp_abort_cnt;

	/* Option ROM information. */
	char		*optrom_buffer;
	uint32_t	optrom_size;
	int		optrom_state;
#define QLA_SWAITING	0
#define QLA_SREADING	1
#define QLA_SWRITING	2

	/* Needed for BEACON */
	uint16_t	beacon_blink_led;
	uint8_t		beacon_color_state;
@@ -2582,7 +2595,9 @@ struct _qla2x00stats {
/*
 * Flash support definitions
 */
#define FLASH_IMAGE_SIZE	131072
#define OPTROM_SIZE_2300	0x20000
#define OPTROM_SIZE_2322	0x100000
#define OPTROM_SIZE_24XX	0x100000

#include "qla_gbl.h"
#include "qla_dbg.h"
+11 −0
Original line number Diff line number Diff line
@@ -79,6 +79,8 @@ extern int qla2x00_down_timeout(struct semaphore *, unsigned long);

extern struct fw_blob *qla2x00_request_firmware(scsi_qla_host_t *);

extern int qla2x00_wait_for_hba_online(scsi_qla_host_t *);

/*
 * Global Function Prototypes in qla_iocb.c source file.
 */
@@ -240,6 +242,15 @@ extern int qla24xx_beacon_on(struct scsi_qla_host *);
extern int qla24xx_beacon_off(struct scsi_qla_host *);
extern void qla24xx_beacon_blink(struct scsi_qla_host *);

extern uint8_t *qla2x00_read_optrom_data(struct scsi_qla_host *, uint8_t *,
    uint32_t, uint32_t);
extern int qla2x00_write_optrom_data(struct scsi_qla_host *, uint8_t *,
    uint32_t, uint32_t);
extern uint8_t *qla24xx_read_optrom_data(struct scsi_qla_host *, uint8_t *,
    uint32_t, uint32_t);
extern int qla24xx_write_optrom_data(struct scsi_qla_host *, uint8_t *,
    uint32_t, uint32_t);

/*
 * Global Function Prototypes in qla_dbg.c source file.
 */
+14 −1
Original line number Diff line number Diff line
@@ -513,7 +513,7 @@ qla2x00_eh_wait_on_command(scsi_qla_host_t *ha, struct scsi_cmnd *cmd)
 *    Success (Adapter is online) : 0
 *    Failed  (Adapter is offline/disabled) : 1
 */
static int
int
qla2x00_wait_for_hba_online(scsi_qla_host_t *ha)
{
	int		return_status;
@@ -1271,6 +1271,9 @@ int qla2x00_probe_one(struct pci_dev *pdev, struct qla_board_info *brd_info)
	fc_port_t *fcport;
	struct scsi_host_template *sht;

if (PCI_FUNC(pdev->devfn))
	goto probe_out;

	if (pci_enable_device(pdev))
		goto probe_out;

@@ -1313,6 +1316,7 @@ int qla2x00_probe_one(struct pci_dev *pdev, struct qla_board_info *brd_info)
	ha->init_cb_size = sizeof(init_cb_t);
	ha->mgmt_svr_loop_id = MANAGEMENT_SERVER;
	ha->link_data_rate = LDR_UNKNOWN;
	ha->optrom_size = OPTROM_SIZE_2300;

	/* Assign ISP specific operations. */
	ha->isp_ops.pci_config		= qla2100_pci_config;
@@ -1340,6 +1344,8 @@ int qla2x00_probe_one(struct pci_dev *pdev, struct qla_board_info *brd_info)
	ha->isp_ops.write_nvram		= qla2x00_write_nvram_data;
	ha->isp_ops.fw_dump		= qla2100_fw_dump;
	ha->isp_ops.ascii_fw_dump	= qla2100_ascii_fw_dump;
	ha->isp_ops.read_optrom		= qla2x00_read_optrom_data;
	ha->isp_ops.write_optrom	= qla2x00_write_optrom_data;
	if (IS_QLA2100(ha)) {
		host->max_id = MAX_TARGETS_2100;
		ha->mbx_count = MAILBOX_REGISTER_COUNT_2100;
@@ -1369,6 +1375,8 @@ int qla2x00_probe_one(struct pci_dev *pdev, struct qla_board_info *brd_info)
		ha->isp_ops.beacon_off = qla2x00_beacon_off;
		ha->isp_ops.beacon_blink = qla2x00_beacon_blink;
		ha->gid_list_info_size = 6;
		if (IS_QLA2322(ha) || IS_QLA6322(ha))
			ha->optrom_size = OPTROM_SIZE_2322;
	} else if (IS_QLA24XX(ha) || IS_QLA25XX(ha)) {
		host->max_id = MAX_TARGETS_2200;
		ha->mbx_count = MAILBOX_REGISTER_COUNT;
@@ -1404,10 +1412,13 @@ int qla2x00_probe_one(struct pci_dev *pdev, struct qla_board_info *brd_info)
		ha->isp_ops.write_nvram = qla24xx_write_nvram_data;
		ha->isp_ops.fw_dump = qla24xx_fw_dump;
		ha->isp_ops.ascii_fw_dump = qla24xx_ascii_fw_dump;
		ha->isp_ops.read_optrom	= qla24xx_read_optrom_data;
		ha->isp_ops.write_optrom = qla24xx_write_optrom_data;
		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->gid_list_info_size = 8;
		ha->optrom_size = OPTROM_SIZE_24XX;
	}
	host->can_queue = ha->request_q_length + 128;

@@ -2073,6 +2084,8 @@ qla2x00_mem_free(scsi_qla_host_t *ha)
	ha->fw_dumped = 0;
	ha->fw_dump_reading = 0;
	ha->fw_dump_buffer = NULL;

	vfree(ha->optrom_buffer);
}

/*
+669 −0

File changed.

Preview size limit exceeded, changes collapsed.