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