1 /* $OpenBSD: ami.c,v 1.11 2001/09/11 20:05:25 miod Exp $ */ 2 3 /* 4 * Copyright (c) 2001 Michael Shalayeff 5 * All rights reserved. 6 * 7 * The SCSI emulation layer is derived from gdt(4) driver, 8 * Copyright (c) 1999, 2000 Niklas Hallqvist. All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by Michael Shalayeff. 21 * 4. The name of the author may not be used to endorse or promote products 22 * derived from this software without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 27 * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, 28 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 29 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 30 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 32 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 33 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 34 * THE POSSIBILITY OF SUCH DAMAGE. 35 */ 36 /* 37 * American Megatrends Inc. MegaRAID controllers driver 38 * 39 * This driver was made because these ppl and organizations 40 * donated hardware and provided documentation: 41 * 42 * - 428 model card 43 * John Kerbawy, Stephan Matis, Mark Stovall; 44 * 45 * - 467 and 475 model cards, docs 46 * American Megatrends Inc.; 47 * 48 * - uninterruptable electric power for cvs 49 * Theo de Raadt. 50 */ 51 52 /* #define AMI_DEBUG */ 53 54 #include <sys/param.h> 55 #include <sys/systm.h> 56 #include <sys/buf.h> 57 #include <sys/device.h> 58 #include <sys/kernel.h> 59 #include <sys/malloc.h> 60 61 #include <machine/bus.h> 62 63 #include <vm/vm.h> 64 #include <uvm/uvm_extern.h> 65 66 #include <scsi/scsi_all.h> 67 #include <scsi/scsi_disk.h> 68 #include <scsi/scsiconf.h> 69 70 #include <dev/ic/amireg.h> 71 #include <dev/ic/amivar.h> 72 73 #ifdef AMI_DEBUG 74 #define AMI_DPRINTF(m,a) if (ami_debug & (m)) printf a 75 #define AMI_D_CMD 0x0001 76 #define AMI_D_INTR 0x0002 77 #define AMI_D_MISC 0x0004 78 #define AMI_D_DMA 0x0008 79 int ami_debug = 0 80 | AMI_D_CMD 81 | AMI_D_INTR 82 | AMI_D_MISC 83 | AMI_D_DMA 84 ; 85 #else 86 #define AMI_DPRINTF(m,a) /* m, a */ 87 #endif 88 89 struct cfdriver ami_cd = { 90 NULL, "ami", DV_DULL 91 }; 92 93 int ami_scsi_cmd __P((struct scsi_xfer *xs)); 94 void amiminphys __P((struct buf *bp)); 95 96 struct scsi_adapter ami_switch = { 97 ami_scsi_cmd, amiminphys, 0, 0, 98 }; 99 100 struct scsi_device ami_dev = { 101 NULL, NULL, NULL, NULL 102 }; 103 104 int ami_scsi_raw_cmd __P((struct scsi_xfer *xs)); 105 106 struct scsi_adapter ami_raw_switch = { 107 ami_scsi_raw_cmd, amiminphys, 0, 0, 108 }; 109 110 struct scsi_device ami_raw_dev = { 111 NULL, NULL, NULL, NULL 112 }; 113 114 static __inline struct ami_ccb *ami_get_ccb __P((struct ami_softc *sc)); 115 static __inline void ami_put_ccb __P((struct ami_ccb *ccb)); 116 void ami_copyhds __P((struct ami_softc *sc, const u_int32_t *sizes, 117 const u_int8_t *props, const u_int8_t *stats)); 118 void *ami_allocmem __P((bus_dma_tag_t dmat, bus_dmamap_t *map, 119 bus_dma_segment_t *segp, size_t isize, size_t nent, const char *iname)); 120 void ami_freemem __P((bus_dma_tag_t dmat, bus_dmamap_t *map, 121 bus_dma_segment_t *segp, size_t isize, size_t nent, const char *iname)); 122 void ami_dispose __P((struct ami_softc *sc)); 123 void ami_stimeout __P((void *v)); 124 int ami_cmd __P((struct ami_ccb *ccb, int flags, int wait)); 125 int ami_start __P((struct ami_ccb *ccb, int wait)); 126 int ami_complete __P((struct ami_ccb *ccb)); 127 int ami_done __P((struct ami_softc *sc, int idx)); 128 void ami_copy_internal_data __P((struct scsi_xfer *xs, void *v, size_t size)); 129 int ami_inquire __P((struct ami_softc *sc, u_int8_t op)); 130 131 132 static __inline struct ami_ccb * 133 ami_get_ccb(sc) 134 struct ami_softc *sc; 135 { 136 struct ami_ccb *ccb; 137 138 ccb = TAILQ_LAST(&sc->sc_free_ccb, ami_queue_head); 139 if (ccb) { 140 TAILQ_REMOVE(&sc->sc_free_ccb, ccb, ccb_link); 141 ccb->ccb_state = AMI_CCB_READY; 142 } 143 return ccb; 144 } 145 146 static __inline void 147 ami_put_ccb(ccb) 148 struct ami_ccb *ccb; 149 { 150 struct ami_softc *sc = ccb->ccb_sc; 151 152 ccb->ccb_state = AMI_CCB_FREE; 153 TAILQ_INSERT_TAIL(&sc->sc_free_ccb, ccb, ccb_link); 154 } 155 156 void * 157 ami_allocmem(dmat, map, segp, isize, nent, iname) 158 bus_dma_tag_t dmat; 159 bus_dmamap_t *map; 160 bus_dma_segment_t *segp; 161 size_t isize, nent; 162 const char *iname; 163 { 164 size_t total = isize * nent; 165 caddr_t p; 166 int error, rseg; 167 168 /* XXX this is because we might have no dmamem_load_raw */ 169 if ((error = bus_dmamem_alloc(dmat, total, PAGE_SIZE, 0, segp, 1, 170 &rseg, BUS_DMA_NOWAIT))) { 171 printf(": cannot allocate %s%s (%d)\n", 172 iname, nent==1? "": "s", error); 173 return (NULL); 174 } 175 176 if ((error = bus_dmamem_map(dmat, segp, rseg, total, &p, 177 BUS_DMA_NOWAIT))) { 178 printf(": cannot map %s%s (%d)\n", 179 iname, nent==1? "": "s", error); 180 return (NULL); 181 } 182 183 bzero(p, total); 184 if ((error = bus_dmamap_create(dmat, total, 1, 185 total, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, map))) { 186 printf(": cannot create %s dmamap (%d)\n", iname, error); 187 return (NULL); 188 } 189 if ((error = bus_dmamap_load(dmat, *map, p, total, NULL, 190 BUS_DMA_NOWAIT))) { 191 printf(": cannot load %s dma map (%d)\n", iname, error); 192 return (NULL); 193 } 194 195 return (p); 196 } 197 198 void 199 ami_freemem(dmat, map, segp, isize, nent, iname) 200 bus_dma_tag_t dmat; 201 bus_dmamap_t *map; 202 bus_dma_segment_t *segp; 203 size_t isize, nent; 204 const char *iname; 205 { 206 bus_dmamem_free(dmat, segp, 1); 207 bus_dmamap_destroy(dmat, *map); 208 *map = NULL; 209 } 210 211 void 212 ami_dispose(sc) 213 struct ami_softc *sc; 214 { 215 register struct ami_ccb *ccb; 216 217 /* traverse the ccbs and destroy the maps */ 218 for (ccb = &sc->sc_ccbs[AMI_MAXCMDS - 1]; ccb > sc->sc_ccbs; ccb--) 219 if (ccb->ccb_dmamap) 220 bus_dmamap_destroy(sc->dmat, ccb->ccb_dmamap); 221 ami_freemem(sc->dmat, &sc->sc_sgmap, sc->sc_sgseg, 222 sizeof(struct ami_sgent) * AMI_SGEPERCMD, AMI_MAXCMDS, "sglist"); 223 ami_freemem(sc->dmat, &sc->sc_cmdmap, sc->sc_cmdseg, 224 sizeof(struct ami_iocmd), AMI_MAXCMDS + 1, "command"); 225 } 226 227 228 void 229 ami_copyhds(sc, sizes, props, stats) 230 struct ami_softc *sc; 231 const u_int32_t *sizes; 232 const u_int8_t *props, *stats; 233 { 234 int i; 235 236 for (i = 0; i < sc->sc_nunits; i++) { 237 sc->sc_hdr[i].hd_present = 1; 238 sc->sc_hdr[i].hd_is_logdrv = 1; 239 sc->sc_hdr[i].hd_size = letoh32(sizes[i]); 240 sc->sc_hdr[i].hd_prop = props[i]; 241 sc->sc_hdr[i].hd_stat = stats[i]; 242 if (sc->sc_hdr[i].hd_size > 0x200000) { 243 sc->sc_hdr[i].hd_heads = 255; 244 sc->sc_hdr[i].hd_secs = 63; 245 } else { 246 sc->sc_hdr[i].hd_heads = 64; 247 sc->sc_hdr[i].hd_secs = 32; 248 } 249 } 250 } 251 252 int 253 ami_attach(sc) 254 struct ami_softc *sc; 255 { 256 /* struct ami_rawsoftc *rsc; */ 257 struct ami_ccb *ccb; 258 struct ami_iocmd *cmd; 259 struct ami_sgent *sg; 260 bus_dmamap_t idatamap; 261 bus_dma_segment_t idataseg[1]; 262 const char *p; 263 void *idata; 264 int error; 265 266 if (!(idata = ami_allocmem(sc->dmat, &idatamap, idataseg, 267 NBPG, 1, "init data"))) { 268 ami_freemem(sc->dmat, &idatamap, idataseg, 269 NBPG, 1, "init data"); 270 return 1; 271 } 272 273 sc->sc_cmds = ami_allocmem(sc->dmat, &sc->sc_cmdmap, sc->sc_cmdseg, 274 sizeof(struct ami_iocmd), AMI_MAXCMDS+1, "command"); 275 if (!sc->sc_cmds) { 276 ami_dispose(sc); 277 ami_freemem(sc->dmat, &idatamap, 278 idataseg, NBPG, 1, "init data"); 279 return 1; 280 } 281 sc->sc_sgents = ami_allocmem(sc->dmat, &sc->sc_sgmap, sc->sc_sgseg, 282 sizeof(struct ami_sgent) * AMI_SGEPERCMD, AMI_MAXCMDS+1, "sglist"); 283 if (!sc->sc_sgents) { 284 ami_dispose(sc); 285 ami_freemem(sc->dmat, &idatamap, 286 idataseg, NBPG, 1, "init data"); 287 return 1; 288 } 289 290 TAILQ_INIT(&sc->sc_ccbq); 291 TAILQ_INIT(&sc->sc_ccb2q); 292 TAILQ_INIT(&sc->sc_ccbdone); 293 TAILQ_INIT(&sc->sc_free_ccb); 294 295 /* 0th command is a mailbox */ 296 for (ccb = &sc->sc_ccbs[AMI_MAXCMDS-1], 297 cmd = sc->sc_cmds + sizeof(*cmd) * AMI_MAXCMDS, 298 sg = sc->sc_sgents + sizeof(*sg) * AMI_MAXCMDS * AMI_SGEPERCMD; 299 cmd >= (struct ami_iocmd *)sc->sc_cmds; 300 cmd--, ccb--, sg -= AMI_SGEPERCMD) { 301 302 cmd->acc_id = cmd - (struct ami_iocmd *)sc->sc_cmds; 303 if (cmd->acc_id) { 304 error = bus_dmamap_create(sc->dmat, 305 AMI_MAXFER, AMI_MAXOFFSETS, AMI_MAXFER, 0, 306 BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, 307 &ccb->ccb_dmamap); 308 if (error) { 309 printf(": cannot create ccb dmamap (%d)\n", 310 error); 311 ami_dispose(sc); 312 ami_freemem(sc->dmat, &idatamap, 313 idataseg, NBPG, 1, "init data"); 314 return (1); 315 } 316 ccb->ccb_sc = sc; 317 ccb->ccb_cmd = cmd; 318 ccb->ccb_state = AMI_CCB_FREE; 319 ccb->ccb_cmdpa = htole32(sc->sc_cmdseg[0].ds_addr + 320 cmd->acc_id * sizeof(*cmd)); 321 ccb->ccb_sglist = sg; 322 ccb->ccb_sglistpa = htole32(sc->sc_sgseg[0].ds_addr + 323 cmd->acc_id * sizeof(*sg) * AMI_SGEPERCMD); 324 TAILQ_INSERT_TAIL(&sc->sc_free_ccb, ccb, ccb_link); 325 } else { 326 sc->sc_mbox = cmd; 327 sc->sc_mbox_pa = sc->sc_cmdseg[0].ds_addr; 328 } 329 } 330 331 timeout_set(&sc->sc_poll_tmo, (void (*)__P((void *)))ami_intr, sc); 332 333 (sc->sc_init)(sc); 334 { 335 paddr_t pa = idataseg[0].ds_addr; 336 ami_lock_t lock; 337 338 lock = AMI_LOCK_AMI(sc); 339 340 ccb = ami_get_ccb(sc); 341 cmd = ccb->ccb_cmd; 342 343 /* try FC inquiry first */ 344 cmd->acc_cmd = AMI_FCOP; 345 cmd->acc_io.aio_channel = AMI_FC_EINQ3; 346 cmd->acc_io.aio_param = AMI_FC_EINQ3_SOLICITED_FULL; 347 cmd->acc_io.aio_data = htole32(pa); 348 if (ami_cmd(ccb, 0, 1) == 0) { 349 struct ami_fc_einquiry *einq = idata; 350 struct ami_fc_prodinfo *pi = idata; 351 352 sc->sc_nunits = einq->ain_nlogdrv; 353 ami_copyhds(sc, einq->ain_ldsize, einq->ain_ldprop, 354 einq->ain_ldstat); 355 356 ccb = ami_get_ccb(sc); 357 cmd = ccb->ccb_cmd; 358 359 cmd->acc_cmd = AMI_FCOP; 360 cmd->acc_io.aio_channel = AMI_FC_PRODINF; 361 cmd->acc_io.aio_param = 0; 362 cmd->acc_io.aio_data = htole32(pa); 363 if (ami_cmd(ccb, 0, 1) == 0) { 364 sc->sc_maxunits = AMI_BIG_MAX_LDRIVES; 365 366 bcopy (pi->api_fwver, sc->sc_fwver, 16); 367 sc->sc_fwver[16] = '\0'; 368 bcopy (pi->api_biosver, sc->sc_biosver, 16); 369 sc->sc_biosver[16] = '\0'; 370 sc->sc_channels = pi->api_channels; 371 sc->sc_targets = pi->api_fcloops; 372 sc->sc_memory = letoh16(pi->api_ramsize); 373 sc->sc_maxcmds = pi->api_maxcmd; 374 p = "FC loop"; 375 } 376 } 377 378 if (sc->sc_maxunits == 0) { 379 struct ami_inquiry *inq = idata; 380 381 ccb = ami_get_ccb(sc); 382 cmd = ccb->ccb_cmd; 383 384 cmd->acc_cmd = AMI_EINQUIRY; 385 cmd->acc_io.aio_channel = 0; 386 cmd->acc_io.aio_param = 0; 387 cmd->acc_io.aio_data = htole32(pa); 388 if (ami_cmd(ccb, 0, 1) != 0) { 389 ccb = ami_get_ccb(sc); 390 cmd = ccb->ccb_cmd; 391 392 cmd->acc_cmd = AMI_INQUIRY; 393 cmd->acc_io.aio_channel = 0; 394 cmd->acc_io.aio_param = 0; 395 cmd->acc_io.aio_data = htole32(pa); 396 if (ami_cmd(ccb, 0, 1) != 0) { 397 AMI_UNLOCK_AMI(sc, lock); 398 printf(": cannot do inquiry\n"); 399 ami_dispose(sc); 400 ami_freemem(sc->dmat, &idatamap, 401 idataseg, NBPG, 1, "init data"); 402 return (1); 403 } 404 } 405 406 sc->sc_maxunits = AMI_MAX_LDRIVES; 407 sc->sc_nunits = inq->ain_nlogdrv; 408 ami_copyhds(sc, inq->ain_ldsize, inq->ain_ldprop, 409 inq->ain_ldstat); 410 411 bcopy (inq->ain_fwver, sc->sc_fwver, 4); 412 sc->sc_fwver[4] = '\0'; 413 bcopy (inq->ain_biosver, sc->sc_biosver, 4); 414 sc->sc_biosver[4] = '\0'; 415 sc->sc_channels = inq->ain_channels; 416 sc->sc_targets = inq->ain_targets; 417 sc->sc_memory = inq->ain_ramsize; 418 sc->sc_maxcmds = inq->ain_maxcmd; 419 p = "target"; 420 } 421 422 AMI_UNLOCK_AMI(sc, lock); 423 424 if (sc->sc_maxcmds > AMI_MAXCMDS) 425 sc->sc_maxcmds = 1 /* AMI_MAXCMDS */; 426 } 427 ami_freemem(sc->dmat, &idatamap, idataseg, NBPG, 1, "init data"); 428 429 /* hack for hp netraid version encoding */ 430 if ('A' <= sc->sc_fwver[2] && sc->sc_fwver[2] <= 'Z' && 431 sc->sc_fwver[1] < ' ' && sc->sc_fwver[0] < ' ' && 432 'A' <= sc->sc_biosver[2] && sc->sc_biosver[2] <= 'Z' && 433 sc->sc_biosver[1] < ' ' && sc->sc_biosver[0] < ' ') { 434 435 sprintf(sc->sc_fwver, "%c.%02d.%02d", sc->sc_fwver[2], 436 sc->sc_fwver[1], sc->sc_fwver[0]); 437 sprintf(sc->sc_biosver, "%c.%02d.%02d", sc->sc_biosver[2], 438 sc->sc_biosver[1], sc->sc_biosver[0]); 439 } 440 441 printf(": FW %s, BIOS v%s, %dMB RAM\n" 442 "%s: %d channels, %d %ss, %d logical drives\n", 443 sc->sc_fwver, sc->sc_biosver, sc->sc_memory, 444 sc->sc_dev.dv_xname, 445 sc->sc_channels, sc->sc_targets, p, sc->sc_nunits); 446 447 /* TODO: fetch & print cache strategy */ 448 /* TODO: fetch & print scsi and raid info */ 449 450 sc->sc_link.device = &ami_dev; 451 sc->sc_link.openings = sc->sc_maxcmds; 452 sc->sc_link.adapter_softc = sc; 453 sc->sc_link.adapter = &ami_switch; 454 sc->sc_link.adapter_target = sc->sc_maxunits; 455 sc->sc_link.adapter_buswidth = sc->sc_maxunits; 456 457 config_found(&sc->sc_dev, &sc->sc_link, scsiprint); 458 #if 0 459 rsc = malloc(sizeof(struct ami_rawsoftc) * sc->sc_channels, 460 M_DEVBUF, M_NOWAIT); 461 if (!rsc) { 462 printf("%s: no memory for raw interface\n", 463 sc->sc_dev.dv_xname); 464 return (0); 465 } 466 467 bzero(rsc, sizeof(struct ami_rawsoftc) * sc->sc_channels); 468 for (sc->sc_rawsoftcs = rsc; 469 rsc < &sc->sc_rawsoftcs[sc->sc_channels]; rsc++) { 470 471 /* TODO fetch and print channel properties */ 472 473 rsc->sc_softc = sc; 474 rsc->sc_channel = rsc - sc->sc_rawsoftcs; 475 rsc->sc_link.device = &ami_raw_dev; 476 rsc->sc_link.openings = sc->sc_maxcmds; 477 rsc->sc_link.adapter_softc = rsc; 478 rsc->sc_link.adapter = &ami_raw_switch; 479 /* TODO fetch it from the controller */ 480 rsc->sc_link.adapter_target = sc->sc_targets; 481 rsc->sc_link.adapter_buswidth = sc->sc_targets; 482 483 config_found(&sc->sc_dev, &rsc->sc_link, scsiprint); 484 } 485 #endif 486 return 0; 487 } 488 489 int 490 ami_quartz_init(sc) 491 struct ami_softc *sc; 492 { 493 return 0; 494 } 495 496 int 497 ami_quartz_exec(sc, cmd) 498 struct ami_softc *sc; 499 struct ami_iocmd *cmd; 500 { 501 u_int32_t qidb; 502 503 qidb = bus_space_read_4(sc->iot, sc->ioh, AMI_QIDB); 504 if (qidb & (AMI_QIDB_EXEC | AMI_QIDB_ACK)) { 505 AMI_DPRINTF(AMI_D_CMD, ("qidb=%x ", qidb)); 506 return (EBUSY); 507 } 508 509 *sc->sc_mbox = *cmd; 510 511 qidb = sc->sc_mbox_pa | AMI_QIDB_EXEC; 512 AMI_DPRINTF(AMI_D_CMD, ("qidb=%x ", qidb)); 513 bus_space_write_4(sc->iot, sc->ioh, AMI_QIDB, qidb); 514 return (0); 515 } 516 517 int 518 ami_quartz_done(sc, mbox) 519 struct ami_softc *sc; 520 struct ami_iocmd *mbox; 521 { 522 u_int32_t qdb; 523 #if 0 524 /* do not scramble the busy mailbox */ 525 if (sc->sc_mbox->acc_busy) { 526 AMI_DPRINTF(AMI_D_CMD, ("mbox_busy ")); 527 return (0); 528 } 529 #endif 530 qdb = bus_space_read_4(sc->iot, sc->ioh, AMI_QIDB); 531 if (qdb & (AMI_QIDB_EXEC | AMI_QIDB_ACK)) { 532 AMI_DPRINTF(AMI_D_CMD, ("qidb=%x ", qdb)); 533 return (0); 534 } 535 536 qdb = bus_space_read_4(sc->iot, sc->ioh, AMI_QODB); 537 if (qdb == AMI_QODB_READY) { 538 539 bus_dmamap_sync(sc->dmat, sc->sc_cmdmap, BUS_DMASYNC_POSTREAD); 540 *mbox = *sc->sc_mbox; 541 542 /* ack interrupt */ 543 bus_space_write_4(sc->iot, sc->ioh, AMI_QODB, AMI_QODB_READY); 544 545 qdb = sc->sc_mbox_pa | AMI_QIDB_ACK; 546 bus_space_write_4(sc->iot, sc->ioh, AMI_QIDB, qdb); 547 return (1); 548 } 549 550 AMI_DPRINTF(AMI_D_CMD, ("qodb=%x ", qdb)); 551 552 return (0); 553 } 554 555 int 556 ami_schwartz_init(sc) 557 struct ami_softc *sc; 558 { 559 u_int32_t a = (u_int32_t)sc->sc_mbox_pa; 560 561 bus_space_write_4(sc->iot, sc->ioh, AMI_SMBADDR, a); 562 /* XXX 40bit address ??? */ 563 bus_space_write_1(sc->iot, sc->ioh, AMI_SMBENA, 0); 564 565 bus_space_write_1(sc->iot, sc->ioh, AMI_SCMD, AMI_SCMD_ACK); 566 bus_space_write_1(sc->iot, sc->ioh, AMI_SIEM, AMI_SEIM_ENA | 567 bus_space_read_1(sc->iot, sc->ioh, AMI_SIEM)); 568 569 return 0; 570 } 571 572 int 573 ami_schwartz_exec(sc, cmd) 574 struct ami_softc *sc; 575 struct ami_iocmd *cmd; 576 { 577 if (bus_space_read_1(sc->iot, sc->ioh, AMI_SMBSTAT) & AMI_SMBST_BUSY) 578 return EBUSY; 579 580 *sc->sc_mbox = *cmd; 581 bus_space_write_1(sc->iot, sc->ioh, AMI_SCMD, AMI_SCMD_EXEC); 582 return 0; 583 } 584 585 int 586 ami_schwartz_done(sc, mbox) 587 struct ami_softc *sc; 588 struct ami_iocmd *mbox; 589 { 590 u_int8_t stat; 591 #if 0 592 /* do not scramble the busy mailbox */ 593 if (sc->sc_mbox->acc_busy) 594 return (0); 595 #endif 596 if (bus_space_read_1(sc->iot, sc->ioh, AMI_SMBSTAT) & AMI_SMBST_BUSY) 597 return 0; 598 599 stat = bus_space_read_1(sc->iot, sc->ioh, AMI_ISTAT); 600 if (stat & AMI_ISTAT_PEND) { 601 bus_space_write_1(sc->iot, sc->ioh, AMI_ISTAT, stat); 602 603 *mbox = *sc->sc_mbox; 604 605 bus_space_write_1(sc->iot, sc->ioh, AMI_SCMD, AMI_SCMD_ACK); 606 607 return 1; 608 } 609 610 return 0; 611 } 612 613 int 614 ami_cmd(ccb, flags, wait) 615 struct ami_ccb *ccb; 616 int flags, wait; 617 { 618 struct ami_softc *sc = ccb->ccb_sc; 619 bus_dmamap_t dmap = ccb->ccb_dmamap; 620 int error = 0, i; 621 622 if (ccb->ccb_data) { 623 struct ami_iocmd *cmd = ccb->ccb_cmd; 624 bus_dma_segment_t *sgd; 625 626 error = bus_dmamap_load(sc->dmat, dmap, ccb->ccb_data, 627 ccb->ccb_len, NULL, flags); 628 if (error) { 629 if (error == EFBIG) 630 printf("more than %d dma segs\n", AMI_MAXOFFSETS); 631 else 632 printf("error %d loading dma map\n", error); 633 634 ami_put_ccb(ccb); 635 return error; 636 } 637 638 sgd = dmap->dm_segs; 639 AMI_DPRINTF(AMI_D_DMA, ("data=%p/%u<0x%lx/%u", 640 ccb->ccb_data, ccb->ccb_len, 641 sgd->ds_addr, sgd->ds_len)); 642 643 if(dmap->dm_nsegs > 1) { 644 struct ami_sgent *sgl = ccb->ccb_sglist; 645 646 cmd->acc_mbox.amb_nsge = htole32(dmap->dm_nsegs); 647 cmd->acc_mbox.amb_data = ccb->ccb_sglistpa; 648 649 for (i = 0; i < dmap->dm_nsegs; i++, sgd++) { 650 sgl[i].asg_addr = htole32(sgd->ds_addr); 651 sgl[i].asg_len = htole32(sgd->ds_len); 652 if (i) 653 AMI_DPRINTF(AMI_D_DMA, (",0x%lx/%u", 654 sgd->ds_addr, sgd->ds_len)); 655 } 656 } else { 657 cmd->acc_mbox.amb_nsge = htole32(0); 658 cmd->acc_mbox.amb_data = htole32(sgd->ds_addr); 659 } 660 AMI_DPRINTF(AMI_D_DMA, ("> ")); 661 662 bus_dmamap_sync(sc->dmat, dmap, BUS_DMASYNC_PREWRITE); 663 } 664 bus_dmamap_sync(sc->dmat, sc->sc_cmdmap, BUS_DMASYNC_PREWRITE); 665 666 if ((error = ami_start(ccb, wait))) { 667 AMI_DPRINTF(AMI_D_DMA, ("error=%d ", error)); 668 __asm __volatile(".globl _bpamierr\n_bpamierr:"); 669 if (ccb->ccb_data) 670 bus_dmamap_unload(sc->dmat, dmap); 671 ami_put_ccb(ccb); 672 } else if (wait) { 673 AMI_DPRINTF(AMI_D_DMA, ("waiting ")); 674 if ((error = ami_complete(ccb))) 675 ami_put_ccb(ccb); 676 } 677 678 return error; 679 } 680 681 int 682 ami_start(ccb, wait) 683 struct ami_ccb *ccb; 684 int wait; 685 { 686 struct ami_softc *sc = ccb->ccb_sc; 687 struct ami_iocmd *cmd = ccb->ccb_cmd; 688 struct scsi_xfer *xs = ccb->ccb_xs; 689 volatile struct ami_iocmd *mbox = sc->sc_mbox; 690 int i; 691 692 AMI_DPRINTF(AMI_D_CMD, ("start(%d) ", cmd->acc_id)); 693 694 if (ccb->ccb_state != AMI_CCB_READY) { 695 printf("%s: ccb %d not ready <%d>\n", 696 sc->sc_dev.dv_xname, cmd->acc_id, ccb->ccb_state); 697 return EINVAL; 698 } 699 700 if (xs) 701 timeout_set(&xs->stimeout, ami_stimeout, ccb); 702 703 if (mbox->acc_busy) { 704 705 if (!wait) { 706 AMI_DPRINTF(AMI_D_CMD, ("2queue(%d) ", cmd->acc_id)); 707 ccb->ccb_state = AMI_CCB_PREQUEUED; 708 if (xs) 709 timeout_add(&xs->stimeout, 1); 710 711 return (xs? 0 : EBUSY); 712 } 713 714 for (i = 100000; i-- && mbox->acc_busy; DELAY(10)); 715 716 if (mbox->acc_busy) { 717 AMI_DPRINTF(AMI_D_CMD, ("mbox_busy ")); 718 return (EAGAIN); 719 } 720 } 721 722 AMI_DPRINTF(AMI_D_CMD, ("exec ")); 723 724 cmd->acc_busy = 1; 725 cmd->acc_poll = 0; 726 cmd->acc_ack = 0; 727 728 if (!(i = (sc->sc_exec)(sc, cmd))) { 729 ccb->ccb_state = AMI_CCB_QUEUED; 730 TAILQ_INSERT_TAIL(&sc->sc_ccbq, ccb, ccb_link); 731 if (!wait) { 732 #ifdef AMI_POLLING 733 if (!timeout_pending(&sc->sc_poll_tmo)) 734 timeout_add(&sc->sc_poll_tmo, 1); 735 #endif 736 if (xs) 737 /*timeout_add(&xs->stimeout, hz * xs->timeout / 1000)*/; 738 } 739 } else if (!wait) { 740 AMI_DPRINTF(AMI_D_CMD, ("2queue1(%d) ", cmd->acc_id)); 741 ccb->ccb_state = AMI_CCB_PREQUEUED; 742 if (xs) { 743 timeout_add(&xs->stimeout, 1); 744 return (0); 745 } 746 } 747 748 return i; 749 } 750 751 void 752 ami_stimeout(v) 753 void *v; 754 { 755 struct ami_ccb *ccb = v; 756 struct ami_softc *sc = ccb->ccb_sc; 757 struct scsi_xfer *xs = ccb->ccb_xs; 758 struct ami_iocmd *cmd = ccb->ccb_cmd; 759 volatile struct ami_iocmd *mbox = sc->sc_mbox; 760 ami_lock_t lock; 761 762 switch (ccb->ccb_state) { 763 case AMI_CCB_PREQUEUED: 764 if (mbox->acc_busy) { 765 timeout_add(&xs->stimeout, 1); 766 return; 767 } 768 769 AMI_DPRINTF(AMI_D_CMD, ("requeue(%d) ", cmd->acc_id)); 770 ccb->ccb_state = AMI_CCB_READY; 771 772 lock = AMI_LOCK_AMI(sc); 773 if (ami_start(ccb, 0)) { 774 AMI_DPRINTF(AMI_D_CMD, ("requeue(%d) again\n", cmd->acc_id)); 775 ccb->ccb_state = AMI_CCB_PREQUEUED; 776 timeout_add(&xs->stimeout, 1); 777 } 778 AMI_UNLOCK_AMI(sc, lock); 779 break; 780 781 case AMI_CCB_QUEUED: 782 /* XXX need to kill all cmds in the queue and reset the card */ 783 AMI_DPRINTF(AMI_D_CMD, ("timeout(%d) ", cmd->acc_id)); 784 lock = AMI_LOCK_AMI(sc); 785 TAILQ_REMOVE(&sc->sc_ccbq, ccb, ccb_link); 786 ami_put_ccb(ccb); 787 AMI_UNLOCK_AMI(sc, lock); 788 xs->error = XS_TIMEOUT; 789 scsi_done(xs); 790 break; 791 case AMI_CCB_FREE: 792 case AMI_CCB_READY: 793 panic("ami_stimeout(%p) botch", cmd->acc_id); 794 } 795 } 796 797 int 798 ami_complete(ccb) 799 struct ami_ccb *ccb; 800 { 801 struct ami_softc *sc = ccb->ccb_sc; 802 struct scsi_xfer *xs = ccb->ccb_xs; 803 struct ami_iocmd mbox; 804 int i, j, rv, status; 805 806 DELAY(10000000); 807 for (rv = 1, status = 0, i = 1 * (xs? xs->timeout: 1000); 808 !status && rv && i--; DELAY(1000)) 809 if ((sc->sc_done)(sc, &mbox)) { 810 AMI_DPRINTF(AMI_D_CMD, ("got#%d ", mbox.acc_nstat)); 811 status = mbox.acc_status; 812 for (j = 0; j < mbox.acc_nstat; j++ ) { 813 int ready = mbox.acc_cmplidl[j]; 814 815 AMI_DPRINTF(AMI_D_CMD, ("ready=%x ", ready)); 816 817 if (!ami_done(sc, ready) && 818 ccb->ccb_cmd->acc_id == ready) 819 rv = 0; 820 } 821 } 822 823 if (status) { 824 AMI_DPRINTF(AMI_D_CMD, ("aborted\n")); 825 } else if (!rv) { 826 AMI_DPRINTF(AMI_D_CMD, ("complete\n")); 827 } else if (i < 0) { 828 AMI_DPRINTF(AMI_D_CMD, ("timeout\n")); 829 } else 830 AMI_DPRINTF(AMI_D_CMD, ("screwed\n")); 831 832 return rv? rv : status; 833 } 834 835 int 836 ami_done(sc, idx) 837 struct ami_softc *sc; 838 int idx; 839 { 840 struct ami_ccb *ccb = &sc->sc_ccbs[idx - 1]; 841 struct scsi_xfer *xs = ccb->ccb_xs; 842 ami_lock_t lock; 843 844 AMI_DPRINTF(AMI_D_CMD, ("done(%d) ", ccb->ccb_cmd->acc_id)); 845 846 if (ccb->ccb_state != AMI_CCB_QUEUED) { 847 printf("%s: unqueued ccb %d ready, state = %d\n", 848 sc->sc_dev.dv_xname, idx, ccb->ccb_state); 849 return 1; 850 } 851 852 lock = AMI_LOCK_AMI(sc); 853 TAILQ_REMOVE(&sc->sc_ccbq, ccb, ccb_link); 854 ccb->ccb_state = AMI_CCB_READY; 855 AMI_UNLOCK_AMI(sc, lock); 856 857 if (xs) { 858 timeout_del(&xs->stimeout); 859 if (xs->cmd->opcode != PREVENT_ALLOW && 860 xs->cmd->opcode != SYNCHRONIZE_CACHE) { 861 bus_dmamap_sync(sc->dmat, ccb->ccb_dmamap, 862 (xs->flags & SCSI_DATA_IN) ? 863 BUS_DMASYNC_POSTREAD : 864 BUS_DMASYNC_POSTWRITE); 865 bus_dmamap_unload(sc->dmat, ccb->ccb_dmamap); 866 } 867 } else { 868 struct ami_iocmd *cmd = ccb->ccb_cmd; 869 870 switch (cmd->acc_cmd) { 871 case AMI_INQUIRY: 872 case AMI_EINQUIRY: 873 case AMI_EINQUIRY3: 874 bus_dmamap_sync(sc->dmat, ccb->ccb_dmamap, 875 BUS_DMASYNC_POSTREAD); 876 bus_dmamap_unload(sc->dmat, ccb->ccb_dmamap); 877 break; 878 default: 879 /* no data */ 880 break; 881 } 882 } 883 884 lock = AMI_LOCK_AMI(sc); 885 ami_put_ccb(ccb); 886 AMI_UNLOCK_AMI(sc, lock); 887 888 if (xs) { 889 xs->resid = 0; 890 xs->flags |= ITSDONE; 891 AMI_DPRINTF(AMI_D_CMD, ("scsi_done(%d) ", idx)); 892 scsi_done(xs); 893 } 894 895 return 0; 896 } 897 898 void 899 amiminphys(bp) 900 struct buf *bp; 901 { 902 if (bp->b_bcount > AMI_MAXFER) 903 bp->b_bcount = AMI_MAXFER; 904 minphys(bp); 905 } 906 907 void 908 ami_copy_internal_data(xs, v, size) 909 struct scsi_xfer *xs; 910 void *v; 911 size_t size; 912 { 913 size_t copy_cnt; 914 915 AMI_DPRINTF(AMI_D_MISC, ("ami_copy_internal_data ")); 916 917 if (!xs->datalen) 918 printf("uio move not yet supported\n"); 919 else { 920 copy_cnt = MIN(size, xs->datalen); 921 bcopy(v, xs->data, copy_cnt); 922 } 923 } 924 925 int 926 ami_scsi_raw_cmd(xs) 927 struct scsi_xfer *xs; 928 { 929 struct scsi_link *link = xs->sc_link; 930 struct ami_rawsoftc *rsc = link->adapter_softc; 931 struct ami_softc *sc = rsc->sc_softc; 932 u_int8_t channel = rsc->sc_channel, target = link->target; 933 struct ami_ccb *ccb, *ccb1; 934 struct ami_iocmd *cmd; 935 struct ami_passthrough *ps; 936 int error; 937 ami_lock_t lock; 938 939 AMI_DPRINTF(AMI_D_CMD, ("ami_scsi_raw_cmd ")); 940 941 if (xs->cmdlen > AMI_MAX_CDB) { 942 AMI_DPRINTF(AMI_D_CMD, ("CDB too big %p ", xs)); 943 bzero(&xs->sense, sizeof(xs->sense)); 944 xs->sense.error_code = SSD_ERRCODE_VALID | 0x70; 945 xs->sense.flags = SKEY_ILLEGAL_REQUEST; 946 xs->sense.add_sense_code = 0x20; /* illcmd, 0x24 illfield */ 947 xs->error = XS_SENSE; 948 scsi_done(xs); 949 return (COMPLETE); 950 } 951 952 xs->error = XS_NOERROR; 953 954 lock = AMI_LOCK_AMI(sc); 955 956 if ((ccb = ami_get_ccb(sc)) == NULL) { 957 AMI_UNLOCK_AMI(sc, lock); 958 xs->error = XS_DRIVER_STUFFUP; 959 scsi_done(xs); 960 return (COMPLETE); 961 } 962 963 if ((ccb1 = ami_get_ccb(sc)) == NULL) { 964 ami_put_ccb(ccb); 965 AMI_UNLOCK_AMI(sc, lock); 966 xs->error = XS_DRIVER_STUFFUP; 967 scsi_done(xs); 968 return (COMPLETE); 969 } 970 971 ccb->ccb_xs = xs; 972 ccb->ccb_ccb1 = ccb1; 973 ccb->ccb_len = xs->datalen; 974 ccb->ccb_data = xs->data; 975 976 ps = (struct ami_passthrough *)ccb1->ccb_cmd; 977 ps->apt_param = AMI_PTPARAM(AMI_TIMEOUT_6,1,0); 978 ps->apt_channel = channel; 979 ps->apt_target = target; 980 bcopy(xs->cmd, ps->apt_cdb, AMI_MAX_CDB); 981 ps->apt_ncdb = xs->cmdlen; 982 ps->apt_nsense = AMI_MAX_SENSE; 983 984 cmd = ccb->ccb_cmd; 985 cmd->acc_cmd = AMI_PASSTHRU; 986 cmd->acc_passthru.apt_data = ccb1->ccb_cmdpa; 987 988 if ((error = ami_cmd(ccb, ((xs->flags & SCSI_NOSLEEP)? 989 BUS_DMA_NOWAIT : BUS_DMA_WAITOK), xs->flags & SCSI_POLL))) { 990 991 AMI_UNLOCK_AMI(sc, lock); 992 AMI_DPRINTF(AMI_D_CMD, ("failed %p ", xs)); 993 if (xs->flags & SCSI_POLL) { 994 xs->error = XS_TIMEOUT; 995 return (TRY_AGAIN_LATER); 996 } else { 997 xs->error = XS_DRIVER_STUFFUP; 998 scsi_done(xs); 999 return (COMPLETE); 1000 } 1001 } 1002 1003 AMI_UNLOCK_AMI(sc, lock); 1004 1005 if (xs->flags & SCSI_POLL) { 1006 scsi_done(xs); 1007 return (COMPLETE); 1008 } 1009 1010 return (SUCCESSFULLY_QUEUED); 1011 } 1012 1013 int 1014 ami_scsi_cmd(xs) 1015 struct scsi_xfer *xs; 1016 { 1017 struct scsi_link *link = xs->sc_link; 1018 struct ami_softc *sc = link->adapter_softc; 1019 struct ami_ccb *ccb; 1020 struct ami_iocmd *cmd; 1021 struct scsi_inquiry_data inq; 1022 struct scsi_sense_data sd; 1023 struct { 1024 struct scsi_mode_header hd; 1025 struct scsi_blk_desc bd; 1026 union scsi_disk_pages dp; 1027 } mpd; 1028 struct scsi_read_cap_data rcd; 1029 u_int8_t target = link->target; 1030 u_int32_t blockno, blockcnt; 1031 struct scsi_rw *rw; 1032 struct scsi_rw_big *rwb; 1033 int error, flags; 1034 ami_lock_t lock; 1035 1036 if (target >= sc->sc_nunits || !sc->sc_hdr[target].hd_present || 1037 link->lun != 0) { 1038 /* XXX should be XS_SENSE and sense filled out */ 1039 xs->error = XS_DRIVER_STUFFUP; 1040 xs->flags |= ITSDONE; 1041 scsi_done(xs); 1042 return (COMPLETE); 1043 } 1044 1045 AMI_DPRINTF(AMI_D_CMD, ("ami_scsi_cmd ")); 1046 1047 error = 0; 1048 xs->error = XS_NOERROR; 1049 1050 switch (xs->cmd->opcode) { 1051 case TEST_UNIT_READY: 1052 case START_STOP: 1053 #if 0 1054 case VERIFY: 1055 #endif 1056 AMI_DPRINTF(AMI_D_CMD, ("opc %d tgt %d ", xs->cmd->opcode, 1057 target)); 1058 break; 1059 1060 case REQUEST_SENSE: 1061 AMI_DPRINTF(AMI_D_CMD, ("REQUEST SENSE tgt %d ", target)); 1062 bzero(&sd, sizeof sd); 1063 sd.error_code = 0x70; 1064 sd.segment = 0; 1065 sd.flags = SKEY_NO_SENSE; 1066 *(u_int32_t*)sd.info = htole32(0); 1067 sd.extra_len = 0; 1068 ami_copy_internal_data(xs, &sd, sizeof sd); 1069 break; 1070 1071 case INQUIRY: 1072 AMI_DPRINTF(AMI_D_CMD, ("INQUIRY tgt %d ", target)); 1073 bzero(&inq, sizeof inq); 1074 inq.device = T_DIRECT; 1075 inq.dev_qual2 = 0; 1076 inq.version = 2; 1077 inq.response_format = 2; 1078 inq.additional_length = 32; 1079 strcpy(inq.vendor, "AMI "); 1080 sprintf(inq.product, "Host drive #%02d", target); 1081 strcpy(inq.revision, " "); 1082 ami_copy_internal_data(xs, &inq, sizeof inq); 1083 break; 1084 1085 case MODE_SENSE: 1086 AMI_DPRINTF(AMI_D_CMD, ("MODE SENSE tgt %d ", target)); 1087 1088 bzero(&mpd, sizeof mpd); 1089 switch (((struct scsi_mode_sense *)xs->cmd)->page) { 1090 case 4: 1091 /* scsi_disk.h says this should be 0x16 */ 1092 mpd.dp.rigid_geometry.pg_length = 0x16; 1093 mpd.hd.data_length = sizeof mpd.hd + sizeof mpd.bd + 1094 mpd.dp.rigid_geometry.pg_length; 1095 mpd.hd.blk_desc_len = sizeof mpd.bd; 1096 1097 mpd.hd.dev_spec = 0; /* writeprotect ? XXX */ 1098 _lto3b(AMI_SECTOR_SIZE, mpd.bd.blklen); 1099 mpd.dp.rigid_geometry.pg_code = 4; 1100 _lto3b(sc->sc_hdr[target].hd_size / 1101 sc->sc_hdr[target].hd_heads / 1102 sc->sc_hdr[target].hd_secs, 1103 mpd.dp.rigid_geometry.ncyl); 1104 mpd.dp.rigid_geometry.nheads = 1105 sc->sc_hdr[target].hd_heads; 1106 ami_copy_internal_data(xs, (u_int8_t *)&mpd, 1107 sizeof mpd); 1108 break; 1109 1110 default: 1111 printf("%s: mode sense page %d not simulated\n", 1112 sc->sc_dev.dv_xname, 1113 ((struct scsi_mode_sense *)xs->cmd)->page); 1114 xs->error = XS_DRIVER_STUFFUP; 1115 } 1116 break; 1117 1118 case READ_CAPACITY: 1119 AMI_DPRINTF(AMI_D_CMD, ("READ CAPACITY tgt %d ", target)); 1120 bzero(&rcd, sizeof rcd); 1121 _lto4b(sc->sc_hdr[target].hd_size - 1, rcd.addr); 1122 _lto4b(AMI_SECTOR_SIZE, rcd.length); 1123 ami_copy_internal_data(xs, &rcd, sizeof rcd); 1124 break; 1125 1126 case PREVENT_ALLOW: 1127 AMI_DPRINTF(AMI_D_CMD, ("PREVENT/ALLOW ")); 1128 return (COMPLETE); 1129 1130 case SYNCHRONIZE_CACHE: 1131 AMI_DPRINTF(AMI_D_CMD, ("SYNCHRONIZE CACHE ")); 1132 error++; 1133 case READ_COMMAND: 1134 if (!error) { 1135 AMI_DPRINTF(AMI_D_CMD, ("READ ")); 1136 error++; 1137 } 1138 case READ_BIG: 1139 if (!error) { 1140 AMI_DPRINTF(AMI_D_CMD, ("READ BIG ")); 1141 error++; 1142 } 1143 case WRITE_COMMAND: 1144 if (!error) { 1145 AMI_DPRINTF(AMI_D_CMD, ("WRITE ")); 1146 error++; 1147 } 1148 case WRITE_BIG: 1149 if (!error) { 1150 AMI_DPRINTF(AMI_D_CMD, ("WRITE BIG ")); 1151 error++; 1152 } 1153 lock = AMI_LOCK_AMI(sc); 1154 1155 flags = 0; 1156 if (xs->cmd->opcode != SYNCHRONIZE_CACHE) { 1157 /* A read or write operation. */ 1158 if (xs->cmdlen == 6) { 1159 rw = (struct scsi_rw *)xs->cmd; 1160 blockno = _3btol(rw->addr) & 1161 (SRW_TOPADDR << 16 | 0xffff); 1162 blockcnt = rw->length ? rw->length : 0x100; 1163 } else { 1164 rwb = (struct scsi_rw_big *)xs->cmd; 1165 blockno = _4btol(rwb->addr); 1166 blockcnt = _2btol(rwb->length); 1167 /* TODO: reflect DPO & FUA flags */ 1168 if (xs->cmd->opcode == WRITE_BIG && 1169 rwb->byte2 & 0x18) 1170 flags = 0; 1171 } 1172 if (blockno >= sc->sc_hdr[target].hd_size || 1173 blockno + blockcnt > sc->sc_hdr[target].hd_size) { 1174 AMI_UNLOCK_AMI(sc, lock); 1175 printf("%s: out of bounds %u-%u >= %u\n", 1176 sc->sc_dev.dv_xname, blockno, blockcnt, 1177 sc->sc_hdr[target].hd_size); 1178 xs->error = XS_DRIVER_STUFFUP; 1179 break; 1180 } 1181 } 1182 1183 if ((ccb = ami_get_ccb(sc)) == NULL) { 1184 AMI_UNLOCK_AMI(sc, lock); 1185 AMI_DPRINTF(AMI_D_CMD, ("no more ccbs ")); 1186 xs->error = XS_DRIVER_STUFFUP; 1187 __asm __volatile(".globl _bpamiccb\n_bpamiccb:"); 1188 break; 1189 } 1190 1191 ccb->ccb_xs = xs; 1192 ccb->ccb_ccb1 = NULL; 1193 ccb->ccb_len = xs->datalen; 1194 ccb->ccb_data = xs->data; 1195 cmd = ccb->ccb_cmd; 1196 cmd->acc_mbox.amb_nsect = htole16(blockcnt); 1197 cmd->acc_mbox.amb_lba = htole32(blockno); 1198 cmd->acc_mbox.amb_ldn = target; 1199 cmd->acc_mbox.amb_data = 0; 1200 1201 switch (xs->cmd->opcode) { 1202 case SYNCHRONIZE_CACHE: 1203 cmd->acc_cmd = AMI_FLUSH; 1204 /* XXX do other fields matter ? */ 1205 break; 1206 case READ_COMMAND: case READ_BIG: 1207 cmd->acc_cmd = AMI_READ; 1208 break; 1209 case WRITE_COMMAND: case WRITE_BIG: 1210 cmd->acc_cmd = AMI_WRITE; 1211 break; 1212 } 1213 1214 if ((error = ami_cmd(ccb, ((xs->flags & SCSI_NOSLEEP)? 1215 BUS_DMA_NOWAIT : BUS_DMA_WAITOK), xs->flags & SCSI_POLL))) { 1216 1217 AMI_UNLOCK_AMI(sc, lock); 1218 AMI_DPRINTF(AMI_D_CMD, ("failed %p ", xs)); 1219 __asm __volatile(".globl _bpamifail\n_bpamifail:"); 1220 if (xs->flags & SCSI_POLL) { 1221 xs->error = XS_TIMEOUT; 1222 return (TRY_AGAIN_LATER); 1223 } else { 1224 xs->error = XS_DRIVER_STUFFUP; 1225 break; 1226 } 1227 } 1228 1229 AMI_UNLOCK_AMI(sc, lock); 1230 if (xs->flags & SCSI_POLL) 1231 break; 1232 return (SUCCESSFULLY_QUEUED); 1233 1234 default: 1235 AMI_DPRINTF(AMI_D_CMD, ("unknown opc %d ", xs->cmd->opcode)); 1236 xs->error = XS_DRIVER_STUFFUP; 1237 } 1238 1239 xs->flags |= ITSDONE; 1240 scsi_done(xs); 1241 return (xs->flags & SCSI_POLL? COMPLETE : SUCCESSFULLY_QUEUED); 1242 } 1243 1244 int 1245 ami_intr(v) 1246 void *v; 1247 { 1248 struct ami_softc *sc = v; 1249 struct ami_iocmd mbox; 1250 int i, rv = 0; 1251 ami_lock_t lock; 1252 1253 if (TAILQ_EMPTY(&sc->sc_ccbq)) 1254 return (0); 1255 1256 AMI_DPRINTF(AMI_D_INTR, ("intr ")); 1257 1258 lock = AMI_LOCK_AMI(sc); 1259 while ((sc->sc_done)(sc, &mbox)) { 1260 AMI_UNLOCK_AMI(sc, lock); 1261 AMI_DPRINTF(AMI_D_CMD, ("got#%d ", mbox.acc_nstat)); 1262 for (i = 0; i < mbox.acc_nstat; i++ ) { 1263 register int ready = mbox.acc_cmplidl[i]; 1264 1265 AMI_DPRINTF(AMI_D_CMD, ("ready=%d ", ready)); 1266 1267 if (!ami_done(sc, ready)) 1268 rv = 1; 1269 } 1270 lock = AMI_LOCK_AMI(sc); 1271 } 1272 1273 #ifdef AMI_POLLING 1274 if (!TAILQ_EMPTY(&sc->sc_ccbq) && !timeout_pending(&sc->sc_poll_tmo)) { 1275 AMI_DPRINTF(AMI_D_INTR, ("tmo ")); 1276 timeout_add(&sc->sc_poll_tmo, 100); 1277 } 1278 #endif 1279 1280 AMI_UNLOCK_AMI(sc, lock); 1281 return rv; 1282 } 1283