wd7000.c revision 106592
1/* 2 * Copyright (c) 1994 Ludd, University of Lule}, Sweden. 3 * Copyright (c) 2000 Sergey A. Babkin 4 * All rights reserved. 5 * 6 * Written by Olof Johansson (offe@ludd.luth.se) 1995. 7 * Based on code written by Theo de Raadt (deraadt@fsa.ca). 8 * Resurrected, ported to CAM and generally cleaned up by Sergey Babkin 9 * <babkin@bellatlantic.net> or <babkin@users.sourceforge.net>. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed at Ludd, University of Lule} 22 * and by the FreeBSD project. 23 * 4. The name of the author may not be used to endorse or promote products 24 * derived from this software without specific prior written permission 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 27 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 28 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 29 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 30 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 31 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 35 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 * 37 * $FreeBSD: head/sys/dev/wds/wd7000.c 106592 2002-11-07 22:25:13Z jhb $ 38 */ 39 40/* All bugs are subject to removal without further notice */ 41 42/* 43 * offe 01/07/95 44 * 45 * This version of the driver _still_ doesn't implement scatter/gather for the 46 * WD7000-FASST2. This is due to the fact that my controller doesn't seem to 47 * support it. That, and the lack of documentation makes it impossible for me 48 * to implement it. What I've done instead is allocated a local buffer, 49 * contiguous buffer big enough to handle the requests. I haven't seen any 50 * read/write bigger than 64k, so I allocate a buffer of 64+16k. The data 51 * that needs to be DMA'd to/from the controller is copied to/from that 52 * buffer before/after the command is sent to the card. 53 * 54 * SB 03/30/00 55 * 56 * An intermediate buffer is needed anyway to make sure that the buffer is 57 * located under 16MB, otherwise it's out of reach of ISA cards. I've added 58 * optimizations to allocate space in buffer in fragments. 59 */ 60 61/* 62 * Jumpers: (see The Ref(TM) for more info) 63 * W1/W2 - interrupt selection: 64 * W1 (1-2) IRQ3, (3-4) IRQ4, (5-6) IRQ5, (7-8) IRQ7, (9-10) IRQ9 65 * W2 (21-22) IRQ10, (19-20) IRQ11, (17-18) IRQ12, (15-16) IRQ14, (13-14) IRQ15 66 * 67 * W2 - DRQ/DACK selection, DRQ and DACK must be the same: 68 * (5-6) DRQ5 (11-12) DACK5 69 * (3-4) DRQ6 (9-10) DACK6 70 * (1-2) DRQ7 (7-8) DACK7 71 * 72 * W3 - I/O address selection: open pair of pins (OFF) means 1, jumpered (ON) means 0 73 * pair (1-2) is bit 3, ..., pair (9-10) is bit 7. All the other bits are equal 74 * to the value 0x300. In bitwise representation that would be: 75 * 0 0 1 1 (9-10) (7-8) (5-6) (3-4) (1-2) 0 0 0 76 * For example, address 0x3C0, bitwise 1111000000 will be represented as: 77 * (9-10) OFF, (7-8) OFF, (5-6) ON, (3-4) ON, (1-2) ON 78 * 79 * W4 - BIOS address: open pair of pins (OFF) means 1, jumpered (ON) means 0 80 * pair (1-2) is bit 13, ..., pair (7-8) is bit 16. All the other bits are 81 * equal to the value 0xC0000. In bitwise representation that would be: 82 * 1 1 0 (7-8) (5-6) (3-4) (1-2) 0 0000 0000 0000 83 * For example, address 0xD8000 will be represented as: 84 * (7-8) OFF, (5-6) OFF, (3-4) ON, (1-2) ON 85 * 86 * W98 (on newer cards) - BIOS enabled; on older cards just remove the BIOS 87 * chip to disable it 88 * W99 (on newer cards) - ROM size (1-2) OFF, (3-4) ON 89 * 90 * W5 - terminator power 91 * ON - host supplies term. power 92 * OFF - target supplies term. power 93 * 94 * W6, W9 - floppy support (a bit cryptic): 95 * W6 ON, W9 ON - disabled 96 * W6 OFF, W9 ON - enabled with HardCard only 97 * W6 OFF, W9 OFF - enabled with no hardCard or Combo 98 * 99 * Default: I/O 0x350, IRQ15, DMA6 100 */ 101 102/* 103 * debugging levels: 104 * 0 - disabled 105 * 1 - print debugging messages 106 * 2 - collect debugging messages in an internal log buffer which can be 107 * printed later by calling wds_printlog from DDB 108 * 109 * Both kind of logs are heavy and interact significantly with the timing 110 * of commands, so the observed problems may become invisible if debug 111 * logging is enabled. 112 * 113 * The light-weight logging facility may be enabled by defining 114 * WDS_ENABLE_SMALLOG as 1. It has very little overhead and allows observing 115 * the traces of various race conditions without affectiong them but the log is 116 * quite terse. The small log can be printer from DDB by calling 117 * wds_printsmallog. 118 */ 119#ifndef WDS_DEBUG 120#define WDS_DEBUG 0 121#endif 122 123#ifndef WDS_ENABLE_SMALLOG 124#define WDS_ENABLE_SMALLOG 0 125#endif 126 127#include <sys/types.h> 128#include <sys/param.h> 129#include <sys/systm.h> 130#include <sys/errno.h> 131#include <sys/kernel.h> 132#include <sys/assym.h> 133 134#include <sys/bio.h> 135#include <sys/buf.h> 136#include <sys/disklabel.h> 137 138#include <cam/cam.h> 139#include <cam/cam_ccb.h> 140#include <cam/cam_sim.h> 141#include <cam/cam_xpt_sim.h> 142#include <cam/cam_debug.h> 143#include <cam/scsi/scsi_all.h> 144#include <cam/scsi/scsi_message.h> 145 146#include <machine/clock.h> 147 148#include <vm/vm.h> 149#include <vm/vm_param.h> 150#include <vm/pmap.h> 151 152#include <sys/module.h> 153#include <sys/bus.h> 154#include <machine/bus.h> 155#include <machine/resource.h> 156#include <sys/rman.h> 157 158#include <isa/isavar.h> 159#include <isa/pnpvar.h> 160 161#define WDSTOPHYS(wp, a) ( ((u_long)a) - ((u_long)wp->dx) + ((u_long)wp->dx_p) ) 162#define WDSTOVIRT(wp, a) ( ((char *)a) - ((char*)wp->dx_p) + ((char *)wp->dx) ) 163 164/* 0x10000 (64k) should be enough. But just to be sure... */ 165#define BUFSIZ 0x12000 166/* buffer fragment size, no more than 32 frags per buffer */ 167#define FRAGSIZ 0x1000 168 169 170/* WD7000 registers */ 171#define WDS_STAT 0 /* read */ 172#define WDS_IRQSTAT 1 /* read */ 173 174#define WDS_CMD 0 /* write */ 175#define WDS_IRQACK 1 /* write */ 176#define WDS_HCR 2 /* write */ 177 178#define WDS_NPORTS 4 /* number of ports used */ 179 180/* WDS_STAT (read) defs */ 181#define WDS_IRQ 0x80 182#define WDS_RDY 0x40 183#define WDS_REJ 0x20 184#define WDS_INIT 0x10 185 186/* WDS_IRQSTAT (read) defs */ 187#define WDSI_MASK 0xc0 188#define WDSI_ERR 0x00 189#define WDSI_MFREE 0x80 190#define WDSI_MSVC 0xc0 191 192/* WDS_CMD (write) defs */ 193#define WDSC_NOOP 0x00 194#define WDSC_INIT 0x01 195#define WDSC_DISUNSOL 0x02 /* disable unsolicited ints */ 196#define WDSC_ENAUNSOL 0x03 /* enable unsolicited ints */ 197#define WDSC_IRQMFREE 0x04 /* interrupt on free RQM */ 198#define WDSC_SCSIRESETSOFT 0x05 /* soft reset */ 199#define WDSC_SCSIRESETHARD 0x06 /* hard reset ack */ 200#define WDSC_MSTART(m) (0x80 + (m)) /* start mailbox */ 201#define WDSC_MMSTART(m) (0xc0 + (m)) /* start all mailboxes */ 202 203/* WDS_HCR (write) defs */ 204#define WDSH_IRQEN 0x08 205#define WDSH_DRQEN 0x04 206#define WDSH_SCSIRESET 0x02 207#define WDSH_ASCRESET 0x01 208 209struct wds_cmd { 210 u_int8_t cmd; 211 u_int8_t targ; 212 u_int8_t scb[12]; 213 u_int8_t stat; 214 u_int8_t venderr; 215 u_int8_t len[3]; 216 u_int8_t data[3]; 217 u_int8_t next[3]; 218 u_int8_t write; 219 u_int8_t xx[6]; 220}; 221 222struct wds_req { 223 struct wds_cmd cmd; 224 union ccb *ccb; 225 enum { 226 WR_DONE = 0x01, 227 WR_SENSE = 0x02 228 } flags; 229 u_int8_t *buf; /* address of linear data buffer */ 230 u_int32_t mask; /* mask of allocated fragments */ 231 u_int8_t ombn; 232 u_int8_t id; /* number of request */ 233}; 234 235#define WDSX_SCSICMD 0x00 236#define WDSX_OPEN_RCVBUF 0x80 237#define WDSX_RCV_CMD 0x81 238#define WDSX_RCV_DATA 0x82 239#define WDSX_RCV_DATASTAT 0x83 240#define WDSX_SND_DATA 0x84 241#define WDSX_SND_DATASTAT 0x85 242#define WDSX_SND_CMDSTAT 0x86 243#define WDSX_READINIT 0x88 244#define WDSX_READSCSIID 0x89 245#define WDSX_SETUNSOLIRQMASK 0x8a 246#define WDSX_GETUNSOLIRQMASK 0x8b 247#define WDSX_GETFIRMREV 0x8c 248#define WDSX_EXECDIAG 0x8d 249#define WDSX_SETEXECPARM 0x8e 250#define WDSX_GETEXECPARM 0x8f 251 252struct wds_mb { 253 u_int8_t stat; 254 u_int8_t addr[3]; 255}; 256/* ICMB status value */ 257#define ICMB_OK 0x01 258#define ICMB_OKERR 0x02 259#define ICMB_ETIME 0x04 260#define ICMB_ERESET 0x05 261#define ICMB_ETARCMD 0x06 262#define ICMB_ERESEL 0x80 263#define ICMB_ESEL 0x81 264#define ICMB_EABORT 0x82 265#define ICMB_ESRESET 0x83 266#define ICMB_EHRESET 0x84 267 268struct wds_setup { 269 u_int8_t cmd; 270 u_int8_t scsi_id; 271 u_int8_t buson_t; 272 u_int8_t busoff_t; 273 u_int8_t xx; 274 u_int8_t mbaddr[3]; 275 u_int8_t nomb; 276 u_int8_t nimb; 277}; 278 279/* the code depends on equality of these parameters */ 280#define MAXSIMUL 8 281#define WDS_NOMB MAXSIMUL 282#define WDS_NIMB MAXSIMUL 283 284static int fragsiz; 285static int nfrags; 286 287/* structure for data exchange with controller */ 288 289struct wdsdx { 290 struct wds_req req[MAXSIMUL]; 291 struct wds_mb ombs[MAXSIMUL]; 292 struct wds_mb imbs[MAXSIMUL]; 293 u_int8_t data[BUFSIZ]; 294}; 295 296/* structure softc */ 297 298struct wds { 299 device_t dev; 300 int unit; 301 int addr; 302 int drq; 303 struct cam_sim *sim; /* SIM descriptor for this card */ 304 struct cam_path *path; /* wildcard path for this card */ 305 char want_wdsr; /* resource shortage flag */ 306 u_int32_t data_free; 307 u_int32_t wdsr_free; 308 struct wdsdx *dx; 309 struct wdsdx *dx_p; /* physical address */ 310 struct resource *port_r; 311 int port_rid; 312 struct resource *drq_r; 313 int drq_rid; 314 struct resource *intr_r; 315 int intr_rid; 316 void *intr_cookie; 317 bus_dma_tag_t bustag; 318 bus_dmamap_t busmap; 319}; 320 321#define ccb_wdsr spriv_ptr1 /* for wds request */ 322 323static int wds_probe(device_t dev); 324static int wds_attach(device_t dev); 325static void wds_intr(struct wds *wp); 326 327static void wds_action(struct cam_sim * sim, union ccb * ccb); 328static void wds_poll(struct cam_sim * sim); 329 330static int wds_preinit(struct wds *wp); 331static int wds_init(struct wds *wp); 332 333static void wds_alloc_callback(void *arg, bus_dma_segment_t *seg, 334 int nseg, int error); 335static void wds_free_resources(struct wds *wp); 336 337static struct wds_req *wdsr_alloc(struct wds *wp); 338 339static void wds_scsi_io(struct cam_sim * sim, struct ccb_scsiio * csio); 340static void wdsr_ccb_done(struct wds *wp, struct wds_req *r, 341 union ccb *ccb, u_int32_t status); 342 343static void wds_done(struct wds *wp, struct wds_req *r, u_int8_t stat); 344static int wds_runsense(struct wds *wp, struct wds_req *r); 345static int wds_getvers(struct wds *wp); 346 347static int wds_cmd(int base, u_int8_t * p, int l); 348static void wds_wait(int reg, int mask, int val); 349 350static struct wds_req *cmdtovirt(struct wds *wp, u_int32_t phys); 351 352static u_int32_t frag_alloc(struct wds *wp, int size, u_int8_t **res, 353 u_int32_t *maskp); 354static void frag_free(struct wds *wp, u_int32_t mask); 355 356void wds_print(void); 357 358#if WDS_ENABLE_SMALLOG==1 359static __inline void smallog(char c); 360void wds_printsmallog(void); 361#endif /* SMALLOG */ 362 363/* SCSI ID of the adapter itself */ 364#ifndef WDS_HBA_ID 365#define WDS_HBA_ID 7 366#endif 367 368#if WDS_DEBUG == 2 369#define LOGLINESIZ 81 370#define NLOGLINES 300 371#define DBX wds_nextlog(), LOGLINESIZ, 372#define DBG snprintf 373 374static char wds_log[NLOGLINES][LOGLINESIZ]; 375static int logwrite = 0, logread = 0; 376static char *wds_nextlog(void); 377void wds_printlog(void); 378 379#elif WDS_DEBUG != 0 380#define DBX 381#define DBG printf 382#else 383#define DBX 384#define DBG if(0) printf 385#endif 386 387/* the table of supported bus methods */ 388static device_method_t wds_isa_methods[] = { 389 DEVMETHOD(device_probe, wds_probe), 390 DEVMETHOD(device_attach, wds_attach), 391 { 0, 0 } 392}; 393 394static driver_t wds_isa_driver = { 395 "wds", 396 wds_isa_methods, 397 sizeof(struct wds), 398}; 399 400static devclass_t wds_devclass; 401 402DRIVER_MODULE(wds, isa, wds_isa_driver, wds_devclass, 0, 0); 403 404#if WDS_ENABLE_SMALLOG==1 405#define SMALLOGSIZ 512 406static char wds_smallog[SMALLOGSIZ]; 407static char *wds_smallogp = wds_smallog; 408static char wds_smallogover = 0; 409 410static __inline void 411smallog(char c) 412{ 413 *wds_smallogp = c; 414 if (++wds_smallogp == &wds_smallog[SMALLOGSIZ]) { 415 wds_smallogp = wds_smallog; 416 wds_smallogover = 1; 417 } 418} 419 420#define smallog2(a, b) (smallog(a), smallog(b)) 421#define smallog3(a, b, c) (smallog(a), smallog(b), smallog(c)) 422#define smallog4(a, b, c, d) (smallog(a),smallog(b),smallog(c),smallog(d)) 423 424void 425wds_printsmallog(void) 426{ 427 int i; 428 char *p; 429 430 printf("wds: "); 431 p = wds_smallogover ? wds_smallogp : wds_smallog; 432 i = 0; 433 do { 434 printf("%c", *p); 435 if (++p == &wds_smallog[SMALLOGSIZ]) 436 p = wds_smallog; 437 if (++i == 70) { 438 i = 0; 439 printf("\nwds: "); 440 } 441 } while (p != wds_smallogp); 442 printf("\n"); 443} 444#else 445#define smallog(a) 446#define smallog2(a, b) 447#define smallog3(a, b, c) 448#define smallog4(a, b, c, d) 449#endif /* SMALLOG */ 450 451static int 452wds_probe(device_t dev) 453{ 454 struct wds *wp; 455 int error = 0; 456 int irq; 457 458 /* No pnp support */ 459 if (isa_get_vendorid(dev)) 460 return (ENXIO); 461 462 wp = (struct wds *) device_get_softc(dev); 463 wp->unit = device_get_unit(dev); 464 wp->dev = dev; 465 466 wp->addr = bus_get_resource_start(dev, SYS_RES_IOPORT, 0 /*rid*/); 467 if (wp->addr == 0 || wp->addr <0x300 468 || wp->addr > 0x3f8 || wp->addr & 0x7) { 469 device_printf(dev, "invalid port address 0x%x\n", wp->addr); 470 return (ENXIO); 471 } 472 473 if (bus_set_resource(dev, SYS_RES_IOPORT, 0, wp->addr, WDS_NPORTS) < 0) 474 return (ENXIO); 475 476 /* get the DRQ */ 477 wp->drq = bus_get_resource_start(dev, SYS_RES_DRQ, 0 /*rid*/); 478 if (wp->drq < 5 || wp->drq > 7) { 479 device_printf(dev, "invalid DRQ %d\n", wp->drq); 480 return (ENXIO); 481 } 482 483 /* get the IRQ */ 484 irq = bus_get_resource_start(dev, SYS_RES_IRQ, 0 /*rid*/); 485 if (irq < 3) { 486 device_printf(dev, "invalid IRQ %d\n", irq); 487 return (ENXIO); 488 } 489 490 wp->port_rid = 0; 491 wp->port_r = bus_alloc_resource(dev, SYS_RES_IOPORT, &wp->port_rid, 492 /*start*/ 0, /*end*/ ~0, 493 /*count*/ 0, RF_ACTIVE); 494 if (wp->port_r == NULL) 495 return (ENXIO); 496 497 error = wds_preinit(wp); 498 499 /* 500 * We cannot hold resources between probe and 501 * attach as we may never be attached. 502 */ 503 wds_free_resources(wp); 504 505 return (error); 506} 507 508static int 509wds_attach(device_t dev) 510{ 511 struct wds *wp; 512 struct cam_devq *devq; 513 struct cam_sim *sim; 514 struct cam_path *pathp; 515 int i; 516 int error = 0; 517 518 wp = (struct wds *)device_get_softc(dev); 519 520 wp->port_rid = 0; 521 wp->port_r = bus_alloc_resource(dev, SYS_RES_IOPORT, &wp->port_rid, 522 /*start*/ 0, /*end*/ ~0, 523 /*count*/ 0, RF_ACTIVE); 524 if (wp->port_r == NULL) 525 return (ENXIO); 526 527 /* We must now release resources on error. */ 528 529 wp->drq_rid = 0; 530 wp->drq_r = bus_alloc_resource(dev, SYS_RES_DRQ, &wp->drq_rid, 531 /*start*/ 0, /*end*/ ~0, 532 /*count*/ 0, RF_ACTIVE); 533 if (wp->drq_r == NULL) 534 goto bad; 535 536 wp->intr_rid = 0; 537 wp->intr_r = bus_alloc_resource(dev, SYS_RES_IRQ, &wp->intr_rid, 538 /*start*/ 0, /*end*/ ~0, 539 /*count*/ 0, RF_ACTIVE); 540 if (wp->intr_r == NULL) 541 goto bad; 542 error = bus_setup_intr(dev, wp->intr_r, INTR_TYPE_CAM | INTR_ENTROPY, 543 (driver_intr_t *)wds_intr, (void *)wp, 544 &wp->intr_cookie); 545 if (error) 546 goto bad; 547 548 /* now create the memory buffer */ 549 error = bus_dma_tag_create(NULL, /*alignment*/4, 550 /*boundary*/0, 551 /*lowaddr*/BUS_SPACE_MAXADDR_24BIT, 552 /*highaddr*/ BUS_SPACE_MAXADDR, 553 /*filter*/ NULL, /*filterarg*/ NULL, 554 /*maxsize*/ sizeof(* wp->dx), 555 /*nsegments*/ 1, 556 /*maxsegsz*/ sizeof(* wp->dx), /*flags*/ 0, 557 &wp->bustag); 558 if (error) 559 goto bad; 560 561 error = bus_dmamem_alloc(wp->bustag, (void **)&wp->dx, 562 /*flags*/ 0, &wp->busmap); 563 if (error) 564 goto bad; 565 566 bus_dmamap_load(wp->bustag, wp->busmap, (void *)wp->dx, 567 sizeof(* wp->dx), wds_alloc_callback, 568 (void *)&wp->dx_p, /*flags*/0); 569 570 /* initialize the wds_req structures on this unit */ 571 for(i=0; i<MAXSIMUL; i++) { 572 wp->dx->req[i].id = i; 573 wp->wdsr_free |= 1<<i; 574 } 575 576 /* initialize the memory buffer allocation for this unit */ 577 if (BUFSIZ / FRAGSIZ > 32) { 578 fragsiz = (BUFSIZ / 32) & ~0x01; /* keep it word-aligned */ 579 device_printf(dev, "data buffer fragment size too small. " 580 "BUFSIZE / FRAGSIZE must be <= 32\n"); 581 } else 582 fragsiz = FRAGSIZ & ~0x01; /* keep it word-aligned */ 583 584 wp->data_free = 0; 585 nfrags = 0; 586 for (i = fragsiz; i <= BUFSIZ; i += fragsiz) { 587 nfrags++; 588 wp->data_free = (wp->data_free << 1) | 1; 589 } 590 591 /* complete the hardware initialization */ 592 if (wds_init(wp) != 0) 593 goto bad; 594 595 if (wds_getvers(wp) == -1) 596 device_printf(dev, "getvers failed\n"); 597 device_printf(dev, "using %d bytes / %d frags for dma buffer\n", 598 BUFSIZ, nfrags); 599 600 devq = cam_simq_alloc(MAXSIMUL); 601 if (devq == NULL) 602 goto bad; 603 604 sim = cam_sim_alloc(wds_action, wds_poll, "wds", (void *) wp, 605 wp->unit, 1, 1, devq); 606 if (sim == NULL) { 607 cam_simq_free(devq); 608 goto bad; 609 } 610 wp->sim = sim; 611 612 if (xpt_bus_register(sim, 0) != CAM_SUCCESS) { 613 cam_sim_free(sim, /* free_devq */ TRUE); 614 goto bad; 615 } 616 if (xpt_create_path(&pathp, /* periph */ NULL, 617 cam_sim_path(sim), CAM_TARGET_WILDCARD, 618 CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 619 xpt_bus_deregister(cam_sim_path(sim)); 620 cam_sim_free(sim, /* free_devq */ TRUE); 621 goto bad; 622 } 623 wp->path = pathp; 624 625 return (0); 626 627bad: 628 wds_free_resources(wp); 629 if (error) 630 return (error); 631 else /* exact error is unknown */ 632 return (ENXIO); 633} 634 635/* callback to save the physical address */ 636static void 637wds_alloc_callback(void *arg, bus_dma_segment_t *seg, int nseg, int error) 638{ 639 *(bus_addr_t *)arg = seg[0].ds_addr; 640} 641 642static void 643wds_free_resources(struct wds *wp) 644{ 645 /* check every resource and free if not zero */ 646 647 /* interrupt handler */ 648 if (wp->intr_r) { 649 bus_teardown_intr(wp->dev, wp->intr_r, wp->intr_cookie); 650 bus_release_resource(wp->dev, SYS_RES_IRQ, wp->intr_rid, 651 wp->intr_r); 652 wp->intr_r = 0; 653 } 654 655 /* all kinds of memory maps we could have allocated */ 656 if (wp->dx_p) { 657 bus_dmamap_unload(wp->bustag, wp->busmap); 658 wp->dx_p = 0; 659 } 660 if (wp->dx) { /* wp->busmap may be legitimately equal to 0 */ 661 /* the map will also be freed */ 662 bus_dmamem_free(wp->bustag, wp->dx, wp->busmap); 663 wp->dx = 0; 664 } 665 if (wp->bustag) { 666 bus_dma_tag_destroy(wp->bustag); 667 wp->bustag = 0; 668 } 669 /* release all the bus resources */ 670 if (wp->drq_r) { 671 bus_release_resource(wp->dev, SYS_RES_DRQ, 672 wp->drq_rid, wp->drq_r); 673 wp->drq_r = 0; 674 } 675 if (wp->port_r) { 676 bus_release_resource(wp->dev, SYS_RES_IOPORT, 677 wp->port_rid, wp->port_r); 678 wp->port_r = 0; 679 } 680} 681 682/* allocate contiguous fragments from the buffer */ 683static u_int32_t 684frag_alloc(struct wds *wp, int size, u_int8_t **res, u_int32_t *maskp) 685{ 686 int i; 687 u_int32_t mask; 688 u_int32_t free; 689 690 if (size > fragsiz * nfrags) 691 return (CAM_REQ_TOO_BIG); 692 693 mask = 1; /* always allocate at least 1 fragment */ 694 for (i = fragsiz; i < size; i += fragsiz) 695 mask = (mask << 1) | 1; 696 697 free = wp->data_free; 698 if(free != 0) { 699 i = ffs(free)-1; /* ffs counts bits from 1 */ 700 for (mask <<= i; i < nfrags; i++) { 701 if ((free & mask) == mask) { 702 wp->data_free &= ~mask; /* mark frags as busy */ 703 *maskp = mask; 704 *res = &wp->dx->data[fragsiz * i]; 705 DBG(DBX "wds%d: allocated buffer mask=0x%x\n", 706 wp->unit, mask); 707 return (CAM_REQ_CMP); 708 } 709 if (mask & 0x80000000) 710 break; 711 712 mask <<= 1; 713 } 714 } 715 return (CAM_REQUEUE_REQ); /* no free memory now, try later */ 716} 717 718static void 719frag_free(struct wds *wp, u_int32_t mask) 720{ 721 wp->data_free |= mask; /* mark frags as free */ 722 DBG(DBX "wds%d: freed buffer mask=0x%x\n", wp->unit, mask); 723} 724 725static struct wds_req * 726wdsr_alloc(struct wds *wp) 727{ 728 struct wds_req *r; 729 int x; 730 int i; 731 732 r = NULL; 733 x = splcam(); 734 735 /* anyway most of the time only 1 or 2 commands will 736 * be active because SCSI disconnect is not supported 737 * by hardware, so the search should be fast enough 738 */ 739 i = ffs(wp->wdsr_free) - 1; 740 if(i < 0) { 741 splx(x); 742 return (NULL); 743 } 744 wp->wdsr_free &= ~ (1<<i); 745 r = &wp->dx->req[i]; 746 r->flags = 0; /* reset all flags */ 747 r->ombn = i; /* luckily we have one omb per wdsr */ 748 wp->dx->ombs[i].stat = 1; 749 750 r->mask = 0; 751 splx(x); 752 smallog3('r', i + '0', r->ombn + '0'); 753 return (r); 754} 755 756static void 757wds_intr(struct wds *wp) 758{ 759 struct wds_req *rp; 760 struct wds_mb *in; 761 u_int8_t stat; 762 u_int8_t c; 763 int addr = wp->addr; 764 765 DBG(DBX "wds%d: interrupt [\n", wp->unit); 766 smallog('['); 767 768 if (inb(addr + WDS_STAT) & WDS_IRQ) { 769 c = inb(addr + WDS_IRQSTAT); 770 if ((c & WDSI_MASK) == WDSI_MSVC) { 771 c = c & ~WDSI_MASK; 772 in = &wp->dx->imbs[c]; 773 774 rp = cmdtovirt(wp, scsi_3btoul(in->addr)); 775 stat = in->stat; 776 777 if (rp != NULL) 778 wds_done(wp, rp, stat); 779 else 780 device_printf(wp->dev, 781 "got weird command address %p" 782 "from controller\n", rp); 783 784 in->stat = 0; 785 } else 786 device_printf(wp->dev, 787 "weird interrupt, irqstat=0x%x\n", c); 788 outb(addr + WDS_IRQACK, 0); 789 } else { 790 smallog('?'); 791 } 792 smallog(']'); 793 DBG(DBX "wds%d: ]\n", wp->unit); 794} 795 796static void 797wds_done(struct wds *wp, struct wds_req *r, u_int8_t stat) 798{ 799 struct ccb_hdr *ccb_h; 800 struct ccb_scsiio *csio; 801 int status; 802 803 smallog('d'); 804 805 if (r->flags & WR_DONE) { 806 device_printf(wp->dev, 807 "request %d reported done twice\n", r->id); 808 smallog2('x', r->id + '0'); 809 return; 810 } 811 812 smallog(r->id + '0'); 813 ccb_h = &r->ccb->ccb_h; 814 csio = &r->ccb->csio; 815 status = CAM_REQ_CMP_ERR; 816 817 DBG(DBX "wds%d: %s stat=0x%x c->stat=0x%x c->venderr=0x%x\n", wp->unit, 818 r->flags & WR_SENSE ? "(sense)" : "", 819 stat, r->cmd.stat, r->cmd.venderr); 820 821 if (r->flags & WR_SENSE) { 822 if (stat == ICMB_OK || (stat == ICMB_OKERR && r->cmd.stat == 0)) { 823 DBG(DBX "wds%d: sense 0x%x\n", wp->unit, r->buf[0]); 824 /* it has the same size now but for future */ 825 bcopy(r->buf, &csio->sense_data, 826 sizeof(struct scsi_sense_data) > csio->sense_len ? 827 csio->sense_len : sizeof(struct scsi_sense_data)); 828 if (sizeof(struct scsi_sense_data) >= csio->sense_len) 829 csio->sense_resid = 0; 830 else 831 csio->sense_resid = 832 csio->sense_len 833 - sizeof(struct scsi_sense_data); 834 status = CAM_AUTOSNS_VALID | CAM_SCSI_STATUS_ERROR; 835 } else { 836 status = CAM_AUTOSENSE_FAIL; 837 } 838 } else { 839 switch (stat) { 840 case ICMB_OK: 841 if (ccb_h) { 842 csio->resid = 0; 843 csio->scsi_status = r->cmd.stat; 844 status = CAM_REQ_CMP; 845 } 846 break; 847 case ICMB_OKERR: 848 if (ccb_h) { 849 csio->scsi_status = r->cmd.stat; 850 if (r->cmd.stat) { 851 if (ccb_h->flags & CAM_DIS_AUTOSENSE) 852 status = CAM_SCSI_STATUS_ERROR; 853 else { 854 if ( wds_runsense(wp, r) == CAM_REQ_CMP ) 855 return; 856 /* in case of error continue with freeing of CCB */ 857 } 858 } else { 859 csio->resid = 0; 860 status = CAM_REQ_CMP; 861 } 862 } 863 break; 864 case ICMB_ETIME: 865 if (ccb_h) 866 status = CAM_SEL_TIMEOUT; 867 break; 868 case ICMB_ERESET: 869 case ICMB_ETARCMD: 870 case ICMB_ERESEL: 871 case ICMB_ESEL: 872 case ICMB_EABORT: 873 case ICMB_ESRESET: 874 case ICMB_EHRESET: 875 if (ccb_h) 876 status = CAM_REQ_CMP_ERR; 877 break; 878 } 879 880 if (ccb_h && (ccb_h->flags & CAM_DIR_MASK) == CAM_DIR_IN) { 881 /* we accept only virtual addresses in wds_action() */ 882 bcopy(r->buf, csio->data_ptr, csio->dxfer_len); 883 } 884 } 885 886 r->flags |= WR_DONE; 887 wp->dx->ombs[r->ombn].stat = 0; 888 889 if (ccb_h) { 890 wdsr_ccb_done(wp, r, r->ccb, status); 891 smallog3('-', ccb_h->target_id + '0', ccb_h->target_lun + '0'); 892 } else { 893 frag_free(wp, r->mask); 894 if (wp->want_wdsr) { 895 wp->want_wdsr = 0; 896 xpt_release_simq(wp->sim, /* run queue */ 1); 897 } 898 wp->wdsr_free |= (1 << r->id); 899 } 900 901 DBG(DBX "wds%d: request %p done\n", wp->unit, r); 902} 903 904/* command returned bad status, request sense */ 905 906static int 907wds_runsense(struct wds *wp, struct wds_req *r) 908{ 909 u_int8_t c; 910 struct ccb_hdr *ccb_h; 911 912 ccb_h = &r->ccb->ccb_h; 913 914 r->flags |= WR_SENSE; 915 scsi_ulto3b(WDSTOPHYS(wp, &r->cmd), 916 wp->dx->ombs[r->ombn].addr); 917 bzero(&r->cmd, sizeof r->cmd); 918 r->cmd.cmd = WDSX_SCSICMD; 919 r->cmd.targ = (ccb_h->target_id << 5) | 920 ccb_h->target_lun; 921 922 scsi_ulto3b(0, r->cmd.next); 923 924 r->cmd.scb[0] = REQUEST_SENSE; 925 r->cmd.scb[1] = ccb_h->target_lun << 5; 926 r->cmd.scb[4] = sizeof(struct scsi_sense_data); 927 r->cmd.scb[5] = 0; 928 scsi_ulto3b(WDSTOPHYS(wp, r->buf), r->cmd.data); 929 scsi_ulto3b(sizeof(struct scsi_sense_data), r->cmd.len); 930 r->cmd.write = 0x80; 931 932 outb(wp->addr + WDS_HCR, WDSH_IRQEN | WDSH_DRQEN); 933 934 wp->dx->ombs[r->ombn].stat = 1; 935 c = WDSC_MSTART(r->ombn); 936 937 if (wds_cmd(wp->addr, &c, sizeof c) != 0) { 938 device_printf(wp->dev, "unable to start outgoing sense mbox\n"); 939 wp->dx->ombs[r->ombn].stat = 0; 940 wdsr_ccb_done(wp, r, r->ccb, CAM_AUTOSENSE_FAIL); 941 return CAM_AUTOSENSE_FAIL; 942 } else { 943 DBG(DBX "wds%d: enqueued status cmd 0x%x, r=%p\n", 944 wp->unit, r->cmd.scb[0] & 0xFF, r); 945 /* don't free CCB yet */ 946 smallog3('*', ccb_h->target_id + '0', 947 ccb_h->target_lun + '0'); 948 return CAM_REQ_CMP; 949 } 950} 951 952static int 953wds_getvers(struct wds *wp) 954{ 955 struct wds_req *r; 956 int base; 957 u_int8_t c; 958 int i; 959 960 base = wp->addr; 961 962 r = wdsr_alloc(wp); 963 if (!r) { 964 device_printf(wp->dev, "no request slot available!\n"); 965 return (-1); 966 } 967 r->flags &= ~WR_DONE; 968 969 r->ccb = NULL; 970 971 scsi_ulto3b(WDSTOPHYS(wp, &r->cmd), wp->dx->ombs[r->ombn].addr); 972 973 bzero(&r->cmd, sizeof r->cmd); 974 r->cmd.cmd = WDSX_GETFIRMREV; 975 976 outb(base + WDS_HCR, WDSH_DRQEN); 977 978 c = WDSC_MSTART(r->ombn); 979 if (wds_cmd(base, (u_int8_t *) & c, sizeof c)) { 980 device_printf(wp->dev, "version request failed\n"); 981 wp->wdsr_free |= (1 << r->id); 982 wp->dx->ombs[r->ombn].stat = 0; 983 return (-1); 984 } 985 while (1) { 986 i = 0; 987 while ((inb(base + WDS_STAT) & WDS_IRQ) == 0) { 988 DELAY(9000); 989 if (++i == 100) { 990 device_printf(wp->dev, "getvers timeout\n"); 991 return (-1); 992 } 993 } 994 wds_intr(wp); 995 if (r->flags & WR_DONE) { 996 device_printf(wp->dev, "firmware version %d.%02d\n", 997 r->cmd.targ, r->cmd.scb[0]); 998 wp->wdsr_free |= (1 << r->id); 999 return (0); 1000 } 1001 } 1002} 1003 1004static void 1005wdsr_ccb_done(struct wds *wp, struct wds_req *r, 1006 union ccb *ccb, u_int32_t status) 1007{ 1008 ccb->ccb_h.ccb_wdsr = 0; 1009 1010 if (r != NULL) { 1011 /* To implement timeouts we would need to know how to abort the 1012 * command on controller, and this is a great mystery. 1013 * So for now we just pass the responsibility for timeouts 1014 * to the controlles itself, it does that reasonably good. 1015 */ 1016 /* untimeout(_timeout, (caddr_t) hcb, ccb->ccb_h.timeout_ch); */ 1017 /* we're about to free a hcb, so the shortage has ended */ 1018 frag_free(wp, r->mask); 1019 if (wp->want_wdsr && status != CAM_REQUEUE_REQ) { 1020 wp->want_wdsr = 0; 1021 status |= CAM_RELEASE_SIMQ; 1022 smallog('R'); 1023 } 1024 wp->wdsr_free |= (1 << r->id); 1025 } 1026 ccb->ccb_h.status = 1027 status | (ccb->ccb_h.status & ~(CAM_STATUS_MASK | CAM_SIM_QUEUED)); 1028 xpt_done(ccb); 1029} 1030 1031static void 1032wds_scsi_io(struct cam_sim * sim, struct ccb_scsiio * csio) 1033{ 1034 int unit = cam_sim_unit(sim); 1035 struct wds *wp; 1036 struct ccb_hdr *ccb_h; 1037 struct wds_req *r; 1038 int base; 1039 u_int8_t c; 1040 int error; 1041 int n; 1042 1043 wp = (struct wds *)cam_sim_softc(sim); 1044 ccb_h = &csio->ccb_h; 1045 1046 DBG(DBX "wds%d: cmd TARG=%d LUN=%d\n", unit, ccb_h->target_id, 1047 ccb_h->target_lun); 1048 1049 if (ccb_h->target_id > 7 || ccb_h->target_id == WDS_HBA_ID) { 1050 ccb_h->status = CAM_TID_INVALID; 1051 xpt_done((union ccb *) csio); 1052 return; 1053 } 1054 if (ccb_h->target_lun > 7) { 1055 ccb_h->status = CAM_LUN_INVALID; 1056 xpt_done((union ccb *) csio); 1057 return; 1058 } 1059 if (csio->dxfer_len > BUFSIZ) { 1060 ccb_h->status = CAM_REQ_TOO_BIG; 1061 xpt_done((union ccb *) csio); 1062 return; 1063 } 1064 if (ccb_h->flags & (CAM_CDB_PHYS | CAM_SCATTER_VALID | CAM_DATA_PHYS)) { 1065 /* don't support these */ 1066 ccb_h->status = CAM_REQ_INVALID; 1067 xpt_done((union ccb *) csio); 1068 return; 1069 } 1070 base = wp->addr; 1071 1072 /* 1073 * this check is mostly for debugging purposes, 1074 * "can't happen" normally. 1075 */ 1076 if(wp->want_wdsr) { 1077 DBG(DBX "wds%d: someone already waits for buffer\n", unit); 1078 smallog('b'); 1079 n = xpt_freeze_simq(sim, /* count */ 1); 1080 smallog('0'+n); 1081 ccb_h->status = CAM_REQUEUE_REQ; 1082 xpt_done((union ccb *) csio); 1083 return; 1084 } 1085 1086 r = wdsr_alloc(wp); 1087 if (r == NULL) { 1088 device_printf(wp->dev, "no request slot available!\n"); 1089 wp->want_wdsr = 1; 1090 n = xpt_freeze_simq(sim, /* count */ 1); 1091 smallog2('f', '0'+n); 1092 ccb_h->status = CAM_REQUEUE_REQ; 1093 xpt_done((union ccb *) csio); 1094 return; 1095 } 1096 1097 ccb_h->ccb_wdsr = (void *) r; 1098 r->ccb = (union ccb *) csio; 1099 1100 switch (error = frag_alloc(wp, csio->dxfer_len, &r->buf, &r->mask)) { 1101 case CAM_REQ_CMP: 1102 break; 1103 case CAM_REQUEUE_REQ: 1104 DBG(DBX "wds%d: no data buffer available\n", unit); 1105 wp->want_wdsr = 1; 1106 n = xpt_freeze_simq(sim, /* count */ 1); 1107 smallog2('f', '0'+n); 1108 wdsr_ccb_done(wp, r, r->ccb, CAM_REQUEUE_REQ); 1109 return; 1110 default: 1111 DBG(DBX "wds%d: request is too big\n", unit); 1112 wdsr_ccb_done(wp, r, r->ccb, error); 1113 break; 1114 } 1115 1116 ccb_h->status |= CAM_SIM_QUEUED; 1117 r->flags &= ~WR_DONE; 1118 1119 scsi_ulto3b(WDSTOPHYS(wp, &r->cmd), wp->dx->ombs[r->ombn].addr); 1120 1121 bzero(&r->cmd, sizeof r->cmd); 1122 r->cmd.cmd = WDSX_SCSICMD; 1123 r->cmd.targ = (ccb_h->target_id << 5) | ccb_h->target_lun; 1124 1125 if (ccb_h->flags & CAM_CDB_POINTER) 1126 bcopy(csio->cdb_io.cdb_ptr, &r->cmd.scb, 1127 csio->cdb_len < 12 ? csio->cdb_len : 12); 1128 else 1129 bcopy(csio->cdb_io.cdb_bytes, &r->cmd.scb, 1130 csio->cdb_len < 12 ? csio->cdb_len : 12); 1131 1132 scsi_ulto3b(csio->dxfer_len, r->cmd.len); 1133 1134 if (csio->dxfer_len > 0 1135 && (ccb_h->flags & CAM_DIR_MASK) == CAM_DIR_OUT) { 1136 /* we already rejected physical or scattered addresses */ 1137 bcopy(csio->data_ptr, r->buf, csio->dxfer_len); 1138 } 1139 scsi_ulto3b(csio->dxfer_len ? WDSTOPHYS(wp, r->buf) : 0, r->cmd.data); 1140 1141 if ((ccb_h->flags & CAM_DIR_MASK) == CAM_DIR_IN) 1142 r->cmd.write = 0x80; 1143 else 1144 r->cmd.write = 0x00; 1145 1146 scsi_ulto3b(0, r->cmd.next); 1147 1148 outb(base + WDS_HCR, WDSH_IRQEN | WDSH_DRQEN); 1149 1150 c = WDSC_MSTART(r->ombn); 1151 1152 if (wds_cmd(base, &c, sizeof c) != 0) { 1153 device_printf(wp->dev, "unable to start outgoing mbox\n"); 1154 wp->dx->ombs[r->ombn].stat = 0; 1155 wdsr_ccb_done(wp, r, r->ccb, CAM_RESRC_UNAVAIL); 1156 return; 1157 } 1158 DBG(DBX "wds%d: enqueued cmd 0x%x, r=%p\n", unit, 1159 r->cmd.scb[0] & 0xFF, r); 1160 1161 smallog3('+', ccb_h->target_id + '0', ccb_h->target_lun + '0'); 1162} 1163 1164static void 1165wds_action(struct cam_sim * sim, union ccb * ccb) 1166{ 1167 int unit = cam_sim_unit(sim); 1168 int s; 1169 1170 DBG(DBX "wds%d: action 0x%x\n", unit, ccb->ccb_h.func_code); 1171 switch (ccb->ccb_h.func_code) { 1172 case XPT_SCSI_IO: 1173 s = splcam(); 1174 DBG(DBX "wds%d: SCSI IO entered\n", unit); 1175 wds_scsi_io(sim, &ccb->csio); 1176 DBG(DBX "wds%d: SCSI IO returned\n", unit); 1177 splx(s); 1178 break; 1179 case XPT_RESET_BUS: 1180 /* how to do it right ? */ 1181 printf("wds%d: reset\n", unit); 1182 ccb->ccb_h.status = CAM_REQ_CMP; 1183 xpt_done(ccb); 1184 break; 1185 case XPT_ABORT: 1186 ccb->ccb_h.status = CAM_UA_ABORT; 1187 xpt_done(ccb); 1188 break; 1189 case XPT_CALC_GEOMETRY: 1190 { 1191 struct ccb_calc_geometry *ccg; 1192 u_int32_t size_mb; 1193 u_int32_t secs_per_cylinder; 1194 1195 ccg = &ccb->ccg; 1196 size_mb = ccg->volume_size 1197 / ((1024L * 1024L) / ccg->block_size); 1198 1199 ccg->heads = 64; 1200 ccg->secs_per_track = 16; 1201 secs_per_cylinder = ccg->heads * ccg->secs_per_track; 1202 ccg->cylinders = ccg->volume_size / secs_per_cylinder; 1203 ccb->ccb_h.status = CAM_REQ_CMP; 1204 xpt_done(ccb); 1205 break; 1206 } 1207 case XPT_PATH_INQ: /* Path routing inquiry */ 1208 { 1209 struct ccb_pathinq *cpi = &ccb->cpi; 1210 1211 cpi->version_num = 1; /* XXX??? */ 1212 cpi->hba_inquiry = 0; /* nothing fancy */ 1213 cpi->target_sprt = 0; 1214 cpi->hba_misc = 0; 1215 cpi->hba_eng_cnt = 0; 1216 cpi->max_target = 7; 1217 cpi->max_lun = 7; 1218 cpi->initiator_id = WDS_HBA_ID; 1219 cpi->hba_misc = 0; 1220 cpi->bus_id = cam_sim_bus(sim); 1221 cpi->base_transfer_speed = 3300; 1222 strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 1223 strncpy(cpi->hba_vid, "WD/FDC", HBA_IDLEN); 1224 strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 1225 cpi->unit_number = cam_sim_unit(sim); 1226 cpi->ccb_h.status = CAM_REQ_CMP; 1227 xpt_done(ccb); 1228 break; 1229 } 1230 default: 1231 ccb->ccb_h.status = CAM_REQ_INVALID; 1232 xpt_done(ccb); 1233 break; 1234 } 1235} 1236 1237static void 1238wds_poll(struct cam_sim * sim) 1239{ 1240 wds_intr((struct wds *)cam_sim_softc(sim)); 1241} 1242 1243/* part of initialization done in probe() */ 1244/* returns 0 if OK, ENXIO if bad */ 1245 1246static int 1247wds_preinit(struct wds *wp) 1248{ 1249 int base; 1250 int i; 1251 1252 base = wp->addr; 1253 1254 /* 1255 * Sending a command causes the CMDRDY bit to clear. 1256 */ 1257 outb(base + WDS_CMD, WDSC_NOOP); 1258 if (inb(base + WDS_STAT) & WDS_RDY) 1259 return (ENXIO); 1260 1261 /* 1262 * the controller exists. reset and init. 1263 */ 1264 outb(base + WDS_HCR, WDSH_ASCRESET | WDSH_SCSIRESET); 1265 DELAY(30); 1266 outb(base + WDS_HCR, 0); 1267 1268 if ((inb(base + WDS_STAT) & (WDS_RDY)) != WDS_RDY) { 1269 for (i = 0; i < 10; i++) { 1270 if ((inb(base + WDS_STAT) & (WDS_RDY)) == WDS_RDY) 1271 break; 1272 DELAY(40000); 1273 } 1274 if ((inb(base + WDS_STAT) & (WDS_RDY)) != WDS_RDY) 1275 /* probe timeout */ 1276 return (ENXIO); 1277 } 1278 1279 return (0); 1280} 1281 1282/* part of initialization done in attach() */ 1283/* returns 0 if OK, 1 if bad */ 1284 1285static int 1286wds_init(struct wds *wp) 1287{ 1288 struct wds_setup init; 1289 int base; 1290 int i; 1291 struct wds_cmd wc; 1292 1293 base = wp->addr; 1294 1295 outb(base + WDS_HCR, WDSH_DRQEN); 1296 1297 isa_dmacascade(wp->drq); 1298 1299 if ((inb(base + WDS_STAT) & (WDS_RDY)) != WDS_RDY) { 1300 for (i = 0; i < 10; i++) { 1301 if ((inb(base + WDS_STAT) & (WDS_RDY)) == WDS_RDY) 1302 break; 1303 DELAY(40000); 1304 } 1305 if ((inb(base + WDS_STAT) & (WDS_RDY)) != WDS_RDY) 1306 /* probe timeout */ 1307 return (1); 1308 } 1309 bzero(&init, sizeof init); 1310 init.cmd = WDSC_INIT; 1311 init.scsi_id = WDS_HBA_ID; 1312 init.buson_t = 24; 1313 init.busoff_t = 48; 1314 scsi_ulto3b(WDSTOPHYS(wp, &wp->dx->ombs), init.mbaddr); 1315 init.xx = 0; 1316 init.nomb = WDS_NOMB; 1317 init.nimb = WDS_NIMB; 1318 1319 wds_wait(base + WDS_STAT, WDS_RDY, WDS_RDY); 1320 if (wds_cmd(base, (u_int8_t *) & init, sizeof init) != 0) { 1321 device_printf(wp->dev, "wds_cmd init failed\n"); 1322 return (1); 1323 } 1324 wds_wait(base + WDS_STAT, WDS_INIT, WDS_INIT); 1325 1326 wds_wait(base + WDS_STAT, WDS_RDY, WDS_RDY); 1327 1328 bzero(&wc, sizeof wc); 1329 wc.cmd = WDSC_DISUNSOL; 1330 if (wds_cmd(base, (char *) &wc, sizeof wc) != 0) { 1331 device_printf(wp->dev, "wds_cmd init2 failed\n"); 1332 return (1); 1333 } 1334 return (0); 1335} 1336 1337static int 1338wds_cmd(int base, u_int8_t * p, int l) 1339{ 1340 int s = splcam(); 1341 1342 while (l--) { 1343 do { 1344 outb(base + WDS_CMD, *p); 1345 wds_wait(base + WDS_STAT, WDS_RDY, WDS_RDY); 1346 } while (inb(base + WDS_STAT) & WDS_REJ); 1347 p++; 1348 } 1349 1350 wds_wait(base + WDS_STAT, WDS_RDY, WDS_RDY); 1351 1352 splx(s); 1353 1354 return (0); 1355} 1356 1357static void 1358wds_wait(int reg, int mask, int val) 1359{ 1360 while ((inb(reg) & mask) != val) 1361 ; 1362} 1363 1364static struct wds_req * 1365cmdtovirt(struct wds *wp, u_int32_t phys) 1366{ 1367 char *a; 1368 1369 a = WDSTOVIRT(wp, (uintptr_t)phys); 1370 if( a < (char *)&wp->dx->req[0] || a>= (char *)&wp->dx->req[MAXSIMUL]) { 1371 device_printf(wp->dev, "weird phys address 0x%x\n", phys); 1372 return (NULL); 1373 } 1374 a -= (int)offsetof(struct wds_req, cmd); /* convert cmd to request */ 1375 return ((struct wds_req *)a); 1376} 1377 1378/* for debugging, print out all the data about the status of devices */ 1379void 1380wds_print(void) 1381{ 1382 int unit; 1383 int i; 1384 struct wds_req *r; 1385 struct wds *wp; 1386 1387 for (unit = 0; unit < devclass_get_maxunit(wds_devclass); unit++) { 1388 wp = (struct wds *) devclass_get_device(wds_devclass, unit); 1389 if (wp == NULL) 1390 continue; 1391 printf("wds%d: want_wdsr=0x%x stat=0x%x irq=%s irqstat=0x%x\n", 1392 unit, wp->want_wdsr, inb(wp->addr + WDS_STAT) & 0xff, 1393 (inb(wp->addr + WDS_STAT) & WDS_IRQ) ? "ready" : "no", 1394 inb(wp->addr + WDS_IRQSTAT) & 0xff); 1395 for (i = 0; i < MAXSIMUL; i++) { 1396 r = &wp->dx->req[i]; 1397 if( wp->wdsr_free & (1 << r->id) ) { 1398 printf("req=%d flg=0x%x ombn=%d ombstat=%d " 1399 "mask=0x%x targ=%d lun=%d cmd=0x%x\n", 1400 i, r->flags, r->ombn, 1401 wp->dx->ombs[r->ombn].stat, 1402 r->mask, r->cmd.targ >> 5, 1403 r->cmd.targ & 7, r->cmd.scb[0]); 1404 } 1405 } 1406 } 1407} 1408 1409#if WDS_DEBUG == 2 1410/* create circular log buffer */ 1411static char * 1412wds_nextlog(void) 1413{ 1414 int n = logwrite; 1415 1416 if (++logwrite >= NLOGLINES) 1417 logwrite = 0; 1418 if (logread == logwrite) 1419 if (++logread >= NLOGLINES) 1420 logread = 0; 1421 return (wds_log[n]); 1422} 1423 1424void 1425wds_printlog(void) 1426{ 1427 /* print the circular buffer */ 1428 int i; 1429 1430 for (i = logread; i != logwrite;) { 1431 printf("%s", wds_log[i]); 1432 if (i == NLOGLINES) 1433 i = 0; 1434 else 1435 i++; 1436 } 1437} 1438#endif /* WDS_DEBUG */ 1439