1 /* $NetBSD: scsi.c,v 1.2 1999/03/26 06:54:40 dbj Exp $ */ 2 /* 3 * Copyright (c) 1994, 1997 Rolf Grossmann 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by Rolf Grossmann. 17 * 4. The name of the author may not be used to endorse or promote products 18 * derived from this software without specific prior written permission 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/param.h> 33 #include <next68k/dev/espreg.h> 34 #include <dev/scsipi/scsi_message.h> 35 #if 0 36 #include <next/next/prominfo.h> 37 #else 38 #include <next68k/next68k/nextrom.h> 39 #endif 40 #include "scsireg.h" 41 #include "dmareg.h" 42 #include "scsivar.h" 43 44 #include <lib/libsa/stand.h> 45 46 struct scsi_softc scsi_softc, *sc = &scsi_softc; 47 char the_dma_buffer[MAX_DMASIZE+DMA_ENDALIGNMENT], *dma_buffer; 48 49 int scsi_msgin(void); 50 int dma_start(char *addr, int len); 51 int dma_done(void); 52 53 void scsi_init(void); 54 void scsierror(char *error); 55 short scsi_getbyte(volatile caddr_t sr); 56 int scsi_wait_for_intr(void); 57 int scsiicmd(char target, char lun, 58 u_char *cbuf, int clen, char *addr, int len); 59 60 #ifdef SCSI_DEBUG 61 #define DPRINTF(x) printf x; 62 #else 63 #define DPRINTF(x) 64 #endif 65 66 void 67 scsi_init(void) 68 { 69 volatile caddr_t sr; 70 struct dma_dev *dma; 71 72 sr = P_SCSI; 73 dma = (struct dma_dev *)P_SCSI_CSR; 74 75 dma_buffer = DMA_ALIGN(char *, the_dma_buffer); 76 77 P_FLOPPY[FLP_CTRL] &= ~FLC_82077_SEL; /* select SCSI chip */ 78 79 /* first reset dma */ 80 dma->dd_csr = DMACSR_RESET; 81 DELAY(200); 82 sr[ESP_DCTL] = ESPDCTL_20MHZ | ESPDCTL_INTENB | ESPDCTL_RESET; 83 DELAY(10); 84 sr[ESP_DCTL] = ESPDCTL_20MHZ | ESPDCTL_INTENB; 85 DELAY(10); 86 87 /* then reset the SCSI chip */ 88 sr[ESP_CMD] = ESPCMD_RSTCHIP; 89 sr[ESP_CMD] = ESPCMD_NOP; 90 DELAY(500); 91 92 /* now reset the SCSI bus */ 93 sr[ESP_CMD] = ESPCMD_RSTSCSI; 94 DELAY(18000000); /* XXX should be about 2-3 seconds at least */ 95 96 /* then reset the SCSI chip again and initialize it properly */ 97 sr[ESP_CMD] = ESPCMD_RSTCHIP; 98 sr[ESP_CMD] = ESPCMD_NOP; 99 DELAY(500); 100 sr[ESP_CFG1] = ESPCFG1_SLOW | ESPCFG1_BUSID; 101 sr[ESP_CFG2] = 0; 102 sr[ESP_CCF] = 4; /* S5RCLKCONV_FACTOR(20); */ 103 sr[ESP_TIMEOUT] = 152; /* S5RSELECT_TIMEOUT(20,250); */ 104 sr[ESP_SYNCOFF] = 0; 105 sr[ESP_SYNCTP] = 5; 106 /* 107 sc->sc_intrstatus = sr->s5r_intrstatus; 108 sc->sc_intrstatus = sr->s5r_intrstatus; 109 */ 110 sr[ESP_CFG1] = ESPCFG1_PARENB | ESPCFG1_BUSID; 111 112 sc->sc_state = SCSI_IDLE; 113 } 114 115 void 116 scsierror(char *error) 117 { 118 printf("scsierror: %s.\n", error); 119 } 120 121 short 122 scsi_getbyte(volatile caddr_t sr) 123 { 124 if ((sr[ESP_FFLAG] & ESPFIFO_FF) == 0) 125 { 126 printf("getbyte: no data!\n"); 127 return -1; 128 } 129 return sr[ESP_FIFO]; 130 } 131 132 int 133 scsi_wait_for_intr(void) 134 { 135 #if 0 136 extern struct prominfo *pi; 137 volitle int = pi->pi_intrstat; /* ### use constant? */ 138 #else 139 extern char *mg; 140 #define MON(type, off) (*(type *)((u_int) (mg) + off)) 141 volatile int *intrstat = MON(volatile int *,MG_intrstat); 142 volatile int *intrmask = MON(volatile int *,MG_intrmask); 143 #endif 144 int count; 145 146 for(count = 0; count < SCSI_TIMEOUT; count++) { 147 DPRINTF((" *intrstat = 0x%x\t*intrmask = 0x%x\n",*intrstat,*intrmask)); 148 149 if (*intrstat & SCSI_INTR) 150 return 0; 151 } 152 153 printf("scsiicmd: timed out.\n"); 154 return -1; 155 } 156 157 int 158 scsiicmd(char target, char lun, 159 u_char *cbuf, int clen, 160 char *addr, int len) 161 { 162 volatile caddr_t sr; 163 int i; 164 165 DPRINTF(("scsiicmd: [%x, %d] -> %d (%lx, %d)\n",*cbuf, clen, 166 target, (long)addr, len)); 167 sr = P_SCSI; 168 169 if (sc->sc_state != SCSI_IDLE) { 170 scsierror("scsiiscmd: bad state"); 171 return EIO; 172 } 173 sc->sc_result = 0; 174 175 /* select target */ 176 sr[ESP_CMD] = ESPCMD_FLUSH; 177 DELAY(10); 178 sr[ESP_SELID] = target; 179 sr[ESP_FIFO] = MSG_IDENTIFY(lun, 0); 180 for (i=0; i<clen; i++) 181 sr[ESP_FIFO] = cbuf[i]; 182 sr[ESP_CMD] = ESPCMD_SELATN; 183 sc->sc_state = SCSI_SELECTING; 184 185 while(sc->sc_state != SCSI_DONE) { 186 if (scsi_wait_for_intr()) /* maybe we'd better use real intrs ? */ 187 return EIO; 188 189 if (sc->sc_state == SCSI_DMA) 190 { 191 /* registers are not valid on dma intr */ 192 sc->sc_status = sc->sc_seqstep = sc->sc_intrstatus = 0; 193 DPRINTF(("scsiicmd: dma intr\n")); 194 } else { 195 /* scsi processing */ 196 sc->sc_status = sr[ESP_STAT]; 197 sc->sc_seqstep = sr[ESP_STEP]; 198 sc->sc_intrstatus = sr[ESP_INTR]; 199 DPRINTF(("scsiicmd: regs[intr=%x, stat=%x, step=%x]\n", 200 sc->sc_intrstatus, sc->sc_status, sc->sc_seqstep)); 201 } 202 203 if (sc->sc_intrstatus & ESPINTR_SBR) { 204 scsierror("scsi bus reset"); 205 return EIO; 206 } 207 208 if ((sc->sc_status & ESPSTAT_GE) 209 || (sc->sc_intrstatus & ESPINTR_ILL)) { 210 scsierror("software error"); 211 return EIO; 212 } 213 if (sc->sc_status & ESPSTAT_PE) 214 { 215 scsierror("parity error"); 216 return EIO; 217 } 218 219 switch(sc->sc_state) 220 { 221 case SCSI_SELECTING: 222 if (sc->sc_intrstatus & ESPINTR_DIS) 223 { 224 sc->sc_state = SCSI_IDLE; 225 return EUNIT; /* device not present */ 226 } 227 228 #define ESPINTR_DONE (ESPINTR_BS | ESPINTR_FC) 229 if ((sc->sc_intrstatus & ESPINTR_DONE) != ESPINTR_DONE) 230 { 231 scsierror("selection failed"); 232 return EIO; 233 } 234 sc->sc_state = SCSI_HASBUS; 235 break; 236 case SCSI_HASBUS: 237 if (sc->sc_intrstatus & ESPINTR_DIS) 238 { 239 scsierror("target disconnected"); 240 return EIO; 241 } 242 break; 243 case SCSI_DMA: 244 if (sc->sc_intrstatus & ESPINTR_DIS) 245 { 246 scsierror("target disconnected"); 247 return EIO; 248 } 249 if (dma_done() != 0) 250 return EIO; 251 continue; 252 case SCSI_CLEANUP: 253 if (sc->sc_intrstatus & ESPINTR_DIS) 254 { 255 sc->sc_state = SCSI_DONE; 256 continue; 257 } 258 DPRINTF(("hmm ... no disconnect on cleanup?\n")); 259 sc->sc_state = SCSI_DONE; /* maybe ... */ 260 break; 261 } 262 263 /* transfer information now */ 264 switch(sc->sc_status & ESPSTAT_PHASE) 265 { 266 case DATA_IN_PHASE: 267 if (dma_start(addr, len) != 0) 268 return EIO; 269 break; 270 case DATA_OUT_PHASE: 271 scsierror("data out phase not implemented"); 272 return EIO; 273 case STATUS_PHASE: 274 DPRINTF(("status phase: ")); 275 sr[ESP_CMD] = ESPCMD_ICCS; 276 sc->sc_result = scsi_getbyte(sr); 277 DPRINTF(("status is 0x%x.\n", sc->sc_result)); 278 break; 279 case MSG_IN_PHASE: 280 if (scsi_msgin() != 0) 281 return EIO; 282 break; 283 default: 284 DPRINTF(("phase not implemented: 0x%x.\n", 285 sc->sc_status & ESPSTAT_PHASE)); 286 scsierror("bad phase"); 287 return EIO; 288 } 289 } 290 291 sc->sc_state = SCSI_IDLE; 292 return -sc->sc_result; 293 } 294 295 int 296 scsi_msgin(void) 297 { 298 volatile caddr_t sr; 299 u_char msg; 300 301 sr = P_SCSI; 302 303 msg = scsi_getbyte(sr); 304 if (msg) 305 { 306 printf("unexpected msg: 0x%x.\n",msg); 307 return -1; 308 } 309 if ((sc->sc_intrstatus & ESPINTR_FC) == 0) 310 { 311 printf("not function complete.\n"); 312 return -1; 313 } 314 sc->sc_state = SCSI_CLEANUP; 315 sr[ESP_CMD] = ESPCMD_MSGOK; 316 return 0; 317 } 318 319 int 320 dma_start(char *addr, int len) 321 { 322 volatile caddr_t sr; 323 struct dma_dev *dma; 324 325 326 sr = P_SCSI; 327 dma = (struct dma_dev *)P_SCSI_CSR; 328 329 if (len > MAX_DMASIZE) 330 { 331 scsierror("dma too long"); 332 return -1; 333 } 334 335 if (addr == NULL || len == 0) 336 { 337 #if 0 /* I'd take that as an error in my code */ 338 DPRINTF(("hmm ... no dma requested.\n")); 339 sr[ESP_TCL] = 0; 340 sr[ESP_TCM] = 1; 341 sr[ESP_CMD] = ESPCMD_NOP; 342 sr[ESP_CMD] = ESPCMD_DMA | ESPCMD_TRPAD; 343 return 0; 344 #else 345 scsierror("unrequested dma"); 346 return -1; 347 #endif 348 } 349 350 DPRINTF(("dma start: %lx, %d byte.\n", (long)addr, len)); 351 352 DPRINTF(("dma_bufffer: start: 0x%lx end: 0x%lx \n", 353 (long)dma_buffer,(long)DMA_ENDALIGN(char *, dma_buffer+len))); 354 355 sc->dma_addr = addr; 356 sc->dma_len = len; 357 358 sr[ESP_TCL] = len & 0xff; 359 sr[ESP_TCM] = len >> 8; 360 sr[ESP_CMD] = ESPCMD_DMA | ESPCMD_NOP; 361 sr[ESP_CMD] = ESPCMD_DMA | ESPCMD_TRANS; 362 363 #if 0 364 dma->dd_csr = DMACSR_READ | DMACSR_RESET; 365 dma->dd_next_initbuf = dma_buffer; 366 dma->dd_limit = DMA_ENDALIGN(char *, dma_buffer+len); 367 dma->dd_csr = DMACSR_READ | DMACSR_SETENABLE; 368 #else 369 dma->dd_csr = 0; 370 dma->dd_csr = DMACSR_INITBUF | DMACSR_READ | DMACSR_RESET; 371 dma->dd_next_initbuf = dma_buffer; 372 dma->dd_limit = DMA_ENDALIGN(char *, dma_buffer+len); 373 dma->dd_csr = DMACSR_READ | DMACSR_SETENABLE; 374 #endif 375 376 sr[ESP_DCTL] = ESPDCTL_20MHZ|ESPDCTL_INTENB|ESPDCTL_DMAMOD|ESPDCTL_DMARD; 377 378 sc->sc_state = SCSI_DMA; 379 return 0; 380 } 381 382 int 383 dma_done(void) 384 { 385 volatile caddr_t sr; 386 struct dma_dev *dma; 387 int count, state; 388 389 sr = P_SCSI; 390 dma = (struct dma_dev *)P_SCSI_CSR; 391 392 state = dma->dd_csr & (DMACSR_BUSEXC | DMACSR_COMPLETE 393 | DMACSR_SUPDATE | DMACSR_ENABLE); 394 395 count = sr[ESP_TCM]<<8 | sr[ESP_TCL]; 396 DPRINTF(("dma state = 0x%x, remain = %d.\n", state, count)); 397 398 if (state & DMACSR_ENABLE) 399 { 400 401 DPRINTF(("dma still enabled, flushing DCTL.\n")); 402 403 sr[ESP_DCTL] = ESPDCTL_20MHZ | ESPDCTL_INTENB | ESPDCTL_DMAMOD 404 | ESPDCTL_DMARD | ESPDCTL_FLUSH; 405 /* DELAY(5); */ 406 sr[ESP_DCTL] = ESPDCTL_20MHZ | ESPDCTL_INTENB | ESPDCTL_DMAMOD 407 | ESPDCTL_DMARD; 408 /* DELAY(5); */ 409 410 return 0; 411 } 412 413 sr[ESP_DCTL] = ESPDCTL_20MHZ | ESPDCTL_INTENB; 414 count = sr[ESP_TCM]<<8 | sr[ESP_TCL]; 415 dma->dd_csr = DMACSR_RESET; 416 417 DPRINTF(("dma done. remain = %d, state = 0x%x.\n", count, state)); 418 419 if (count != 0) 420 { 421 printf("WARNING: unexpected %d characters remain in dma\n",count); 422 scsierror("dma transfer incomplete"); 423 #if 0 424 return -1; 425 #endif 426 } 427 428 if (state & DMACSR_COMPLETE) 429 { 430 bcopy(dma_buffer, sc->dma_addr, sc->dma_len); 431 sc->sc_state = SCSI_HASBUS; 432 return 0; 433 } 434 if (state & DMACSR_BUSEXC) 435 { 436 scsierror("dma failed"); 437 return -1; 438 } 439 scsierror("dma not completed\n"); 440 441 return -1; 442 } 443