1 1.34 thorpej /* $NetBSD: sc_wrap.c,v 1.34 2023/12/20 15:29:05 thorpej Exp $ */ 2 1.3 tsubai 3 1.1 tsubai /* 4 1.4 tsubai * This driver is slow! Need to rewrite. 5 1.4 tsubai */ 6 1.25 lukem 7 1.25 lukem #include <sys/cdefs.h> 8 1.34 thorpej __KERNEL_RCSID(0, "$NetBSD: sc_wrap.c,v 1.34 2023/12/20 15:29:05 thorpej Exp $"); 9 1.1 tsubai 10 1.1 tsubai #include <sys/types.h> 11 1.1 tsubai #include <sys/param.h> 12 1.1 tsubai #include <sys/systm.h> 13 1.1 tsubai #include <sys/kernel.h> 14 1.1 tsubai #include <sys/device.h> 15 1.1 tsubai #include <sys/proc.h> 16 1.1 tsubai #include <sys/buf.h> 17 1.1 tsubai 18 1.21 thorpej #include <uvm/uvm_extern.h> 19 1.21 thorpej 20 1.1 tsubai #include <dev/scsipi/scsi_all.h> 21 1.1 tsubai #include <dev/scsipi/scsipi_all.h> 22 1.1 tsubai #include <dev/scsipi/scsiconf.h> 23 1.1 tsubai #include <dev/scsipi/scsi_message.h> 24 1.1 tsubai 25 1.23 tsutsui #include <newsmips/dev/hbvar.h> 26 1.2 thorpej #include <newsmips/dev/scsireg.h> 27 1.2 thorpej #include <newsmips/dev/dmac_0448.h> 28 1.2 thorpej #include <newsmips/dev/screg_1185.h> 29 1.1 tsubai 30 1.1 tsubai #include <machine/adrsmap.h> 31 1.1 tsubai #include <machine/autoconf.h> 32 1.1 tsubai #include <machine/machConst.h> 33 1.1 tsubai 34 1.18 thorpej #include <mips/cache.h> 35 1.18 thorpej 36 1.31 tsutsui static int cxd1185_match(device_t, cfdata_t, void *); 37 1.31 tsutsui static void cxd1185_attach(device_t, device_t, void *); 38 1.1 tsubai 39 1.31 tsutsui CFATTACH_DECL_NEW(sc, sizeof(struct sc_softc), 40 1.20 thorpej cxd1185_match, cxd1185_attach, NULL, NULL); 41 1.1 tsubai 42 1.27 tsutsui void cxd1185_init(struct sc_softc *); 43 1.27 tsutsui static void free_scb(struct sc_softc *, struct sc_scb *); 44 1.27 tsutsui static struct sc_scb *get_scb(struct sc_softc *, int); 45 1.27 tsutsui static void sc_scsipi_request(struct scsipi_channel *, 46 1.27 tsutsui scsipi_adapter_req_t, void *); 47 1.27 tsutsui static int sc_poll(struct sc_softc *, int, int); 48 1.27 tsutsui static void sc_sched(struct sc_softc *); 49 1.27 tsutsui void sc_done(struct sc_scb *); 50 1.27 tsutsui int sc_intr(void *); 51 1.27 tsutsui static void cxd1185_timeout(void *); 52 1.27 tsutsui 53 1.27 tsutsui extern void sc_send(struct sc_scb *, int, int); 54 1.27 tsutsui extern int scintr(void); 55 1.27 tsutsui extern void scsi_hardreset(void); 56 1.27 tsutsui extern int sc_busy(struct sc_softc *, int); 57 1.27 tsutsui extern paddr_t kvtophys(vaddr_t); 58 1.1 tsubai 59 1.4 tsubai static int sc_disconnect = IDT_DISCON; 60 1.4 tsubai 61 1.1 tsubai int 62 1.31 tsutsui cxd1185_match(device_t parent, cfdata_t cf, void *aux) 63 1.1 tsubai { 64 1.23 tsutsui struct hb_attach_args *ha = aux; 65 1.1 tsubai 66 1.23 tsutsui if (strcmp(ha->ha_name, "sc")) 67 1.1 tsubai return 0; 68 1.1 tsubai 69 1.1 tsubai return 1; 70 1.1 tsubai } 71 1.1 tsubai 72 1.1 tsubai void 73 1.31 tsutsui cxd1185_attach(device_t parent, device_t self, void *aux) 74 1.1 tsubai { 75 1.31 tsutsui struct sc_softc *sc = device_private(self); 76 1.23 tsutsui struct hb_attach_args *ha = aux; 77 1.1 tsubai struct sc_scb *scb; 78 1.13 tsubai int i, intlevel; 79 1.13 tsubai 80 1.31 tsutsui sc->sc_dev = self; 81 1.31 tsutsui 82 1.23 tsutsui intlevel = ha->ha_level; 83 1.13 tsubai if (intlevel == -1) { 84 1.13 tsubai #if 0 85 1.31 tsutsui aprint_error(": interrupt level not configured\n"); 86 1.13 tsubai return; 87 1.13 tsubai #else 88 1.31 tsutsui aprint_normal(": interrupt level not configured; using"); 89 1.13 tsubai intlevel = 0; 90 1.13 tsubai #endif 91 1.13 tsubai } 92 1.31 tsutsui aprint_normal(" level %d\n", intlevel); 93 1.1 tsubai 94 1.1 tsubai if (sc_idenr & 0x08) 95 1.4 tsubai sc->scsi_1185AQ = 1; 96 1.4 tsubai else 97 1.4 tsubai sc->scsi_1185AQ = 0; 98 1.1 tsubai 99 1.31 tsutsui sc->sc_adapter.adapt_dev = self; 100 1.17 bouyer sc->sc_adapter.adapt_nchannels = 1; 101 1.17 bouyer sc->sc_adapter.adapt_openings = 7; 102 1.17 bouyer sc->sc_adapter.adapt_max_periph = 1; 103 1.17 bouyer sc->sc_adapter.adapt_ioctl = NULL; 104 1.17 bouyer sc->sc_adapter.adapt_minphys = minphys; 105 1.17 bouyer sc->sc_adapter.adapt_request = sc_scsipi_request; 106 1.17 bouyer 107 1.17 bouyer memset(&sc->sc_channel, 0, sizeof(sc->sc_channel)); 108 1.17 bouyer sc->sc_channel.chan_adapter = &sc->sc_adapter; 109 1.17 bouyer sc->sc_channel.chan_bustype = &scsi_bustype; 110 1.17 bouyer sc->sc_channel.chan_channel = 0; 111 1.17 bouyer sc->sc_channel.chan_ntargets = 8; 112 1.17 bouyer sc->sc_channel.chan_nluns = 8; 113 1.17 bouyer sc->sc_channel.chan_id = 7; 114 1.1 tsubai 115 1.1 tsubai TAILQ_INIT(&sc->ready_list); 116 1.1 tsubai TAILQ_INIT(&sc->free_list); 117 1.1 tsubai 118 1.1 tsubai scb = sc->sc_scb; 119 1.1 tsubai for (i = 0; i < 24; i++) { /* XXX 24 */ 120 1.1 tsubai TAILQ_INSERT_TAIL(&sc->free_list, scb, chain); 121 1.1 tsubai scb++; 122 1.1 tsubai } 123 1.1 tsubai 124 1.1 tsubai cxd1185_init(sc); 125 1.1 tsubai DELAY(100000); 126 1.1 tsubai 127 1.24 tsutsui hb_intr_establish(intlevel, INTEN1_DMA, IPL_BIO, sc_intr, sc); 128 1.12 tsubai 129 1.33 thorpej config_found(self, &sc->sc_channel, scsiprint, CFARGS_NONE); 130 1.1 tsubai } 131 1.1 tsubai 132 1.1 tsubai void 133 1.27 tsutsui cxd1185_init(struct sc_softc *sc) 134 1.1 tsubai { 135 1.1 tsubai int i; 136 1.1 tsubai 137 1.1 tsubai for (i = 0; i < 8; i++) 138 1.1 tsubai sc->inuse[i] = 0; 139 1.1 tsubai 140 1.1 tsubai scsi_hardreset(); 141 1.1 tsubai } 142 1.1 tsubai 143 1.1 tsubai void 144 1.27 tsutsui free_scb(struct sc_softc *sc, struct sc_scb *scb) 145 1.1 tsubai { 146 1.1 tsubai int s; 147 1.1 tsubai 148 1.1 tsubai s = splbio(); 149 1.1 tsubai 150 1.1 tsubai TAILQ_INSERT_HEAD(&sc->free_list, scb, chain); 151 1.1 tsubai 152 1.1 tsubai /* 153 1.1 tsubai * If there were none, wake anybody waiting for one to come free, 154 1.1 tsubai * starting with queued entries. 155 1.1 tsubai */ 156 1.1 tsubai if (scb->chain.tqe_next == 0) 157 1.1 tsubai wakeup(&sc->free_list); 158 1.1 tsubai 159 1.1 tsubai splx(s); 160 1.1 tsubai } 161 1.1 tsubai 162 1.1 tsubai struct sc_scb * 163 1.27 tsutsui get_scb(struct sc_softc *sc, int flags) 164 1.1 tsubai { 165 1.1 tsubai int s; 166 1.1 tsubai struct sc_scb *scb; 167 1.1 tsubai 168 1.1 tsubai s = splbio(); 169 1.1 tsubai 170 1.1 tsubai while ((scb = sc->free_list.tqh_first) == NULL && 171 1.11 thorpej (flags & XS_CTL_NOSLEEP) == 0) 172 1.1 tsubai tsleep(&sc->free_list, PRIBIO, "sc_scb", 0); 173 1.1 tsubai if (scb) { 174 1.1 tsubai TAILQ_REMOVE(&sc->free_list, scb, chain); 175 1.1 tsubai } 176 1.1 tsubai 177 1.1 tsubai splx(s); 178 1.1 tsubai return scb; 179 1.1 tsubai } 180 1.1 tsubai 181 1.17 bouyer void 182 1.27 tsutsui sc_scsipi_request(struct scsipi_channel *chan, scsipi_adapter_req_t req, 183 1.27 tsutsui void *arg) 184 1.17 bouyer { 185 1.1 tsubai struct scsipi_xfer *xs; 186 1.17 bouyer struct scsipi_periph *periph; 187 1.31 tsutsui struct sc_softc *sc = device_private(chan->chan_adapter->adapt_dev); 188 1.1 tsubai struct sc_scb *scb; 189 1.1 tsubai int flags, s; 190 1.17 bouyer int target; 191 1.1 tsubai 192 1.17 bouyer switch (req) { 193 1.17 bouyer case ADAPTER_REQ_RUN_XFER: 194 1.17 bouyer xs = arg; 195 1.17 bouyer periph = xs->xs_periph; 196 1.17 bouyer 197 1.17 bouyer flags = xs->xs_control; 198 1.17 bouyer if ((scb = get_scb(sc, flags)) == NULL) 199 1.31 tsutsui panic("%s: no scb", __func__); 200 1.17 bouyer 201 1.17 bouyer scb->xs = xs; 202 1.17 bouyer scb->flags = 0; 203 1.17 bouyer scb->sc_ctag = 0; 204 1.17 bouyer scb->sc_coffset = 0; 205 1.17 bouyer scb->istatus = 0; 206 1.17 bouyer scb->tstatus = 0; 207 1.17 bouyer scb->message = 0; 208 1.27 tsutsui memset(scb->msgbuf, 0, sizeof(scb->msgbuf)); 209 1.17 bouyer 210 1.17 bouyer s = splbio(); 211 1.17 bouyer 212 1.17 bouyer TAILQ_INSERT_TAIL(&sc->ready_list, scb, chain); 213 1.17 bouyer sc_sched(sc); 214 1.17 bouyer splx(s); 215 1.17 bouyer 216 1.17 bouyer if (flags & XS_CTL_POLL) { 217 1.17 bouyer target = periph->periph_target; 218 1.17 bouyer if (sc_poll(sc, target, xs->timeout)) { 219 1.17 bouyer printf("sc: timeout (retry)\n"); 220 1.17 bouyer if (sc_poll(sc, target, xs->timeout)) { 221 1.17 bouyer printf("sc: timeout\n"); 222 1.17 bouyer } 223 1.17 bouyer } 224 1.17 bouyer /* called during autoconfig only... */ 225 1.18 thorpej mips_dcache_wbinv_all(); /* Flush DCache */ 226 1.1 tsubai } 227 1.17 bouyer return; 228 1.17 bouyer case ADAPTER_REQ_GROW_RESOURCES: 229 1.17 bouyer /* XXX Not supported. */ 230 1.17 bouyer return; 231 1.17 bouyer case ADAPTER_REQ_SET_XFER_MODE: 232 1.17 bouyer /* XXX Not supported. */ 233 1.17 bouyer return; 234 1.1 tsubai } 235 1.1 tsubai } 236 1.1 tsubai 237 1.1 tsubai /* 238 1.1 tsubai * Used when interrupt driven I/O isn't allowed, e.g. during boot. 239 1.1 tsubai */ 240 1.1 tsubai int 241 1.27 tsutsui sc_poll(struct sc_softc *sc, int chan, int count) 242 1.1 tsubai { 243 1.31 tsutsui volatile uint8_t *int_stat = (void *)INTST1; 244 1.31 tsutsui volatile uint8_t *int_clear = (void *)INTCLR1; 245 1.1 tsubai 246 1.4 tsubai while (sc_busy(sc, chan)) { 247 1.1 tsubai if (*int_stat & INTST1_DMA) { 248 1.1 tsubai *int_clear = INTST1_DMA; 249 1.1 tsubai if (dmac_gstat & CH_INT(CH_SCSI)) { 250 1.1 tsubai if (dmac_gstat & CH_MRQ(CH_SCSI)) { 251 1.1 tsubai DELAY(50); 252 1.1 tsubai if (dmac_gstat & CH_MRQ(CH_SCSI)) 253 1.1 tsubai printf("dma_poll\n"); 254 1.1 tsubai } 255 1.1 tsubai DELAY(10); 256 1.1 tsubai scintr(); 257 1.1 tsubai } 258 1.1 tsubai } 259 1.1 tsubai DELAY(1000); 260 1.1 tsubai count--; 261 1.1 tsubai if (count <= 0) 262 1.1 tsubai return 1; 263 1.1 tsubai } 264 1.1 tsubai return 0; 265 1.1 tsubai } 266 1.1 tsubai 267 1.1 tsubai void 268 1.27 tsutsui sc_sched(struct sc_softc *sc) 269 1.1 tsubai { 270 1.1 tsubai struct scsipi_xfer *xs; 271 1.17 bouyer struct scsipi_periph *periph; 272 1.1 tsubai int ie = 0; 273 1.1 tsubai int flags; 274 1.1 tsubai int chan, lun; 275 1.5 tsubai struct sc_scb *scb, *nextscb; 276 1.1 tsubai 277 1.1 tsubai scb = sc->ready_list.tqh_first; 278 1.1 tsubai start: 279 1.1 tsubai if (scb == NULL) 280 1.1 tsubai return; 281 1.1 tsubai 282 1.1 tsubai xs = scb->xs; 283 1.17 bouyer periph = xs->xs_periph; 284 1.17 bouyer chan = periph->periph_target; 285 1.11 thorpej flags = xs->xs_control; 286 1.1 tsubai 287 1.1 tsubai if (sc->inuse[chan]) { 288 1.1 tsubai scb = scb->chain.tqe_next; 289 1.1 tsubai goto start; 290 1.1 tsubai } 291 1.1 tsubai sc->inuse[chan] = 1; 292 1.1 tsubai 293 1.11 thorpej if (flags & XS_CTL_RESET) 294 1.1 tsubai printf("SCSI RESET\n"); 295 1.1 tsubai 296 1.17 bouyer lun = periph->periph_lun; 297 1.1 tsubai 298 1.4 tsubai scb->identify = MSG_IDENT | sc_disconnect | (lun & IDT_DRMASK); 299 1.4 tsubai scb->sc_ctrnscnt = xs->datalen; 300 1.1 tsubai 301 1.22 wiz /* make va->pa mapping table for DMA */ 302 1.1 tsubai if (xs->datalen > 0) { 303 1.31 tsutsui uint32_t pn, pages, offset; 304 1.31 tsutsui int i; 305 1.6 tsubai vaddr_t va; 306 1.1 tsubai 307 1.27 tsutsui #if 0 308 1.27 tsutsui memset(&sc->sc_map[chan], 0, sizeof(struct sc_map)); 309 1.27 tsutsui #endif 310 1.1 tsubai 311 1.6 tsubai va = (vaddr_t)xs->data; 312 1.1 tsubai 313 1.1 tsubai offset = va & PGOFSET; 314 1.21 thorpej pages = (offset + xs->datalen + PAGE_SIZE -1 ) >> PGSHIFT; 315 1.1 tsubai if (pages >= NSCMAP) 316 1.1 tsubai panic("sc_map: Too many pages"); 317 1.1 tsubai 318 1.1 tsubai for (i = 0; i < pages; i++) { 319 1.6 tsubai pn = kvtophys(va) >> PGSHIFT; 320 1.1 tsubai sc->sc_map[chan].mp_addr[i] = pn; 321 1.21 thorpej va += PAGE_SIZE; 322 1.1 tsubai } 323 1.1 tsubai 324 1.1 tsubai sc->sc_map[chan].mp_offset = offset; 325 1.1 tsubai sc->sc_map[chan].mp_pages = pages; 326 1.4 tsubai scb->sc_map = &sc->sc_map[chan]; 327 1.1 tsubai } 328 1.1 tsubai 329 1.11 thorpej if ((flags & XS_CTL_POLL) == 0) 330 1.3 tsubai ie = SCSI_INTEN; 331 1.1 tsubai 332 1.4 tsubai if (xs->data) 333 1.4 tsubai scb->sc_cpoint = (void *)xs->data; 334 1.4 tsubai else 335 1.4 tsubai scb->sc_cpoint = scb->msgbuf; 336 1.4 tsubai scb->scb_softc = sc; 337 1.4 tsubai 338 1.15 thorpej callout_reset(&scb->xs->xs_callout, hz * 10, cxd1185_timeout, scb); 339 1.4 tsubai sc_send(scb, chan, ie); 340 1.15 thorpej callout_stop(&scb->xs->xs_callout); 341 1.1 tsubai 342 1.5 tsubai nextscb = scb->chain.tqe_next; 343 1.5 tsubai 344 1.5 tsubai TAILQ_REMOVE(&sc->ready_list, scb, chain); 345 1.5 tsubai 346 1.5 tsubai scb = nextscb; 347 1.5 tsubai 348 1.1 tsubai goto start; 349 1.1 tsubai } 350 1.1 tsubai 351 1.1 tsubai void 352 1.27 tsutsui sc_done(struct sc_scb *scb) 353 1.1 tsubai { 354 1.4 tsubai struct scsipi_xfer *xs = scb->xs; 355 1.17 bouyer struct scsipi_periph *periph = xs->xs_periph; 356 1.31 tsutsui struct sc_softc *sc; 357 1.1 tsubai 358 1.31 tsutsui sc = device_private(periph->periph_channel->chan_adapter->adapt_dev); 359 1.1 tsubai xs->resid = 0; 360 1.1 tsubai xs->status = 0; 361 1.1 tsubai 362 1.4 tsubai if (scb->istatus != INST_EP) { 363 1.16 matt if (scb->istatus == (INST_EP|INST_TO)) 364 1.12 tsubai xs->error = XS_SELTIMEOUT; 365 1.12 tsubai else { 366 1.1 tsubai printf("SC(i): [istatus=0x%x, tstatus=0x%x]\n", 367 1.4 tsubai scb->istatus, scb->tstatus); 368 1.12 tsubai xs->error = XS_DRIVER_STUFFUP; 369 1.12 tsubai } 370 1.1 tsubai } 371 1.1 tsubai 372 1.4 tsubai switch (scb->tstatus) { 373 1.1 tsubai 374 1.1 tsubai case TGST_GOOD: 375 1.1 tsubai break; 376 1.1 tsubai 377 1.1 tsubai case TGST_CC: 378 1.17 bouyer xs->status = SCSI_CHECK; 379 1.17 bouyer if (xs->error == 0) 380 1.17 bouyer xs->error = XS_BUSY; 381 1.29 tsutsui break; 382 1.1 tsubai 383 1.1 tsubai default: 384 1.1 tsubai printf("SC(t): [istatus=0x%x, tstatus=0x%x]\n", 385 1.4 tsubai scb->istatus, scb->tstatus); 386 1.1 tsubai break; 387 1.1 tsubai } 388 1.1 tsubai 389 1.1 tsubai scsipi_done(xs); 390 1.4 tsubai free_scb(sc, scb); 391 1.17 bouyer sc->inuse[periph->periph_target] = 0; 392 1.1 tsubai sc_sched(sc); 393 1.1 tsubai } 394 1.1 tsubai 395 1.1 tsubai int 396 1.27 tsutsui sc_intr(void *v) 397 1.1 tsubai { 398 1.14 tsubai /* struct sc_softc *sc = v; */ 399 1.31 tsutsui volatile uint8_t *gsp = (uint8_t *)DMAC_GSTAT; 400 1.14 tsubai u_int gstat = *gsp; 401 1.14 tsubai int mrqb, i; 402 1.14 tsubai 403 1.14 tsubai if ((gstat & CH_INT(CH_SCSI)) == 0) 404 1.14 tsubai return 0; 405 1.14 tsubai 406 1.14 tsubai /* 407 1.14 tsubai * when DMA interrupt occurs there remain some untransferred data. 408 1.14 tsubai * wait data transfer completion. 409 1.14 tsubai */ 410 1.14 tsubai mrqb = (gstat & CH_INT(CH_SCSI)) << 1; 411 1.14 tsubai if (gstat & mrqb) { 412 1.14 tsubai /* 413 1.14 tsubai * XXX SHOULD USE DELAY() 414 1.14 tsubai */ 415 1.14 tsubai for (i = 0; i < 50; i++) 416 1.14 tsubai ; 417 1.14 tsubai if (*gsp & mrqb) 418 1.31 tsutsui printf("%s: MRQ\n", __func__); 419 1.14 tsubai } 420 1.14 tsubai scintr(); 421 1.14 tsubai 422 1.14 tsubai return 1; 423 1.1 tsubai } 424 1.1 tsubai 425 1.1 tsubai 426 1.4 tsubai #if 0 427 1.1 tsubai /* 428 1.1 tsubai * SCOP_RSENSE request 429 1.1 tsubai */ 430 1.1 tsubai void 431 1.27 tsutsui scop_rsense(int intr, struct scsi *sc_param, int lun, int ie, int count, 432 1.30 christos void *param) 433 1.1 tsubai { 434 1.27 tsutsui 435 1.27 tsutsui memset(sc_param, 0, sizeof(struct scsi)); 436 1.4 tsubai sc_param->identify = MSG_IDENT | sc_disconnect | (lun & IDT_DRMASK); 437 1.1 tsubai sc_param->sc_lun = lun; 438 1.1 tsubai 439 1.31 tsutsui sc_param->sc_cpoint = (uint8_t *)param; 440 1.1 tsubai sc_param->sc_ctrnscnt = count; 441 1.1 tsubai 442 1.1 tsubai /* sc_cdb */ 443 1.1 tsubai sc_param->sc_opcode = SCOP_RSENSE; 444 1.1 tsubai sc_param->sc_count = count; 445 1.1 tsubai 446 1.4 tsubai sc_go(intr, sc_param, ie, sc_param); 447 1.1 tsubai } 448 1.4 tsubai #endif 449 1.1 tsubai 450 1.1 tsubai void 451 1.27 tsutsui cxd1185_timeout(void *arg) 452 1.1 tsubai { 453 1.1 tsubai struct sc_scb *scb = arg; 454 1.1 tsubai struct scsipi_xfer *xs = scb->xs; 455 1.17 bouyer struct scsipi_periph *periph = xs->xs_periph; 456 1.1 tsubai int chan; 457 1.1 tsubai 458 1.17 bouyer chan = periph->periph_target; 459 1.1 tsubai 460 1.1 tsubai printf("sc: timeout ch=%d\n", chan); 461 1.1 tsubai 462 1.1 tsubai /* XXX abort transfer and ... */ 463 1.1 tsubai } 464