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