1 /* $NetBSD: uha.c,v 1.8 1997/06/06 23:31:05 thorpej Exp $ */ 2 3 #undef UHADEBUG 4 #ifdef DDB 5 #define integrate 6 #else 7 #define integrate static inline 8 #endif 9 10 /*- 11 * Copyright (c) 1997 The NetBSD Foundation, Inc. 12 * All rights reserved. 13 * 14 * This code is derived from software contributed to The NetBSD Foundation 15 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 16 * NASA Ames Research Center. 17 * 18 * Redistribution and use in source and binary forms, with or without 19 * modification, are permitted provided that the following conditions 20 * are met: 21 * 1. Redistributions of source code must retain the above copyright 22 * notice, this list of conditions and the following disclaimer. 23 * 2. Redistributions in binary form must reproduce the above copyright 24 * notice, this list of conditions and the following disclaimer in the 25 * documentation and/or other materials provided with the distribution. 26 * 3. All advertising materials mentioning features or use of this software 27 * must display the following acknowledgement: 28 * This product includes software developed by the NetBSD 29 * Foundation, Inc. and its contributors. 30 * 4. Neither the name of The NetBSD Foundation nor the names of its 31 * contributors may be used to endorse or promote products derived 32 * from this software without specific prior written permission. 33 * 34 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 35 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 36 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 37 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 38 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 39 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 40 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 41 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 42 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 43 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 44 * POSSIBILITY OF SUCH DAMAGE. 45 */ 46 47 /* 48 * Copyright (c) 1994, 1996, 1997 Charles M. Hannum. All rights reserved. 49 * 50 * Redistribution and use in source and binary forms, with or without 51 * modification, are permitted provided that the following conditions 52 * are met: 53 * 1. Redistributions of source code must retain the above copyright 54 * notice, this list of conditions and the following disclaimer. 55 * 2. Redistributions in binary form must reproduce the above copyright 56 * notice, this list of conditions and the following disclaimer in the 57 * documentation and/or other materials provided with the distribution. 58 * 3. All advertising materials mentioning features or use of this software 59 * must display the following acknowledgement: 60 * This product includes software developed by Charles M. Hannum. 61 * 4. The name of the author may not be used to endorse or promote products 62 * derived from this software without specific prior written permission. 63 * 64 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 65 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 66 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 67 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 68 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 69 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 70 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 71 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 72 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 73 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 74 */ 75 76 /* 77 * Ported for use with the UltraStor 14f by Gary Close (gclose@wvnvms.wvnet.edu) 78 * Slight fixes to timeouts to run with the 34F 79 * Thanks to Julian Elischer for advice and help with this port. 80 * 81 * Originally written by Julian Elischer (julian@tfs.com) 82 * for TRW Financial Systems for use under the MACH(2.5) operating system. 83 * 84 * TRW Financial Systems, in accordance with their agreement with Carnegie 85 * Mellon University, makes this software available to CMU to distribute 86 * or use in any manner that they see fit as long as this message is kept with 87 * the software. For this reason TFS also grants any other persons or 88 * organisations permission to use or modify this software. 89 * 90 * TFS supplies this software to be publicly redistributed 91 * on the understanding that TFS is not responsible for the correct 92 * functioning of this software in any circumstances. 93 * 94 * commenced: Sun Sep 27 18:14:01 PDT 1992 95 * slight mod to make work with 34F as well: Wed Jun 2 18:05:48 WST 1993 96 */ 97 98 #include <sys/types.h> 99 #include <sys/param.h> 100 #include <sys/systm.h> 101 #include <sys/kernel.h> 102 #include <sys/errno.h> 103 #include <sys/ioctl.h> 104 #include <sys/device.h> 105 #include <sys/malloc.h> 106 #include <sys/buf.h> 107 #include <sys/proc.h> 108 #include <sys/user.h> 109 110 #include <machine/bus.h> 111 #include <machine/intr.h> 112 113 #include <scsi/scsi_all.h> 114 #include <scsi/scsiconf.h> 115 116 #include <dev/ic/uhareg.h> 117 #include <dev/ic/uhavar.h> 118 119 #ifndef DDB 120 #define Debugger() panic("should call debugger here (uha.c)") 121 #endif /* ! DDB */ 122 123 #define UHA_MAXXFER ((UHA_NSEG - 1) << PGSHIFT) 124 125 integrate void uha_reset_mscp __P((struct uha_softc *, struct uha_mscp *)); 126 void uha_free_mscp __P((struct uha_softc *, struct uha_mscp *)); 127 integrate void uha_init_mscp __P((struct uha_softc *, struct uha_mscp *)); 128 struct uha_mscp *uha_get_mscp __P((struct uha_softc *, int)); 129 void uhaminphys __P((struct buf *)); 130 int uha_scsi_cmd __P((struct scsi_xfer *)); 131 int uha_create_mscps __P((struct uha_softc *, void *, size_t)); 132 133 struct scsi_adapter uha_switch = { 134 uha_scsi_cmd, 135 uhaminphys, 136 0, 137 0, 138 }; 139 140 /* the below structure is so we have a default dev struct for out link struct */ 141 struct scsi_device uha_dev = { 142 NULL, /* Use default error handler */ 143 NULL, /* have a queue, served by this */ 144 NULL, /* have no async handler */ 145 NULL, /* Use default 'done' routine */ 146 }; 147 148 struct cfdriver uha_cd = { 149 NULL, "uha", DV_DULL 150 }; 151 152 #define UHA_ABORT_TIMEOUT 2000 /* time to wait for abort (mSec) */ 153 154 /* XXX Should put this in a better place. */ 155 #define offsetof(type, member) ((size_t)(&((type *)0)->member)) 156 157 /* 158 * Attach all the sub-devices we can find 159 */ 160 void 161 uha_attach(sc, upd) 162 struct uha_softc *sc; 163 struct uha_probe_data *upd; 164 { 165 166 TAILQ_INIT(&sc->sc_free_mscp); 167 168 (sc->init)(sc); 169 170 /* 171 * fill in the prototype scsi_link. 172 */ 173 sc->sc_link.channel = SCSI_CHANNEL_ONLY_ONE; 174 sc->sc_link.adapter_softc = sc; 175 sc->sc_link.adapter_target = upd->sc_scsi_dev; 176 sc->sc_link.adapter = &uha_switch; 177 sc->sc_link.device = &uha_dev; 178 sc->sc_link.openings = 2; 179 sc->sc_link.max_target = 7; 180 181 /* 182 * ask the adapter what subunits are present 183 */ 184 config_found(&sc->sc_dev, &sc->sc_link, scsiprint); 185 } 186 187 integrate void 188 uha_reset_mscp(sc, mscp) 189 struct uha_softc *sc; 190 struct uha_mscp *mscp; 191 { 192 193 mscp->flags = 0; 194 } 195 196 /* 197 * A mscp (and hence a mbx-out) is put onto the free list. 198 */ 199 void 200 uha_free_mscp(sc, mscp) 201 struct uha_softc *sc; 202 struct uha_mscp *mscp; 203 { 204 int s; 205 206 s = splbio(); 207 208 uha_reset_mscp(sc, mscp); 209 TAILQ_INSERT_HEAD(&sc->sc_free_mscp, mscp, chain); 210 211 /* 212 * If there were none, wake anybody waiting for one to come free, 213 * starting with queued entries. 214 */ 215 if (mscp->chain.tqe_next == 0) 216 wakeup(&sc->sc_free_mscp); 217 218 splx(s); 219 } 220 221 integrate void 222 uha_init_mscp(sc, mscp) 223 struct uha_softc *sc; 224 struct uha_mscp *mscp; 225 { 226 bus_dma_tag_t dmat = sc->sc_dmat; 227 int hashnum; 228 229 /* 230 * XXX Should we put a DIAGNOSTIC check for multiple 231 * XXX MSCP inits here? 232 */ 233 234 bzero(mscp, sizeof(struct uha_mscp)); 235 236 /* 237 * Create the DMA maps for this MSCP. 238 */ 239 if (bus_dmamap_create(dmat, sizeof(struct uha_mscp), 1, 240 sizeof(struct uha_mscp), 0, BUS_DMA_NOWAIT | sc->sc_dmaflags, 241 &mscp->dmamap_self) || 242 243 /* XXX What's a good value for this? */ 244 bus_dmamap_create(dmat, UHA_MAXXFER, UHA_NSEG, UHA_MAXXFER, 245 0, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW | sc->sc_dmaflags, 246 &mscp->dmamap_xfer)) 247 panic("uha_init_mscp: can't create DMA maps"); 248 249 /* 250 * Load the permanent DMA maps. 251 */ 252 if (bus_dmamap_load(dmat, mscp->dmamap_self, mscp, 253 sizeof(struct uha_mscp), NULL, BUS_DMA_NOWAIT)) 254 panic("uha_init_mscp: can't load permanent maps"); 255 256 /* 257 * put in the phystokv hash table 258 * Never gets taken out. 259 */ 260 mscp->hashkey = mscp->dmamap_self->dm_segs[0].ds_addr; 261 hashnum = MSCP_HASH(mscp->hashkey); 262 mscp->nexthash = sc->sc_mscphash[hashnum]; 263 sc->sc_mscphash[hashnum] = mscp; 264 uha_reset_mscp(sc, mscp); 265 } 266 267 /* 268 * Create a set of MSCPs and add them to the free list. 269 */ 270 int 271 uha_create_mscps(sc, mem, size) 272 struct uha_softc *sc; 273 void *mem; 274 size_t size; 275 { 276 bus_dma_segment_t seg; 277 struct uha_mscp *mscp; 278 int rseg, error; 279 280 if (sc->sc_nummscps >= UHA_MSCP_MAX) 281 return (0); 282 283 if ((mscp = mem) != NULL) 284 goto have_mem; 285 286 size = NBPG; 287 error = bus_dmamem_alloc(sc->sc_dmat, size, NBPG, 0, &seg, 1, &rseg, 288 BUS_DMA_NOWAIT); 289 if (error) 290 return (error); 291 292 error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, size, 293 (caddr_t *)&mscp, BUS_DMA_NOWAIT|BUS_DMAMEM_NOSYNC); 294 if (error) { 295 bus_dmamem_free(sc->sc_dmat, &seg, rseg); 296 return (error); 297 } 298 299 have_mem: 300 bzero(mscp, size); 301 while (size > sizeof(struct uha_mscp)) { 302 uha_init_mscp(sc, mscp); 303 sc->sc_nummscps++; 304 TAILQ_INSERT_TAIL(&sc->sc_free_mscp, mscp, chain); 305 (caddr_t)mscp += ALIGN(sizeof(struct uha_mscp)); 306 size -= ALIGN(sizeof(struct uha_mscp)); 307 if (sc->sc_nummscps >= UHA_MSCP_MAX) 308 break; 309 } 310 311 return (0); 312 } 313 314 /* 315 * Get a free mscp 316 * 317 * If there are none, see if we can allocate a new one. If so, put it in the 318 * hash table too otherwise either return an error or sleep. 319 */ 320 struct uha_mscp * 321 uha_get_mscp(sc, flags) 322 struct uha_softc *sc; 323 int flags; 324 { 325 struct uha_mscp *mscp; 326 int s; 327 328 s = splbio(); 329 330 /* 331 * If we can and have to, sleep waiting for one to come free 332 * but only if we can't allocate a new one 333 */ 334 for (;;) { 335 mscp = sc->sc_free_mscp.tqh_first; 336 if (mscp) { 337 TAILQ_REMOVE(&sc->sc_free_mscp, mscp, chain); 338 break; 339 } 340 if (sc->sc_nummscps < UHA_MSCP_MAX) { 341 if (uha_create_mscps(sc, NULL, 0)) { 342 printf("%s: can't allocate mscps\n", 343 sc->sc_dev.dv_xname); 344 goto out; 345 } 346 continue; 347 } 348 if ((flags & SCSI_NOSLEEP) != 0) 349 goto out; 350 tsleep(&sc->sc_free_mscp, PRIBIO, "uhamsc", 0); 351 } 352 353 mscp->flags |= MSCP_ALLOC; 354 355 out: 356 splx(s); 357 return (mscp); 358 } 359 360 /* 361 * given a physical address, find the mscp that it corresponds to. 362 */ 363 struct uha_mscp * 364 uha_mscp_phys_kv(sc, mscp_phys) 365 struct uha_softc *sc; 366 u_long mscp_phys; 367 { 368 int hashnum = MSCP_HASH(mscp_phys); 369 struct uha_mscp *mscp = sc->sc_mscphash[hashnum]; 370 371 while (mscp) { 372 if (mscp->hashkey == mscp_phys) 373 break; 374 mscp = mscp->nexthash; 375 } 376 return (mscp); 377 } 378 379 /* 380 * We have a mscp which has been processed by the adaptor, now we look to see 381 * how the operation went. 382 */ 383 void 384 uha_done(sc, mscp) 385 struct uha_softc *sc; 386 struct uha_mscp *mscp; 387 { 388 bus_dma_tag_t dmat = sc->sc_dmat; 389 struct scsi_sense_data *s1, *s2; 390 struct scsi_xfer *xs = mscp->xs; 391 392 SC_DEBUG(xs->sc_link, SDEV_DB2, ("uha_done\n")); 393 394 /* 395 * If we were a data transfer, unload the map that described 396 * the data buffer. 397 */ 398 if (xs->datalen) { 399 bus_dmamap_sync(dmat, mscp->dmamap_xfer, 400 (xs->flags & SCSI_DATA_IN) ? BUS_DMASYNC_POSTREAD : 401 BUS_DMASYNC_POSTWRITE); 402 bus_dmamap_unload(dmat, mscp->dmamap_xfer); 403 } 404 405 /* 406 * Otherwise, put the results of the operation 407 * into the xfer and call whoever started it 408 */ 409 if ((mscp->flags & MSCP_ALLOC) == 0) { 410 printf("%s: exiting ccb not allocated!\n", sc->sc_dev.dv_xname); 411 Debugger(); 412 return; 413 } 414 if (xs->error == XS_NOERROR) { 415 if (mscp->host_stat != UHA_NO_ERR) { 416 switch (mscp->host_stat) { 417 case UHA_SBUS_TIMEOUT: /* No response */ 418 xs->error = XS_SELTIMEOUT; 419 break; 420 default: /* Other scsi protocol messes */ 421 printf("%s: host_stat %x\n", 422 sc->sc_dev.dv_xname, mscp->host_stat); 423 xs->error = XS_DRIVER_STUFFUP; 424 } 425 } else if (mscp->target_stat != SCSI_OK) { 426 switch (mscp->target_stat) { 427 case SCSI_CHECK: 428 s1 = &mscp->mscp_sense; 429 s2 = &xs->sense; 430 *s2 = *s1; 431 xs->error = XS_SENSE; 432 break; 433 case SCSI_BUSY: 434 xs->error = XS_BUSY; 435 break; 436 default: 437 printf("%s: target_stat %x\n", 438 sc->sc_dev.dv_xname, mscp->target_stat); 439 xs->error = XS_DRIVER_STUFFUP; 440 } 441 } else 442 xs->resid = 0; 443 } 444 uha_free_mscp(sc, mscp); 445 xs->flags |= ITSDONE; 446 scsi_done(xs); 447 } 448 449 void 450 uhaminphys(bp) 451 struct buf *bp; 452 { 453 454 if (bp->b_bcount > UHA_MAXXFER) 455 bp->b_bcount = UHA_MAXXFER; 456 minphys(bp); 457 } 458 459 /* 460 * start a scsi operation given the command and the data address. Also 461 * needs the unit, target and lu. 462 */ 463 int 464 uha_scsi_cmd(xs) 465 struct scsi_xfer *xs; 466 { 467 struct scsi_link *sc_link = xs->sc_link; 468 struct uha_softc *sc = sc_link->adapter_softc; 469 bus_dma_tag_t dmat = sc->sc_dmat; 470 struct uha_mscp *mscp; 471 struct uha_dma_seg *sg; 472 int error, seg, flags, s; 473 474 SC_DEBUG(sc_link, SDEV_DB2, ("uha_scsi_cmd\n")); 475 /* 476 * get a mscp (mbox-out) to use. If the transfer 477 * is from a buf (possibly from interrupt time) 478 * then we can't allow it to sleep 479 */ 480 flags = xs->flags; 481 if ((mscp = uha_get_mscp(sc, flags)) == NULL) { 482 xs->error = XS_DRIVER_STUFFUP; 483 return (TRY_AGAIN_LATER); 484 } 485 mscp->xs = xs; 486 mscp->timeout = xs->timeout; 487 488 /* 489 * Put all the arguments for the xfer in the mscp 490 */ 491 if (flags & SCSI_RESET) { 492 mscp->opcode = UHA_SDR; 493 mscp->ca = 0x01; 494 } else { 495 mscp->opcode = UHA_TSP; 496 /* XXX Not for tapes. */ 497 mscp->ca = 0x01; 498 bcopy(xs->cmd, &mscp->scsi_cmd, mscp->scsi_cmd_length); 499 } 500 mscp->xdir = UHA_SDET; 501 mscp->dcn = 0x00; 502 mscp->chan = 0x00; 503 mscp->target = sc_link->target; 504 mscp->lun = sc_link->lun; 505 mscp->scsi_cmd_length = xs->cmdlen; 506 mscp->sense_ptr = mscp->dmamap_self->dm_segs[0].ds_addr + 507 offsetof(struct uha_mscp, mscp_sense); 508 mscp->req_sense_length = sizeof(mscp->mscp_sense); 509 mscp->host_stat = 0x00; 510 mscp->target_stat = 0x00; 511 512 if (xs->datalen) { 513 sg = mscp->uha_dma; 514 seg = 0; 515 #ifdef TFS 516 if (flags & SCSI_DATA_UIO) { 517 error = bus_dmamap_load_uio(dmat, 518 mscp->dmamap_xfer, (struct uio *)xs->data, 519 (flags & SCSI_NOSLEEP) ? BUS_DMA_NOWAIT : 520 BUS_DMA_WAITOK); 521 } else 522 #endif /*TFS */ 523 { 524 error = bus_dmamap_load(dmat, 525 mscp->dmamap_xfer, xs->data, xs->datalen, NULL, 526 (flags & SCSI_NOSLEEP) ? BUS_DMA_NOWAIT : 527 BUS_DMA_WAITOK); 528 } 529 530 if (error) { 531 if (error == EFBIG) { 532 printf("%s: uha_scsi_cmd, more than %d" 533 " dma segments\n", 534 sc->sc_dev.dv_xname, UHA_NSEG); 535 } else { 536 printf("%s: uha_scsi_cmd, error %d loading" 537 " dma map\n", 538 sc->sc_dev.dv_xname, error); 539 } 540 goto bad; 541 } 542 543 bus_dmamap_sync(dmat, mscp->dmamap_xfer, 544 (flags & SCSI_DATA_IN) ? BUS_DMASYNC_PREREAD : 545 BUS_DMASYNC_PREWRITE); 546 547 /* 548 * Load the hardware scatter/gather map with the 549 * contents of the DMA map. 550 */ 551 for (seg = 0; seg < mscp->dmamap_xfer->dm_nsegs; seg++) { 552 mscp->uha_dma[seg].seg_addr = 553 mscp->dmamap_xfer->dm_segs[seg].ds_addr; 554 mscp->uha_dma[seg].seg_len = 555 mscp->dmamap_xfer->dm_segs[seg].ds_len; 556 } 557 558 mscp->data_addr = mscp->dmamap_self->dm_segs[0].ds_addr + 559 offsetof(struct uha_mscp, uha_dma); 560 mscp->data_length = xs->datalen; 561 mscp->sgth = 0x01; 562 mscp->sg_num = seg; 563 } else { /* No data xfer, use non S/G values */ 564 mscp->data_addr = (physaddr)0; 565 mscp->data_length = 0; 566 mscp->sgth = 0x00; 567 mscp->sg_num = 0; 568 } 569 mscp->link_id = 0; 570 mscp->link_addr = (physaddr)0; 571 572 s = splbio(); 573 (sc->start_mbox)(sc, mscp); 574 splx(s); 575 576 /* 577 * Usually return SUCCESSFULLY QUEUED 578 */ 579 if ((flags & SCSI_POLL) == 0) 580 return (SUCCESSFULLY_QUEUED); 581 582 /* 583 * If we can't use interrupts, poll on completion 584 */ 585 if ((sc->poll)(sc, xs, mscp->timeout)) { 586 uha_timeout(mscp); 587 if ((sc->poll)(sc, xs, mscp->timeout)) 588 uha_timeout(mscp); 589 } 590 return (COMPLETE); 591 592 bad: 593 xs->error = XS_DRIVER_STUFFUP; 594 uha_free_mscp(sc, mscp); 595 return (COMPLETE); 596 } 597 598 void 599 uha_timeout(arg) 600 void *arg; 601 { 602 struct uha_mscp *mscp = arg; 603 struct scsi_xfer *xs = mscp->xs; 604 struct scsi_link *sc_link = xs->sc_link; 605 struct uha_softc *sc = sc_link->adapter_softc; 606 int s; 607 608 sc_print_addr(sc_link); 609 printf("timed out"); 610 611 s = splbio(); 612 613 if (mscp->flags & MSCP_ABORT) { 614 /* abort timed out */ 615 printf(" AGAIN\n"); 616 /* XXX Must reset! */ 617 } else { 618 /* abort the operation that has timed out */ 619 printf("\n"); 620 mscp->xs->error = XS_TIMEOUT; 621 mscp->timeout = UHA_ABORT_TIMEOUT; 622 mscp->flags |= MSCP_ABORT; 623 (sc->start_mbox)(sc, mscp); 624 } 625 626 splx(s); 627 } 628