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