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