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