isp_netbsd.c revision 1.11 1 /* $NetBSD: isp_netbsd.c,v 1.11 1999/03/17 06:15:48 mjacob Exp $ */
2 /* release_03_16_99 */
3 /*
4 * Platform (NetBSD) dependent common attachment code for Qlogic adapters.
5 *
6 *---------------------------------------
7 * Copyright (c) 1997, 1998 by Matthew Jacob
8 * NASA/Ames Research Center
9 * All rights reserved.
10 *---------------------------------------
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice immediately at the beginning of the file, without modification,
17 * this list of conditions, and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. The name of the author may not be used to endorse or promote products
22 * derived from this software without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
28 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * The author may be reached via electronic communications at
37 *
38 * mjacob (at) nas.nasa.gov
39 * mjacob (at) feral.com
40 *
41 * or, via United States Postal Address
42 *
43 * Matthew Jacob
44 * Feral Software
45 * 2339 3rd Street
46 * Suite 24
47 * San Francisco, CA, 94107
48 */
49
50 #include <dev/ic/isp_netbsd.h>
51
52 static void ispminphys __P((struct buf *));
53 static int32_t ispcmd __P((ISP_SCSI_XFER_T *));
54
55 static struct scsipi_device isp_dev = { NULL, NULL, NULL, NULL };
56 static int isp_poll __P((struct ispsoftc *, ISP_SCSI_XFER_T *, int));
57 static void isp_watch __P((void *));
58 static void isp_internal_restart __P((void *));
59
60 #define FC_OPENINGS RQUEST_QUEUE_LEN / (MAX_FC_TARG-1)
61 #define PI_OPENINGS RQUEST_QUEUE_LEN / (MAX_TARGETS-1)
62
63 /*
64 * Complete attachment of hardware, include subdevices.
65 */
66 void
67 isp_attach(isp)
68 struct ispsoftc *isp;
69 {
70
71 isp->isp_osinfo._adapter.scsipi_cmd = ispcmd;
72 isp->isp_osinfo._adapter.scsipi_minphys = ispminphys;
73
74 isp->isp_state = ISP_RUNSTATE;
75 isp->isp_osinfo._link.scsipi_scsi.channel = SCSI_CHANNEL_ONLY_ONE;
76 isp->isp_osinfo._link.adapter_softc = isp;
77 isp->isp_osinfo._link.device = &isp_dev;
78 isp->isp_osinfo._link.adapter = &isp->isp_osinfo._adapter;
79 TAILQ_INIT(&isp->isp_osinfo.waitq);
80
81 if (isp->isp_type & ISP_HA_FC) {
82 /*
83 * Give it another chance here to come alive...
84 */
85 fcparam *fcp = isp->isp_param;
86 if (fcp->isp_fwstate != FW_READY) {
87 (void) isp_control(isp, ISPCTL_FCLINK_TEST, NULL);
88 }
89 isp->isp_osinfo._link.scsipi_scsi.max_target = MAX_FC_TARG-1;
90 #ifdef ISP2100_SCCLUN
91 /*
92 * 16 bits worth, but let's be reasonable..
93 */
94 isp->isp_osinfo._link.scsipi_scsi.max_lun = 255;
95 #else
96 isp->isp_osinfo._link.scsipi_scsi.max_lun = 15;
97 #endif
98 isp->isp_osinfo._link.openings = FC_OPENINGS;
99 isp->isp_osinfo._link.scsipi_scsi.adapter_target =
100 ((fcparam *)isp->isp_param)->isp_loopid;
101 } else {
102 isp->isp_osinfo._link.openings = PI_OPENINGS;
103 isp->isp_osinfo._link.scsipi_scsi.max_target = MAX_TARGETS-1;
104 if (isp->isp_bustype == ISP_BT_SBUS) {
105 isp->isp_osinfo._link.scsipi_scsi.max_lun = 7;
106 } else {
107 /*
108 * Too much target breakage at present.
109 */
110 #if 0
111 if (isp->isp_fwrev >= ISP_FW_REV(7,55))
112 isp->isp_osinfo._link.scsipi_scsi.max_lun = 31;
113 else
114 #endif
115 isp->isp_osinfo._link.scsipi_scsi.max_lun = 7;
116 }
117 isp->isp_osinfo._link.scsipi_scsi.adapter_target =
118 ((sdparam *)isp->isp_param)->isp_initiator_id;
119 }
120 if (isp->isp_osinfo._link.openings < 2)
121 isp->isp_osinfo._link.openings = 2;
122 isp->isp_osinfo._link.type = BUS_SCSI;
123
124 /*
125 * Send a SCSI Bus Reset (used to be done as part of attach,
126 * but now left to the OS outer layers).
127 *
128 * XXX: For now, skip resets for FC because the method by which
129 * XXX: we deal with loop down after issuing resets (which causes
130 * XXX: port logouts for all devices) needs interrupts to run so
131 * XXX: that async events happen.
132 */
133
134 if (isp->isp_type & ISP_HA_SCSI) {
135 (void) isp_control(isp, ISPCTL_RESET_BUS, NULL);
136 SYS_DELAY(2*1000000);
137 } else {
138 ;
139 }
140
141 /*
142 * Start the watchdog.
143 */
144 isp->isp_dogactive = 1;
145 timeout(isp_watch, isp, 30 * hz);
146
147 /*
148 * And attach children (if any).
149 */
150 config_found((void *)isp, &isp->isp_osinfo._link, scsiprint);
151 }
152
153 /*
154 * minphys our xfers
155 *
156 * Unfortunately, the buffer pointer describes the target device- not the
157 * adapter device, so we can't use the pointer to find out what kind of
158 * adapter we are and adjust accordingly.
159 */
160
161 static void
162 ispminphys(bp)
163 struct buf *bp;
164 {
165 /*
166 * XX: Only the 1020 has a 24 bit limit.
167 */
168 if (bp->b_bcount >= (1 << 24)) {
169 bp->b_bcount = (1 << 24);
170 }
171 minphys(bp);
172 }
173
174 static int
175 ispcmd(xs)
176 ISP_SCSI_XFER_T *xs;
177 {
178 struct ispsoftc *isp;
179 int result;
180 int s;
181
182 isp = XS_ISP(xs);
183 s = splbio();
184 /*
185 * This is less efficient than I would like in that the
186 * majority of cases will have to do some pointer deferences
187 * to find out that things don't need to be updated.
188 */
189 if ((xs->flags & SCSI_AUTOCONF) == 0 && (isp->isp_type & ISP_HA_SCSI)) {
190 sdparam *sdp = isp->isp_param;
191 if (sdp->isp_devparam[XS_TGT(xs)].dev_flags !=
192 sdp->isp_devparam[XS_TGT(xs)].cur_dflags) {
193 u_int16_t f = DPARM_WIDE|DPARM_SYNC|DPARM_TQING;
194 if (xs->sc_link->quirks & SDEV_NOSYNC)
195 f &= ~DPARM_SYNC;
196 if (xs->sc_link->quirks & SDEV_NOWIDE)
197 f &= ~DPARM_WIDE;
198 if (xs->sc_link->quirks & SDEV_NOTAG)
199 f &= ~DPARM_TQING;
200 sdp->isp_devparam[XS_TGT(xs)].dev_flags &=
201 ~(DPARM_WIDE|DPARM_SYNC|DPARM_TQING);
202 sdp->isp_devparam[XS_TGT(xs)].dev_flags |= f;
203 sdp->isp_devparam[XS_TGT(xs)].dev_update = 1;
204 isp->isp_update = 1;
205 }
206 }
207
208 if (isp->isp_state < ISP_RUNSTATE) {
209 DISABLE_INTS(isp);
210 isp_init(isp);
211 if (isp->isp_state != ISP_INITSTATE) {
212 ENABLE_INTS(isp);
213 (void) splx(s);
214 XS_SETERR(xs, HBA_BOTCH);
215 return (CMD_COMPLETE);
216 }
217 isp->isp_state = ISP_RUNSTATE;
218 ENABLE_INTS(isp);
219 }
220
221 /*
222 * Check for queue blockage...
223 */
224
225 if (isp->isp_osinfo.blocked) {
226 if (xs->flags & SCSI_POLL) {
227 xs->error = XS_DRIVER_STUFFUP;
228 splx(s);
229 return (TRY_AGAIN_LATER);
230 }
231 TAILQ_INSERT_TAIL(&isp->isp_osinfo.waitq, xs, adapter_q);
232 splx(s);
233 return (CMD_QUEUED);
234 }
235
236 DISABLE_INTS(isp);
237 result = ispscsicmd(xs);
238 ENABLE_INTS(isp);
239 if (result != CMD_QUEUED || (xs->flags & SCSI_POLL) == 0) {
240 (void) splx(s);
241 return (result);
242 }
243
244 /*
245 * If we can't use interrupts, poll on completion.
246 */
247 if (isp_poll(isp, xs, XS_TIME(xs))) {
248 /*
249 * If no other error occurred but we didn't finish,
250 * something bad happened.
251 */
252 if (XS_IS_CMD_DONE(xs) == 0) {
253 isp->isp_nactive--;
254 if (isp->isp_nactive < 0)
255 isp->isp_nactive = 0;
256 if (XS_NOERR(xs)) {
257 isp_lostcmd(isp, xs);
258 XS_SETERR(xs, HBA_BOTCH);
259 }
260 }
261 }
262 (void) splx(s);
263 return (CMD_COMPLETE);
264 }
265
266 static int
267 isp_poll(isp, xs, mswait)
268 struct ispsoftc *isp;
269 ISP_SCSI_XFER_T *xs;
270 int mswait;
271 {
272
273 while (mswait) {
274 /* Try the interrupt handling routine */
275 (void)isp_intr((void *)isp);
276
277 /* See if the xs is now done */
278 if (XS_IS_CMD_DONE(xs)) {
279 return (0);
280 }
281 SYS_DELAY(1000); /* wait one millisecond */
282 mswait--;
283 }
284 return (1);
285 }
286
287 static void
288 isp_watch(arg)
289 void *arg;
290 {
291 int i;
292 struct ispsoftc *isp = arg;
293 ISP_SCSI_XFER_T *xs;
294 ISP_ILOCKVAL_DECL;
295
296 /*
297 * Look for completely dead commands (but not polled ones).
298 */
299 ISP_ILOCK(isp);
300 for (i = 0; i < RQUEST_QUEUE_LEN; i++) {
301 if ((xs = (ISP_SCSI_XFER_T *) isp->isp_xflist[i]) == NULL) {
302 continue;
303 }
304 if (XS_TIME(xs) == 0) {
305 continue;
306 }
307 XS_TIME(xs) -= (WATCH_INTERVAL * 1000);
308 /*
309 * Avoid later thinking that this
310 * transaction is not being timed.
311 * Then give ourselves to watchdog
312 * periods of grace.
313 */
314 if (XS_TIME(xs) == 0) {
315 XS_TIME(xs) = 1;
316 } else if (XS_TIME(xs) > -(2 * WATCH_INTERVAL * 1000)) {
317 continue;
318 }
319 if (isp_control(isp, ISPCTL_ABORT_CMD, xs)) {
320 printf("%s: isp_watch failed to abort command\n",
321 isp->isp_name);
322 isp_restart(isp);
323 break;
324 }
325 }
326 timeout(isp_watch, isp, WATCH_INTERVAL * hz);
327 isp->isp_dogactive = 1;
328 ISP_IUNLOCK(isp);
329 }
330
331 /*
332 * Free any associated resources prior to decommissioning and
333 * set the card to a known state (so it doesn't wake up and kick
334 * us when we aren't expecting it to).
335 *
336 * Locks are held before coming here.
337 */
338 void
339 isp_uninit(isp)
340 struct ispsoftc *isp;
341 {
342 ISP_ILOCKVAL_DECL;
343 ISP_ILOCK(isp);
344 /*
345 * Leave with interrupts disabled.
346 */
347 DISABLE_INTS(isp);
348
349 /*
350 * Turn off the watchdog (if active).
351 */
352 if (isp->isp_dogactive) {
353 untimeout(isp_watch, isp);
354 isp->isp_dogactive = 0;
355 }
356
357 ISP_IUNLOCK(isp);
358 }
359
360 /*
361 * Restart function after a LOOP UP event (e.g.),
362 * done as a timeout for some hysteresis.
363 */
364 static void
365 isp_internal_restart(arg)
366 void *arg;
367 {
368 struct ispsoftc *isp = arg;
369 int result, nrestarted = 0, s;
370
371 s = splbio();
372 if (isp->isp_osinfo.blocked == 0) {
373 struct scsipi_xfer *xs;
374 while ((xs = TAILQ_FIRST(&isp->isp_osinfo.waitq)) != NULL) {
375 TAILQ_REMOVE(&isp->isp_osinfo.waitq, xs, adapter_q);
376 DISABLE_INTS(isp);
377 result = ispscsicmd(xs);
378 ENABLE_INTS(isp);
379 if (result != CMD_QUEUED) {
380 printf("%s: botched command restart (0x%x)\n",
381 isp->isp_name, result);
382 xs->flags |= ITSDONE;
383 if (xs->error == XS_NOERROR)
384 xs->error = XS_DRIVER_STUFFUP;
385 scsipi_done(xs);
386 }
387 nrestarted++;
388 }
389 printf("%s: requeued %d commands\n", isp->isp_name, nrestarted);
390 }
391 (void) splx(s);
392 }
393
394 int
395 isp_async(isp, cmd, arg)
396 struct ispsoftc *isp;
397 ispasync_t cmd;
398 void *arg;
399 {
400 int s = splbio();
401 switch (cmd) {
402 case ISPASYNC_NEW_TGT_PARAMS:
403 if (isp->isp_type & ISP_HA_SCSI) {
404 sdparam *sdp = isp->isp_param;
405 char *wt;
406 int ns, flags, tgt;
407
408 tgt = *((int *) arg);
409
410 flags = sdp->isp_devparam[tgt].dev_flags;
411 if (flags & DPARM_SYNC) {
412 ns = sdp->isp_devparam[tgt].sync_period * 4;
413 } else {
414 ns = 0;
415 }
416 switch (flags & (DPARM_WIDE|DPARM_TQING)) {
417 case DPARM_WIDE:
418 wt = ", 16 bit wide\n";
419 break;
420 case DPARM_TQING:
421 wt = ", Tagged Queueing Enabled\n";
422 break;
423 case DPARM_WIDE|DPARM_TQING:
424 wt = ", 16 bit wide, Tagged Queueing Enabled\n";
425 break;
426 default:
427 wt = "\n";
428 break;
429 }
430 if (ns) {
431 printf("%s: Target %d at %dMHz Max Offset %d%s",
432 isp->isp_name, tgt, 1000 / ns,
433 sdp->isp_devparam[tgt].sync_offset, wt);
434 } else {
435 printf("%s: Target %d Async Mode%s",
436 isp->isp_name, tgt, wt);
437 }
438 }
439 break;
440 case ISPASYNC_BUS_RESET:
441 printf("%s: SCSI bus reset detected\n", isp->isp_name);
442 break;
443 case ISPASYNC_LOOP_DOWN:
444 /*
445 * Hopefully we get here in time to minimize the number
446 * of commands we are firing off that are sure to die.
447 */
448 isp->isp_osinfo.blocked = 1;
449 printf("%s: Loop DOWN\n", isp->isp_name);
450 break;
451 case ISPASYNC_LOOP_UP:
452 isp->isp_osinfo.blocked = 0;
453 timeout(isp_internal_restart, isp, 1);
454 printf("%s: Loop UP\n", isp->isp_name);
455 break;
456 case ISPASYNC_PDB_CHANGE_COMPLETE:
457 if (isp->isp_type & ISP_HA_FC) {
458 static char *roles[4] = {
459 "No", "Target", "Initiator", "Target/Initiator"
460 };
461 long tgt = (long) arg;
462 isp_pdb_t *pdbp = &((fcparam *)isp->isp_param)->isp_pdb[tgt];
463 printf("%s: Loop ID %d, %s role\n",
464 isp->isp_name, pdbp->pdb_loopid,
465 roles[(pdbp->pdb_prli_svc3 >> 4) & 0x3]);
466 printf(" Node Address 0x%x WWN 0x"
467 "%02x%02x%02x%02x%02x%02x%02x%02x\n",
468 BITS2WORD(pdbp->pdb_portid_bits),
469 pdbp->pdb_portname[0], pdbp->pdb_portname[1],
470 pdbp->pdb_portname[2], pdbp->pdb_portname[3],
471 pdbp->pdb_portname[4], pdbp->pdb_portname[5],
472 pdbp->pdb_portname[6], pdbp->pdb_portname[7]);
473 if (pdbp->pdb_options & PDB_OPTIONS_ADISC)
474 printf(" Hard Address 0x%x WWN 0x"
475 "%02x%02x%02x%02x%02x%02x%02x%02x\n",
476 BITS2WORD(pdbp->pdb_hardaddr_bits),
477 pdbp->pdb_nodename[0],
478 pdbp->pdb_nodename[1],
479 pdbp->pdb_nodename[2],
480 pdbp->pdb_nodename[3],
481 pdbp->pdb_nodename[4],
482 pdbp->pdb_nodename[5],
483 pdbp->pdb_nodename[6],
484 pdbp->pdb_nodename[7]);
485 switch (pdbp->pdb_prli_svc3 & SVC3_ROLE_MASK) {
486 case SVC3_TGT_ROLE|SVC3_INI_ROLE:
487 printf(" Master State=%s, Slave State=%s\n",
488 isp2100_pdb_statename(pdbp->pdb_mstate),
489 isp2100_pdb_statename(pdbp->pdb_sstate));
490 break;
491 case SVC3_TGT_ROLE:
492 printf(" Master State=%s\n",
493 isp2100_pdb_statename(pdbp->pdb_mstate));
494 break;
495 case SVC3_INI_ROLE:
496 printf(" Slave State=%s\n",
497 isp2100_pdb_statename(pdbp->pdb_sstate));
498 break;
499 default:
500 break;
501 }
502 break;
503 }
504 case ISPASYNC_CHANGE_NOTIFY:
505 printf("%s: Name Server Database Changed\n", isp->isp_name);
506 break;
507 default:
508 break;
509 }
510 (void) splx(s);
511 return (0);
512 }
513