ispfw.c revision 129879
1/*-
2 * ISP Firmware Helper Pseudo Device for FreeBSD
3 *
4 * Copyright (c) 2000, 2001, by Matthew Jacob
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice immediately at the beginning of the file, without modification,
12 *    this list of conditions, and the following disclaimer.
13 * 2. The name of the author may not be used to endorse or promote products
14 *    derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
20 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD: head/sys/dev/ispfw/ispfw.c 129879 2004-05-30 20:08:47Z phk $");
31
32#include <sys/param.h>
33#include <sys/kernel.h>
34#include <sys/malloc.h>
35#include <sys/module.h>
36
37#include <dev/ispfw/asm_1040.h>
38#include <dev/ispfw/asm_1080.h>
39#include <dev/ispfw/asm_12160.h>
40#include <dev/ispfw/asm_2100.h>
41#include <dev/ispfw/asm_2200.h>
42#include <dev/ispfw/asm_2300.h>
43#if	_MACHINE_ARCH == sparc64
44#include <dev/ispfw/asm_1000.h>
45#endif
46
47#define	ISPFW_VERSION	0
48
49#define	PCI_PRODUCT_QLOGIC_ISP1020	0x1020
50#define	PCI_PRODUCT_QLOGIC_ISP1080	0x1080
51#define	PCI_PRODUCT_QLOGIC_ISP10160	0x1016
52#define	PCI_PRODUCT_QLOGIC_ISP12160	0x1216
53#define	PCI_PRODUCT_QLOGIC_ISP1240	0x1240
54#define	PCI_PRODUCT_QLOGIC_ISP1280	0x1280
55#define	PCI_PRODUCT_QLOGIC_ISP2100	0x2100
56#define	PCI_PRODUCT_QLOGIC_ISP2200	0x2200
57#define	PCI_PRODUCT_QLOGIC_ISP2300	0x2300
58#define	PCI_PRODUCT_QLOGIC_ISP2312	0x2312
59#if	_MACHINE_ARCH == sparc64
60#define	SBUS_PRODUCT_QLOGIC_ISP1000	0x1000
61#endif
62
63typedef void ispfwfunc(int, int, int, const u_int16_t **);
64extern ispfwfunc *isp_get_firmware_p;
65static void isp_get_firmware(int, int, int, const u_int16_t **);
66
67static int ncallers = 0;
68static const u_int16_t ***callp = NULL;
69static int addcaller(const u_int16_t **);
70
71static int
72addcaller(const u_int16_t **caller)
73{
74	const u_int16_t ***newcallp;
75	int i;
76	for (i = 0; i < ncallers; i++) {
77		if (callp[i] == caller)
78			return (1);
79	}
80	newcallp = malloc((ncallers + 1) * sizeof (const u_int16_t ***),
81	    M_DEVBUF, M_NOWAIT);
82	if (newcallp == NULL) {
83		return (0);
84	}
85	for (i = 0; i < ncallers; i++) {
86		newcallp[i] = callp[i];
87	}
88	newcallp[ncallers] = caller;
89	if (ncallers++)
90		free(callp, M_DEVBUF);
91	callp = newcallp;
92	return (1);
93}
94
95static void
96isp_get_firmware(int version, int tgtmode, int devid, const u_int16_t **ptrp)
97{
98	const u_int16_t *rp = NULL;
99
100	if (version == ISPFW_VERSION) {
101		switch (devid) {
102		case PCI_PRODUCT_QLOGIC_ISP1020:
103			if (tgtmode)
104				rp = isp_1040_risc_code_it;
105			else
106				rp = isp_1040_risc_code;
107			break;
108		case PCI_PRODUCT_QLOGIC_ISP1080:
109		case PCI_PRODUCT_QLOGIC_ISP1240:
110		case PCI_PRODUCT_QLOGIC_ISP1280:
111			if (tgtmode)
112				rp = isp_1080_risc_code_it;
113			else
114				rp = isp_1080_risc_code;
115			break;
116		case PCI_PRODUCT_QLOGIC_ISP10160:
117		case PCI_PRODUCT_QLOGIC_ISP12160:
118			if (tgtmode)
119				rp = isp_12160_risc_code_it;
120			else
121				rp = isp_12160_risc_code;
122			break;
123		case PCI_PRODUCT_QLOGIC_ISP2100:
124			rp = isp_2100_risc_code;
125			break;
126		case PCI_PRODUCT_QLOGIC_ISP2200:
127			rp = isp_2200_risc_code;
128			break;
129		case PCI_PRODUCT_QLOGIC_ISP2300:
130		case PCI_PRODUCT_QLOGIC_ISP2312:
131			rp = isp_2300_risc_code;
132			break;
133#if	_MACHINE_ARCH == sparc64
134		case SBUS_PRODUCT_QLOGIC_ISP1000:
135			if (tgtmode)
136				break;
137			rp = isp_1000_risc_code;
138			break;
139#endif
140		default:
141			break;
142		}
143	}
144	if (rp && addcaller(ptrp)) {
145		*ptrp = rp;
146	}
147}
148
149static int
150isp_module_handler(module_t mod, int what, void *arg)
151{
152	switch (what) {
153	case MOD_LOAD:
154		isp_get_firmware_p = isp_get_firmware;
155		break;
156	case MOD_UNLOAD:
157		isp_get_firmware_p = NULL;
158		if (ncallers)  {
159			int i;
160			for (i = 0; i < ncallers; i++) {
161				*callp[i] = NULL;
162			}
163			free(callp, M_DEVBUF);
164		}
165		break;
166	default:
167		break;
168	}
169	return (0);
170}
171static moduledata_t ispfw_mod = {
172	"ispfw", isp_module_handler, NULL
173};
174DECLARE_MODULE(ispfw, ispfw_mod, SI_SUB_DRIVERS, SI_ORDER_THIRD);
175MODULE_VERSION(ispfw, ISPFW_VERSION);
176MODULE_DEPEND(ispfw, isp, 1, 1, 1);
177