uha.c revision 1.8 1 /* $NetBSD: uha.c,v 1.8 1997/06/06 23:31:05 thorpej Exp $ */
2
3 #undef UHADEBUG
4 #ifdef DDB
5 #define integrate
6 #else
7 #define integrate static inline
8 #endif
9
10 /*-
11 * Copyright (c) 1997 The NetBSD Foundation, Inc.
12 * All rights reserved.
13 *
14 * This code is derived from software contributed to The NetBSD Foundation
15 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
16 * NASA Ames Research Center.
17 *
18 * Redistribution and use in source and binary forms, with or without
19 * modification, are permitted provided that the following conditions
20 * are met:
21 * 1. Redistributions of source code must retain the above copyright
22 * notice, this list of conditions and the following disclaimer.
23 * 2. Redistributions in binary form must reproduce the above copyright
24 * notice, this list of conditions and the following disclaimer in the
25 * documentation and/or other materials provided with the distribution.
26 * 3. All advertising materials mentioning features or use of this software
27 * must display the following acknowledgement:
28 * This product includes software developed by the NetBSD
29 * Foundation, Inc. and its contributors.
30 * 4. Neither the name of The NetBSD Foundation nor the names of its
31 * contributors may be used to endorse or promote products derived
32 * from this software without specific prior written permission.
33 *
34 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
35 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
36 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
37 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
38 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
39 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
40 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
41 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
42 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
43 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
44 * POSSIBILITY OF SUCH DAMAGE.
45 */
46
47 /*
48 * Copyright (c) 1994, 1996, 1997 Charles M. Hannum. All rights reserved.
49 *
50 * Redistribution and use in source and binary forms, with or without
51 * modification, are permitted provided that the following conditions
52 * are met:
53 * 1. Redistributions of source code must retain the above copyright
54 * notice, this list of conditions and the following disclaimer.
55 * 2. Redistributions in binary form must reproduce the above copyright
56 * notice, this list of conditions and the following disclaimer in the
57 * documentation and/or other materials provided with the distribution.
58 * 3. All advertising materials mentioning features or use of this software
59 * must display the following acknowledgement:
60 * This product includes software developed by Charles M. Hannum.
61 * 4. The name of the author may not be used to endorse or promote products
62 * derived from this software without specific prior written permission.
63 *
64 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
65 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
66 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
67 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
68 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
69 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
70 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
71 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
72 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
73 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
74 */
75
76 /*
77 * Ported for use with the UltraStor 14f by Gary Close (gclose (at) wvnvms.wvnet.edu)
78 * Slight fixes to timeouts to run with the 34F
79 * Thanks to Julian Elischer for advice and help with this port.
80 *
81 * Originally written by Julian Elischer (julian (at) tfs.com)
82 * for TRW Financial Systems for use under the MACH(2.5) operating system.
83 *
84 * TRW Financial Systems, in accordance with their agreement with Carnegie
85 * Mellon University, makes this software available to CMU to distribute
86 * or use in any manner that they see fit as long as this message is kept with
87 * the software. For this reason TFS also grants any other persons or
88 * organisations permission to use or modify this software.
89 *
90 * TFS supplies this software to be publicly redistributed
91 * on the understanding that TFS is not responsible for the correct
92 * functioning of this software in any circumstances.
93 *
94 * commenced: Sun Sep 27 18:14:01 PDT 1992
95 * slight mod to make work with 34F as well: Wed Jun 2 18:05:48 WST 1993
96 */
97
98 #include <sys/types.h>
99 #include <sys/param.h>
100 #include <sys/systm.h>
101 #include <sys/kernel.h>
102 #include <sys/errno.h>
103 #include <sys/ioctl.h>
104 #include <sys/device.h>
105 #include <sys/malloc.h>
106 #include <sys/buf.h>
107 #include <sys/proc.h>
108 #include <sys/user.h>
109
110 #include <machine/bus.h>
111 #include <machine/intr.h>
112
113 #include <scsi/scsi_all.h>
114 #include <scsi/scsiconf.h>
115
116 #include <dev/ic/uhareg.h>
117 #include <dev/ic/uhavar.h>
118
119 #ifndef DDB
120 #define Debugger() panic("should call debugger here (uha.c)")
121 #endif /* ! DDB */
122
123 #define UHA_MAXXFER ((UHA_NSEG - 1) << PGSHIFT)
124
125 integrate void uha_reset_mscp __P((struct uha_softc *, struct uha_mscp *));
126 void uha_free_mscp __P((struct uha_softc *, struct uha_mscp *));
127 integrate void uha_init_mscp __P((struct uha_softc *, struct uha_mscp *));
128 struct uha_mscp *uha_get_mscp __P((struct uha_softc *, int));
129 void uhaminphys __P((struct buf *));
130 int uha_scsi_cmd __P((struct scsi_xfer *));
131 int uha_create_mscps __P((struct uha_softc *, void *, size_t));
132
133 struct scsi_adapter uha_switch = {
134 uha_scsi_cmd,
135 uhaminphys,
136 0,
137 0,
138 };
139
140 /* the below structure is so we have a default dev struct for out link struct */
141 struct scsi_device uha_dev = {
142 NULL, /* Use default error handler */
143 NULL, /* have a queue, served by this */
144 NULL, /* have no async handler */
145 NULL, /* Use default 'done' routine */
146 };
147
148 struct cfdriver uha_cd = {
149 NULL, "uha", DV_DULL
150 };
151
152 #define UHA_ABORT_TIMEOUT 2000 /* time to wait for abort (mSec) */
153
154 /* XXX Should put this in a better place. */
155 #define offsetof(type, member) ((size_t)(&((type *)0)->member))
156
157 /*
158 * Attach all the sub-devices we can find
159 */
160 void
161 uha_attach(sc, upd)
162 struct uha_softc *sc;
163 struct uha_probe_data *upd;
164 {
165
166 TAILQ_INIT(&sc->sc_free_mscp);
167
168 (sc->init)(sc);
169
170 /*
171 * fill in the prototype scsi_link.
172 */
173 sc->sc_link.channel = SCSI_CHANNEL_ONLY_ONE;
174 sc->sc_link.adapter_softc = sc;
175 sc->sc_link.adapter_target = upd->sc_scsi_dev;
176 sc->sc_link.adapter = &uha_switch;
177 sc->sc_link.device = &uha_dev;
178 sc->sc_link.openings = 2;
179 sc->sc_link.max_target = 7;
180
181 /*
182 * ask the adapter what subunits are present
183 */
184 config_found(&sc->sc_dev, &sc->sc_link, scsiprint);
185 }
186
187 integrate void
188 uha_reset_mscp(sc, mscp)
189 struct uha_softc *sc;
190 struct uha_mscp *mscp;
191 {
192
193 mscp->flags = 0;
194 }
195
196 /*
197 * A mscp (and hence a mbx-out) is put onto the free list.
198 */
199 void
200 uha_free_mscp(sc, mscp)
201 struct uha_softc *sc;
202 struct uha_mscp *mscp;
203 {
204 int s;
205
206 s = splbio();
207
208 uha_reset_mscp(sc, mscp);
209 TAILQ_INSERT_HEAD(&sc->sc_free_mscp, mscp, chain);
210
211 /*
212 * If there were none, wake anybody waiting for one to come free,
213 * starting with queued entries.
214 */
215 if (mscp->chain.tqe_next == 0)
216 wakeup(&sc->sc_free_mscp);
217
218 splx(s);
219 }
220
221 integrate void
222 uha_init_mscp(sc, mscp)
223 struct uha_softc *sc;
224 struct uha_mscp *mscp;
225 {
226 bus_dma_tag_t dmat = sc->sc_dmat;
227 int hashnum;
228
229 /*
230 * XXX Should we put a DIAGNOSTIC check for multiple
231 * XXX MSCP inits here?
232 */
233
234 bzero(mscp, sizeof(struct uha_mscp));
235
236 /*
237 * Create the DMA maps for this MSCP.
238 */
239 if (bus_dmamap_create(dmat, sizeof(struct uha_mscp), 1,
240 sizeof(struct uha_mscp), 0, BUS_DMA_NOWAIT | sc->sc_dmaflags,
241 &mscp->dmamap_self) ||
242
243 /* XXX What's a good value for this? */
244 bus_dmamap_create(dmat, UHA_MAXXFER, UHA_NSEG, UHA_MAXXFER,
245 0, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW | sc->sc_dmaflags,
246 &mscp->dmamap_xfer))
247 panic("uha_init_mscp: can't create DMA maps");
248
249 /*
250 * Load the permanent DMA maps.
251 */
252 if (bus_dmamap_load(dmat, mscp->dmamap_self, mscp,
253 sizeof(struct uha_mscp), NULL, BUS_DMA_NOWAIT))
254 panic("uha_init_mscp: can't load permanent maps");
255
256 /*
257 * put in the phystokv hash table
258 * Never gets taken out.
259 */
260 mscp->hashkey = mscp->dmamap_self->dm_segs[0].ds_addr;
261 hashnum = MSCP_HASH(mscp->hashkey);
262 mscp->nexthash = sc->sc_mscphash[hashnum];
263 sc->sc_mscphash[hashnum] = mscp;
264 uha_reset_mscp(sc, mscp);
265 }
266
267 /*
268 * Create a set of MSCPs and add them to the free list.
269 */
270 int
271 uha_create_mscps(sc, mem, size)
272 struct uha_softc *sc;
273 void *mem;
274 size_t size;
275 {
276 bus_dma_segment_t seg;
277 struct uha_mscp *mscp;
278 int rseg, error;
279
280 if (sc->sc_nummscps >= UHA_MSCP_MAX)
281 return (0);
282
283 if ((mscp = mem) != NULL)
284 goto have_mem;
285
286 size = NBPG;
287 error = bus_dmamem_alloc(sc->sc_dmat, size, NBPG, 0, &seg, 1, &rseg,
288 BUS_DMA_NOWAIT);
289 if (error)
290 return (error);
291
292 error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, size,
293 (caddr_t *)&mscp, BUS_DMA_NOWAIT|BUS_DMAMEM_NOSYNC);
294 if (error) {
295 bus_dmamem_free(sc->sc_dmat, &seg, rseg);
296 return (error);
297 }
298
299 have_mem:
300 bzero(mscp, size);
301 while (size > sizeof(struct uha_mscp)) {
302 uha_init_mscp(sc, mscp);
303 sc->sc_nummscps++;
304 TAILQ_INSERT_TAIL(&sc->sc_free_mscp, mscp, chain);
305 (caddr_t)mscp += ALIGN(sizeof(struct uha_mscp));
306 size -= ALIGN(sizeof(struct uha_mscp));
307 if (sc->sc_nummscps >= UHA_MSCP_MAX)
308 break;
309 }
310
311 return (0);
312 }
313
314 /*
315 * Get a free mscp
316 *
317 * If there are none, see if we can allocate a new one. If so, put it in the
318 * hash table too otherwise either return an error or sleep.
319 */
320 struct uha_mscp *
321 uha_get_mscp(sc, flags)
322 struct uha_softc *sc;
323 int flags;
324 {
325 struct uha_mscp *mscp;
326 int s;
327
328 s = splbio();
329
330 /*
331 * If we can and have to, sleep waiting for one to come free
332 * but only if we can't allocate a new one
333 */
334 for (;;) {
335 mscp = sc->sc_free_mscp.tqh_first;
336 if (mscp) {
337 TAILQ_REMOVE(&sc->sc_free_mscp, mscp, chain);
338 break;
339 }
340 if (sc->sc_nummscps < UHA_MSCP_MAX) {
341 if (uha_create_mscps(sc, NULL, 0)) {
342 printf("%s: can't allocate mscps\n",
343 sc->sc_dev.dv_xname);
344 goto out;
345 }
346 continue;
347 }
348 if ((flags & SCSI_NOSLEEP) != 0)
349 goto out;
350 tsleep(&sc->sc_free_mscp, PRIBIO, "uhamsc", 0);
351 }
352
353 mscp->flags |= MSCP_ALLOC;
354
355 out:
356 splx(s);
357 return (mscp);
358 }
359
360 /*
361 * given a physical address, find the mscp that it corresponds to.
362 */
363 struct uha_mscp *
364 uha_mscp_phys_kv(sc, mscp_phys)
365 struct uha_softc *sc;
366 u_long mscp_phys;
367 {
368 int hashnum = MSCP_HASH(mscp_phys);
369 struct uha_mscp *mscp = sc->sc_mscphash[hashnum];
370
371 while (mscp) {
372 if (mscp->hashkey == mscp_phys)
373 break;
374 mscp = mscp->nexthash;
375 }
376 return (mscp);
377 }
378
379 /*
380 * We have a mscp which has been processed by the adaptor, now we look to see
381 * how the operation went.
382 */
383 void
384 uha_done(sc, mscp)
385 struct uha_softc *sc;
386 struct uha_mscp *mscp;
387 {
388 bus_dma_tag_t dmat = sc->sc_dmat;
389 struct scsi_sense_data *s1, *s2;
390 struct scsi_xfer *xs = mscp->xs;
391
392 SC_DEBUG(xs->sc_link, SDEV_DB2, ("uha_done\n"));
393
394 /*
395 * If we were a data transfer, unload the map that described
396 * the data buffer.
397 */
398 if (xs->datalen) {
399 bus_dmamap_sync(dmat, mscp->dmamap_xfer,
400 (xs->flags & SCSI_DATA_IN) ? BUS_DMASYNC_POSTREAD :
401 BUS_DMASYNC_POSTWRITE);
402 bus_dmamap_unload(dmat, mscp->dmamap_xfer);
403 }
404
405 /*
406 * Otherwise, put the results of the operation
407 * into the xfer and call whoever started it
408 */
409 if ((mscp->flags & MSCP_ALLOC) == 0) {
410 printf("%s: exiting ccb not allocated!\n", sc->sc_dev.dv_xname);
411 Debugger();
412 return;
413 }
414 if (xs->error == XS_NOERROR) {
415 if (mscp->host_stat != UHA_NO_ERR) {
416 switch (mscp->host_stat) {
417 case UHA_SBUS_TIMEOUT: /* No response */
418 xs->error = XS_SELTIMEOUT;
419 break;
420 default: /* Other scsi protocol messes */
421 printf("%s: host_stat %x\n",
422 sc->sc_dev.dv_xname, mscp->host_stat);
423 xs->error = XS_DRIVER_STUFFUP;
424 }
425 } else if (mscp->target_stat != SCSI_OK) {
426 switch (mscp->target_stat) {
427 case SCSI_CHECK:
428 s1 = &mscp->mscp_sense;
429 s2 = &xs->sense;
430 *s2 = *s1;
431 xs->error = XS_SENSE;
432 break;
433 case SCSI_BUSY:
434 xs->error = XS_BUSY;
435 break;
436 default:
437 printf("%s: target_stat %x\n",
438 sc->sc_dev.dv_xname, mscp->target_stat);
439 xs->error = XS_DRIVER_STUFFUP;
440 }
441 } else
442 xs->resid = 0;
443 }
444 uha_free_mscp(sc, mscp);
445 xs->flags |= ITSDONE;
446 scsi_done(xs);
447 }
448
449 void
450 uhaminphys(bp)
451 struct buf *bp;
452 {
453
454 if (bp->b_bcount > UHA_MAXXFER)
455 bp->b_bcount = UHA_MAXXFER;
456 minphys(bp);
457 }
458
459 /*
460 * start a scsi operation given the command and the data address. Also
461 * needs the unit, target and lu.
462 */
463 int
464 uha_scsi_cmd(xs)
465 struct scsi_xfer *xs;
466 {
467 struct scsi_link *sc_link = xs->sc_link;
468 struct uha_softc *sc = sc_link->adapter_softc;
469 bus_dma_tag_t dmat = sc->sc_dmat;
470 struct uha_mscp *mscp;
471 struct uha_dma_seg *sg;
472 int error, seg, flags, s;
473
474 SC_DEBUG(sc_link, SDEV_DB2, ("uha_scsi_cmd\n"));
475 /*
476 * get a mscp (mbox-out) to use. If the transfer
477 * is from a buf (possibly from interrupt time)
478 * then we can't allow it to sleep
479 */
480 flags = xs->flags;
481 if ((mscp = uha_get_mscp(sc, flags)) == NULL) {
482 xs->error = XS_DRIVER_STUFFUP;
483 return (TRY_AGAIN_LATER);
484 }
485 mscp->xs = xs;
486 mscp->timeout = xs->timeout;
487
488 /*
489 * Put all the arguments for the xfer in the mscp
490 */
491 if (flags & SCSI_RESET) {
492 mscp->opcode = UHA_SDR;
493 mscp->ca = 0x01;
494 } else {
495 mscp->opcode = UHA_TSP;
496 /* XXX Not for tapes. */
497 mscp->ca = 0x01;
498 bcopy(xs->cmd, &mscp->scsi_cmd, mscp->scsi_cmd_length);
499 }
500 mscp->xdir = UHA_SDET;
501 mscp->dcn = 0x00;
502 mscp->chan = 0x00;
503 mscp->target = sc_link->target;
504 mscp->lun = sc_link->lun;
505 mscp->scsi_cmd_length = xs->cmdlen;
506 mscp->sense_ptr = mscp->dmamap_self->dm_segs[0].ds_addr +
507 offsetof(struct uha_mscp, mscp_sense);
508 mscp->req_sense_length = sizeof(mscp->mscp_sense);
509 mscp->host_stat = 0x00;
510 mscp->target_stat = 0x00;
511
512 if (xs->datalen) {
513 sg = mscp->uha_dma;
514 seg = 0;
515 #ifdef TFS
516 if (flags & SCSI_DATA_UIO) {
517 error = bus_dmamap_load_uio(dmat,
518 mscp->dmamap_xfer, (struct uio *)xs->data,
519 (flags & SCSI_NOSLEEP) ? BUS_DMA_NOWAIT :
520 BUS_DMA_WAITOK);
521 } else
522 #endif /*TFS */
523 {
524 error = bus_dmamap_load(dmat,
525 mscp->dmamap_xfer, xs->data, xs->datalen, NULL,
526 (flags & SCSI_NOSLEEP) ? BUS_DMA_NOWAIT :
527 BUS_DMA_WAITOK);
528 }
529
530 if (error) {
531 if (error == EFBIG) {
532 printf("%s: uha_scsi_cmd, more than %d"
533 " dma segments\n",
534 sc->sc_dev.dv_xname, UHA_NSEG);
535 } else {
536 printf("%s: uha_scsi_cmd, error %d loading"
537 " dma map\n",
538 sc->sc_dev.dv_xname, error);
539 }
540 goto bad;
541 }
542
543 bus_dmamap_sync(dmat, mscp->dmamap_xfer,
544 (flags & SCSI_DATA_IN) ? BUS_DMASYNC_PREREAD :
545 BUS_DMASYNC_PREWRITE);
546
547 /*
548 * Load the hardware scatter/gather map with the
549 * contents of the DMA map.
550 */
551 for (seg = 0; seg < mscp->dmamap_xfer->dm_nsegs; seg++) {
552 mscp->uha_dma[seg].seg_addr =
553 mscp->dmamap_xfer->dm_segs[seg].ds_addr;
554 mscp->uha_dma[seg].seg_len =
555 mscp->dmamap_xfer->dm_segs[seg].ds_len;
556 }
557
558 mscp->data_addr = mscp->dmamap_self->dm_segs[0].ds_addr +
559 offsetof(struct uha_mscp, uha_dma);
560 mscp->data_length = xs->datalen;
561 mscp->sgth = 0x01;
562 mscp->sg_num = seg;
563 } else { /* No data xfer, use non S/G values */
564 mscp->data_addr = (physaddr)0;
565 mscp->data_length = 0;
566 mscp->sgth = 0x00;
567 mscp->sg_num = 0;
568 }
569 mscp->link_id = 0;
570 mscp->link_addr = (physaddr)0;
571
572 s = splbio();
573 (sc->start_mbox)(sc, mscp);
574 splx(s);
575
576 /*
577 * Usually return SUCCESSFULLY QUEUED
578 */
579 if ((flags & SCSI_POLL) == 0)
580 return (SUCCESSFULLY_QUEUED);
581
582 /*
583 * If we can't use interrupts, poll on completion
584 */
585 if ((sc->poll)(sc, xs, mscp->timeout)) {
586 uha_timeout(mscp);
587 if ((sc->poll)(sc, xs, mscp->timeout))
588 uha_timeout(mscp);
589 }
590 return (COMPLETE);
591
592 bad:
593 xs->error = XS_DRIVER_STUFFUP;
594 uha_free_mscp(sc, mscp);
595 return (COMPLETE);
596 }
597
598 void
599 uha_timeout(arg)
600 void *arg;
601 {
602 struct uha_mscp *mscp = arg;
603 struct scsi_xfer *xs = mscp->xs;
604 struct scsi_link *sc_link = xs->sc_link;
605 struct uha_softc *sc = sc_link->adapter_softc;
606 int s;
607
608 sc_print_addr(sc_link);
609 printf("timed out");
610
611 s = splbio();
612
613 if (mscp->flags & MSCP_ABORT) {
614 /* abort timed out */
615 printf(" AGAIN\n");
616 /* XXX Must reset! */
617 } else {
618 /* abort the operation that has timed out */
619 printf("\n");
620 mscp->xs->error = XS_TIMEOUT;
621 mscp->timeout = UHA_ABORT_TIMEOUT;
622 mscp->flags |= MSCP_ABORT;
623 (sc->start_mbox)(sc, mscp);
624 }
625
626 splx(s);
627 }
628