1 1.29 thorpej /* $NetBSD: sunscpal.c,v 1.29 2021/08/07 16:19:12 thorpej Exp $ */ 2 1.1 fredette 3 1.1 fredette /* 4 1.1 fredette * Copyright (c) 2001 Matthew Fredette 5 1.1 fredette * Copyright (c) 1995 David Jones, Gordon W. Ross 6 1.1 fredette * Copyright (c) 1994 Jarle Greipsland 7 1.1 fredette * All rights reserved. 8 1.1 fredette * 9 1.1 fredette * Redistribution and use in source and binary forms, with or without 10 1.1 fredette * modification, are permitted provided that the following conditions 11 1.1 fredette * are met: 12 1.1 fredette * 1. Redistributions of source code must retain the above copyright 13 1.1 fredette * notice, this list of conditions and the following disclaimer. 14 1.1 fredette * 2. Redistributions in binary form must reproduce the above copyright 15 1.1 fredette * notice, this list of conditions and the following disclaimer in the 16 1.1 fredette * documentation and/or other materials provided with the distribution. 17 1.1 fredette * 3. The name of the authors may not be used to endorse or promote products 18 1.1 fredette * derived from this software without specific prior written permission. 19 1.1 fredette * 4. All advertising materials mentioning features or use of this software 20 1.1 fredette * must display the following acknowledgement: 21 1.1 fredette * This product includes software developed by 22 1.1 fredette * David Jones and Gordon Ross 23 1.1 fredette * 24 1.1 fredette * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 25 1.1 fredette * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 26 1.1 fredette * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 27 1.1 fredette * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 28 1.1 fredette * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 29 1.1 fredette * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 30 1.1 fredette * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 31 1.1 fredette * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 32 1.1 fredette * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 33 1.1 fredette * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 1.1 fredette */ 35 1.1 fredette 36 1.1 fredette /* 37 1.1 fredette * This is a machine-independent driver for the Sun "sc" 38 1.1 fredette * SCSI Bus Controller (SBC). 39 1.1 fredette * 40 1.1 fredette * This code should work with any memory-mapped card, 41 1.1 fredette * and can be shared by multiple adapters that address 42 1.1 fredette * the card with different register offset spacings. 43 1.1 fredette * (This can happen on the atari, for example.) 44 1.1 fredette * 45 1.1 fredette * Credits, history: 46 1.1 fredette * 47 1.1 fredette * Matthew Fredette completely copied revision 1.38 of 48 1.1 fredette * ncr5380sbc.c, and then heavily modified it to match 49 1.1 fredette * the Sun sc PAL. The remaining credits are for 50 1.1 fredette * ncr5380sbc.c: 51 1.1 fredette * 52 1.1 fredette * David Jones is the author of most of the code that now 53 1.1 fredette * appears in this file, and was the architect of the 54 1.1 fredette * current overall structure (MI/MD code separation, etc.) 55 1.1 fredette * 56 1.1 fredette * Gordon Ross integrated the message phase code, added lots of 57 1.1 fredette * comments about what happens when and why (re. SCSI spec.), 58 1.1 fredette * debugged some reentrance problems, and added several new 59 1.1 fredette * "hooks" needed for the Sun3 "si" adapters. 60 1.1 fredette * 61 1.1 fredette * The message in/out code was taken nearly verbatim from 62 1.1 fredette * the aic6360 driver by Jarle Greipsland. 63 1.1 fredette * 64 1.1 fredette * Several other NCR5380 drivers were used for reference 65 1.1 fredette * while developing this driver, including work by: 66 1.1 fredette * The Alice Group (mac68k port) namely: 67 1.1 fredette * Allen K. Briggs, Chris P. Caputo, Michael L. Finch, 68 1.1 fredette * Bradley A. Grantham, and Lawrence A. Kesteloot 69 1.1 fredette * Michael L. Hitch (amiga drivers: sci.c) 70 1.1 fredette * Leo Weppelman (atari driver: ncr5380.c) 71 1.1 fredette * There are others too. Thanks, everyone. 72 1.1 fredette * 73 1.1 fredette * Transliteration to bus_space() performed 9/17/98 by 74 1.1 fredette * John Ruschmeyer (jruschme (at) exit109.com) for i386 'nca' driver. 75 1.1 fredette * Thank you all. 76 1.1 fredette */ 77 1.9 lukem 78 1.9 lukem #include <sys/cdefs.h> 79 1.29 thorpej __KERNEL_RCSID(0, "$NetBSD: sunscpal.c,v 1.29 2021/08/07 16:19:12 thorpej Exp $"); 80 1.1 fredette 81 1.1 fredette #include "opt_ddb.h" 82 1.1 fredette 83 1.1 fredette #include <sys/param.h> 84 1.1 fredette #include <sys/systm.h> 85 1.1 fredette #include <sys/kernel.h> 86 1.1 fredette #include <sys/errno.h> 87 1.1 fredette #include <sys/malloc.h> 88 1.1 fredette #include <sys/device.h> 89 1.1 fredette #include <sys/buf.h> 90 1.1 fredette #include <sys/proc.h> 91 1.1 fredette 92 1.1 fredette #include <dev/scsipi/scsi_all.h> 93 1.1 fredette #include <dev/scsipi/scsipi_all.h> 94 1.1 fredette #include <dev/scsipi/scsipi_debug.h> 95 1.1 fredette #include <dev/scsipi/scsi_message.h> 96 1.1 fredette #include <dev/scsipi/scsiconf.h> 97 1.1 fredette 98 1.1 fredette #ifdef DDB 99 1.1 fredette #include <ddb/db_output.h> 100 1.1 fredette #endif 101 1.1 fredette 102 1.1 fredette #include <dev/ic/sunscpalreg.h> 103 1.1 fredette #include <dev/ic/sunscpalvar.h> 104 1.1 fredette 105 1.16 perry static void sunscpal_reset_scsibus(struct sunscpal_softc *); 106 1.16 perry static void sunscpal_sched(struct sunscpal_softc *); 107 1.16 perry static void sunscpal_done(struct sunscpal_softc *); 108 1.1 fredette 109 1.23 tsutsui static int sunscpal_select(struct sunscpal_softc *, struct sunscpal_req *); 110 1.16 perry static void sunscpal_reselect(struct sunscpal_softc *); 111 1.1 fredette 112 1.16 perry static int sunscpal_msg_in(struct sunscpal_softc *); 113 1.16 perry static int sunscpal_msg_out(struct sunscpal_softc *); 114 1.16 perry static int sunscpal_data_xfer(struct sunscpal_softc *, int); 115 1.16 perry static int sunscpal_command(struct sunscpal_softc *); 116 1.16 perry static int sunscpal_status(struct sunscpal_softc *); 117 1.16 perry static void sunscpal_machine(struct sunscpal_softc *); 118 1.1 fredette 119 1.16 perry void sunscpal_abort(struct sunscpal_softc *); 120 1.16 perry void sunscpal_cmd_timeout(void *); 121 1.1 fredette /* 122 1.5 wiz * Action flags returned by the info_transfer functions: 123 1.1 fredette * (These determine what happens next.) 124 1.1 fredette */ 125 1.1 fredette #define ACT_CONTINUE 0x00 /* No flags: expect another phase */ 126 1.1 fredette #define ACT_DISCONNECT 0x01 /* Target is disconnecting */ 127 1.1 fredette #define ACT_CMD_DONE 0x02 /* Need to call scsipi_done() */ 128 1.1 fredette #define ACT_RESET_BUS 0x04 /* Need bus reset (cmd timeout) */ 129 1.1 fredette #define ACT_WAIT_DMA 0x10 /* Wait for DMA to complete */ 130 1.1 fredette 131 1.1 fredette /***************************************************************** 132 1.1 fredette * Debugging stuff 133 1.1 fredette *****************************************************************/ 134 1.1 fredette 135 1.1 fredette #ifndef DDB 136 1.1 fredette /* This is used only in recoverable places. */ 137 1.1 fredette #ifndef Debugger 138 1.1 fredette #define Debugger() printf("Debug: sunscpal.c:%d\n", __LINE__) 139 1.1 fredette #endif 140 1.1 fredette #endif 141 1.1 fredette 142 1.1 fredette #ifdef SUNSCPAL_DEBUG 143 1.1 fredette 144 1.1 fredette #define SUNSCPAL_DBG_BREAK 1 145 1.1 fredette #define SUNSCPAL_DBG_CMDS 2 146 1.1 fredette #define SUNSCPAL_DBG_DMA 4 147 1.1 fredette int sunscpal_debug = 0; 148 1.1 fredette #define SUNSCPAL_BREAK() \ 149 1.1 fredette do { if (sunscpal_debug & SUNSCPAL_DBG_BREAK) Debugger(); } while (0) 150 1.16 perry static void sunscpal_show_scsi_cmd(struct scsipi_xfer *); 151 1.1 fredette #ifdef DDB 152 1.16 perry void sunscpal_clear_trace(void); 153 1.16 perry void sunscpal_show_trace(void); 154 1.16 perry void sunscpal_show_req(struct sunscpal_req *); 155 1.16 perry void sunscpal_show_state(void); 156 1.1 fredette #endif /* DDB */ 157 1.1 fredette #else /* SUNSCPAL_DEBUG */ 158 1.1 fredette 159 1.1 fredette #define SUNSCPAL_BREAK() /* nada */ 160 1.1 fredette #define sunscpal_show_scsi_cmd(xs) /* nada */ 161 1.1 fredette 162 1.1 fredette #endif /* SUNSCPAL_DEBUG */ 163 1.1 fredette 164 1.18 tsutsui static const char * 165 1.1 fredette phase_names[8] = { 166 1.1 fredette "DATA_OUT", 167 1.1 fredette "DATA_IN", 168 1.1 fredette "COMMAND", 169 1.1 fredette "STATUS", 170 1.1 fredette "UNSPEC1", 171 1.1 fredette "UNSPEC2", 172 1.1 fredette "MSG_OUT", 173 1.1 fredette "MSG_IN", 174 1.1 fredette }; 175 1.1 fredette 176 1.1 fredette #ifdef SUNSCPAL_USE_BUS_DMA 177 1.16 perry static void sunscpal_dma_alloc(struct sunscpal_softc *); 178 1.16 perry static void sunscpal_dma_free(struct sunscpal_softc *); 179 1.16 perry static void sunscpal_dma_setup(struct sunscpal_softc *); 180 1.1 fredette #else 181 1.1 fredette #define sunscpal_dma_alloc(sc) (*sc->sc_dma_alloc)(sc) 182 1.1 fredette #define sunscpal_dma_free(sc) (*sc->sc_dma_free)(sc) 183 1.1 fredette #define sunscpal_dma_setup(sc) (*sc->sc_dma_setup)(sc) 184 1.1 fredette #endif 185 1.16 perry static void sunscpal_minphys(struct buf *); 186 1.1 fredette 187 1.1 fredette /***************************************************************** 188 1.1 fredette * Actual chip control 189 1.1 fredette *****************************************************************/ 190 1.1 fredette 191 1.1 fredette /* 192 1.1 fredette * XXX: These timeouts might need to be tuned... 193 1.1 fredette */ 194 1.1 fredette 195 1.1 fredette /* This one is used when waiting for a phase change. (X100uS.) */ 196 1.1 fredette int sunscpal_wait_phase_timo = 1000 * 10 * 300; /* 5 min. */ 197 1.1 fredette 198 1.1 fredette /* These are used in the following inline functions. */ 199 1.1 fredette int sunscpal_wait_req_timo = 1000 * 50; /* X2 = 100 mS. */ 200 1.1 fredette int sunscpal_wait_nrq_timo = 1000 * 25; /* X2 = 50 mS. */ 201 1.1 fredette 202 1.20 perry static inline int sunscpal_wait_req(struct sunscpal_softc *); 203 1.20 perry static inline int sunscpal_wait_not_req(struct sunscpal_softc *); 204 1.20 perry static inline void sunscpal_sched_msgout(struct sunscpal_softc *, int); 205 1.1 fredette 206 1.1 fredette /* Return zero on success. */ 207 1.23 tsutsui static inline int sunscpal_wait_req(struct sunscpal_softc *sc) 208 1.1 fredette { 209 1.1 fredette int timo = sunscpal_wait_req_timo; 210 1.23 tsutsui 211 1.1 fredette for (;;) { 212 1.1 fredette if (SUNSCPAL_READ_2(sc, sunscpal_icr) & SUNSCPAL_ICR_REQUEST) { 213 1.1 fredette timo = 0; /* return 0 */ 214 1.1 fredette break; 215 1.1 fredette } 216 1.1 fredette if (--timo < 0) 217 1.1 fredette break; /* return -1 */ 218 1.1 fredette delay(2); 219 1.1 fredette } 220 1.23 tsutsui return timo; 221 1.1 fredette } 222 1.1 fredette 223 1.1 fredette /* Return zero on success. */ 224 1.23 tsutsui static inline int sunscpal_wait_not_req(struct sunscpal_softc *sc) 225 1.1 fredette { 226 1.1 fredette int timo = sunscpal_wait_nrq_timo; 227 1.23 tsutsui 228 1.1 fredette for (;;) { 229 1.23 tsutsui if ((SUNSCPAL_READ_2(sc, sunscpal_icr) & 230 1.23 tsutsui SUNSCPAL_ICR_REQUEST) == 0) { 231 1.1 fredette timo = 0; /* return 0 */ 232 1.1 fredette break; 233 1.1 fredette } 234 1.1 fredette if (--timo < 0) 235 1.1 fredette break; /* return -1 */ 236 1.1 fredette delay(2); 237 1.1 fredette } 238 1.23 tsutsui return timo; 239 1.1 fredette } 240 1.1 fredette 241 1.1 fredette /* 242 1.1 fredette * These functions control DMA functions in the chipset independent of 243 1.1 fredette * the host DMA implementation. 244 1.1 fredette */ 245 1.16 perry static void sunscpal_dma_start(struct sunscpal_softc *); 246 1.16 perry static void sunscpal_dma_poll(struct sunscpal_softc *); 247 1.16 perry static void sunscpal_dma_stop(struct sunscpal_softc *); 248 1.1 fredette 249 1.1 fredette static void 250 1.23 tsutsui sunscpal_dma_start(struct sunscpal_softc *sc) 251 1.1 fredette { 252 1.1 fredette struct sunscpal_req *sr = sc->sc_current; 253 1.1 fredette int xlen; 254 1.23 tsutsui uint16_t icr; 255 1.1 fredette 256 1.1 fredette xlen = sc->sc_reqlen; 257 1.1 fredette 258 1.1 fredette /* Let'er rip! */ 259 1.1 fredette icr = SUNSCPAL_READ_2(sc, sunscpal_icr); 260 1.1 fredette icr |= SUNSCPAL_ICR_DMA_ENABLE | 261 1.17 perry ((xlen & 1) ? 0 : SUNSCPAL_ICR_WORD_MODE) | 262 1.1 fredette ((sr->sr_flags & SR_IMMED) ? 0 : SUNSCPAL_ICR_INTERRUPT_ENABLE); 263 1.1 fredette SUNSCPAL_WRITE_2(sc, sunscpal_icr, icr); 264 1.1 fredette 265 1.1 fredette sc->sc_state |= SUNSCPAL_DOINGDMA; 266 1.1 fredette 267 1.1 fredette #ifdef SUNSCPAL_DEBUG 268 1.1 fredette if (sunscpal_debug & SUNSCPAL_DBG_DMA) { 269 1.23 tsutsui printf("%s: started, flags=0x%x\n", 270 1.23 tsutsui __func__, sc->sc_state); 271 1.1 fredette } 272 1.1 fredette #endif 273 1.1 fredette } 274 1.1 fredette 275 1.1 fredette #define ICR_MASK (SUNSCPAL_ICR_PARITY_ERROR | SUNSCPAL_ICR_BUS_ERROR | SUNSCPAL_ICR_INTERRUPT_REQUEST) 276 1.1 fredette #define POLL_TIMO 50000 /* X100 = 5 sec. */ 277 1.1 fredette 278 1.1 fredette /* 279 1.1 fredette * Poll (spin-wait) for DMA completion. 280 1.1 fredette * Called right after xx_dma_start(), and 281 1.1 fredette * xx_dma_stop() will be called next. 282 1.1 fredette */ 283 1.1 fredette static void 284 1.23 tsutsui sunscpal_dma_poll(struct sunscpal_softc *sc) 285 1.1 fredette { 286 1.1 fredette struct sunscpal_req *sr = sc->sc_current; 287 1.1 fredette int tmo; 288 1.1 fredette 289 1.1 fredette /* Make sure DMA started successfully. */ 290 1.1 fredette if (sc->sc_state & SUNSCPAL_ABORTING) 291 1.1 fredette return; 292 1.1 fredette 293 1.14 wiz /* Wait for any "DMA complete" or error bits. */ 294 1.1 fredette tmo = POLL_TIMO; 295 1.1 fredette for (;;) { 296 1.1 fredette if (SUNSCPAL_READ_2(sc, sunscpal_icr) & ICR_MASK) 297 1.1 fredette break; 298 1.1 fredette if (--tmo <= 0) { 299 1.1 fredette printf("sc: DMA timeout (while polling)\n"); 300 1.1 fredette /* Indicate timeout as MI code would. */ 301 1.1 fredette sr->sr_flags |= SR_OVERDUE; 302 1.1 fredette break; 303 1.1 fredette } 304 1.1 fredette delay(100); 305 1.1 fredette } 306 1.23 tsutsui SUNSCPAL_TRACE("sunscpal_dma_poll: waited %d\n", POLL_TIMO - tmo); 307 1.1 fredette 308 1.1 fredette #ifdef SUNSCPAL_DEBUG 309 1.1 fredette if (sunscpal_debug & SUNSCPAL_DBG_DMA) { 310 1.6 fredette char buffer[64]; 311 1.24 christos snprintb(buffer, sizeof(buffer), 312 1.24 christos SUNSCPAL_READ_2(sc, sunscpal_icr), SUNSCPAL_ICR_BITS); 313 1.23 tsutsui printf("%s: done, icr=%s\n", __func__, buffer); 314 1.1 fredette } 315 1.1 fredette #endif 316 1.1 fredette } 317 1.1 fredette 318 1.1 fredette static void 319 1.23 tsutsui sunscpal_dma_stop(struct sunscpal_softc *sc) 320 1.1 fredette { 321 1.1 fredette struct sunscpal_req *sr = sc->sc_current; 322 1.1 fredette struct scsipi_xfer *xs = sr->sr_xs; 323 1.1 fredette int resid, ntrans; 324 1.23 tsutsui uint16_t icr; 325 1.1 fredette 326 1.1 fredette if ((sc->sc_state & SUNSCPAL_DOINGDMA) == 0) { 327 1.1 fredette #ifdef DEBUG 328 1.23 tsutsui printf("%s: DMA not running\n", __func__); 329 1.1 fredette #endif 330 1.1 fredette return; 331 1.1 fredette } 332 1.1 fredette sc->sc_state &= ~SUNSCPAL_DOINGDMA; 333 1.1 fredette 334 1.1 fredette /* First, halt the DMA engine. */ 335 1.1 fredette icr = SUNSCPAL_READ_2(sc, sunscpal_icr); 336 1.23 tsutsui icr &= ~(SUNSCPAL_ICR_DMA_ENABLE | SUNSCPAL_ICR_WORD_MODE | 337 1.23 tsutsui SUNSCPAL_ICR_INTERRUPT_ENABLE); 338 1.1 fredette SUNSCPAL_WRITE_2(sc, sunscpal_icr, icr); 339 1.1 fredette 340 1.1 fredette #ifdef SUNSCPAL_USE_BUS_DMA 341 1.1 fredette /* 342 1.17 perry * XXX - this function is supposed to be independent of 343 1.1 fredette * the host's DMA implementation. 344 1.1 fredette */ 345 1.1 fredette { 346 1.1 fredette sunscpal_dma_handle_t dh = sr->sr_dma_hand; 347 1.17 perry 348 1.1 fredette /* sync the DMA map: */ 349 1.17 perry bus_dmamap_sync(sc->sunscpal_dmat, dh->dh_dmamap, 0, dh->dh_maplen, 350 1.23 tsutsui ((xs->xs_control & XS_CTL_DATA_OUT) == 0 ? 351 1.23 tsutsui BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE)); 352 1.1 fredette } 353 1.1 fredette #endif /* SUNSCPAL_USE_BUS_DMA */ 354 1.1 fredette 355 1.1 fredette 356 1.1 fredette if (icr & (SUNSCPAL_ICR_BUS_ERROR)) { 357 1.6 fredette char buffer[64]; 358 1.24 christos snprintb(buffer, sizeof(buffer), SUNSCPAL_ICR_BITS, icr); 359 1.6 fredette printf("sc: DMA error, icr=%s, reset\n", buffer); 360 1.1 fredette sr->sr_xs->error = XS_DRIVER_STUFFUP; 361 1.1 fredette sc->sc_state |= SUNSCPAL_ABORTING; 362 1.1 fredette goto out; 363 1.1 fredette } 364 1.1 fredette 365 1.1 fredette /* Note that timeout may have set the error flag. */ 366 1.1 fredette if (sc->sc_state & SUNSCPAL_ABORTING) 367 1.1 fredette goto out; 368 1.1 fredette 369 1.1 fredette /* XXX: Wait for DMA to actually finish? */ 370 1.1 fredette 371 1.1 fredette /* 372 1.1 fredette * Now try to figure out how much actually transferred 373 1.1 fredette */ 374 1.1 fredette 375 1.23 tsutsui resid = SUNSCPAL_DMA_COUNT_FLIP(SUNSCPAL_READ_2(sc, 376 1.23 tsutsui sunscpal_dma_count)); 377 1.1 fredette ntrans = sc->sc_reqlen - resid; 378 1.1 fredette 379 1.1 fredette #ifdef SUNSCPAL_DEBUG 380 1.1 fredette if (sunscpal_debug & SUNSCPAL_DBG_DMA) { 381 1.23 tsutsui printf("%s: resid=0x%x ntrans=0x%x\n", 382 1.23 tsutsui __func__, resid, ntrans); 383 1.1 fredette } 384 1.1 fredette #endif 385 1.1 fredette 386 1.1 fredette if (ntrans < sc->sc_min_dma_len) { 387 1.1 fredette printf("sc: DMA count: 0x%x\n", resid); 388 1.1 fredette sc->sc_state |= SUNSCPAL_ABORTING; 389 1.1 fredette goto out; 390 1.1 fredette } 391 1.1 fredette if (ntrans > sc->sc_datalen) 392 1.23 tsutsui panic("%s: excess transfer", __func__); 393 1.1 fredette 394 1.1 fredette /* Adjust data pointer */ 395 1.1 fredette sc->sc_dataptr += ntrans; 396 1.1 fredette sc->sc_datalen -= ntrans; 397 1.1 fredette 398 1.1 fredette /* 399 1.1 fredette * After a read, we may need to clean-up 400 1.1 fredette * "Left-over bytes" (yuck!) 401 1.1 fredette */ 402 1.1 fredette if (((xs->xs_control & XS_CTL_DATA_OUT) == 0) && 403 1.23 tsutsui ((icr & SUNSCPAL_ICR_ODD_LENGTH) != 0)) { 404 1.1 fredette #ifdef DEBUG 405 1.1 fredette printf("sc: Got Left-over bytes!\n"); 406 1.1 fredette #endif 407 1.1 fredette *(sc->sc_dataptr++) = SUNSCPAL_READ_1(sc, sunscpal_data); 408 1.1 fredette sc->sc_datalen--; 409 1.1 fredette } 410 1.1 fredette 411 1.23 tsutsui out: 412 1.1 fredette SUNSCPAL_WRITE_2(sc, sunscpal_dma_count, SUNSCPAL_DMA_COUNT_FLIP(0)); 413 1.1 fredette 414 1.1 fredette } 415 1.1 fredette 416 1.1 fredette /* Ask the target for a MSG_OUT phase. */ 417 1.20 perry static inline void 418 1.23 tsutsui sunscpal_sched_msgout(struct sunscpal_softc *sc, int msg_code) 419 1.1 fredette { 420 1.17 perry /* 421 1.1 fredette * This controller does not allow you to assert ATN, which 422 1.1 fredette * will eventually leave us with no option other than to reset 423 1.1 fredette * the bus. We keep this function as a placeholder, though, 424 1.1 fredette * and this printf will eventually go away or get #ifdef'ed: 425 1.1 fredette */ 426 1.23 tsutsui printf("%s: trying to schedule 0x%0x\n", __func__, msg_code); 427 1.1 fredette sc->sc_msgpriq |= msg_code; 428 1.1 fredette } 429 1.1 fredette 430 1.1 fredette int 431 1.23 tsutsui sunscpal_pio_out(struct sunscpal_softc *sc, int phase, int count, uint8_t *data) 432 1.1 fredette { 433 1.1 fredette int resid; 434 1.1 fredette 435 1.1 fredette resid = count; 436 1.1 fredette while (resid > 0) { 437 1.1 fredette if (!SUNSCPAL_BUSY(sc)) { 438 1.1 fredette SUNSCPAL_TRACE("pio_out: lost BSY, resid=%d\n", resid); 439 1.1 fredette break; 440 1.1 fredette } 441 1.1 fredette if (sunscpal_wait_req(sc)) { 442 1.1 fredette SUNSCPAL_TRACE("pio_out: no REQ, resid=%d\n", resid); 443 1.1 fredette break; 444 1.1 fredette } 445 1.23 tsutsui if (SUNSCPAL_BUS_PHASE(SUNSCPAL_READ_2(sc, sunscpal_icr)) != 446 1.23 tsutsui phase) 447 1.1 fredette break; 448 1.1 fredette 449 1.1 fredette /* Put the data on the bus. */ 450 1.1 fredette if (data) { 451 1.1 fredette SUNSCPAL_BYTE_WRITE(sc, phase, *data++); 452 1.1 fredette } else { 453 1.1 fredette SUNSCPAL_BYTE_WRITE(sc, phase, 0); 454 1.1 fredette } 455 1.1 fredette 456 1.1 fredette --resid; 457 1.1 fredette } 458 1.1 fredette 459 1.23 tsutsui return count - resid; 460 1.1 fredette } 461 1.1 fredette 462 1.1 fredette 463 1.1 fredette int 464 1.23 tsutsui sunscpal_pio_in(struct sunscpal_softc *sc, int phase, int count, uint8_t *data) 465 1.1 fredette { 466 1.1 fredette int resid; 467 1.1 fredette 468 1.1 fredette resid = count; 469 1.1 fredette while (resid > 0) { 470 1.1 fredette if (!SUNSCPAL_BUSY(sc)) { 471 1.1 fredette SUNSCPAL_TRACE("pio_in: lost BSY, resid=%d\n", resid); 472 1.1 fredette break; 473 1.1 fredette } 474 1.1 fredette if (sunscpal_wait_req(sc)) { 475 1.1 fredette SUNSCPAL_TRACE("pio_in: no REQ, resid=%d\n", resid); 476 1.1 fredette break; 477 1.1 fredette } 478 1.1 fredette /* A phase change is not valid until AFTER REQ rises! */ 479 1.23 tsutsui if (SUNSCPAL_BUS_PHASE(SUNSCPAL_READ_2(sc, sunscpal_icr)) != 480 1.23 tsutsui phase) 481 1.1 fredette break; 482 1.1 fredette 483 1.1 fredette /* Read the data bus. */ 484 1.1 fredette if (data) 485 1.1 fredette *data++ = SUNSCPAL_BYTE_READ(sc, phase); 486 1.1 fredette else 487 1.23 tsutsui (void)SUNSCPAL_BYTE_READ(sc, phase); 488 1.1 fredette 489 1.1 fredette --resid; 490 1.1 fredette } 491 1.1 fredette 492 1.23 tsutsui return count - resid; 493 1.1 fredette } 494 1.1 fredette 495 1.1 fredette 496 1.1 fredette void 497 1.23 tsutsui sunscpal_init(struct sunscpal_softc *sc) 498 1.1 fredette { 499 1.1 fredette int i, j; 500 1.1 fredette 501 1.1 fredette #ifdef SUNSCPAL_DEBUG 502 1.1 fredette sunscpal_debug_sc = sc; 503 1.1 fredette #endif 504 1.1 fredette 505 1.1 fredette for (i = 0; i < SUNSCPAL_OPENINGS; i++) 506 1.1 fredette sc->sc_ring[i].sr_xs = NULL; 507 1.1 fredette for (i = 0; i < 8; i++) 508 1.1 fredette for (j = 0; j < 8; j++) 509 1.1 fredette sc->sc_matrix[i][j] = NULL; 510 1.1 fredette 511 1.1 fredette sc->sc_prevphase = SUNSCPAL_PHASE_INVALID; 512 1.1 fredette sc->sc_state = SUNSCPAL_IDLE; 513 1.1 fredette 514 1.1 fredette SUNSCPAL_WRITE_2(sc, sunscpal_icr, 0); 515 1.1 fredette SUNSCPAL_WRITE_2(sc, sunscpal_dma_addr_h, 0); 516 1.1 fredette SUNSCPAL_WRITE_2(sc, sunscpal_dma_addr_l, 0); 517 1.1 fredette SUNSCPAL_WRITE_2(sc, sunscpal_dma_count, SUNSCPAL_DMA_COUNT_FLIP(0)); 518 1.1 fredette 519 1.1 fredette SUNSCPAL_CLR_INTR(sc); 520 1.1 fredette 521 1.1 fredette /* Another hack (Er.. hook!) for anything that needs it: */ 522 1.1 fredette if (sc->sc_intr_on) { 523 1.1 fredette SUNSCPAL_TRACE("init: intr ON\n", 0); 524 1.1 fredette sc->sc_intr_on(sc); 525 1.1 fredette } 526 1.1 fredette } 527 1.1 fredette 528 1.1 fredette 529 1.1 fredette static void 530 1.23 tsutsui sunscpal_reset_scsibus(struct sunscpal_softc *sc) 531 1.1 fredette { 532 1.1 fredette 533 1.23 tsutsui SUNSCPAL_TRACE("reset_scsibus, cur=0x%x\n", (long)sc->sc_current); 534 1.1 fredette 535 1.1 fredette SUNSCPAL_WRITE_2(sc, sunscpal_icr, SUNSCPAL_ICR_RESET); 536 1.1 fredette delay(500); 537 1.1 fredette SUNSCPAL_WRITE_2(sc, sunscpal_icr, 0); 538 1.1 fredette 539 1.1 fredette SUNSCPAL_CLR_INTR(sc); 540 1.1 fredette /* XXX - Need long delay here! */ 541 1.1 fredette delay(100000); 542 1.1 fredette 543 1.1 fredette /* XXX - Need to cancel disconnected requests. */ 544 1.1 fredette } 545 1.1 fredette 546 1.1 fredette 547 1.1 fredette /* 548 1.1 fredette * Interrupt handler for the SCSI Bus Controller (SBC) 549 1.1 fredette * This may also called for a DMA timeout (at splbio). 550 1.1 fredette */ 551 1.1 fredette int 552 1.23 tsutsui sunscpal_intr(void *arg) 553 1.1 fredette { 554 1.1 fredette struct sunscpal_softc *sc = arg; 555 1.1 fredette int claimed = 0; 556 1.1 fredette 557 1.1 fredette /* 558 1.1 fredette * Do not touch SBC regs here unless sc_current == NULL 559 1.1 fredette * or it will complain about "register conflict" errors. 560 1.1 fredette * Instead, just let sunscpal_machine() deal with it. 561 1.1 fredette */ 562 1.1 fredette SUNSCPAL_TRACE("intr: top, state=%d\n", sc->sc_state); 563 1.1 fredette 564 1.1 fredette if (sc->sc_state == SUNSCPAL_IDLE) { 565 1.1 fredette /* 566 1.1 fredette * Might be reselect. sunscpal_reselect() will check, 567 1.1 fredette * and set up the connection if so. This will verify 568 1.1 fredette * that sc_current == NULL at the beginning... 569 1.1 fredette */ 570 1.1 fredette 571 1.1 fredette /* Another hack (Er.. hook!) for anything that needs it: */ 572 1.1 fredette if (sc->sc_intr_off) { 573 1.1 fredette SUNSCPAL_TRACE("intr: for reselect, intr off\n", 0); 574 1.1 fredette sc->sc_intr_off(sc); 575 1.1 fredette } 576 1.1 fredette 577 1.1 fredette sunscpal_reselect(sc); 578 1.1 fredette } 579 1.1 fredette 580 1.1 fredette /* 581 1.1 fredette * The remaining documented interrupt causes are a DMA complete 582 1.1 fredette * condition. 583 1.1 fredette * 584 1.17 perry * The procedure is to let sunscpal_machine() figure out what 585 1.1 fredette * to do next. 586 1.1 fredette */ 587 1.1 fredette if (sc->sc_state & SUNSCPAL_WORKING) { 588 1.1 fredette SUNSCPAL_TRACE("intr: call machine, cur=0x%x\n", 589 1.23 tsutsui (long)sc->sc_current); 590 1.1 fredette /* This will usually free-up the nexus. */ 591 1.1 fredette sunscpal_machine(sc); 592 1.1 fredette SUNSCPAL_TRACE("intr: machine done, cur=0x%x\n", 593 1.23 tsutsui (long)sc->sc_current); 594 1.1 fredette claimed = 1; 595 1.1 fredette } 596 1.1 fredette 597 1.1 fredette /* Maybe we can run some commands now... */ 598 1.1 fredette if (sc->sc_state == SUNSCPAL_IDLE) { 599 1.1 fredette SUNSCPAL_TRACE("intr: call sched, cur=0x%x\n", 600 1.23 tsutsui (long)sc->sc_current); 601 1.1 fredette sunscpal_sched(sc); 602 1.1 fredette SUNSCPAL_TRACE("intr: sched done, cur=0x%x\n", 603 1.23 tsutsui (long)sc->sc_current); 604 1.1 fredette } 605 1.1 fredette 606 1.1 fredette return claimed; 607 1.1 fredette } 608 1.1 fredette 609 1.1 fredette 610 1.1 fredette /* 611 1.1 fredette * Abort the current command (i.e. due to timeout) 612 1.1 fredette */ 613 1.1 fredette void 614 1.23 tsutsui sunscpal_abort(struct sunscpal_softc *sc) 615 1.1 fredette { 616 1.1 fredette 617 1.1 fredette /* 618 1.1 fredette * Finish it now. If DMA is in progress, we 619 1.1 fredette * can not call sunscpal_sched_msgout() because 620 1.1 fredette * that hits the SBC (avoid DMA conflict). 621 1.1 fredette */ 622 1.1 fredette 623 1.1 fredette /* Another hack (Er.. hook!) for anything that needs it: */ 624 1.1 fredette if (sc->sc_intr_off) { 625 1.1 fredette SUNSCPAL_TRACE("abort: intr off\n", 0); 626 1.1 fredette sc->sc_intr_off(sc); 627 1.1 fredette } 628 1.1 fredette 629 1.1 fredette sc->sc_state |= SUNSCPAL_ABORTING; 630 1.1 fredette if ((sc->sc_state & SUNSCPAL_DOINGDMA) == 0) { 631 1.1 fredette sunscpal_sched_msgout(sc, SEND_ABORT); 632 1.1 fredette } 633 1.1 fredette SUNSCPAL_TRACE("abort: call machine, cur=0x%x\n", 634 1.23 tsutsui (long)sc->sc_current); 635 1.1 fredette sunscpal_machine(sc); 636 1.1 fredette SUNSCPAL_TRACE("abort: machine done, cur=0x%x\n", 637 1.23 tsutsui (long)sc->sc_current); 638 1.1 fredette 639 1.1 fredette /* Another hack (Er.. hook!) for anything that needs it: */ 640 1.1 fredette if (sc->sc_intr_on) { 641 1.1 fredette SUNSCPAL_TRACE("abort: intr ON\n", 0); 642 1.23 tsutsui sc->sc_intr_on(sc); 643 1.1 fredette } 644 1.1 fredette } 645 1.1 fredette 646 1.1 fredette /* 647 1.1 fredette * Timeout handler, scheduled for each SCSI command. 648 1.1 fredette */ 649 1.1 fredette void 650 1.23 tsutsui sunscpal_cmd_timeout(void *arg) 651 1.1 fredette { 652 1.1 fredette struct sunscpal_req *sr = arg; 653 1.1 fredette struct scsipi_xfer *xs; 654 1.2 bouyer struct scsipi_periph *periph; 655 1.1 fredette struct sunscpal_softc *sc; 656 1.1 fredette int s; 657 1.1 fredette 658 1.1 fredette s = splbio(); 659 1.1 fredette 660 1.1 fredette /* Get all our variables... */ 661 1.1 fredette xs = sr->sr_xs; 662 1.1 fredette if (xs == NULL) { 663 1.23 tsutsui printf("%s: no scsipi_xfer\n", __func__); 664 1.1 fredette goto out; 665 1.1 fredette } 666 1.2 bouyer periph = xs->xs_periph; 667 1.23 tsutsui sc = device_private(periph->periph_channel->chan_adapter->adapt_dev); 668 1.1 fredette 669 1.1 fredette printf("%s: cmd timeout, targ=%d, lun=%d\n", 670 1.23 tsutsui device_xname(sc->sc_dev), 671 1.1 fredette sr->sr_target, sr->sr_lun); 672 1.1 fredette 673 1.1 fredette /* 674 1.1 fredette * Mark the overdue job as failed, and arrange for 675 1.1 fredette * sunscpal_machine to terminate it. If the victim 676 1.1 fredette * is the current job, call sunscpal_machine() now. 677 1.1 fredette * Otherwise arrange for sunscpal_sched() to do it. 678 1.1 fredette */ 679 1.1 fredette sr->sr_flags |= SR_OVERDUE; 680 1.1 fredette if (sc->sc_current == sr) { 681 1.23 tsutsui SUNSCPAL_TRACE("cmd_tmo: call abort, sr=0x%x\n", (long)sr); 682 1.1 fredette sunscpal_abort(sc); 683 1.1 fredette } else { 684 1.1 fredette /* 685 1.1 fredette * The driver may be idle, or busy with another job. 686 1.1 fredette * Arrange for sunscpal_sched() to do the deed. 687 1.1 fredette */ 688 1.1 fredette SUNSCPAL_TRACE("cmd_tmo: clear matrix, t/l=0x%02x\n", 689 1.23 tsutsui (sr->sr_target << 4) | sr->sr_lun); 690 1.1 fredette sc->sc_matrix[sr->sr_target][sr->sr_lun] = NULL; 691 1.1 fredette } 692 1.1 fredette 693 1.1 fredette /* 694 1.1 fredette * We may have aborted the current job, or may have 695 1.1 fredette * already been idle. In either case, we should now 696 1.1 fredette * be idle, so try to start another job. 697 1.1 fredette */ 698 1.1 fredette if (sc->sc_state == SUNSCPAL_IDLE) { 699 1.1 fredette SUNSCPAL_TRACE("cmd_tmo: call sched, cur=0x%x\n", 700 1.23 tsutsui (long)sc->sc_current); 701 1.1 fredette sunscpal_sched(sc); 702 1.1 fredette SUNSCPAL_TRACE("cmd_tmo: sched done, cur=0x%x\n", 703 1.23 tsutsui (long)sc->sc_current); 704 1.1 fredette } 705 1.1 fredette 706 1.23 tsutsui out: 707 1.1 fredette splx(s); 708 1.1 fredette } 709 1.1 fredette 710 1.1 fredette 711 1.1 fredette /***************************************************************** 712 1.1 fredette * Interface to higher level 713 1.1 fredette *****************************************************************/ 714 1.1 fredette 715 1.1 fredette 716 1.1 fredette /* 717 1.1 fredette * Enter a new SCSI command into the "issue" queue, and 718 1.1 fredette * if there is work to do, start it going. 719 1.1 fredette * 720 1.1 fredette * WARNING: This can be called recursively! 721 1.1 fredette * (see comment in sunscpal_done) 722 1.1 fredette */ 723 1.2 bouyer void 724 1.23 tsutsui sunscpal_scsipi_request(struct scsipi_channel *chan, scsipi_adapter_req_t req, 725 1.23 tsutsui void *arg) 726 1.2 bouyer { 727 1.1 fredette struct scsipi_xfer *xs; 728 1.23 tsutsui struct sunscpal_softc *sc; 729 1.23 tsutsui struct sunscpal_req *sr; 730 1.2 bouyer int s, i, flags; 731 1.1 fredette 732 1.23 tsutsui sc = device_private(chan->chan_adapter->adapt_dev); 733 1.23 tsutsui 734 1.2 bouyer switch (req) { 735 1.2 bouyer case ADAPTER_REQ_RUN_XFER: 736 1.2 bouyer xs = arg; 737 1.2 bouyer flags = xs->xs_control; 738 1.1 fredette 739 1.2 bouyer if (flags & XS_CTL_DATA_UIO) 740 1.2 bouyer panic("sunscpal: scsi data uio requested"); 741 1.1 fredette 742 1.2 bouyer s = splbio(); 743 1.1 fredette 744 1.2 bouyer if (flags & XS_CTL_POLL) { 745 1.2 bouyer /* Terminate any current command. */ 746 1.2 bouyer sr = sc->sc_current; 747 1.23 tsutsui if (sr != NULL) { 748 1.23 tsutsui printf("%s: polled request aborting %d/%d\n", 749 1.23 tsutsui device_xname(sc->sc_dev), sr->sr_target, 750 1.23 tsutsui sr->sr_lun); 751 1.2 bouyer sunscpal_abort(sc); 752 1.2 bouyer } 753 1.2 bouyer if (sc->sc_state != SUNSCPAL_IDLE) { 754 1.23 tsutsui panic("%s: polled request, abort failed", 755 1.23 tsutsui __func__); 756 1.2 bouyer } 757 1.1 fredette } 758 1.1 fredette 759 1.2 bouyer /* 760 1.2 bouyer * Find lowest empty slot in ring buffer. 761 1.2 bouyer * XXX: What about "fairness" and cmd order? 762 1.2 bouyer */ 763 1.2 bouyer for (i = 0; i < SUNSCPAL_OPENINGS; i++) 764 1.2 bouyer if (sc->sc_ring[i].sr_xs == NULL) 765 1.2 bouyer goto new; 766 1.1 fredette 767 1.2 bouyer xs->error = XS_RESOURCE_SHORTAGE; 768 1.2 bouyer SUNSCPAL_TRACE("scsipi_cmd: no openings, rv=%d\n", rv); 769 1.2 bouyer goto out; 770 1.1 fredette 771 1.23 tsutsui new: 772 1.2 bouyer /* Create queue entry */ 773 1.2 bouyer sr = &sc->sc_ring[i]; 774 1.2 bouyer sr->sr_xs = xs; 775 1.2 bouyer sr->sr_target = xs->xs_periph->periph_target; 776 1.2 bouyer sr->sr_lun = xs->xs_periph->periph_lun; 777 1.2 bouyer sr->sr_dma_hand = NULL; 778 1.2 bouyer sr->sr_dataptr = xs->data; 779 1.2 bouyer sr->sr_datalen = xs->datalen; 780 1.2 bouyer sr->sr_flags = (flags & XS_CTL_POLL) ? SR_IMMED : 0; 781 1.2 bouyer sr->sr_status = -1; /* no value */ 782 1.2 bouyer sc->sc_ncmds++; 783 1.2 bouyer 784 1.2 bouyer SUNSCPAL_TRACE("scsipi_cmd: new sr=0x%x\n", (long)sr); 785 1.2 bouyer 786 1.2 bouyer if (flags & XS_CTL_POLL) { 787 1.2 bouyer /* Force this new command to be next. */ 788 1.2 bouyer sc->sc_rr = i; 789 1.2 bouyer } 790 1.1 fredette 791 1.2 bouyer /* 792 1.2 bouyer * If we were idle, run some commands... 793 1.2 bouyer */ 794 1.2 bouyer if (sc->sc_state == SUNSCPAL_IDLE) { 795 1.2 bouyer SUNSCPAL_TRACE("scsipi_cmd: call sched, cur=0x%x\n", 796 1.23 tsutsui (long)sc->sc_current); 797 1.2 bouyer sunscpal_sched(sc); 798 1.2 bouyer SUNSCPAL_TRACE("scsipi_cmd: sched done, cur=0x%x\n", 799 1.23 tsutsui (long)sc->sc_current); 800 1.2 bouyer } 801 1.1 fredette 802 1.2 bouyer if (flags & XS_CTL_POLL) { 803 1.2 bouyer /* Make sure sunscpal_sched() finished it. */ 804 1.2 bouyer if ((xs->xs_status & XS_STS_DONE) == 0) 805 1.23 tsutsui panic("%s: poll didn't finish", __func__); 806 1.2 bouyer } 807 1.1 fredette 808 1.23 tsutsui out: 809 1.2 bouyer splx(s); 810 1.2 bouyer return; 811 1.7 fredette 812 1.2 bouyer case ADAPTER_REQ_GROW_RESOURCES: 813 1.7 fredette /* XXX Not supported. */ 814 1.7 fredette return; 815 1.7 fredette 816 1.2 bouyer case ADAPTER_REQ_SET_XFER_MODE: 817 1.7 fredette { 818 1.7 fredette /* 819 1.7 fredette * We don't support Sync, Wide, or Tagged Queueing. 820 1.7 fredette * Just callback now, to report this. 821 1.7 fredette */ 822 1.7 fredette struct scsipi_xfer_mode *xm = arg; 823 1.7 fredette 824 1.7 fredette xm->xm_mode = 0; 825 1.7 fredette xm->xm_period = 0; 826 1.7 fredette xm->xm_offset = 0; 827 1.7 fredette scsipi_async_event(chan, ASYNC_EVENT_XFER_MODE, xm); 828 1.2 bouyer return; 829 1.7 fredette } 830 1.2 bouyer } 831 1.1 fredette } 832 1.1 fredette 833 1.1 fredette 834 1.1 fredette /* 835 1.1 fredette * POST PROCESSING OF SCSI_CMD (usually current) 836 1.1 fredette * Called by sunscpal_sched(), sunscpal_machine() 837 1.1 fredette */ 838 1.1 fredette static void 839 1.23 tsutsui sunscpal_done(struct sunscpal_softc *sc) 840 1.1 fredette { 841 1.1 fredette struct sunscpal_req *sr; 842 1.1 fredette struct scsipi_xfer *xs; 843 1.1 fredette 844 1.1 fredette #ifdef DIAGNOSTIC 845 1.1 fredette if (sc->sc_state == SUNSCPAL_IDLE) 846 1.23 tsutsui panic("%s: state=idle", __func__); 847 1.1 fredette if (sc->sc_current == NULL) 848 1.23 tsutsui panic("%s: current=0", __func__); 849 1.1 fredette #endif 850 1.1 fredette 851 1.1 fredette sr = sc->sc_current; 852 1.1 fredette xs = sr->sr_xs; 853 1.1 fredette 854 1.23 tsutsui SUNSCPAL_TRACE("done: top, cur=0x%x\n", (long)sc->sc_current); 855 1.1 fredette 856 1.1 fredette /* 857 1.1 fredette * Clean up DMA resources for this command. 858 1.1 fredette */ 859 1.1 fredette if (sr->sr_dma_hand) { 860 1.1 fredette SUNSCPAL_TRACE("done: dma_free, dh=0x%x\n", 861 1.23 tsutsui (long)sr->sr_dma_hand); 862 1.1 fredette sunscpal_dma_free(sc); 863 1.1 fredette } 864 1.1 fredette #ifdef DIAGNOSTIC 865 1.1 fredette if (sr->sr_dma_hand) 866 1.23 tsutsui panic("%s: DMA free did not", __func__); 867 1.1 fredette #endif 868 1.1 fredette 869 1.1 fredette if (sc->sc_state & SUNSCPAL_ABORTING) { 870 1.1 fredette SUNSCPAL_TRACE("done: aborting, error=%d\n", xs->error); 871 1.1 fredette if (xs->error == XS_NOERROR) 872 1.1 fredette xs->error = XS_TIMEOUT; 873 1.1 fredette } 874 1.1 fredette 875 1.23 tsutsui SUNSCPAL_TRACE("done: check error=%d\n", (long)xs->error); 876 1.1 fredette 877 1.1 fredette /* If error is already set, ignore sr_status value. */ 878 1.1 fredette if (xs->error != XS_NOERROR) 879 1.1 fredette goto finish; 880 1.1 fredette 881 1.1 fredette SUNSCPAL_TRACE("done: check status=%d\n", sr->sr_status); 882 1.1 fredette 883 1.2 bouyer xs->status = sr->sr_status; 884 1.1 fredette switch (sr->sr_status) { 885 1.1 fredette case SCSI_OK: /* 0 */ 886 1.1 fredette break; 887 1.1 fredette 888 1.1 fredette case SCSI_CHECK: 889 1.1 fredette case SCSI_BUSY: 890 1.1 fredette xs->error = XS_BUSY; 891 1.1 fredette break; 892 1.1 fredette 893 1.1 fredette case -1: 894 1.1 fredette /* This is our "impossible" initial value. */ 895 1.1 fredette /* fallthrough */ 896 1.1 fredette default: 897 1.1 fredette printf("%s: target %d, bad status=%d\n", 898 1.23 tsutsui device_xname(sc->sc_dev), sr->sr_target, sr->sr_status); 899 1.1 fredette xs->error = XS_DRIVER_STUFFUP; 900 1.1 fredette break; 901 1.1 fredette } 902 1.1 fredette 903 1.23 tsutsui finish: 904 1.1 fredette 905 1.1 fredette SUNSCPAL_TRACE("done: finish, error=%d\n", xs->error); 906 1.1 fredette 907 1.1 fredette /* 908 1.1 fredette * Dequeue the finished command, but don't clear sc_state until 909 1.1 fredette * after the call to scsipi_done(), because that may call back to 910 1.1 fredette * sunscpal_scsi_cmd() - unwanted recursion! 911 1.1 fredette * 912 1.1 fredette * Keeping sc->sc_state != idle terminates the recursion. 913 1.1 fredette */ 914 1.1 fredette #ifdef DIAGNOSTIC 915 1.1 fredette if ((sc->sc_state & SUNSCPAL_WORKING) == 0) 916 1.23 tsutsui panic("%s: bad state", __func__); 917 1.1 fredette #endif 918 1.1 fredette 919 1.1 fredette /* Clear our pointers to the request. */ 920 1.1 fredette sc->sc_current = NULL; 921 1.1 fredette sc->sc_matrix[sr->sr_target][sr->sr_lun] = NULL; 922 1.1 fredette callout_stop(&sr->sr_xs->xs_callout); 923 1.1 fredette 924 1.1 fredette /* Make the request free. */ 925 1.1 fredette sr->sr_xs = NULL; 926 1.1 fredette sc->sc_ncmds--; 927 1.1 fredette 928 1.1 fredette /* Tell common SCSI code it is done. */ 929 1.1 fredette scsipi_done(xs); 930 1.1 fredette 931 1.1 fredette sc->sc_state = SUNSCPAL_IDLE; 932 1.1 fredette /* Now sunscpal_sched() may be called again. */ 933 1.1 fredette } 934 1.1 fredette 935 1.1 fredette 936 1.1 fredette /* 937 1.1 fredette * Schedule a SCSI operation. This routine should return 938 1.1 fredette * only after it achieves one of the following conditions: 939 1.1 fredette * Busy (sc->sc_state != SUNSCPAL_IDLE) 940 1.1 fredette * No more work can be started. 941 1.1 fredette */ 942 1.1 fredette static void 943 1.23 tsutsui sunscpal_sched(struct sunscpal_softc *sc) 944 1.1 fredette { 945 1.1 fredette struct sunscpal_req *sr; 946 1.1 fredette struct scsipi_xfer *xs; 947 1.1 fredette int target = 0, lun = 0; 948 1.1 fredette int error, i; 949 1.1 fredette 950 1.1 fredette /* Another hack (Er.. hook!) for anything that needs it: */ 951 1.1 fredette if (sc->sc_intr_off) { 952 1.1 fredette SUNSCPAL_TRACE("sched: top, intr off\n", 0); 953 1.23 tsutsui sc->sc_intr_off(sc); 954 1.1 fredette } 955 1.1 fredette 956 1.23 tsutsui next_job: 957 1.1 fredette /* 958 1.1 fredette * Grab the next job from queue. Must be idle. 959 1.1 fredette */ 960 1.1 fredette #ifdef DIAGNOSTIC 961 1.1 fredette if (sc->sc_state != SUNSCPAL_IDLE) 962 1.23 tsutsui panic("%s: not idle", __func__); 963 1.1 fredette if (sc->sc_current) 964 1.23 tsutsui panic("%s: current set", __func__); 965 1.1 fredette #endif 966 1.1 fredette 967 1.1 fredette /* 968 1.1 fredette * Always start the search where we last looked. 969 1.1 fredette */ 970 1.1 fredette i = sc->sc_rr; 971 1.1 fredette sr = NULL; 972 1.1 fredette do { 973 1.1 fredette if (sc->sc_ring[i].sr_xs) { 974 1.1 fredette target = sc->sc_ring[i].sr_target; 975 1.1 fredette lun = sc->sc_ring[i].sr_lun; 976 1.1 fredette if (sc->sc_matrix[target][lun] == NULL) { 977 1.1 fredette /* 978 1.1 fredette * Do not mark the target/LUN busy yet, 979 1.1 fredette * because reselect may cause some other 980 1.1 fredette * job to become the current one, so we 981 1.1 fredette * might not actually start this job. 982 1.1 fredette * Instead, set sc_matrix later on. 983 1.1 fredette */ 984 1.1 fredette sc->sc_rr = i; 985 1.1 fredette sr = &sc->sc_ring[i]; 986 1.1 fredette break; 987 1.1 fredette } 988 1.1 fredette } 989 1.1 fredette i++; 990 1.1 fredette if (i == SUNSCPAL_OPENINGS) 991 1.1 fredette i = 0; 992 1.1 fredette } while (i != sc->sc_rr); 993 1.1 fredette 994 1.1 fredette if (sr == NULL) { 995 1.1 fredette SUNSCPAL_TRACE("sched: no work, cur=0x%x\n", 996 1.23 tsutsui (long)sc->sc_current); 997 1.1 fredette 998 1.1 fredette /* Another hack (Er.. hook!) for anything that needs it: */ 999 1.1 fredette if (sc->sc_intr_on) { 1000 1.1 fredette SUNSCPAL_TRACE("sched: ret, intr ON\n", 0); 1001 1.23 tsutsui sc->sc_intr_on(sc); 1002 1.1 fredette } 1003 1.1 fredette 1004 1.1 fredette return; /* No more work to do. */ 1005 1.1 fredette } 1006 1.1 fredette 1007 1.1 fredette SUNSCPAL_TRACE("sched: select for t/l=0x%02x\n", 1008 1.23 tsutsui (sr->sr_target << 4) | sr->sr_lun); 1009 1.1 fredette 1010 1.1 fredette sc->sc_state = SUNSCPAL_WORKING; 1011 1.1 fredette error = sunscpal_select(sc, sr); 1012 1.1 fredette if (sc->sc_current) { 1013 1.1 fredette /* Lost the race! reselected out from under us! */ 1014 1.1 fredette /* Work with the reselected job. */ 1015 1.1 fredette if (sr->sr_flags & SR_IMMED) { 1016 1.1 fredette printf("%s: reselected while polling (abort)\n", 1017 1.23 tsutsui device_xname(sc->sc_dev)); 1018 1.1 fredette /* Abort the reselected job. */ 1019 1.1 fredette sc->sc_state |= SUNSCPAL_ABORTING; 1020 1.1 fredette sc->sc_msgpriq |= SEND_ABORT; 1021 1.1 fredette } 1022 1.1 fredette sr = sc->sc_current; 1023 1.1 fredette xs = sr->sr_xs; 1024 1.1 fredette SUNSCPAL_TRACE("sched: reselect, new sr=0x%x\n", (long)sr); 1025 1.1 fredette goto have_nexus; 1026 1.1 fredette } 1027 1.1 fredette 1028 1.1 fredette /* Normal selection result. Target/LUN is now busy. */ 1029 1.1 fredette sc->sc_matrix[target][lun] = sr; 1030 1.1 fredette sc->sc_current = sr; /* connected */ 1031 1.1 fredette xs = sr->sr_xs; 1032 1.1 fredette 1033 1.1 fredette /* 1034 1.1 fredette * Initialize pointers, etc. for this job 1035 1.1 fredette */ 1036 1.1 fredette sc->sc_dataptr = sr->sr_dataptr; 1037 1.1 fredette sc->sc_datalen = sr->sr_datalen; 1038 1.1 fredette sc->sc_prevphase = SUNSCPAL_PHASE_INVALID; 1039 1.1 fredette sc->sc_msgpriq = SEND_IDENTIFY; 1040 1.1 fredette sc->sc_msgoutq = 0; 1041 1.1 fredette sc->sc_msgout = 0; 1042 1.1 fredette 1043 1.1 fredette SUNSCPAL_TRACE("sched: select rv=%d\n", error); 1044 1.1 fredette 1045 1.1 fredette switch (error) { 1046 1.1 fredette case XS_NOERROR: 1047 1.1 fredette break; 1048 1.1 fredette 1049 1.1 fredette case XS_BUSY: 1050 1.1 fredette /* XXX - Reset and try again. */ 1051 1.1 fredette printf("%s: select found SCSI bus busy, resetting...\n", 1052 1.23 tsutsui device_xname(sc->sc_dev)); 1053 1.1 fredette sunscpal_reset_scsibus(sc); 1054 1.1 fredette /* fallthrough */ 1055 1.1 fredette case XS_SELTIMEOUT: 1056 1.1 fredette default: 1057 1.1 fredette xs->error = error; /* from select */ 1058 1.1 fredette SUNSCPAL_TRACE("sched: call done, sr=0x%x\n", (long)sr); 1059 1.1 fredette sunscpal_done(sc); 1060 1.1 fredette 1061 1.1 fredette /* Paranoia: clear everything. */ 1062 1.1 fredette sc->sc_dataptr = NULL; 1063 1.1 fredette sc->sc_datalen = 0; 1064 1.1 fredette sc->sc_prevphase = SUNSCPAL_PHASE_INVALID; 1065 1.1 fredette sc->sc_msgpriq = 0; 1066 1.1 fredette sc->sc_msgoutq = 0; 1067 1.1 fredette sc->sc_msgout = 0; 1068 1.1 fredette 1069 1.1 fredette goto next_job; 1070 1.1 fredette } 1071 1.1 fredette 1072 1.1 fredette /* 1073 1.1 fredette * Selection was successful. Normally, this means 1074 1.1 fredette * we are starting a new command. However, this 1075 1.1 fredette * might be the termination of an overdue job. 1076 1.1 fredette */ 1077 1.1 fredette if (sr->sr_flags & SR_OVERDUE) { 1078 1.1 fredette SUNSCPAL_TRACE("sched: overdue, sr=0x%x\n", (long)sr); 1079 1.1 fredette sc->sc_state |= SUNSCPAL_ABORTING; 1080 1.1 fredette sc->sc_msgpriq |= SEND_ABORT; 1081 1.1 fredette goto have_nexus; 1082 1.1 fredette } 1083 1.1 fredette 1084 1.1 fredette /* 1085 1.1 fredette * OK, we are starting a new command. 1086 1.1 fredette * Initialize and allocate resources for the new command. 1087 1.1 fredette * Device reset is special (only uses MSG_OUT phase). 1088 1.1 fredette * Normal commands start in MSG_OUT phase where we will 1089 1.1 fredette * send and IDENDIFY message, and then expect CMD phase. 1090 1.1 fredette */ 1091 1.1 fredette #ifdef SUNSCPAL_DEBUG 1092 1.1 fredette if (sunscpal_debug & SUNSCPAL_DBG_CMDS) { 1093 1.23 tsutsui printf("%s: begin, target=%d, LUN=%d\n", __func__, 1094 1.2 bouyer xs->xs_periph->periph_target, xs->xs_periph->periph_lun); 1095 1.1 fredette sunscpal_show_scsi_cmd(xs); 1096 1.1 fredette } 1097 1.1 fredette #endif 1098 1.1 fredette if (xs->xs_control & XS_CTL_RESET) { 1099 1.1 fredette SUNSCPAL_TRACE("sched: cmd=reset, sr=0x%x\n", (long)sr); 1100 1.1 fredette /* Not an error, so do not set SUNSCPAL_ABORTING */ 1101 1.1 fredette sc->sc_msgpriq |= SEND_DEV_RESET; 1102 1.1 fredette goto have_nexus; 1103 1.1 fredette } 1104 1.1 fredette 1105 1.1 fredette #ifdef DIAGNOSTIC 1106 1.1 fredette if ((xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) == 0) { 1107 1.1 fredette if (sc->sc_dataptr) { 1108 1.1 fredette printf("%s: ptr but no data in/out flags?\n", 1109 1.23 tsutsui device_xname(sc->sc_dev)); 1110 1.1 fredette SUNSCPAL_BREAK(); 1111 1.1 fredette sc->sc_dataptr = NULL; 1112 1.1 fredette } 1113 1.1 fredette } 1114 1.1 fredette #endif 1115 1.1 fredette 1116 1.1 fredette /* Allocate DMA space (maybe) */ 1117 1.1 fredette if (sc->sc_dataptr && (sc->sc_flags & SUNSCPAL_DISABLE_DMA) == 0 && 1118 1.1 fredette (sc->sc_datalen >= sc->sc_min_dma_len)) 1119 1.1 fredette { 1120 1.1 fredette SUNSCPAL_TRACE("sched: dma_alloc, len=%d\n", sc->sc_datalen); 1121 1.1 fredette sunscpal_dma_alloc(sc); 1122 1.1 fredette } 1123 1.1 fredette 1124 1.1 fredette /* 1125 1.1 fredette * Initialization hook called just after select, 1126 1.1 fredette * at the beginning of COMMAND phase. 1127 1.1 fredette * (but AFTER the DMA allocation is done) 1128 1.1 fredette * 1129 1.1 fredette * We need to set up the DMA engine BEFORE the target puts 1130 1.1 fredette * the SCSI bus into any DATA phase. 1131 1.1 fredette */ 1132 1.1 fredette if (sr->sr_dma_hand) { 1133 1.1 fredette SUNSCPAL_TRACE("sched: dma_setup, dh=0x%x\n", 1134 1.23 tsutsui (long) sr->sr_dma_hand); 1135 1.1 fredette sunscpal_dma_setup(sc); 1136 1.1 fredette } 1137 1.1 fredette 1138 1.1 fredette /* 1139 1.1 fredette * Schedule a timeout for the job we are starting. 1140 1.1 fredette */ 1141 1.1 fredette if ((sr->sr_flags & SR_IMMED) == 0) { 1142 1.12 bouyer i = mstohz(xs->timeout); 1143 1.1 fredette SUNSCPAL_TRACE("sched: set timeout=%d\n", i); 1144 1.1 fredette callout_reset(&sr->sr_xs->xs_callout, i, 1145 1.1 fredette sunscpal_cmd_timeout, sr); 1146 1.1 fredette } 1147 1.1 fredette 1148 1.23 tsutsui have_nexus: 1149 1.1 fredette 1150 1.1 fredette SUNSCPAL_TRACE("sched: call machine, cur=0x%x\n", 1151 1.23 tsutsui (long)sc->sc_current); 1152 1.1 fredette sunscpal_machine(sc); 1153 1.1 fredette SUNSCPAL_TRACE("sched: machine done, cur=0x%x\n", 1154 1.23 tsutsui (long)sc->sc_current); 1155 1.1 fredette 1156 1.1 fredette /* 1157 1.1 fredette * What state did sunscpal_machine() leave us in? 1158 1.1 fredette * Hopefully it sometimes completes a job... 1159 1.1 fredette */ 1160 1.1 fredette if (sc->sc_state == SUNSCPAL_IDLE) 1161 1.1 fredette goto next_job; 1162 1.1 fredette 1163 1.1 fredette return; /* Have work in progress. */ 1164 1.1 fredette } 1165 1.1 fredette 1166 1.1 fredette 1167 1.1 fredette /* 1168 1.1 fredette * Reselect handler: checks for reselection, and if we are being 1169 1.1 fredette * reselected, it sets up sc->sc_current. 1170 1.1 fredette * 1171 1.1 fredette * We are reselected when: 1172 1.1 fredette * SEL is TRUE 1173 1.1 fredette * IO is TRUE 1174 1.1 fredette * BSY is FALSE 1175 1.1 fredette */ 1176 1.1 fredette void 1177 1.23 tsutsui sunscpal_reselect(struct sunscpal_softc *sc) 1178 1.1 fredette { 1179 1.23 tsutsui 1180 1.17 perry /* 1181 1.1 fredette * This controller does not implement disconnect/reselect, so 1182 1.1 fredette * we really don't have anything to do here. We keep this 1183 1.1 fredette * function as a placeholder, though. 1184 1.1 fredette */ 1185 1.1 fredette } 1186 1.1 fredette 1187 1.1 fredette /* 1188 1.1 fredette * Select target: xs is the transfer that we are selecting for. 1189 1.1 fredette * sc->sc_current should be NULL. 1190 1.1 fredette * 1191 1.1 fredette * Returns: 1192 1.1 fredette * sc->sc_current != NULL ==> we were reselected (race!) 1193 1.1 fredette * XS_NOERROR ==> selection worked 1194 1.1 fredette * XS_BUSY ==> lost arbitration 1195 1.1 fredette * XS_SELTIMEOUT ==> no response to selection 1196 1.1 fredette */ 1197 1.1 fredette static int 1198 1.23 tsutsui sunscpal_select(struct sunscpal_softc *sc, struct sunscpal_req *sr) 1199 1.1 fredette { 1200 1.1 fredette int timo, target_mask; 1201 1.1 fredette u_short mode; 1202 1.1 fredette 1203 1.1 fredette /* Check for reselect */ 1204 1.1 fredette sunscpal_reselect(sc); 1205 1.1 fredette if (sc->sc_current) { 1206 1.1 fredette SUNSCPAL_TRACE("select: reselect, cur=0x%x\n", 1207 1.23 tsutsui (long)sc->sc_current); 1208 1.1 fredette return XS_BUSY; /* reselected */ 1209 1.1 fredette } 1210 1.1 fredette 1211 1.1 fredette /* 1212 1.1 fredette * Select the target. 1213 1.1 fredette */ 1214 1.1 fredette target_mask = (1 << sr->sr_target); 1215 1.1 fredette SUNSCPAL_WRITE_1(sc, sunscpal_data, target_mask); 1216 1.1 fredette SUNSCPAL_WRITE_2(sc, sunscpal_icr, SUNSCPAL_ICR_SELECT); 1217 1.1 fredette 1218 1.1 fredette /* 1219 1.1 fredette * Wait for the target to assert BSY. 1220 1.1 fredette * SCSI spec. says wait for 250 mS. 1221 1.1 fredette */ 1222 1.1 fredette for (timo = 25000;;) { 1223 1.1 fredette if (SUNSCPAL_READ_2(sc, sunscpal_icr) & SUNSCPAL_ICR_BUSY) 1224 1.1 fredette goto success; 1225 1.1 fredette if (--timo <= 0) 1226 1.1 fredette break; 1227 1.1 fredette delay(10); 1228 1.1 fredette } 1229 1.1 fredette 1230 1.1 fredette SUNSCPAL_WRITE_1(sc, sunscpal_data, 0); 1231 1.1 fredette SUNSCPAL_WRITE_2(sc, sunscpal_icr, 0); 1232 1.1 fredette 1233 1.1 fredette SUNSCPAL_TRACE("select: device down, rc=%d\n", XS_SELTIMEOUT); 1234 1.1 fredette return XS_SELTIMEOUT; 1235 1.1 fredette 1236 1.23 tsutsui success: 1237 1.1 fredette 1238 1.1 fredette /* 1239 1.1 fredette * The target is now driving BSY, so we can stop 1240 1.1 fredette * driving SEL and the data bus. We do set up 1241 1.1 fredette * whether or not this target needs parity. 1242 1.1 fredette */ 1243 1.1 fredette mode = 0; 1244 1.1 fredette if ((sc->sc_parity_disable & target_mask) == 0) 1245 1.1 fredette mode |= SUNSCPAL_ICR_PARITY_ENABLE; 1246 1.1 fredette SUNSCPAL_WRITE_2(sc, sunscpal_icr, mode); 1247 1.1 fredette 1248 1.1 fredette return XS_NOERROR; 1249 1.1 fredette } 1250 1.1 fredette 1251 1.1 fredette /***************************************************************** 1252 1.1 fredette * Functions to handle each info. transfer phase: 1253 1.1 fredette *****************************************************************/ 1254 1.1 fredette 1255 1.1 fredette /* 1256 1.1 fredette * The message system: 1257 1.1 fredette * 1258 1.21 christos * This is a revamped message system that now should easier accommodate 1259 1.1 fredette * new messages, if necessary. 1260 1.1 fredette * 1261 1.1 fredette * Currently we accept these messages: 1262 1.1 fredette * IDENTIFY (when reselecting) 1263 1.1 fredette * COMMAND COMPLETE # (expect bus free after messages marked #) 1264 1.1 fredette * NOOP 1265 1.1 fredette * MESSAGE REJECT 1266 1.1 fredette * SYNCHRONOUS DATA TRANSFER REQUEST 1267 1.1 fredette * SAVE DATA POINTER 1268 1.1 fredette * RESTORE POINTERS 1269 1.1 fredette * DISCONNECT # 1270 1.1 fredette * 1271 1.1 fredette * We may send these messages in prioritized order: 1272 1.1 fredette * BUS DEVICE RESET # if XS_CTL_RESET & xs->xs_control (or in 1273 1.1 fredette * weird sits.) 1274 1.1 fredette * MESSAGE PARITY ERROR par. err. during MSGI 1275 1.1 fredette * MESSAGE REJECT If we get a message we don't know how to handle 1276 1.1 fredette * ABORT # send on errors 1277 1.1 fredette * INITIATOR DETECTED ERROR also on errors (SCSI2) (during info xfer) 1278 1.1 fredette * IDENTIFY At the start of each transfer 1279 1.1 fredette * SYNCHRONOUS DATA TRANSFER REQUEST if appropriate 1280 1.1 fredette * NOOP if nothing else fits the bill ... 1281 1.1 fredette */ 1282 1.1 fredette 1283 1.1 fredette /* 1284 1.1 fredette * Precondition: 1285 1.1 fredette * The SCSI bus is already in the MSGI phase and there is a message byte 1286 1.1 fredette * on the bus, along with an asserted REQ signal. 1287 1.1 fredette * 1288 1.1 fredette * Our return value determines whether our caller, sunscpal_machine() 1289 1.1 fredette * will expect to see another REQ (and possibly phase change). 1290 1.1 fredette */ 1291 1.1 fredette static int 1292 1.23 tsutsui sunscpal_msg_in(struct sunscpal_softc *sc) 1293 1.1 fredette { 1294 1.1 fredette struct sunscpal_req *sr = sc->sc_current; 1295 1.1 fredette struct scsipi_xfer *xs = sr->sr_xs; 1296 1.1 fredette int n, phase; 1297 1.1 fredette int act_flags; 1298 1.1 fredette 1299 1.1 fredette act_flags = ACT_CONTINUE; 1300 1.1 fredette 1301 1.1 fredette if (sc->sc_prevphase == SUNSCPAL_PHASE_MSG_IN) { 1302 1.1 fredette /* This is a continuation of the previous message. */ 1303 1.1 fredette n = sc->sc_imp - sc->sc_imess; 1304 1.1 fredette SUNSCPAL_TRACE("msg_in: continuation, n=%d\n", n); 1305 1.1 fredette goto nextbyte; 1306 1.1 fredette } 1307 1.1 fredette 1308 1.1 fredette /* This is a new MESSAGE IN phase. Clean up our state. */ 1309 1.1 fredette sc->sc_state &= ~SUNSCPAL_DROP_MSGIN; 1310 1.1 fredette 1311 1.23 tsutsui nextmsg: 1312 1.1 fredette n = 0; 1313 1.1 fredette sc->sc_imp = &sc->sc_imess[n]; 1314 1.1 fredette 1315 1.23 tsutsui nextbyte: 1316 1.1 fredette /* 1317 1.1 fredette * Read a whole message, but don't ack the last byte. If we reject the 1318 1.1 fredette * message, we have to assert ATN during the message transfer phase 1319 1.1 fredette * itself. 1320 1.1 fredette */ 1321 1.1 fredette for (;;) { 1322 1.1 fredette /* 1323 1.1 fredette * Read a message byte. 1324 1.1 fredette * First, check BSY, REQ, phase... 1325 1.1 fredette */ 1326 1.1 fredette if (!SUNSCPAL_BUSY(sc)) { 1327 1.1 fredette SUNSCPAL_TRACE("msg_in: lost BSY, n=%d\n", n); 1328 1.1 fredette /* XXX - Assume the command completed? */ 1329 1.1 fredette act_flags |= (ACT_DISCONNECT | ACT_CMD_DONE); 1330 1.23 tsutsui return act_flags; 1331 1.1 fredette } 1332 1.1 fredette if (sunscpal_wait_req(sc)) { 1333 1.1 fredette SUNSCPAL_TRACE("msg_in: BSY but no REQ, n=%d\n", n); 1334 1.1 fredette /* Just let sunscpal_machine() handle it... */ 1335 1.23 tsutsui return act_flags; 1336 1.1 fredette } 1337 1.1 fredette phase = SUNSCPAL_BUS_PHASE(SUNSCPAL_READ_2(sc, sunscpal_icr)); 1338 1.1 fredette if (phase != SUNSCPAL_PHASE_MSG_IN) { 1339 1.1 fredette /* 1340 1.1 fredette * Target left MESSAGE IN, probably because it 1341 1.1 fredette * a) noticed our ATN signal, or 1342 1.1 fredette * b) ran out of messages. 1343 1.1 fredette */ 1344 1.23 tsutsui return act_flags; 1345 1.1 fredette } 1346 1.1 fredette /* Still in MESSAGE IN phase, and REQ is asserted. */ 1347 1.23 tsutsui if ((SUNSCPAL_READ_2(sc, sunscpal_icr) & 1348 1.23 tsutsui SUNSCPAL_ICR_PARITY_ERROR) != 0) { 1349 1.1 fredette sunscpal_sched_msgout(sc, SEND_PARITY_ERROR); 1350 1.1 fredette sc->sc_state |= SUNSCPAL_DROP_MSGIN; 1351 1.1 fredette } 1352 1.1 fredette 1353 1.1 fredette /* Gather incoming message bytes if needed. */ 1354 1.1 fredette if ((sc->sc_state & SUNSCPAL_DROP_MSGIN) == 0) { 1355 1.1 fredette if (n >= SUNSCPAL_MAX_MSG_LEN) { 1356 1.1 fredette sunscpal_sched_msgout(sc, SEND_REJECT); 1357 1.1 fredette sc->sc_state |= SUNSCPAL_DROP_MSGIN; 1358 1.1 fredette } else { 1359 1.23 tsutsui *sc->sc_imp++ = 1360 1.23 tsutsui SUNSCPAL_READ_1(sc, sunscpal_cmd_stat); 1361 1.1 fredette n++; 1362 1.1 fredette /* 1363 1.1 fredette * This testing is suboptimal, but most 1364 1.1 fredette * messages will be of the one byte variety, so 1365 1.1 fredette * it should not affect performance 1366 1.1 fredette * significantly. 1367 1.1 fredette */ 1368 1.8 tsutsui if (n == 1 && MSG_IS1BYTE(sc->sc_imess[0])) 1369 1.1 fredette goto have_msg; 1370 1.8 tsutsui if (n == 2 && MSG_IS2BYTE(sc->sc_imess[0])) 1371 1.1 fredette goto have_msg; 1372 1.8 tsutsui if (n >= 3 && MSG_ISEXTENDED(sc->sc_imess[0]) && 1373 1.1 fredette n == sc->sc_imess[1] + 2) 1374 1.1 fredette goto have_msg; 1375 1.1 fredette } 1376 1.1 fredette } 1377 1.1 fredette 1378 1.1 fredette /* 1379 1.1 fredette * If we reach this spot we're either: 1380 1.1 fredette * a) in the middle of a multi-byte message, or 1381 1.1 fredette * b) dropping bytes. 1382 1.1 fredette */ 1383 1.1 fredette 1384 1.1 fredette if (act_flags != ACT_CONTINUE) 1385 1.23 tsutsui return act_flags; 1386 1.1 fredette 1387 1.1 fredette /* back to nextbyte */ 1388 1.1 fredette } 1389 1.1 fredette 1390 1.23 tsutsui have_msg: 1391 1.1 fredette /* We now have a complete message. Parse it. */ 1392 1.1 fredette 1393 1.1 fredette switch (sc->sc_imess[0]) { 1394 1.1 fredette case MSG_CMDCOMPLETE: 1395 1.1 fredette SUNSCPAL_TRACE("msg_in: CMDCOMPLETE\n", 0); 1396 1.1 fredette /* Target is about to disconnect. */ 1397 1.1 fredette act_flags |= (ACT_DISCONNECT | ACT_CMD_DONE); 1398 1.1 fredette break; 1399 1.1 fredette 1400 1.1 fredette case MSG_PARITY_ERROR: 1401 1.1 fredette SUNSCPAL_TRACE("msg_in: PARITY_ERROR\n", 0); 1402 1.1 fredette /* Resend the last message. */ 1403 1.1 fredette sunscpal_sched_msgout(sc, sc->sc_msgout); 1404 1.1 fredette break; 1405 1.1 fredette 1406 1.1 fredette case MSG_MESSAGE_REJECT: 1407 1.1 fredette /* The target rejects the last message we sent. */ 1408 1.1 fredette SUNSCPAL_TRACE("msg_in: got reject for 0x%x\n", sc->sc_msgout); 1409 1.1 fredette switch (sc->sc_msgout) { 1410 1.1 fredette case SEND_IDENTIFY: 1411 1.1 fredette /* Really old target controller? */ 1412 1.1 fredette /* XXX ... */ 1413 1.1 fredette break; 1414 1.1 fredette case SEND_INIT_DET_ERR: 1415 1.1 fredette goto abort; 1416 1.1 fredette } 1417 1.1 fredette break; 1418 1.1 fredette 1419 1.1 fredette case MSG_NOOP: 1420 1.1 fredette SUNSCPAL_TRACE("msg_in: NOOP\n", 0); 1421 1.1 fredette break; 1422 1.1 fredette 1423 1.1 fredette case MSG_DISCONNECT: 1424 1.1 fredette SUNSCPAL_TRACE("msg_in: DISCONNECT\n", 0); 1425 1.1 fredette /* Target is about to disconnect. */ 1426 1.1 fredette act_flags |= ACT_DISCONNECT; 1427 1.2 bouyer if ((xs->xs_periph->periph_quirks & PQUIRK_AUTOSAVE) == 0) 1428 1.1 fredette break; 1429 1.1 fredette /*FALLTHROUGH*/ 1430 1.1 fredette 1431 1.1 fredette case MSG_SAVEDATAPOINTER: 1432 1.1 fredette SUNSCPAL_TRACE("msg_in: SAVE_PTRS\n", 0); 1433 1.1 fredette sr->sr_dataptr = sc->sc_dataptr; 1434 1.1 fredette sr->sr_datalen = sc->sc_datalen; 1435 1.1 fredette break; 1436 1.1 fredette 1437 1.1 fredette case MSG_RESTOREPOINTERS: 1438 1.1 fredette SUNSCPAL_TRACE("msg_in: RESTORE_PTRS\n", 0); 1439 1.1 fredette sc->sc_dataptr = sr->sr_dataptr; 1440 1.1 fredette sc->sc_datalen = sr->sr_datalen; 1441 1.1 fredette break; 1442 1.1 fredette 1443 1.1 fredette case MSG_EXTENDED: 1444 1.1 fredette switch (sc->sc_imess[2]) { 1445 1.1 fredette case MSG_EXT_SDTR: 1446 1.1 fredette case MSG_EXT_WDTR: 1447 1.23 tsutsui /* This controller can not do synchronous mode. */ 1448 1.1 fredette goto reject; 1449 1.1 fredette default: 1450 1.23 tsutsui printf("%s: unrecognized MESSAGE EXTENDED; " 1451 1.23 tsutsui "sending REJECT\n", 1452 1.23 tsutsui device_xname(sc->sc_dev)); 1453 1.1 fredette SUNSCPAL_BREAK(); 1454 1.1 fredette goto reject; 1455 1.1 fredette } 1456 1.1 fredette break; 1457 1.1 fredette 1458 1.1 fredette default: 1459 1.1 fredette SUNSCPAL_TRACE("msg_in: eh? imsg=0x%x\n", sc->sc_imess[0]); 1460 1.1 fredette printf("%s: unrecognized MESSAGE; sending REJECT\n", 1461 1.23 tsutsui device_xname(sc->sc_dev)); 1462 1.1 fredette SUNSCPAL_BREAK(); 1463 1.23 tsutsui /* FALLTHROUGH */ 1464 1.1 fredette reject: 1465 1.1 fredette sunscpal_sched_msgout(sc, SEND_REJECT); 1466 1.1 fredette break; 1467 1.1 fredette 1468 1.1 fredette abort: 1469 1.1 fredette sc->sc_state |= SUNSCPAL_ABORTING; 1470 1.1 fredette sunscpal_sched_msgout(sc, SEND_ABORT); 1471 1.1 fredette break; 1472 1.1 fredette } 1473 1.1 fredette 1474 1.1 fredette /* Go get the next message, if any. */ 1475 1.1 fredette if (act_flags == ACT_CONTINUE) 1476 1.1 fredette goto nextmsg; 1477 1.1 fredette 1478 1.23 tsutsui return act_flags; 1479 1.1 fredette } 1480 1.1 fredette 1481 1.1 fredette 1482 1.1 fredette /* 1483 1.1 fredette * The message out (and in) stuff is a bit complicated: 1484 1.1 fredette * If the target requests another message (sequence) without 1485 1.1 fredette * having changed phase in between it really asks for a 1486 1.1 fredette * retransmit, probably due to parity error(s). 1487 1.1 fredette * The following messages can be sent: 1488 1.1 fredette * IDENTIFY @ These 4 stem from SCSI command activity 1489 1.1 fredette * SDTR @ 1490 1.1 fredette * WDTR @ 1491 1.1 fredette * DEV_RESET @ 1492 1.1 fredette * REJECT if MSGI doesn't make sense 1493 1.1 fredette * PARITY_ERROR if parity error while in MSGI 1494 1.1 fredette * INIT_DET_ERR if parity error while not in MSGI 1495 1.1 fredette * ABORT if INIT_DET_ERR rejected 1496 1.1 fredette * NOOP if asked for a message and there's nothing to send 1497 1.1 fredette * 1498 1.1 fredette * Note that we call this one with (sc_current == NULL) 1499 1.1 fredette * when sending ABORT for unwanted reselections. 1500 1.1 fredette */ 1501 1.1 fredette static int 1502 1.23 tsutsui sunscpal_msg_out(struct sunscpal_softc *sc) 1503 1.1 fredette { 1504 1.17 perry /* 1505 1.1 fredette * This controller does not allow you to assert ATN, which 1506 1.1 fredette * means we will never get the opportunity to send messages to 1507 1.1 fredette * the target (the bus will never enter this MSG_OUT phase). 1508 1.1 fredette * This will eventually leave us with no option other than to 1509 1.1 fredette * reset the bus. We keep this function as a placeholder, 1510 1.1 fredette * though, and this printf will eventually go away or get 1511 1.1 fredette * #ifdef'ed: 1512 1.1 fredette */ 1513 1.23 tsutsui printf("%s: bus is in MSG_OUT phase?\n", __func__); 1514 1.23 tsutsui return ACT_CONTINUE | ACT_RESET_BUS; 1515 1.1 fredette } 1516 1.1 fredette 1517 1.1 fredette /* 1518 1.1 fredette * Handle command phase. 1519 1.1 fredette */ 1520 1.1 fredette static int 1521 1.23 tsutsui sunscpal_command(struct sunscpal_softc *sc) 1522 1.1 fredette { 1523 1.1 fredette struct sunscpal_req *sr = sc->sc_current; 1524 1.1 fredette struct scsipi_xfer *xs = sr->sr_xs; 1525 1.1 fredette int len; 1526 1.1 fredette 1527 1.2 bouyer /* Assume command can be sent in one go. */ 1528 1.2 bouyer /* XXX: Do this using DMA, and get a phase change intr? */ 1529 1.2 bouyer len = sunscpal_pio_out(sc, SUNSCPAL_PHASE_COMMAND, xs->cmdlen, 1530 1.23 tsutsui (uint8_t *)xs->cmd); 1531 1.1 fredette 1532 1.1 fredette if (len != xs->cmdlen) { 1533 1.1 fredette #ifdef SUNSCPAL_DEBUG 1534 1.23 tsutsui printf("%s: short transfer: wanted %d got %d.\n", 1535 1.23 tsutsui __func__, xs->cmdlen, len); 1536 1.1 fredette sunscpal_show_scsi_cmd(xs); 1537 1.1 fredette SUNSCPAL_BREAK(); 1538 1.1 fredette #endif 1539 1.1 fredette if (len < 6) { 1540 1.1 fredette xs->error = XS_DRIVER_STUFFUP; 1541 1.1 fredette sc->sc_state |= SUNSCPAL_ABORTING; 1542 1.1 fredette sunscpal_sched_msgout(sc, SEND_ABORT); 1543 1.1 fredette } 1544 1.1 fredette 1545 1.1 fredette } 1546 1.1 fredette 1547 1.1 fredette return ACT_CONTINUE; 1548 1.1 fredette } 1549 1.1 fredette 1550 1.1 fredette 1551 1.1 fredette /* 1552 1.1 fredette * Handle either data_in or data_out 1553 1.1 fredette */ 1554 1.1 fredette static int 1555 1.23 tsutsui sunscpal_data_xfer(struct sunscpal_softc *sc, int phase) 1556 1.1 fredette { 1557 1.1 fredette struct sunscpal_req *sr = sc->sc_current; 1558 1.1 fredette struct scsipi_xfer *xs = sr->sr_xs; 1559 1.1 fredette int expected_phase; 1560 1.1 fredette int len; 1561 1.1 fredette 1562 1.1 fredette /* 1563 1.1 fredette * When aborting a command, disallow any data phase. 1564 1.1 fredette */ 1565 1.1 fredette if (sc->sc_state & SUNSCPAL_ABORTING) { 1566 1.23 tsutsui printf("%s: aborting, bus phase=%s (reset)\n", 1567 1.23 tsutsui device_xname(sc->sc_dev), phase_names[(phase >> 8) & 7]); 1568 1.1 fredette return ACT_RESET_BUS; /* XXX */ 1569 1.1 fredette } 1570 1.1 fredette 1571 1.1 fredette /* Validate expected phase (data_in or data_out) */ 1572 1.1 fredette expected_phase = (xs->xs_control & XS_CTL_DATA_OUT) ? 1573 1.23 tsutsui SUNSCPAL_PHASE_DATA_OUT : SUNSCPAL_PHASE_DATA_IN; 1574 1.1 fredette if (phase != expected_phase) { 1575 1.23 tsutsui printf("%s: data phase error\n", device_xname(sc->sc_dev)); 1576 1.1 fredette goto abort; 1577 1.1 fredette } 1578 1.1 fredette 1579 1.1 fredette /* Make sure we have some data to move. */ 1580 1.1 fredette if (sc->sc_datalen <= 0) { 1581 1.1 fredette /* Device needs padding. */ 1582 1.1 fredette if (phase == SUNSCPAL_PHASE_DATA_IN) 1583 1.1 fredette sunscpal_pio_in(sc, phase, 4096, NULL); 1584 1.1 fredette else 1585 1.1 fredette sunscpal_pio_out(sc, phase, 4096, NULL); 1586 1.1 fredette /* Make sure that caused a phase change. */ 1587 1.23 tsutsui if (SUNSCPAL_BUS_PHASE(SUNSCPAL_READ_2(sc, sunscpal_icr)) == 1588 1.23 tsutsui phase) { 1589 1.1 fredette /* More than 4k is just too much! */ 1590 1.23 tsutsui printf("%s: too much data padding\n", 1591 1.23 tsutsui device_xname(sc->sc_dev)); 1592 1.1 fredette goto abort; 1593 1.1 fredette } 1594 1.1 fredette return ACT_CONTINUE; 1595 1.1 fredette } 1596 1.1 fredette 1597 1.1 fredette /* 1598 1.1 fredette * Attempt DMA only if dma_alloc gave us a DMA handle AND 1599 1.1 fredette * there is enough left to transfer so DMA is worth while. 1600 1.1 fredette */ 1601 1.23 tsutsui if (sr->sr_dma_hand && (sc->sc_datalen >= sc->sc_min_dma_len)) { 1602 1.1 fredette /* 1603 1.1 fredette * OK, really start DMA. Note, the MD start function 1604 1.1 fredette * is responsible for setting the TCMD register, etc. 1605 1.1 fredette * (Acknowledge the phase change there, not here.) 1606 1.1 fredette */ 1607 1.1 fredette SUNSCPAL_TRACE("data_xfer: dma_start, dh=0x%x\n", 1608 1.23 tsutsui (long)sr->sr_dma_hand); 1609 1.1 fredette sunscpal_dma_start(sc); 1610 1.1 fredette return ACT_WAIT_DMA; 1611 1.1 fredette } 1612 1.1 fredette 1613 1.1 fredette /* 1614 1.1 fredette * Doing PIO for data transfer. (Possibly "Pseudo DMA") 1615 1.1 fredette * XXX: Do PDMA functions need to set tcmd later? 1616 1.1 fredette */ 1617 1.1 fredette SUNSCPAL_TRACE("data_xfer: doing PIO, len=%d\n", sc->sc_datalen); 1618 1.1 fredette if (phase == SUNSCPAL_PHASE_DATA_OUT) { 1619 1.23 tsutsui len = sunscpal_pio_out(sc, phase, 1620 1.23 tsutsui sc->sc_datalen, sc->sc_dataptr); 1621 1.1 fredette } else { 1622 1.23 tsutsui len = sunscpal_pio_in(sc, phase, 1623 1.23 tsutsui sc->sc_datalen, sc->sc_dataptr); 1624 1.1 fredette } 1625 1.1 fredette sc->sc_dataptr += len; 1626 1.1 fredette sc->sc_datalen -= len; 1627 1.1 fredette 1628 1.1 fredette SUNSCPAL_TRACE("data_xfer: did PIO, resid=%d\n", sc->sc_datalen); 1629 1.23 tsutsui return ACT_CONTINUE; 1630 1.1 fredette 1631 1.23 tsutsui abort: 1632 1.1 fredette sc->sc_state |= SUNSCPAL_ABORTING; 1633 1.1 fredette sunscpal_sched_msgout(sc, SEND_ABORT); 1634 1.23 tsutsui return ACT_CONTINUE; 1635 1.1 fredette } 1636 1.1 fredette 1637 1.1 fredette 1638 1.1 fredette static int 1639 1.23 tsutsui sunscpal_status(struct sunscpal_softc *sc) 1640 1.1 fredette { 1641 1.1 fredette int len; 1642 1.23 tsutsui uint8_t status; 1643 1.1 fredette struct sunscpal_req *sr = sc->sc_current; 1644 1.1 fredette 1645 1.1 fredette len = sunscpal_pio_in(sc, SUNSCPAL_PHASE_STATUS, 1, &status); 1646 1.1 fredette if (len) { 1647 1.1 fredette sr->sr_status = status; 1648 1.1 fredette } else { 1649 1.23 tsutsui printf("%s: none?\n", __func__); 1650 1.1 fredette } 1651 1.1 fredette 1652 1.1 fredette return ACT_CONTINUE; 1653 1.1 fredette } 1654 1.1 fredette 1655 1.1 fredette 1656 1.1 fredette /* 1657 1.1 fredette * This is the big state machine that follows SCSI phase changes. 1658 1.1 fredette * This is somewhat like a co-routine. It will do a SCSI command, 1659 1.1 fredette * and exit if the command is complete, or if it must wait, i.e. 1660 1.1 fredette * for DMA to complete or for reselect to resume the job. 1661 1.1 fredette * 1662 1.1 fredette * The bus must be selected, and we need to know which command is 1663 1.1 fredette * being undertaken. 1664 1.1 fredette */ 1665 1.1 fredette static void 1666 1.23 tsutsui sunscpal_machine(struct sunscpal_softc *sc) 1667 1.1 fredette { 1668 1.1 fredette struct sunscpal_req *sr; 1669 1.1 fredette struct scsipi_xfer *xs; 1670 1.1 fredette int act_flags, phase, timo; 1671 1.1 fredette 1672 1.1 fredette #ifdef DIAGNOSTIC 1673 1.1 fredette if (sc->sc_state == SUNSCPAL_IDLE) 1674 1.23 tsutsui panic("%s: state=idle", __func__); 1675 1.1 fredette if (sc->sc_current == NULL) 1676 1.23 tsutsui panic("%s: no current cmd", __func__); 1677 1.1 fredette #endif 1678 1.1 fredette 1679 1.1 fredette sr = sc->sc_current; 1680 1.1 fredette xs = sr->sr_xs; 1681 1.1 fredette act_flags = ACT_CONTINUE; 1682 1.1 fredette 1683 1.1 fredette /* 1684 1.1 fredette * This will be called by sunscpal_intr() when DMA is 1685 1.1 fredette * complete. Must stop DMA before touching the PAL or 1686 1.1 fredette * there will be "register conflict" errors. 1687 1.1 fredette */ 1688 1.23 tsutsui if ((sc->sc_state & SUNSCPAL_DOINGDMA) != 0) { 1689 1.1 fredette /* Pick-up where where we left off... */ 1690 1.1 fredette goto dma_done; 1691 1.1 fredette } 1692 1.1 fredette 1693 1.23 tsutsui next_phase: 1694 1.1 fredette 1695 1.1 fredette if (!SUNSCPAL_BUSY(sc)) { 1696 1.1 fredette /* Unexpected disconnect */ 1697 1.23 tsutsui printf("%s: unexpected disconnect.\n", __func__); 1698 1.1 fredette xs->error = XS_DRIVER_STUFFUP; 1699 1.1 fredette act_flags |= (ACT_DISCONNECT | ACT_CMD_DONE); 1700 1.1 fredette goto do_actions; 1701 1.1 fredette } 1702 1.1 fredette 1703 1.1 fredette /* 1704 1.1 fredette * Wait for REQ before reading the phase. 1705 1.1 fredette * Need to wait longer than usual here, because 1706 1.1 fredette * some devices are just plain slow... 1707 1.1 fredette */ 1708 1.1 fredette timo = sunscpal_wait_phase_timo; 1709 1.1 fredette for (;;) { 1710 1.1 fredette if (SUNSCPAL_READ_2(sc, sunscpal_icr) & SUNSCPAL_ICR_REQUEST) 1711 1.1 fredette break; 1712 1.1 fredette if (--timo <= 0) { 1713 1.1 fredette if (sc->sc_state & SUNSCPAL_ABORTING) { 1714 1.23 tsutsui printf("%s: no REQ while aborting, reset\n", 1715 1.23 tsutsui device_xname(sc->sc_dev)); 1716 1.1 fredette act_flags |= ACT_RESET_BUS; 1717 1.1 fredette goto do_actions; 1718 1.1 fredette } 1719 1.23 tsutsui printf("%s: no REQ for next phase, abort\n", 1720 1.23 tsutsui device_xname(sc->sc_dev)); 1721 1.1 fredette sc->sc_state |= SUNSCPAL_ABORTING; 1722 1.1 fredette sunscpal_sched_msgout(sc, SEND_ABORT); 1723 1.1 fredette goto next_phase; 1724 1.1 fredette } 1725 1.1 fredette delay(100); 1726 1.1 fredette } 1727 1.1 fredette 1728 1.1 fredette phase = SUNSCPAL_BUS_PHASE(SUNSCPAL_READ_2(sc, sunscpal_icr)); 1729 1.1 fredette SUNSCPAL_TRACE("machine: phase=%s\n", 1730 1.23 tsutsui (long)phase_names[(phase >> 8) & 7]); 1731 1.1 fredette 1732 1.1 fredette /* 1733 1.1 fredette * We assume that the device knows what it's doing, 1734 1.1 fredette * so any phase is good. 1735 1.1 fredette */ 1736 1.1 fredette 1737 1.1 fredette switch (phase) { 1738 1.1 fredette 1739 1.1 fredette case SUNSCPAL_PHASE_DATA_OUT: 1740 1.1 fredette case SUNSCPAL_PHASE_DATA_IN: 1741 1.1 fredette act_flags = sunscpal_data_xfer(sc, phase); 1742 1.1 fredette break; 1743 1.1 fredette 1744 1.1 fredette case SUNSCPAL_PHASE_COMMAND: 1745 1.1 fredette act_flags = sunscpal_command(sc); 1746 1.1 fredette break; 1747 1.1 fredette 1748 1.1 fredette case SUNSCPAL_PHASE_STATUS: 1749 1.1 fredette act_flags = sunscpal_status(sc); 1750 1.1 fredette break; 1751 1.1 fredette 1752 1.1 fredette case SUNSCPAL_PHASE_MSG_OUT: 1753 1.1 fredette act_flags = sunscpal_msg_out(sc); 1754 1.1 fredette break; 1755 1.1 fredette 1756 1.1 fredette case SUNSCPAL_PHASE_MSG_IN: 1757 1.1 fredette act_flags = sunscpal_msg_in(sc); 1758 1.1 fredette break; 1759 1.1 fredette 1760 1.1 fredette default: 1761 1.23 tsutsui printf("%s: Unexpected phase 0x%x\n", __func__, phase); 1762 1.1 fredette sc->sc_state |= SUNSCPAL_ABORTING; 1763 1.1 fredette sunscpal_sched_msgout(sc, SEND_ABORT); 1764 1.1 fredette goto next_phase; 1765 1.1 fredette 1766 1.1 fredette } /* switch */ 1767 1.1 fredette sc->sc_prevphase = phase; 1768 1.1 fredette 1769 1.23 tsutsui do_actions: 1770 1.1 fredette 1771 1.1 fredette if (act_flags & ACT_WAIT_DMA) { 1772 1.1 fredette act_flags &= ~ACT_WAIT_DMA; 1773 1.1 fredette /* Wait for DMA to complete (polling, or interrupt). */ 1774 1.1 fredette if ((sr->sr_flags & SR_IMMED) == 0) { 1775 1.1 fredette SUNSCPAL_TRACE("machine: wait for DMA intr.\n", 0); 1776 1.1 fredette return; /* will resume at dma_done */ 1777 1.1 fredette } 1778 1.1 fredette /* Busy-wait for it to finish. */ 1779 1.1 fredette SUNSCPAL_TRACE("machine: dma_poll, dh=0x%x\n", 1780 1.23 tsutsui (long)sr->sr_dma_hand); 1781 1.1 fredette sunscpal_dma_poll(sc); 1782 1.23 tsutsui dma_done: 1783 1.1 fredette /* Return here after interrupt. */ 1784 1.1 fredette if (sr->sr_flags & SR_OVERDUE) 1785 1.1 fredette sc->sc_state |= SUNSCPAL_ABORTING; 1786 1.1 fredette SUNSCPAL_TRACE("machine: dma_stop, dh=0x%x\n", 1787 1.23 tsutsui (long)sr->sr_dma_hand); 1788 1.1 fredette sunscpal_dma_stop(sc); 1789 1.1 fredette SUNSCPAL_CLR_INTR(sc); /* XXX */ 1790 1.1 fredette /* 1791 1.1 fredette * While DMA is running we can not touch the SBC, 1792 1.1 fredette * so various places just set SUNSCPAL_ABORTING and 1793 1.1 fredette * expect us the "kick it" when DMA is done. 1794 1.1 fredette */ 1795 1.1 fredette if (sc->sc_state & SUNSCPAL_ABORTING) { 1796 1.1 fredette sunscpal_sched_msgout(sc, SEND_ABORT); 1797 1.1 fredette } 1798 1.1 fredette } 1799 1.1 fredette 1800 1.1 fredette /* 1801 1.1 fredette * Check for parity error. 1802 1.1 fredette * XXX - better place to check? 1803 1.1 fredette */ 1804 1.1 fredette if (SUNSCPAL_READ_2(sc, sunscpal_icr) & SUNSCPAL_ICR_PARITY_ERROR) { 1805 1.23 tsutsui printf("%s: parity error!\n", device_xname(sc->sc_dev)); 1806 1.1 fredette /* XXX: sc->sc_state |= SUNSCPAL_ABORTING; */ 1807 1.1 fredette sunscpal_sched_msgout(sc, SEND_PARITY_ERROR); 1808 1.1 fredette } 1809 1.1 fredette 1810 1.1 fredette if (act_flags == ACT_CONTINUE) 1811 1.1 fredette goto next_phase; 1812 1.1 fredette /* All other actions "break" from the loop. */ 1813 1.1 fredette 1814 1.1 fredette SUNSCPAL_TRACE("machine: act_flags=0x%x\n", act_flags); 1815 1.1 fredette 1816 1.1 fredette if (act_flags & ACT_RESET_BUS) { 1817 1.1 fredette act_flags |= ACT_CMD_DONE; 1818 1.1 fredette /* 1819 1.1 fredette * Reset the SCSI bus, usually due to a timeout. 1820 1.1 fredette * The error code XS_TIMEOUT allows retries. 1821 1.1 fredette */ 1822 1.1 fredette sc->sc_state |= SUNSCPAL_ABORTING; 1823 1.1 fredette printf("%s: reset SCSI bus for TID=%d LUN=%d\n", 1824 1.23 tsutsui device_xname(sc->sc_dev), sr->sr_target, sr->sr_lun); 1825 1.1 fredette sunscpal_reset_scsibus(sc); 1826 1.1 fredette } 1827 1.1 fredette 1828 1.1 fredette if (act_flags & ACT_CMD_DONE) { 1829 1.1 fredette act_flags |= ACT_DISCONNECT; 1830 1.1 fredette /* Need to call scsipi_done() */ 1831 1.1 fredette /* XXX: from the aic6360 driver, but why? */ 1832 1.1 fredette if (sc->sc_datalen < 0) { 1833 1.1 fredette printf("%s: %d extra bytes from %d:%d\n", 1834 1.23 tsutsui device_xname(sc->sc_dev), -sc->sc_datalen, 1835 1.1 fredette sr->sr_target, sr->sr_lun); 1836 1.1 fredette sc->sc_datalen = 0; 1837 1.1 fredette } 1838 1.1 fredette xs->resid = sc->sc_datalen; 1839 1.1 fredette /* Note: this will clear sc_current */ 1840 1.1 fredette SUNSCPAL_TRACE("machine: call done, cur=0x%x\n", (long)sr); 1841 1.1 fredette sunscpal_done(sc); 1842 1.1 fredette } 1843 1.1 fredette 1844 1.1 fredette if (act_flags & ACT_DISCONNECT) { 1845 1.1 fredette /* 1846 1.1 fredette * The device has dropped BSY (or will soon). 1847 1.1 fredette * We have to wait here for BSY to drop, otherwise 1848 1.1 fredette * the next command may decide we need a bus reset. 1849 1.1 fredette */ 1850 1.1 fredette timo = sunscpal_wait_req_timo; /* XXX */ 1851 1.1 fredette for (;;) { 1852 1.1 fredette if (!SUNSCPAL_BUSY(sc)) 1853 1.1 fredette goto busfree; 1854 1.1 fredette if (--timo <= 0) 1855 1.1 fredette break; 1856 1.1 fredette delay(2); 1857 1.1 fredette } 1858 1.1 fredette /* Device is sitting on the bus! */ 1859 1.1 fredette printf("%s: Target %d LUN %d stuck busy, resetting...\n", 1860 1.23 tsutsui device_xname(sc->sc_dev), sr->sr_target, sr->sr_lun); 1861 1.1 fredette sunscpal_reset_scsibus(sc); 1862 1.23 tsutsui busfree: 1863 1.1 fredette SUNSCPAL_TRACE("machine: discon, waited %d\n", 1864 1.1 fredette sunscpal_wait_req_timo - timo); 1865 1.1 fredette 1866 1.1 fredette SUNSCPAL_WRITE_2(sc, sunscpal_icr, 0); 1867 1.1 fredette 1868 1.1 fredette if ((act_flags & ACT_CMD_DONE) == 0) { 1869 1.1 fredette SUNSCPAL_TRACE("machine: discon, cur=0x%x\n", (long)sr); 1870 1.1 fredette } 1871 1.1 fredette 1872 1.1 fredette /* 1873 1.1 fredette * We may be here due to a disconnect message, 1874 1.1 fredette * in which case we did NOT call sunscpal_done, 1875 1.1 fredette * and we need to clear sc_current. 1876 1.1 fredette */ 1877 1.1 fredette sc->sc_state = SUNSCPAL_IDLE; 1878 1.1 fredette sc->sc_current = NULL; 1879 1.1 fredette 1880 1.1 fredette /* Paranoia: clear everything. */ 1881 1.1 fredette sc->sc_dataptr = NULL; 1882 1.1 fredette sc->sc_datalen = 0; 1883 1.1 fredette sc->sc_prevphase = SUNSCPAL_PHASE_INVALID; 1884 1.1 fredette sc->sc_msgpriq = 0; 1885 1.1 fredette sc->sc_msgoutq = 0; 1886 1.1 fredette sc->sc_msgout = 0; 1887 1.1 fredette 1888 1.1 fredette /* Our caller will re-enable interrupts. */ 1889 1.1 fredette } 1890 1.1 fredette } 1891 1.1 fredette 1892 1.1 fredette 1893 1.1 fredette #ifdef SUNSCPAL_DEBUG 1894 1.1 fredette 1895 1.1 fredette static void 1896 1.23 tsutsui sunscpal_show_scsi_cmd(struct scsipi_xfer *xs) 1897 1.1 fredette { 1898 1.23 tsutsui uint8_t *b = (uint8_t *)xs->cmd; 1899 1.23 tsutsui int i = 0; 1900 1.1 fredette 1901 1.2 bouyer scsipi_printaddr(xs->xs_periph); 1902 1.23 tsutsui if ((xs->xs_control & XS_CTL_RESET) == 0) { 1903 1.2 bouyer printf("-"); 1904 1.1 fredette while (i < xs->cmdlen) { 1905 1.23 tsutsui if (i != 0) 1906 1.23 tsutsui printf(","); 1907 1.23 tsutsui printf("%x", b[i++]); 1908 1.1 fredette } 1909 1.1 fredette printf("-\n"); 1910 1.1 fredette } else { 1911 1.2 bouyer printf("-RESET-\n"); 1912 1.1 fredette } 1913 1.1 fredette } 1914 1.1 fredette 1915 1.1 fredette 1916 1.1 fredette int sunscpal_traceidx = 0; 1917 1.1 fredette 1918 1.1 fredette #define TRACE_MAX 1024 1919 1.1 fredette struct trace_ent { 1920 1.1 fredette char *msg; 1921 1.1 fredette long val; 1922 1.1 fredette } sunscpal_tracebuf[TRACE_MAX]; 1923 1.1 fredette 1924 1.1 fredette void 1925 1.23 tsutsui sunscpal_trace(char *msg, long val) 1926 1.1 fredette { 1927 1.1 fredette struct trace_ent *tr; 1928 1.1 fredette int s; 1929 1.1 fredette 1930 1.1 fredette s = splbio(); 1931 1.1 fredette 1932 1.1 fredette tr = &sunscpal_tracebuf[sunscpal_traceidx]; 1933 1.1 fredette 1934 1.1 fredette sunscpal_traceidx++; 1935 1.1 fredette if (sunscpal_traceidx >= TRACE_MAX) 1936 1.1 fredette sunscpal_traceidx = 0; 1937 1.1 fredette 1938 1.1 fredette tr->msg = msg; 1939 1.1 fredette tr->val = val; 1940 1.1 fredette 1941 1.1 fredette splx(s); 1942 1.1 fredette } 1943 1.1 fredette 1944 1.1 fredette #ifdef DDB 1945 1.1 fredette void 1946 1.23 tsutsui sunscpal_clear_trace(void) 1947 1.1 fredette { 1948 1.23 tsutsui 1949 1.1 fredette sunscpal_traceidx = 0; 1950 1.23 tsutsui memset((void *)sunscpal_tracebuf, 0, sizeof(sunscpal_tracebuf)); 1951 1.1 fredette } 1952 1.1 fredette 1953 1.1 fredette void 1954 1.23 tsutsui sunscpal_show_trace(void) 1955 1.1 fredette { 1956 1.1 fredette struct trace_ent *tr; 1957 1.1 fredette int idx; 1958 1.1 fredette 1959 1.1 fredette idx = sunscpal_traceidx; 1960 1.1 fredette do { 1961 1.1 fredette tr = &sunscpal_tracebuf[idx]; 1962 1.1 fredette idx++; 1963 1.1 fredette if (idx >= TRACE_MAX) 1964 1.1 fredette idx = 0; 1965 1.1 fredette if (tr->msg) 1966 1.1 fredette db_printf(tr->msg, tr->val); 1967 1.1 fredette } while (idx != sunscpal_traceidx); 1968 1.1 fredette } 1969 1.1 fredette 1970 1.1 fredette void 1971 1.23 tsutsui sunscpal_show_req(struct sunscpal_req *sr) 1972 1.1 fredette { 1973 1.1 fredette struct scsipi_xfer *xs = sr->sr_xs; 1974 1.1 fredette 1975 1.1 fredette db_printf("TID=%d ", sr->sr_target); 1976 1.1 fredette db_printf("LUN=%d ", sr->sr_lun); 1977 1.1 fredette db_printf("dh=%p ", sr->sr_dma_hand); 1978 1.1 fredette db_printf("dptr=%p ", sr->sr_dataptr); 1979 1.1 fredette db_printf("dlen=0x%x ", sr->sr_datalen); 1980 1.1 fredette db_printf("flags=%d ", sr->sr_flags); 1981 1.1 fredette db_printf("stat=%d ", sr->sr_status); 1982 1.1 fredette 1983 1.1 fredette if (xs == NULL) { 1984 1.1 fredette db_printf("(xs=NULL)\n"); 1985 1.1 fredette return; 1986 1.1 fredette } 1987 1.1 fredette db_printf("\n"); 1988 1.1 fredette #ifdef SCSIDEBUG 1989 1.1 fredette show_scsipi_xs(xs); 1990 1.1 fredette #else 1991 1.1 fredette db_printf("xs=%p\n", xs); 1992 1.1 fredette #endif 1993 1.1 fredette } 1994 1.1 fredette 1995 1.1 fredette void 1996 1.23 tsutsui sunscpal_show_state(void) 1997 1.1 fredette { 1998 1.1 fredette struct sunscpal_softc *sc; 1999 1.1 fredette struct sunscpal_req *sr; 2000 1.1 fredette int i, j, k; 2001 1.1 fredette 2002 1.1 fredette sc = sunscpal_debug_sc; 2003 1.1 fredette 2004 1.1 fredette if (sc == NULL) { 2005 1.1 fredette db_printf("sunscpal_debug_sc == NULL\n"); 2006 1.1 fredette return; 2007 1.1 fredette } 2008 1.1 fredette 2009 1.1 fredette db_printf("sc_ncmds=%d\n", sc->sc_ncmds); 2010 1.1 fredette k = -1; /* which is current? */ 2011 1.1 fredette for (i = 0; i < SUNSCPAL_OPENINGS; i++) { 2012 1.1 fredette sr = &sc->sc_ring[i]; 2013 1.1 fredette if (sr->sr_xs) { 2014 1.1 fredette if (sr == sc->sc_current) 2015 1.1 fredette k = i; 2016 1.1 fredette db_printf("req %d: (sr=%p)", i, sr); 2017 1.1 fredette sunscpal_show_req(sr); 2018 1.1 fredette } 2019 1.1 fredette } 2020 1.1 fredette db_printf("sc_rr=%d, current=%d\n", sc->sc_rr, k); 2021 1.1 fredette 2022 1.1 fredette db_printf("Active request matrix:\n"); 2023 1.1 fredette for(i = 0; i < 8; i++) { /* targets */ 2024 1.1 fredette for (j = 0; j < 8; j++) { /* LUN */ 2025 1.1 fredette sr = sc->sc_matrix[i][j]; 2026 1.1 fredette if (sr) { 2027 1.1 fredette db_printf("TID=%d LUN=%d sr=%p\n", i, j, sr); 2028 1.1 fredette } 2029 1.1 fredette } 2030 1.1 fredette } 2031 1.1 fredette 2032 1.1 fredette db_printf("sc_state=0x%x\n", sc->sc_state); 2033 1.1 fredette db_printf("sc_current=%p\n", sc->sc_current); 2034 1.1 fredette db_printf("sc_dataptr=%p\n", sc->sc_dataptr); 2035 1.1 fredette db_printf("sc_datalen=0x%x\n", sc->sc_datalen); 2036 1.1 fredette 2037 1.1 fredette db_printf("sc_prevphase=%d\n", sc->sc_prevphase); 2038 1.1 fredette db_printf("sc_msgpriq=0x%x\n", sc->sc_msgpriq); 2039 1.1 fredette } 2040 1.1 fredette #endif /* DDB */ 2041 1.1 fredette #endif /* SUNSCPAL_DEBUG */ 2042 1.1 fredette 2043 1.1 fredette void 2044 1.23 tsutsui sunscpal_attach(struct sunscpal_softc *sc, int options) 2045 1.1 fredette { 2046 1.1 fredette 2047 1.1 fredette /* 2048 1.1 fredette * Handle our options. 2049 1.1 fredette */ 2050 1.23 tsutsui aprint_normal(": options=0x%x\n", options); 2051 1.1 fredette sc->sc_parity_disable = (options & SUNSCPAL_OPT_NO_PARITY_CHK); 2052 1.1 fredette if (options & SUNSCPAL_OPT_DISABLE_DMA) 2053 1.1 fredette sc->sc_flags |= SUNSCPAL_DISABLE_DMA; 2054 1.1 fredette 2055 1.1 fredette /* 2056 1.1 fredette * Fill in the adapter. 2057 1.1 fredette */ 2058 1.2 bouyer memset(&sc->sc_adapter, 0, sizeof(sc->sc_adapter)); 2059 1.23 tsutsui sc->sc_adapter.adapt_dev = sc->sc_dev; 2060 1.2 bouyer sc->sc_adapter.adapt_nchannels = 1; 2061 1.2 bouyer sc->sc_adapter.adapt_openings = SUNSCPAL_OPENINGS; 2062 1.2 bouyer sc->sc_adapter.adapt_max_periph = 1; 2063 1.2 bouyer sc->sc_adapter.adapt_request = sunscpal_scsipi_request; 2064 1.2 bouyer sc->sc_adapter.adapt_minphys = sunscpal_minphys; 2065 1.15 mycroft if (options & SUNSCPAL_OPT_FORCE_POLLING) 2066 1.15 mycroft sc->sc_adapter.adapt_flags |= SCSIPI_ADAPT_POLL_ONLY; 2067 1.2 bouyer 2068 1.2 bouyer sc->sc_channel.chan_adapter = &sc->sc_adapter; 2069 1.2 bouyer sc->sc_channel.chan_bustype = &scsi_bustype; 2070 1.2 bouyer sc->sc_channel.chan_channel = 0; 2071 1.2 bouyer sc->sc_channel.chan_ntargets = 8; 2072 1.2 bouyer sc->sc_channel.chan_nluns = 8; 2073 1.2 bouyer sc->sc_channel.chan_id = 7; 2074 1.1 fredette 2075 1.1 fredette /* 2076 1.1 fredette * Add reference to adapter so that we drop the reference after 2077 1.27 skrll * config_found() to make sure the adapter is disabled. 2078 1.1 fredette */ 2079 1.2 bouyer if (scsipi_adapter_addref(&sc->sc_adapter) != 0) { 2080 1.23 tsutsui aprint_error_dev(sc->sc_dev, "unable to enable controller\n"); 2081 1.1 fredette return; 2082 1.1 fredette } 2083 1.1 fredette 2084 1.1 fredette sunscpal_init(sc); /* Init chip and driver */ 2085 1.1 fredette sunscpal_reset_scsibus(sc); 2086 1.1 fredette 2087 1.1 fredette /* 2088 1.1 fredette * Ask the adapter what subunits are present 2089 1.1 fredette */ 2090 1.29 thorpej (void)config_found(sc->sc_dev, &sc->sc_channel, scsiprint, CFARGS_NONE); 2091 1.2 bouyer scsipi_adapter_delref(&sc->sc_adapter); 2092 1.1 fredette } 2093 1.1 fredette 2094 1.1 fredette int 2095 1.23 tsutsui sunscpal_detach(struct sunscpal_softc *sc, int flags) 2096 1.1 fredette { 2097 1.1 fredette 2098 1.23 tsutsui return EOPNOTSUPP; 2099 1.1 fredette } 2100 1.1 fredette 2101 1.1 fredette static void 2102 1.1 fredette sunscpal_minphys(struct buf *bp) 2103 1.1 fredette { 2104 1.23 tsutsui 2105 1.1 fredette if (bp->b_bcount > SUNSCPAL_MAX_DMA_LEN) { 2106 1.1 fredette #ifdef SUNSCPAL_DEBUG 2107 1.1 fredette if (sunscpal_debug & SUNSCPAL_DBG_DMA) { 2108 1.23 tsutsui printf("%s: len = 0x%lx.\n", __func__, bp->b_bcount); 2109 1.1 fredette Debugger(); 2110 1.1 fredette } 2111 1.1 fredette #endif 2112 1.1 fredette bp->b_bcount = SUNSCPAL_MAX_DMA_LEN; 2113 1.1 fredette } 2114 1.23 tsutsui return minphys(bp); 2115 1.1 fredette } 2116 1.1 fredette 2117 1.1 fredette #ifdef SUNSCPAL_USE_BUS_DMA 2118 1.1 fredette 2119 1.1 fredette /* 2120 1.1 fredette * Allocate a DMA handle and put it in sr->sr_dma_hand. Prepare 2121 1.17 perry * for DMA transfer. 2122 1.1 fredette */ 2123 1.1 fredette static void 2124 1.23 tsutsui sunscpal_dma_alloc(struct sunscpal_softc *sc) 2125 1.1 fredette { 2126 1.1 fredette struct sunscpal_req *sr = sc->sc_current; 2127 1.1 fredette sunscpal_dma_handle_t dh; 2128 1.1 fredette int i, xlen; 2129 1.1 fredette u_long addr; 2130 1.1 fredette 2131 1.1 fredette #ifdef DIAGNOSTIC 2132 1.1 fredette if (sr->sr_dma_hand != NULL) 2133 1.23 tsutsui panic("%s: already have DMA handle", __func__); 2134 1.1 fredette #endif 2135 1.1 fredette 2136 1.23 tsutsui addr = (u_long)sc->sc_dataptr; 2137 1.1 fredette xlen = sc->sc_datalen; 2138 1.1 fredette 2139 1.1 fredette /* If the DMA start addr is misaligned then do PIO */ 2140 1.1 fredette if ((addr & 1) || (xlen & 1)) { 2141 1.23 tsutsui printf("%s: misaligned.\n", __func__); 2142 1.1 fredette return; 2143 1.1 fredette } 2144 1.1 fredette 2145 1.1 fredette /* Make sure our caller checked sc_min_dma_len. */ 2146 1.1 fredette if (xlen < sc->sc_min_dma_len) 2147 1.23 tsutsui panic("%s: xlen=0x%x", __func__, xlen); 2148 1.1 fredette 2149 1.1 fredette /* 2150 1.1 fredette * Never attempt single transfers of more than 63k, because 2151 1.1 fredette * our count register is only 16 bits. 2152 1.1 fredette * This should never happen since already bounded by minphys(). 2153 1.1 fredette * XXX - Should just segment these... 2154 1.1 fredette */ 2155 1.1 fredette if (xlen > SUNSCPAL_MAX_DMA_LEN) { 2156 1.23 tsutsui printf("%s: excessive xlen=0x%x\n", __func__, xlen); 2157 1.1 fredette Debugger(); 2158 1.1 fredette sc->sc_datalen = xlen = SUNSCPAL_MAX_DMA_LEN; 2159 1.1 fredette } 2160 1.1 fredette 2161 1.1 fredette /* Find free DMA handle. Guaranteed to find one since we have 2162 1.1 fredette as many DMA handles as the driver has processes. */ 2163 1.1 fredette for (i = 0; i < SUNSCPAL_OPENINGS; i++) { 2164 1.1 fredette if ((sc->sc_dma_handles[i].dh_flags & SUNSCDH_BUSY) == 0) 2165 1.1 fredette goto found; 2166 1.1 fredette } 2167 1.23 tsutsui panic("%s: no free DMA handles.", device_xname(sc->sc_dev)); 2168 1.23 tsutsui found: 2169 1.1 fredette 2170 1.1 fredette dh = &sc->sc_dma_handles[i]; 2171 1.1 fredette dh->dh_flags = SUNSCDH_BUSY; 2172 1.23 tsutsui dh->dh_mapaddr = (uint8_t *)addr; 2173 1.1 fredette dh->dh_maplen = xlen; 2174 1.1 fredette dh->dh_dvma = 0; 2175 1.1 fredette 2176 1.1 fredette /* Load the DMA map. */ 2177 1.23 tsutsui if (bus_dmamap_load(sc->sunscpal_dmat, dh->dh_dmamap, 2178 1.23 tsutsui dh->dh_mapaddr, dh->dh_maplen, NULL, BUS_DMA_NOWAIT) != 0) { 2179 1.1 fredette /* Can't load map */ 2180 1.23 tsutsui printf("%s: can't DMA %p/0x%x\n", __func__, 2181 1.23 tsutsui dh->dh_mapaddr, dh->dh_maplen); 2182 1.1 fredette dh->dh_flags = 0; 2183 1.1 fredette return; 2184 1.1 fredette } 2185 1.1 fredette 2186 1.1 fredette /* success */ 2187 1.1 fredette sr->sr_dma_hand = dh; 2188 1.1 fredette } 2189 1.1 fredette 2190 1.1 fredette static void 2191 1.23 tsutsui sunscpal_dma_free(struct sunscpal_softc *sc) 2192 1.1 fredette { 2193 1.1 fredette struct sunscpal_req *sr = sc->sc_current; 2194 1.1 fredette sunscpal_dma_handle_t dh = sr->sr_dma_hand; 2195 1.1 fredette 2196 1.1 fredette #ifdef DIAGNOSTIC 2197 1.1 fredette if (dh == NULL) 2198 1.23 tsutsui panic("%s: no DMA handle", __func__); 2199 1.1 fredette #endif 2200 1.1 fredette 2201 1.1 fredette if (sc->sc_state & SUNSCPAL_DOINGDMA) 2202 1.23 tsutsui panic("%s: free while in progress", __func__); 2203 1.1 fredette 2204 1.1 fredette if (dh->dh_flags & SUNSCDH_BUSY) { 2205 1.1 fredette /* XXX - Should separate allocation and mapping. */ 2206 1.1 fredette /* Give back the DVMA space. */ 2207 1.1 fredette bus_dmamap_unload(sc->sunscpal_dmat, dh->dh_dmamap); 2208 1.1 fredette dh->dh_flags = 0; 2209 1.1 fredette } 2210 1.1 fredette sr->sr_dma_hand = NULL; 2211 1.1 fredette } 2212 1.1 fredette 2213 1.1 fredette /* 2214 1.17 perry * This function is called during the SELECT phase that 2215 1.17 perry * precedes a COMMAND phase, in case we need to setup the 2216 1.1 fredette * DMA engine before the bus enters a DATA phase. 2217 1.1 fredette * 2218 1.1 fredette * On the sc version, setup the start address and the count. 2219 1.1 fredette */ 2220 1.1 fredette static void 2221 1.23 tsutsui sunscpal_dma_setup(struct sunscpal_softc *sc) 2222 1.1 fredette { 2223 1.1 fredette struct sunscpal_req *sr = sc->sc_current; 2224 1.1 fredette struct scsipi_xfer *xs = sr->sr_xs; 2225 1.1 fredette sunscpal_dma_handle_t dh = sr->sr_dma_hand; 2226 1.1 fredette long data_pa; 2227 1.1 fredette int xlen; 2228 1.1 fredette 2229 1.1 fredette /* 2230 1.1 fredette * Get the DVMA mapping for this segment. 2231 1.1 fredette * XXX - Should separate allocation and mapin. 2232 1.1 fredette */ 2233 1.1 fredette data_pa = dh->dh_dvma; 2234 1.1 fredette data_pa += (sc->sc_dataptr - dh->dh_mapaddr); 2235 1.1 fredette if (data_pa & 1) 2236 1.23 tsutsui panic("%s: bad pa=0x%lx", __func__, data_pa); 2237 1.1 fredette xlen = sc->sc_datalen; 2238 1.1 fredette if (xlen & 1) 2239 1.23 tsutsui panic("%s: bad xlen=0x%x", __func__, xlen); 2240 1.1 fredette sc->sc_reqlen = xlen; /* XXX: or less? */ 2241 1.1 fredette 2242 1.1 fredette #ifdef SUNSCPAL_DEBUG 2243 1.1 fredette if (sunscpal_debug & SUNSCPAL_DBG_DMA) { 2244 1.23 tsutsui printf("%s: dh=%p, pa=0x%lx, xlen=0x%x\n", 2245 1.23 tsutsui __func__, dh, data_pa, xlen); 2246 1.1 fredette } 2247 1.1 fredette #endif 2248 1.1 fredette 2249 1.1 fredette /* sync the DMA map: */ 2250 1.17 perry bus_dmamap_sync(sc->sunscpal_dmat, dh->dh_dmamap, 0, dh->dh_maplen, 2251 1.23 tsutsui ((xs->xs_control & XS_CTL_DATA_OUT) == 0 ? 2252 1.23 tsutsui BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE)); 2253 1.1 fredette 2254 1.1 fredette /* Load the start address and the count. */ 2255 1.1 fredette SUNSCPAL_WRITE_2(sc, sunscpal_dma_addr_h, (data_pa >> 16) & 0xFFFF); 2256 1.1 fredette SUNSCPAL_WRITE_2(sc, sunscpal_dma_addr_l, (data_pa >> 0) & 0xFFFF); 2257 1.1 fredette SUNSCPAL_WRITE_2(sc, sunscpal_dma_count, SUNSCPAL_DMA_COUNT_FLIP(xlen)); 2258 1.1 fredette } 2259 1.1 fredette 2260 1.1 fredette #endif /* SUNSCPAL_USE_BUS_DMA */ 2261