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