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