isp_netbsd.c revision 1.8 1 1.7 mjacob /* $NetBSD: isp_netbsd.c,v 1.8 1998/12/28 19:10:43 mjacob Exp $ */
2 1.8 mjacob /* release_12_28_98_A */
3 1.1 mjacob /*
4 1.1 mjacob * Platform (NetBSD) dependent common attachment code for Qlogic adapters.
5 1.1 mjacob *
6 1.1 mjacob *---------------------------------------
7 1.1 mjacob * Copyright (c) 1997, 1998 by Matthew Jacob
8 1.1 mjacob * NASA/Ames Research Center
9 1.1 mjacob * All rights reserved.
10 1.1 mjacob *---------------------------------------
11 1.1 mjacob *
12 1.1 mjacob * Redistribution and use in source and binary forms, with or without
13 1.1 mjacob * modification, are permitted provided that the following conditions
14 1.1 mjacob * are met:
15 1.1 mjacob * 1. Redistributions of source code must retain the above copyright
16 1.1 mjacob * notice immediately at the beginning of the file, without modification,
17 1.1 mjacob * this list of conditions, and the following disclaimer.
18 1.1 mjacob * 2. Redistributions in binary form must reproduce the above copyright
19 1.1 mjacob * notice, this list of conditions and the following disclaimer in the
20 1.1 mjacob * documentation and/or other materials provided with the distribution.
21 1.1 mjacob * 3. The name of the author may not be used to endorse or promote products
22 1.1 mjacob * derived from this software without specific prior written permission.
23 1.1 mjacob *
24 1.1 mjacob * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
25 1.1 mjacob * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 1.1 mjacob * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 1.1 mjacob * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
28 1.1 mjacob * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 1.1 mjacob * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 1.1 mjacob * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 1.1 mjacob * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 1.1 mjacob * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 1.1 mjacob * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 1.1 mjacob * SUCH DAMAGE.
35 1.1 mjacob *
36 1.1 mjacob * The author may be reached via electronic communications at
37 1.1 mjacob *
38 1.1 mjacob * mjacob (at) nas.nasa.gov
39 1.1 mjacob * mjacob (at) feral.com
40 1.1 mjacob *
41 1.1 mjacob * or, via United States Postal Address
42 1.1 mjacob *
43 1.1 mjacob * Matthew Jacob
44 1.1 mjacob * Feral Software
45 1.1 mjacob * 2339 3rd Street
46 1.1 mjacob * Suite 24
47 1.1 mjacob * San Francisco, CA, 94107
48 1.1 mjacob */
49 1.1 mjacob
50 1.1 mjacob #include <dev/ic/isp_netbsd.h>
51 1.1 mjacob
52 1.1 mjacob static void ispminphys __P((struct buf *));
53 1.1 mjacob static int32_t ispcmd __P((ISP_SCSI_XFER_T *));
54 1.1 mjacob
55 1.1 mjacob static struct scsipi_device isp_dev = { NULL, NULL, NULL, NULL };
56 1.1 mjacob static int isp_poll __P((struct ispsoftc *, ISP_SCSI_XFER_T *, int));
57 1.8 mjacob static void isp_watch __P ((void *));
58 1.1 mjacob
59 1.1 mjacob /*
60 1.1 mjacob * Complete attachment of hardware, include subdevices.
61 1.1 mjacob */
62 1.1 mjacob void
63 1.1 mjacob isp_attach(isp)
64 1.1 mjacob struct ispsoftc *isp;
65 1.1 mjacob {
66 1.6 thorpej
67 1.6 thorpej isp->isp_osinfo._adapter.scsipi_cmd = ispcmd;
68 1.6 thorpej isp->isp_osinfo._adapter.scsipi_minphys = ispminphys;
69 1.6 thorpej
70 1.1 mjacob isp->isp_state = ISP_RUNSTATE;
71 1.1 mjacob isp->isp_osinfo._link.scsipi_scsi.channel = SCSI_CHANNEL_ONLY_ONE;
72 1.1 mjacob isp->isp_osinfo._link.adapter_softc = isp;
73 1.1 mjacob isp->isp_osinfo._link.device = &isp_dev;
74 1.6 thorpej isp->isp_osinfo._link.adapter = &isp->isp_osinfo._adapter;
75 1.1 mjacob
76 1.1 mjacob if (isp->isp_type & ISP_HA_FC) {
77 1.1 mjacob isp->isp_osinfo._link.scsipi_scsi.max_target = MAX_FC_TARG-1;
78 1.7 mjacob #ifdef SCCLUN
79 1.7 mjacob /*
80 1.7 mjacob * 16 bits worth, but let's be reasonable..
81 1.7 mjacob */
82 1.7 mjacob isp->isp_osinfo._link.scsipi_scsi.max_lun = 255;
83 1.7 mjacob #else
84 1.7 mjacob isp->isp_osinfo._link.scsipi_scsi.max_lun = 15;
85 1.7 mjacob #endif
86 1.1 mjacob isp->isp_osinfo._link.openings =
87 1.1 mjacob RQUEST_QUEUE_LEN / (MAX_FC_TARG-1);
88 1.7 mjacob isp->isp_osinfo._link.scsipi_scsi.adapter_target =
89 1.7 mjacob ((fcparam *)isp->isp_param)->isp_loopid;
90 1.1 mjacob } else {
91 1.1 mjacob isp->isp_osinfo._link.openings =
92 1.1 mjacob RQUEST_QUEUE_LEN / (MAX_TARGETS-1);
93 1.1 mjacob isp->isp_osinfo._link.scsipi_scsi.max_target = MAX_TARGETS-1;
94 1.7 mjacob if (isp->isp_bustype == ISP_BT_SBUS) {
95 1.7 mjacob isp->isp_osinfo._link.scsipi_scsi.max_lun = 7;
96 1.7 mjacob } else {
97 1.7 mjacob /*
98 1.7 mjacob * Too much target breakage at present.
99 1.7 mjacob */
100 1.7 mjacob #if 0
101 1.7 mjacob if (isp->isp_fwrev >= ISP_FW_REV(7,55))
102 1.7 mjacob isp->isp_osinfo._link.scsipi_scsi.max_lun = 31;
103 1.7 mjacob else
104 1.7 mjacob #endif
105 1.7 mjacob isp->isp_osinfo._link.scsipi_scsi.max_lun = 7;
106 1.7 mjacob }
107 1.1 mjacob isp->isp_osinfo._link.scsipi_scsi.adapter_target =
108 1.1 mjacob ((sdparam *)isp->isp_param)->isp_initiator_id;
109 1.1 mjacob }
110 1.1 mjacob if (isp->isp_osinfo._link.openings < 2)
111 1.1 mjacob isp->isp_osinfo._link.openings = 2;
112 1.1 mjacob isp->isp_osinfo._link.type = BUS_SCSI;
113 1.8 mjacob
114 1.8 mjacob /*
115 1.8 mjacob * Start the watchdog.
116 1.8 mjacob */
117 1.8 mjacob isp->isp_dogactive = 1;
118 1.8 mjacob timeout(isp_watch, isp, 30 * hz);
119 1.8 mjacob
120 1.8 mjacob /*
121 1.8 mjacob * And attach children (if any).
122 1.8 mjacob */
123 1.1 mjacob config_found((void *)isp, &isp->isp_osinfo._link, scsiprint);
124 1.1 mjacob }
125 1.1 mjacob
126 1.1 mjacob /*
127 1.1 mjacob * minphys our xfers
128 1.1 mjacob *
129 1.1 mjacob * Unfortunately, the buffer pointer describes the target device- not the
130 1.1 mjacob * adapter device, so we can't use the pointer to find out what kind of
131 1.1 mjacob * adapter we are and adjust accordingly.
132 1.1 mjacob */
133 1.1 mjacob
134 1.1 mjacob static void
135 1.1 mjacob ispminphys(bp)
136 1.1 mjacob struct buf *bp;
137 1.1 mjacob {
138 1.1 mjacob /*
139 1.1 mjacob * XX: Only the 1020 has a 24 bit limit.
140 1.1 mjacob */
141 1.1 mjacob if (bp->b_bcount >= (1 << 24)) {
142 1.1 mjacob bp->b_bcount = (1 << 24);
143 1.1 mjacob }
144 1.1 mjacob minphys(bp);
145 1.1 mjacob }
146 1.1 mjacob
147 1.1 mjacob static int
148 1.1 mjacob ispcmd(xs)
149 1.1 mjacob ISP_SCSI_XFER_T *xs;
150 1.1 mjacob {
151 1.1 mjacob struct ispsoftc *isp;
152 1.3 mjacob int result;
153 1.1 mjacob ISP_LOCKVAL_DECL;
154 1.1 mjacob
155 1.1 mjacob isp = XS_ISP(xs);
156 1.1 mjacob ISP_LOCK(isp);
157 1.3 mjacob /*
158 1.3 mjacob * This is less efficient than I would like in that the
159 1.3 mjacob * majority of cases will have to do some pointer deferences
160 1.3 mjacob * to find out that things don't need to be updated.
161 1.3 mjacob */
162 1.3 mjacob if ((xs->flags & SCSI_AUTOCONF) == 0 && (isp->isp_type & ISP_HA_SCSI)) {
163 1.3 mjacob sdparam *sdp = isp->isp_param;
164 1.3 mjacob if (sdp->isp_devparam[XS_TGT(xs)].dev_flags !=
165 1.3 mjacob sdp->isp_devparam[XS_TGT(xs)].cur_dflags) {
166 1.3 mjacob u_int16_t f = DPARM_WIDE|DPARM_SYNC|DPARM_TQING;
167 1.3 mjacob if (xs->sc_link->quirks & SDEV_NOSYNC)
168 1.3 mjacob f &= ~DPARM_SYNC;
169 1.3 mjacob if (xs->sc_link->quirks & SDEV_NOWIDE)
170 1.3 mjacob f &= ~DPARM_WIDE;
171 1.3 mjacob if (xs->sc_link->quirks & SDEV_NOTAG)
172 1.3 mjacob f &= ~DPARM_TQING;
173 1.3 mjacob sdp->isp_devparam[XS_TGT(xs)].dev_flags &=
174 1.3 mjacob ~(DPARM_WIDE|DPARM_SYNC|DPARM_TQING);
175 1.3 mjacob sdp->isp_devparam[XS_TGT(xs)].dev_flags |= f;
176 1.3 mjacob sdp->isp_devparam[XS_TGT(xs)].dev_update = 1;
177 1.3 mjacob isp->isp_update = 1;
178 1.3 mjacob }
179 1.3 mjacob }
180 1.8 mjacob DISABLE_INTS(isp);
181 1.3 mjacob result = ispscsicmd(xs);
182 1.8 mjacob ENABLE_INTS(isp);
183 1.3 mjacob if (result != CMD_QUEUED || (xs->flags & SCSI_POLL) == 0) {
184 1.1 mjacob ISP_UNLOCK(isp);
185 1.3 mjacob return (result);
186 1.1 mjacob }
187 1.1 mjacob
188 1.1 mjacob /*
189 1.1 mjacob * If we can't use interrupts, poll on completion.
190 1.1 mjacob */
191 1.1 mjacob if (isp_poll(isp, xs, XS_TIME(xs))) {
192 1.1 mjacob /*
193 1.1 mjacob * If no other error occurred but we didn't finish,
194 1.1 mjacob * something bad happened.
195 1.1 mjacob */
196 1.1 mjacob if (XS_IS_CMD_DONE(xs) == 0) {
197 1.1 mjacob isp->isp_nactive--;
198 1.1 mjacob if (isp->isp_nactive < 0)
199 1.1 mjacob isp->isp_nactive = 0;
200 1.1 mjacob if (XS_NOERR(xs)) {
201 1.1 mjacob isp_lostcmd(isp, xs);
202 1.1 mjacob XS_SETERR(xs, HBA_BOTCH);
203 1.1 mjacob }
204 1.1 mjacob }
205 1.1 mjacob }
206 1.1 mjacob ISP_UNLOCK(isp);
207 1.1 mjacob return (CMD_COMPLETE);
208 1.1 mjacob }
209 1.1 mjacob
210 1.1 mjacob static int
211 1.1 mjacob isp_poll(isp, xs, mswait)
212 1.1 mjacob struct ispsoftc *isp;
213 1.1 mjacob ISP_SCSI_XFER_T *xs;
214 1.1 mjacob int mswait;
215 1.1 mjacob {
216 1.1 mjacob
217 1.1 mjacob while (mswait) {
218 1.1 mjacob /* Try the interrupt handling routine */
219 1.1 mjacob (void)isp_intr((void *)isp);
220 1.1 mjacob
221 1.1 mjacob /* See if the xs is now done */
222 1.1 mjacob if (XS_IS_CMD_DONE(xs)) {
223 1.1 mjacob return (0);
224 1.1 mjacob }
225 1.1 mjacob SYS_DELAY(1000); /* wait one millisecond */
226 1.1 mjacob mswait--;
227 1.1 mjacob }
228 1.1 mjacob return (1);
229 1.8 mjacob }
230 1.8 mjacob
231 1.8 mjacob static void
232 1.8 mjacob isp_watch(arg)
233 1.8 mjacob void *arg;
234 1.8 mjacob {
235 1.8 mjacob int i;
236 1.8 mjacob struct ispsoftc *isp = arg;
237 1.8 mjacob ISP_SCSI_XFER_T *xs;
238 1.8 mjacob ISP_ILOCKVAL_DECL;
239 1.8 mjacob
240 1.8 mjacob /*
241 1.8 mjacob * Look for completely dead commands (but not polled ones).
242 1.8 mjacob */
243 1.8 mjacob ISP_ILOCK(isp);
244 1.8 mjacob for (i = 0; i < RQUEST_QUEUE_LEN; i++) {
245 1.8 mjacob if ((xs = (ISP_SCSI_XFER_T *) isp->isp_xflist[i]) == NULL) {
246 1.8 mjacob continue;
247 1.8 mjacob }
248 1.8 mjacob if (XS_TIME(xs) == 0) {
249 1.8 mjacob continue;
250 1.8 mjacob }
251 1.8 mjacob XS_TIME(xs) -= (WATCH_INTERVAL * 1000);
252 1.8 mjacob /*
253 1.8 mjacob * Avoid later thinking that this
254 1.8 mjacob * transaction is not being timed.
255 1.8 mjacob * Then give ourselves to watchdog
256 1.8 mjacob * periods of grace.
257 1.8 mjacob */
258 1.8 mjacob if (XS_TIME(xs) == 0) {
259 1.8 mjacob XS_TIME(xs) = 1;
260 1.8 mjacob } else if (XS_TIME(xs) > -(2 * WATCH_INTERVAL * 1000)) {
261 1.8 mjacob continue;
262 1.8 mjacob }
263 1.8 mjacob if (isp_control(isp, ISPCTL_ABORT_CMD, xs)) {
264 1.8 mjacob printf("%s: isp_watch failed to abort command\n",
265 1.8 mjacob isp->isp_name);
266 1.8 mjacob isp_restart(isp);
267 1.8 mjacob break;
268 1.8 mjacob }
269 1.8 mjacob }
270 1.8 mjacob timeout(isp_watch, isp, WATCH_INTERVAL * hz);
271 1.8 mjacob isp->isp_dogactive = 1;
272 1.8 mjacob ISP_IUNLOCK(isp);
273 1.8 mjacob }
274 1.8 mjacob
275 1.8 mjacob /*
276 1.8 mjacob * Free any associated resources prior to decommissioning and
277 1.8 mjacob * set the card to a known state (so it doesn't wake up and kick
278 1.8 mjacob * us when we aren't expecting it to).
279 1.8 mjacob *
280 1.8 mjacob * Locks are held before coming here.
281 1.8 mjacob */
282 1.8 mjacob void
283 1.8 mjacob isp_uninit(isp)
284 1.8 mjacob struct ispsoftc *isp;
285 1.8 mjacob {
286 1.8 mjacob ISP_ILOCKVAL_DECL;
287 1.8 mjacob ISP_ILOCK(isp);
288 1.8 mjacob /*
289 1.8 mjacob * Leave with interrupts disabled.
290 1.8 mjacob */
291 1.8 mjacob DISABLE_INTS(isp);
292 1.8 mjacob
293 1.8 mjacob /*
294 1.8 mjacob * Turn off the watchdog (if active).
295 1.8 mjacob */
296 1.8 mjacob if (isp->isp_dogactive) {
297 1.8 mjacob untimeout(isp_watch, isp);
298 1.8 mjacob isp->isp_dogactive = 0;
299 1.8 mjacob }
300 1.8 mjacob
301 1.8 mjacob ISP_IUNLOCK(isp);
302 1.1 mjacob }
303