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