1 /* $NetBSD: mlx_pci.c,v 1.6 2001/11/13 07:48:46 lukem Exp $ */ 2 3 /*- 4 * Copyright (c) 2001 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Andrew Doran. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /*- 40 * Copyright (c) 1999 Michael Smith 41 * All rights reserved. 42 * 43 * Redistribution and use in source and binary forms, with or without 44 * modification, are permitted provided that the following conditions 45 * are met: 46 * 1. Redistributions of source code must retain the above copyright 47 * notice, this list of conditions and the following disclaimer. 48 * 2. Redistributions in binary form must reproduce the above copyright 49 * notice, this list of conditions and the following disclaimer in the 50 * documentation and/or other materials provided with the distribution. 51 * 52 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 55 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 62 * SUCH DAMAGE. 63 * 64 * from FreeBSD: mlx_pci.c,v 1.4.2.4 2000/10/28 10:48:09 msmith Exp 65 */ 66 67 /* 68 * PCI front-end for the mlx(4) driver. 69 */ 70 71 #include <sys/cdefs.h> 72 __KERNEL_RCSID(0, "$NetBSD: mlx_pci.c,v 1.6 2001/11/13 07:48:46 lukem Exp $"); 73 74 #include <sys/param.h> 75 #include <sys/systm.h> 76 #include <sys/kernel.h> 77 #include <sys/device.h> 78 #include <sys/queue.h> 79 #include <sys/callout.h> 80 81 #include <machine/endian.h> 82 #include <machine/bus.h> 83 84 #include <dev/ic/mlxreg.h> 85 #include <dev/ic/mlxio.h> 86 #include <dev/ic/mlxvar.h> 87 88 #include <dev/pci/pcireg.h> 89 #include <dev/pci/pcivar.h> 90 #include <dev/pci/pcidevs.h> 91 92 static void mlx_pci_attach(struct device *, struct device *, void *); 93 static int mlx_pci_match(struct device *, struct cfdata *, void *); 94 static const struct mlx_pci_ident *mlx_pci_findmpi(struct pci_attach_args *); 95 96 static int mlx_v3_submit(struct mlx_softc *, struct mlx_ccb *); 97 static int mlx_v3_findcomplete(struct mlx_softc *, u_int *, u_int *); 98 static void mlx_v3_intaction(struct mlx_softc *, int); 99 static int mlx_v3_fw_handshake(struct mlx_softc *, int *, int *, int *); 100 #ifdef MLX_RESET 101 static int mlx_v3_reset(struct mlx_softc *); 102 #endif 103 104 static int mlx_v4_submit(struct mlx_softc *, struct mlx_ccb *); 105 static int mlx_v4_findcomplete(struct mlx_softc *, u_int *, u_int *); 106 static void mlx_v4_intaction(struct mlx_softc *, int); 107 static int mlx_v4_fw_handshake(struct mlx_softc *, int *, int *, int *); 108 109 static int mlx_v5_submit(struct mlx_softc *, struct mlx_ccb *); 110 static int mlx_v5_findcomplete(struct mlx_softc *, u_int *, u_int *); 111 static void mlx_v5_intaction(struct mlx_softc *, int); 112 static int mlx_v5_fw_handshake(struct mlx_softc *, int *, int *, int *); 113 114 struct mlx_pci_ident { 115 u_short mpi_vendor; 116 u_short mpi_product; 117 u_short mpi_subvendor; 118 u_short mpi_subproduct; 119 int mpi_iftype; 120 } static const mlx_pci_ident[] = { 121 { 122 PCI_VENDOR_MYLEX, 123 PCI_PRODUCT_MYLEX_RAID_V2, 124 0x0000, 125 0x0000, 126 2, 127 }, 128 { 129 PCI_VENDOR_MYLEX, 130 PCI_PRODUCT_MYLEX_RAID_V3, 131 0x0000, 132 0x0000, 133 3, 134 }, 135 { 136 PCI_VENDOR_MYLEX, 137 PCI_PRODUCT_MYLEX_RAID_V4, 138 0x0000, 139 0x0000, 140 4, 141 }, 142 { 143 PCI_VENDOR_DEC, 144 PCI_PRODUCT_DEC_SWXCR, 145 PCI_VENDOR_MYLEX, 146 PCI_PRODUCT_MYLEX_RAID_V5, 147 5, 148 }, 149 }; 150 151 struct cfattach mlx_pci_ca = { 152 sizeof(struct mlx_softc), mlx_pci_match, mlx_pci_attach 153 }; 154 155 /* 156 * Try to find a `mlx_pci_ident' entry corresponding to this board. 157 */ 158 static const struct mlx_pci_ident * 159 mlx_pci_findmpi(struct pci_attach_args *pa) 160 { 161 const struct mlx_pci_ident *mpi, *maxmpi; 162 pcireg_t reg; 163 164 mpi = mlx_pci_ident; 165 maxmpi = mpi + sizeof(mlx_pci_ident) / sizeof(mlx_pci_ident[0]); 166 167 for (; mpi < maxmpi; mpi++) { 168 if (PCI_VENDOR(pa->pa_id) != mpi->mpi_vendor || 169 PCI_PRODUCT(pa->pa_id) != mpi->mpi_product) 170 continue; 171 172 if (mpi->mpi_subvendor == 0x0000) 173 return (mpi); 174 175 reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG); 176 177 if (PCI_VENDOR(reg) == mpi->mpi_subvendor && 178 PCI_PRODUCT(reg) == mpi->mpi_subproduct) 179 return (mpi); 180 } 181 182 return (NULL); 183 } 184 185 /* 186 * Match a supported board. 187 */ 188 static int 189 mlx_pci_match(struct device *parent, struct cfdata *cfdata, void *aux) 190 { 191 192 return (mlx_pci_findmpi(aux) != NULL); 193 } 194 195 /* 196 * Attach a supported board. 197 */ 198 static void 199 mlx_pci_attach(struct device *parent, struct device *self, void *aux) 200 { 201 struct pci_attach_args *pa; 202 struct mlx_softc *mlx; 203 pci_chipset_tag_t pc; 204 pci_intr_handle_t ih; 205 bus_space_handle_t memh, ioh; 206 bus_space_tag_t memt, iot; 207 pcireg_t reg; 208 const char *intrstr; 209 int ior, memr, i; 210 const struct mlx_pci_ident *mpi; 211 212 mlx = (struct mlx_softc *)self; 213 pa = aux; 214 pc = pa->pa_pc; 215 mpi = mlx_pci_findmpi(aux); 216 217 mlx->mlx_dmat = pa->pa_dmat; 218 mlx->mlx_iftype = mpi->mpi_iftype; 219 220 printf(": Mylex RAID (v%d interface)\n", mpi->mpi_iftype); 221 222 /* 223 * Map the PCI register window. 224 */ 225 memr = -1; 226 ior = -1; 227 228 for (i = 0x10; i <= 0x14; i += 4) { 229 reg = pci_conf_read(pa->pa_pc, pa->pa_tag, i); 230 231 if (PCI_MAPREG_TYPE(reg) == PCI_MAPREG_TYPE_IO) { 232 if (ior == -1 && PCI_MAPREG_IO_SIZE(reg) != 0) 233 ior = i; 234 } else { 235 if (memr == -1 && PCI_MAPREG_MEM_SIZE(reg) != 0) 236 memr = i; 237 } 238 } 239 240 if (memr != -1) 241 if (pci_mapreg_map(pa, memr, PCI_MAPREG_TYPE_MEM, 0, 242 &memt, &memh, NULL, NULL)) 243 memr = -1; 244 if (ior != -1) 245 if (pci_mapreg_map(pa, ior, PCI_MAPREG_TYPE_IO, 0, 246 &iot, &ioh, NULL, NULL)) 247 ior = -1; 248 249 if (memr != -1) { 250 mlx->mlx_iot = memt; 251 mlx->mlx_ioh = memh; 252 } else if (ior != -1) { 253 mlx->mlx_iot = iot; 254 mlx->mlx_ioh = ioh; 255 } else { 256 printf("%s: can't map i/o or memory space\n", self->dv_xname); 257 return; 258 } 259 260 /* Enable the device. */ 261 reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG); 262 pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, 263 reg | PCI_COMMAND_MASTER_ENABLE); 264 265 /* Map and establish the interrupt. */ 266 if (pci_intr_map(pa, &ih)) { 267 printf("%s: can't map interrupt\n", self->dv_xname); 268 return; 269 } 270 intrstr = pci_intr_string(pc, ih); 271 mlx->mlx_ih = pci_intr_establish(pc, ih, IPL_BIO, mlx_intr, mlx); 272 if (mlx->mlx_ih == NULL) { 273 printf("%s: can't establish interrupt", self->dv_xname); 274 if (intrstr != NULL) 275 printf(" at %s", intrstr); 276 printf("\n"); 277 return; 278 } 279 280 /* Select linkage based on controller interface type. */ 281 switch (mlx->mlx_iftype) { 282 case 2: 283 case 3: 284 mlx->mlx_submit = mlx_v3_submit; 285 mlx->mlx_findcomplete = mlx_v3_findcomplete; 286 mlx->mlx_intaction = mlx_v3_intaction; 287 mlx->mlx_fw_handshake = mlx_v3_fw_handshake; 288 #ifdef MLX_RESET 289 mlx->mlx_reset = mlx_v3_reset; 290 #endif 291 break; 292 293 case 4: 294 mlx->mlx_submit = mlx_v4_submit; 295 mlx->mlx_findcomplete = mlx_v4_findcomplete; 296 mlx->mlx_intaction = mlx_v4_intaction; 297 mlx->mlx_fw_handshake = mlx_v4_fw_handshake; 298 break; 299 300 case 5: 301 mlx->mlx_submit = mlx_v5_submit; 302 mlx->mlx_findcomplete = mlx_v5_findcomplete; 303 mlx->mlx_intaction = mlx_v5_intaction; 304 mlx->mlx_fw_handshake = mlx_v5_fw_handshake; 305 break; 306 } 307 308 mlx_init(mlx, intrstr); 309 } 310 311 /* 312 * ================= V3 interface linkage ================= 313 */ 314 315 /* 316 * Try to give (mc) to the controller. Returns 1 if successful, 0 on 317 * failure (the controller is not ready to take a command). 318 * 319 * Must be called at splbio or in a fashion that prevents reentry. 320 */ 321 static int 322 mlx_v3_submit(struct mlx_softc *mlx, struct mlx_ccb *mc) 323 { 324 325 /* Ready for our command? */ 326 if ((mlx_inb(mlx, MLX_V3REG_IDB) & MLX_V3_IDB_FULL) == 0) { 327 /* Copy mailbox data to window. */ 328 bus_space_write_region_1(mlx->mlx_iot, mlx->mlx_ioh, 329 MLX_V3REG_MAILBOX, mc->mc_mbox, MLX_V3_MAILBOX_LEN); 330 bus_space_barrier(mlx->mlx_iot, mlx->mlx_ioh, 331 MLX_V3REG_MAILBOX, MLX_V3_MAILBOX_LEN, 332 BUS_SPACE_BARRIER_WRITE); 333 334 /* Post command. */ 335 mlx_outb(mlx, MLX_V3REG_IDB, MLX_V3_IDB_FULL); 336 return (1); 337 } 338 339 return (0); 340 } 341 342 /* 343 * See if a command has been completed, if so acknowledge its completion and 344 * recover the slot number and status code. 345 * 346 * Must be called at splbio or in a fashion that prevents reentry. 347 */ 348 static int 349 mlx_v3_findcomplete(struct mlx_softc *mlx, u_int *slot, u_int *status) 350 { 351 352 /* Status available? */ 353 if ((mlx_inb(mlx, MLX_V3REG_ODB) & MLX_V3_ODB_SAVAIL) != 0) { 354 *slot = mlx_inb(mlx, MLX_V3REG_STATUS_IDENT); 355 *status = mlx_inw(mlx, MLX_V3REG_STATUS); 356 357 /* Acknowledge completion. */ 358 mlx_outb(mlx, MLX_V3REG_ODB, MLX_V3_ODB_SAVAIL); 359 mlx_outb(mlx, MLX_V3REG_IDB, MLX_V3_IDB_SACK); 360 return (1); 361 } 362 363 return (0); 364 } 365 366 /* 367 * Enable/disable interrupts as requested. (No acknowledge required) 368 * 369 * Must be called at splbio or in a fashion that prevents reentry. 370 */ 371 static void 372 mlx_v3_intaction(struct mlx_softc *mlx, int action) 373 { 374 375 mlx_outb(mlx, MLX_V3REG_IE, action != 0); 376 } 377 378 /* 379 * Poll for firmware error codes during controller initialisation. 380 * 381 * Returns 0 if initialisation is complete, 1 if still in progress but no 382 * error has been fetched, 2 if an error has been retrieved. 383 */ 384 static int 385 mlx_v3_fw_handshake(struct mlx_softc *mlx, int *error, int *param1, int *param2) 386 { 387 u_int8_t fwerror; 388 389 /* First time around, clear any hardware completion status. */ 390 if ((mlx->mlx_flags & MLXF_FW_INITTED) == 0) { 391 mlx_outb(mlx, MLX_V3REG_IDB, MLX_V3_IDB_SACK); 392 DELAY(1000); 393 mlx->mlx_flags |= MLXF_FW_INITTED; 394 } 395 396 /* Init in progress? */ 397 if ((mlx_inb(mlx, MLX_V3REG_IDB) & MLX_V3_IDB_INIT_BUSY) == 0) 398 return (0); 399 400 /* Test error value. */ 401 fwerror = mlx_inb(mlx, MLX_V3REG_FWERROR); 402 403 if ((fwerror & MLX_V3_FWERROR_PEND) == 0) 404 return (1); 405 406 /* Mask status pending bit, fetch status. */ 407 *error = fwerror & ~MLX_V3_FWERROR_PEND; 408 *param1 = mlx_inb(mlx, MLX_V3REG_FWERROR_PARAM1); 409 *param2 = mlx_inb(mlx, MLX_V3REG_FWERROR_PARAM2); 410 411 /* Acknowledge. */ 412 mlx_outb(mlx, MLX_V3REG_FWERROR, 0); 413 414 return (2); 415 } 416 417 #ifdef MLX_RESET 418 /* 419 * Reset the controller. Return non-zero on failure. 420 */ 421 static int 422 mlx_v3_reset(struct mlx_softc *mlx) 423 { 424 int i; 425 426 mlx_outb(mlx, MLX_V3REG_IDB, MLX_V3_IDB_SACK); 427 delay(1000000); 428 429 /* Wait up to 2 minutes for the bit to clear. */ 430 for (i = 120; i != 0; i--) { 431 delay(1000000); 432 if ((mlx_inb(mlx, MLX_V3REG_IDB) & MLX_V3_IDB_SACK) == 0) 433 break; 434 } 435 if (i == 0) { 436 /* ZZZ */ 437 printf("mlx0: SACK didn't clear\n"); 438 return (-1); 439 } 440 441 mlx_outb(mlx, MLX_V3REG_IDB, MLX_V3_IDB_RESET); 442 443 /* Wait up to 5 seconds for the bit to clear. */ 444 for (i = 5; i != 0; i--) { 445 delay(1000000); 446 if ((mlx_inb(mlx, MLX_V3REG_IDB) & MLX_V3_IDB_RESET) == 0) 447 break; 448 } 449 if (i == 0) { 450 /* ZZZ */ 451 printf("mlx0: RESET didn't clear\n"); 452 return (-1); 453 } 454 455 return (0); 456 } 457 #endif /* MLX_RESET */ 458 459 /* 460 * ================= V4 interface linkage ================= 461 */ 462 463 /* 464 * Try to give (mc) to the controller. Returns 1 if successful, 0 on 465 * failure (the controller is not ready to take a command). 466 * 467 * Must be called at splbio or in a fashion that prevents reentry. 468 */ 469 static int 470 mlx_v4_submit(struct mlx_softc *mlx, struct mlx_ccb *mc) 471 { 472 473 /* Ready for our command? */ 474 if ((mlx_inl(mlx, MLX_V4REG_IDB) & MLX_V4_IDB_FULL) == 0) { 475 /* Copy mailbox data to window. */ 476 bus_space_write_region_1(mlx->mlx_iot, mlx->mlx_ioh, 477 MLX_V4REG_MAILBOX, mc->mc_mbox, MLX_V4_MAILBOX_LEN); 478 bus_space_barrier(mlx->mlx_iot, mlx->mlx_ioh, 479 MLX_V4REG_MAILBOX, MLX_V4_MAILBOX_LEN, 480 BUS_SPACE_BARRIER_WRITE); 481 482 /* Post command. */ 483 mlx_outl(mlx, MLX_V4REG_IDB, MLX_V4_IDB_HWMBOX_CMD); 484 return (1); 485 } 486 487 return (0); 488 } 489 490 /* 491 * See if a command has been completed, if so acknowledge its completion and 492 * recover the slot number and status code. 493 * 494 * Must be called at splbio or in a fashion that prevents reentry. 495 */ 496 static int 497 mlx_v4_findcomplete(struct mlx_softc *mlx, u_int *slot, u_int *status) 498 { 499 500 /* Status available? */ 501 if ((mlx_inl(mlx, MLX_V4REG_ODB) & MLX_V4_ODB_HWSAVAIL) != 0) { 502 *slot = mlx_inb(mlx, MLX_V4REG_STATUS_IDENT); 503 *status = mlx_inw(mlx, MLX_V4REG_STATUS); 504 505 /* Acknowledge completion. */ 506 mlx_outl(mlx, MLX_V4REG_ODB, MLX_V4_ODB_HWMBOX_ACK); 507 mlx_outl(mlx, MLX_V4REG_IDB, MLX_V4_IDB_SACK); 508 return (1); 509 } 510 511 return (0); 512 } 513 514 /* 515 * Enable/disable interrupts as requested. 516 * 517 * Must be called at splbio or in a fashion that prevents reentry. 518 */ 519 static void 520 mlx_v4_intaction(struct mlx_softc *mlx, int action) 521 { 522 u_int32_t ier; 523 524 if (!action) 525 ier = MLX_V4_IE_MASK | MLX_V4_IE_DISINT; 526 else 527 ier = MLX_V4_IE_MASK & ~MLX_V4_IE_DISINT; 528 529 mlx_outl(mlx, MLX_V4REG_IE, ier); 530 } 531 532 /* 533 * Poll for firmware error codes during controller initialisation. 534 * 535 * Returns 0 if initialisation is complete, 1 if still in progress but no 536 * error has been fetched, 2 if an error has been retrieved. 537 */ 538 static int 539 mlx_v4_fw_handshake(struct mlx_softc *mlx, int *error, int *param1, int *param2) 540 { 541 u_int8_t fwerror; 542 543 /* First time around, clear any hardware completion status. */ 544 if ((mlx->mlx_flags & MLXF_FW_INITTED) == 0) { 545 mlx_outl(mlx, MLX_V4REG_IDB, MLX_V4_IDB_SACK); 546 DELAY(1000); 547 mlx->mlx_flags |= MLXF_FW_INITTED; 548 } 549 550 /* Init in progress? */ 551 if ((mlx_inl(mlx, MLX_V4REG_IDB) & MLX_V4_IDB_INIT_BUSY) == 0) 552 return (0); 553 554 /* Test error value */ 555 fwerror = mlx_inb(mlx, MLX_V4REG_FWERROR); 556 if ((fwerror & MLX_V4_FWERROR_PEND) == 0) 557 return (1); 558 559 /* Mask status pending bit, fetch status. */ 560 *error = fwerror & ~MLX_V4_FWERROR_PEND; 561 *param1 = mlx_inb(mlx, MLX_V4REG_FWERROR_PARAM1); 562 *param2 = mlx_inb(mlx, MLX_V4REG_FWERROR_PARAM2); 563 564 /* Acknowledge. */ 565 mlx_outb(mlx, MLX_V4REG_FWERROR, 0); 566 567 return (2); 568 } 569 570 /* 571 * ================= V5 interface linkage ================= 572 */ 573 574 /* 575 * Try to give (mc) to the controller. Returns 1 if successful, 0 on failure 576 * (the controller is not ready to take a command). 577 * 578 * Must be called at splbio or in a fashion that prevents reentry. 579 */ 580 static int 581 mlx_v5_submit(struct mlx_softc *mlx, struct mlx_ccb *mc) 582 { 583 584 /* Ready for our command? */ 585 if ((mlx_inb(mlx, MLX_V5REG_IDB) & MLX_V5_IDB_EMPTY) != 0) { 586 /* Copy mailbox data to window. */ 587 bus_space_write_region_1(mlx->mlx_iot, mlx->mlx_ioh, 588 MLX_V5REG_MAILBOX, mc->mc_mbox, MLX_V5_MAILBOX_LEN); 589 bus_space_barrier(mlx->mlx_iot, mlx->mlx_ioh, 590 MLX_V5REG_MAILBOX, MLX_V5_MAILBOX_LEN, 591 BUS_SPACE_BARRIER_WRITE); 592 593 /* Post command */ 594 mlx_outb(mlx, MLX_V5REG_IDB, MLX_V5_IDB_HWMBOX_CMD); 595 return (1); 596 } 597 598 return (0); 599 } 600 601 /* 602 * See if a command has been completed, if so acknowledge its completion and 603 * recover the slot number and status code. 604 * 605 * Must be called at splbio or in a fashion that prevents reentry. 606 */ 607 static int 608 mlx_v5_findcomplete(struct mlx_softc *mlx, u_int *slot, u_int *status) 609 { 610 611 /* Status available? */ 612 if ((mlx_inb(mlx, MLX_V5REG_ODB) & MLX_V5_ODB_HWSAVAIL) != 0) { 613 *slot = mlx_inb(mlx, MLX_V5REG_STATUS_IDENT); 614 *status = mlx_inw(mlx, MLX_V5REG_STATUS); 615 616 /* Acknowledge completion. */ 617 mlx_outb(mlx, MLX_V5REG_ODB, MLX_V5_ODB_HWMBOX_ACK); 618 mlx_outb(mlx, MLX_V5REG_IDB, MLX_V5_IDB_SACK); 619 return (1); 620 } 621 622 return (0); 623 } 624 625 /* 626 * Enable/disable interrupts as requested. 627 * 628 * Must be called at splbio or in a fashion that prevents reentry. 629 */ 630 static void 631 mlx_v5_intaction(struct mlx_softc *mlx, int action) 632 { 633 u_int8_t ier; 634 635 if (!action) 636 ier = 0xff & MLX_V5_IE_DISINT; 637 else 638 ier = 0xff & ~MLX_V5_IE_DISINT; 639 640 mlx_outb(mlx, MLX_V5REG_IE, ier); 641 } 642 643 /* 644 * Poll for firmware error codes during controller initialisation. 645 * 646 * Returns 0 if initialisation is complete, 1 if still in progress but no 647 * error has been fetched, 2 if an error has been retrieved. 648 */ 649 static int 650 mlx_v5_fw_handshake(struct mlx_softc *mlx, int *error, int *param1, int *param2) 651 { 652 u_int8_t fwerror; 653 654 /* First time around, clear any hardware completion status. */ 655 if ((mlx->mlx_flags & MLXF_FW_INITTED) == 0) { 656 mlx_outb(mlx, MLX_V5REG_IDB, MLX_V5_IDB_SACK); 657 DELAY(1000); 658 mlx->mlx_flags |= MLXF_FW_INITTED; 659 } 660 661 /* Init in progress? */ 662 if ((mlx_inb(mlx, MLX_V5REG_IDB) & MLX_V5_IDB_INIT_DONE) != 0) 663 return (0); 664 665 /* Test for error value. */ 666 fwerror = mlx_inb(mlx, MLX_V5REG_FWERROR); 667 if ((fwerror & MLX_V5_FWERROR_PEND) == 0) 668 return (1); 669 670 /* Mask status pending bit, fetch status. */ 671 *error = fwerror & ~MLX_V5_FWERROR_PEND; 672 *param1 = mlx_inb(mlx, MLX_V5REG_FWERROR_PARAM1); 673 *param2 = mlx_inb(mlx, MLX_V5REG_FWERROR_PARAM2); 674 675 /* Acknowledge. */ 676 mlx_outb(mlx, MLX_V5REG_FWERROR, 0xff); 677 678 return (2); 679 } 680