isp_netbsd.c revision 1.10 1 1.10 mjacob /* $NetBSD: isp_netbsd.c,v 1.10 1999/02/09 00:42:22 mjacob Exp $ */
2 1.10 mjacob /* release_02_05_99 */
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.10 mjacob static void isp_watch __P((void *));
58 1.10 mjacob static void isp_internal_restart __P((void *));
59 1.10 mjacob
60 1.10 mjacob #define FC_OPENINGS RQUEST_QUEUE_LEN / (MAX_FC_TARG-1)
61 1.10 mjacob #define PI_OPENINGS RQUEST_QUEUE_LEN / (MAX_TARGETS-1)
62 1.1 mjacob
63 1.1 mjacob /*
64 1.1 mjacob * Complete attachment of hardware, include subdevices.
65 1.1 mjacob */
66 1.1 mjacob void
67 1.1 mjacob isp_attach(isp)
68 1.1 mjacob struct ispsoftc *isp;
69 1.1 mjacob {
70 1.6 thorpej
71 1.6 thorpej isp->isp_osinfo._adapter.scsipi_cmd = ispcmd;
72 1.6 thorpej isp->isp_osinfo._adapter.scsipi_minphys = ispminphys;
73 1.6 thorpej
74 1.1 mjacob isp->isp_state = ISP_RUNSTATE;
75 1.1 mjacob isp->isp_osinfo._link.scsipi_scsi.channel = SCSI_CHANNEL_ONLY_ONE;
76 1.1 mjacob isp->isp_osinfo._link.adapter_softc = isp;
77 1.1 mjacob isp->isp_osinfo._link.device = &isp_dev;
78 1.6 thorpej isp->isp_osinfo._link.adapter = &isp->isp_osinfo._adapter;
79 1.10 mjacob TAILQ_INIT(&isp->isp_osinfo.waitq);
80 1.1 mjacob
81 1.1 mjacob if (isp->isp_type & ISP_HA_FC) {
82 1.1 mjacob isp->isp_osinfo._link.scsipi_scsi.max_target = MAX_FC_TARG-1;
83 1.7 mjacob #ifdef SCCLUN
84 1.7 mjacob /*
85 1.7 mjacob * 16 bits worth, but let's be reasonable..
86 1.7 mjacob */
87 1.7 mjacob isp->isp_osinfo._link.scsipi_scsi.max_lun = 255;
88 1.7 mjacob #else
89 1.7 mjacob isp->isp_osinfo._link.scsipi_scsi.max_lun = 15;
90 1.7 mjacob #endif
91 1.10 mjacob isp->isp_osinfo._link.openings = FC_OPENINGS;
92 1.7 mjacob isp->isp_osinfo._link.scsipi_scsi.adapter_target =
93 1.7 mjacob ((fcparam *)isp->isp_param)->isp_loopid;
94 1.1 mjacob } else {
95 1.10 mjacob isp->isp_osinfo._link.openings = PI_OPENINGS;
96 1.1 mjacob isp->isp_osinfo._link.scsipi_scsi.max_target = MAX_TARGETS-1;
97 1.7 mjacob if (isp->isp_bustype == ISP_BT_SBUS) {
98 1.7 mjacob isp->isp_osinfo._link.scsipi_scsi.max_lun = 7;
99 1.7 mjacob } else {
100 1.7 mjacob /*
101 1.7 mjacob * Too much target breakage at present.
102 1.7 mjacob */
103 1.7 mjacob #if 0
104 1.7 mjacob if (isp->isp_fwrev >= ISP_FW_REV(7,55))
105 1.7 mjacob isp->isp_osinfo._link.scsipi_scsi.max_lun = 31;
106 1.7 mjacob else
107 1.7 mjacob #endif
108 1.7 mjacob isp->isp_osinfo._link.scsipi_scsi.max_lun = 7;
109 1.7 mjacob }
110 1.1 mjacob isp->isp_osinfo._link.scsipi_scsi.adapter_target =
111 1.1 mjacob ((sdparam *)isp->isp_param)->isp_initiator_id;
112 1.1 mjacob }
113 1.1 mjacob if (isp->isp_osinfo._link.openings < 2)
114 1.1 mjacob isp->isp_osinfo._link.openings = 2;
115 1.1 mjacob isp->isp_osinfo._link.type = BUS_SCSI;
116 1.8 mjacob
117 1.8 mjacob /*
118 1.10 mjacob * Send a SCSI Bus Reset (used to be done as part of attach,
119 1.10 mjacob * but now left to the OS outer layers).
120 1.10 mjacob *
121 1.10 mjacob * XXX: For now, skip resets for FC because the method by which
122 1.10 mjacob * XXX: we deal with loop down after issuing resets (which causes
123 1.10 mjacob * XXX: port logouts for all devices) needs interrupts to run so
124 1.10 mjacob * XXX: that async events happen.
125 1.10 mjacob */
126 1.10 mjacob
127 1.10 mjacob if (isp->isp_type & ISP_HA_SCSI)
128 1.10 mjacob (void) isp_control(isp, ISPCTL_RESET_BUS, NULL);
129 1.10 mjacob
130 1.10 mjacob /*
131 1.8 mjacob * Start the watchdog.
132 1.8 mjacob */
133 1.8 mjacob isp->isp_dogactive = 1;
134 1.8 mjacob timeout(isp_watch, isp, 30 * hz);
135 1.8 mjacob
136 1.8 mjacob /*
137 1.8 mjacob * And attach children (if any).
138 1.8 mjacob */
139 1.1 mjacob config_found((void *)isp, &isp->isp_osinfo._link, scsiprint);
140 1.1 mjacob }
141 1.1 mjacob
142 1.1 mjacob /*
143 1.1 mjacob * minphys our xfers
144 1.1 mjacob *
145 1.1 mjacob * Unfortunately, the buffer pointer describes the target device- not the
146 1.1 mjacob * adapter device, so we can't use the pointer to find out what kind of
147 1.1 mjacob * adapter we are and adjust accordingly.
148 1.1 mjacob */
149 1.1 mjacob
150 1.1 mjacob static void
151 1.1 mjacob ispminphys(bp)
152 1.1 mjacob struct buf *bp;
153 1.1 mjacob {
154 1.1 mjacob /*
155 1.1 mjacob * XX: Only the 1020 has a 24 bit limit.
156 1.1 mjacob */
157 1.1 mjacob if (bp->b_bcount >= (1 << 24)) {
158 1.1 mjacob bp->b_bcount = (1 << 24);
159 1.1 mjacob }
160 1.1 mjacob minphys(bp);
161 1.1 mjacob }
162 1.1 mjacob
163 1.1 mjacob static int
164 1.1 mjacob ispcmd(xs)
165 1.1 mjacob ISP_SCSI_XFER_T *xs;
166 1.1 mjacob {
167 1.1 mjacob struct ispsoftc *isp;
168 1.3 mjacob int result;
169 1.10 mjacob int s;
170 1.1 mjacob
171 1.1 mjacob isp = XS_ISP(xs);
172 1.10 mjacob s = splbio();
173 1.3 mjacob /*
174 1.3 mjacob * This is less efficient than I would like in that the
175 1.3 mjacob * majority of cases will have to do some pointer deferences
176 1.3 mjacob * to find out that things don't need to be updated.
177 1.3 mjacob */
178 1.3 mjacob if ((xs->flags & SCSI_AUTOCONF) == 0 && (isp->isp_type & ISP_HA_SCSI)) {
179 1.3 mjacob sdparam *sdp = isp->isp_param;
180 1.3 mjacob if (sdp->isp_devparam[XS_TGT(xs)].dev_flags !=
181 1.3 mjacob sdp->isp_devparam[XS_TGT(xs)].cur_dflags) {
182 1.3 mjacob u_int16_t f = DPARM_WIDE|DPARM_SYNC|DPARM_TQING;
183 1.3 mjacob if (xs->sc_link->quirks & SDEV_NOSYNC)
184 1.3 mjacob f &= ~DPARM_SYNC;
185 1.3 mjacob if (xs->sc_link->quirks & SDEV_NOWIDE)
186 1.3 mjacob f &= ~DPARM_WIDE;
187 1.3 mjacob if (xs->sc_link->quirks & SDEV_NOTAG)
188 1.3 mjacob f &= ~DPARM_TQING;
189 1.3 mjacob sdp->isp_devparam[XS_TGT(xs)].dev_flags &=
190 1.3 mjacob ~(DPARM_WIDE|DPARM_SYNC|DPARM_TQING);
191 1.3 mjacob sdp->isp_devparam[XS_TGT(xs)].dev_flags |= f;
192 1.3 mjacob sdp->isp_devparam[XS_TGT(xs)].dev_update = 1;
193 1.3 mjacob isp->isp_update = 1;
194 1.3 mjacob }
195 1.3 mjacob }
196 1.10 mjacob /*
197 1.10 mjacob * Check for queue blockage...
198 1.10 mjacob */
199 1.10 mjacob
200 1.10 mjacob if (isp->isp_osinfo.blocked) {
201 1.10 mjacob if (xs->flags & SCSI_POLL) {
202 1.10 mjacob xs->error = XS_DRIVER_STUFFUP;
203 1.10 mjacob splx(s);
204 1.10 mjacob return (TRY_AGAIN_LATER);
205 1.10 mjacob }
206 1.10 mjacob TAILQ_INSERT_TAIL(&isp->isp_osinfo.waitq, xs, adapter_q);
207 1.10 mjacob splx(s);
208 1.10 mjacob return (CMD_QUEUED);
209 1.10 mjacob }
210 1.10 mjacob
211 1.3 mjacob result = ispscsicmd(xs);
212 1.3 mjacob if (result != CMD_QUEUED || (xs->flags & SCSI_POLL) == 0) {
213 1.10 mjacob (void) splx(s);
214 1.3 mjacob return (result);
215 1.1 mjacob }
216 1.1 mjacob
217 1.1 mjacob /*
218 1.1 mjacob * If we can't use interrupts, poll on completion.
219 1.1 mjacob */
220 1.1 mjacob if (isp_poll(isp, xs, XS_TIME(xs))) {
221 1.1 mjacob /*
222 1.1 mjacob * If no other error occurred but we didn't finish,
223 1.1 mjacob * something bad happened.
224 1.1 mjacob */
225 1.1 mjacob if (XS_IS_CMD_DONE(xs) == 0) {
226 1.1 mjacob isp->isp_nactive--;
227 1.1 mjacob if (isp->isp_nactive < 0)
228 1.1 mjacob isp->isp_nactive = 0;
229 1.1 mjacob if (XS_NOERR(xs)) {
230 1.1 mjacob isp_lostcmd(isp, xs);
231 1.1 mjacob XS_SETERR(xs, HBA_BOTCH);
232 1.1 mjacob }
233 1.1 mjacob }
234 1.1 mjacob }
235 1.10 mjacob (void) splx(s);
236 1.1 mjacob return (CMD_COMPLETE);
237 1.1 mjacob }
238 1.1 mjacob
239 1.1 mjacob static int
240 1.1 mjacob isp_poll(isp, xs, mswait)
241 1.1 mjacob struct ispsoftc *isp;
242 1.1 mjacob ISP_SCSI_XFER_T *xs;
243 1.1 mjacob int mswait;
244 1.1 mjacob {
245 1.1 mjacob
246 1.1 mjacob while (mswait) {
247 1.1 mjacob /* Try the interrupt handling routine */
248 1.1 mjacob (void)isp_intr((void *)isp);
249 1.1 mjacob
250 1.1 mjacob /* See if the xs is now done */
251 1.1 mjacob if (XS_IS_CMD_DONE(xs)) {
252 1.1 mjacob return (0);
253 1.1 mjacob }
254 1.1 mjacob SYS_DELAY(1000); /* wait one millisecond */
255 1.1 mjacob mswait--;
256 1.1 mjacob }
257 1.1 mjacob return (1);
258 1.8 mjacob }
259 1.8 mjacob
260 1.8 mjacob static void
261 1.8 mjacob isp_watch(arg)
262 1.8 mjacob void *arg;
263 1.8 mjacob {
264 1.8 mjacob int i;
265 1.8 mjacob struct ispsoftc *isp = arg;
266 1.8 mjacob ISP_SCSI_XFER_T *xs;
267 1.8 mjacob ISP_ILOCKVAL_DECL;
268 1.8 mjacob
269 1.8 mjacob /*
270 1.8 mjacob * Look for completely dead commands (but not polled ones).
271 1.8 mjacob */
272 1.8 mjacob ISP_ILOCK(isp);
273 1.8 mjacob for (i = 0; i < RQUEST_QUEUE_LEN; i++) {
274 1.8 mjacob if ((xs = (ISP_SCSI_XFER_T *) isp->isp_xflist[i]) == NULL) {
275 1.8 mjacob continue;
276 1.8 mjacob }
277 1.8 mjacob if (XS_TIME(xs) == 0) {
278 1.8 mjacob continue;
279 1.8 mjacob }
280 1.8 mjacob XS_TIME(xs) -= (WATCH_INTERVAL * 1000);
281 1.8 mjacob /*
282 1.8 mjacob * Avoid later thinking that this
283 1.8 mjacob * transaction is not being timed.
284 1.8 mjacob * Then give ourselves to watchdog
285 1.8 mjacob * periods of grace.
286 1.8 mjacob */
287 1.8 mjacob if (XS_TIME(xs) == 0) {
288 1.8 mjacob XS_TIME(xs) = 1;
289 1.8 mjacob } else if (XS_TIME(xs) > -(2 * WATCH_INTERVAL * 1000)) {
290 1.8 mjacob continue;
291 1.8 mjacob }
292 1.8 mjacob if (isp_control(isp, ISPCTL_ABORT_CMD, xs)) {
293 1.8 mjacob printf("%s: isp_watch failed to abort command\n",
294 1.8 mjacob isp->isp_name);
295 1.8 mjacob isp_restart(isp);
296 1.8 mjacob break;
297 1.8 mjacob }
298 1.8 mjacob }
299 1.8 mjacob timeout(isp_watch, isp, WATCH_INTERVAL * hz);
300 1.8 mjacob isp->isp_dogactive = 1;
301 1.8 mjacob ISP_IUNLOCK(isp);
302 1.8 mjacob }
303 1.8 mjacob
304 1.8 mjacob /*
305 1.8 mjacob * Free any associated resources prior to decommissioning and
306 1.8 mjacob * set the card to a known state (so it doesn't wake up and kick
307 1.8 mjacob * us when we aren't expecting it to).
308 1.8 mjacob *
309 1.8 mjacob * Locks are held before coming here.
310 1.8 mjacob */
311 1.8 mjacob void
312 1.8 mjacob isp_uninit(isp)
313 1.8 mjacob struct ispsoftc *isp;
314 1.8 mjacob {
315 1.8 mjacob ISP_ILOCKVAL_DECL;
316 1.8 mjacob ISP_ILOCK(isp);
317 1.8 mjacob /*
318 1.8 mjacob * Leave with interrupts disabled.
319 1.8 mjacob */
320 1.8 mjacob DISABLE_INTS(isp);
321 1.8 mjacob
322 1.8 mjacob /*
323 1.8 mjacob * Turn off the watchdog (if active).
324 1.8 mjacob */
325 1.8 mjacob if (isp->isp_dogactive) {
326 1.8 mjacob untimeout(isp_watch, isp);
327 1.8 mjacob isp->isp_dogactive = 0;
328 1.8 mjacob }
329 1.8 mjacob
330 1.8 mjacob ISP_IUNLOCK(isp);
331 1.9 mjacob }
332 1.9 mjacob
333 1.10 mjacob /*
334 1.10 mjacob * Restart function after a LOOP UP event (e.g.),
335 1.10 mjacob * done as a timeout for some hysteresis.
336 1.10 mjacob */
337 1.10 mjacob static void
338 1.10 mjacob isp_internal_restart(arg)
339 1.10 mjacob void *arg;
340 1.10 mjacob {
341 1.10 mjacob struct ispsoftc *isp = arg;
342 1.10 mjacob int result, nrestarted = 0, s = splbio();
343 1.10 mjacob
344 1.10 mjacob if (isp->isp_osinfo.blocked == 0) {
345 1.10 mjacob struct scsipi_xfer *xs;
346 1.10 mjacob while ((xs = TAILQ_FIRST(&isp->isp_osinfo.waitq)) != NULL) {
347 1.10 mjacob TAILQ_REMOVE(&isp->isp_osinfo.waitq, xs, adapter_q);
348 1.10 mjacob if ((result = ispscsicmd(xs)) != CMD_QUEUED) {
349 1.10 mjacob printf("%s: botched command restart (0x%x)\n",
350 1.10 mjacob isp->isp_name, result);
351 1.10 mjacob xs->flags |= ITSDONE;
352 1.10 mjacob if (xs->error == XS_NOERROR)
353 1.10 mjacob xs->error = XS_DRIVER_STUFFUP;
354 1.10 mjacob scsipi_done(xs);
355 1.10 mjacob }
356 1.10 mjacob nrestarted++;
357 1.10 mjacob }
358 1.10 mjacob printf("%s: requeued %d commands\n", isp->isp_name, nrestarted);
359 1.10 mjacob }
360 1.10 mjacob (void) splx(s);
361 1.10 mjacob }
362 1.10 mjacob
363 1.9 mjacob int
364 1.9 mjacob isp_async(isp, cmd, arg)
365 1.9 mjacob struct ispsoftc *isp;
366 1.9 mjacob ispasync_t cmd;
367 1.9 mjacob void *arg;
368 1.9 mjacob {
369 1.10 mjacob int s = splbio();
370 1.9 mjacob switch (cmd) {
371 1.10 mjacob case ISPASYNC_LOOP_DOWN:
372 1.10 mjacob /*
373 1.10 mjacob * Hopefully we get here in time to minimize the number
374 1.10 mjacob * of commands we are firing off that are sure to die.
375 1.10 mjacob */
376 1.10 mjacob isp->isp_osinfo.blocked = 1;
377 1.10 mjacob break;
378 1.10 mjacob case ISPASYNC_LOOP_UP:
379 1.10 mjacob isp->isp_osinfo.blocked = 0;
380 1.10 mjacob timeout(isp_internal_restart, isp, 1);
381 1.10 mjacob break;
382 1.9 mjacob case ISPASYNC_NEW_TGT_PARAMS:
383 1.9 mjacob if (isp->isp_type & ISP_HA_SCSI) {
384 1.9 mjacob sdparam *sdp = isp->isp_param;
385 1.9 mjacob char *wt;
386 1.9 mjacob int ns, flags, tgt;
387 1.9 mjacob
388 1.9 mjacob tgt = *((int *) arg);
389 1.9 mjacob
390 1.9 mjacob flags = sdp->isp_devparam[tgt].dev_flags;
391 1.9 mjacob if (flags & DPARM_SYNC) {
392 1.9 mjacob ns = sdp->isp_devparam[tgt].sync_period * 4;
393 1.9 mjacob } else {
394 1.9 mjacob ns = 0;
395 1.9 mjacob }
396 1.9 mjacob switch (flags & (DPARM_WIDE|DPARM_TQING)) {
397 1.9 mjacob case DPARM_WIDE:
398 1.9 mjacob wt = ", 16 bit wide\n";
399 1.9 mjacob break;
400 1.9 mjacob case DPARM_TQING:
401 1.9 mjacob wt = ", Tagged Queueing Enabled\n";
402 1.9 mjacob break;
403 1.9 mjacob case DPARM_WIDE|DPARM_TQING:
404 1.9 mjacob wt = ", 16 bit wide, Tagged Queueing Enabled\n";
405 1.9 mjacob break;
406 1.9 mjacob default:
407 1.9 mjacob wt = "\n";
408 1.9 mjacob break;
409 1.9 mjacob }
410 1.9 mjacob if (ns) {
411 1.9 mjacob printf("%s: Target %d at %dMHz Max Offset %d%s",
412 1.9 mjacob isp->isp_name, tgt, 1000 / ns,
413 1.9 mjacob sdp->isp_devparam[tgt].sync_offset, wt);
414 1.9 mjacob } else {
415 1.9 mjacob printf("%s: Target %d Async Mode%s",
416 1.9 mjacob isp->isp_name, tgt, wt);
417 1.9 mjacob }
418 1.9 mjacob }
419 1.9 mjacob break;
420 1.9 mjacob default:
421 1.9 mjacob break;
422 1.9 mjacob }
423 1.10 mjacob (void) splx(s);
424 1.9 mjacob return (0);
425 1.1 mjacob }
426