This commit was generated by cvs2svn to track changes on a CVS vendor
[unix-history] / sys / i386 / isa / as.c
CommitLineData
15637ed4
RG
1/*
2 * Adaptech 1542 SCSI driver for 386bsd
3 *
4 * Pace Willisson pace@blitz.com March 28, 1992
5 *
6 * Placed in the public domain with NO WARRANTIES, not even the
7 * implied warranties for MERCHANTABILITY or FITNESS FOR A
8 * PARTICULAR PURPOSE.
9 *
10 *
11 * This is a very early version - use with care.
12 *
13 * Here is the config info:
14 *
15 * controller as0 at isa? port 0x330 bio irq 11 drq 5 vector asintr
16 * disk dk6 at as0 drive 0
17 *
18 * Also, don't forget to update sys/i386/conf/files.i386.
19 *
20 * So far, used with:
21 *
22 * CDC WREN 5 600 Megabyte magnetic disk
23 * EXABYTE EXB-8200 8mm tape drive
24 * SONY CDU-541 cdrom
25 *
26 * The the tape stuff still needs a lot of working concerning
27 * file marks, end of tape handling and rewinding, but I have
28 * extracted tar tapes to a file system mounted on the CDC disk.
29 *
30 * minor number bits:
31 *
32 * 7 6 5 4 3 2 1 0
33 * +-----+ partition number
34 * +-----+ scsi target number
35 * +--+ unused (should be 0)
36 *
37 * For tape drives, set the partition number to 0 for regular,
38 * 1 for no rewind.
39 *
40 * Only supports LUN 0.
41 *
42 * To use with a read-write disk, first use diskpart to create
43 * a disktab entry, then use disklabel. Since I don't have
44 * the boot programs done yet, I faked it with:
45 *
46 * # cd /usr/mdec
47 * # cp wdboot asboot
48 * # cp bootwd bootas
49 *
50 * Now you can run disklabel, newfs, etc.
51 *
52 * Please send patches and names other perpherials that work to
53 * pace@blitz.com. If you have trouble that you can't fix, please
54 * wait for the next release before contacting me.
55 *
56 * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
57 * -------------------- ----- ----------------------
58 * CURRENT PATCH LEVEL: 1 00088
59 * -------------------- ----- ----------------------
60 *
61 * 23 Oct 92 Joerg Lohse changed ccb opcode for compatibility
62 * with Adaptec AHA-1542A
63 * 27 Feb 93 James da Silva Tapedrive fixes.
64 */
65
66#include "as.h"
67#if NAS > 0
68
69#include "param.h"
70#include "dkbad.h"
71#include "systm.h"
72#include "conf.h"
73#include "file.h"
74#include "stat.h"
75#include "ioctl.h"
76#include "disklabel.h"
77#include "buf.h"
78#include "uio.h"
79#include "i386/isa/isa_device.h"
80#include "i386/isa/icu.h"
81#include "syslog.h"
82#include "vm/vm.h"
83#include "kernel.h"
84
85#include "asreg.h"
86
87int asstrategy ();
88int asabort ();
89extern int hz;
90
91int asverbose = 0;
92
93
94/* target id 7 is the controller itself */
95#define NTARGETS 7
96
97struct mailbox_entry mailboxes[NTARGETS * 2] = {0};
98
99#define b_cylin b_resid /* fake cylinder number for disksort */
100
101/* maximum scatter list size for Adaptech controller */
102#define NSCATTER 17
103
104/* this array must reside in contiguous physical memory */
105struct asinfo {
106 dev_t dev;
107 struct buf requests;
108 struct mailbox_entry *mailbox;
109 int active;
110 struct ccb ccb;
111 unsigned int ccb_phys;
112 char scatter_list[NSCATTER * 6];
113
114 struct disklabel label;
115 struct dos_partition dospart[NDOSPART];
116 int have_label;
117
118 int scsi_lock;
119 struct buf *scsi_bp;
120 int scsi_cdb_len;
121 unsigned char scsi_cdb[MAXCDB];
122
123 int tape; /* sequential */
124 int disk; /* nonsequential */
125 int read_only; /* CDROM */
126 int removable; /* unsupported and tested */
127 char vendor[9];
128 char model[17];
129 char revision[5];
130 int bs; /* device block size */
131
132 int open_lock;
133 int open;
134 int units_open;
135
136 int wlabel;
137
138 int retry_count;
139 int start_time;
140 int restart_pending;
141
142} asinfo[NTARGETS] = {0};
143
144#define dev_part(dev) (minor (dev) & 7)
145#define dev_target(dev) ((minor (dev) >> 3) & 7)
146#define dev_rewind(dev) ((minor (dev) & 1) == 0)
147
148#define makeasdev(major, target, part) \
149 makedev ((major), ((target) << 3) | (part))
150
151int as_port;
152
153int asprobe(struct isa_device *), asattach(struct isa_device *),
154 asintr(dev_t);
155
156struct isa_driver asdriver = {
157 asprobe, asattach, "as",
158};
159
160int
161asprobe (struct isa_device *dvp)
162{
163 int val;
164
165 as_port = dvp->id_iobase;
166
167 outb (as_port + AS_CONTROL, AS_CONTROL_SRST);
168 DELAY (30000);
169 val = inb (as_port + AS_STATUS);
170
171 if (val == (AS_STATUS_INIT | AS_STATUS_IDLE))
172 return (1);
173 as_port = 0;
174 return (0);
175}
176
177asattach (struct isa_device *dvp)
178{
179 int i;
180 unsigned int physaddr;
181 int val;
182 int s;
183
184 for (i = 0; i < NTARGETS; i++) {
185 asinfo[i].mailbox = &mailboxes[i];
186 asinfo[i].ccb_phys = vtophys (&asinfo[i].ccb);
187 }
188
189 isa_dmacascade(dvp->id_drq);
190
191 physaddr = vtophys (mailboxes);
192
193 s = splbio ();
194 if (as_put_byte (AS_CMD_MAILBOX_INIT) < 0
195 || as_put_byte (NTARGETS) < 0
196 || as_put_byte (physaddr >> 16) < 0
197 || as_put_byte (physaddr >> 8) < 0
198 || as_put_byte (physaddr) < 0) {
199 splx (s);
200 return (EIO);
201 }
202 splx (s);
203 DELAY (300);
204 val = inb (as_port + AS_STATUS);
205
206 if (val & AS_STATUS_INIT)
207 printf ("as: mailbox init error: 0x%x\n", val);
208}
209
210int
211ascmd (as, bp, direction, count, retrycount)
212struct asinfo *as;
213struct buf *bp;
214int direction;
215int count;
216int retrycount;
217{
218 int err;
219
220 do {
221 if (asverbose)
222 printf ("ascmd ");
223 bp->b_bcount = count;
224 bp->b_error = 0;
225 bp->b_flags &= ~(B_READ | B_ERROR | B_DONE);
226 if (direction == B_READ)
227 bp->b_flags |= B_READ;
228
229 bp->b_dev = as->dev;
230 bp->b_blkno = 0;
231
232 as->scsi_bp = bp;
233 /* scsi_cdb, scsi_cdb_len set up by caller */
234
235 asstrategy (bp);
236 err = biowait (bp);
237 as->scsi_bp = NULL;
238
239 } while (err && --retrycount);
240
241 return (err);
242}
243
244asstring (dest, src, size)
245char *dest;
246char *src;
247int size;
248{
249 size--;
250 bcopy (src, dest, size);
251 while (size > 0 && dest[size - 1] == ' ')
252 size--;
253 dest[size] = 0;
254}
255
256asopen (dev, flag)
257dev_t dev;
258int flag;
259{
260 struct asinfo *as;
261 unsigned int physaddr;
262 struct buf *bp = NULL;
263 int retry;
264 unsigned char *cdb;
265 char *p, *q;
266 int n;
267 int error;
268 char vendor[9];
269 char model[17];
270 int disksize;
271
272 if (as_port == 0 || dev_target (dev) >= NTARGETS)
273 return (ENXIO);
274
275 as = &asinfo[dev_target (dev)];
276 as->dev = dev;
277
278 while (as->open_lock)
279 if (error = tsleep ((caddr_t)as, PZERO|PCATCH, "scsiopen", 0))
280 return (error);
281
282 if (as->open) {
283 if (as->tape)
284 return (EBUSY);
285
286 if (as->have_label == 0 && dev_part (dev) != 3)
287 return (ENXIO);
288
289 as->units_open |= 1 << dev_part (dev);
290 return (0);
291 }
292
293 as->open_lock = 1;
294
295 /* it seems like we might have to block here in case someone
296 * opens the device just after someone else closes
297 */
298 while (as->scsi_lock)
299 if (error = tsleep ((caddr_t)as, PZERO|PCATCH, "scsicmd", 0))
300 return (error);
301
302 as->scsi_lock = 1;
303
304 error = EIO;
305
306 as->have_label = 0;
307 as->tape = 0;
308 as->disk = 0;
309 as->read_only = 0;
310 as->removable = 0;
311 bcopy(as->vendor, vendor, sizeof(vendor));
312 bcopy(as->model, model, sizeof(model));
313 as->vendor[0] = 0;
314 as->model[0] = 0;
315 as->revision[0] = 0;
316
317 bp = geteblk (DEV_BSIZE);
318
319 if (asverbose) {
320 printf ("openbuf = 0x%x phys 0x%x\n",
321 bp->b_un.b_addr, vtophys (bp->b_un.b_addr));
322 printf ("mailboxes = 0x%x\n", mailboxes);
323 }
324
325 /* first, find out if a device is present, and just what it is */
326 as->scsi_cdb_len = 6;
327 cdb = as->scsi_cdb;
328 bzero (cdb, 6);
329 cdb[0] = 0x12; /* INQUIRY */
330 cdb[4] = 255; /* allocation length */
331 if (error = ascmd (as, bp, B_READ, DEV_BSIZE, 2))
332 /* does not respond to inquiry, obviously not CCS, give up */
333 goto done;
334
335
336 /* blather on console about it */
337 p = bp->b_un.b_addr;
338 if (asverbose) {
339 printf ("inquiry: ");
340 for (n = 0; n < 20; n++)
341 printf ("%x ", p[n] & 0xff);
342 printf ("\n");
343 for (n = 0; n < 40; n++) {
344 if (p[n] >= ' ' && p[n] < 0177)
345 printf ("%c", p[n]);
346 else
347 printf (".");
348 }
349 printf ("\n");
350 }
351
352 switch (p[0]) {
353 case 0: /* normal disk */
354 case 4: /* write once disk */
355 as->disk = 1;
356 break;
357 case 5: /* read only disk */
358 as->read_only = 1;
359 as->disk = 1;
360 break;
361 case 1: /* tape */
362 as->tape = 1;
363 break;
364 case 0x7f:
365 printf ("logical unit not present\n");
366 goto done;
367 default:
368 printf ("unknown peripheral device type: 0x%x\n", p[0]);
369 goto done;
370 }
371
372 as->removable = (p[1] & 0x80) ? 1 : 0;
373
374 n = p[4] & 0xff;
375 if (n >= 31) {
376 asstring (as->vendor, p + 8, sizeof as->vendor);
377 asstring (as->model, p + 16, sizeof as->model);
378 asstring (as->revision, p + 32, sizeof as->revision);
379 }
380
381 if(bcmp(as->vendor,vendor, sizeof(vendor)) != 0 ||
382 bcmp(as->model,model, sizeof(model)) != 0) {
383 printf("as%d: attached tgt %d <%s %s %s> ", 0, dev_target(dev),
384 as->vendor, as->model, as->revision);
385 if (as->read_only) printf("readonly ");
386 if (!as->removable) printf("winchester ");
387 if (as->tape) printf("tape ");
388 if (as->disk) printf("disk ");
389 printf("\n");
390 }
391
392 /* probe for desired block size */
393
394 /* assume default of 512, except if CDROM (2048) */
395 if (as->read_only)
396 as->bs = 2048;
397 else
398 as->bs = 512;
399
400 bzero(cdb, 6);
401 cdb[0] = 0x1A; /* SCSI_MDSENSE */
402 cdb[4] = 255;
403 if (as->tape && ascmd (as, bp, B_READ, 12, 2) == 0) {
404 int minblk, maxblk;
405
406#ifdef notdef
407 /* blather about device more */
408 if(bcmp(as->vendor,vendor, sizeof(vendor)) != 0 ||
409 bcmp(as->model,model, sizeof(model)) != 0) {
410 p = bp->b_un.b_addr;
411 printf("as%d: data len %d medium %d speed/bufmode 0x%x desc len %d\n",
412 dev_target(dev), p[0], p[1], p[2], p[3]);
413 printf("as%d: density %d nblocks %d block len %d\n",
414 dev_target(dev), p[4],
415 (long)p[5]*65536+p[6]*256+p[7],
416 (long)p[9]*65536+p[10]*256+p[11]);
417 }
418#endif
419
420 /* obtain possible block sizes */
421 bzero(cdb, 6);
422 cdb[0] = 0x05; /* SCSI_RDLIMITS; */
423 if (ascmd (as, bp, B_READ, 12, 2) == 0) {
424 p = bp->b_un.b_addr;
425 minblk = p[4]*256+p[5];
426 maxblk = p[1]*65536+p[2]*256+p[3];
427#ifdef notdef
428 if(bcmp(as->vendor,vendor, sizeof(vendor)) != 0 ||
429 bcmp(as->model,model, sizeof(model)) != 0) {
430 printf("as%d: limits: min block len %ld max block len %ld\n",
431 dev_target(dev), minblk, maxblk);
432 }
433#endif
434 if ( minblk == maxblk )
435 as->bs = minblk;
436 else if (as->tape)
437 as->bs = 1;
438 }
439 }
440
441 as->scsi_cdb_len = 10;
442 bzero(cdb, 10);
443 cdb[0] = 0x25; /* SCSI_READCAPACITY */
444 disksize = 0;
445 if (as->disk && ascmd (as, bp, B_READ, 12, 2) == 0) {
446 p = bp->b_un.b_addr;
447 disksize = ntohl(*(long *)p);
448 as->bs = ntohl(*(long *)(p+4));
449
450 }
451
452if(asverbose)
453 printf("block size %d disksize %d ", as->bs, disksize);
454
455
456 /* for standard disk, negotiate block size */
457 if (as->read_only == 0 && as->disk) {
458 /* do mode select to set the logical block size */
459 as->scsi_cdb_len = 6;
460 cdb = as->scsi_cdb;
461 bzero (cdb, 6);
462 cdb[0] = 0x15; /* MODE SELECT */
463 cdb[4] = 12; /* parameter list length */
464
465 p = bp->b_un.b_addr;
466 bzero (p, 12);
467 p[3] = 8; /* block descriptor length */
468 n = as->bs == 1 ? 0 : as->bs;
469 p[9] = n >> 16;
470 p[10] = n >> 8;
471 p[11] = n;
472
473 (void) ascmd (as, bp, B_WRITE, 12, 2);
474 }
475
476 /* device online and ready? */
477 as->scsi_cdb_len = 6;
478 bzero(cdb, 6);
479 cdb[0] = 0x00; /* SCSI_UNITRDY */
480 if (error = ascmd (as, bp, B_READ, 12, 2)) {
481 printf("as%d: drive not online\n", dev_target(dev));
482 goto done;
483 }
484
485 if (as->disk && as->read_only == 0) {
486 /* read disk label */
487 bzero ((caddr_t)&as->label, sizeof as->label);
488 as->label.d_secsize = as->bs;
489 as->label.d_secpercyl = 64*32;
490 as->label.d_type = DTYPE_SCSI;
491
492
493 /* read label using "d" partition */
494 if ((p = readdisklabel (
495 makeasdev (major (dev), dev_target (dev), 3),
496 asstrategy, &as->label, as->dospart, 0, 0)) == NULL){
497 as->have_label = 1;
498 } else {
499 if (disksize) {
500 as->label.d_subtype = DSTYPE_GEOMETRY;
501 as->label.d_npartitions = 3;
502 /* partition 0 holds bios, partition 1 ESDI */
503 as->label.d_partitions[2].p_size = disksize;
504 as->label.d_partitions[2].p_offset = 0;
505 }
506 if (asverbose || dev_part (dev) != 3)
507 printf ("error reading label: %s\n", p);
508 if (dev_part (dev) != 3) {
509 error = EINVAL;
510 goto done;
511 }
512 }
513 }
514
515 /* may want to set logical block size here ? */
516 error = 0;
517
518 done:
519 if (bp) {
520 bp->b_flags |= B_INVAL | B_AGE;
521 brelse (bp);
522 }
523
524 if (error == 0)
525 as->open = 1;
526
527 as->open_lock = 0;
528 as->scsi_lock = 0;
529 wakeup (as);
530
531 return (error);
532}
533
534asclose (dev, flag)
535dev_t dev;
536{
537 struct asinfo *as;
538 int error = 0;
539 unsigned char *cdb;
540 struct buf *bp;
541 int n;
542
543 as = &asinfo[dev_target (dev)];
544
545 while (as->open_lock)
546 if (error = tsleep ((caddr_t)as, PZERO|PCATCH, "scsiclose", 0))
547 return (error);
548
549 as->open_lock = 1;
550
551 if (as->tape) {
552 while (as->scsi_lock)
553 if (error = tsleep ((caddr_t)as, PZERO|PCATCH,
554 "scsicmd", 0))
555 return (error);
556
557 as->scsi_lock = 1;
558
559 bp = geteblk (DEV_BSIZE);
560
561 if ((flag & FWRITE) != 0) {
562 /* presume user will use tape again */
563 as->scsi_cdb_len = 6;
564 cdb = as->scsi_cdb;
565 bzero (cdb, 6);
566 cdb[0] = 0x10; /* write filemarks */
567 cdb[4] = 1; /* one of them */
568 error = ascmd (as, bp, B_READ, 0, 1);
569 }
570 if (dev_rewind (dev) || error) {
571 if ( error == 0 && (flag & FWRITE) != 0) {
572 /* presumption error correction */
573 as->scsi_cdb_len = 6;
574 cdb = as->scsi_cdb;
575 bzero (cdb, 6);
576 cdb[0] = 0x10; /* write filemarks */
577 cdb[4] = 1; /* one of them */
578 error |= ascmd (as, bp, B_READ, 0, 1);
579 }
580 as->scsi_cdb_len = 6;
581 cdb = as->scsi_cdb;
582 bzero (cdb, 6);
583 cdb[0] = 0x1; /* rewind */
584 cdb[1] = 1; /* don't wait until done */
585 error |= ascmd (as, bp, B_READ, 0, 1);
586 }
587#ifdef notdef
588 } else {
589 cdb[0] = 0x11; /* backspace */
590 cdb[1] = 1; /* look at filemarks (instead of blocks) */
591 n = -1;
592 cdb[2] = n >> 16;
593 cdb[3] = n >> 8;
594 cdb[4] = n;
595 error = ascmd (as, bp, B_READ, 0, 1);
596 }
597#endif
598
599 bp->b_flags |= B_INVAL | B_AGE;
600 brelse (bp);
601
602 as->scsi_lock = 0;
603 }
604
605 as->units_open &= ~(1 << dev_part (dev));
606
607 if (as->units_open == 0)
608 as->open = 0;
609
610 as->open_lock = 0;
611
612 wakeup (as);
613
614 return (error);
615}
616
617int
618asioctl (dev, cmd, addr, flag)
619dev_t dev;
620int cmd;
621caddr_t addr;
622int flag;
623{
624 struct scsicmd *cmdp;
625 struct asinfo *as;
626 int ccblen;
627 struct buf *bp;
628 int error = 0;
629 int direction;
630 struct disklabel *dl;
631 int old_wlabel;
632
633 as = &asinfo[dev_target (dev)];
634
635 switch (cmd) {
636 case DIOCGDINFO:
637 *(struct disklabel *)addr = as->label;
638 break;
639
640 case DIOCSDINFO:
641 if ((flag & FWRITE) == 0) {
642 error = EBADF;
643 break;
644 }
645 dl = (struct disklabel *)addr;
646 if (error = setdisklabel(&as->label, dl, 0, as->dospart))
647 break;
648 as->have_label = 1;
649 break;
650
651 case DIOCWLABEL:
652 if ((flag & FWRITE) == 0) {
653 error = EBADF;
654 break;
655 }
656 as->wlabel = *(int *)addr;
657 break;
658
659 case DIOCWDINFO:
660 if ((flag & FWRITE) == 0) {
661 error = EBADF;
662 break;
663 }
664
665 dl = (struct disklabel *)addr;
666
667 if (error = setdisklabel (&as->label, dl, 0, as->dospart))
668 break;
669
670 as->have_label = 1;
671
672 old_wlabel = as->wlabel;
673 as->wlabel = 1;
674 error = writedisklabel(dev, asstrategy, &as->label,
675 as->dospart);
676 as->wlabel = old_wlabel;
677 break;
678
679 case SCSICMD:
680 cmdp = (struct scsicmd *)addr;
681
682 /* limited by max sizeof of geteblk */
683 if (cmdp->datalen >= 8192
684 || cmdp->cdblen >= MAXCDB) {
685 error = EINVAL;
686 break;
687 }
688
689 ccblen = cmdp->ccblen;
690 if (ccblen > sizeof (struct ccb))
691 ccblen = sizeof (struct ccb);
692
693 while (as->scsi_lock)
694 if (error = tsleep ((caddr_t)as, PZERO|PCATCH,
695 "scsicmd", 0))
696 break;
697
698 as->scsi_lock = 1;
699
700 bp = geteblk (cmdp->datalen);
701
702 as->scsi_cdb_len = cmdp->cdblen;
703 if (error = copyin (cmdp->cdb, as->scsi_cdb, cmdp->cdblen))
704 goto done;
705
706 direction = cmdp->readflag ? B_READ : B_WRITE;
707
708 if (direction == B_WRITE)
709 if (error = copyin (cmdp->data,
710 bp->b_un.b_addr, cmdp->datalen))
711 goto done;
712
713 ascmd (as, bp, direction, cmdp->datalen, 1);
714
715 copyout (&as->ccb, cmdp->ccb, ccblen);
716 if (direction == B_READ)
717 copyout (bp->b_un.b_addr, cmdp->data, cmdp->datalen);
718 done:
719 bp->b_flags |= B_INVAL | B_AGE;
720 brelse (bp);
721 as->scsi_lock = 0;
722 wakeup (as);
723 break;
724 default:
725 error = ENOTTY;
726 break;
727 }
728 return (error);
729}
730
731int
732asstrategy (bp)
733struct buf *bp;
734{
735 struct asinfo *as;
736 int s;
737
738 if (asverbose)
739 printf ("asstrategy %d %d ", bp->b_blkno, bp->b_bcount);
740 s = splbio ();
741
742 as = &asinfo[dev_target (bp->b_dev)];
743
744 if (as->tape) {
745 bp->av_forw = NULL;
746 if (as->requests.b_actf)
747 as->requests.b_actl->av_forw = bp;
748 else
749 as->requests.b_actf = bp;
750 as->requests.b_actl = bp;
751 } else {
752 if (bp != as->scsi_bp
753 && as->have_label == 0
754 && dev_part (bp->b_dev) != 3)
755 goto bad;
756
757 bp->b_cylin = bp->b_blkno;
758 disksort (&as->requests, bp);
759 }
760
761 if (as->active == 0)
762 asstart (as);
763
764 splx (s);
765 return;
766
767 bad:
768 bp->b_flags |= B_ERROR;
769 biodone (bp);
770}
771
772asrestart (as)
773struct asinfo *as;
774{
775 int s;
776 s = splbio ();
777 as->restart_pending = 0;
778 as->retry_count++;
779 asstart (as);
780 splx (s);
781}
782
783asstart (as)
784struct asinfo *as;
785{
786 struct buf *bp;
787 int blknum;
788 unsigned int physaddr;
789 struct ccb *ccb;
790 unsigned char *cdb;
791 int target;
792 char *p;
793 int n;
794 char *sp;
795 int nscatter;
796 int thistime;
797 int nbytes;
798 struct partition *part;
799 int blkno;
800 int nblocks;
801 int total;
802 int bs = as->bs;
803
804
805 if (as->restart_pending) {
806 as->restart_pending = 0;
807 untimeout (asrestart, as);
808 }
809
810 again:
811 if ((bp = as->requests.b_actf) == NULL)
812 return;
813
814 bp->b_error = 0;
815
816 if (asverbose)
817 printf ("asstart %x ", bp);
818
819 if (as->mailbox->cmd != 0) {
820 /* this can't happen, unless the card flakes */
821 printf ("asstart: mailbox not available\n");
822 bp->b_error = EIO;
823 goto bad;
824 }
825
826 if (as->retry_count == 0) {
827 as->start_time = time.tv_sec;
828 } else {
829 if (time.tv_sec - as->start_time > 60) {
830 printf ("as: command timed out\n");
831 bp->b_error = EIO;
832 goto done;
833 }
834 }
835
836 if (bp != as->scsi_bp) {
837 if (bp->b_bcount == 0)
838 goto done;
839
840 if ((bp->b_bcount % bs) != 0) {
841 printf("as: partial block read\n");
842 bp->b_error = EIO;
843 goto bad;
844 }
845 }
846
847 if (bp != as->scsi_bp) {
848
849 blkno = bp->b_blkno;
850 nblocks = bp->b_bcount / bs;
851
852 if (as->have_label && dev_part(bp->b_dev) != 3) {
853 part = &as->label.d_partitions[dev_part (bp->b_dev)];
854
855 if (blkno > part->p_size) {
856 bp->b_error = EINVAL;
857 goto bad;
858 }
859 if (blkno == part->p_size) {
860 bp->b_resid = bp->b_bcount;
861 goto done;
862 }
863
864 if (blkno + nblocks >= part->p_size)
865 nblocks = part->p_size - blkno;
866
867 blkno += part->p_offset;
868 } else
869 blkno = (blkno * DEV_BSIZE)/bs;
870if(asverbose)
871 printf("trans %d ", blkno);
872 if (nblocks > 255)
873 nblocks = 255;
874 total = nblocks * bs;
875if(asverbose)
876printf("total %d nblocks %d ", total, nblocks);
877 /*bp->b_bcount = total; /* XXX partial tape block read - wrong */
878 } else {
879#ifdef nomore
880 if (as->fixed == 0) {
881 total = bp->b_bcount;
882 } else {
883 total = bp->b_bcount;
884 blkno = bp->b_blkno;
885 nblocks = bp->b_bcount / as->fixed;
886 }
887#else
888 total = bp->b_bcount;
889#endif
890 }
891
892 p = bp->b_un.b_addr;
893 n = 0;
894 sp = as->scatter_list;
895 nscatter = 0;
896 if (as->tape && as->bs == 1)
897 total = bp->b_bcount;
898 while (n < total && nscatter < NSCATTER) {
899 thistime = page_size - ((vm_offset_t)p - trunc_page (p));
900
901 if (n + thistime > total)
902 thistime = total - n;
903
904 physaddr = vtophys (p);
905
906 if (asverbose)
907 printf ("%d bytes to %x (%x)\n",
908 thistime, p, physaddr);
909 sp[0] = thistime >> 16;
910 sp[1] = thistime >> 8;
911 sp[2] = thistime;
912 sp[3] = physaddr >> 16;
913 sp[4] = physaddr >> 8;
914 sp[5] = physaddr;
915
916 p += thistime;
917 n += thistime;
918 sp += 6;
919 nscatter++;
920 }
921
922 if (nscatter == NSCATTER) {
923 printf("out of range, cannot happen?");
924 bp->b_error = ENXIO;
925 goto bad;
926 }
927
928 ccb = &as->ccb;
929
930 /* this only needed to make debugging easier */
931 bzero ((caddr_t)ccb, sizeof *ccb);
932
933 if (nscatter)
934 ccb->ccb_opcode = 2; /* scatter cmd, return resid */
935 else
936 ccb->ccb_opcode = 0;
937 target = dev_target (bp->b_dev);
938 ccb->ccb_addr_and_control = target << 5;
939 if (bp->b_bcount != 0)
940 ccb->ccb_addr_and_control |= (bp->b_flags & B_READ) ? 8 : 0x10;
941 else
942 ccb->ccb_addr_and_control |= 0x18;
943
944 nbytes = nscatter * 6;
945 ccb->ccb_data_len_msb = nbytes >> 16;
946 ccb->ccb_data_len_mid = nbytes >> 8;
947 ccb->ccb_data_len_lsb = nbytes;
948
949 ccb->ccb_requst_sense_allocation_len = MAXSENSE;
950
951 physaddr = vtophys (as->scatter_list);
952 ccb->ccb_data_ptr_msb = physaddr >> 16;
953 ccb->ccb_data_ptr_mid = physaddr >> 8;
954 ccb->ccb_data_ptr_lsb = physaddr;
955
956 ccb->ccb_link_msb = 0;
957 ccb->ccb_link_mid = 0;
958 ccb->ccb_link_lsb = 0;
959 ccb->ccb_link_id = 0;
960 ccb->ccb_host_status = 0;
961 ccb->ccb_target_status = 0;
962 ccb->ccb_zero1 = 0;
963 ccb->ccb_zero2 = 0;
964
965 cdb = ccb->ccb_cdb;
966 if (bp == as->scsi_bp) {
967 ccb->ccb_scsi_command_len = as->scsi_cdb_len;
968 bcopy (as->scsi_cdb, cdb, as->scsi_cdb_len);
969 } else if (as->tape) {
970 ccb->ccb_scsi_command_len = 6;
971 cdb[0] = (bp->b_flags & B_READ) ? 8 : 0xa;
972 if (as->bs == 1) {
973 cdb[1] = 0; /* logical unit 0, variable block size */
974 cdb[2] = bp->b_bcount >> 16;
975 cdb[3] = bp->b_bcount >> 8;
976 cdb[4] = bp->b_bcount;
977 } else {
978 cdb[1] = 1; /* fixed block size */
979 cdb[2] = nblocks >> 16;
980 cdb[3] = nblocks >> 8;
981 cdb[4] = nblocks;
982 }
983 cdb[5] = 0; /* control byte (used in linking) */
984 } else {
985 ccb->ccb_scsi_command_len = 10;
986 cdb[0] = (bp->b_flags & B_READ) ? 0x28 : 0x2a;
987 cdb[1] = 0;
988 *(long *) (cdb+2) = htonl(blkno);
989 *(short *) (cdb+7) = htons(nblocks);
990 cdb[9] = 0; /* control byte (used in linking) */
991 }
992
993#ifdef notdef
994 if (asverbose) {
995 printf ("ccb: ");
996 for (n = 0; n < 48; n++)
997 printf ("%02x ", ((unsigned char *)ccb)[n]);
998 printf ("\n");
999 }
1000#endif
1001
1002 physaddr = vtophys (ccb);
1003 as->mailbox->msb = physaddr >> 16;
1004 as->mailbox->mid = physaddr >> 8;
1005 as->mailbox->lsb = physaddr;
1006 as->mailbox->cmd = 1;
1007
1008 /* tell controller to look in its mailbox */
1009 as_put_byte (AS_CMD_START_SCSI_COMMAND);
1010 as->active = 1;
1011 timeout (asabort, as, hz * 60 * 2);
1012 return;
1013
1014 bad:
1015 bp->b_flags |= B_ERROR;
1016 done:
1017 asdone (as, 0);
1018 goto again;
1019}
1020
1021asabort (as)
1022struct asinfo *as;
1023{
1024 int s;
1025 int physaddr;
1026 struct buf *bp;
1027
1028 s = splbio ();
1029 if (as->active) {
1030 printf ("asabort %d\n", as - asinfo);
1031 physaddr = vtophys (&as->ccb);
1032 as->mailbox->msb = physaddr >> 16;
1033 as->mailbox->mid = physaddr >> 8;
1034 as->mailbox->lsb = physaddr;
1035 as->mailbox->cmd = 2;
1036 as_put_byte (AS_CMD_START_SCSI_COMMAND);
1037
1038 as->active = 0;
1039 bp = as->requests.b_actf;
1040 if (bp) {
1041 bp->b_flags |= B_ERROR;
1042 asdone (as, 1);
1043 }
1044 }
1045 splx (s);
1046}
1047
1048asintr (dev_t dev)
1049{
1050 int didwork;
1051 int i, j;
1052 struct mailbox_entry *mp;
1053 unsigned int physaddr;
1054 int val;
1055
1056 outb (as_port + AS_CONTROL, AS_CONTROL_IRST);
1057#ifdef notdef
1058 if (asverbose)
1059 printf ("asintr %x ", cpl);
1060#endif
1061 again:
1062 didwork = 0;
1063 for (i = NTARGETS; i < NTARGETS * 2; i++) {
1064 mp = &mailboxes[i];
1065
1066 if ((val = mp->cmd) == 0)
1067 continue;
1068
1069 didwork = 1;
1070
1071 physaddr = (mp->msb << 16)
1072 | (mp->mid << 8)
1073 | mp->lsb;
1074
1075 for (j = 0; j < NTARGETS; j++) {
1076 if (asinfo[j].ccb_phys == physaddr) {
1077 mp->cmd = 0;
1078 asintr1 (&asinfo[j], val);
1079 break;
1080 }
1081 }
1082 if (j == NTARGETS) {
1083 printf ("as: unknown mailbox paddr 0x%x\n", physaddr);
1084 mp->cmd = 0;
1085 }
1086 }
1087
1088 if (didwork)
1089 goto again;
1090}
1091
1092asintr1 (as, val)
1093struct asinfo *as;
1094int val;
1095{
1096 struct buf *bp;
1097 struct ccb *ccb;
1098 int n;
1099 int bad;
1100 char *msg;
1101 char msgbuf[100];
1102 unsigned char *sp;
1103 int i,key;
1104
1105 if (asverbose)
1106 printf ("asintr1 %x ", val);
1107 if (as->active == 0) {
1108 printf ("as: stray intr 0x%x\n", as->dev);
1109 return;
1110 }
1111
1112 as->active = 0;
1113 untimeout (asabort, as);
1114
1115 bp = as->requests.b_actf;
1116 ccb = &as->ccb;
1117
1118 if (bp == as->scsi_bp) {
1119 /* no fancy error recovery in this case */
1120 if (asverbose)
1121 printf ("asintr1:scsicmd ");
1122#if 0
1123 if (val != 1)
1124 bp->b_flags |= B_ERROR;
1125 goto next;
1126#endif
1127 }
1128
1129 bad = 0;
1130 msg = NULL;
1131
1132 if (val != 1 && val != 4) {
1133 bad = 1;
1134 sprintf (msgbuf, "funny mailbox message 0x%x\n", val);
1135 msg = msgbuf;
1136 goto wrapup;
1137 }
1138
1139 if (ccb->ccb_host_status != 0) {
1140 bad = 1;
1141 sprintf (msgbuf, "controller error 0x%x",
1142 ccb->ccb_host_status);
1143 msg = msgbuf;
1144 goto wrapup;
1145 }
1146
1147 if (ccb->ccb_target_status == 0)
1148 /* good transfer */
1149 goto wrapup;
1150
1151 if (ccb->ccb_target_status == 8) {
1152 /* target rejected command because it is busy
1153 * and wants us to try again later. We'll wait 1 second
1154 */
1155 as->restart_pending = 1;
1156 timeout (asrestart, as, hz);
1157 return;
1158 }
1159
1160 if (ccb->ccb_target_status != 2) {
1161 bad = 1;
1162 sprintf (msgbuf, "target error 0x%x",
1163 ccb->ccb_target_status);
1164 msg = msgbuf;
1165 goto wrapup;
1166 }
1167
1168 /* normal path for errors */
1169
1170 sp = ccb_sense (ccb);
1171 /* check for extended sense information */
1172 if ((sp[0] & 0x7f) != 0x70) {
1173 /* none */
1174 bad = 1;
1175 sprintf (msgbuf, "scsi error 0x%x", sp[0] & 0x7f);
1176 msg = msgbuf;
1177 goto wrapup;
1178 }
1179
1180 if (as->tape && (sp[2] & 0xf) == 0) {
1181 if (sp[2] & 0xe0) {
1182 /* either we read a file mark, the early warning EOT,
1183 * or the block size did not match. In any case, the
1184 * normal residue handling will work (I think)
1185 */
1186 goto wrapup;
1187 }
1188 }
1189
1190 bad = 1;
1191
1192 switch (key = sp[2] & 0xf) {
1193 case 1:
1194 msg = "soft error";
1195 bad = 0;
1196 break;
1197 case 2:
1198 msg = "not ready";
1199 break;
1200 case 3:
1201 msg = "hard error";
1202 break;
1203 case 4:
1204 msg = "target hardware error";
1205 break;
1206 case 5:
1207 msg = "illegal request";
1208 break;
1209 case 6:
1210 msg = "unit attention error";
1211 break;
1212 case 7:
1213 msg = "write protect error";
1214 break;
1215 case 0xd:
1216 msg = "volume overflow";
1217 break;
1218 default:
1219 sprintf (msgbuf, "scsi extended error 0x%x", sp[2] & 0xf);
1220 msg = msgbuf;
1221 break;
1222 }
1223
1224 wrapup:
1225
1226 if (bad && msg == NULL)
1227 msg = "unknown error";
1228
1229 if (msg && key != 6) {
1230 diskerr (bp, "as", msg,
1231 LOG_PRINTF,
1232 -1, /* number of successful blks */
1233 as->have_label ? &as->label : NULL);
1234 printf ("\n");
1235 }
1236
1237 if (bad && key != 6) {
1238 bp->b_flags |= B_ERROR;
1239 printf ("scsi sense: ");
1240 sp = ccb_sense (ccb);
1241 for (i = 0; i < 30; i++)
1242 printf ("%x ", sp[i] & 0xff);
1243 printf ("\n");
1244 }
1245
1246 /* this assignment mixed sizes of controller commands
1247 and data to read/write.
1248 bp->b_resid = (ccb->ccb_data_len_msb << 16)
1249 | (ccb->ccb_data_len_mid << 8)
1250 | ccb->ccb_data_len_lsb;
1251 */
1252 bp->b_resid = 0;
1253
1254 next:
1255 asdone (as, 1);
1256}
1257
1258asdone (as, restart)
1259struct asinfo *as;
1260int restart;
1261{
1262 struct buf *bp;
1263
1264 bp = as->requests.b_actf;
1265 as->requests.b_actf = bp->av_forw;
1266 biodone (bp);
1267 as->retry_count = 0;
1268 if (restart && as->requests.b_actf)
1269 asstart (as);
1270}
1271
1272int
1273assize (dev)
1274dev_t dev;
1275{
1276 struct asinfo *as;
1277 struct disklabel *lp;
1278 int val;
1279
1280 if (as_port == 0 || dev_target (dev) >= NTARGETS)
1281 return (ENXIO);
1282
1283 as = &asinfo[dev_target (dev)];
1284
1285 if (as->open == 0
1286 && asopen (dev, FREAD, S_IFBLK, NULL) != 0)
1287 return (0);
1288
1289 if (as->have_label == 0)
1290 return (0);
1291
1292 lp = &as->label;
1293 val = lp->d_partitions[dev_part (dev)].p_size
1294 * lp->d_secsize / DEV_BSIZE;
1295 (void) asclose(dev, FREAD, S_IFBLK, NULL);
1296 return (val);
1297}
1298
1299int
1300as_put_byte (val)
1301int val;
1302{
1303 int i;
1304
1305 for (i = 100; i > 0; i--) {
1306 if ((inb (as_port + AS_STATUS) & AS_STATUS_CDF) == 0)
1307 break;
1308 DELAY (100);
1309 }
1310 if (i == 0) {
1311 printf ("as: put byte timed out\n");
1312 return (-1);
1313 }
1314 outb (as_port + AS_DATA_OUT, val);
1315 return (0);
1316}
1317
1318int
1319as_get_byte (as)
1320{
1321 int i;
1322
1323 for (i = 100; i > 0; i--) {
1324 if ((inb (as_port + AS_STATUS) & AS_STATUS_DF) != 0)
1325 break;
1326 DELAY (100);
1327 }
1328 if (i == 0) {
1329 printf ("as_get_byte timed out\n");
1330 return (-1);
1331 }
1332 return (inb (as_port + AS_DATA_OUT) & 0xff);
1333}
1334#endif /* NAS */