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