xref: /386bsd/usr/src/kernel/as/as.c (revision a2142627)
1 /*
2  * Adaptec 1542 SCSI driver for 386bsd
3  *
4  * $Id$
5  *
6  * Pace Willisson     pace@blitz.com    March 28, 1992
7  *
8  * Placed in the public domain with NO WARRANTIES, not even the
9  * implied warranties for MERCHANTABILITY or FITNESS FOR A
10  * PARTICULAR PURPOSE.
11  *
12  * The the tape stuff still needs a lot of working concerning
13  * file marks, end of tape handling and rewinding.
14  *
15  * minor number bits:
16  *
17  *      7  6  5  4  3  2  1  0
18  *                     +-----+  partition number
19  *            +-----+           scsi target number
20  *      +--+                    controller number
21  *
22  * For tape drives, set the partition number to 0 for regular,
23  * 1 for no rewind.
24  *
25  * Only supports LUN 0.
26  */
27 
28 /* manufacturer default configuration: */
29 static char *as_config =
30 	"as 4 13 1 (0x330).	# Adaptec 1542 SCSI, $Revision$";
31 #define	NAS	1
32 
33 /* maximum configuration, regardless of conflicts:
34 	"as 2 13 4 (0x330) (0x334) (0x230) (0x234) (0x130) (0x134).
35 	# Adaptec 1542 SCSI, $Revision$" */
36 
37 #include "sys/param.h"
38 #include "sys/file.h"
39 #include "sys/stat.h"
40 #include "sys/ioctl.h"
41 #include "sys/errno.h"
42 #include	"proc.h" /* PCATCH et al */
43 #include "uio.h"
44 #include "dkbad.h"
45 #include "systm.h"
46 #include "disklabel.h"
47 #include "buf.h"
48 #include "malloc.h"
49 #include "prototypes.h"
50 #include "machine/inline/io.h"
51 #include "isa_driver.h"
52 #include "isa_irq.h"
53 #include "sys/syslog.h"
54 #include "vm.h"
55 #include "kmem.h"
56 #include "kernel.h"
57 #include "modconfig.h"
58 
59 #include "asreg.h"
60 
61 static int asstrategy ();
62 static int asabort ();
63 extern int hz;
64 
65 int asverbose = 0;
66 
67 /* target id 7 is the controller itself */
68 #define NTARGETS 8
69 
70 struct mailbox_entry mailboxes[NAS * NTARGETS * 2];
71 
72 #define b_cylin	b_resid /* fake cylinder number for disksort */
73 
74 /* maximum scatter list size for Adaptec controller */
75 #define NSCATTER 17
76 
77 /* this array must reside in contiguous physical memory */
78 struct asinfo {
79 	dev_t dev;
80 	struct buf requests;
81 	struct mailbox_entry *mailbox;
82 	int active;
83 	struct ccb ccb;
84 	unsigned int ccb_phys;
85 	char scatter_list[NSCATTER * 6];
86 
87 	struct disklabel label;
88 	struct dos_partition dospart[NDOSPART];
89 	int have_label;
90 
91 	int scsi_lock;
92 	struct buf *scsi_bp;
93 	int scsi_cdb_len;
94 	unsigned char scsi_cdb[MAXCDB];
95 
96 	int tape;		/* sequential */
97 	int disk;		/* nonsequential */
98 	int read_only;		/* CDROM */
99 	int removable;		/* unsupported and tested */
100 	char vendor[9];
101 	char model[17];
102 	char revision[5];
103 	int bs;			/* device block size */
104 
105 	int open_lock;
106 	int open;
107 	int units_open;
108 
109 	int wlabel;
110 
111 	int retry_count;
112 	int start_time;
113 	int restart_pending;
114 	int mbi_status;		/* mailbox in status */
115 	vm_offset_t bounce;	/* ISA bounce buffer for systems with > 16MB */
116 	int isbounced;
117 
118 } asinfo[NAS * NTARGETS];
119 extern caddr_t dumpISA;
120 
121 #define dev_part(dev) (minor (dev) & 7)
122 #define dev_target(dev) ((minor (dev) >> 3) & 7)
123 #define dev_rewind(dev) ((minor (dev) & 1) == 0)
124 #define dev_ctlr(dev) ((minor (dev) >> 6) & 3)
125 #define dev_to_as(dev)  (asinfo + (dev_ctlr(dev) * NTARGETS + dev_target(dev)))
126 
127 #define makeasdev(major, ctlr, target, part) \
128 	makedev ((major), ((ctlr) << 6) || ((target) << 3) | (part))
129 
130 static int as_port[NAS] = {0};
131 
132 /* default ports for 1542 controller */
133 static int def_ports[] = { 0x330, 0x334, 0x230, 0x234, 0x130, 0x134 };
134 
135 static asintr (int ctl /* dev_t dev*/);
136 static  asintr1 (struct asinfo *as, int val);
137 static int	asprobe(struct isa_device *), asattach(struct isa_device *),
138 	asintr(int /*dev_t*/);
139 static  asstart (struct asinfo *as);
140 static  asdone (struct asinfo *as, int restart);
141 static int as_get_byte (int port);
142 static int as_put_byte (int port, int val);
143 extern int biomask; /* XXX */
144 
145 struct	isa_driver asdriver = {
146 	asprobe, asattach, asintr, "as", &biomask
147 };
148 
149 /* default per device */
150 static struct isa_device as_default_devices[] = {
151 	{ &asdriver,    0x330, 0, -1,  0x00000,     0,  0 },
152 	{ &asdriver,    0x334, 0, -1,  0x00000,     0,  0 },
153 	{ &asdriver,    0x230, 0, -1,  0x00000,     0,  0 },
154 	{ &asdriver,    0x234, 0, -1,  0x00000,     0,  0 },
155 	{ &asdriver,    0x130, 0, -1,  0x00000,     0,  0 },
156 	{ &asdriver,    0x134, 0, -1,  0x00000,     0,  0 },
157 	{ 0 }
158 };
159 
160 static int aspartition(struct asinfo *as, struct buf *bp, int *blknop);
161 static int asmakescatter(struct asinfo *as, struct buf *bp, int phys);
162 static struct asinfo *asscan (dev_t dev);
163 static void asissue(struct asinfo *as);
164 static void asmakecdb(struct asinfo *as, int blkno, int count, int dir);
165 static void asmakeccb(struct asinfo *as, int nscatter, dev_t dev, int count, int dir);
166 
167 static u_char asctlcmd_nop[] = { 0 };
168 static u_char asctlcmd_mailboxinit[] = { 1, 0, 0, 0, 0 };
169 static u_char asctlcmd_conf[] = { 0xb };
170 
171 /* */
172 static int
173 asctlcmd(int ctl, u_char *cmdstring, int n, u_char *results) {
174 	int s, i, c, port = as_port[ctl] ;
175 
176 	c = *cmdstring;
177 	s = splbio ();
178 
179 	if (inb (port + AS_INTR) & AS_INTR_HACC)
180 		outb (port + AS_CONTROL, AS_CONTROL_IRST);
181 	/* if startscsi or enable mailbox out interrupt, don't wait for idle */
182 	if (c != 2 && c != 5) {
183 		for (i = 1000; i > 0; i--) {
184 			if ((inb (port + AS_STATUS) & AS_STATUS_IDLE))
185 				break;
186 			DELAY (100);
187 		}
188 		/* timeout waiting for idle */
189 		if (i == 0) {
190 printf("\nlost idle %x\n", c);
191 			splx(s);
192 			return(-1);
193 		}
194 
195 		/* if command expects results, obtain them */
196 		if (results) {
197 			int tmp;
198 
199 			/* get bytes until idle */
200 			while ((inb (port + AS_STATUS) & AS_STATUS_DF)) {
201 				if(as_get_byte(port) < 0) {
202 printf("\nno prior results %x\n", c);
203 					splx(s);
204 					return(-1);
205 				}
206 
207 			}
208 		}
209 	}
210 
211 	/* issue command to controller */
212 	for (i = 0; i < n ; i++) {
213 		if (as_put_byte (port, *cmdstring++) < 0) {
214 printf("\nfailed command %x\n", c);
215 			splx(s);
216 			return(-1);
217 		}
218 	}
219 
220 	/* if command expects results, obtain them */
221 	if (results) {
222 		int tmp;
223 
224 		/* get bytes until idle */
225 		while((tmp = as_get_byte(port)) > 0) {
226 			*results++ = tmp;
227 			DELAY(1000);
228 			if ((inb (port + AS_STATUS) & (AS_STATUS_IDLE|AS_STATUS_DF)) == AS_STATUS_IDLE)
229 				break;
230 		}
231 		if (tmp < 0) {
232 printf("\nno results %x\n", c);
233 			splx(s);
234 			return(-1);
235 		}
236 	}
237 
238 DELAY (100000);
239 printf("intr %x sts %x ", inb(port+ AS_INTR), inb(port+AS_STATUS));
240 	/* if startscsi or enable mailbox out interrupt, don't wait for hacc */
241 	if (c != 2 && c != 5 /* && c != 0 */) {
242 		for (i = 10000; i > 0; i--) {
243 			if (inb(port + AS_INTR) & AS_INTR_HACC)
244 				break;
245 			DELAY (100);
246 		}
247 		if (inb (port + AS_INTR) & AS_INTR_HACC)
248 			outb (port + AS_CONTROL, AS_CONTROL_IRST);
249 		/* timeout waiting for idle */
250 		if (i == 0) {
251 printf("\nno hacc %x\n", c);
252 #ifdef nope
253 1542C generates a HACC on NOP command, B does not.
254 #endif
255 			splx(s);
256 			return(-1);
257 		}
258 	}
259 	splx(s);
260 	return(0);
261 }
262 
263 static int
264 asprobe (struct isa_device *dvp)
265 {
266 	int i;
267 	u_char cfg[3];
268 	unsigned int physaddr;
269 	int val;
270 	int s, ctl, ap;
271 
272 	/* wildcard ? */
273 	if (dvp->id_unit == '?') {
274 		/* first, find a controller index */
275 		for (i = 0; as_port[i] != 0; i++) ;
276 		if (i > NAS)
277 			return (0);
278 		dvp->id_unit = i;
279 
280 		/* next, look for possible controllers */
281 		for (i = 0 ; i < sizeof(def_ports)/sizeof(def_ports[0]) ; i++) {
282 			if (def_ports[i]) {
283 				dvp->id_iobase = def_ports[i];
284 				if (asprobe(dvp))
285 					return (1);
286 			}
287 			def_ports[i] = 0;
288 		}
289 		return (0);
290 	}
291 
292 	ctl = dvp->id_unit;
293 	ap = as_port[ctl] = dvp->id_iobase;
294 
295 	if (inb(ap + AS_STATUS) == 0xff)
296 		goto fail;
297 	outb (ap + AS_CONTROL, AS_CONTROL_SRST);
298 	DELAY (30000);
299 
300 	/* for (i = 10000; i > 0; i--) {
301 		if ((inb (ap + AS_STATUS) & (AS_STATUS_IDLE | AS_STATUS_INIT))
302 			!= AS_STATUS_IDLE | AS_STATUS_INIT)
303 			break;
304 		DELAY (100);
305 	}*/
306 
307 	for (i = 0; i < NTARGETS; i++) {
308 		asinfo[ctl*NTARGETS+i].mailbox = &mailboxes[ctl*NTARGETS+i];
309 		asinfo[ctl*NTARGETS+i].ccb_phys = vtophys (&asinfo[ctl*NTARGETS+i].ccb);
310 	}
311 
312 
313 	physaddr = vtophys (mailboxes);
314 
315 	asctlcmd_mailboxinit[1] = NTARGETS;
316 	asctlcmd_mailboxinit[2] = physaddr >> 16;
317 	asctlcmd_mailboxinit[3] = physaddr >> 8;
318 	asctlcmd_mailboxinit[4] = physaddr;
319 printf("intr %x sts %x ", inb(ap+ AS_INTR), inb(ap+AS_STATUS));
320 	if (asctlcmd(ctl, asctlcmd_nop, sizeof(asctlcmd_nop), 0) == 0 &&
321 	    asctlcmd(ctl, asctlcmd_mailboxinit, sizeof(asctlcmd_mailboxinit), 0) == 0) {
322 
323 		if ((val = inb (ap + AS_STATUS)) & AS_STATUS_INIT) {
324 			printf ("as: mailbox init error: 0x%x\n", val);
325 			goto fail;
326 		}
327 		if (asctlcmd(ctl, asctlcmd_nop, sizeof(asctlcmd_nop), 0) == 0 &&
328 	    		asctlcmd(ctl, asctlcmd_conf, sizeof(asctlcmd_conf), cfg) == 0) {
329 			dvp->id_drq = ffs(cfg[0]) - 1;
330 			dvp->id_irq = cfg[1]<<9;
331 			return(1);
332 		}
333 	}
334 fail:
335 	as_port[ctl] = 0;
336 	return (0);
337 }
338 
339 static asattach (struct isa_device *dvp)
340 {
341 	int i;
342 	unsigned int physaddr;
343 	int val;
344 	int s, ctl;
345 
346 	ctl = dvp->id_unit;
347 	if (ctl > 0)
348 		printf("controller %d ", ctl + 1);
349 	isa_dmacascade(dvp->id_drq);
350 
351 	/* take out of the available list */
352 	for (i = 0 ; i < sizeof(def_ports)/sizeof(def_ports[0]) ; i++)
353 		if (dvp->id_iobase == def_ports[i])
354 			def_ports[i] = 0;
355 }
356 
357 static int
358 ascmd (as, bp, direction, count, retrycount)
359 struct asinfo *as;
360 struct buf *bp;
361 int direction;
362 int count;
363 int retrycount;
364 {
365 	int err;
366 
367 	do {
368 		if (asverbose)
369 			printf ("ascmd ");
370 		bp->b_bcount = count;
371 		bp->b_error = 0;
372 		bp->b_flags &= ~(B_READ | B_ERROR | B_DONE);
373 		if (direction == B_READ)
374 			bp->b_flags |= B_READ;
375 
376 		bp->b_dev = as->dev;
377 		bp->b_blkno = 0;
378 
379 		as->scsi_bp = bp;
380 		/* scsi_cdb, scsi_cdb_len set up by caller */
381 
382 		asstrategy (bp);
383 		err = biowait (bp);
384 		as->scsi_bp = NULL;
385 
386 	} while (err && --retrycount);
387 
388 	return (err);
389 }
390 
391 static asstring (dest, src, size)
392 char *dest;
393 char *src;
394 int size;
395 {
396 	size--;
397 	memcpy (dest, src, size);
398 	while (size > 0 && dest[size - 1] == ' ')
399 		size--;
400 	dest[size] = 0;
401 }
402 
403 static int
404 asopen(dev_t dev, int flag, int fmt, struct proc *pr)
405 {
406 	struct asinfo *as;
407 	unsigned int physaddr;
408 	struct buf *bp = NULL;
409 	int retry;
410 	unsigned char *cdb;
411 	char *p, *q;
412 	int n;
413 	int error;
414 	char vendor[9];
415 	char model[17];
416 	int disksize, ctl;
417 
418 	ctl = dev_ctlr(dev);
419 printf("as %x: ctl %d tgt %d ", dev, ctl, dev_target(dev));
420 	if (ctl > NAS || as_port[ctl] == 0 || dev_target (dev) >= NTARGETS)
421 		return (ENXIO);
422 
423 	as = dev_to_as(dev);
424 	as->dev = dev;
425 
426 	while (as->open_lock)
427 		if (error = tsleep ((caddr_t)as, PWAIT|PCATCH, "scsiopen", 0))
428 			return (error);
429 
430 	if (as->open) {
431 		if (as->tape)
432 			return (EBUSY);
433 
434 printf("as part %d ", dev_part(dev));
435 		if (as->have_label == 0 && dev_part (dev) != 3)
436 			return (ENXIO);
437 
438 		as->units_open |= 1 << dev_part (dev);
439 		return (0);
440 	}
441 
442 	as->open_lock = 1;
443 
444 	/* it seems like we might have to block here in case someone
445 	 * opens the device just after someone else closes
446 	 */
447 	while (as->scsi_lock)
448 		if (error = tsleep ((caddr_t)as, PWAIT|PCATCH, "scsicmd", 0))
449 			return (error);
450 
451 	as->scsi_lock = 1;
452 
453 	error = EIO;
454 
455 	as->have_label = 0;
456 	as->tape = 0;
457 	as->disk = 0;
458 	as->read_only = 0;
459 	as->removable = 0;
460 	memcpy(vendor, as->vendor, sizeof(vendor));
461 	memcpy(model, as->model, sizeof(model));
462 	as->vendor[0] = 0;
463 	as->model[0] = 0;
464 	as->revision[0] = 0;
465 
466 	bp = geteblk (DEV_BSIZE);
467 
468 	if (asverbose) {
469 		printf ("openbuf = 0x%x phys 0x%x\n",
470 			bp->b_un.b_addr, vtophys (bp->b_un.b_addr));
471 		printf ("mailboxes = 0x%x\n", mailboxes);
472 	}
473 
474 	/* first, find out if a device is present, and just what it is */
475 	as->scsi_cdb_len = 6;
476 	cdb = as->scsi_cdb;
477 	(void)memset (cdb, 0, 6);
478 	cdb[0] = 0x12; /* INQUIRY */
479 	cdb[4] = 255; /* allocation length */
480 	if (error = ascmd (as, bp, B_READ, DEV_BSIZE, 2))
481 		/* does not respond to inquiry, obviously not CCS, give up */
482 		goto done;
483 
484 
485 	/* blather on console about it */
486 	p = bp->b_un.b_addr;
487 	if (asverbose) {
488 		printf ("inquiry: ");
489 		for (n = 0; n < 20; n++)
490 			printf ("%x ", p[n] & 0xff);
491 		printf ("\n");
492 		for (n = 0; n < 40; n++) {
493 			if (p[n] >= ' ' && p[n] < 0177)
494 				printf ("%c", p[n]);
495 			else
496 				printf (".");
497 		}
498 		printf ("\n");
499 	}
500 
501 	switch (p[0]) {
502 	case 0: /* normal disk */
503 	case 4: /* write once disk */
504 		as->disk = 1;
505 		break;
506 	case 5: /* read only disk */
507 		as->read_only = 1;
508 		as->disk = 1;
509 		break;
510 	case 1: /* tape */
511 		as->tape = 1;
512 		break;
513 	case 0x7f:
514 		printf ("logical unit not present\n");
515 		goto done;
516 	default:
517 		printf ("unknown peripheral device type: 0x%x\n", p[0]);
518 		goto done;
519 	}
520 
521 	as->removable = (p[1] & 0x80) ? 1 : 0;
522 
523 	n = p[4] & 0xff;
524 	if (n >= 31) {
525 		asstring (as->vendor, p + 8, sizeof as->vendor);
526 		asstring (as->model, p + 16, sizeof as->model);
527 		asstring (as->revision, p + 32, sizeof as->revision);
528 	}
529 
530 	if(memcmp(as->vendor,vendor, sizeof(vendor)) != 0 ||
531 		memcmp(as->model,model, sizeof(model)) != 0) {
532 		printf("as: attached tgt %d <%s %s %s> ",
533 			dev_target(dev), as->vendor, as->model, as->revision);
534 		if (as->read_only) printf("readonly ");
535 		if (!as->removable) printf("winchester ");
536 		if (as->tape) printf("tape ");
537 		if (as->disk) printf("disk ");
538 		printf("(as%d)", (as->dev & 0xff) >> 3);
539 		printf("\n");
540 	}
541 
542 	/* probe for desired block size */
543 
544 	/* assume default of 512, except if CDROM (2048) */
545 	if (as->read_only)
546 		as->bs = 2048;
547 	else
548 		as->bs = 512;
549 
550 	(void)memset(cdb, 0, 6);
551 	cdb[0] = 0x1A;  /* SCSI_MDSENSE */
552 	cdb[4] = 255;
553 	if (as->tape && ascmd (as, bp, B_READ, 12, 2) == 0)  {
554 		int minblk, maxblk;
555 
556 #ifdef notdef
557 		/* blather about device more */
558 		if(memcmp(as->vendor,vendor, sizeof(vendor)) != 0 ||
559 			memcmp(as->model,model, sizeof(model)) != 0) {
560 			p = bp->b_un.b_addr;
561 			printf("as%d: data len %d medium %d speed/bufmode 0x%x desc len %d\n",
562 				dev_target(dev), p[0], p[1], p[2], p[3]);
563 			printf("as%d: density %d nblocks %d block len %d\n",
564 				dev_target(dev), p[4],
565 				(long)p[5]*65536+p[6]*256+p[7],
566 				(long)p[9]*65536+p[10]*256+p[11]);
567 		}
568 #endif
569 
570 		/* obtain possible block sizes */
571 		(void)memset(cdb, 0, 6);
572 		cdb[0] = 0x05; /* SCSI_RDLIMITS; */
573 		if (ascmd (as, bp, B_READ, 12, 2) == 0) {
574 			p = bp->b_un.b_addr;
575 			minblk = p[4]*256+p[5];
576 			maxblk = p[1]*65536+p[2]*256+p[3];
577 #ifdef notdef
578 			if(memcmp(as->vendor,vendor, sizeof(vendor)) != 0 ||
579 				memcmp(as->model,model, sizeof(model)) != 0) {
580 				printf("as%d: limits: min block len %ld  max block len %ld\n",
581 					dev_target(dev), minblk, maxblk);
582 			}
583 #endif
584 			if ( minblk == maxblk )
585 				as->bs = minblk;
586 			else if (as->tape)
587 				as->bs = 1;
588 		}
589 	}
590 
591 	if (as->tape &&  dev_part(dev)) {
592 		error = EIO;
593 		goto done;
594 	}
595 
596 	as->scsi_cdb_len = 10;
597 	(void)memset(cdb, 0, 10);
598 	cdb[0] = 0x25;  /* SCSI_READCAPACITY */
599 	disksize = 0;
600 	if (as->disk && ascmd (as, bp, B_READ, 12, 2) == 0)  {
601 		p = bp->b_un.b_addr;
602 		disksize = ntohl(*(long *)p);
603 		as->bs = ntohl(*(long *)(p+4));
604 
605 	}
606 
607 if(asverbose)
608 	printf("block size %d disksize %d ", as->bs, disksize);
609 
610 
611 	/* for standard disk, negotiate block size */
612 	if (as->read_only == 0 && as->disk) {
613 		/* do mode select to set the logical block size */
614 		as->scsi_cdb_len = 6;
615 		cdb = as->scsi_cdb;
616 		(void)memset(cdb, 0, 6);
617 		cdb[0] = 0x15; /* MODE SELECT */
618 		cdb[4] = 12; /* parameter list length */
619 
620 		p = bp->b_un.b_addr;
621 		(void)memset(p, 0, 12);
622 		p[3] = 8; /* block descriptor length */
623 		n = as->bs == 1 ? 0 : as->bs;
624 		p[9] = n >> 16;
625 		p[10] = n >> 8;
626 		p[11] = n;
627 
628 		(void) ascmd (as, bp, B_WRITE, 12, 2);
629 	}
630 
631 	/* device online and ready? */
632 	as->scsi_cdb_len = 6;
633 	(void)memset(cdb, 0, 6);
634 	cdb[0] = 0x00;  /* SCSI_UNITRDY */
635 	if (error = ascmd (as, bp, B_READ, 12, 2)) {
636 		printf("as%d: drive not online\n", dev_target(dev));
637 		goto done;
638 	}
639 
640 	if (as->disk && as->read_only == 0) {
641 		/* read disk label */
642 		(void)memset ((caddr_t)&as->label, 0, sizeof as->label);
643 		as->label.d_secsize = as->bs;
644 		as->label.d_secpercyl = 64*32;
645 		as->label.d_type = DTYPE_SCSI;
646 
647 
648 		/* read label using "d" partition */
649 		if ((p = readdisklabel (
650 			makeasdev (major (dev), dev_ctlr (dev), dev_target (dev), 3),
651 			asstrategy, &as->label, as->dospart, 0, 0)) == NULL){
652 			as->have_label = 1;
653 		} else {
654 			if (disksize) {
655 				as->label.d_subtype = DSTYPE_GEOMETRY;
656 				as->label.d_npartitions = 3;
657 				/* partition 0  holds bios, partition 1 ESDI */
658 				as->label.d_partitions[2].p_size = disksize;
659 				as->label.d_partitions[2].p_offset = 0;
660 			}
661 			if (asverbose || dev_part (dev) != 3)
662 				printf ("error reading label: %s\n", p);
663 			if (dev_part (dev) != 3) {
664 				error = EINVAL;
665 				goto done;
666 			}
667 		}
668 	}
669 
670 	/* may want to set logical block size here ? */
671 	error = 0;
672 
673  done:
674 	if (bp) {
675 		bp->b_flags |= B_INVAL | B_AGE;
676 		brelse (bp);
677 	}
678 
679 	if (error == 0) {
680 		as->open = 1;
681 		/* if more memory than adapter supports, allocate a bounce buf */
682 		if (physmem > (16*1024*1024/NBPG))
683 			as->bounce = kmem_alloc(kmem_map, 64*1024, 0);
684 		else
685 			as->bounce = 0;
686 	}
687 
688 	as->open_lock = 0;
689 	as->scsi_lock = 0;
690 	wakeup ((caddr_t)as);
691 
692 	return (error);
693 }
694 
695 static int
696 asclose(dev_t dev, int flag, int fmt, struct proc *pr)
697 {
698 	struct asinfo *as;
699 	int error = 0;
700 	unsigned char *cdb;
701 	struct buf *bp;
702 	int n;
703 
704 	as = dev_to_as(dev);
705 
706 	while (as->open_lock)
707 		if (error = tsleep ((caddr_t)as, PWAIT|PCATCH, "scsiclose", 0))
708 			return (error);
709 
710 	as->open_lock = 1;
711 
712 	if (as->tape) {
713 		while (as->scsi_lock)
714 			if (error = tsleep ((caddr_t)as, PWAIT|PCATCH,
715 					    "scsicmd", 0))
716 				return (error);
717 
718 		as->scsi_lock = 1;
719 
720 		bp = geteblk (DEV_BSIZE);
721 
722              if ((flag & FWRITE) != 0) {
723                              /* presume user will use tape again */
724                      as->scsi_cdb_len = 6;
725                      cdb = as->scsi_cdb;
726                      (void) memset (cdb, 0, 6);
727                      cdb[0] = 0x10; /* write filemarks */
728                      cdb[4] = 1; /* one of them */
729                      error = ascmd (as, bp, B_READ, 0, 1);
730              }
731              if (dev_rewind (dev) || error) {
732                      if ( error == 0 && (flag & FWRITE) != 0) {
733                                      /* presumption error correction */
734                              as->scsi_cdb_len = 6;
735                              cdb = as->scsi_cdb;
736                              (void) memset (cdb, 0, 6);
737                              cdb[0] = 0x10; /* write filemarks */
738                              cdb[4] = 1; /* one of them */
739                              error |= ascmd (as, bp, B_READ, 0, 1);
740                      }
741                      as->scsi_cdb_len = 6;
742                      cdb = as->scsi_cdb;
743                      (void) memset (cdb, 0, 6);
744                      cdb[0] = 0x1; /* rewind */
745                      cdb[1] = 1; /* don't wait until done */
746                      error |= ascmd (as, bp, B_READ, 0, 1);
747              }
748 #ifdef notdef
749 		} else {
750 			cdb[0] = 0x11; /* backspace */
751 			cdb[1] = 1; /* look at filemarks (instead of blocks) */
752 			n = -1;
753 			cdb[2] = n >> 16;
754 			cdb[3] = n >> 8;
755 			cdb[4] = n;
756 			error = ascmd (as, bp, B_READ, 0, 1);
757 		}
758 #endif
759 
760 		bp->b_flags |= B_INVAL | B_AGE;
761 		brelse (bp);
762 
763 		as->scsi_lock = 0;
764 	}
765 
766 	as->units_open &= ~(1 << dev_part (dev));
767 
768 	if (as->units_open == 0) {
769 		if (as->bounce)
770 			kmem_free(kmem_map, as->bounce, 64*1024);
771 		as->bounce = 0;
772 		as->open = 0;
773 	}
774 
775 	as->open_lock = 0;
776 
777 	wakeup ((caddr_t)as);
778 
779 	return (error);
780 }
781 
782 static int
783 asioctl(dev_t dev, int cmd, caddr_t addr, int flag, struct proc *p)
784 {
785 	struct scsicmd *cmdp;
786 	struct asinfo *as;
787 	int ccblen;
788 	struct buf *bp;
789 	int error = 0;
790 	int direction;
791 	struct disklabel *dl;
792 	int old_wlabel;
793 
794 	as = dev_to_as(dev);
795 
796 	switch (cmd) {
797 	case DIOCGDINFO:
798 		*(struct disklabel *)addr = as->label;
799 		break;
800 
801         case DIOCSDINFO:
802                 if ((flag & FWRITE) == 0) {
803                         error = EBADF;
804 			break;
805 		}
806 		dl = (struct disklabel *)addr;
807 		if (error = setdisklabel(&as->label, dl, 0, as->dospart))
808 			break;
809 		as->have_label = 1;
810                 break;
811 
812         case DIOCWLABEL:
813                 if ((flag & FWRITE) == 0) {
814                         error = EBADF;
815 			break;
816 		}
817 		as->wlabel = *(int *)addr;
818                 break;
819 
820         case DIOCWDINFO:
821                 if ((flag & FWRITE) == 0) {
822                         error = EBADF;
823 			break;
824 		}
825 
826 		dl = (struct disklabel *)addr;
827 
828 		if (error = setdisklabel (&as->label, dl, 0, as->dospart))
829 			break;
830 
831 		as->have_label = 1;
832 
833 		old_wlabel = as->wlabel;
834 		as->wlabel = 1;
835 		error = writedisklabel(dev, asstrategy, &as->label,
836 				as->dospart);
837 		as->wlabel = old_wlabel;
838                 break;
839 
840 	case SCSICMD:
841 		cmdp = (struct scsicmd *)addr;
842 
843 		/* limited by max sizeof of geteblk */
844 		if (cmdp->datalen >= 8192
845 		    || cmdp->cdblen >= MAXCDB) {
846 			error = EINVAL;
847 			break;
848 		}
849 
850 		ccblen = cmdp->ccblen;
851 		if (ccblen > sizeof (struct ccb))
852 			ccblen = sizeof (struct ccb);
853 
854 		while (as->scsi_lock)
855 			if (error = tsleep ((caddr_t)as, PWAIT|PCATCH,
856 					    "scsicmd", 0))
857 				break;
858 
859 		as->scsi_lock = 1;
860 
861 		bp = geteblk (cmdp->datalen);
862 
863 		as->scsi_cdb_len = cmdp->cdblen;
864 		if (error = copyin (curproc, cmdp->cdb, as->scsi_cdb, cmdp->cdblen))
865 			goto done;
866 
867 		direction = cmdp->readflag ? B_READ : B_WRITE;
868 
869 		if (direction == B_WRITE)
870 			if (error = copyin (curproc, cmdp->data,
871 					    bp->b_un.b_addr, cmdp->datalen))
872 				goto done;
873 
874 		ascmd (as, bp, direction, cmdp->datalen, 1);
875 
876 		copyout (curproc, &as->ccb, cmdp->ccb, ccblen);
877 		if (direction == B_READ)
878 			copyout (curproc, bp->b_un.b_addr, cmdp->data, cmdp->datalen);
879 	done:
880 		bp->b_flags |= B_INVAL | B_AGE;
881 		brelse (bp);
882 		as->scsi_lock = 0;
883 		wakeup ((caddr_t)as);
884 		break;
885 	default:
886 		error = ENOTTY;
887 		break;
888 	}
889 	return (error);
890 }
891 
892 static int
893 asstrategy (bp)
894 struct buf *bp;
895 {
896 	struct asinfo *as;
897 	int s;
898 
899 	if (asverbose)
900 		printf ("asstrategy %d %d ", bp->b_blkno, bp->b_bcount);
901 	s = splbio ();
902 
903 	as = dev_to_as (bp->b_dev);
904 
905 	if (as->tape) {
906 		bp->av_forw = NULL;
907 		if (as->requests.b_actf)
908 			as->requests.b_actl->av_forw = bp;
909 		else
910 			as->requests.b_actf = bp;
911 		as->requests.b_actl = bp;
912 	} else {
913 		if (bp != as->scsi_bp
914 		    && as->have_label == 0
915 		    && dev_part (bp->b_dev) != 3)
916 			goto bad;
917 
918 		bp->b_cylin = bp->b_blkno;
919 		disksort (&as->requests, bp);
920 	}
921 
922 	if (as->active == 0)
923 		asstart (as);
924 
925 	splx (s);
926 	return;
927 
928  bad:
929 	bp->b_flags |= B_ERROR;
930 	biodone (bp);
931 	splx (s);
932 }
933 static
934 asrestart (as)
935 struct asinfo *as;
936 {
937 	int s;
938 	s = splbio ();
939 	as->restart_pending = 0;
940 	as->retry_count++;
941 	asstart (as);
942 	splx (s);
943 }
944 static
945 asstart (as)
946 struct asinfo *as;
947 {
948 	struct buf *bp;
949 	int blknum;
950 	unsigned int physaddr, p2;
951 	struct ccb *ccb;
952 	unsigned char *cdb;
953 	int target;
954 	char *p, *nnext;
955 	int n;
956 	char *sp;
957 	int nscatter;
958 	int thistime;
959 	int nbytes;
960 	struct partition *part;
961 	int blkno;
962 	int nblocks;
963 	int total;
964 	int bs = as->bs;
965 
966 
967 	if (as->restart_pending) {
968 		as->restart_pending = 0;
969 		untimeout (asrestart, (caddr_t)as);
970 	}
971 
972  again:
973 	if ((bp = as->requests.b_actf) == NULL)
974 		return;
975 
976 	bp->b_error = 0;
977 
978 	if (asverbose)
979 		printf ("asstart %x ", bp);
980 
981 	if (as->mailbox->cmd != 0) {
982 		/* this can't happen, unless the card flakes */
983 		printf ("asstart: mailbox not available\n");
984 		bp->b_error = EIO;
985 		goto bad;
986 	}
987 
988 	if (as->isbounced == 0)
989 		bp->b_resid = 0;
990 
991 	if (as->retry_count == 0) {
992 		as->start_time = time.tv_sec;
993 	} else {
994 		if (time.tv_sec - as->start_time > 60) {
995 			printf ("as: command timed out\n");
996 			bp->b_error = EIO;
997 			goto done;
998 		}
999 	}
1000 
1001 	if (bp != as->scsi_bp) {
1002 		if (bp->b_bcount == 0)
1003 			goto done;
1004 
1005 		if ((bp->b_bcount % bs) != 0) {
1006 			printf("as: partial block read\n");
1007 			bp->b_error = EIO;
1008 			goto bad;
1009 		}
1010 	}
1011 
1012 	if (bp != as->scsi_bp) {
1013 		nblocks = aspartition(as, bp, &blkno);
1014 		if (nblocks < 0)
1015 			goto bad;
1016 		if (nblocks == 0)
1017 			goto done;
1018 		total = nblocks * bs;
1019 if(asverbose)
1020 printf("total %d nblocks %d ", total, nblocks);
1021 	} else
1022 		total = bp->b_bcount;
1023 
1024 	nscatter = asmakescatter(as, bp, 0);
1025 
1026 	if (nscatter > NSCATTER) {
1027 		printf("out of range, cannot happen?");
1028 		bp->b_error = ENXIO;
1029 		goto bad;
1030 	}
1031 
1032 
1033 	asmakeccb(as, nscatter, bp->b_dev, bp->b_bcount, bp->b_flags & B_READ);
1034 
1035 	ccb = &as->ccb;
1036 	cdb = ccb->ccb_cdb;
1037 	if (bp == as->scsi_bp) {
1038 		ccb->ccb_scsi_command_len = as->scsi_cdb_len;
1039 		(void) memcpy(cdb, as->scsi_cdb, as->scsi_cdb_len);
1040 	}
1041 	else
1042 		asmakecdb(as, blkno, bp->b_bcount,
1043 		    bp->b_flags & B_READ);
1044 
1045  	/* write back cache contents */
1046  	/*if ((bp->b_flags & B_READ) == 0)
1047  		asm (".byte 0x0f,0x09 # wbinvd");	*/
1048 
1049 	asissue(as);
1050 	timeout (asabort, (caddr_t)as, hz * 60 * 2);
1051 	return;
1052 
1053  bad:
1054 	bp->b_flags |= B_ERROR;
1055  done:
1056 	asdone (as, 0);
1057 	goto again;
1058 }
1059 
1060 static
1061 asabort (as)
1062 struct asinfo *as;
1063 {
1064 	int s;
1065 	int physaddr;
1066 	struct buf *bp;
1067 
1068 	s = splbio ();
1069 	if (as->active) {
1070 		printf ("asabort %d\n", as - asinfo);
1071 		physaddr = vtophys (&as->ccb);
1072 		as->mailbox->msb = physaddr >> 16;
1073 		as->mailbox->mid = physaddr >> 8;
1074 		as->mailbox->lsb = physaddr;
1075 		as->mailbox->cmd = 2;
1076 		as_put_byte (as_port[dev_ctlr(as->dev)], AS_CMD_START_SCSI_COMMAND);
1077 
1078 		as->active = 0;
1079 		bp = as->requests.b_actf;
1080 		if (bp) {
1081 			bp->b_flags |= B_ERROR;
1082 			asdone (as, 1);
1083 		}
1084 	}
1085 	splx (s);
1086 }
1087 static
1088 asintr (int ctl /* dev_t dev*/)
1089 {
1090 	int didwork;
1091 	int i, j;
1092 	struct mailbox_entry *mp;
1093 	unsigned int physaddr;
1094 	int val;
1095 	struct asinfo *as;
1096 
1097 	outb (as_port[ctl /*dev_ctlr(dev)*/] + AS_CONTROL, AS_CONTROL_IRST);
1098 	if (asverbose)
1099 		printf ("asintr %x ", ctl /*dev*/);
1100  again:
1101 	didwork = 0;
1102 	if (as = asscan((ctl <<6) /*dev*/)) {
1103 		asintr1(as, as->mbi_status);
1104 		didwork = 1;
1105 	}
1106 
1107 	if (didwork)
1108 		goto again;
1109 }
1110 static
1111 asintr1 (as, val)
1112 struct asinfo *as;
1113 int val;
1114 {
1115 	struct buf *bp;
1116 	struct ccb *ccb;
1117 	int n;
1118 	int bad;
1119 	char *msg;
1120 	char msgbuf[100];
1121 	unsigned char *sp;
1122 	int i, key;
1123 	int resid;
1124 
1125 	if (asverbose)
1126 		printf ("asintr1 %x ", val);
1127 	if (as->active == 0) {
1128 		printf ("as: stray intr 0x%x\n", as->dev);
1129 		return;
1130 	}
1131 
1132 	as->active = 0;
1133 	key = 0;
1134 	untimeout (asabort, (caddr_t)as);
1135 
1136 	bp = as->requests.b_actf;
1137 	ccb = &as->ccb;
1138 
1139 	if (bp == as->scsi_bp) {
1140 		/* no fancy error recovery in this case */
1141 		if (asverbose)
1142 			printf ("asintr1:scsicmd ");
1143 #if 0
1144 		if (val != 1)
1145 			bp->b_flags |= B_ERROR;
1146 		goto next;
1147 #endif
1148 	}
1149 
1150 	bad = 0;
1151 	msg = NULL;
1152 	bp->b_error = 0;
1153 
1154 	if (val != 1 && val != 4) {
1155 		bad = 1;
1156 		bp->b_error = EIO;
1157 		sprintf (msgbuf, "funny mailbox message 0x%x\n", val);
1158 		msg = msgbuf;
1159 		goto wrapup;
1160 	}
1161 
1162 	if (ccb->ccb_host_status != 0) {
1163 		bad = 1;
1164 		/* selection timeout */
1165 		if (ccb->ccb_host_status == 0x11) {
1166 			bp->b_error = ENXIO;
1167 		} else {
1168 			sprintf (msgbuf, "controller error 0x%x",
1169 				ccb->ccb_host_status);
1170 			bp->b_error = EIO;
1171 		}
1172 		msg = msgbuf;
1173 		goto wrapup;
1174 	}
1175 
1176 	if (ccb->ccb_target_status == 0)
1177 		/* good transfer */
1178 		goto wrapup;
1179 
1180 	if (ccb->ccb_target_status == 8) {
1181 		/* target rejected command because it is busy
1182 		 * and wants us to try again later.  We'll wait 1 second
1183 		 */
1184 		as->restart_pending = 1;
1185 		timeout (asrestart, (caddr_t)as, hz);
1186 		return;
1187 	}
1188 
1189 	if (ccb->ccb_target_status != 2) {
1190 		bad = 1;
1191 		bp->b_error = EIO;
1192 		sprintf (msgbuf, "target error 0x%x",
1193 			 ccb->ccb_target_status);
1194 		msg = msgbuf;
1195 		goto wrapup;
1196 	}
1197 
1198 	/* normal path for errors */
1199 
1200 	sp = ccb_sense (ccb);
1201 	/* check for extended sense information */
1202 	if ((sp[0] & 0x7f) != 0x70) {
1203 		/* none */
1204 		bad = 1;
1205 		bp->b_error = EIO;
1206 		sprintf (msgbuf, "scsi error 0x%x", sp[0] & 0x7f);
1207 		msg = msgbuf;
1208 		goto wrapup;
1209 	}
1210 
1211 	if (as->tape && (sp[2] & 0xf) == 0) {
1212 		if (sp[2] & 0xe0) {
1213 			/* either we read a file mark, the early warning EOT,
1214 			 * or the block size did not match.  In any case, the
1215 			 * normal residue handling will work (I think)
1216 			 */
1217 			goto wrapup;
1218 		}
1219 	}
1220 
1221 	bad = 1;
1222 
1223 	switch (key = sp[2] & 0xf) {
1224 	case 1:
1225 		msg = "soft error";
1226 		bad = 0;
1227 		break;
1228 	case 2:
1229 		msg = "not ready";
1230 		break;
1231 	case 3:
1232 		msg = "hard error";
1233 		break;
1234 	case 4:
1235 		msg = "target hardware error";
1236 		break;
1237 	case 5:
1238 		msg = "illegal request";
1239 		break;
1240 	case 6:
1241 		msg = "unit attention error";
1242 		break;
1243 	case 7:
1244 		msg = "write protect error";
1245 		break;
1246 	case 0xd:
1247 		msg = "volume overflow";
1248 		break;
1249 	default:
1250 		sprintf (msgbuf, "scsi extended error 0x%x", sp[2] & 0xf);
1251 		msg = msgbuf;
1252 		break;
1253 	}
1254 
1255  wrapup:
1256 	/* unit attention? */
1257 	if (key == 6) {
1258 		asstart (as);
1259 		return;
1260 	}
1261 
1262 	if (bad && msg == NULL)
1263 		msg = "unknown error";
1264 
1265 	if (msg && key != 6 && bp->b_error != ENXIO) {
1266 		diskerr (bp, "as", msg,
1267 			 LOG_PRINTF,
1268 			 -1, /* number of successful blks */
1269 			 as->have_label ? &as->label : NULL);
1270 		printf ("\n");
1271 	}
1272 
1273 	if (bad && key != 6 && bp->b_error != ENXIO) {
1274 		bp->b_flags |= B_ERROR;
1275 		printf ("scsi sense: ");
1276 		sp = ccb_sense (ccb);
1277 		for (i = 0; i < 30; i++)
1278 			printf ("%x ", sp[i] & 0xff);
1279 		printf ("\n");
1280 	}
1281 
1282 	/*resid = (ccb->ccb_data_len_msb << 16)
1283 		| (ccb->ccb_data_len_mid << 8)
1284 			| ccb->ccb_data_len_lsb;*/
1285 resid = 0;
1286 
1287  	/* flush cache if read */
1288  	/*if ((bp->b_flags & B_READ) != 0)
1289  		asm (".byte 0x0f,0x08 # invd");	*/
1290 
1291 	if (bad == 0 && as->isbounced && (bp->b_flags & B_READ) != 0) {
1292 		memcpy(bp->b_un.b_addr, (char *)as->bounce, bp->b_bcount - resid);
1293 		/* as->isbounced = 0;*/
1294 	}
1295 
1296 	bp->b_resid += resid;
1297 	if (bp != as->scsi_bp && bp->b_resid != 0)
1298 		printf ("scsi resid = %d\n", bp->b_resid);
1299 
1300  next:
1301 	asdone (as, 1);
1302 }
1303 static
1304 asdone (as, restart)
1305 struct asinfo *as;
1306 int restart;
1307 {
1308 	struct buf *bp;
1309 
1310 	bp = as->requests.b_actf;
1311 	as->requests.b_actf = bp->av_forw;
1312 	biodone (bp);
1313 	as->retry_count = 0;
1314 	if (restart && as->requests.b_actf)
1315 		asstart (as);
1316 }
1317 
1318 static int
1319 assize (dev_t dev)
1320 {
1321 	struct asinfo *as;
1322 	struct disklabel *lp;
1323 	int val, ctl;
1324 
1325 	ctl = dev_ctlr(dev);
1326 	if (ctl > NAS || as_port[ctl] == 0 || dev_target (dev) > NTARGETS)
1327 		return (ENXIO);
1328 
1329 	as = dev_to_as (dev);
1330 	if (as->open == 0
1331 	    && asopen (dev, FREAD, S_IFBLK, NULL) != 0)
1332 		return (0);
1333 
1334 	if (as->have_label == 0)
1335 		return (0);
1336 
1337 	lp = &as->label;
1338 	val = lp->d_partitions[dev_part (dev)].p_size
1339 		* lp->d_secsize / DEV_BSIZE;
1340 
1341 	/* XXX hold open: (void) asclose(dev, FREAD, S_IFBLK, NULL); */
1342 	return (val);
1343 }
1344 
1345 static void
1346 asmakeccb(struct asinfo *as, int nscatter, dev_t dev, int count, int dir)
1347 {
1348 	struct ccb *ccb = &as->ccb;
1349 	int target = dev_target (dev);
1350 	int nbytes;
1351 	unsigned int physaddr;
1352 
1353 	/* this only needed to make debugging easier */
1354 	(void) memset ((caddr_t)ccb, 0, sizeof *ccb);
1355 
1356 	if (nscatter) {
1357 		ccb->ccb_opcode = 2; /* scatter cmd, return resid */
1358 		nbytes = nscatter * 6;
1359 		physaddr = vtophys (as->scatter_list);
1360 	} else {
1361 		ccb->ccb_opcode = 0;
1362 		nbytes = count;
1363 		physaddr = 0;
1364 	}
1365 
1366 	ccb->ccb_addr_and_control = target << 5;
1367 	if (count != 0)
1368 		ccb->ccb_addr_and_control |= (dir == B_READ) ? 8 : 0x10;
1369 	else
1370 		ccb->ccb_addr_and_control |= 0x18;
1371 
1372 	ccb->ccb_data_len_msb = nbytes >> 16;
1373 	ccb->ccb_data_len_mid = nbytes >> 8;
1374 	ccb->ccb_data_len_lsb = nbytes;
1375 
1376 	ccb->ccb_requst_sense_allocation_len = MAXSENSE;
1377 
1378 	ccb->ccb_data_ptr_msb = physaddr >> 16;
1379 	ccb->ccb_data_ptr_mid = physaddr >> 8;
1380 	ccb->ccb_data_ptr_lsb = physaddr;
1381 
1382 	ccb->ccb_link_msb = 0;
1383 	ccb->ccb_link_mid = 0;
1384 	ccb->ccb_link_lsb = 0;
1385 	ccb->ccb_link_id = 0;
1386 	ccb->ccb_host_status = 0;
1387 	ccb->ccb_target_status = 0;
1388 	ccb->ccb_zero1 = 0;
1389 	ccb->ccb_zero2 = 0;
1390 }
1391 
1392 static void
1393 asmakecdb(struct asinfo *as, int blkno, int count, int dir)
1394 {
1395 	struct ccb *ccb = &as->ccb;
1396 	unsigned char *cdb;
1397 	int nblocks = howmany(count, as->bs);
1398 
1399 	cdb = ccb->ccb_cdb;
1400 	if (as->tape) {
1401 		ccb->ccb_scsi_command_len = 6;
1402 		cdb[0] = (dir == B_READ) ? 8 : 0xa;
1403 		if (as->bs == 1)
1404 			cdb[1] = 0; /* logical unit 0, variable block size */
1405 		else
1406 			cdb[1] = 1; /* fixed block size */
1407 		cdb[2] = nblocks >> 16;
1408 		cdb[3] = nblocks >> 8;
1409 		cdb[4] = nblocks;
1410 		cdb[5] = 0; /* control byte (used in linking) */
1411 	} else {
1412 		ccb->ccb_scsi_command_len = 10;
1413 		cdb[0] = (dir == B_READ) ? 0x28 : 0x2a;
1414 		cdb[1] = 0;
1415 		*(long *) (cdb+2) = htonl(blkno);
1416 		*(short *) (cdb+7) = htons(nblocks);
1417 		cdb[9] = 0; /* control byte (used in linking) */
1418 	}
1419 }
1420 
1421 static void
1422 asissue(struct asinfo *as) {
1423 	struct ccb *ccb = &as->ccb;
1424 	int n;
1425 	unsigned int physaddr /*= vtophys (ccb);*/;
1426 
1427 	physaddr = vtophys (ccb);
1428 	if (asverbose) {
1429 		printf ("ccb: ");
1430 		for (n = 0; n < 48; n++)
1431 			printf ("%02x ", ((unsigned char *)ccb)[n]);
1432 		printf ("\n");
1433 	}
1434 
1435 	as->mailbox->msb = physaddr >> 16;
1436 	as->mailbox->mid = physaddr >> 8;
1437 	as->mailbox->lsb = physaddr;
1438 	as->mailbox->cmd = 1;
1439 
1440 	/* tell controller to look in its mailbox */
1441 	as_put_byte (as_port[dev_ctlr(as->dev)], AS_CMD_START_SCSI_COMMAND);
1442 	as->active = 1;
1443 }
1444 
1445 static struct asinfo *
1446 asscan (dev_t dev)
1447 {
1448 	int i, j;
1449 	struct mailbox_entry *mp;
1450 	unsigned int physaddr;
1451 	int val, ctl = dev_ctlr(dev);
1452 
1453 	outb (as_port[ctl] + AS_CONTROL, AS_CONTROL_IRST);
1454 
1455 	ctl *= NTARGETS;
1456 	for (i = NTARGETS; i < NTARGETS * 2; i++) {
1457 		mp = &mailboxes[ctl + i];
1458 
1459 		if ((val = mp->cmd) == 0)
1460 			continue;
1461 
1462 		physaddr = (mp->msb << 16)
1463 			| (mp->mid << 8)
1464 				| mp->lsb;
1465 
1466 		for (j = 0; j < NTARGETS; j++) {
1467 			if (asinfo[ctl + j].ccb_phys == physaddr) {
1468 				mp->cmd = 0;
1469 				(asinfo + ctl + j) ->mbi_status = val;
1470 				return (asinfo + ctl + j);
1471 			}
1472 		}
1473 		if (j == NTARGETS) {
1474 			printf ("as: unknown mailbox paddr 0x%x\n", physaddr);
1475 			mp->cmd = 0;
1476 		}
1477 	}
1478 	return (0);
1479 }
1480 
1481 static int
1482 as_put_byte (port, val)
1483 int val;
1484 {
1485 	int i, sts, intr;
1486 
1487 	for (i = 10000; i > 0; i--) {
1488 		sts = inb (port + AS_STATUS);
1489 		intr = inb (port + AS_INTR);
1490 		if ((sts & AS_STATUS_CDF) == 0)
1491 			break;
1492 		DELAY (1000);
1493 	}
1494 
1495 	/* time out? */
1496 	if (i == 0) {
1497 		printf ("as: put byte timed out %x %x", sts, intr);
1498 		goto fail;
1499 	}
1500 
1501 	if ((intr & AS_INTR_HACC) && (sts & AS_STATUS_INVDCMD)) {
1502 		printf ("as: put byte invalid command %x %x", sts, intr);
1503 	fail:
1504 		outb (port + AS_CONTROL, AS_CONTROL_IRST);
1505 		return (-1);
1506 	}
1507 
1508 	outb (port + AS_DATA_OUT, val);
1509 	return (0);
1510 }
1511 
1512 static int
1513 asmakescatter(struct asinfo *as, struct buf *bp, int phys)
1514 {
1515 	int n;
1516 	char *sp;
1517 	int nscatter;
1518 	int thistime;
1519 	unsigned int physaddr, p2;
1520 	int total;
1521 	char *p = bp->b_un.b_addr;
1522 
1523 	/* restrict transfer to maximum controller can handle */
1524 	if (bp->b_bcount > (16*1024*1024 - as->bs)) {
1525 		int	amt = 16*1024*1024 - as->bs;
1526 		bp->b_resid  += bp->b_bcount - amt;
1527 		bp->b_bcount -= bp->b_bcount - amt;
1528 	}
1529 
1530 	if (bp != as->scsi_bp && as->bs)
1531 		total =  roundup(bp->b_bcount, as->bs);
1532 	else
1533 		total =  bp->b_bcount;
1534 
1535 redo:
1536 	if (asverbose)
1537 		printf("%d bytes from %x: ", total, p);
1538 
1539 	/* generate scatter list */
1540 	n = 0;
1541 	sp = as->scatter_list;
1542 	nscatter = 0;
1543 	while (n < total && nscatter < NSCATTER) {
1544 
1545 		/* physical or virtual */
1546 		if (phys) {
1547 			physaddr = (unsigned int) p;
1548 			thistime = 16*1024*1024 - (int)p;
1549 		} else {
1550 			thistime = page_size - ((vm_offset_t)p - trunc_page (p));
1551 			physaddr = vtophys (p);
1552 		}
1553 		if (n + thistime > total)
1554 			thistime = total - n;
1555 
1556 		/* if any page is outside of ISA bus address space, bounce */
1557 		if (physaddr >= 16*1024*1024) {
1558 			/* no buffer? */
1559 			if (as->bounce == 0)
1560 	    			panic(
1561 "as: i/o outside of bus address space and no buffer");
1562 			/* if (asverbose) */
1563 				printf ("as: bounce transfer ");
1564 
1565 			/* truncate to max size, */
1566 			if (total > 64*1024) {
1567 				bp->b_resid +=  bp->b_bcount - 64*1024;
1568 				total = 64*1024;
1569 				bp->b_bcount = 64*1024;
1570 			}
1571 
1572 			/* if a write, load bounce buffer */
1573 			if ((bp->b_flags & B_READ) == 0) {
1574 
1575 				if (asverbose)
1576 					printf("load bounce: ");
1577 				/* if physical dump, map VA == PA */
1578 				/* XXX should reserve address space on boot for this */
1579 				if (phys) {
1580 					pmap_map((vm_offset_t)dumpISA,
1581 					    trunc_page((vm_offset_t)bp->b_un.b_addr),
1582 					    round_page((vm_offset_t)bp->b_un.b_addr + total),
1583 					    VM_PROT_ALL);
1584 				memcpy((char *)as->bounce,
1585 				    dumpISA + ((int)bp->b_un.b_addr & (NBPG-1)),
1586 				    bp->b_bcount);
1587 				} else
1588 				memcpy((char *)as->bounce, bp->b_un.b_addr,
1589 				    bp->b_bcount);
1590 			}
1591 
1592 			/* if a read, bounce buffer will be unloaded after transfer */
1593 			as->isbounced = 1;
1594 			p = (char *)as->bounce;
1595 			phys = 0;
1596 			goto redo;
1597 		}
1598 		else
1599 			as->isbounced = 0;
1600 
1601 		/*
1602 		 * Do we have a run of consecutive pages?
1603 		 */
1604 		if (phys == 0) {
1605 			/* check for consecutive physical pages */
1606 			p2 = physaddr;
1607 			for (; n + thistime < total ;) {
1608 				if (trunc_page(p2) + page_size !=
1609 			    	    trunc_page(vtophys(p + thistime)))
1610 					break;
1611 				p2 = vtophys(p + thistime);
1612 				if (p2 >= 16*1024*1024)
1613 					break;
1614 				thistime += page_size;
1615 				if (n + thistime > total) {
1616 					thistime = total - n;
1617 					break;
1618 				}
1619 			}
1620 		}
1621 
1622 		if (asverbose)
1623 			printf ("%d bytes to %x (%x) ", thistime, p, physaddr);
1624 		sp[0] = thistime >> 16;
1625 		sp[1] = thistime >> 8;
1626 		sp[2] = thistime;
1627 		sp[3] = physaddr >> 16;
1628 		sp[4] = physaddr >> 8;
1629 		sp[5] = physaddr;
1630 
1631 		p += thistime;
1632 		n += thistime;
1633 		sp += 6;
1634 		nscatter++;
1635 
1636 		/* only one segment allowed for a phys transfer */
1637 		if (phys && bp->b_bcount > n) {
1638 			bp->b_resid  += bp->b_bcount - n;
1639 			bp->b_bcount -= bp->b_bcount - n;
1640 			if (asverbose)
1641 				printf("restricted to %d bytes: ",
1642 					bp->b_bcount);
1643 			break;
1644 		}
1645 	}
1646 
1647 	return (nscatter);
1648 }
1649 
1650 static int
1651 aspartition(struct asinfo *as, struct buf *bp, int *blknop)
1652 {
1653 	int blkno = bp->b_blkno;
1654 	int nblocks = bp->b_bcount / as->bs;
1655 	struct partition *part;
1656 
1657 	if (as->have_label && dev_part(bp->b_dev) != 3) {
1658 		part = &as->label.d_partitions[dev_part(bp->b_dev)];
1659 
1660 		if (blkno > part->p_size) {
1661 			bp->b_error = EINVAL;
1662 			return (-1);
1663 		}
1664 		if (blkno == part->p_size) {
1665 			bp->b_resid += bp->b_bcount;
1666 			return (0);
1667 		}
1668 
1669 		if (blkno + nblocks > part->p_size) {
1670 			int remaining = part->p_size - blkno;
1671 			/* nblocks = part->p_size - blkno; */
1672 			bp->b_resid += as->bs * (nblocks - remaining);
1673 			bp->b_bcount -= as->bs * (nblocks - remaining);
1674 			nblocks = remaining;
1675 		}
1676 
1677 		blkno += part->p_offset;
1678 	} else if (as->bs != 1)
1679 		blkno = (blkno * DEV_BSIZE)/as->bs;
1680 	if (asverbose)
1681 		printf("trans %d ", blkno);
1682 	*blknop = blkno;
1683 	return (nblocks);
1684 }
1685 
1686 static int
1687 as_get_byte (port)
1688 {
1689 	int i;
1690 
1691 	while ((inb (port + AS_STATUS) & AS_STATUS_DF) == 0)
1692 		DELAY (100);
1693 	return (inb (port + AS_DATA_OUT) & 0xff);
1694 }
1695 
1696 static int
1697 asdump(dev_t dev)			/* dump core after a system crash */
1698 {
1699 	struct asinfo *as;
1700 	long	num;			/* number of sectors to write */
1701 	int	ctl, unit, part, asc;
1702 	int	blkoff, blknum, blkcnt;
1703 	long	nblocks, i;
1704 	extern	int maxmem;
1705 	static  int asdoingadump = 0 ;
1706 	struct buf buf;
1707 	char *sp;
1708 	int nscatter;
1709 
1710 
1711 	/* toss any characters present prior to dump */
1712 	while (sgetc(1))
1713 		;
1714 
1715 	/* size of memory to dump */
1716 	num = maxmem;
1717 	ctl = dev_ctlr(dev);
1718 	unit = dev_target(dev);
1719 	part = dev_part(dev);		/* file system */
1720 
1721 	/* check for acceptable controller number */
1722 	if (ctl > NAS)
1723 		return(ENXIO);
1724 
1725 	/* check for acceptable drive number */
1726 	if (unit > NTARGETS)
1727 		return(ENXIO);
1728 
1729 	as = dev_to_as(dev);
1730 	if (as_port[ctl] == 0) return(ENXIO);
1731 
1732 	/* check if controller active */
1733 	/*if (astab.b_active) return(EFAULT); */
1734 	if (asdoingadump) return(EFAULT);
1735 
1736 	/* create a buffer */
1737 	buf.b_flags = B_WRITE;
1738 	buf.b_dev = dev;
1739 	buf.b_blkno = dumplo;
1740 	buf.b_bcount = maxmem * NBPG;
1741 	buf.b_un.b_addr = 0;
1742 	buf.b_resid = 0;
1743 
1744 	for (;;) {
1745 	nblocks = aspartition(as, &buf, &blknum);
1746 
1747 /*printf("blkno %d, nblocks %d, dumplo %d num %d\n",
1748 blknum, nblocks,dumplo,num); */
1749 
1750 	/* check transfer bounds against partition size */
1751 	/*if ((dumplo < 0) || ((dumplo + num) > nblocks))
1752 		return(EINVAL);*/
1753 
1754 	/*astab.b_active = 1;		/* mark controller active for if we
1755 					   panic during the dump */
1756 	/* transfer in progress */
1757 	while(as->active)
1758 		asscan(dev);
1759 	/* otherwise, asabort() */
1760 	asdoingadump = 1;
1761 
1762 	nscatter = asmakescatter(as, &buf, 1);
1763 /*printf("nscat %d addr %x count %d resid %d\n", nscatter,
1764 	buf.b_un.b_addr, buf.b_bcount, buf.b_resid);*/
1765 
1766 	/* build a ccb */
1767 	asmakeccb(as, nscatter, dev, buf.b_bcount, B_WRITE);
1768 	asmakecdb(as, blknum, buf.b_bcount, B_WRITE);
1769 /*printf("blk %d sz %d count %d resid %d\n", blknum, nblocks,
1770 	buf.b_bcount, buf.b_resid); */
1771 	asissue(as);
1772 	while(as->active)
1773 		if (as == asscan(0))
1774 			as->active = 0;
1775 	if (buf.b_resid == 0)
1776 		break;
1777 	buf.b_un.b_addr += buf.b_bcount;
1778 	buf.b_blkno += buf.b_bcount / 512;
1779 	buf.b_bcount = buf.b_resid;
1780 	buf.b_resid = 0;
1781 	}
1782 	printf("done");
1783 DELAY(10000000);
1784 	return(0);
1785 }
1786 
1787 struct devif as_devif =
1788 {
1789 	{0}, -1, -1, 0x38, 3, 7, 0, 0, 0,
1790 	asopen,	asclose, asioctl, 0, 0, 0, 0,
1791 	asstrategy,	0, asdump, assize,
1792 };
1793 
1794 /*static struct bdevsw as_bdevsw =
1795 	{ asopen,	asclose,	asstrategy,	asioctl,
1796 	  asdump,	assize,		NULL };
1797 
1798 void mkraw(struct bdevsw *bdp, struct cdevsw *cdp);*/
1799 
1800 DRIVER_MODCONFIG() {
1801 	int vec[3], nvec = 3, nctl;	/* (bdev, cdev, nctl) */
1802 	char *cfg_string = as_config;
1803 #ifdef foo
1804 	struct cdevsw as_cdevsw;
1805 
1806 	vec[2] = 1;	/* by default, one controller */
1807 	if (!config_scan(as_config, &cfg_string))
1808 		return /*(EINVAL)*/;
1809 
1810 	/* no more controllers than 2 */
1811 	if (vec[2] > 2)
1812 		vec[2] = 2;
1813 
1814 	/*bdevsw[vec[0]] = as_bdevsw;
1815 	mkraw(&as_bdevsw, &as_cdevsw);
1816 	cdevsw[vec[1]] = as_cdevsw; */
1817 
1818 	if (!spec_config(&cfg_string, &as_bdevsw, (struct cdevsw *) -1, 0))
1819 		return;
1820 #else
1821 	if (devif_config(&cfg_string, &as_devif) == 0)
1822 		return;
1823 #endif
1824 
1825 	(void)cfg_number(&cfg_string, &nctl);
1826 	/* malloc(vec[2]*controllerresources) ... */
1827 
1828 	new_isa_configure(&cfg_string, &asdriver);
1829 
1830 	/*return (0);*/
1831 }
1832