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