1 /* $OpenBSD: ami.c,v 1.197 2009/08/12 14:15:05 dlg Exp $ */ 2 3 /* 4 * Copyright (c) 2001 Michael Shalayeff 5 * Copyright (c) 2005 Marco Peereboom 6 * Copyright (c) 2006 David Gwynne 7 * All rights reserved. 8 * 9 * The SCSI emulation layer is derived from gdt(4) driver, 10 * Copyright (c) 1999, 2000 Niklas Hallqvist. All rights reserved. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, 25 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 30 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 31 * THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 /* 34 * American Megatrends Inc. MegaRAID controllers driver 35 * 36 * This driver was made because these ppl and organizations 37 * donated hardware and provided documentation: 38 * 39 * - 428 model card 40 * John Kerbawy, Stephan Matis, Mark Stovall; 41 * 42 * - 467 and 475 model cards, docs 43 * American Megatrends Inc.; 44 * 45 * - uninterruptable electric power for cvs 46 * Theo de Raadt. 47 */ 48 49 #include "bio.h" 50 51 /* #define AMI_DEBUG */ 52 53 #include <sys/param.h> 54 #include <sys/systm.h> 55 #include <sys/buf.h> 56 #include <sys/ioctl.h> 57 #include <sys/device.h> 58 #include <sys/kernel.h> 59 #include <sys/malloc.h> 60 #include <sys/proc.h> 61 #include <sys/rwlock.h> 62 63 #include <machine/bus.h> 64 65 #include <scsi/scsi_all.h> 66 #include <scsi/scsi_disk.h> 67 #include <scsi/scsiconf.h> 68 69 #include <dev/biovar.h> 70 #include <dev/ic/amireg.h> 71 #include <dev/ic/amivar.h> 72 73 #ifdef AMI_DEBUG 74 #define AMI_DPRINTF(m,a) do { if (ami_debug & (m)) printf a; } while (0) 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 #define AMI_D_IOCTL 0x0010 80 int ami_debug = 0 81 /* | AMI_D_CMD */ 82 /* | AMI_D_INTR */ 83 /* | AMI_D_MISC */ 84 /* | AMI_D_DMA */ 85 /* | AMI_D_IOCTL */ 86 ; 87 #else 88 #define AMI_DPRINTF(m,a) /* m, a */ 89 #endif 90 91 struct cfdriver ami_cd = { 92 NULL, "ami", DV_DULL 93 }; 94 95 int ami_scsi_cmd(struct scsi_xfer *); 96 int ami_scsi_ioctl(struct scsi_link *, u_long, caddr_t, int, struct proc *); 97 void amiminphys(struct buf *bp, struct scsi_link *sl); 98 99 struct scsi_adapter ami_switch = { 100 ami_scsi_cmd, amiminphys, 0, 0, ami_scsi_ioctl 101 }; 102 103 struct scsi_device ami_dev = { 104 NULL, NULL, NULL, NULL 105 }; 106 107 int ami_scsi_raw_cmd(struct scsi_xfer *); 108 109 struct scsi_adapter ami_raw_switch = { 110 ami_scsi_raw_cmd, amiminphys, 0, 0, 111 }; 112 113 struct scsi_device ami_raw_dev = { 114 NULL, NULL, NULL, NULL 115 }; 116 117 void ami_remove_runq(struct ami_ccb *); 118 void ami_insert_runq(struct ami_ccb *); 119 struct ami_ccb *ami_get_ccb(struct ami_softc *); 120 void ami_put_ccb(struct ami_ccb *); 121 122 u_int32_t ami_read(struct ami_softc *, bus_size_t); 123 void ami_write(struct ami_softc *, bus_size_t, u_int32_t); 124 125 void ami_copyhds(struct ami_softc *, const u_int32_t *, 126 const u_int8_t *, const u_int8_t *); 127 struct ami_mem *ami_allocmem(struct ami_softc *, size_t); 128 void ami_freemem(struct ami_softc *, struct ami_mem *); 129 int ami_alloc_ccbs(struct ami_softc *, int); 130 131 int ami_poll(struct ami_softc *, struct ami_ccb *); 132 void ami_start(struct ami_softc *, struct ami_ccb *); 133 void ami_complete(struct ami_softc *, struct ami_ccb *, int); 134 int ami_done(struct ami_softc *, int, int); 135 void ami_runqueue_tick(void *); 136 void ami_runqueue(struct ami_softc *); 137 138 int ami_start_xs(struct ami_softc *sc, struct ami_ccb *, 139 struct scsi_xfer *); 140 void ami_done_xs(struct ami_softc *, struct ami_ccb *); 141 void ami_done_pt(struct ami_softc *, struct ami_ccb *); 142 void ami_done_flush(struct ami_softc *, struct ami_ccb *); 143 void ami_done_sysflush(struct ami_softc *, struct ami_ccb *); 144 void ami_stimeout(void *); 145 146 void ami_done_dummy(struct ami_softc *, struct ami_ccb *); 147 void ami_done_ioctl(struct ami_softc *, struct ami_ccb *); 148 void ami_done_init(struct ami_softc *, struct ami_ccb *); 149 150 void ami_copy_internal_data(struct scsi_xfer *, void *, size_t); 151 152 int ami_load_ptmem(struct ami_softc*, struct ami_ccb *, 153 void *, size_t, int, int); 154 155 #if NBIO > 0 156 int ami_mgmt(struct ami_softc *, u_int8_t, u_int8_t, u_int8_t, 157 u_int8_t, size_t, void *); 158 int ami_drv_pt(struct ami_softc *, u_int8_t, u_int8_t, u_int8_t *, 159 int, int, void *); 160 int ami_drv_readcap(struct ami_softc *, u_int8_t, u_int8_t, 161 daddr64_t *); 162 int ami_drv_inq(struct ami_softc *, u_int8_t, u_int8_t, u_int8_t, 163 void *); 164 int ami_ioctl(struct device *, u_long, caddr_t); 165 int ami_ioctl_inq(struct ami_softc *, struct bioc_inq *); 166 int ami_vol(struct ami_softc *, struct bioc_vol *, 167 struct ami_big_diskarray *); 168 int ami_disk(struct ami_softc *, struct bioc_disk *, 169 struct ami_big_diskarray *); 170 int ami_ioctl_vol(struct ami_softc *, struct bioc_vol *); 171 int ami_ioctl_disk(struct ami_softc *, struct bioc_disk *); 172 int ami_ioctl_alarm(struct ami_softc *, struct bioc_alarm *); 173 int ami_ioctl_setstate(struct ami_softc *, struct bioc_setstate *); 174 175 #ifndef SMALL_KERNEL 176 int ami_create_sensors(struct ami_softc *); 177 void ami_refresh_sensors(void *); 178 #endif 179 #endif /* NBIO > 0 */ 180 181 #define DEVNAME(_s) ((_s)->sc_dev.dv_xname) 182 183 void 184 ami_remove_runq(struct ami_ccb *ccb) 185 { 186 splassert(IPL_BIO); 187 188 TAILQ_REMOVE(&ccb->ccb_sc->sc_ccb_runq, ccb, ccb_link); 189 if (TAILQ_EMPTY(&ccb->ccb_sc->sc_ccb_runq)) { 190 ccb->ccb_sc->sc_drained = 1; 191 if (ccb->ccb_sc->sc_drainio) 192 wakeup(ccb->ccb_sc); 193 } 194 } 195 196 void 197 ami_insert_runq(struct ami_ccb *ccb) 198 { 199 splassert(IPL_BIO); 200 201 ccb->ccb_sc->sc_drained = 0; 202 TAILQ_INSERT_TAIL(&ccb->ccb_sc->sc_ccb_runq, ccb, ccb_link); 203 } 204 205 struct ami_ccb * 206 ami_get_ccb(struct ami_softc *sc) 207 { 208 struct ami_ccb *ccb; 209 210 splassert(IPL_BIO); 211 212 ccb = TAILQ_FIRST(&sc->sc_ccb_freeq); 213 if (ccb) { 214 TAILQ_REMOVE(&sc->sc_ccb_freeq, ccb, ccb_link); 215 ccb->ccb_state = AMI_CCB_READY; 216 } 217 218 return (ccb); 219 } 220 221 void 222 ami_put_ccb(struct ami_ccb *ccb) 223 { 224 struct ami_softc *sc = ccb->ccb_sc; 225 226 splassert(IPL_BIO); 227 228 ccb->ccb_state = AMI_CCB_FREE; 229 ccb->ccb_xs = NULL; 230 ccb->ccb_flags = 0; 231 ccb->ccb_done = NULL; 232 TAILQ_INSERT_TAIL(&sc->sc_ccb_freeq, ccb, ccb_link); 233 } 234 235 u_int32_t 236 ami_read(struct ami_softc *sc, bus_size_t r) 237 { 238 u_int32_t rv; 239 240 bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, 4, 241 BUS_SPACE_BARRIER_READ); 242 rv = bus_space_read_4(sc->sc_iot, sc->sc_ioh, r); 243 244 AMI_DPRINTF(AMI_D_CMD, ("ari 0x%x 0x08%x ", r, rv)); 245 return (rv); 246 } 247 248 void 249 ami_write(struct ami_softc *sc, bus_size_t r, u_int32_t v) 250 { 251 AMI_DPRINTF(AMI_D_CMD, ("awo 0x%x 0x%08x ", r, v)); 252 253 bus_space_write_4(sc->sc_iot, sc->sc_ioh, r, v); 254 bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, 4, 255 BUS_SPACE_BARRIER_WRITE); 256 } 257 258 struct ami_mem * 259 ami_allocmem(struct ami_softc *sc, size_t size) 260 { 261 struct ami_mem *am; 262 int nsegs; 263 264 am = malloc(sizeof(struct ami_mem), M_DEVBUF, M_NOWAIT|M_ZERO); 265 if (am == NULL) 266 return (NULL); 267 268 am->am_size = size; 269 270 if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, 271 BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &am->am_map) != 0) 272 goto amfree; 273 274 if (bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &am->am_seg, 1, 275 &nsegs, BUS_DMA_NOWAIT) != 0) 276 goto destroy; 277 278 if (bus_dmamem_map(sc->sc_dmat, &am->am_seg, nsegs, size, &am->am_kva, 279 BUS_DMA_NOWAIT) != 0) 280 goto free; 281 282 if (bus_dmamap_load(sc->sc_dmat, am->am_map, am->am_kva, size, NULL, 283 BUS_DMA_NOWAIT) != 0) 284 goto unmap; 285 286 memset(am->am_kva, 0, size); 287 return (am); 288 289 unmap: 290 bus_dmamem_unmap(sc->sc_dmat, am->am_kva, size); 291 free: 292 bus_dmamem_free(sc->sc_dmat, &am->am_seg, 1); 293 destroy: 294 bus_dmamap_destroy(sc->sc_dmat, am->am_map); 295 amfree: 296 free(am, M_DEVBUF); 297 298 return (NULL); 299 } 300 301 void 302 ami_freemem(struct ami_softc *sc, struct ami_mem *am) 303 { 304 bus_dmamap_unload(sc->sc_dmat, am->am_map); 305 bus_dmamem_unmap(sc->sc_dmat, am->am_kva, am->am_size); 306 bus_dmamem_free(sc->sc_dmat, &am->am_seg, 1); 307 bus_dmamap_destroy(sc->sc_dmat, am->am_map); 308 free(am, M_DEVBUF); 309 } 310 311 void 312 ami_copyhds(struct ami_softc *sc, const u_int32_t *sizes, 313 const u_int8_t *props, const u_int8_t *stats) 314 { 315 int i; 316 317 for (i = 0; i < sc->sc_nunits; i++) { 318 sc->sc_hdr[i].hd_present = 1; 319 sc->sc_hdr[i].hd_is_logdrv = 1; 320 sc->sc_hdr[i].hd_size = letoh32(sizes[i]); 321 sc->sc_hdr[i].hd_prop = props[i]; 322 sc->sc_hdr[i].hd_stat = stats[i]; 323 } 324 } 325 326 int 327 ami_alloc_ccbs(struct ami_softc *sc, int nccbs) 328 { 329 struct ami_ccb *ccb; 330 struct ami_ccbmem *ccbmem, *mem; 331 int i, s, error; 332 333 sc->sc_ccbs = malloc(sizeof(struct ami_ccb) * nccbs, 334 M_DEVBUF, M_NOWAIT); 335 if (sc->sc_ccbs == NULL) { 336 printf(": unable to allocate ccbs\n"); 337 return (1); 338 } 339 340 sc->sc_ccbmem_am = ami_allocmem(sc, sizeof(struct ami_ccbmem) * nccbs); 341 if (sc->sc_ccbmem_am == NULL) { 342 printf(": unable to allocate ccb dmamem\n"); 343 goto free_ccbs; 344 } 345 ccbmem = AMIMEM_KVA(sc->sc_ccbmem_am); 346 347 TAILQ_INIT(&sc->sc_ccb_freeq); 348 TAILQ_INIT(&sc->sc_ccb_preq); 349 TAILQ_INIT(&sc->sc_ccb_runq); 350 timeout_set(&sc->sc_run_tmo, ami_runqueue_tick, sc); 351 352 for (i = 0; i < nccbs; i++) { 353 ccb = &sc->sc_ccbs[i]; 354 mem = &ccbmem[i]; 355 356 error = bus_dmamap_create(sc->sc_dmat, AMI_MAXFER, 357 AMI_MAXOFFSETS, AMI_MAXFER, 0, 358 BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &ccb->ccb_dmamap); 359 if (error) { 360 printf(": cannot create ccb dmamap (%d)\n", error); 361 goto free_list; 362 } 363 364 ccb->ccb_sc = sc; 365 366 ccb->ccb_cmd.acc_id = i + 1; 367 ccb->ccb_offset = sizeof(struct ami_ccbmem) * i; 368 369 ccb->ccb_pt = &mem->cd_pt; 370 ccb->ccb_ptpa = htole32(AMIMEM_DVA(sc->sc_ccbmem_am) + 371 ccb->ccb_offset); 372 373 ccb->ccb_sglist = mem->cd_sg; 374 ccb->ccb_sglistpa = htole32(AMIMEM_DVA(sc->sc_ccbmem_am) + 375 ccb->ccb_offset + sizeof(struct ami_passthrough)); 376 377 /* override last command for management */ 378 if (i == nccbs - 1) { 379 ccb->ccb_cmd.acc_id = 0xfe; 380 sc->sc_mgmtccb = ccb; 381 } else { 382 s = splbio(); 383 ami_put_ccb(ccb); 384 splx(s); 385 } 386 } 387 388 return (0); 389 390 free_list: 391 while ((ccb = ami_get_ccb(sc)) != NULL) 392 bus_dmamap_destroy(sc->sc_dmat, ccb->ccb_dmamap); 393 394 ami_freemem(sc, sc->sc_ccbmem_am); 395 free_ccbs: 396 free(sc->sc_ccbs, M_DEVBUF); 397 398 return (1); 399 } 400 401 int 402 ami_attach(struct ami_softc *sc) 403 { 404 struct scsibus_attach_args saa; 405 struct ami_rawsoftc *rsc; 406 struct ami_ccb iccb; 407 struct ami_iocmd *cmd; 408 struct ami_mem *am; 409 struct ami_inquiry *inq; 410 struct ami_fc_einquiry *einq; 411 struct ami_fc_prodinfo *pi; 412 const char *p; 413 paddr_t pa; 414 int s; 415 416 am = ami_allocmem(sc, NBPG); 417 if (am == NULL) { 418 printf(": unable to allocate init data\n"); 419 return (1); 420 } 421 pa = htole32(AMIMEM_DVA(am)); 422 423 sc->sc_mbox_am = ami_allocmem(sc, sizeof(struct ami_iocmd)); 424 if (sc->sc_mbox_am == NULL) { 425 printf(": unable to allocate mbox\n"); 426 goto free_idata; 427 } 428 sc->sc_mbox = (volatile struct ami_iocmd *)AMIMEM_KVA(sc->sc_mbox_am); 429 sc->sc_mbox_pa = htole32(AMIMEM_DVA(sc->sc_mbox_am)); 430 AMI_DPRINTF(AMI_D_CMD, ("mbox=%p ", sc->sc_mbox)); 431 AMI_DPRINTF(AMI_D_CMD, ("mbox_pa=0x%llx ", (long long)sc->sc_mbox_pa)); 432 433 /* create a spartan ccb for use with ami_poll */ 434 bzero(&iccb, sizeof(iccb)); 435 iccb.ccb_sc = sc; 436 iccb.ccb_done = ami_done_init; 437 cmd = &iccb.ccb_cmd; 438 439 (sc->sc_init)(sc); 440 441 s = splbio(); 442 443 /* try FC inquiry first */ 444 cmd->acc_cmd = AMI_FCOP; 445 cmd->acc_io.aio_channel = AMI_FC_EINQ3; 446 cmd->acc_io.aio_param = AMI_FC_EINQ3_SOLICITED_FULL; 447 cmd->acc_io.aio_data = pa; 448 if (ami_poll(sc, &iccb) == 0) { 449 einq = AMIMEM_KVA(am); 450 pi = AMIMEM_KVA(am); 451 452 sc->sc_nunits = einq->ain_nlogdrv; 453 sc->sc_drvinscnt = einq->ain_drvinscnt + 1; /* force scan */ 454 ami_copyhds(sc, einq->ain_ldsize, einq->ain_ldprop, 455 einq->ain_ldstat); 456 457 cmd->acc_cmd = AMI_FCOP; 458 cmd->acc_io.aio_channel = AMI_FC_PRODINF; 459 cmd->acc_io.aio_param = 0; 460 cmd->acc_io.aio_data = pa; 461 if (ami_poll(sc, &iccb) == 0) { 462 sc->sc_maxunits = AMI_BIG_MAX_LDRIVES; 463 464 bcopy (pi->api_fwver, sc->sc_fwver, 16); 465 sc->sc_fwver[15] = '\0'; 466 bcopy (pi->api_biosver, sc->sc_biosver, 16); 467 sc->sc_biosver[15] = '\0'; 468 sc->sc_channels = pi->api_channels; 469 sc->sc_targets = pi->api_fcloops; 470 sc->sc_memory = letoh16(pi->api_ramsize); 471 sc->sc_maxcmds = pi->api_maxcmd; 472 p = "FC loop"; 473 } 474 } 475 476 if (sc->sc_maxunits == 0) { 477 inq = AMIMEM_KVA(am); 478 479 cmd->acc_cmd = AMI_EINQUIRY; 480 cmd->acc_io.aio_channel = 0; 481 cmd->acc_io.aio_param = 0; 482 cmd->acc_io.aio_data = pa; 483 if (ami_poll(sc, &iccb) != 0) { 484 cmd->acc_cmd = AMI_INQUIRY; 485 cmd->acc_io.aio_channel = 0; 486 cmd->acc_io.aio_param = 0; 487 cmd->acc_io.aio_data = pa; 488 if (ami_poll(sc, &iccb) != 0) { 489 splx(s); 490 printf(": cannot do inquiry\n"); 491 goto free_mbox; 492 } 493 } 494 495 sc->sc_maxunits = AMI_MAX_LDRIVES; 496 sc->sc_nunits = inq->ain_nlogdrv; 497 ami_copyhds(sc, inq->ain_ldsize, inq->ain_ldprop, 498 inq->ain_ldstat); 499 500 bcopy (inq->ain_fwver, sc->sc_fwver, 4); 501 sc->sc_fwver[4] = '\0'; 502 bcopy (inq->ain_biosver, sc->sc_biosver, 4); 503 sc->sc_biosver[4] = '\0'; 504 sc->sc_channels = inq->ain_channels; 505 sc->sc_targets = inq->ain_targets; 506 sc->sc_memory = inq->ain_ramsize; 507 sc->sc_maxcmds = inq->ain_maxcmd; 508 sc->sc_drvinscnt = inq->ain_drvinscnt + 1; /* force scan */ 509 p = "target"; 510 } 511 512 if (sc->sc_flags & AMI_BROKEN) { 513 sc->sc_link.openings = 1; 514 sc->sc_maxcmds = 1; 515 sc->sc_maxunits = 1; 516 } else { 517 sc->sc_maxunits = AMI_BIG_MAX_LDRIVES; 518 if (sc->sc_maxcmds > AMI_MAXCMDS) 519 sc->sc_maxcmds = AMI_MAXCMDS; 520 /* 521 * Reserve ccb's for ioctl's and raw commands to 522 * processors/enclosures by lowering the number of 523 * openings available for logical units. 524 */ 525 sc->sc_maxcmds -= AMI_MAXIOCTLCMDS + AMI_MAXPROCS * 526 AMI_MAXRAWCMDS * sc->sc_channels; 527 528 if (sc->sc_nunits) 529 sc->sc_link.openings = 530 sc->sc_maxcmds / sc->sc_nunits; 531 else 532 sc->sc_link.openings = sc->sc_maxcmds; 533 } 534 535 splx(s); 536 537 ami_freemem(sc, am); 538 539 if (ami_alloc_ccbs(sc, AMI_MAXCMDS + 1) != 0) { 540 /* error already printed */ 541 goto free_mbox; 542 } 543 sc->sc_drained = 1; 544 545 /* hack for hp netraid version encoding */ 546 if ('A' <= sc->sc_fwver[2] && sc->sc_fwver[2] <= 'Z' && 547 sc->sc_fwver[1] < ' ' && sc->sc_fwver[0] < ' ' && 548 'A' <= sc->sc_biosver[2] && sc->sc_biosver[2] <= 'Z' && 549 sc->sc_biosver[1] < ' ' && sc->sc_biosver[0] < ' ') { 550 551 snprintf(sc->sc_fwver, sizeof sc->sc_fwver, "%c.%02d.%02d", 552 sc->sc_fwver[2], sc->sc_fwver[1], sc->sc_fwver[0]); 553 snprintf(sc->sc_biosver, sizeof sc->sc_biosver, "%c.%02d.%02d", 554 sc->sc_biosver[2], sc->sc_biosver[1], sc->sc_biosver[0]); 555 } 556 557 /* TODO: fetch & print cache strategy */ 558 /* TODO: fetch & print scsi and raid info */ 559 560 sc->sc_link.device = &ami_dev; 561 sc->sc_link.adapter_softc = sc; 562 sc->sc_link.adapter = &ami_switch; 563 sc->sc_link.adapter_target = sc->sc_maxunits; 564 sc->sc_link.adapter_buswidth = sc->sc_maxunits; 565 566 #ifdef AMI_DEBUG 567 printf(", FW %s, BIOS v%s, %dMB RAM\n" 568 "%s: %d channels, %d %ss, %d logical drives, " 569 "openings %d, max commands %d, quirks: %04x\n", 570 sc->sc_fwver, sc->sc_biosver, sc->sc_memory, DEVNAME(sc), 571 sc->sc_channels, sc->sc_targets, p, sc->sc_nunits, 572 sc->sc_link.openings, sc->sc_maxcmds, sc->sc_flags); 573 #else 574 printf(", FW %s, BIOS v%s, %dMB RAM\n" 575 "%s: %d channels, %d %ss, %d logical drives\n", 576 sc->sc_fwver, sc->sc_biosver, sc->sc_memory, DEVNAME(sc), 577 sc->sc_channels, sc->sc_targets, p, sc->sc_nunits); 578 #endif /* AMI_DEBUG */ 579 580 if (sc->sc_flags & AMI_BROKEN && sc->sc_nunits > 1) 581 printf("%s: firmware buggy, limiting access to first logical " 582 "disk\n", DEVNAME(sc)); 583 584 /* lock around ioctl requests */ 585 rw_init(&sc->sc_lock, NULL); 586 587 bzero(&saa, sizeof(saa)); 588 saa.saa_sc_link = &sc->sc_link; 589 590 config_found(&sc->sc_dev, &saa, scsiprint); 591 592 /* can't do bioctls, sensors, or pass-through on broken devices */ 593 if (sc->sc_flags & AMI_BROKEN) 594 return (0); 595 596 #if NBIO > 0 597 if (bio_register(&sc->sc_dev, ami_ioctl) != 0) 598 printf("%s: controller registration failed\n", DEVNAME(sc)); 599 else 600 sc->sc_ioctl = ami_ioctl; 601 602 #ifndef SMALL_KERNEL 603 if (ami_create_sensors(sc) != 0) 604 printf("%s: unable to create sensors\n", DEVNAME(sc)); 605 #endif 606 #endif 607 608 rsc = malloc(sizeof(struct ami_rawsoftc) * sc->sc_channels, 609 M_DEVBUF, M_NOWAIT|M_ZERO); 610 if (!rsc) { 611 printf("%s: no memory for raw interface\n", DEVNAME(sc)); 612 return (0); 613 } 614 615 for (sc->sc_rawsoftcs = rsc; 616 rsc < &sc->sc_rawsoftcs[sc->sc_channels]; rsc++) { 617 618 rsc->sc_softc = sc; 619 rsc->sc_channel = rsc - sc->sc_rawsoftcs; 620 rsc->sc_link.device = &ami_raw_dev; 621 rsc->sc_link.openings = AMI_MAXRAWCMDS; 622 rsc->sc_link.adapter_softc = rsc; 623 rsc->sc_link.adapter = &ami_raw_switch; 624 rsc->sc_proctarget = -1; 625 /* TODO fetch it from the controller */ 626 rsc->sc_link.adapter_target = 16; 627 rsc->sc_link.adapter_buswidth = 16; 628 629 bzero(&saa, sizeof(saa)); 630 saa.saa_sc_link = &rsc->sc_link; 631 632 config_found(&sc->sc_dev, &saa, scsiprint); 633 } 634 635 return (0); 636 637 free_mbox: 638 ami_freemem(sc, sc->sc_mbox_am); 639 free_idata: 640 ami_freemem(sc, am); 641 642 return (1); 643 } 644 645 int 646 ami_quartz_init(struct ami_softc *sc) 647 { 648 ami_write(sc, AMI_QIDB, 0); 649 650 return (0); 651 } 652 653 int 654 ami_quartz_exec(struct ami_softc *sc, struct ami_iocmd *cmd) 655 { 656 if (sc->sc_mbox->acc_busy) { 657 AMI_DPRINTF(AMI_D_CMD, ("mbox_busy ")); 658 return (EBUSY); 659 } 660 661 memcpy((struct ami_iocmd *)sc->sc_mbox, cmd, 16); 662 bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_mbox_am), 0, 663 sizeof(struct ami_iocmd), BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD); 664 665 sc->sc_mbox->acc_busy = 1; 666 sc->sc_mbox->acc_poll = 0; 667 sc->sc_mbox->acc_ack = 0; 668 669 ami_write(sc, AMI_QIDB, sc->sc_mbox_pa | htole32(AMI_QIDB_EXEC)); 670 671 return (0); 672 } 673 674 int 675 ami_quartz_done(struct ami_softc *sc, struct ami_iocmd *mbox) 676 { 677 u_int32_t i, n; 678 u_int8_t nstat, status; 679 u_int8_t completed[AMI_MAXSTATACK]; 680 681 if (ami_read(sc, AMI_QODB) != AMI_QODB_READY) 682 return (0); /* nothing to do */ 683 684 ami_write(sc, AMI_QODB, AMI_QODB_READY); 685 686 /* 687 * The following sequence is not supposed to have a timeout clause 688 * since the firmware has a "guarantee" that all commands will 689 * complete. The choice is either panic or hoping for a miracle 690 * and that the IOs will complete much later. 691 */ 692 i = 0; 693 while ((nstat = sc->sc_mbox->acc_nstat) == 0xff) { 694 bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_mbox_am), 0, 695 sizeof(struct ami_iocmd), BUS_DMASYNC_POSTREAD); 696 delay(1); 697 if (i++ > 1000000) 698 return (0); /* nothing to do */ 699 } 700 sc->sc_mbox->acc_nstat = 0xff; 701 bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_mbox_am), 0, 702 sizeof(struct ami_iocmd), BUS_DMASYNC_POSTWRITE); 703 704 /* wait until fw wrote out all completions */ 705 i = 0; 706 AMI_DPRINTF(AMI_D_CMD, ("aqd %d ", nstat)); 707 for (n = 0; n < nstat; n++) { 708 bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_mbox_am), 0, 709 sizeof(struct ami_iocmd), BUS_DMASYNC_PREREAD); 710 while ((completed[n] = sc->sc_mbox->acc_cmplidl[n]) == 0xff) { 711 delay(1); 712 if (i++ > 1000000) 713 return (0); /* nothing to do */ 714 } 715 sc->sc_mbox->acc_cmplidl[n] = 0xff; 716 bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_mbox_am), 0, 717 sizeof(struct ami_iocmd), BUS_DMASYNC_POSTWRITE); 718 } 719 720 /* this should never happen, someone screwed up the completion status */ 721 if ((status = sc->sc_mbox->acc_status) == 0xff) 722 panic("%s: status 0xff from the firmware", DEVNAME(sc)); 723 724 sc->sc_mbox->acc_status = 0xff; 725 726 /* copy mailbox to temporary one and fixup other changed values */ 727 bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_mbox_am), 0, 16, 728 BUS_DMASYNC_POSTWRITE); 729 memcpy(mbox, (struct ami_iocmd *)sc->sc_mbox, 16); 730 mbox->acc_nstat = nstat; 731 mbox->acc_status = status; 732 for (n = 0; n < nstat; n++) 733 mbox->acc_cmplidl[n] = completed[n]; 734 735 /* ack interrupt */ 736 ami_write(sc, AMI_QIDB, AMI_QIDB_ACK); 737 738 return (1); /* ready to complete all IOs in acc_cmplidl */ 739 } 740 741 int 742 ami_quartz_poll(struct ami_softc *sc, struct ami_iocmd *cmd) 743 { 744 /* struct scsi_xfer *xs = ccb->ccb_xs; */ 745 u_int32_t i; 746 u_int8_t status; 747 748 splassert(IPL_BIO); 749 750 if (sc->sc_dis_poll) 751 return (-1); /* fail */ 752 753 i = 0; 754 while (sc->sc_mbox->acc_busy && (i < AMI_MAX_BUSYWAIT)) { 755 delay(1); 756 i++; 757 } 758 if (sc->sc_mbox->acc_busy) { 759 AMI_DPRINTF(AMI_D_CMD, ("mbox_busy ")); 760 return (-1); 761 } 762 763 memcpy((struct ami_iocmd *)sc->sc_mbox, cmd, 16); 764 bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_mbox_am), 0, 16, 765 BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD); 766 767 sc->sc_mbox->acc_id = 0xfe; 768 sc->sc_mbox->acc_busy = 1; 769 sc->sc_mbox->acc_poll = 0; 770 sc->sc_mbox->acc_ack = 0; 771 sc->sc_mbox->acc_nstat = 0xff; 772 sc->sc_mbox->acc_status = 0xff; 773 774 /* send command to firmware */ 775 ami_write(sc, AMI_QIDB, sc->sc_mbox_pa | htole32(AMI_QIDB_EXEC)); 776 777 i = 0; 778 while ((sc->sc_mbox->acc_nstat == 0xff) && (i < AMI_MAX_POLLWAIT)) { 779 delay(1); 780 i++; 781 } 782 if (i >= AMI_MAX_POLLWAIT) { 783 printf("%s: command not accepted, polling disabled\n", 784 DEVNAME(sc)); 785 sc->sc_dis_poll = 1; 786 return (-1); 787 } 788 789 /* poll firmware */ 790 i = 0; 791 while ((sc->sc_mbox->acc_poll != 0x77) && (i < AMI_MAX_POLLWAIT)) { 792 delay(1); 793 i++; 794 } 795 if (i >= AMI_MAX_POLLWAIT) { 796 printf("%s: firmware didn't reply, polling disabled\n", 797 DEVNAME(sc)); 798 sc->sc_dis_poll = 1; 799 return (-1); 800 } 801 802 /* ack */ 803 ami_write(sc, AMI_QIDB, sc->sc_mbox_pa | htole32(AMI_QIDB_ACK)); 804 805 i = 0; 806 while((ami_read(sc, AMI_QIDB) & AMI_QIDB_ACK) && 807 (i < AMI_MAX_POLLWAIT)) { 808 delay(1); 809 i++; 810 } 811 if (i >= AMI_MAX_POLLWAIT) { 812 printf("%s: firmware didn't ack the ack, polling disabled\n", 813 DEVNAME(sc)); 814 sc->sc_dis_poll = 1; 815 return (-1); 816 } 817 818 sc->sc_mbox->acc_poll = 0; 819 sc->sc_mbox->acc_ack = 0x77; 820 status = sc->sc_mbox->acc_status; 821 sc->sc_mbox->acc_nstat = 0xff; 822 sc->sc_mbox->acc_status = 0xff; 823 824 for (i = 0; i < AMI_MAXSTATACK; i++) 825 sc->sc_mbox->acc_cmplidl[i] = 0xff; 826 827 return (status); 828 } 829 830 int 831 ami_schwartz_init(struct ami_softc *sc) 832 { 833 u_int32_t a = (u_int32_t)sc->sc_mbox_pa; 834 835 bus_space_write_4(sc->sc_iot, sc->sc_ioh, AMI_SMBADDR, a); 836 /* XXX 40bit address ??? */ 837 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMI_SMBENA, 0); 838 839 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMI_SCMD, AMI_SCMD_ACK); 840 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMI_SIEM, AMI_SEIM_ENA | 841 bus_space_read_1(sc->sc_iot, sc->sc_ioh, AMI_SIEM)); 842 843 return (0); 844 } 845 846 int 847 ami_schwartz_exec(struct ami_softc *sc, struct ami_iocmd *cmd) 848 { 849 if (bus_space_read_1(sc->sc_iot, sc->sc_ioh, AMI_SMBSTAT) & 850 AMI_SMBST_BUSY) { 851 AMI_DPRINTF(AMI_D_CMD, ("mbox_busy ")); 852 return (EBUSY); 853 } 854 855 memcpy((struct ami_iocmd *)sc->sc_mbox, cmd, 16); 856 sc->sc_mbox->acc_busy = 1; 857 sc->sc_mbox->acc_poll = 0; 858 sc->sc_mbox->acc_ack = 0; 859 860 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMI_SCMD, AMI_SCMD_EXEC); 861 return (0); 862 } 863 864 int 865 ami_schwartz_done(struct ami_softc *sc, struct ami_iocmd *mbox) 866 { 867 u_int8_t stat; 868 869 #if 0 870 /* do not scramble the busy mailbox */ 871 if (sc->sc_mbox->acc_busy) 872 return (0); 873 #endif 874 if (bus_space_read_1(sc->sc_iot, sc->sc_ioh, AMI_SMBSTAT) & 875 AMI_SMBST_BUSY) 876 return (0); 877 878 stat = bus_space_read_1(sc->sc_iot, sc->sc_ioh, AMI_ISTAT); 879 if (stat & AMI_ISTAT_PEND) { 880 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMI_ISTAT, stat); 881 882 *mbox = *sc->sc_mbox; 883 AMI_DPRINTF(AMI_D_CMD, ("asd %d ", mbox->acc_nstat)); 884 885 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMI_SCMD, 886 AMI_SCMD_ACK); 887 888 return (1); 889 } 890 891 return (0); 892 } 893 894 int 895 ami_schwartz_poll(struct ami_softc *sc, struct ami_iocmd *mbox) 896 { 897 u_int8_t status; 898 u_int32_t i; 899 int rv; 900 901 splassert(IPL_BIO); 902 903 if (sc->sc_dis_poll) 904 return (-1); /* fail */ 905 906 for (i = 0; i < AMI_MAX_POLLWAIT; i++) { 907 if (!(bus_space_read_1(sc->sc_iot, sc->sc_ioh, AMI_SMBSTAT) & 908 AMI_SMBST_BUSY)) 909 break; 910 delay(1); 911 } 912 if (i >= AMI_MAX_POLLWAIT) { 913 AMI_DPRINTF(AMI_D_CMD, ("mbox_busy ")); 914 return (-1); 915 } 916 917 memcpy((struct ami_iocmd *)sc->sc_mbox, mbox, 16); 918 bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_mbox_am), 0, 16, 919 BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD); 920 921 sc->sc_mbox->acc_busy = 1; 922 sc->sc_mbox->acc_poll = 0; 923 sc->sc_mbox->acc_ack = 0; 924 /* send command to firmware */ 925 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMI_SCMD, AMI_SCMD_EXEC); 926 927 /* wait until no longer busy */ 928 for (i = 0; i < AMI_MAX_POLLWAIT; i++) { 929 if (!(bus_space_read_1(sc->sc_iot, sc->sc_ioh, AMI_SMBSTAT) & 930 AMI_SMBST_BUSY)) 931 break; 932 delay(1); 933 } 934 if (i >= AMI_MAX_POLLWAIT) { 935 printf("%s: command not accepted, polling disabled\n", 936 DEVNAME(sc)); 937 sc->sc_dis_poll = 1; 938 return (-1); 939 } 940 941 /* wait for interrupt bit */ 942 for (i = 0; i < AMI_MAX_POLLWAIT; i++) { 943 status = bus_space_read_1(sc->sc_iot, sc->sc_ioh, AMI_ISTAT); 944 if (status & AMI_ISTAT_PEND) 945 break; 946 delay(1); 947 } 948 if (i >= AMI_MAX_POLLWAIT) { 949 printf("%s: interrupt didn't arrive, polling disabled\n", 950 DEVNAME(sc)); 951 sc->sc_dis_poll = 1; 952 return (-1); 953 } 954 955 /* write ststus back to firmware */ 956 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMI_ISTAT, status); 957 958 /* copy mailbox and status back */ 959 bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_mbox_am), 0, 960 sizeof(struct ami_iocmd), BUS_DMASYNC_PREREAD); 961 *mbox = *sc->sc_mbox; 962 rv = sc->sc_mbox->acc_status; 963 964 /* ack interrupt */ 965 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMI_SCMD, AMI_SCMD_ACK); 966 967 return (rv); 968 } 969 970 int 971 ami_start_xs(struct ami_softc *sc, struct ami_ccb *ccb, struct scsi_xfer *xs) 972 { 973 timeout_set(&xs->stimeout, ami_stimeout, ccb); 974 975 if (xs->flags & SCSI_POLL) { 976 ami_complete(sc, ccb, xs->timeout); 977 return (COMPLETE); 978 } 979 980 /* XXX way wrong, this timeout needs to be set later */ 981 timeout_add_sec(&xs->stimeout, 61); 982 ami_start(sc, ccb); 983 984 return (SUCCESSFULLY_QUEUED); 985 } 986 987 void 988 ami_start(struct ami_softc *sc, struct ami_ccb *ccb) 989 { 990 int s; 991 992 s = splbio(); 993 ccb->ccb_state = AMI_CCB_PREQUEUED; 994 TAILQ_INSERT_TAIL(&sc->sc_ccb_preq, ccb, ccb_link); 995 ami_runqueue(sc); 996 splx(s); 997 } 998 999 void 1000 ami_runqueue_tick(void *arg) 1001 { 1002 struct ami_softc *sc = arg; 1003 int s; 1004 1005 s = splbio(); 1006 ami_runqueue(sc); 1007 splx(s); 1008 } 1009 1010 void 1011 ami_runqueue(struct ami_softc *sc) 1012 { 1013 struct ami_ccb *ccb; 1014 1015 splassert(IPL_BIO); 1016 1017 if (sc->sc_drainio) 1018 return; 1019 1020 while ((ccb = TAILQ_FIRST(&sc->sc_ccb_preq)) != NULL) { 1021 if (sc->sc_exec(sc, &ccb->ccb_cmd) != 0) { 1022 /* this is now raceable too with other incomming io */ 1023 timeout_add(&sc->sc_run_tmo, 1); 1024 break; 1025 } 1026 1027 TAILQ_REMOVE(&sc->sc_ccb_preq, ccb, ccb_link); 1028 ccb->ccb_state = AMI_CCB_QUEUED; 1029 ami_insert_runq(ccb); 1030 } 1031 } 1032 1033 int 1034 ami_poll(struct ami_softc *sc, struct ami_ccb *ccb) 1035 { 1036 int error; 1037 int s; 1038 1039 s = splbio(); 1040 error = sc->sc_poll(sc, &ccb->ccb_cmd); 1041 if (error == -1) 1042 ccb->ccb_flags |= AMI_CCB_F_ERR; 1043 1044 ccb->ccb_done(sc, ccb); 1045 splx(s); 1046 1047 return (error); 1048 } 1049 1050 void 1051 ami_complete(struct ami_softc *sc, struct ami_ccb *ccb, int timeout) 1052 { 1053 struct ami_iocmd mbox; 1054 int i = 0, j, done = 0; 1055 int s, ready; 1056 1057 s = splbio(); 1058 1059 /* 1060 * since exec will return if the mbox is busy we have to busy wait 1061 * ourselves. once its in, jam it into the runq. 1062 */ 1063 while (i < AMI_MAX_BUSYWAIT) { 1064 if (sc->sc_exec(sc, &ccb->ccb_cmd) == 0) { 1065 ccb->ccb_state = AMI_CCB_QUEUED; 1066 ami_insert_runq(ccb); 1067 break; 1068 } 1069 DELAY(1000); 1070 i++; 1071 } 1072 if (ccb->ccb_state != AMI_CCB_QUEUED) 1073 goto err; 1074 1075 /* 1076 * Override timeout for PERC3. The first command triggers a chip 1077 * reset on the QL12160 chip which causes the firmware to reload. 1078 * 30000 is slightly less than double of how long it takes for the 1079 * firmware to be up again. After the first two commands the 1080 * timeouts are as expected. 1081 */ 1082 i = 0; 1083 while (i < 30000 /* timeout */) { 1084 if (sc->sc_done(sc, &mbox) != 0) { 1085 for (j = 0; j < mbox.acc_nstat; j++) { 1086 ready = mbox.acc_cmplidl[j]; 1087 ami_done(sc, ready, mbox.acc_status); 1088 if (ready == ccb->ccb_cmd.acc_id) 1089 done = 1; 1090 } 1091 if (done) 1092 break; 1093 } 1094 1095 DELAY(1000); 1096 i++; 1097 } 1098 if (!done) { 1099 printf("%s: timeout ccb %d\n", DEVNAME(sc), 1100 ccb->ccb_cmd.acc_id); 1101 ami_remove_runq(ccb); 1102 goto err; 1103 } 1104 1105 /* start the runqueue again */ 1106 ami_runqueue(sc); 1107 1108 splx(s); 1109 1110 return; 1111 1112 err: 1113 ccb->ccb_flags |= AMI_CCB_F_ERR; 1114 ccb->ccb_state = AMI_CCB_READY; 1115 ccb->ccb_done(sc, ccb); 1116 splx(s); 1117 } 1118 1119 void 1120 ami_stimeout(void *v) 1121 { 1122 struct ami_ccb *ccb = v; 1123 struct ami_softc *sc = ccb->ccb_sc; 1124 struct ami_iocmd *cmd = &ccb->ccb_cmd; 1125 int s; 1126 1127 s = splbio(); 1128 switch (ccb->ccb_state) { 1129 case AMI_CCB_PREQUEUED: 1130 /* command never ran, cleanup is easy */ 1131 TAILQ_REMOVE(&sc->sc_ccb_preq, ccb, ccb_link); 1132 ccb->ccb_flags |= AMI_CCB_F_ERR; 1133 ccb->ccb_done(sc, ccb); 1134 break; 1135 1136 case AMI_CCB_QUEUED: 1137 /* 1138 * ccb has taken more than a minute to finish. we can't take 1139 * it off the hardware in case it finishes later, but we can 1140 * warn the user to look at what is happening. 1141 */ 1142 AMI_DPRINTF(AMI_D_CMD, ("%s: stimeout ccb %d, check volume " 1143 "state\n", DEVNAME(sc), cmd->acc_id)); 1144 break; 1145 1146 default: 1147 panic("%s: ami_stimeout(%d) botch", DEVNAME(sc), cmd->acc_id); 1148 } 1149 1150 splx(s); 1151 } 1152 1153 int 1154 ami_done(struct ami_softc *sc, int idx, int status) 1155 { 1156 struct ami_ccb *ccb = &sc->sc_ccbs[idx - 1]; 1157 1158 AMI_DPRINTF(AMI_D_CMD, ("done(%d) ", ccb->ccb_cmd.acc_id)); 1159 1160 if (ccb->ccb_state != AMI_CCB_QUEUED) { 1161 printf("%s: unqueued ccb %d ready, state = %d\n", 1162 DEVNAME(sc), idx, ccb->ccb_state); 1163 return (1); 1164 } 1165 1166 ccb->ccb_state = AMI_CCB_READY; 1167 ccb->ccb_status = status; 1168 ami_remove_runq(ccb); 1169 1170 ccb->ccb_done(sc, ccb); 1171 1172 return (0); 1173 } 1174 1175 void 1176 ami_done_pt(struct ami_softc *sc, struct ami_ccb *ccb) 1177 { 1178 struct scsi_xfer *xs = ccb->ccb_xs; 1179 struct scsi_link *link = xs->sc_link; 1180 struct ami_rawsoftc *rsc = link->adapter_softc; 1181 u_int8_t target = link->target, type; 1182 1183 bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_ccbmem_am), 1184 ccb->ccb_offset, sizeof(struct ami_ccbmem), 1185 BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1186 1187 if (xs->data != NULL) { 1188 bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap, 0, 1189 ccb->ccb_dmamap->dm_mapsize, 1190 (xs->flags & SCSI_DATA_IN) ? 1191 BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); 1192 1193 bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap); 1194 } 1195 1196 timeout_del(&xs->stimeout); 1197 xs->resid = 0; 1198 xs->flags |= ITSDONE; 1199 1200 if (ccb->ccb_flags & AMI_CCB_F_ERR) 1201 xs->error = XS_DRIVER_STUFFUP; 1202 else if (ccb->ccb_status != 0x00) 1203 xs->error = XS_DRIVER_STUFFUP; 1204 else if (xs->flags & SCSI_POLL && xs->cmd->opcode == INQUIRY) { 1205 type = ((struct scsi_inquiry_data *)xs->data)->device & 1206 SID_TYPE; 1207 if (!(type == T_PROCESSOR || type == T_ENCLOSURE)) 1208 xs->error = XS_DRIVER_STUFFUP; 1209 else 1210 rsc->sc_proctarget = target; 1211 } 1212 1213 ami_put_ccb(ccb); 1214 scsi_done(xs); 1215 } 1216 1217 void 1218 ami_done_xs(struct ami_softc *sc, struct ami_ccb *ccb) 1219 { 1220 struct scsi_xfer *xs = ccb->ccb_xs; 1221 1222 if (xs->data != NULL) { 1223 bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap, 0, 1224 ccb->ccb_dmamap->dm_mapsize, 1225 (xs->flags & SCSI_DATA_IN) ? 1226 BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); 1227 1228 bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_ccbmem_am), 1229 ccb->ccb_offset, sizeof(struct ami_ccbmem), 1230 BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1231 1232 bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap); 1233 } 1234 1235 timeout_del(&xs->stimeout); 1236 xs->resid = 0; 1237 xs->flags |= ITSDONE; 1238 1239 if (ccb->ccb_flags & AMI_CCB_F_ERR) 1240 xs->error = XS_DRIVER_STUFFUP; 1241 1242 ami_put_ccb(ccb); 1243 scsi_done(xs); 1244 } 1245 1246 void 1247 ami_done_flush(struct ami_softc *sc, struct ami_ccb *ccb) 1248 { 1249 struct scsi_xfer *xs = ccb->ccb_xs; 1250 struct ami_iocmd *cmd = &ccb->ccb_cmd; 1251 1252 timeout_del(&xs->stimeout); 1253 if (ccb->ccb_flags & AMI_CCB_F_ERR) { 1254 xs->error = XS_DRIVER_STUFFUP; 1255 xs->resid = 0; 1256 xs->flags |= ITSDONE; 1257 1258 ami_put_ccb(ccb); 1259 scsi_done(xs); 1260 return; 1261 } 1262 1263 /* reuse the ccb for the sysflush command */ 1264 ccb->ccb_done = ami_done_sysflush; 1265 cmd->acc_cmd = AMI_SYSFLUSH; 1266 1267 ami_start_xs(sc, ccb, xs); 1268 } 1269 1270 void 1271 ami_done_sysflush(struct ami_softc *sc, struct ami_ccb *ccb) 1272 { 1273 struct scsi_xfer *xs = ccb->ccb_xs; 1274 1275 timeout_del(&xs->stimeout); 1276 xs->resid = 0; 1277 xs->flags |= ITSDONE; 1278 if (ccb->ccb_flags & AMI_CCB_F_ERR) 1279 xs->error = XS_DRIVER_STUFFUP; 1280 1281 ami_put_ccb(ccb); 1282 scsi_done(xs); 1283 } 1284 1285 void 1286 ami_done_dummy(struct ami_softc *sc, struct ami_ccb *ccb) 1287 { 1288 } 1289 1290 void 1291 ami_done_ioctl(struct ami_softc *sc, struct ami_ccb *ccb) 1292 { 1293 wakeup(ccb); 1294 } 1295 1296 void 1297 ami_done_init(struct ami_softc *sc, struct ami_ccb *ccb) 1298 { 1299 /* the ccb is going to be reused, so do nothing with it */ 1300 } 1301 1302 void 1303 amiminphys(struct buf *bp, struct scsi_link *sl) 1304 { 1305 if (bp->b_bcount > AMI_MAXFER) 1306 bp->b_bcount = AMI_MAXFER; 1307 minphys(bp); 1308 } 1309 1310 void 1311 ami_copy_internal_data(struct scsi_xfer *xs, void *v, size_t size) 1312 { 1313 size_t copy_cnt; 1314 1315 AMI_DPRINTF(AMI_D_MISC, ("ami_copy_internal_data ")); 1316 1317 if (!xs->datalen) 1318 printf("uio move not yet supported\n"); 1319 else { 1320 copy_cnt = MIN(size, xs->datalen); 1321 bcopy(v, xs->data, copy_cnt); 1322 } 1323 } 1324 1325 int 1326 ami_scsi_raw_cmd(struct scsi_xfer *xs) 1327 { 1328 struct scsi_link *link = xs->sc_link; 1329 struct ami_rawsoftc *rsc = link->adapter_softc; 1330 struct ami_softc *sc = rsc->sc_softc; 1331 u_int8_t channel = rsc->sc_channel, target = link->target; 1332 struct device *dev = link->device_softc; 1333 struct ami_ccb *ccb; 1334 int s; 1335 1336 AMI_DPRINTF(AMI_D_CMD, ("ami_scsi_raw_cmd ")); 1337 1338 if (!cold && target == rsc->sc_proctarget) 1339 strlcpy(rsc->sc_procdev, dev->dv_xname, 1340 sizeof(rsc->sc_procdev)); 1341 1342 if (xs->cmdlen > AMI_MAX_CDB) { 1343 AMI_DPRINTF(AMI_D_CMD, ("CDB too big %p ", xs)); 1344 bzero(&xs->sense, sizeof(xs->sense)); 1345 xs->sense.error_code = SSD_ERRCODE_VALID | 0x70; 1346 xs->sense.flags = SKEY_ILLEGAL_REQUEST; 1347 xs->sense.add_sense_code = 0x20; /* illcmd, 0x24 illfield */ 1348 xs->error = XS_SENSE; 1349 xs->flags |= ITSDONE; 1350 s = splbio(); 1351 scsi_done(xs); 1352 splx(s); 1353 return (COMPLETE); 1354 } 1355 1356 xs->error = XS_NOERROR; 1357 1358 s = splbio(); 1359 ccb = ami_get_ccb(sc); 1360 splx(s); 1361 if (ccb == NULL) { 1362 return (NO_CCB); 1363 } 1364 1365 memset(ccb->ccb_pt, 0, sizeof(struct ami_passthrough)); 1366 1367 ccb->ccb_xs = xs; 1368 ccb->ccb_done = ami_done_pt; 1369 1370 ccb->ccb_cmd.acc_cmd = AMI_PASSTHRU; 1371 ccb->ccb_cmd.acc_passthru.apt_data = ccb->ccb_ptpa; 1372 1373 ccb->ccb_pt->apt_param = AMI_PTPARAM(AMI_TIMEOUT_6,1,0); 1374 ccb->ccb_pt->apt_channel = channel; 1375 ccb->ccb_pt->apt_target = target; 1376 bcopy(xs->cmd, ccb->ccb_pt->apt_cdb, AMI_MAX_CDB); 1377 ccb->ccb_pt->apt_ncdb = xs->cmdlen; 1378 ccb->ccb_pt->apt_nsense = AMI_MAX_SENSE; 1379 ccb->ccb_pt->apt_datalen = xs->datalen; 1380 ccb->ccb_pt->apt_data = 0; 1381 1382 if (ami_load_ptmem(sc, ccb, xs->data, xs->datalen, 1383 xs->flags & SCSI_DATA_IN, xs->flags & SCSI_NOSLEEP) != 0) { 1384 xs->error = XS_DRIVER_STUFFUP; 1385 xs->flags |= ITSDONE; 1386 s = splbio(); 1387 ami_put_ccb(ccb); 1388 scsi_done(xs); 1389 splx(s); 1390 return (COMPLETE); 1391 } 1392 1393 return (ami_start_xs(sc, ccb, xs)); 1394 } 1395 1396 int 1397 ami_load_ptmem(struct ami_softc *sc, struct ami_ccb *ccb, void *data, 1398 size_t len, int read, int nowait) 1399 { 1400 bus_dmamap_t dmap = ccb->ccb_dmamap; 1401 bus_dma_segment_t *sgd; 1402 int error, i; 1403 1404 if (data != NULL) { 1405 error = bus_dmamap_load(sc->sc_dmat, dmap, data, len, NULL, 1406 nowait ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK); 1407 if (error) { 1408 if (error == EFBIG) 1409 printf("more than %d dma segs\n", 1410 AMI_MAXOFFSETS); 1411 else 1412 printf("error %d loading dma map\n", error); 1413 1414 return (1); 1415 } 1416 1417 sgd = dmap->dm_segs; 1418 if (dmap->dm_nsegs > 1) { 1419 struct ami_sgent *sgl = ccb->ccb_sglist; 1420 1421 ccb->ccb_pt->apt_nsge = dmap->dm_nsegs; 1422 ccb->ccb_pt->apt_data = ccb->ccb_sglistpa; 1423 1424 for (i = 0; i < dmap->dm_nsegs; i++) { 1425 sgl[i].asg_addr = htole32(sgd[i].ds_addr); 1426 sgl[i].asg_len = htole32(sgd[i].ds_len); 1427 } 1428 } else { 1429 ccb->ccb_pt->apt_nsge = 0; 1430 ccb->ccb_pt->apt_data = htole32(sgd->ds_addr); 1431 } 1432 1433 bus_dmamap_sync(sc->sc_dmat, dmap, 0, dmap->dm_mapsize, 1434 read ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); 1435 } 1436 1437 bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_ccbmem_am), 1438 ccb->ccb_offset, sizeof(struct ami_ccbmem), 1439 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1440 1441 return (0); 1442 } 1443 1444 int 1445 ami_scsi_cmd(struct scsi_xfer *xs) 1446 { 1447 struct scsi_link *link = xs->sc_link; 1448 struct ami_softc *sc = link->adapter_softc; 1449 struct device *dev = link->device_softc; 1450 struct ami_ccb *ccb; 1451 struct ami_iocmd *cmd; 1452 struct scsi_inquiry_data inq; 1453 struct scsi_sense_data sd; 1454 struct scsi_read_cap_data rcd; 1455 u_int8_t target = link->target; 1456 u_int32_t blockno, blockcnt; 1457 struct scsi_rw *rw; 1458 struct scsi_rw_big *rwb; 1459 bus_dma_segment_t *sgd; 1460 int error; 1461 int s; 1462 int i; 1463 1464 AMI_DPRINTF(AMI_D_CMD, ("ami_scsi_cmd ")); 1465 1466 if (target >= sc->sc_nunits || !sc->sc_hdr[target].hd_present || 1467 link->lun != 0) { 1468 AMI_DPRINTF(AMI_D_CMD, ("no target %d ", target)); 1469 /* XXX should be XS_SENSE and sense filled out */ 1470 xs->error = XS_DRIVER_STUFFUP; 1471 xs->flags |= ITSDONE; 1472 s = splbio(); 1473 scsi_done(xs); 1474 splx(s); 1475 return (COMPLETE); 1476 } 1477 1478 error = 0; 1479 xs->error = XS_NOERROR; 1480 1481 switch (xs->cmd->opcode) { 1482 case READ_COMMAND: 1483 case READ_BIG: 1484 case WRITE_COMMAND: 1485 case WRITE_BIG: 1486 /* deal with io outside the switch */ 1487 break; 1488 1489 case SYNCHRONIZE_CACHE: 1490 s = splbio(); 1491 ccb = ami_get_ccb(sc); 1492 splx(s); 1493 if (ccb == NULL) { 1494 return (NO_CCB); 1495 } 1496 1497 ccb->ccb_xs = xs; 1498 ccb->ccb_done = ami_done_flush; 1499 if (xs->timeout < 30000) 1500 xs->timeout = 30000; /* at least 30sec */ 1501 1502 cmd = &ccb->ccb_cmd; 1503 cmd->acc_cmd = AMI_FLUSH; 1504 1505 return (ami_start_xs(sc, ccb, xs)); 1506 1507 case TEST_UNIT_READY: 1508 /* save off sd? after autoconf */ 1509 if (!cold) /* XXX bogus */ 1510 strlcpy(sc->sc_hdr[target].dev, dev->dv_xname, 1511 sizeof(sc->sc_hdr[target].dev)); 1512 case START_STOP: 1513 #if 0 1514 case VERIFY: 1515 #endif 1516 case PREVENT_ALLOW: 1517 AMI_DPRINTF(AMI_D_CMD, ("opc %d tgt %d ", xs->cmd->opcode, 1518 target)); 1519 xs->error = XS_NOERROR; 1520 xs->flags |= ITSDONE; 1521 s = splbio(); 1522 scsi_done(xs); 1523 splx(s); 1524 return (COMPLETE); 1525 1526 case REQUEST_SENSE: 1527 AMI_DPRINTF(AMI_D_CMD, ("REQUEST SENSE tgt %d ", target)); 1528 bzero(&sd, sizeof(sd)); 1529 sd.error_code = 0x70; 1530 sd.segment = 0; 1531 sd.flags = SKEY_NO_SENSE; 1532 *(u_int32_t*)sd.info = htole32(0); 1533 sd.extra_len = 0; 1534 ami_copy_internal_data(xs, &sd, sizeof(sd)); 1535 1536 xs->error = XS_NOERROR; 1537 xs->flags |= ITSDONE; 1538 s = splbio(); 1539 scsi_done(xs); 1540 splx(s); 1541 return (COMPLETE); 1542 1543 case INQUIRY: 1544 AMI_DPRINTF(AMI_D_CMD, ("INQUIRY tgt %d ", target)); 1545 bzero(&inq, sizeof(inq)); 1546 inq.device = T_DIRECT; 1547 inq.dev_qual2 = 0; 1548 inq.version = 2; 1549 inq.response_format = 2; 1550 inq.additional_length = 32; 1551 strlcpy(inq.vendor, "AMI ", sizeof(inq.vendor)); 1552 snprintf(inq.product, sizeof(inq.product), 1553 "Host drive #%02d", target); 1554 strlcpy(inq.revision, " ", sizeof(inq.revision)); 1555 ami_copy_internal_data(xs, &inq, sizeof(inq)); 1556 1557 xs->error = XS_NOERROR; 1558 xs->flags |= ITSDONE; 1559 s = splbio(); 1560 scsi_done(xs); 1561 splx(s); 1562 return (COMPLETE); 1563 1564 case READ_CAPACITY: 1565 AMI_DPRINTF(AMI_D_CMD, ("READ CAPACITY tgt %d ", target)); 1566 bzero(&rcd, sizeof(rcd)); 1567 _lto4b(sc->sc_hdr[target].hd_size - 1, rcd.addr); 1568 _lto4b(AMI_SECTOR_SIZE, rcd.length); 1569 ami_copy_internal_data(xs, &rcd, sizeof(rcd)); 1570 1571 xs->error = XS_NOERROR; 1572 xs->flags |= ITSDONE; 1573 s = splbio(); 1574 scsi_done(xs); 1575 splx(s); 1576 return (COMPLETE); 1577 1578 default: 1579 AMI_DPRINTF(AMI_D_CMD, ("unsupported scsi command %#x tgt %d ", 1580 xs->cmd->opcode, target)); 1581 1582 xs->error = XS_DRIVER_STUFFUP; 1583 xs->flags |= ITSDONE; 1584 s = splbio(); 1585 scsi_done(xs); 1586 splx(s); 1587 return (COMPLETE); 1588 } 1589 1590 /* A read or write operation. */ 1591 if (xs->cmdlen == 6) { 1592 rw = (struct scsi_rw *)xs->cmd; 1593 blockno = _3btol(rw->addr) & (SRW_TOPADDR << 16 | 0xffff); 1594 blockcnt = rw->length ? rw->length : 0x100; 1595 } else { 1596 rwb = (struct scsi_rw_big *)xs->cmd; 1597 blockno = _4btol(rwb->addr); 1598 blockcnt = _2btol(rwb->length); 1599 } 1600 1601 if (blockno >= sc->sc_hdr[target].hd_size || 1602 blockno + blockcnt > sc->sc_hdr[target].hd_size) { 1603 printf("%s: out of bounds %u-%u >= %u\n", DEVNAME(sc), 1604 blockno, blockcnt, sc->sc_hdr[target].hd_size); 1605 xs->error = XS_DRIVER_STUFFUP; 1606 xs->flags |= ITSDONE; 1607 s = splbio(); 1608 scsi_done(xs); 1609 splx(s); 1610 return (COMPLETE); 1611 } 1612 1613 s = splbio(); 1614 ccb = ami_get_ccb(sc); 1615 splx(s); 1616 if (ccb == NULL) { 1617 return (NO_CCB); 1618 } 1619 1620 ccb->ccb_xs = xs; 1621 ccb->ccb_done = ami_done_xs; 1622 1623 cmd = &ccb->ccb_cmd; 1624 cmd->acc_cmd = (xs->flags & SCSI_DATA_IN) ? AMI_READ : AMI_WRITE; 1625 cmd->acc_mbox.amb_nsect = htole16(blockcnt); 1626 cmd->acc_mbox.amb_lba = htole32(blockno); 1627 cmd->acc_mbox.amb_ldn = target; 1628 1629 error = bus_dmamap_load(sc->sc_dmat, ccb->ccb_dmamap, 1630 xs->data, xs->datalen, NULL, 1631 (xs->flags & SCSI_NOSLEEP) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK); 1632 if (error) { 1633 if (error == EFBIG) 1634 printf("more than %d dma segs\n", AMI_MAXOFFSETS); 1635 else 1636 printf("error %d loading dma map\n", error); 1637 1638 xs->error = XS_DRIVER_STUFFUP; 1639 xs->flags |= ITSDONE; 1640 s = splbio(); 1641 ami_put_ccb(ccb); 1642 scsi_done(xs); 1643 splx(s); 1644 return (COMPLETE); 1645 } 1646 1647 sgd = ccb->ccb_dmamap->dm_segs; 1648 if (ccb->ccb_dmamap->dm_nsegs > 1) { 1649 struct ami_sgent *sgl = ccb->ccb_sglist; 1650 1651 cmd->acc_mbox.amb_nsge = ccb->ccb_dmamap->dm_nsegs; 1652 cmd->acc_mbox.amb_data = ccb->ccb_sglistpa; 1653 1654 for (i = 0; i < ccb->ccb_dmamap->dm_nsegs; i++) { 1655 sgl[i].asg_addr = htole32(sgd[i].ds_addr); 1656 sgl[i].asg_len = htole32(sgd[i].ds_len); 1657 } 1658 } else { 1659 cmd->acc_mbox.amb_nsge = 0; 1660 cmd->acc_mbox.amb_data = htole32(sgd->ds_addr); 1661 } 1662 1663 bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_ccbmem_am), 1664 ccb->ccb_offset, sizeof(struct ami_ccbmem), 1665 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1666 1667 bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap, 0, 1668 ccb->ccb_dmamap->dm_mapsize, (xs->flags & SCSI_DATA_IN) ? 1669 BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); 1670 1671 return (ami_start_xs(sc, ccb, xs)); 1672 } 1673 1674 int 1675 ami_intr(void *v) 1676 { 1677 struct ami_softc *sc = v; 1678 struct ami_iocmd mbox; 1679 int i, rv = 0, ready; 1680 1681 splassert(IPL_BIO); 1682 1683 if (TAILQ_EMPTY(&sc->sc_ccb_runq)) 1684 return (0); 1685 1686 AMI_DPRINTF(AMI_D_INTR, ("intr ")); 1687 1688 while ((sc->sc_done)(sc, &mbox)) { 1689 AMI_DPRINTF(AMI_D_CMD, ("got#%d ", mbox.acc_nstat)); 1690 for (i = 0; i < mbox.acc_nstat; i++ ) { 1691 ready = mbox.acc_cmplidl[i]; 1692 AMI_DPRINTF(AMI_D_CMD, ("ready=%d ", ready)); 1693 if (!ami_done(sc, ready, mbox.acc_status)) 1694 rv |= 1; 1695 } 1696 } 1697 1698 if (rv) 1699 ami_runqueue(sc); 1700 1701 AMI_DPRINTF(AMI_D_INTR, ("exit ")); 1702 return (rv); 1703 } 1704 1705 int 1706 ami_scsi_ioctl(struct scsi_link *link, u_long cmd, caddr_t addr, int flag, 1707 struct proc *p) 1708 { 1709 struct ami_softc *sc = (struct ami_softc *)link->adapter_softc; 1710 /* struct device *dev = (struct device *)link->device_softc; */ 1711 /* u_int8_t target = link->target; */ 1712 1713 if (sc->sc_ioctl) 1714 return (sc->sc_ioctl(link->adapter_softc, cmd, addr)); 1715 else 1716 return (ENOTTY); 1717 } 1718 1719 #if NBIO > 0 1720 int 1721 ami_ioctl(struct device *dev, u_long cmd, caddr_t addr) 1722 { 1723 struct ami_softc *sc = (struct ami_softc *)dev; 1724 int error = 0; 1725 1726 AMI_DPRINTF(AMI_D_IOCTL, ("%s: ioctl ", DEVNAME(sc))); 1727 1728 if (sc->sc_flags & AMI_BROKEN) 1729 return (ENODEV); /* can't do this to broken device for now */ 1730 1731 switch (cmd) { 1732 case BIOCINQ: 1733 AMI_DPRINTF(AMI_D_IOCTL, ("inq ")); 1734 error = ami_ioctl_inq(sc, (struct bioc_inq *)addr); 1735 break; 1736 1737 case BIOCVOL: 1738 AMI_DPRINTF(AMI_D_IOCTL, ("vol ")); 1739 error = ami_ioctl_vol(sc, (struct bioc_vol *)addr); 1740 break; 1741 1742 case BIOCDISK: 1743 AMI_DPRINTF(AMI_D_IOCTL, ("disk ")); 1744 error = ami_ioctl_disk(sc, (struct bioc_disk *)addr); 1745 break; 1746 1747 case BIOCALARM: 1748 AMI_DPRINTF(AMI_D_IOCTL, ("alarm ")); 1749 error = ami_ioctl_alarm(sc, (struct bioc_alarm *)addr); 1750 break; 1751 1752 case BIOCSETSTATE: 1753 AMI_DPRINTF(AMI_D_IOCTL, ("setstate ")); 1754 error = ami_ioctl_setstate(sc, (struct bioc_setstate *)addr); 1755 break; 1756 1757 default: 1758 AMI_DPRINTF(AMI_D_IOCTL, (" invalid ioctl\n")); 1759 error = EINVAL; 1760 } 1761 1762 return (error); 1763 } 1764 1765 int 1766 ami_drv_pt(struct ami_softc *sc, u_int8_t ch, u_int8_t tg, u_int8_t *cmd, 1767 int clen, int blen, void *buf) 1768 { 1769 struct ami_ccb *ccb; 1770 struct ami_passthrough *pt; 1771 int error = 0; 1772 int s; 1773 1774 rw_enter_write(&sc->sc_lock); 1775 1776 s = splbio(); 1777 ccb = ami_get_ccb(sc); 1778 splx(s); 1779 if (ccb == NULL) { 1780 error = ENOMEM; 1781 goto err; 1782 } 1783 1784 ccb->ccb_done = ami_done_ioctl; 1785 1786 ccb->ccb_cmd.acc_cmd = AMI_PASSTHRU; 1787 ccb->ccb_cmd.acc_passthru.apt_data = ccb->ccb_ptpa; 1788 1789 pt = ccb->ccb_pt; 1790 memset(pt, 0, sizeof *pt); 1791 pt->apt_channel = ch; 1792 pt->apt_target = tg; 1793 pt->apt_ncdb = clen; 1794 pt->apt_nsense = sizeof(struct scsi_sense_data); 1795 pt->apt_datalen = blen; 1796 pt->apt_data = 0; 1797 1798 bcopy(cmd, pt->apt_cdb, clen); 1799 1800 if (ami_load_ptmem(sc, ccb, buf, blen, 1, 0) != 0) { 1801 error = ENOMEM; 1802 goto ptmemerr; 1803 } 1804 1805 ami_start(sc, ccb); 1806 1807 while (ccb->ccb_state != AMI_CCB_READY) 1808 tsleep(ccb, PRIBIO, "ami_drv_pt", 0); 1809 1810 bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap, 0, 1811 ccb->ccb_dmamap->dm_mapsize, BUS_DMASYNC_POSTREAD); 1812 bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_ccbmem_am), 1813 ccb->ccb_offset, sizeof(struct ami_ccbmem), 1814 BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1815 bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap); 1816 1817 if (ccb->ccb_flags & AMI_CCB_F_ERR) 1818 error = EIO; 1819 else if (pt->apt_scsistat != 0x00) 1820 error = EIO; 1821 1822 ptmemerr: 1823 s = splbio(); 1824 ami_put_ccb(ccb); 1825 splx(s); 1826 1827 err: 1828 rw_exit_write(&sc->sc_lock); 1829 return (error); 1830 } 1831 1832 int 1833 ami_drv_inq(struct ami_softc *sc, u_int8_t ch, u_int8_t tg, u_int8_t page, 1834 void *inqbuf) 1835 { 1836 struct scsi_inquiry_data *inq = inqbuf; 1837 u_int8_t cdb[6]; 1838 int error = 0; 1839 1840 bzero(&cdb, sizeof cdb); 1841 1842 cdb[0] = INQUIRY; 1843 cdb[1] = 0; 1844 cdb[2] = 0; 1845 cdb[3] = 0; 1846 cdb[4] = sizeof(struct scsi_inquiry_data); 1847 cdb[5] = 0; 1848 if (page != 0) { 1849 cdb[1] = SI_EVPD; 1850 cdb[2] = page; 1851 } 1852 1853 error = ami_drv_pt(sc, ch, tg, cdb, 6, sizeof *inq, inqbuf); 1854 if (error) 1855 return (error); 1856 1857 if ((inq->device & SID_TYPE) != T_DIRECT) 1858 error = EINVAL; 1859 1860 return (error); 1861 } 1862 1863 int 1864 ami_drv_readcap(struct ami_softc *sc, u_int8_t ch, u_int8_t tg, daddr64_t *sz) 1865 { 1866 struct scsi_read_cap_data rcd; 1867 struct scsi_read_cap_data_16 rcd16; 1868 u_int8_t cdb[16]; 1869 u_int32_t blksz; 1870 daddr64_t noblk; 1871 int error = 0; 1872 1873 bzero(&rcd, sizeof rcd); 1874 bzero(&cdb, sizeof cdb); 1875 cdb[0] = READ_CAPACITY; 1876 1877 error = ami_drv_pt(sc, ch, tg, cdb, 10, sizeof rcd, &rcd); 1878 if (error) 1879 return (error); 1880 1881 noblk = _4btol(rcd.addr); 1882 if (noblk == 0xffffffffllu) { 1883 /* huge disk */ 1884 bzero(&rcd16, sizeof rcd16); 1885 bzero(&cdb, sizeof cdb); 1886 cdb[0] = READ_CAPACITY_16; 1887 1888 error = ami_drv_pt(sc, ch, tg, cdb, 16, sizeof rcd16, &rcd16); 1889 if (error) 1890 return (error); 1891 1892 noblk = _8btol(rcd16.addr); 1893 blksz = _4btol(rcd16.length); 1894 } else 1895 blksz = _4btol(rcd.length); 1896 1897 if (blksz == 0) 1898 blksz = 512; 1899 *sz = noblk * blksz; 1900 1901 return (error); 1902 } 1903 1904 int 1905 ami_mgmt(struct ami_softc *sc, u_int8_t opcode, u_int8_t par1, u_int8_t par2, 1906 u_int8_t par3, size_t size, void *buffer) 1907 { 1908 struct ami_ccb *ccb; 1909 struct ami_iocmd *cmd; 1910 struct ami_mem *am = NULL; 1911 char *idata = NULL; 1912 int s, error = 0; 1913 1914 rw_enter_write(&sc->sc_lock); 1915 1916 if (opcode != AMI_CHSTATE) { 1917 s = splbio(); 1918 ccb = ami_get_ccb(sc); 1919 splx(s); 1920 if (ccb == NULL) { 1921 error = ENOMEM; 1922 goto err; 1923 } 1924 ccb->ccb_done = ami_done_ioctl; 1925 } else { 1926 ccb = sc->sc_mgmtccb; 1927 ccb->ccb_done = ami_done_dummy; 1928 } 1929 1930 if (size) { 1931 if ((am = ami_allocmem(sc, size)) == NULL) { 1932 error = ENOMEM; 1933 goto memerr; 1934 } 1935 idata = AMIMEM_KVA(am); 1936 } 1937 1938 cmd = &ccb->ccb_cmd; 1939 cmd->acc_cmd = opcode; 1940 1941 /* 1942 * some commands require data to be written to idata before sending 1943 * command to fw 1944 */ 1945 switch (opcode) { 1946 case AMI_SPEAKER: 1947 *idata = par1; 1948 break; 1949 default: 1950 cmd->acc_io.aio_channel = par1; 1951 cmd->acc_io.aio_param = par2; 1952 cmd->acc_io.aio_pad[0] = par3; 1953 break; 1954 }; 1955 1956 cmd->acc_io.aio_data = am ? htole32(AMIMEM_DVA(am)) : 0; 1957 1958 if (opcode != AMI_CHSTATE) { 1959 ami_start(sc, ccb); 1960 while (ccb->ccb_state != AMI_CCB_READY) 1961 tsleep(ccb, PRIBIO,"ami_mgmt", 0); 1962 } else { 1963 /* change state must be run with id 0xfe and MUST be polled */ 1964 sc->sc_drainio = 1; 1965 while (sc->sc_drained != 1) 1966 if (tsleep(sc, PRIBIO, "ami_mgmt_drain", hz * 60) == 1967 EWOULDBLOCK) { 1968 printf("%s: drain io timeout\n", DEVNAME(sc)); 1969 ccb->ccb_flags |= AMI_CCB_F_ERR; 1970 goto restartio; 1971 } 1972 ami_poll(sc, ccb); 1973 restartio: 1974 /* restart io */ 1975 s = splbio(); 1976 sc->sc_drainio = 0; 1977 ami_runqueue(sc); 1978 splx(s); 1979 } 1980 1981 if (ccb->ccb_flags & AMI_CCB_F_ERR) 1982 error = EIO; 1983 else if (buffer && size) 1984 memcpy(buffer, idata, size); 1985 1986 if (am) 1987 ami_freemem(sc, am); 1988 memerr: 1989 if (opcode != AMI_CHSTATE) { 1990 s = splbio(); 1991 ami_put_ccb(ccb); 1992 splx(s); 1993 } else { 1994 ccb->ccb_flags = 0; 1995 ccb->ccb_state = AMI_CCB_FREE; 1996 ccb->ccb_done = NULL; 1997 } 1998 1999 err: 2000 rw_exit_write(&sc->sc_lock); 2001 return (error); 2002 } 2003 2004 int 2005 ami_ioctl_inq(struct ami_softc *sc, struct bioc_inq *bi) 2006 { 2007 struct ami_big_diskarray *p; /* struct too large for stack */ 2008 struct scsi_inquiry_data inqbuf; 2009 struct ami_fc_einquiry einq; 2010 int ch, tg; 2011 int i, s, t, off; 2012 int error = 0, changes = 0; 2013 2014 if ((error = ami_mgmt(sc, AMI_FCOP, AMI_FC_EINQ3, 2015 AMI_FC_EINQ3_SOLICITED_FULL, 0, sizeof einq, &einq))) 2016 return (EINVAL); 2017 2018 if (einq.ain_drvinscnt == sc->sc_drvinscnt) { 2019 /* poke existing known drives to make sure they aren't gone */ 2020 for(i = 0; i < sc->sc_channels * 16; i++) { 2021 if (sc->sc_plist[i] == 0) 2022 continue; 2023 2024 ch = (i & 0xf0) >> 4; 2025 tg = i & 0x0f; 2026 if (ami_drv_inq(sc, ch, tg, 0, &inqbuf)) { 2027 /* drive is gone, force rescan */ 2028 changes = 1; 2029 break; 2030 } 2031 } 2032 if (changes == 0) { 2033 bcopy(&sc->sc_bi, bi, sizeof *bi); 2034 return (0); 2035 } 2036 } 2037 2038 sc->sc_drvinscnt = einq.ain_drvinscnt; 2039 2040 p = malloc(sizeof *p, M_DEVBUF, M_NOWAIT); 2041 if (!p) 2042 return (ENOMEM); 2043 2044 if ((error = ami_mgmt(sc, AMI_FCOP, AMI_FC_RDCONF, 0, 0, sizeof *p, 2045 p))) { 2046 error = EINVAL; 2047 goto bail; 2048 } 2049 2050 bzero(sc->sc_plist, sizeof sc->sc_plist); 2051 2052 bi->bi_novol = p->ada_nld; 2053 bi->bi_nodisk = 0; 2054 strlcpy(bi->bi_dev, DEVNAME(sc), sizeof(bi->bi_dev)); 2055 2056 /* count used disks, including failed ones */ 2057 for (i = 0; i < p->ada_nld; i++) 2058 for (s = 0; s < p->ald[i].adl_spandepth; s++) 2059 for (t = 0; t < p->ald[i].adl_nstripes; t++) { 2060 off = p->ald[i].asp[s].adv[t].add_channel * 2061 AMI_MAX_TARGET + 2062 p->ald[i].asp[s].adv[t].add_target; 2063 2064 /* account for multi raid vol on same disk */ 2065 if (!sc->sc_plist[off]) { 2066 sc->sc_plist[off] = 1; 2067 bi->bi_nodisk++; 2068 } 2069 } 2070 2071 /* count unsued disks */ 2072 for(i = 0; i < sc->sc_channels * 16; i++) { 2073 if (sc->sc_plist[i]) 2074 continue; /* skip claimed drives */ 2075 2076 /* 2077 * hack to invalidate device type, needed for initiator id 2078 * on an unconnected channel. 2079 * XXX find out if we can determine this differently 2080 */ 2081 memset(&inqbuf, 0xff, sizeof inqbuf); 2082 2083 ch = (i & 0xf0) >> 4; 2084 tg = i & 0x0f; 2085 if (!ami_drv_inq(sc, ch, tg, 0, &inqbuf)) { 2086 if ((inqbuf.device & SID_TYPE) != T_DIRECT) 2087 continue; 2088 bi->bi_novol++; 2089 bi->bi_nodisk++; 2090 sc->sc_plist[i] = 2; 2091 } else 2092 sc->sc_plist[i] = 0; 2093 } 2094 2095 bcopy(bi, &sc->sc_bi, sizeof sc->sc_bi); 2096 error = 0; 2097 bail: 2098 free(p, M_DEVBUF); 2099 return (error); 2100 } 2101 2102 int 2103 ami_vol(struct ami_softc *sc, struct bioc_vol *bv, struct ami_big_diskarray *p) 2104 { 2105 int i, ld = p->ada_nld, error = EINVAL; 2106 2107 for(i = 0; i < sc->sc_channels * 16; i++) { 2108 /* skip claimed/unused drives */ 2109 if (sc->sc_plist[i] != 2) 2110 continue; 2111 2112 /* are we it? */ 2113 if (ld != bv->bv_volid) { 2114 ld++; 2115 continue; 2116 } 2117 2118 bv->bv_status = BIOC_SVONLINE; 2119 bv->bv_size = (u_quad_t)p->apd[i].adp_size * 2120 (u_quad_t)512; 2121 bv->bv_nodisk = 1; 2122 strlcpy(bv->bv_dev, 2123 sc->sc_hdr[bv->bv_volid].dev, 2124 sizeof(bv->bv_dev)); 2125 2126 if (p->apd[i].adp_ostatus == AMI_PD_HOTSPARE 2127 && p->apd[i].adp_type == 0) 2128 bv->bv_level = -1; 2129 else 2130 bv->bv_level = -2; 2131 2132 error = 0; 2133 goto bail; 2134 } 2135 2136 bail: 2137 return (error); 2138 } 2139 2140 int 2141 ami_disk(struct ami_softc *sc, struct bioc_disk *bd, 2142 struct ami_big_diskarray *p) 2143 { 2144 char vend[8+16+4+1]; 2145 char ser[32 + 1]; 2146 struct scsi_inquiry_data inqbuf; 2147 struct scsi_vpd_serial vpdbuf; 2148 int i, ld = p->ada_nld, error = EINVAL; 2149 u_int8_t ch, tg; 2150 daddr64_t sz = 0; 2151 2152 for(i = 0; i < sc->sc_channels * 16; i++) { 2153 /* skip claimed/unused drives */ 2154 if (sc->sc_plist[i] != 2) 2155 continue; 2156 2157 /* are we it? */ 2158 if (ld != bd->bd_volid) { 2159 ld++; 2160 continue; 2161 } 2162 2163 ch = (i & 0xf0) >> 4; 2164 tg = i & 0x0f; 2165 if (ami_drv_inq(sc, ch, tg, 0, &inqbuf)) 2166 goto bail; 2167 2168 bcopy(inqbuf.vendor, vend, sizeof vend - 1); 2169 2170 vend[sizeof vend - 1] = '\0'; 2171 strlcpy(bd->bd_vendor, vend, sizeof(bd->bd_vendor)); 2172 2173 if (!ami_drv_inq(sc, ch, tg, 0x80, &vpdbuf)) { 2174 bcopy(vpdbuf.serial, ser, sizeof ser - 1); 2175 ser[sizeof ser - 1] = '\0'; 2176 if (vpdbuf.hdr.page_length < sizeof ser) 2177 ser[vpdbuf.hdr.page_length] = '\0'; 2178 strlcpy(bd->bd_serial, ser, sizeof(bd->bd_serial)); 2179 } 2180 2181 error = ami_drv_readcap(sc, ch, tg, &sz); 2182 if (error) 2183 goto bail; 2184 2185 bd->bd_size = sz; 2186 bd->bd_channel = ch; 2187 bd->bd_target = tg; 2188 2189 strlcpy(bd->bd_procdev, sc->sc_rawsoftcs[ch].sc_procdev, 2190 sizeof(bd->bd_procdev)); 2191 2192 if (p->apd[i].adp_ostatus == AMI_PD_HOTSPARE) 2193 bd->bd_status = BIOC_SDHOTSPARE; 2194 else 2195 bd->bd_status = BIOC_SDUNUSED; 2196 2197 #ifdef AMI_DEBUG 2198 if (p->apd[i].adp_type != 0) 2199 printf("invalid disk type: %d %d %x inquiry type: %x\n", 2200 ch, tg, p->apd[i].adp_type, inqbuf.device); 2201 #endif /* AMI_DEBUG */ 2202 2203 error = 0; 2204 goto bail; 2205 } 2206 2207 bail: 2208 return (error); 2209 } 2210 2211 int 2212 ami_ioctl_vol(struct ami_softc *sc, struct bioc_vol *bv) 2213 { 2214 struct ami_big_diskarray *p; /* struct too large for stack */ 2215 int i, s, t, off; 2216 int error = 0; 2217 struct ami_progress perc; 2218 u_int8_t bgi[5]; /* 40 LD, 1 bit per LD if BGI is active */ 2219 2220 p = malloc(sizeof *p, M_DEVBUF, M_NOWAIT); 2221 if (!p) 2222 return (ENOMEM); 2223 2224 if ((error = ami_mgmt(sc, AMI_FCOP, AMI_FC_RDCONF, 0, 0, sizeof *p, p))) 2225 goto bail; 2226 2227 if (bv->bv_volid >= p->ada_nld) { 2228 error = ami_vol(sc, bv, p); 2229 goto bail; 2230 } 2231 2232 i = bv->bv_volid; 2233 2234 switch (p->ald[i].adl_status) { 2235 case AMI_RDRV_OFFLINE: 2236 bv->bv_status = BIOC_SVOFFLINE; 2237 break; 2238 2239 case AMI_RDRV_DEGRADED: 2240 bv->bv_status = BIOC_SVDEGRADED; 2241 break; 2242 2243 case AMI_RDRV_OPTIMAL: 2244 bv->bv_status = BIOC_SVONLINE; 2245 bv->bv_percent = -1; 2246 2247 /* get BGI progress here and over-ride status if so */ 2248 memset(bgi, 0, sizeof bgi); 2249 if (ami_mgmt(sc, AMI_MISC, AMI_GET_BGI, 0, 0, sizeof bgi, &bgi)) 2250 break; 2251 2252 if ((bgi[i / 8] & (1 << i % 8)) == 0) 2253 break; 2254 2255 if (!ami_mgmt(sc, AMI_GCHECKPROGR, i, 0, 0, sizeof perc, &perc)) 2256 if (perc.apr_progress < 100) { 2257 bv->bv_status = BIOC_SVSCRUB; 2258 bv->bv_percent = perc.apr_progress >= 100 ? -1 : 2259 perc.apr_progress; 2260 } 2261 break; 2262 2263 default: 2264 bv->bv_status = BIOC_SVINVALID; 2265 } 2266 2267 /* over-ride status if a pd is in rebuild status for this ld */ 2268 for (s = 0; s < p->ald[i].adl_spandepth; s++) 2269 for (t = 0; t < p->ald[i].adl_nstripes; t++) { 2270 off = p->ald[i].asp[s].adv[t].add_channel * 2271 AMI_MAX_TARGET + 2272 p->ald[i].asp[s].adv[t].add_target; 2273 2274 if (p->apd[off].adp_ostatus != AMI_PD_RBLD) 2275 continue; 2276 2277 /* get rebuild progress from pd 0 */ 2278 bv->bv_status = BIOC_SVREBUILD; 2279 if (ami_mgmt(sc, AMI_GRBLDPROGR, 2280 p->ald[i].asp[s].adv[t].add_channel, 2281 p->ald[i].asp[s].adv[t].add_target, 0, 2282 sizeof perc, &perc)) 2283 bv->bv_percent = -1; 2284 else 2285 bv->bv_percent = perc.apr_progress >= 100 ? -1 : 2286 perc.apr_progress; 2287 break; 2288 } 2289 2290 bv->bv_size = 0; 2291 bv->bv_level = p->ald[i].adl_raidlvl; 2292 bv->bv_nodisk = 0; 2293 2294 for (s = 0; s < p->ald[i].adl_spandepth; s++) { 2295 for (t = 0; t < p->ald[i].adl_nstripes; t++) 2296 bv->bv_nodisk++; 2297 2298 switch (bv->bv_level) { 2299 case 0: 2300 bv->bv_size += p->ald[i].asp[s].ads_length * 2301 p->ald[i].adl_nstripes; 2302 break; 2303 2304 case 1: 2305 bv->bv_size += p->ald[i].asp[s].ads_length; 2306 break; 2307 2308 case 5: 2309 bv->bv_size += p->ald[i].asp[s].ads_length * 2310 (p->ald[i].adl_nstripes - 1); 2311 break; 2312 } 2313 } 2314 2315 if (p->ald[i].adl_spandepth > 1) 2316 bv->bv_level *= 10; 2317 2318 bv->bv_size *= (u_quad_t)512; 2319 2320 strlcpy(bv->bv_dev, sc->sc_hdr[i].dev, sizeof(bv->bv_dev)); 2321 2322 bail: 2323 free(p, M_DEVBUF); 2324 2325 return (error); 2326 } 2327 2328 int 2329 ami_ioctl_disk(struct ami_softc *sc, struct bioc_disk *bd) 2330 { 2331 struct scsi_inquiry_data inqbuf; 2332 struct scsi_vpd_serial vpdbuf; 2333 struct ami_big_diskarray *p; /* struct too large for stack */ 2334 int i, s, t, d; 2335 int off; 2336 int error = EINVAL; 2337 u_int16_t ch, tg; 2338 char vend[8+16+4+1]; 2339 char ser[32 + 1]; 2340 2341 p = malloc(sizeof *p, M_DEVBUF, M_NOWAIT); 2342 if (!p) 2343 return (ENOMEM); 2344 2345 if ((error = ami_mgmt(sc, AMI_FCOP, AMI_FC_RDCONF, 0, 0, sizeof *p, p))) 2346 goto bail; 2347 2348 if (bd->bd_volid >= p->ada_nld) { 2349 error = ami_disk(sc, bd, p); 2350 goto bail; 2351 } 2352 2353 i = bd->bd_volid; 2354 for (s = 0, d = 0; s < p->ald[i].adl_spandepth; s++) 2355 for (t = 0; t < p->ald[i].adl_nstripes; t++) { 2356 if (d != bd->bd_diskid) { 2357 d++; 2358 continue; 2359 } 2360 2361 off = p->ald[i].asp[s].adv[t].add_channel * 2362 AMI_MAX_TARGET + 2363 p->ald[i].asp[s].adv[t].add_target; 2364 2365 bd->bd_size = (u_quad_t)p->apd[off].adp_size * 2366 (u_quad_t)512; 2367 2368 switch (p->apd[off].adp_ostatus) { 2369 case AMI_PD_UNCNF: 2370 bd->bd_status = BIOC_SDUNUSED; 2371 break; 2372 2373 case AMI_PD_ONLINE: 2374 bd->bd_status = BIOC_SDONLINE; 2375 break; 2376 2377 case AMI_PD_FAILED: 2378 bd->bd_status = BIOC_SDFAILED; 2379 bd->bd_size = 0; 2380 break; 2381 2382 case AMI_PD_RBLD: 2383 bd->bd_status = BIOC_SDREBUILD; 2384 break; 2385 2386 case AMI_PD_HOTSPARE: 2387 bd->bd_status = BIOC_SDHOTSPARE; 2388 break; 2389 2390 default: 2391 bd->bd_status = BIOC_SDINVALID; 2392 bd->bd_size = 0; 2393 } 2394 2395 2396 ch = p->ald[i].asp[s].adv[t].add_target >> 4; 2397 tg = p->ald[i].asp[s].adv[t].add_target & 0x0f; 2398 2399 bd->bd_channel = ch; 2400 bd->bd_target = tg; 2401 strlcpy(bd->bd_procdev, sc->sc_rawsoftcs[ch].sc_procdev, 2402 sizeof(bd->bd_procdev)); 2403 2404 /* if we are failed don't query drive */ 2405 if (bd->bd_size == 0) { 2406 bzero(&bd->bd_vendor, sizeof(bd->bd_vendor)); 2407 bzero(&bd->bd_serial, sizeof(bd->bd_serial)); 2408 goto done; 2409 } 2410 2411 if (!ami_drv_inq(sc, ch, tg, 0, &inqbuf)) { 2412 bcopy(inqbuf.vendor, vend, sizeof vend - 1); 2413 vend[sizeof vend - 1] = '\0'; 2414 strlcpy(bd->bd_vendor, vend, 2415 sizeof(bd->bd_vendor)); 2416 } 2417 2418 if (!ami_drv_inq(sc, ch, tg, 0x80, &vpdbuf)) { 2419 bcopy(vpdbuf.serial, ser, sizeof ser - 1); 2420 ser[sizeof ser - 1] = '\0'; 2421 if (vpdbuf.hdr.page_length < sizeof ser) 2422 ser[vpdbuf.hdr.page_length] = '\0'; 2423 strlcpy(bd->bd_serial, ser, 2424 sizeof(bd->bd_serial)); 2425 } 2426 goto done; 2427 } 2428 2429 done: 2430 error = 0; 2431 bail: 2432 free(p, M_DEVBUF); 2433 2434 return (error); 2435 } 2436 2437 int ami_ioctl_alarm(struct ami_softc *sc, struct bioc_alarm *ba) 2438 { 2439 int error = 0; 2440 u_int8_t func, ret; 2441 2442 switch(ba->ba_opcode) { 2443 case BIOC_SADISABLE: 2444 func = AMI_SPKR_OFF; 2445 break; 2446 2447 case BIOC_SAENABLE: 2448 func = AMI_SPKR_ON; 2449 break; 2450 2451 case BIOC_SASILENCE: 2452 func = AMI_SPKR_SHUT; 2453 break; 2454 2455 case BIOC_GASTATUS: 2456 func = AMI_SPKR_GVAL; 2457 break; 2458 2459 case BIOC_SATEST: 2460 func = AMI_SPKR_TEST; 2461 break; 2462 2463 default: 2464 AMI_DPRINTF(AMI_D_IOCTL, ("%s: biocalarm invalid opcode %x\n", 2465 DEVNAME(sc), ba->ba_opcode)); 2466 return (EINVAL); 2467 } 2468 2469 if (!(error = ami_mgmt(sc, AMI_SPEAKER, func, 0, 0, sizeof ret, 2470 &ret))) { 2471 if (ba->ba_opcode == BIOC_GASTATUS) 2472 ba->ba_status = ret; 2473 else 2474 ba->ba_status = 0; 2475 } 2476 2477 return (error); 2478 } 2479 2480 int 2481 ami_ioctl_setstate(struct ami_softc *sc, struct bioc_setstate *bs) 2482 { 2483 struct scsi_inquiry_data inqbuf; 2484 int func, error; 2485 2486 switch (bs->bs_status) { 2487 case BIOC_SSONLINE: 2488 func = AMI_STATE_ON; 2489 break; 2490 2491 case BIOC_SSOFFLINE: 2492 func = AMI_STATE_FAIL; 2493 break; 2494 2495 case BIOC_SSHOTSPARE: 2496 if (ami_drv_inq(sc, bs->bs_channel, bs->bs_target, 0, 2497 &inqbuf)) 2498 return (EINVAL); 2499 2500 func = AMI_STATE_SPARE; 2501 break; 2502 2503 default: 2504 AMI_DPRINTF(AMI_D_IOCTL, ("%s: biocsetstate invalid opcode %x\n" 2505 , DEVNAME(sc), bs->bs_status)); 2506 return (EINVAL); 2507 } 2508 2509 if ((error = ami_mgmt(sc, AMI_CHSTATE, bs->bs_channel, bs->bs_target, 2510 func, 0, NULL))) 2511 return (error); 2512 2513 return (0); 2514 } 2515 2516 #ifndef SMALL_KERNEL 2517 int 2518 ami_create_sensors(struct ami_softc *sc) 2519 { 2520 struct device *dev; 2521 struct scsibus_softc *ssc = NULL; 2522 int i; 2523 2524 TAILQ_FOREACH(dev, &alldevs, dv_list) { 2525 if (dev->dv_parent != &sc->sc_dev) 2526 continue; 2527 2528 /* check if this is the scsibus for the logical disks */ 2529 ssc = (struct scsibus_softc *)dev; 2530 if (ssc->adapter_link == &sc->sc_link) 2531 break; 2532 } 2533 2534 if (ssc == NULL) 2535 return (1); 2536 2537 sc->sc_sensors = malloc(sizeof(struct ksensor) * sc->sc_nunits, 2538 M_DEVBUF, M_WAITOK|M_ZERO); 2539 if (sc->sc_sensors == NULL) 2540 return (1); 2541 2542 strlcpy(sc->sc_sensordev.xname, DEVNAME(sc), 2543 sizeof(sc->sc_sensordev.xname)); 2544 2545 for (i = 0; i < sc->sc_nunits; i++) { 2546 if (ssc->sc_link[i][0] == NULL) 2547 goto bad; 2548 2549 dev = ssc->sc_link[i][0]->device_softc; 2550 2551 sc->sc_sensors[i].type = SENSOR_DRIVE; 2552 sc->sc_sensors[i].status = SENSOR_S_UNKNOWN; 2553 2554 strlcpy(sc->sc_sensors[i].desc, dev->dv_xname, 2555 sizeof(sc->sc_sensors[i].desc)); 2556 2557 sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[i]); 2558 } 2559 2560 sc->sc_bd = malloc(sizeof(*sc->sc_bd), M_DEVBUF, M_WAITOK); 2561 if (sc->sc_bd == NULL) 2562 goto bad; 2563 2564 if (sensor_task_register(sc, ami_refresh_sensors, 10) == NULL) 2565 goto freebd; 2566 2567 sensordev_install(&sc->sc_sensordev); 2568 2569 return (0); 2570 2571 freebd: 2572 free(sc->sc_bd, M_DEVBUF); 2573 bad: 2574 free(sc->sc_sensors, M_DEVBUF); 2575 2576 return (1); 2577 } 2578 2579 void 2580 ami_refresh_sensors(void *arg) 2581 { 2582 struct ami_softc *sc = arg; 2583 int i; 2584 2585 if (ami_mgmt(sc, AMI_FCOP, AMI_FC_RDCONF, 0, 0, sizeof(*sc->sc_bd), 2586 sc->sc_bd)) { 2587 for (i = 0; i < sc->sc_nunits; i++) { 2588 sc->sc_sensors[i].value = 0; /* unknown */ 2589 sc->sc_sensors[i].status = SENSOR_S_UNKNOWN; 2590 } 2591 return; 2592 } 2593 2594 for (i = 0; i < sc->sc_nunits; i++) { 2595 switch (sc->sc_bd->ald[i].adl_status) { 2596 case AMI_RDRV_OFFLINE: 2597 sc->sc_sensors[i].value = SENSOR_DRIVE_FAIL; 2598 sc->sc_sensors[i].status = SENSOR_S_CRIT; 2599 break; 2600 2601 case AMI_RDRV_DEGRADED: 2602 sc->sc_sensors[i].value = SENSOR_DRIVE_PFAIL; 2603 sc->sc_sensors[i].status = SENSOR_S_WARN; 2604 break; 2605 2606 case AMI_RDRV_OPTIMAL: 2607 sc->sc_sensors[i].value = SENSOR_DRIVE_ONLINE; 2608 sc->sc_sensors[i].status = SENSOR_S_OK; 2609 break; 2610 2611 default: 2612 sc->sc_sensors[i].value = 0; /* unknown */ 2613 sc->sc_sensors[i].status = SENSOR_S_UNKNOWN; 2614 } 2615 } 2616 } 2617 #endif /* SMALL_KERNEL */ 2618 #endif /* NBIO > 0 */ 2619 2620 #ifdef AMI_DEBUG 2621 void 2622 ami_print_mbox(struct ami_iocmd *mbox) 2623 { 2624 int i; 2625 2626 printf("acc_cmd: %d aac_id: %d acc_busy: %d acc_nstat: %d ", 2627 mbox->acc_cmd, mbox->acc_id, mbox->acc_busy, mbox->acc_nstat); 2628 printf("acc_status: %d acc_poll: %d acc_ack: %d\n", 2629 mbox->acc_status, mbox->acc_poll, mbox->acc_ack); 2630 2631 printf("acc_cmplidl: "); 2632 for (i = 0; i < AMI_MAXSTATACK; i++) { 2633 printf("[%d] = %d ", i, mbox->acc_cmplidl[i]); 2634 } 2635 2636 printf("\n"); 2637 } 2638 #endif /* AMI_DEBUG */ 2639