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