1 /** $MirOS: src/sys/dev/ic/uha.c,v 1.2 2005/03/06 21:27:40 tg Exp $ */
2 /* $OpenBSD: uha.c,v 1.4 2002/03/14 01:26:55 millert Exp $ */
3 /* $NetBSD: uha.c,v 1.3 1996/10/13 01:37:29 christos Exp $ */
4
5 #undef UHADEBUG
6 #ifdef DDB
7 #define integrate
8 #else
9 #define integrate static inline
10 #endif
11
12 /*
13 * Copyright (c) 1994, 1996 Charles M. Hannum. All rights reserved.
14 *
15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions
17 * are met:
18 * 1. Redistributions of source code must retain the above copyright
19 * notice, this list of conditions and the following disclaimer.
20 * 2. Redistributions in binary form must reproduce the above copyright
21 * notice, this list of conditions and the following disclaimer in the
22 * documentation and/or other materials provided with the distribution.
23 * 3. All advertising materials mentioning features or use of this software
24 * must display the following acknowledgement:
25 * This product includes software developed by Charles M. Hannum.
26 * 4. The name of the author may not be used to endorse or promote products
27 * derived from this software without specific prior written permission.
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
30 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
31 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
32 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
33 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
34 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
38 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 */
40
41 /*
42 * Ported for use with the UltraStor 14f by Gary Close (gclose@wvnvms.wvnet.edu)
43 * Slight fixes to timeouts to run with the 34F
44 * Thanks to Julian Elischer for advice and help with this port.
45 *
46 * Originally written by Julian Elischer (julian@tfs.com)
47 * for TRW Financial Systems for use under the MACH(2.5) operating system.
48 *
49 * TRW Financial Systems, in accordance with their agreement with Carnegie
50 * Mellon University, makes this software available to CMU to distribute
51 * or use in any manner that they see fit as long as this message is kept with
52 * the software. For this reason TFS also grants any other persons or
53 * organisations permission to use or modify this software.
54 *
55 * TFS supplies this software to be publicly redistributed
56 * on the understanding that TFS is not responsible for the correct
57 * functioning of this software in any circumstances.
58 */
59
60 #include <sys/param.h>
61 #include <sys/systm.h>
62 #include <sys/kernel.h>
63 #include <sys/errno.h>
64 #include <sys/ioctl.h>
65 #include <sys/device.h>
66 #include <sys/malloc.h>
67 #include <sys/buf.h>
68 #include <sys/proc.h>
69 #include <sys/user.h>
70
71 #include <machine/bus.h>
72 #include <machine/intr.h>
73
74 #include <scsi/scsi_all.h>
75 #include <scsi/scsiconf.h>
76
77 #include <dev/ic/uhareg.h>
78 #include <dev/ic/uhavar.h>
79
80 #ifndef DDB
81 #define Debugger() panic("should call debugger here (ultra14f.c)")
82 #endif /* ! DDB */
83
84 #define KVTOPHYS(x) vtophys(x)
85
86 integrate void uha_reset_mscp(struct uha_softc *, struct uha_mscp *);
87 void uha_free_mscp(struct uha_softc *, struct uha_mscp *);
88 integrate void uha_init_mscp(struct uha_softc *, struct uha_mscp *);
89 struct uha_mscp *uha_get_mscp(struct uha_softc *, int);
90 void uhaminphys(struct buf *);
91 int uha_scsi_cmd(struct scsi_xfer *);
92
93 struct scsi_adapter uha_switch = {
94 uha_scsi_cmd,
95 uhaminphys,
96 0,
97 0,
98 };
99
100 /* the below structure is so we have a default dev struct for out link struct */
101 struct scsi_device uha_dev = {
102 NULL, /* Use default error handler */
103 NULL, /* have a queue, served by this */
104 NULL, /* have no async handler */
105 NULL, /* Use default 'done' routine */
106 };
107
108 struct cfdriver uha_cd = {
109 NULL, "uha", DV_DULL
110 };
111
112 #define UHA_ABORT_TIMEOUT 2000 /* time to wait for abort (mSec) */
113
114 #ifdef __OpenBSD__
115 int uhaprint(void *, const char *);
116
117 int
uhaprint(aux,name)118 uhaprint(aux, name)
119 void *aux;
120 const char *name;
121 {
122
123 if (name != NULL)
124 printf("%s: scsibus ", name);
125 return UNCONF;
126 }
127 #endif
128
129 /*
130 * Attach all the sub-devices we can find
131 */
132 void
uha_attach(sc)133 uha_attach(sc)
134 struct uha_softc *sc;
135 {
136
137 (sc->init)(sc);
138 TAILQ_INIT(&sc->sc_free_mscp);
139
140 /*
141 * fill in the prototype scsi_link.
142 */
143 #ifndef __OpenBSD__
144 sc->sc_link.channel = SCSI_CHANNEL_ONLY_ONE;
145 #endif
146 sc->sc_link.adapter_softc = sc;
147 sc->sc_link.adapter_target = sc->sc_scsi_dev;
148 sc->sc_link.adapter = &uha_switch;
149 sc->sc_link.device = &uha_dev;
150 sc->sc_link.openings = 2;
151
152 /*
153 * ask the adapter what subunits are present
154 */
155 #ifdef __OpenBSD__
156 config_found(&sc->sc_dev, &sc->sc_link, uhaprint);
157 #else
158 config_found(&sc->sc_dev, &sc->sc_link, scsiprint);
159 #endif
160 }
161
162 integrate void
uha_reset_mscp(sc,mscp)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
uha_free_mscp(sc,mscp)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 (mscp->chain.tqe_next == 0)
191 wakeup(&sc->sc_free_mscp);
192
193 splx(s);
194 }
195
196 integrate void
uha_init_mscp(sc,mscp)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 *
uha_get_mscp(sc,flags)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 = sc->sc_free_mscp.tqh_first;
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 *
uha_mscp_phys_kv(sc,mscp_phys)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
uha_done(sc,mscp)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
uhaminphys(bp)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
uha_scsi_cmd(xs)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 xs->error = XS_DRIVER_STUFFUP;
377 return (TRY_AGAIN_LATER);
378 }
379 mscp->xs = xs;
380 mscp->timeout = xs->timeout;
381 timeout_set(&xs->stimeout, uha_timeout, xs);
382
383 /*
384 * Put all the arguments for the xfer in the mscp
385 */
386 if (flags & SCSI_RESET) {
387 mscp->opcode = UHA_SDR;
388 mscp->ca = 0x01;
389 } else {
390 mscp->opcode = UHA_TSP;
391 /* XXX Not for tapes. */
392 mscp->ca = 0x01;
393 bcopy(xs->cmd, &mscp->scsi_cmd, mscp->scsi_cmd_length);
394 }
395 mscp->xdir = UHA_SDET;
396 mscp->dcn = 0x00;
397 mscp->chan = 0x00;
398 mscp->target = sc_link->target;
399 mscp->lun = sc_link->lun;
400 mscp->scsi_cmd_length = xs->cmdlen;
401 mscp->sense_ptr = KVTOPHYS(&mscp->mscp_sense);
402 mscp->req_sense_length = sizeof(mscp->mscp_sense);
403 mscp->host_stat = 0x00;
404 mscp->target_stat = 0x00;
405
406 if (xs->datalen) {
407 sg = mscp->uha_dma;
408 seg = 0;
409 #ifdef TFS
410 if (flags & SCSI_DATA_UIO) {
411 struct iovec *iovp;
412 iovp = ((struct uio *) xs->data)->uio_iov;
413 datalen = ((struct uio *) xs->data)->uio_iovcnt;
414 xs->datalen = 0;
415 while (datalen && seg < UHA_NSEG) {
416 sg->seg_addr = (physaddr)iovp->iov_base;
417 sg->seg_len = iovp->iov_len;
418 xs->datalen += iovp->iov_len;
419 SC_DEBUGN(sc_link, SDEV_DB4, ("(0x%x@0x%x)",
420 iovp->iov_len, iovp->iov_base));
421 sg++;
422 iovp++;
423 seg++;
424 datalen--;
425 }
426 } else
427 #endif /*TFS */
428 {
429 /*
430 * Set up the scatter gather block
431 */
432 SC_DEBUG(sc_link, SDEV_DB4,
433 ("%d @0x%lx:- ", xs->datalen, (long)xs->data));
434 datalen = xs->datalen;
435 thiskv = (int) xs->data;
436 thisphys = KVTOPHYS(thiskv);
437
438 while (datalen && seg < UHA_NSEG) {
439 bytes_this_seg = 0;
440
441 /* put in the base address */
442 sg->seg_addr = thisphys;
443
444 SC_DEBUGN(sc_link, SDEV_DB4, ("0x%lx", (long)thisphys));
445
446 /* do it at least once */
447 nextphys = thisphys;
448 while (datalen && thisphys == nextphys) {
449 /*
450 * This page is contiguous (physically)
451 * with the the last, just extend the
452 * length
453 */
454 /* how far to the end of the page */
455 nextphys = (thisphys & ~PGOFSET) + NBPG;
456 bytes_this_page = nextphys - thisphys;
457 /**** or the data ****/
458 bytes_this_page = min(bytes_this_page,
459 datalen);
460 bytes_this_seg += bytes_this_page;
461 datalen -= bytes_this_page;
462
463 /* get more ready for the next page */
464 thiskv = (thiskv & ~PGOFSET) + NBPG;
465 if (datalen)
466 thisphys = KVTOPHYS(thiskv);
467 }
468 /*
469 * next page isn't contiguous, finish the seg
470 */
471 SC_DEBUGN(sc_link, SDEV_DB4,
472 ("(0x%x)", bytes_this_seg));
473 sg->seg_len = bytes_this_seg;
474 sg++;
475 seg++;
476 }
477 }
478 /* end of iov/kv decision */
479 SC_DEBUGN(sc_link, SDEV_DB4, ("\n"));
480 if (datalen) {
481 /*
482 * there's still data, must have run out of segs!
483 */
484 printf("%s: uha_scsi_cmd, more than %d dma segs\n",
485 sc->sc_dev.dv_xname, UHA_NSEG);
486 goto bad;
487 }
488 mscp->data_addr = KVTOPHYS(mscp->uha_dma);
489 mscp->data_length = xs->datalen;
490 mscp->sgth = 0x01;
491 mscp->sg_num = seg;
492 } else { /* No data xfer, use non S/G values */
493 mscp->data_addr = (physaddr)0;
494 mscp->data_length = 0;
495 mscp->sgth = 0x00;
496 mscp->sg_num = 0;
497 }
498 mscp->link_id = 0;
499 mscp->link_addr = (physaddr)0;
500
501 s = splbio();
502 (sc->start_mbox)(sc, mscp);
503 splx(s);
504
505 /*
506 * Usually return SUCCESSFULLY QUEUED
507 */
508 if ((flags & SCSI_POLL) == 0)
509 return (SUCCESSFULLY_QUEUED);
510
511 /*
512 * If we can't use interrupts, poll on completion
513 */
514 if ((sc->poll)(sc, xs, mscp->timeout)) {
515 uha_timeout(mscp);
516 if ((sc->poll)(sc, xs, mscp->timeout))
517 uha_timeout(mscp);
518 }
519 return (COMPLETE);
520
521 bad:
522 xs->error = XS_DRIVER_STUFFUP;
523 uha_free_mscp(sc, mscp);
524 return (COMPLETE);
525 }
526
527 void
uha_timeout(arg)528 uha_timeout(arg)
529 void *arg;
530 {
531 struct uha_mscp *mscp = arg;
532 struct scsi_xfer *xs = mscp->xs;
533 struct scsi_link *sc_link = xs->sc_link;
534 struct uha_softc *sc = sc_link->adapter_softc;
535 int s;
536
537 sc_print_addr(sc_link);
538 printf("timed out");
539
540 s = splbio();
541
542 if (mscp->flags & MSCP_ABORT) {
543 /* abort timed out */
544 printf(" AGAIN\n");
545 /* XXX Must reset! */
546 } else {
547 /* abort the operation that has timed out */
548 printf("\n");
549 mscp->xs->error = XS_TIMEOUT;
550 mscp->timeout = UHA_ABORT_TIMEOUT;
551 mscp->flags |= MSCP_ABORT;
552 (sc->start_mbox)(sc, mscp);
553 }
554
555 splx(s);
556 }
557