qla_attr.c revision 30c4766213aeb684ee477ac7f36703f9134ac7ad
1d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek/*
2d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek * QLogic Fibre Channel HBA Driver
3d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek * Copyright (c)  2003-2005 QLogic Corporation
4d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek *
5d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek * See LICENSE.qla2xxx for copyright and licensing details.
6d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek */
7d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek#include "qla_def.h"
8d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
9d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek#include <linux/vmalloc.h>
10d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
11d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek/* SYSFS attributes --------------------------------------------------------- */
12d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
13d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekstatic ssize_t
14d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekqla2x00_sysfs_read_fw_dump(struct kobject *kobj, char *buf, loff_t off,
15d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek    size_t count)
16d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek{
17d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
18d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	    struct device, kobj)));
19d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	char *rbuf = (char *)ha->fw_dump;
20d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
21d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	if (ha->fw_dump_reading == 0)
22d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		return 0;
23d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	if (off > ha->fw_dump_len)
24d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek                return 0;
25d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	if (off + count > ha->fw_dump_len)
26d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		count = ha->fw_dump_len - off;
27d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
28d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	memcpy(buf, &rbuf[off], count);
29d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
30d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	return (count);
31d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek}
32d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
33d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekstatic ssize_t
34d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekqla2x00_sysfs_write_fw_dump(struct kobject *kobj, char *buf, loff_t off,
35d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek    size_t count)
36d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek{
37d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
38d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	    struct device, kobj)));
39d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	int reading;
40d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
41d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	if (off != 0)
42d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		return (0);
43d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
44d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	reading = simple_strtol(buf, NULL, 10);
45d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	switch (reading) {
46d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	case 0:
47d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		if (!ha->fw_dump_reading)
48d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek			break;
49d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
50d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		qla_printk(KERN_INFO, ha,
51d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		    "Firmware dump cleared on (%ld).\n", ha->host_no);
52d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
53d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		ha->fw_dump_reading = 0;
54d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		ha->fw_dumped = 0;
55d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		break;
56d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	case 1:
57d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		if (ha->fw_dumped && !ha->fw_dump_reading) {
58d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek			ha->fw_dump_reading = 1;
59d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
60d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek			qla_printk(KERN_INFO, ha,
61d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek			    "Raw firmware dump ready for read on (%ld).\n",
62d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek			    ha->host_no);
63d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		}
64d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		break;
65d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	case 2:
66d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		qla2x00_alloc_fw_dump(ha);
67d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		break;
68d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	}
69d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	return (count);
70d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek}
71d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
72a8d380f30a7d8cc507fd5cc84b2dc5ee2b2144d7Dima Zavinstatic struct bin_attribute sysfs_fw_dump_attr = {
73d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	.attr = {
74d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		.name = "fw_dump",
75d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		.mode = S_IRUSR | S_IWUSR,
76d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		.owner = THIS_MODULE,
77d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	},
78d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	.size = 0,
79d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	.read = qla2x00_sysfs_read_fw_dump,
80d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	.write = qla2x00_sysfs_write_fw_dump,
81d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek};
82d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
83d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekstatic ssize_t
84d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekqla2x00_sysfs_read_nvram(struct kobject *kobj, char *buf, loff_t off,
85d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek    size_t count)
86d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek{
87d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
88d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	    struct device, kobj)));
89d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	unsigned long	flags;
90d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
91d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	if (!capable(CAP_SYS_ADMIN) || off != 0)
92d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		return 0;
93d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
94d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	/* Read NVRAM. */
95d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	spin_lock_irqsave(&ha->hardware_lock, flags);
96d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	ha->isp_ops.read_nvram(ha, (uint8_t *)buf, ha->nvram_base,
97d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	    ha->nvram_size);
98d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	spin_unlock_irqrestore(&ha->hardware_lock, flags);
99d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
100d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	return ha->nvram_size;
101d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek}
102d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
103d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekstatic ssize_t
104d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekqla2x00_sysfs_write_nvram(struct kobject *kobj, char *buf, loff_t off,
105d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek    size_t count)
106d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek{
107d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
108d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	    struct device, kobj)));
109d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	unsigned long	flags;
110d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	uint16_t	cnt;
111d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
112d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	if (!capable(CAP_SYS_ADMIN) || off != 0 || count != ha->nvram_size)
113d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		return 0;
114d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
115d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	/* Checksum NVRAM. */
116d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
117d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		uint32_t *iter;
118d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		uint32_t chksum;
119d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
120d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		iter = (uint32_t *)buf;
121d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		chksum = 0;
122d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		for (cnt = 0; cnt < ((count >> 2) - 1); cnt++)
123d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek			chksum += le32_to_cpu(*iter++);
124d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		chksum = ~chksum + 1;
125d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		*iter = cpu_to_le32(chksum);
126d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	} else {
127d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		uint8_t *iter;
128d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		uint8_t chksum;
129d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
130d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		iter = (uint8_t *)buf;
131d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		chksum = 0;
132d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		for (cnt = 0; cnt < count - 1; cnt++)
133d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek			chksum += *iter++;
134d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		chksum = ~chksum + 1;
135d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		*iter = chksum;
136d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	}
137d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
138d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	/* Write NVRAM. */
139d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	spin_lock_irqsave(&ha->hardware_lock, flags);
140d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	ha->isp_ops.write_nvram(ha, (uint8_t *)buf, ha->nvram_base, count);
141d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	spin_unlock_irqrestore(&ha->hardware_lock, flags);
142d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
143d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	return (count);
144d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek}
145d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
146d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekstatic struct bin_attribute sysfs_nvram_attr = {
147d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	.attr = {
148d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		.name = "nvram",
149d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		.mode = S_IRUSR | S_IWUSR,
150d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		.owner = THIS_MODULE,
151d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	},
152d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	.size = 512,
153d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	.read = qla2x00_sysfs_read_nvram,
154d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	.write = qla2x00_sysfs_write_nvram,
155d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek};
156d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
157d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekstatic ssize_t
158d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekqla2x00_sysfs_read_optrom(struct kobject *kobj, char *buf, loff_t off,
159d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek    size_t count)
160d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek{
161d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
162d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	    struct device, kobj)));
163d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
164d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	if (ha->optrom_state != QLA_SREADING)
165d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		return 0;
166d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	if (off > ha->optrom_size)
167d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		return 0;
168d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	if (off + count > ha->optrom_size)
169d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		count = ha->optrom_size - off;
170d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
171d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	memcpy(buf, &ha->optrom_buffer[off], count);
172d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
173d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	return count;
174d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek}
175d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
176d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekstatic ssize_t
177d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekqla2x00_sysfs_write_optrom(struct kobject *kobj, char *buf, loff_t off,
178d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek    size_t count)
179d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek{
180d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
181d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	    struct device, kobj)));
182d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
183d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	if (ha->optrom_state != QLA_SWRITING)
184d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		return -EINVAL;
185d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	if (off > ha->optrom_size)
186d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		return -ERANGE;
187d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	if (off + count > ha->optrom_size)
188d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		count = ha->optrom_size - off;
189d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
190d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	memcpy(&ha->optrom_buffer[off], buf, count);
191d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
192d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	return count;
193d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek}
194d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
195d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekstatic struct bin_attribute sysfs_optrom_attr = {
196d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	.attr = {
197d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		.name = "optrom",
198d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		.mode = S_IRUSR | S_IWUSR,
199d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		.owner = THIS_MODULE,
200d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	},
201d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	.size = OPTROM_SIZE_24XX,
202d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	.read = qla2x00_sysfs_read_optrom,
203d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	.write = qla2x00_sysfs_write_optrom,
204d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek};
205d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
206d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekstatic ssize_t
207d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekqla2x00_sysfs_write_optrom_ctl(struct kobject *kobj, char *buf, loff_t off,
208d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek    size_t count)
209d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek{
210d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
211d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	    struct device, kobj)));
212d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	int val;
213d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
214d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	if (off)
215d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		return 0;
216d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
217d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	if (sscanf(buf, "%d", &val) != 1)
218d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		return -EINVAL;
219d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
220d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	switch (val) {
221d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	case 0:
222d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		if (ha->optrom_state != QLA_SREADING &&
223d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		    ha->optrom_state != QLA_SWRITING)
224d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek			break;
225d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
226d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		ha->optrom_state = QLA_SWAITING;
227d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		vfree(ha->optrom_buffer);
228d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		ha->optrom_buffer = NULL;
229d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		break;
230d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	case 1:
231d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		if (ha->optrom_state != QLA_SWAITING)
232d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek			break;
233d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
234d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		ha->optrom_state = QLA_SREADING;
235d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		ha->optrom_buffer = (uint8_t *)vmalloc(ha->optrom_size);
236d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		if (ha->optrom_buffer == NULL) {
237d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek			qla_printk(KERN_WARNING, ha,
238d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek			    "Unable to allocate memory for optrom retrieval "
239d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek			    "(%x).\n", ha->optrom_size);
240d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
241d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek			ha->optrom_state = QLA_SWAITING;
242d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek			return count;
243d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		}
244d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
245d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		memset(ha->optrom_buffer, 0, ha->optrom_size);
246d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		ha->isp_ops.read_optrom(ha, ha->optrom_buffer, 0,
247d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		    ha->optrom_size);
248d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		break;
249d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	case 2:
250d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		if (ha->optrom_state != QLA_SWAITING)
251d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek			break;
252d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
253d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		ha->optrom_state = QLA_SWRITING;
254d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		ha->optrom_buffer = (uint8_t *)vmalloc(ha->optrom_size);
255d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		if (ha->optrom_buffer == NULL) {
256d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek			qla_printk(KERN_WARNING, ha,
257d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek			    "Unable to allocate memory for optrom update "
258d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek			    "(%x).\n", ha->optrom_size);
259d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
260d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek			ha->optrom_state = QLA_SWAITING;
261d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek			return count;
262d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		}
263d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		memset(ha->optrom_buffer, 0, ha->optrom_size);
264d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		break;
265d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	case 3:
266d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		if (ha->optrom_state != QLA_SWRITING)
267d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek			break;
268d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
269d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		ha->isp_ops.write_optrom(ha, ha->optrom_buffer, 0,
270d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		    ha->optrom_size);
271d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		break;
272d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	}
273d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	return count;
274d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek}
275d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
276d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekstatic struct bin_attribute sysfs_optrom_ctl_attr = {
277d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	.attr = {
278d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		.name = "optrom_ctl",
279d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		.mode = S_IWUSR,
280d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		.owner = THIS_MODULE,
281d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	},
282d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	.size = 0,
283d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	.write = qla2x00_sysfs_write_optrom_ctl,
284d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek};
285d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
286d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekstatic ssize_t
287d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekqla2x00_sysfs_read_vpd(struct kobject *kobj, char *buf, loff_t off,
288d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek    size_t count)
289d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek{
290d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
291d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	    struct device, kobj)));
292d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	unsigned long flags;
293d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
294d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	if (!capable(CAP_SYS_ADMIN) || off != 0)
295d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		return 0;
296d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
297d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	/* Read NVRAM. */
298d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	spin_lock_irqsave(&ha->hardware_lock, flags);
299d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	ha->isp_ops.read_nvram(ha, (uint8_t *)buf, ha->vpd_base, ha->vpd_size);
300d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	spin_unlock_irqrestore(&ha->hardware_lock, flags);
301d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
302d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	return ha->vpd_size;
303d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek}
304d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
305d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekstatic ssize_t
306d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekqla2x00_sysfs_write_vpd(struct kobject *kobj, char *buf, loff_t off,
307d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek    size_t count)
308d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek{
309d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
310d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	    struct device, kobj)));
311d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	unsigned long flags;
312d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
313d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	if (!capable(CAP_SYS_ADMIN) || off != 0 || count != ha->vpd_size)
314d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		return 0;
315d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
316d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	/* Write NVRAM. */
317d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	spin_lock_irqsave(&ha->hardware_lock, flags);
318d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	ha->isp_ops.write_nvram(ha, (uint8_t *)buf, ha->vpd_base, count);
319d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	spin_unlock_irqrestore(&ha->hardware_lock, flags);
320d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
321d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	return count;
322d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek}
323d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
324d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekstatic struct bin_attribute sysfs_vpd_attr = {
325d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	.attr = {
326d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		.name = "vpd",
327d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		.mode = S_IRUSR | S_IWUSR,
328d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		.owner = THIS_MODULE,
329d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	},
330d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	.size = 0,
331d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	.read = qla2x00_sysfs_read_vpd,
332d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	.write = qla2x00_sysfs_write_vpd,
333d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek};
334d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
335d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekstatic ssize_t
336d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekqla2x00_sysfs_read_sfp(struct kobject *kobj, char *buf, loff_t off,
337d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek    size_t count)
338d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek{
339d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
340d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	    struct device, kobj)));
341d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	uint16_t iter, addr, offset;
342d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	int rval;
343d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
344d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	if (!capable(CAP_SYS_ADMIN) || off != 0 || count != SFP_DEV_SIZE * 2)
345d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		return 0;
346d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
347d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	addr = 0xa0;
348d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	for (iter = 0, offset = 0; iter < (SFP_DEV_SIZE * 2) / SFP_BLOCK_SIZE;
349d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	    iter++, offset += SFP_BLOCK_SIZE) {
350d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		if (iter == 4) {
351d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek			/* Skip to next device address. */
352d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek			addr = 0xa2;
353d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek			offset = 0;
354d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		}
355d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
356d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		rval = qla2x00_read_sfp(ha, ha->sfp_data_dma, addr, offset,
357d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		    SFP_BLOCK_SIZE);
358d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		if (rval != QLA_SUCCESS) {
359d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek			qla_printk(KERN_WARNING, ha,
360d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek			    "Unable to read SFP data (%x/%x/%x).\n", rval,
361d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek			    addr, offset);
362d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek			count = 0;
363d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek			break;
364d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		}
365d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		memcpy(buf, ha->sfp_data, SFP_BLOCK_SIZE);
366d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		buf += SFP_BLOCK_SIZE;
367d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	}
368d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
369d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	return count;
370d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek}
371d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
372d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekstatic struct bin_attribute sysfs_sfp_attr = {
373d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	.attr = {
374d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		.name = "sfp",
375d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		.mode = S_IRUSR | S_IWUSR,
376d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		.owner = THIS_MODULE,
377d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	},
378d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	.size = SFP_DEV_SIZE * 2,
379d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	.read = qla2x00_sysfs_read_sfp,
380d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek};
381d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
382d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekstatic struct sysfs_entry {
383d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	char *name;
384d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	struct bin_attribute *attr;
385d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	int is4GBp_only;
386d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek} bin_file_entries[] = {
387d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	{ "fw_dump", &sysfs_fw_dump_attr, },
388d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	{ "nvram", &sysfs_nvram_attr, },
389d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	{ "optrom", &sysfs_optrom_attr, },
390d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	{ "optrom_ctl", &sysfs_optrom_ctl_attr, },
391d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	{ "vpd", &sysfs_vpd_attr, 1 },
392d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	{ "sfp", &sysfs_sfp_attr, 1 },
393d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	{ NULL },
394d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek};
395d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
396d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekvoid
397d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekqla2x00_alloc_sysfs_attr(scsi_qla_host_t *ha)
398d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek{
399d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	struct Scsi_Host *host = ha->host;
400d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	struct sysfs_entry *iter;
401d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	int ret;
402d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
403d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	for (iter = bin_file_entries; iter->name; iter++) {
404d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		if (iter->is4GBp_only && (!IS_QLA24XX(ha) && !IS_QLA54XX(ha)))
405d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek			continue;
406d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
407d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		ret = sysfs_create_bin_file(&host->shost_gendev.kobj,
408d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		    iter->attr);
409d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		if (ret)
410d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek			qla_printk(KERN_INFO, ha,
411d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek			    "Unable to create sysfs %s binary attribute "
412d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek			    "(%d).\n", iter->name, ret);
413d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	}
414d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek}
415d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
416d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekvoid
417d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekqla2x00_free_sysfs_attr(scsi_qla_host_t *ha)
418d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek{
419d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	struct Scsi_Host *host = ha->host;
420d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	struct sysfs_entry *iter;
421d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
422d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	for (iter = bin_file_entries; iter->name; iter++) {
423d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		if (iter->is4GBp_only && (!IS_QLA24XX(ha) && !IS_QLA54XX(ha)))
424d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek			continue;
425d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
426d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		sysfs_remove_bin_file(&host->shost_gendev.kobj,
427d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		    iter->attr);
428d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	}
429d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
430d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	if (ha->beacon_blink_led == 1)
431d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		ha->isp_ops.beacon_off(ha);
432d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek}
433d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
434d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek/* Scsi_Host attributes. */
435d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
436d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekstatic ssize_t
437d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekqla2x00_drvr_version_show(struct class_device *cdev, char *buf)
438d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek{
439d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	return snprintf(buf, PAGE_SIZE, "%s\n", qla2x00_version_str);
440d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek}
441d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
442d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekstatic ssize_t
443d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekqla2x00_fw_version_show(struct class_device *cdev, char *buf)
444d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek{
445d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
446d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	char fw_str[30];
447d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
448d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	return snprintf(buf, PAGE_SIZE, "%s\n",
449d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	    ha->isp_ops.fw_version_str(ha, fw_str));
450d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek}
451d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
452d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekstatic ssize_t
453d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekqla2x00_serial_num_show(struct class_device *cdev, char *buf)
454d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek{
455d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
456d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	uint32_t sn;
457d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
458d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	sn = ((ha->serial0 & 0x1f) << 16) | (ha->serial2 << 8) | ha->serial1;
459d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	return snprintf(buf, PAGE_SIZE, "%c%05d\n", 'A' + sn / 100000,
460d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	    sn % 100000);
461d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek}
462d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
463d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekstatic ssize_t
464d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekqla2x00_isp_name_show(struct class_device *cdev, char *buf)
465d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek{
466d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
467d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	return snprintf(buf, PAGE_SIZE, "ISP%04X\n", ha->pdev->device);
468d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek}
469d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
470d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekstatic ssize_t
471d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekqla2x00_isp_id_show(struct class_device *cdev, char *buf)
472d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek{
473d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
474d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	return snprintf(buf, PAGE_SIZE, "%04x %04x %04x %04x\n",
475d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	    ha->product_id[0], ha->product_id[1], ha->product_id[2],
476d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	    ha->product_id[3]);
477d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek}
478d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
479d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekstatic ssize_t
480d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekqla2x00_model_name_show(struct class_device *cdev, char *buf)
481d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek{
482d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
483d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	return snprintf(buf, PAGE_SIZE, "%s\n", ha->model_number);
484d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek}
485d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
486d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekstatic ssize_t
487d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekqla2x00_model_desc_show(struct class_device *cdev, char *buf)
488d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek{
489d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
490d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	return snprintf(buf, PAGE_SIZE, "%s\n",
491d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	    ha->model_desc ? ha->model_desc: "");
492d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek}
493d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
494d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekstatic ssize_t
495d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekqla2x00_pci_info_show(struct class_device *cdev, char *buf)
496d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek{
497d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
498d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	char pci_info[30];
499d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
500d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	return snprintf(buf, PAGE_SIZE, "%s\n",
501d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	    ha->isp_ops.pci_info_str(ha, pci_info));
502d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek}
503d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
504d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekstatic ssize_t
505d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekqla2x00_state_show(struct class_device *cdev, char *buf)
506d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek{
507d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
508d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	int len = 0;
509d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
510d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	if (atomic_read(&ha->loop_state) == LOOP_DOWN ||
511d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	    atomic_read(&ha->loop_state) == LOOP_DEAD)
512d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		len = snprintf(buf, PAGE_SIZE, "Link Down\n");
513d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	else if (atomic_read(&ha->loop_state) != LOOP_READY ||
514d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	    test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags) ||
515d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	    test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags))
516d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		len = snprintf(buf, PAGE_SIZE, "Unknown Link State\n");
517d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	else {
518d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		len = snprintf(buf, PAGE_SIZE, "Link Up - ");
519d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
520d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		switch (ha->current_topology) {
521d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		case ISP_CFG_NL:
522d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek			len += snprintf(buf + len, PAGE_SIZE-len, "Loop\n");
523d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek			break;
524d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		case ISP_CFG_FL:
525d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek			len += snprintf(buf + len, PAGE_SIZE-len, "FL_Port\n");
526d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek			break;
527d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		case ISP_CFG_N:
528d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek			len += snprintf(buf + len, PAGE_SIZE-len,
529d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek			    "N_Port to N_Port\n");
530d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek			break;
531d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		case ISP_CFG_F:
532d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek			len += snprintf(buf + len, PAGE_SIZE-len, "F_Port\n");
533d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek			break;
534d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		default:
535d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek			len += snprintf(buf + len, PAGE_SIZE-len, "Loop\n");
536d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek			break;
537d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		}
538d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	}
539d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	return len;
540d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek}
541d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
542d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekstatic ssize_t
543d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekqla2x00_zio_show(struct class_device *cdev, char *buf)
544d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek{
545d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
546d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	int len = 0;
547d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
548d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	switch (ha->zio_mode) {
549d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	case QLA_ZIO_MODE_6:
550d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		len += snprintf(buf + len, PAGE_SIZE-len, "Mode 6\n");
551d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		break;
552d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	case QLA_ZIO_DISABLED:
553d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		len += snprintf(buf + len, PAGE_SIZE-len, "Disabled\n");
554d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		break;
555d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	}
556d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	return len;
557d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek}
558d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
559d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekstatic ssize_t
560d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekqla2x00_zio_store(struct class_device *cdev, const char *buf, size_t count)
561d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek{
562d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
563d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	int val = 0;
564d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	uint16_t zio_mode;
565d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
566d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	if (!IS_ZIO_SUPPORTED(ha))
567d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		return -ENOTSUPP;
568d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
569d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	if (sscanf(buf, "%d", &val) != 1)
570d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		return -EINVAL;
571d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
572d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	if (val)
573d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		zio_mode = QLA_ZIO_MODE_6;
574d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	else
575d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		zio_mode = QLA_ZIO_DISABLED;
576d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
577d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	/* Update per-hba values and queue a reset. */
578d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	if (zio_mode != QLA_ZIO_DISABLED || ha->zio_mode != QLA_ZIO_DISABLED) {
579d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		ha->zio_mode = zio_mode;
580d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
581d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	}
582d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	return strlen(buf);
583d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek}
584d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
585d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekstatic ssize_t
586d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekqla2x00_zio_timer_show(struct class_device *cdev, char *buf)
587d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek{
588d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
589d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
590d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	return snprintf(buf, PAGE_SIZE, "%d us\n", ha->zio_timer * 100);
591d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek}
592d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
593d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekstatic ssize_t
594d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekqla2x00_zio_timer_store(struct class_device *cdev, const char *buf,
595d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek    size_t count)
596d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek{
597d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
598d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	int val = 0;
599d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	uint16_t zio_timer;
600d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
601d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	if (sscanf(buf, "%d", &val) != 1)
602d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		return -EINVAL;
603d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	if (val > 25500 || val < 100)
604d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		return -ERANGE;
605d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
606d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	zio_timer = (uint16_t)(val / 100);
607d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	ha->zio_timer = zio_timer;
608d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
609d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	return strlen(buf);
610d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek}
611d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
612d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekstatic ssize_t
613d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekqla2x00_beacon_show(struct class_device *cdev, char *buf)
614d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek{
615d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
616d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	int len = 0;
617d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
618d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	if (ha->beacon_blink_led)
619d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		len += snprintf(buf + len, PAGE_SIZE-len, "Enabled\n");
620d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	else
621d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		len += snprintf(buf + len, PAGE_SIZE-len, "Disabled\n");
622d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	return len;
623d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek}
624d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
625d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekstatic ssize_t
626d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekqla2x00_beacon_store(struct class_device *cdev, const char *buf,
627d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek    size_t count)
628d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek{
629d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
630d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	int val = 0;
631d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	int rval;
632d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
633d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	if (IS_QLA2100(ha) || IS_QLA2200(ha))
634d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		return -EPERM;
635d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
636d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	if (test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags)) {
637d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		qla_printk(KERN_WARNING, ha,
638d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		    "Abort ISP active -- ignoring beacon request.\n");
639d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		return -EBUSY;
640d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	}
641d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
642d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	if (sscanf(buf, "%d", &val) != 1)
643d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		return -EINVAL;
644d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
645d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	if (val)
646d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		rval = ha->isp_ops.beacon_on(ha);
647d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	else
648d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		rval = ha->isp_ops.beacon_off(ha);
649d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
650d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	if (rval != QLA_SUCCESS)
651d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek		count = 0;
652d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
653d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	return count;
654d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek}
655d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
656d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekstatic ssize_t
657d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekqla2x00_optrom_bios_version_show(struct class_device *cdev, char *buf)
658d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek{
659d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
660d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
661d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	return snprintf(buf, PAGE_SIZE, "%d.%02d\n", ha->bios_revision[1],
662d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	    ha->bios_revision[0]);
663d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek}
664d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
665d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekstatic ssize_t
666d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekqla2x00_optrom_efi_version_show(struct class_device *cdev, char *buf)
667d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek{
668d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
669d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
670d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	return snprintf(buf, PAGE_SIZE, "%d.%02d\n", ha->efi_revision[1],
671d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	    ha->efi_revision[0]);
672d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek}
673d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
674d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekstatic ssize_t
675d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekqla2x00_optrom_fcode_version_show(struct class_device *cdev, char *buf)
676d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek{
677d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
678d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
679d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	return snprintf(buf, PAGE_SIZE, "%d.%02d\n", ha->fcode_revision[1],
680d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	    ha->fcode_revision[0]);
681d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek}
682d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
683d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekstatic ssize_t
684d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekqla2x00_optrom_fw_version_show(struct class_device *cdev, char *buf)
685d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek{
686d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
687d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
688d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	return snprintf(buf, PAGE_SIZE, "%d.%02d.%02d %d\n",
689d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	    ha->fw_revision[0], ha->fw_revision[1], ha->fw_revision[2],
690d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	    ha->fw_revision[3]);
691d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek}
692d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
693d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekstatic CLASS_DEVICE_ATTR(driver_version, S_IRUGO, qla2x00_drvr_version_show,
694d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	NULL);
695d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekstatic CLASS_DEVICE_ATTR(fw_version, S_IRUGO, qla2x00_fw_version_show, NULL);
696d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekstatic CLASS_DEVICE_ATTR(serial_num, S_IRUGO, qla2x00_serial_num_show, NULL);
697d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekstatic CLASS_DEVICE_ATTR(isp_name, S_IRUGO, qla2x00_isp_name_show, NULL);
698d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekstatic CLASS_DEVICE_ATTR(isp_id, S_IRUGO, qla2x00_isp_id_show, NULL);
699d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekstatic CLASS_DEVICE_ATTR(model_name, S_IRUGO, qla2x00_model_name_show, NULL);
700d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekstatic CLASS_DEVICE_ATTR(model_desc, S_IRUGO, qla2x00_model_desc_show, NULL);
701d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekstatic CLASS_DEVICE_ATTR(pci_info, S_IRUGO, qla2x00_pci_info_show, NULL);
702d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekstatic CLASS_DEVICE_ATTR(state, S_IRUGO, qla2x00_state_show, NULL);
703d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekstatic CLASS_DEVICE_ATTR(zio, S_IRUGO | S_IWUSR, qla2x00_zio_show,
704d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek    qla2x00_zio_store);
705d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekstatic CLASS_DEVICE_ATTR(zio_timer, S_IRUGO | S_IWUSR, qla2x00_zio_timer_show,
706d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek    qla2x00_zio_timer_store);
707d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekstatic CLASS_DEVICE_ATTR(beacon, S_IRUGO | S_IWUSR, qla2x00_beacon_show,
708d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek    qla2x00_beacon_store);
709d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekstatic CLASS_DEVICE_ATTR(optrom_bios_version, S_IRUGO,
710d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek    qla2x00_optrom_bios_version_show, NULL);
711d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekstatic CLASS_DEVICE_ATTR(optrom_efi_version, S_IRUGO,
712d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek    qla2x00_optrom_efi_version_show, NULL);
713d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekstatic CLASS_DEVICE_ATTR(optrom_fcode_version, S_IRUGO,
714d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek    qla2x00_optrom_fcode_version_show, NULL);
715d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekstatic CLASS_DEVICE_ATTR(optrom_fw_version, S_IRUGO,
716d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek    qla2x00_optrom_fw_version_show, NULL);
717d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek
718d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machekstruct class_device_attribute *qla2x00_host_attrs[] = {
719d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	&class_device_attr_driver_version,
720d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	&class_device_attr_fw_version,
721d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	&class_device_attr_serial_num,
722d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	&class_device_attr_isp_name,
723d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	&class_device_attr_isp_id,
724d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	&class_device_attr_model_name,
725d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	&class_device_attr_model_desc,
726d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	&class_device_attr_pci_info,
727d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	&class_device_attr_state,
728d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	&class_device_attr_zio,
729d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	&class_device_attr_zio_timer,
730d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	&class_device_attr_beacon,
731d480ace08d5b59133575e672a0bd1c97b0f8400fPavel Machek	&class_device_attr_optrom_bios_version,
732	&class_device_attr_optrom_efi_version,
733	&class_device_attr_optrom_fcode_version,
734	&class_device_attr_optrom_fw_version,
735	NULL,
736};
737
738/* Host attributes. */
739
740static void
741qla2x00_get_host_port_id(struct Scsi_Host *shost)
742{
743	scsi_qla_host_t *ha = to_qla_host(shost);
744
745	fc_host_port_id(shost) = ha->d_id.b.domain << 16 |
746	    ha->d_id.b.area << 8 | ha->d_id.b.al_pa;
747}
748
749static void
750qla2x00_get_host_speed(struct Scsi_Host *shost)
751{
752	scsi_qla_host_t *ha = to_qla_host(shost);
753	uint32_t speed = 0;
754
755	switch (ha->link_data_rate) {
756	case PORT_SPEED_1GB:
757		speed = 1;
758		break;
759	case PORT_SPEED_2GB:
760		speed = 2;
761		break;
762	case PORT_SPEED_4GB:
763		speed = 4;
764		break;
765	}
766	fc_host_speed(shost) = speed;
767}
768
769static void
770qla2x00_get_host_port_type(struct Scsi_Host *shost)
771{
772	scsi_qla_host_t *ha = to_qla_host(shost);
773	uint32_t port_type = FC_PORTTYPE_UNKNOWN;
774
775	switch (ha->current_topology) {
776	case ISP_CFG_NL:
777		port_type = FC_PORTTYPE_LPORT;
778		break;
779	case ISP_CFG_FL:
780		port_type = FC_PORTTYPE_NLPORT;
781		break;
782	case ISP_CFG_N:
783		port_type = FC_PORTTYPE_PTP;
784		break;
785	case ISP_CFG_F:
786		port_type = FC_PORTTYPE_NPORT;
787		break;
788	}
789	fc_host_port_type(shost) = port_type;
790}
791
792static void
793qla2x00_get_starget_node_name(struct scsi_target *starget)
794{
795	struct Scsi_Host *host = dev_to_shost(starget->dev.parent);
796	scsi_qla_host_t *ha = to_qla_host(host);
797	fc_port_t *fcport;
798	u64 node_name = 0;
799
800	list_for_each_entry(fcport, &ha->fcports, list) {
801		if (starget->id == fcport->os_target_id) {
802			node_name = wwn_to_u64(fcport->node_name);
803			break;
804		}
805	}
806
807	fc_starget_node_name(starget) = node_name;
808}
809
810static void
811qla2x00_get_starget_port_name(struct scsi_target *starget)
812{
813	struct Scsi_Host *host = dev_to_shost(starget->dev.parent);
814	scsi_qla_host_t *ha = to_qla_host(host);
815	fc_port_t *fcport;
816	u64 port_name = 0;
817
818	list_for_each_entry(fcport, &ha->fcports, list) {
819		if (starget->id == fcport->os_target_id) {
820			port_name = wwn_to_u64(fcport->port_name);
821			break;
822		}
823	}
824
825	fc_starget_port_name(starget) = port_name;
826}
827
828static void
829qla2x00_get_starget_port_id(struct scsi_target *starget)
830{
831	struct Scsi_Host *host = dev_to_shost(starget->dev.parent);
832	scsi_qla_host_t *ha = to_qla_host(host);
833	fc_port_t *fcport;
834	uint32_t port_id = ~0U;
835
836	list_for_each_entry(fcport, &ha->fcports, list) {
837		if (starget->id == fcport->os_target_id) {
838			port_id = fcport->d_id.b.domain << 16 |
839			    fcport->d_id.b.area << 8 | fcport->d_id.b.al_pa;
840			break;
841		}
842	}
843
844	fc_starget_port_id(starget) = port_id;
845}
846
847static void
848qla2x00_get_rport_loss_tmo(struct fc_rport *rport)
849{
850	struct Scsi_Host *host = rport_to_shost(rport);
851	scsi_qla_host_t *ha = to_qla_host(host);
852
853	rport->dev_loss_tmo = ha->port_down_retry_count + 5;
854}
855
856static void
857qla2x00_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
858{
859	struct Scsi_Host *host = rport_to_shost(rport);
860	scsi_qla_host_t *ha = to_qla_host(host);
861
862	if (timeout)
863		ha->port_down_retry_count = timeout;
864	else
865		ha->port_down_retry_count = 1;
866
867	rport->dev_loss_tmo = ha->port_down_retry_count + 5;
868}
869
870static int
871qla2x00_issue_lip(struct Scsi_Host *shost)
872{
873	scsi_qla_host_t *ha = to_qla_host(shost);
874
875	set_bit(LOOP_RESET_NEEDED, &ha->dpc_flags);
876	return 0;
877}
878
879static struct fc_host_statistics *
880qla2x00_get_fc_host_stats(struct Scsi_Host *shost)
881{
882	scsi_qla_host_t *ha = to_qla_host(shost);
883	int rval;
884	uint16_t mb_stat[1];
885	link_stat_t stat_buf;
886	struct fc_host_statistics *pfc_host_stat;
887
888	pfc_host_stat = &ha->fc_host_stat;
889	memset(pfc_host_stat, -1, sizeof(struct fc_host_statistics));
890
891	if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
892		rval = qla24xx_get_isp_stats(ha, (uint32_t *)&stat_buf,
893		    sizeof(stat_buf) / 4, mb_stat);
894	} else {
895		rval = qla2x00_get_link_status(ha, ha->loop_id, &stat_buf,
896		    mb_stat);
897	}
898	if (rval != 0) {
899		qla_printk(KERN_WARNING, ha,
900		    "Unable to retrieve host statistics (%d).\n", mb_stat[0]);
901		return pfc_host_stat;
902	}
903
904	pfc_host_stat->link_failure_count = stat_buf.link_fail_cnt;
905	pfc_host_stat->loss_of_sync_count = stat_buf.loss_sync_cnt;
906	pfc_host_stat->loss_of_signal_count = stat_buf.loss_sig_cnt;
907	pfc_host_stat->prim_seq_protocol_err_count = stat_buf.prim_seq_err_cnt;
908	pfc_host_stat->invalid_tx_word_count = stat_buf.inval_xmit_word_cnt;
909	pfc_host_stat->invalid_crc_count = stat_buf.inval_crc_cnt;
910
911	return pfc_host_stat;
912}
913
914static void
915qla2x00_get_host_symbolic_name(struct Scsi_Host *shost)
916{
917	scsi_qla_host_t *ha = to_qla_host(shost);
918
919	qla2x00_get_sym_node_name(ha, fc_host_symbolic_name(shost));
920}
921
922static void
923qla2x00_set_host_system_hostname(struct Scsi_Host *shost)
924{
925	scsi_qla_host_t *ha = to_qla_host(shost);
926
927	set_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags);
928}
929
930static void
931qla2x00_get_host_fabric_name(struct Scsi_Host *shost)
932{
933	scsi_qla_host_t *ha = to_qla_host(shost);
934	u64 node_name;
935
936	if (ha->device_flags & SWITCH_FOUND)
937		node_name = wwn_to_u64(ha->fabric_node_name);
938	else
939		node_name = wwn_to_u64(ha->node_name);
940
941	fc_host_fabric_name(shost) = node_name;
942}
943
944static void
945qla2x00_get_host_port_state(struct Scsi_Host *shost)
946{
947	scsi_qla_host_t *ha = to_qla_host(shost);
948
949	if (!ha->flags.online)
950		fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE;
951	else if (atomic_read(&ha->loop_state) == LOOP_TIMEOUT)
952		fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN;
953	else
954		fc_host_port_state(shost) = FC_PORTSTATE_ONLINE;
955}
956
957struct fc_function_template qla2xxx_transport_functions = {
958
959	.show_host_node_name = 1,
960	.show_host_port_name = 1,
961	.show_host_supported_classes = 1,
962
963	.get_host_port_id = qla2x00_get_host_port_id,
964	.show_host_port_id = 1,
965	.get_host_speed = qla2x00_get_host_speed,
966	.show_host_speed = 1,
967	.get_host_port_type = qla2x00_get_host_port_type,
968	.show_host_port_type = 1,
969	.get_host_symbolic_name = qla2x00_get_host_symbolic_name,
970	.show_host_symbolic_name = 1,
971	.set_host_system_hostname = qla2x00_set_host_system_hostname,
972	.show_host_system_hostname = 1,
973	.get_host_fabric_name = qla2x00_get_host_fabric_name,
974	.show_host_fabric_name = 1,
975	.get_host_port_state = qla2x00_get_host_port_state,
976	.show_host_port_state = 1,
977
978	.dd_fcrport_size = sizeof(struct fc_port *),
979	.show_rport_supported_classes = 1,
980
981	.get_starget_node_name = qla2x00_get_starget_node_name,
982	.show_starget_node_name = 1,
983	.get_starget_port_name = qla2x00_get_starget_port_name,
984	.show_starget_port_name = 1,
985	.get_starget_port_id  = qla2x00_get_starget_port_id,
986	.show_starget_port_id = 1,
987
988	.get_rport_dev_loss_tmo = qla2x00_get_rport_loss_tmo,
989	.set_rport_dev_loss_tmo = qla2x00_set_rport_loss_tmo,
990	.show_rport_dev_loss_tmo = 1,
991
992	.issue_fc_host_lip = qla2x00_issue_lip,
993	.get_fc_host_stats = qla2x00_get_fc_host_stats,
994};
995
996void
997qla2x00_init_host_attr(scsi_qla_host_t *ha)
998{
999	fc_host_node_name(ha->host) = wwn_to_u64(ha->node_name);
1000	fc_host_port_name(ha->host) = wwn_to_u64(ha->port_name);
1001	fc_host_supported_classes(ha->host) = FC_COS_CLASS3;
1002}
1003