1 /* $OpenBSD: uha.c,v 1.4 2002/03/14 01:26:55 millert Exp $ */ 2 /* $NetBSD: uha.c,v 1.3 1996/10/13 01:37:29 christos Exp $ */ 3 4 #undef UHADEBUG 5 #ifdef DDB 6 #define integrate 7 #else 8 #define integrate static inline 9 #endif 10 11 /* 12 * Copyright (c) 1994, 1996 Charles M. Hannum. All rights reserved. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions 16 * are met: 17 * 1. Redistributions of source code must retain the above copyright 18 * notice, this list of conditions and the following disclaimer. 19 * 2. Redistributions in binary form must reproduce the above copyright 20 * notice, this list of conditions and the following disclaimer in the 21 * documentation and/or other materials provided with the distribution. 22 * 3. All advertising materials mentioning features or use of this software 23 * must display the following acknowledgement: 24 * This product includes software developed by Charles M. Hannum. 25 * 4. The name of the author may not be used to endorse or promote products 26 * derived from this software without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 29 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 30 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 31 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 32 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 33 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 34 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 35 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 36 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 37 * THIS SOFTWARE, EVEN IF ADVISED OF THE 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/types.h> 63 #include <sys/param.h> 64 #include <sys/systm.h> 65 #include <sys/kernel.h> 66 #include <sys/errno.h> 67 #include <sys/ioctl.h> 68 #include <sys/device.h> 69 #include <sys/malloc.h> 70 #include <sys/buf.h> 71 #include <sys/proc.h> 72 #include <sys/user.h> 73 74 #include <machine/bus.h> 75 #include <machine/intr.h> 76 77 #include <scsi/scsi_all.h> 78 #include <scsi/scsiconf.h> 79 80 #include <dev/ic/uhareg.h> 81 #include <dev/ic/uhavar.h> 82 83 #ifndef DDB 84 #define Debugger() panic("should call debugger here (ultra14f.c)") 85 #endif /* ! DDB */ 86 87 #define KVTOPHYS(x) vtophys(x) 88 89 integrate void uha_reset_mscp(struct uha_softc *, struct uha_mscp *); 90 void uha_free_mscp(struct uha_softc *, struct uha_mscp *); 91 integrate void uha_init_mscp(struct uha_softc *, struct uha_mscp *); 92 struct uha_mscp *uha_get_mscp(struct uha_softc *, int); 93 void uhaminphys(struct buf *); 94 int uha_scsi_cmd(struct scsi_xfer *); 95 96 struct scsi_adapter uha_switch = { 97 uha_scsi_cmd, 98 uhaminphys, 99 0, 100 0, 101 }; 102 103 /* the below structure is so we have a default dev struct for out link struct */ 104 struct scsi_device uha_dev = { 105 NULL, /* Use default error handler */ 106 NULL, /* have a queue, served by this */ 107 NULL, /* have no async handler */ 108 NULL, /* Use default 'done' routine */ 109 }; 110 111 struct cfdriver uha_cd = { 112 NULL, "uha", DV_DULL 113 }; 114 115 #define UHA_ABORT_TIMEOUT 2000 /* time to wait for abort (mSec) */ 116 117 #ifdef __OpenBSD__ 118 int uhaprint(void *, const char *); 119 120 int 121 uhaprint(aux, name) 122 void *aux; 123 const char *name; 124 { 125 126 if (name != NULL) 127 printf("%s: scsibus ", name); 128 return UNCONF; 129 } 130 #endif 131 132 /* 133 * Attach all the sub-devices we can find 134 */ 135 void 136 uha_attach(sc) 137 struct uha_softc *sc; 138 { 139 140 (sc->init)(sc); 141 TAILQ_INIT(&sc->sc_free_mscp); 142 143 /* 144 * fill in the prototype scsi_link. 145 */ 146 #ifndef __OpenBSD__ 147 sc->sc_link.channel = SCSI_CHANNEL_ONLY_ONE; 148 #endif 149 sc->sc_link.adapter_softc = sc; 150 sc->sc_link.adapter_target = sc->sc_scsi_dev; 151 sc->sc_link.adapter = &uha_switch; 152 sc->sc_link.device = &uha_dev; 153 sc->sc_link.openings = 2; 154 155 /* 156 * ask the adapter what subunits are present 157 */ 158 #ifdef __OpenBSD__ 159 config_found(&sc->sc_dev, &sc->sc_link, uhaprint); 160 #else 161 config_found(&sc->sc_dev, &sc->sc_link, scsiprint); 162 #endif 163 } 164 165 integrate void 166 uha_reset_mscp(sc, mscp) 167 struct uha_softc *sc; 168 struct uha_mscp *mscp; 169 { 170 171 mscp->flags = 0; 172 } 173 174 /* 175 * A mscp (and hence a mbx-out) is put onto the free list. 176 */ 177 void 178 uha_free_mscp(sc, mscp) 179 struct uha_softc *sc; 180 struct uha_mscp *mscp; 181 { 182 int s; 183 184 s = splbio(); 185 186 uha_reset_mscp(sc, mscp); 187 TAILQ_INSERT_HEAD(&sc->sc_free_mscp, mscp, chain); 188 189 /* 190 * If there were none, wake anybody waiting for one to come free, 191 * starting with queued entries. 192 */ 193 if (mscp->chain.tqe_next == 0) 194 wakeup(&sc->sc_free_mscp); 195 196 splx(s); 197 } 198 199 integrate void 200 uha_init_mscp(sc, mscp) 201 struct uha_softc *sc; 202 struct uha_mscp *mscp; 203 { 204 int hashnum; 205 206 bzero(mscp, sizeof(struct uha_mscp)); 207 /* 208 * put in the phystokv hash table 209 * Never gets taken out. 210 */ 211 mscp->hashkey = KVTOPHYS(mscp); 212 hashnum = MSCP_HASH(mscp->hashkey); 213 mscp->nexthash = sc->sc_mscphash[hashnum]; 214 sc->sc_mscphash[hashnum] = mscp; 215 uha_reset_mscp(sc, mscp); 216 } 217 218 /* 219 * Get a free mscp 220 * 221 * If there are none, see if we can allocate a new one. If so, put it in the 222 * hash table too otherwise either return an error or sleep. 223 */ 224 struct uha_mscp * 225 uha_get_mscp(sc, flags) 226 struct uha_softc *sc; 227 int flags; 228 { 229 struct uha_mscp *mscp; 230 int s; 231 232 s = splbio(); 233 234 /* 235 * If we can and have to, sleep waiting for one to come free 236 * but only if we can't allocate a new one 237 */ 238 for (;;) { 239 mscp = sc->sc_free_mscp.tqh_first; 240 if (mscp) { 241 TAILQ_REMOVE(&sc->sc_free_mscp, mscp, chain); 242 break; 243 } 244 if (sc->sc_nummscps < UHA_MSCP_MAX) { 245 mscp = (struct uha_mscp *) malloc(sizeof(struct uha_mscp), 246 M_TEMP, M_NOWAIT); 247 if (!mscp) { 248 printf("%s: can't malloc mscp\n", 249 sc->sc_dev.dv_xname); 250 goto out; 251 } 252 uha_init_mscp(sc, mscp); 253 sc->sc_nummscps++; 254 break; 255 } 256 if ((flags & SCSI_NOSLEEP) != 0) 257 goto out; 258 tsleep(&sc->sc_free_mscp, PRIBIO, "uhamsc", 0); 259 } 260 261 mscp->flags |= MSCP_ALLOC; 262 263 out: 264 splx(s); 265 return (mscp); 266 } 267 268 /* 269 * given a physical address, find the mscp that it corresponds to. 270 */ 271 struct uha_mscp * 272 uha_mscp_phys_kv(sc, mscp_phys) 273 struct uha_softc *sc; 274 u_long mscp_phys; 275 { 276 int hashnum = MSCP_HASH(mscp_phys); 277 struct uha_mscp *mscp = sc->sc_mscphash[hashnum]; 278 279 while (mscp) { 280 if (mscp->hashkey == mscp_phys) 281 break; 282 mscp = mscp->nexthash; 283 } 284 return (mscp); 285 } 286 287 /* 288 * We have a mscp which has been processed by the adaptor, now we look to see 289 * how the operation went. 290 */ 291 void 292 uha_done(sc, mscp) 293 struct uha_softc *sc; 294 struct uha_mscp *mscp; 295 { 296 struct scsi_sense_data *s1, *s2; 297 struct scsi_xfer *xs = mscp->xs; 298 299 SC_DEBUG(xs->sc_link, SDEV_DB2, ("uha_done\n")); 300 /* 301 * Otherwise, put the results of the operation 302 * into the xfer and call whoever started it 303 */ 304 if ((mscp->flags & MSCP_ALLOC) == 0) { 305 printf("%s: exiting ccb not allocated!\n", sc->sc_dev.dv_xname); 306 Debugger(); 307 return; 308 } 309 if (xs->error == XS_NOERROR) { 310 if (mscp->host_stat != UHA_NO_ERR) { 311 switch (mscp->host_stat) { 312 case UHA_SBUS_TIMEOUT: /* No response */ 313 xs->error = XS_SELTIMEOUT; 314 break; 315 default: /* Other scsi protocol messes */ 316 printf("%s: host_stat %x\n", 317 sc->sc_dev.dv_xname, mscp->host_stat); 318 xs->error = XS_DRIVER_STUFFUP; 319 } 320 } else if (mscp->target_stat != SCSI_OK) { 321 switch (mscp->target_stat) { 322 case SCSI_CHECK: 323 s1 = &mscp->mscp_sense; 324 s2 = &xs->sense; 325 *s2 = *s1; 326 xs->error = XS_SENSE; 327 break; 328 case SCSI_BUSY: 329 xs->error = XS_BUSY; 330 break; 331 default: 332 printf("%s: target_stat %x\n", 333 sc->sc_dev.dv_xname, mscp->target_stat); 334 xs->error = XS_DRIVER_STUFFUP; 335 } 336 } else 337 xs->resid = 0; 338 } 339 uha_free_mscp(sc, mscp); 340 xs->flags |= ITSDONE; 341 scsi_done(xs); 342 } 343 344 void 345 uhaminphys(bp) 346 struct buf *bp; 347 { 348 349 if (bp->b_bcount > ((UHA_NSEG - 1) << PGSHIFT)) 350 bp->b_bcount = ((UHA_NSEG - 1) << PGSHIFT); 351 minphys(bp); 352 } 353 354 /* 355 * start a scsi operation given the command and the data address. Also 356 * needs the unit, target and lu. 357 */ 358 int 359 uha_scsi_cmd(xs) 360 struct scsi_xfer *xs; 361 { 362 struct scsi_link *sc_link = xs->sc_link; 363 struct uha_softc *sc = sc_link->adapter_softc; 364 struct uha_mscp *mscp; 365 struct uha_dma_seg *sg; 366 int seg; /* scatter gather seg being worked on */ 367 u_long thiskv, thisphys, nextphys; 368 int bytes_this_seg, bytes_this_page, datalen, flags; 369 int s; 370 371 SC_DEBUG(sc_link, SDEV_DB2, ("uha_scsi_cmd\n")); 372 /* 373 * get a mscp (mbox-out) to use. If the transfer 374 * is from a buf (possibly from interrupt time) 375 * then we can't allow it to sleep 376 */ 377 flags = xs->flags; 378 if ((mscp = uha_get_mscp(sc, flags)) == NULL) { 379 xs->error = XS_DRIVER_STUFFUP; 380 return (TRY_AGAIN_LATER); 381 } 382 mscp->xs = xs; 383 mscp->timeout = xs->timeout; 384 timeout_set(&xs->stimeout, uha_timeout, xs); 385 386 /* 387 * Put all the arguments for the xfer in the mscp 388 */ 389 if (flags & SCSI_RESET) { 390 mscp->opcode = UHA_SDR; 391 mscp->ca = 0x01; 392 } else { 393 mscp->opcode = UHA_TSP; 394 /* XXX Not for tapes. */ 395 mscp->ca = 0x01; 396 bcopy(xs->cmd, &mscp->scsi_cmd, mscp->scsi_cmd_length); 397 } 398 mscp->xdir = UHA_SDET; 399 mscp->dcn = 0x00; 400 mscp->chan = 0x00; 401 mscp->target = sc_link->target; 402 mscp->lun = sc_link->lun; 403 mscp->scsi_cmd_length = xs->cmdlen; 404 mscp->sense_ptr = KVTOPHYS(&mscp->mscp_sense); 405 mscp->req_sense_length = sizeof(mscp->mscp_sense); 406 mscp->host_stat = 0x00; 407 mscp->target_stat = 0x00; 408 409 if (xs->datalen) { 410 sg = mscp->uha_dma; 411 seg = 0; 412 #ifdef TFS 413 if (flags & SCSI_DATA_UIO) { 414 struct iovec *iovp; 415 iovp = ((struct uio *) xs->data)->uio_iov; 416 datalen = ((struct uio *) xs->data)->uio_iovcnt; 417 xs->datalen = 0; 418 while (datalen && seg < UHA_NSEG) { 419 sg->seg_addr = (physaddr)iovp->iov_base; 420 sg->seg_len = iovp->iov_len; 421 xs->datalen += iovp->iov_len; 422 SC_DEBUGN(sc_link, SDEV_DB4, ("(0x%x@0x%x)", 423 iovp->iov_len, iovp->iov_base)); 424 sg++; 425 iovp++; 426 seg++; 427 datalen--; 428 } 429 } else 430 #endif /*TFS */ 431 { 432 /* 433 * Set up the scatter gather block 434 */ 435 SC_DEBUG(sc_link, SDEV_DB4, 436 ("%d @0x%x:- ", xs->datalen, xs->data)); 437 datalen = xs->datalen; 438 thiskv = (int) xs->data; 439 thisphys = KVTOPHYS(thiskv); 440 441 while (datalen && seg < UHA_NSEG) { 442 bytes_this_seg = 0; 443 444 /* put in the base address */ 445 sg->seg_addr = thisphys; 446 447 SC_DEBUGN(sc_link, SDEV_DB4, ("0x%x", thisphys)); 448 449 /* do it at least once */ 450 nextphys = thisphys; 451 while (datalen && thisphys == nextphys) { 452 /* 453 * This page is contiguous (physically) 454 * with the the last, just extend the 455 * length 456 */ 457 /* how far to the end of the page */ 458 nextphys = (thisphys & ~PGOFSET) + NBPG; 459 bytes_this_page = nextphys - thisphys; 460 /**** or the data ****/ 461 bytes_this_page = min(bytes_this_page, 462 datalen); 463 bytes_this_seg += bytes_this_page; 464 datalen -= bytes_this_page; 465 466 /* get more ready for the next page */ 467 thiskv = (thiskv & ~PGOFSET) + NBPG; 468 if (datalen) 469 thisphys = KVTOPHYS(thiskv); 470 } 471 /* 472 * next page isn't contiguous, finish the seg 473 */ 474 SC_DEBUGN(sc_link, SDEV_DB4, 475 ("(0x%x)", bytes_this_seg)); 476 sg->seg_len = bytes_this_seg; 477 sg++; 478 seg++; 479 } 480 } 481 /* end of iov/kv decision */ 482 SC_DEBUGN(sc_link, SDEV_DB4, ("\n")); 483 if (datalen) { 484 /* 485 * there's still data, must have run out of segs! 486 */ 487 printf("%s: uha_scsi_cmd, more than %d dma segs\n", 488 sc->sc_dev.dv_xname, UHA_NSEG); 489 goto bad; 490 } 491 mscp->data_addr = KVTOPHYS(mscp->uha_dma); 492 mscp->data_length = xs->datalen; 493 mscp->sgth = 0x01; 494 mscp->sg_num = seg; 495 } else { /* No data xfer, use non S/G values */ 496 mscp->data_addr = (physaddr)0; 497 mscp->data_length = 0; 498 mscp->sgth = 0x00; 499 mscp->sg_num = 0; 500 } 501 mscp->link_id = 0; 502 mscp->link_addr = (physaddr)0; 503 504 s = splbio(); 505 (sc->start_mbox)(sc, mscp); 506 splx(s); 507 508 /* 509 * Usually return SUCCESSFULLY QUEUED 510 */ 511 if ((flags & SCSI_POLL) == 0) 512 return (SUCCESSFULLY_QUEUED); 513 514 /* 515 * If we can't use interrupts, poll on completion 516 */ 517 if ((sc->poll)(sc, xs, mscp->timeout)) { 518 uha_timeout(mscp); 519 if ((sc->poll)(sc, xs, mscp->timeout)) 520 uha_timeout(mscp); 521 } 522 return (COMPLETE); 523 524 bad: 525 xs->error = XS_DRIVER_STUFFUP; 526 uha_free_mscp(sc, mscp); 527 return (COMPLETE); 528 } 529 530 void 531 uha_timeout(arg) 532 void *arg; 533 { 534 struct uha_mscp *mscp = arg; 535 struct scsi_xfer *xs = mscp->xs; 536 struct scsi_link *sc_link = xs->sc_link; 537 struct uha_softc *sc = sc_link->adapter_softc; 538 int s; 539 540 sc_print_addr(sc_link); 541 printf("timed out"); 542 543 s = splbio(); 544 545 if (mscp->flags & MSCP_ABORT) { 546 /* abort timed out */ 547 printf(" AGAIN\n"); 548 /* XXX Must reset! */ 549 } else { 550 /* abort the operation that has timed out */ 551 printf("\n"); 552 mscp->xs->error = XS_TIMEOUT; 553 mscp->timeout = UHA_ABORT_TIMEOUT; 554 mscp->flags |= MSCP_ABORT; 555 (sc->start_mbox)(sc, mscp); 556 } 557 558 splx(s); 559 } 560