1 /* $NetBSD: mpt.c,v 1.10 2007/07/27 18:38:13 tron Exp $ */ 2 3 /* 4 * Copyright (c) 2000, 2001 by Greg Ansley 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice immediately at the beginning of the file, without modification, 11 * this list of conditions, and the following disclaimer. 12 * 2. The name of the author may not be used to endorse or promote products 13 * derived from this software without specific prior written permission. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 19 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 /* 28 * Additional Copyright (c) 2002 by Matthew Jacob under same license. 29 */ 30 31 32 /* 33 * mpt.c: 34 * 35 * Generic routines for LSI Fusion adapters. 36 * 37 * Adapted from the FreeBSD "mpt" driver by Jason R. Thorpe for 38 * Wasabi Systems, Inc. 39 * 40 * Additional contributions by Garrett D'Amore on behalf of TELES AG. 41 */ 42 43 #include <sys/cdefs.h> 44 __KERNEL_RCSID(0, "$NetBSD: mpt.c,v 1.10 2007/07/27 18:38:13 tron Exp $"); 45 46 #include <dev/ic/mpt.h> 47 48 #define MPT_MAX_TRYS 3 49 #define MPT_MAX_WAIT 300000 50 51 static int maxwait_ack = 0; 52 static int maxwait_int = 0; 53 static int maxwait_state = 0; 54 55 static inline u_int32_t 56 mpt_rd_db(mpt_softc_t *mpt) 57 { 58 return mpt_read(mpt, MPT_OFFSET_DOORBELL); 59 } 60 61 static inline u_int32_t 62 mpt_rd_intr(mpt_softc_t *mpt) 63 { 64 return mpt_read(mpt, MPT_OFFSET_INTR_STATUS); 65 } 66 67 /* Busy wait for a door bell to be read by IOC */ 68 static int 69 mpt_wait_db_ack(mpt_softc_t *mpt) 70 { 71 int i; 72 for (i=0; i < MPT_MAX_WAIT; i++) { 73 if (!MPT_DB_IS_BUSY(mpt_rd_intr(mpt))) { 74 maxwait_ack = i > maxwait_ack ? i : maxwait_ack; 75 return MPT_OK; 76 } 77 78 DELAY(100); 79 } 80 return MPT_FAIL; 81 } 82 83 /* Busy wait for a door bell interrupt */ 84 static int 85 mpt_wait_db_int(mpt_softc_t *mpt) 86 { 87 int i; 88 for (i=0; i < MPT_MAX_WAIT; i++) { 89 if (MPT_DB_INTR(mpt_rd_intr(mpt))) { 90 maxwait_int = i > maxwait_int ? i : maxwait_int; 91 return MPT_OK; 92 } 93 DELAY(100); 94 } 95 return MPT_FAIL; 96 } 97 98 /* Wait for IOC to transition to a give state */ 99 void 100 mpt_check_doorbell(mpt_softc_t *mpt) 101 { 102 u_int32_t db = mpt_rd_db(mpt); 103 if (MPT_STATE(db) != MPT_DB_STATE_RUNNING) { 104 mpt_prt(mpt, "Device not running"); 105 mpt_print_db(db); 106 } 107 } 108 109 /* Wait for IOC to transition to a give state */ 110 static int 111 mpt_wait_state(mpt_softc_t *mpt, enum DB_STATE_BITS state) 112 { 113 int i; 114 115 for (i = 0; i < MPT_MAX_WAIT; i++) { 116 u_int32_t db = mpt_rd_db(mpt); 117 if (MPT_STATE(db) == state) { 118 maxwait_state = i > maxwait_state ? i : maxwait_state; 119 return (MPT_OK); 120 } 121 DELAY(100); 122 } 123 return (MPT_FAIL); 124 } 125 126 127 /* Issue the reset COMMAND to the IOC */ 128 int 129 mpt_soft_reset(mpt_softc_t *mpt) 130 { 131 if (mpt->verbose) { 132 mpt_prt(mpt, "soft reset"); 133 } 134 135 /* Have to use hard reset if we are not in Running state */ 136 if (MPT_STATE(mpt_rd_db(mpt)) != MPT_DB_STATE_RUNNING) { 137 mpt_prt(mpt, "soft reset failed: device not running"); 138 return MPT_FAIL; 139 } 140 141 /* If door bell is in use we don't have a chance of getting 142 * a word in since the IOC probably crashed in message 143 * processing. So don't waste our time. 144 */ 145 if (MPT_DB_IS_IN_USE(mpt_rd_db(mpt))) { 146 mpt_prt(mpt, "soft reset failed: doorbell wedged"); 147 return MPT_FAIL; 148 } 149 150 /* Send the reset request to the IOC */ 151 mpt_write(mpt, MPT_OFFSET_DOORBELL, 152 MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET << MPI_DOORBELL_FUNCTION_SHIFT); 153 if (mpt_wait_db_ack(mpt) != MPT_OK) { 154 mpt_prt(mpt, "soft reset failed: ack timeout"); 155 return MPT_FAIL; 156 } 157 158 /* Wait for the IOC to reload and come out of reset state */ 159 if (mpt_wait_state(mpt, MPT_DB_STATE_READY) != MPT_OK) { 160 mpt_prt(mpt, "soft reset failed: device did not start running"); 161 return MPT_FAIL; 162 } 163 164 return MPT_OK; 165 } 166 167 /* This is a magic diagnostic reset that resets all the ARM 168 * processors in the chip. 169 */ 170 void 171 mpt_hard_reset(mpt_softc_t *mpt) 172 { 173 if (mpt->verbose) { 174 mpt_prt(mpt, "hard reset"); 175 } 176 mpt_write(mpt, MPT_OFFSET_SEQUENCE, 0xff); 177 178 /* Enable diagnostic registers */ 179 mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_1); 180 mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_2); 181 mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_3); 182 mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_4); 183 mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_5); 184 185 /* Diag. port is now active so we can now hit the reset bit */ 186 mpt_write(mpt, MPT_OFFSET_DIAGNOSTIC, MPT_DIAG_RESET_IOC); 187 188 DELAY(10000); 189 190 /* Disable Diagnostic Register */ 191 mpt_write(mpt, MPT_OFFSET_SEQUENCE, 0xFF); 192 } 193 194 /* 195 * Reset the IOC when needed. Try software command first then if needed 196 * poke at the magic diagnostic reset. Note that a hard reset resets 197 * *both* IOCs on dual function chips (FC929 && LSI1030) as well as 198 * fouls up the PCI configuration registers. 199 */ 200 int 201 mpt_reset(mpt_softc_t *mpt) 202 { 203 int ret; 204 205 /* Try a soft reset */ 206 if ((ret = mpt_soft_reset(mpt)) != MPT_OK) { 207 /* Failed; do a hard reset */ 208 mpt_hard_reset(mpt); 209 210 /* Wait for the IOC to reload and come out of reset state */ 211 ret = mpt_wait_state(mpt, MPT_DB_STATE_READY); 212 if (ret != MPT_OK) { 213 mpt_prt(mpt, "failed to reset device"); 214 } 215 } 216 217 return ret; 218 } 219 220 /* Return a command buffer to the free queue */ 221 void 222 mpt_free_request(mpt_softc_t *mpt, request_t *req) 223 { 224 if (req == NULL || req != &mpt->request_pool[req->index]) { 225 panic("mpt_free_request bad req ptr\n"); 226 return; 227 } 228 req->sequence = 0; 229 req->xfer = NULL; 230 req->debug = REQ_FREE; 231 SLIST_INSERT_HEAD(&mpt->request_free_list, req, link); 232 } 233 234 /* Get a command buffer from the free queue */ 235 request_t * 236 mpt_get_request(mpt_softc_t *mpt) 237 { 238 request_t *req; 239 req = SLIST_FIRST(&mpt->request_free_list); 240 if (req != NULL) { 241 if (req != &mpt->request_pool[req->index]) { 242 panic("mpt_get_request: corrupted request free list\n"); 243 } 244 if (req->xfer != NULL) { 245 panic("mpt_get_request: corrupted request free list (xfer)\n"); 246 } 247 SLIST_REMOVE_HEAD(&mpt->request_free_list, link); 248 req->debug = REQ_IN_PROGRESS; 249 } 250 return req; 251 } 252 253 /* Pass the command to the IOC */ 254 void 255 mpt_send_cmd(mpt_softc_t *mpt, request_t *req) 256 { 257 req->sequence = mpt->sequence++; 258 if (mpt->verbose > 1) { 259 u_int32_t *pReq; 260 pReq = req->req_vbuf; 261 mpt_prt(mpt, "Send Request %d (0x%x):", 262 req->index, req->req_pbuf); 263 mpt_prt(mpt, "%08x %08x %08x %08x", 264 pReq[0], pReq[1], pReq[2], pReq[3]); 265 mpt_prt(mpt, "%08x %08x %08x %08x", 266 pReq[4], pReq[5], pReq[6], pReq[7]); 267 mpt_prt(mpt, "%08x %08x %08x %08x", 268 pReq[8], pReq[9], pReq[10], pReq[11]); 269 mpt_prt(mpt, "%08x %08x %08x %08x", 270 pReq[12], pReq[13], pReq[14], pReq[15]); 271 } 272 MPT_SYNC_REQ(mpt, req, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 273 req->debug = REQ_ON_CHIP; 274 mpt_write(mpt, MPT_OFFSET_REQUEST_Q, (u_int32_t) req->req_pbuf); 275 } 276 277 /* 278 * Give the reply buffer back to the IOC after we have 279 * finished processing it. 280 */ 281 void 282 mpt_free_reply(mpt_softc_t *mpt, u_int32_t ptr) 283 { 284 mpt_write(mpt, MPT_OFFSET_REPLY_Q, ptr); 285 } 286 287 /* Get a reply from the IOC */ 288 u_int32_t 289 mpt_pop_reply_queue(mpt_softc_t *mpt) 290 { 291 return mpt_read(mpt, MPT_OFFSET_REPLY_Q); 292 } 293 294 /* 295 * Send a command to the IOC via the handshake register. 296 * 297 * Only done at initialization time and for certain unusual 298 * commands such as device/bus reset as specified by LSI. 299 */ 300 int 301 mpt_send_handshake_cmd(mpt_softc_t *mpt, size_t len, void *cmd) 302 { 303 int i; 304 u_int32_t data, *data32; 305 306 /* Check condition of the IOC */ 307 data = mpt_rd_db(mpt); 308 if (((MPT_STATE(data) != MPT_DB_STATE_READY) && 309 (MPT_STATE(data) != MPT_DB_STATE_RUNNING) && 310 (MPT_STATE(data) != MPT_DB_STATE_FAULT)) || 311 ( MPT_DB_IS_IN_USE(data) )) { 312 mpt_prt(mpt, "handshake aborted due to invalid doorbell state"); 313 mpt_print_db(data); 314 return(EBUSY); 315 } 316 317 /* We move things in 32 bit chunks */ 318 len = (len + 3) >> 2; 319 data32 = cmd; 320 321 /* Clear any left over pending doorbell interrupts */ 322 if (MPT_DB_INTR(mpt_rd_intr(mpt))) 323 mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0); 324 325 /* 326 * Tell the handshake reg. we are going to send a command 327 * and how long it is going to be. 328 */ 329 data = (MPI_FUNCTION_HANDSHAKE << MPI_DOORBELL_FUNCTION_SHIFT) | 330 (len << MPI_DOORBELL_ADD_DWORDS_SHIFT); 331 mpt_write(mpt, MPT_OFFSET_DOORBELL, data); 332 333 /* Wait for the chip to notice */ 334 if (mpt_wait_db_int(mpt) != MPT_OK) { 335 mpt_prt(mpt, "mpt_send_handshake_cmd timeout1"); 336 return ETIMEDOUT; 337 } 338 339 /* Clear the interrupt */ 340 mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0); 341 342 if (mpt_wait_db_ack(mpt) != MPT_OK) { 343 mpt_prt(mpt, "mpt_send_handshake_cmd timeout2"); 344 return ETIMEDOUT; 345 } 346 347 /* Send the command */ 348 for (i = 0; i < len; i++) { 349 mpt_write(mpt, MPT_OFFSET_DOORBELL, *data32++); 350 if (mpt_wait_db_ack(mpt) != MPT_OK) { 351 mpt_prt(mpt, 352 "mpt_send_handshake_cmd timeout! index = %d", i); 353 return ETIMEDOUT; 354 } 355 } 356 return MPT_OK; 357 } 358 359 /* Get the response from the handshake register */ 360 int 361 mpt_recv_handshake_reply(mpt_softc_t *mpt, size_t reply_len, void *reply) 362 { 363 int left, reply_left; 364 u_int16_t *data16; 365 MSG_DEFAULT_REPLY *hdr; 366 367 /* We move things out in 16 bit chunks */ 368 reply_len >>= 1; 369 data16 = (u_int16_t *)reply; 370 371 hdr = (MSG_DEFAULT_REPLY *)reply; 372 373 /* Get first word */ 374 if (mpt_wait_db_int(mpt) != MPT_OK) { 375 mpt_prt(mpt, "mpt_recv_handshake_cmd timeout1"); 376 return ETIMEDOUT; 377 } 378 *data16++ = mpt_read(mpt, MPT_OFFSET_DOORBELL) & MPT_DB_DATA_MASK; 379 mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0); 380 381 /* Get Second Word */ 382 if (mpt_wait_db_int(mpt) != MPT_OK) { 383 mpt_prt(mpt, "mpt_recv_handshake_cmd timeout2"); 384 return ETIMEDOUT; 385 } 386 *data16++ = mpt_read(mpt, MPT_OFFSET_DOORBELL) & MPT_DB_DATA_MASK; 387 mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0); 388 389 /* With the second word, we can now look at the length */ 390 if (mpt->verbose > 1 && ((reply_len >> 1) != hdr->MsgLength)) { 391 mpt_prt(mpt, "reply length does not match message length: " 392 "got 0x%02x, expected 0x%02x", 393 hdr->MsgLength << 2, reply_len << 1); 394 } 395 396 /* Get rest of the reply; but don't overflow the provided buffer */ 397 left = (hdr->MsgLength << 1) - 2; 398 reply_left = reply_len - 2; 399 while (left--) { 400 u_int16_t datum; 401 402 if (mpt_wait_db_int(mpt) != MPT_OK) { 403 mpt_prt(mpt, "mpt_recv_handshake_cmd timeout3"); 404 return ETIMEDOUT; 405 } 406 datum = mpt_read(mpt, MPT_OFFSET_DOORBELL); 407 408 if (reply_left-- > 0) 409 *data16++ = datum & MPT_DB_DATA_MASK; 410 411 mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0); 412 } 413 414 /* One more wait & clear at the end */ 415 if (mpt_wait_db_int(mpt) != MPT_OK) { 416 mpt_prt(mpt, "mpt_recv_handshake_cmd timeout4"); 417 return ETIMEDOUT; 418 } 419 mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0); 420 421 if ((hdr->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) { 422 if (mpt->verbose > 1) 423 mpt_print_reply(hdr); 424 return (MPT_FAIL | hdr->IOCStatus); 425 } 426 427 return (0); 428 } 429 430 static int 431 mpt_get_iocfacts(mpt_softc_t *mpt, MSG_IOC_FACTS_REPLY *freplp) 432 { 433 MSG_IOC_FACTS f_req; 434 int error; 435 436 bzero(&f_req, sizeof f_req); 437 f_req.Function = MPI_FUNCTION_IOC_FACTS; 438 f_req.MsgContext = 0x12071942; 439 error = mpt_send_handshake_cmd(mpt, sizeof f_req, &f_req); 440 if (error) 441 return(error); 442 error = mpt_recv_handshake_reply(mpt, sizeof (*freplp), freplp); 443 return (error); 444 } 445 446 static int 447 mpt_get_portfacts(mpt_softc_t *mpt, MSG_PORT_FACTS_REPLY *freplp) 448 { 449 MSG_PORT_FACTS f_req; 450 int error; 451 452 /* XXX: Only getting PORT FACTS for Port 0 */ 453 bzero(&f_req, sizeof f_req); 454 f_req.Function = MPI_FUNCTION_PORT_FACTS; 455 f_req.MsgContext = 0x12071943; 456 error = mpt_send_handshake_cmd(mpt, sizeof f_req, &f_req); 457 if (error) 458 return(error); 459 error = mpt_recv_handshake_reply(mpt, sizeof (*freplp), freplp); 460 return (error); 461 } 462 463 /* 464 * Send the initialization request. This is where we specify how many 465 * SCSI busses and how many devices per bus we wish to emulate. 466 * This is also the command that specifies the max size of the reply 467 * frames from the IOC that we will be allocating. 468 */ 469 static int 470 mpt_send_ioc_init(mpt_softc_t *mpt, u_int32_t who) 471 { 472 int error = 0; 473 MSG_IOC_INIT init; 474 MSG_IOC_INIT_REPLY reply; 475 476 bzero(&init, sizeof init); 477 init.WhoInit = who; 478 init.Function = MPI_FUNCTION_IOC_INIT; 479 init.MaxDevices = mpt->mpt_max_devices; 480 init.MaxBuses = 1; 481 init.ReplyFrameSize = MPT_REPLY_SIZE; 482 init.MsgContext = 0x12071941; 483 484 if ((error = mpt_send_handshake_cmd(mpt, sizeof init, &init)) != 0) { 485 return(error); 486 } 487 488 error = mpt_recv_handshake_reply(mpt, sizeof reply, &reply); 489 return (error); 490 } 491 492 493 /* 494 * Utiltity routine to read configuration headers and pages 495 */ 496 497 static int 498 mpt_read_cfg_header(mpt_softc_t *, int, int, int, fCONFIG_PAGE_HEADER *); 499 500 static int 501 mpt_read_cfg_header(mpt_softc_t *mpt, int PageType, int PageNumber, 502 int PageAddress, fCONFIG_PAGE_HEADER *rslt) 503 { 504 int count; 505 request_t *req; 506 MSG_CONFIG *cfgp; 507 MSG_CONFIG_REPLY *reply; 508 509 req = mpt_get_request(mpt); 510 511 cfgp = req->req_vbuf; 512 bzero(cfgp, sizeof *cfgp); 513 514 cfgp->Action = MPI_CONFIG_ACTION_PAGE_HEADER; 515 cfgp->Function = MPI_FUNCTION_CONFIG; 516 cfgp->Header.PageNumber = (U8) PageNumber; 517 cfgp->Header.PageType = (U8) PageType; 518 cfgp->PageAddress = PageAddress; 519 MPI_pSGE_SET_FLAGS(((SGE_SIMPLE32 *) &cfgp->PageBufferSGE), 520 (MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER | 521 MPI_SGE_FLAGS_SIMPLE_ELEMENT | MPI_SGE_FLAGS_END_OF_LIST)); 522 cfgp->MsgContext = req->index | 0x80000000; 523 524 mpt_check_doorbell(mpt); 525 mpt_send_cmd(mpt, req); 526 count = 0; 527 do { 528 DELAY(500); 529 mpt_intr(mpt); 530 if (++count == 1000) { 531 mpt_prt(mpt, "read_cfg_header timed out"); 532 return (-1); 533 } 534 } while (req->debug == REQ_ON_CHIP); 535 536 reply = (MSG_CONFIG_REPLY *) MPT_REPLY_PTOV(mpt, req->sequence); 537 if ((reply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) { 538 mpt_prt(mpt, "mpt_read_cfg_header: Config Info Status %x", 539 reply->IOCStatus); 540 mpt_free_reply(mpt, (req->sequence << 1)); 541 return (-1); 542 } 543 bcopy(&reply->Header, rslt, sizeof (fCONFIG_PAGE_HEADER)); 544 mpt_free_reply(mpt, (req->sequence << 1)); 545 mpt_free_request(mpt, req); 546 return (0); 547 } 548 549 #define CFG_DATA_OFF 128 550 551 int 552 mpt_read_cfg_page(mpt_softc_t *mpt, int PageAddress, fCONFIG_PAGE_HEADER *hdr) 553 { 554 int count; 555 request_t *req; 556 SGE_SIMPLE32 *se; 557 MSG_CONFIG *cfgp; 558 size_t amt; 559 MSG_CONFIG_REPLY *reply; 560 561 req = mpt_get_request(mpt); 562 563 cfgp = req->req_vbuf; 564 bzero(cfgp, MPT_REQUEST_AREA); 565 cfgp->Action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; 566 cfgp->Function = MPI_FUNCTION_CONFIG; 567 cfgp->Header = *hdr; 568 amt = (cfgp->Header.PageLength * sizeof (u_int32_t)); 569 cfgp->Header.PageType &= MPI_CONFIG_PAGETYPE_MASK; 570 cfgp->PageAddress = PageAddress; 571 se = (SGE_SIMPLE32 *) &cfgp->PageBufferSGE; 572 se->Address = req->req_pbuf + CFG_DATA_OFF; 573 MPI_pSGE_SET_LENGTH(se, amt); 574 MPI_pSGE_SET_FLAGS(se, (MPI_SGE_FLAGS_SIMPLE_ELEMENT | 575 MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER | 576 MPI_SGE_FLAGS_END_OF_LIST)); 577 578 cfgp->MsgContext = req->index | 0x80000000; 579 580 mpt_check_doorbell(mpt); 581 mpt_send_cmd(mpt, req); 582 count = 0; 583 do { 584 DELAY(500); 585 mpt_intr(mpt); 586 if (++count == 1000) { 587 mpt_prt(mpt, "read_cfg_page timed out"); 588 return (-1); 589 } 590 } while (req->debug == REQ_ON_CHIP); 591 592 reply = (MSG_CONFIG_REPLY *) MPT_REPLY_PTOV(mpt, req->sequence); 593 if ((reply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) { 594 mpt_prt(mpt, "mpt_read_cfg_page: Config Info Status %x", 595 reply->IOCStatus); 596 mpt_free_reply(mpt, (req->sequence << 1)); 597 return (-1); 598 } 599 mpt_free_reply(mpt, (req->sequence << 1)); 600 #if 0 /* XXXJRT */ 601 bus_dmamap_sync(mpt->request_dmat, mpt->request_dmap, 602 BUS_DMASYNC_POSTREAD); 603 #endif 604 if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT && 605 cfgp->Header.PageNumber == 0) { 606 amt = sizeof (fCONFIG_PAGE_SCSI_PORT_0); 607 } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT && 608 cfgp->Header.PageNumber == 1) { 609 amt = sizeof (fCONFIG_PAGE_SCSI_PORT_1); 610 } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT && 611 cfgp->Header.PageNumber == 2) { 612 amt = sizeof (fCONFIG_PAGE_SCSI_PORT_2); 613 } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE && 614 cfgp->Header.PageNumber == 0) { 615 amt = sizeof (fCONFIG_PAGE_SCSI_DEVICE_0); 616 } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE && 617 cfgp->Header.PageNumber == 1) { 618 amt = sizeof (fCONFIG_PAGE_SCSI_DEVICE_1); 619 } 620 memcpy(hdr, (char *)req->req_vbuf + CFG_DATA_OFF, amt); 621 mpt_free_request(mpt, req); 622 return (0); 623 } 624 625 int 626 mpt_write_cfg_page(mpt_softc_t *mpt, int PageAddress, fCONFIG_PAGE_HEADER *hdr) 627 { 628 int count, hdr_attr; 629 request_t *req; 630 SGE_SIMPLE32 *se; 631 MSG_CONFIG *cfgp; 632 size_t amt; 633 MSG_CONFIG_REPLY *reply; 634 635 req = mpt_get_request(mpt); 636 637 cfgp = req->req_vbuf; 638 bzero(cfgp, sizeof *cfgp); 639 640 hdr_attr = hdr->PageType & MPI_CONFIG_PAGEATTR_MASK; 641 if (hdr_attr != MPI_CONFIG_PAGEATTR_CHANGEABLE && 642 hdr_attr != MPI_CONFIG_PAGEATTR_PERSISTENT) { 643 mpt_prt(mpt, "page type 0x%x not changeable", 644 hdr->PageType & MPI_CONFIG_PAGETYPE_MASK); 645 return (-1); 646 } 647 hdr->PageType &= MPI_CONFIG_PAGETYPE_MASK; 648 649 cfgp->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT; 650 cfgp->Function = MPI_FUNCTION_CONFIG; 651 cfgp->Header = *hdr; 652 amt = (cfgp->Header.PageLength * sizeof (u_int32_t)); 653 cfgp->PageAddress = PageAddress; 654 655 se = (SGE_SIMPLE32 *) &cfgp->PageBufferSGE; 656 se->Address = req->req_pbuf + CFG_DATA_OFF; 657 MPI_pSGE_SET_LENGTH(se, amt); 658 MPI_pSGE_SET_FLAGS(se, (MPI_SGE_FLAGS_SIMPLE_ELEMENT | 659 MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER | 660 MPI_SGE_FLAGS_END_OF_LIST | MPI_SGE_FLAGS_HOST_TO_IOC)); 661 662 cfgp->MsgContext = req->index | 0x80000000; 663 664 if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT && 665 cfgp->Header.PageNumber == 0) { 666 amt = sizeof (fCONFIG_PAGE_SCSI_PORT_0); 667 } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT && 668 cfgp->Header.PageNumber == 1) { 669 amt = sizeof (fCONFIG_PAGE_SCSI_PORT_1); 670 } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT && 671 cfgp->Header.PageNumber == 2) { 672 amt = sizeof (fCONFIG_PAGE_SCSI_PORT_2); 673 } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE && 674 cfgp->Header.PageNumber == 0) { 675 amt = sizeof (fCONFIG_PAGE_SCSI_DEVICE_0); 676 } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE && 677 cfgp->Header.PageNumber == 1) { 678 amt = sizeof (fCONFIG_PAGE_SCSI_DEVICE_1); 679 } 680 memcpy((char *)req->req_vbuf + CFG_DATA_OFF, hdr, amt); 681 /* Restore stripped out attributes */ 682 hdr->PageType |= hdr_attr; 683 684 mpt_check_doorbell(mpt); 685 mpt_send_cmd(mpt, req); 686 count = 0; 687 do { 688 DELAY(500); 689 mpt_intr(mpt); 690 if (++count == 1000) { 691 hdr->PageType |= hdr_attr; 692 mpt_prt(mpt, "mpt_write_cfg_page timed out"); 693 return (-1); 694 } 695 } while (req->debug == REQ_ON_CHIP); 696 697 reply = (MSG_CONFIG_REPLY *) MPT_REPLY_PTOV(mpt, req->sequence); 698 if ((reply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) { 699 mpt_prt(mpt, "mpt_write_cfg_page: Config Info Status %x", 700 reply->IOCStatus); 701 mpt_free_reply(mpt, (req->sequence << 1)); 702 return (-1); 703 } 704 mpt_free_reply(mpt, (req->sequence << 1)); 705 706 mpt_free_request(mpt, req); 707 return (0); 708 } 709 710 /* 711 * Read SCSI configuration information 712 */ 713 static int 714 mpt_read_config_info_spi(mpt_softc_t *mpt) 715 { 716 int rv, i; 717 718 rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_PORT, 0, 719 0, &mpt->mpt_port_page0.Header); 720 if (rv) { 721 return (-1); 722 } 723 if (mpt->verbose > 1) { 724 mpt_prt(mpt, "SPI Port Page 0 Header: %x %x %x %x", 725 mpt->mpt_port_page0.Header.PageVersion, 726 mpt->mpt_port_page0.Header.PageLength, 727 mpt->mpt_port_page0.Header.PageNumber, 728 mpt->mpt_port_page0.Header.PageType); 729 } 730 731 rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_PORT, 1, 732 0, &mpt->mpt_port_page1.Header); 733 if (rv) { 734 return (-1); 735 } 736 if (mpt->verbose > 1) { 737 mpt_prt(mpt, "SPI Port Page 1 Header: %x %x %x %x", 738 mpt->mpt_port_page1.Header.PageVersion, 739 mpt->mpt_port_page1.Header.PageLength, 740 mpt->mpt_port_page1.Header.PageNumber, 741 mpt->mpt_port_page1.Header.PageType); 742 } 743 744 rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_PORT, 2, 745 0, &mpt->mpt_port_page2.Header); 746 if (rv) { 747 return (-1); 748 } 749 750 if (mpt->verbose > 1) { 751 mpt_prt(mpt, "SPI Port Page 2 Header: %x %x %x %x", 752 mpt->mpt_port_page1.Header.PageVersion, 753 mpt->mpt_port_page1.Header.PageLength, 754 mpt->mpt_port_page1.Header.PageNumber, 755 mpt->mpt_port_page1.Header.PageType); 756 } 757 758 for (i = 0; i < 16; i++) { 759 rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_DEVICE, 760 0, i, &mpt->mpt_dev_page0[i].Header); 761 if (rv) { 762 return (-1); 763 } 764 if (mpt->verbose > 1) { 765 mpt_prt(mpt, 766 "SPI Target %d Device Page 0 Header: %x %x %x %x", 767 i, mpt->mpt_dev_page0[i].Header.PageVersion, 768 mpt->mpt_dev_page0[i].Header.PageLength, 769 mpt->mpt_dev_page0[i].Header.PageNumber, 770 mpt->mpt_dev_page0[i].Header.PageType); 771 } 772 773 rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_DEVICE, 774 1, i, &mpt->mpt_dev_page1[i].Header); 775 if (rv) { 776 return (-1); 777 } 778 if (mpt->verbose > 1) { 779 mpt_prt(mpt, 780 "SPI Target %d Device Page 1 Header: %x %x %x %x", 781 i, mpt->mpt_dev_page1[i].Header.PageVersion, 782 mpt->mpt_dev_page1[i].Header.PageLength, 783 mpt->mpt_dev_page1[i].Header.PageNumber, 784 mpt->mpt_dev_page1[i].Header.PageType); 785 } 786 } 787 788 /* 789 * At this point, we don't *have* to fail. As long as we have 790 * valid config header information, we can (barely) lurch 791 * along. 792 */ 793 794 rv = mpt_read_cfg_page(mpt, 0, &mpt->mpt_port_page0.Header); 795 if (rv) { 796 mpt_prt(mpt, "failed to read SPI Port Page 0"); 797 } else if (mpt->verbose > 1) { 798 mpt_prt(mpt, 799 "SPI Port Page 0: Capabilities %x PhysicalInterface %x", 800 mpt->mpt_port_page0.Capabilities, 801 mpt->mpt_port_page0.PhysicalInterface); 802 } 803 804 rv = mpt_read_cfg_page(mpt, 0, &mpt->mpt_port_page1.Header); 805 if (rv) { 806 mpt_prt(mpt, "failed to read SPI Port Page 1"); 807 } else if (mpt->verbose > 1) { 808 mpt_prt(mpt, 809 "SPI Port Page 1: Configuration %x OnBusTimerValue %x", 810 mpt->mpt_port_page1.Configuration, 811 mpt->mpt_port_page1.OnBusTimerValue); 812 } 813 814 rv = mpt_read_cfg_page(mpt, 0, &mpt->mpt_port_page2.Header); 815 if (rv) { 816 mpt_prt(mpt, "failed to read SPI Port Page 2"); 817 } else if (mpt->verbose > 1) { 818 mpt_prt(mpt, 819 "SPI Port Page 2: Flags %x Settings %x", 820 mpt->mpt_port_page2.PortFlags, 821 mpt->mpt_port_page2.PortSettings); 822 for (i = 0; i < 16; i++) { 823 mpt_prt(mpt, 824 "SPI Port Page 2 Tgt %d: timo %x SF %x Flags %x", 825 i, mpt->mpt_port_page2.DeviceSettings[i].Timeout, 826 mpt->mpt_port_page2.DeviceSettings[i].SyncFactor, 827 mpt->mpt_port_page2.DeviceSettings[i].DeviceFlags); 828 } 829 } 830 831 for (i = 0; i < 16; i++) { 832 rv = mpt_read_cfg_page(mpt, i, &mpt->mpt_dev_page0[i].Header); 833 if (rv) { 834 mpt_prt(mpt, "cannot read SPI Tgt %d Device Page 0", i); 835 continue; 836 } 837 if (mpt->verbose > 1) { 838 mpt_prt(mpt, 839 "SPI Tgt %d Page 0: NParms %x Information %x", 840 i, mpt->mpt_dev_page0[i].NegotiatedParameters, 841 mpt->mpt_dev_page0[i].Information); 842 } 843 rv = mpt_read_cfg_page(mpt, i, &mpt->mpt_dev_page1[i].Header); 844 if (rv) { 845 mpt_prt(mpt, "cannot read SPI Tgt %d Device Page 1", i); 846 continue; 847 } 848 if (mpt->verbose > 1) { 849 mpt_prt(mpt, 850 "SPI Tgt %d Page 1: RParms %x Configuration %x", 851 i, mpt->mpt_dev_page1[i].RequestedParameters, 852 mpt->mpt_dev_page1[i].Configuration); 853 } 854 } 855 return (0); 856 } 857 858 /* 859 * Validate SPI configuration information. 860 * 861 * In particular, validate SPI Port Page 1. 862 */ 863 static int 864 mpt_set_initial_config_spi(mpt_softc_t *mpt) 865 { 866 int i, pp1val = ((1 << mpt->mpt_ini_id) << 16) | mpt->mpt_ini_id; 867 868 mpt->mpt_disc_enable = 0xff; 869 mpt->mpt_tag_enable = 0; 870 871 if (mpt->mpt_port_page1.Configuration != pp1val) { 872 fCONFIG_PAGE_SCSI_PORT_1 tmp; 873 mpt_prt(mpt, 874 "SPI Port Page 1 Config value bad (%x)- should be %x", 875 mpt->mpt_port_page1.Configuration, pp1val); 876 tmp = mpt->mpt_port_page1; 877 tmp.Configuration = pp1val; 878 if (mpt_write_cfg_page(mpt, 0, &tmp.Header)) { 879 return (-1); 880 } 881 if (mpt_read_cfg_page(mpt, 0, &tmp.Header)) { 882 return (-1); 883 } 884 if (tmp.Configuration != pp1val) { 885 mpt_prt(mpt, 886 "failed to reset SPI Port Page 1 Config value"); 887 return (-1); 888 } 889 mpt->mpt_port_page1 = tmp; 890 } 891 892 for (i = 0; i < 16; i++) { 893 fCONFIG_PAGE_SCSI_DEVICE_1 tmp; 894 tmp = mpt->mpt_dev_page1[i]; 895 tmp.RequestedParameters = 0; 896 tmp.Configuration = 0; 897 if (mpt->verbose > 1) { 898 mpt_prt(mpt, 899 "Set Tgt %d SPI DevicePage 1 values to %x 0 %x", 900 i, tmp.RequestedParameters, tmp.Configuration); 901 } 902 if (mpt_write_cfg_page(mpt, i, &tmp.Header)) { 903 return (-1); 904 } 905 if (mpt_read_cfg_page(mpt, i, &tmp.Header)) { 906 return (-1); 907 } 908 mpt->mpt_dev_page1[i] = tmp; 909 if (mpt->verbose > 1) { 910 mpt_prt(mpt, 911 "SPI Tgt %d Page 1: RParm %x Configuration %x", i, 912 mpt->mpt_dev_page1[i].RequestedParameters, 913 mpt->mpt_dev_page1[i].Configuration); 914 } 915 } 916 return (0); 917 } 918 919 /* 920 * Enable IOC port 921 */ 922 static int 923 mpt_send_port_enable(mpt_softc_t *mpt, int port) 924 { 925 int count; 926 request_t *req; 927 MSG_PORT_ENABLE *enable_req; 928 929 req = mpt_get_request(mpt); 930 931 enable_req = req->req_vbuf; 932 bzero(enable_req, sizeof *enable_req); 933 934 enable_req->Function = MPI_FUNCTION_PORT_ENABLE; 935 enable_req->MsgContext = req->index | 0x80000000; 936 enable_req->PortNumber = port; 937 938 mpt_check_doorbell(mpt); 939 if (mpt->verbose > 1) { 940 mpt_prt(mpt, "enabling port %d", port); 941 } 942 mpt_send_cmd(mpt, req); 943 944 count = 0; 945 do { 946 DELAY(500); 947 mpt_intr(mpt); 948 if (++count == 100000) { 949 mpt_prt(mpt, "port enable timed out"); 950 return (-1); 951 } 952 } while (req->debug == REQ_ON_CHIP); 953 mpt_free_request(mpt, req); 954 return (0); 955 } 956 957 /* 958 * Enable/Disable asynchronous event reporting. 959 * 960 * NB: this is the first command we send via shared memory 961 * instead of the handshake register. 962 */ 963 static int 964 mpt_send_event_request(mpt_softc_t *mpt, int onoff) 965 { 966 request_t *req; 967 MSG_EVENT_NOTIFY *enable_req; 968 969 req = mpt_get_request(mpt); 970 971 enable_req = req->req_vbuf; 972 bzero(enable_req, sizeof *enable_req); 973 974 enable_req->Function = MPI_FUNCTION_EVENT_NOTIFICATION; 975 enable_req->MsgContext = req->index | 0x80000000; 976 enable_req->Switch = onoff; 977 978 mpt_check_doorbell(mpt); 979 if (mpt->verbose > 1) { 980 mpt_prt(mpt, "%sabling async events", onoff? "en" : "dis"); 981 } 982 mpt_send_cmd(mpt, req); 983 984 return (0); 985 } 986 987 /* 988 * Un-mask the interrupts on the chip. 989 */ 990 void 991 mpt_enable_ints(mpt_softc_t *mpt) 992 { 993 /* Unmask every thing except door bell int */ 994 mpt_write(mpt, MPT_OFFSET_INTR_MASK, MPT_INTR_DB_MASK); 995 } 996 997 /* 998 * Mask the interrupts on the chip. 999 */ 1000 void 1001 mpt_disable_ints(mpt_softc_t *mpt) 1002 { 1003 /* Mask all interrupts */ 1004 mpt_write(mpt, MPT_OFFSET_INTR_MASK, 1005 MPT_INTR_REPLY_MASK | MPT_INTR_DB_MASK); 1006 } 1007 1008 /* (Re)Initialize the chip for use */ 1009 int 1010 mpt_hw_init(mpt_softc_t *mpt) 1011 { 1012 u_int32_t db; 1013 int try; 1014 1015 /* 1016 * Start by making sure we're not at FAULT or RESET state 1017 */ 1018 for (try = 0; try < MPT_MAX_TRYS; try++) { 1019 1020 db = mpt_rd_db(mpt); 1021 1022 switch (MPT_STATE(db)) { 1023 case MPT_DB_STATE_READY: 1024 return (0); 1025 1026 default: 1027 /* if peer has already reset us, don't do it again! */ 1028 if (MPT_WHO(db) == MPT_DB_INIT_PCIPEER) 1029 return (0); 1030 /*FALLTHRU*/ 1031 case MPT_DB_STATE_RESET: 1032 case MPT_DB_STATE_FAULT: 1033 if (mpt_reset(mpt) != MPT_OK) { 1034 DELAY(10000); 1035 continue; 1036 } 1037 break; 1038 } 1039 } 1040 return (EIO); 1041 } 1042 1043 int 1044 mpt_init(mpt_softc_t *mpt, u_int32_t who) 1045 { 1046 int try; 1047 MSG_IOC_FACTS_REPLY facts; 1048 MSG_PORT_FACTS_REPLY pfp; 1049 u_int32_t pptr; 1050 int val; 1051 1052 /* Put all request buffers (back) on the free list */ 1053 SLIST_INIT(&mpt->request_free_list); 1054 for (val = 0; val < MPT_MAX_REQUESTS(mpt); val++) { 1055 mpt_free_request(mpt, &mpt->request_pool[val]); 1056 } 1057 1058 if (mpt->verbose > 1) { 1059 mpt_prt(mpt, "doorbell req = %s", 1060 mpt_ioc_diag(mpt_read(mpt, MPT_OFFSET_DOORBELL))); 1061 } 1062 1063 /* 1064 * Start by making sure we're not at FAULT or RESET state 1065 */ 1066 if (mpt_hw_init(mpt) != 0) 1067 return (EIO); 1068 1069 for (try = 0; try < MPT_MAX_TRYS; try++) { 1070 /* 1071 * No need to reset if the IOC is already in the READY state. 1072 */ 1073 1074 if (mpt_get_iocfacts(mpt, &facts) != MPT_OK) { 1075 mpt_prt(mpt, "mpt_get_iocfacts failed"); 1076 continue; 1077 } 1078 1079 if (mpt->verbose > 1) { 1080 mpt_prt(mpt, 1081 "IOCFACTS: GlobalCredits=%d BlockSize=%u " 1082 "Request Frame Size %u\n", facts.GlobalCredits, 1083 facts.BlockSize, facts.RequestFrameSize); 1084 } 1085 mpt->mpt_max_devices = facts.MaxDevices; 1086 mpt->mpt_global_credits = facts.GlobalCredits; 1087 mpt->request_frame_size = facts.RequestFrameSize; 1088 1089 if (mpt_get_portfacts(mpt, &pfp) != MPT_OK) { 1090 mpt_prt(mpt, "mpt_get_portfacts failed"); 1091 continue; 1092 } 1093 1094 if (mpt->verbose > 1) { 1095 mpt_prt(mpt, 1096 "PORTFACTS: Type %x PFlags %x IID %d MaxDev %d\n", 1097 pfp.PortType, pfp.ProtocolFlags, pfp.PortSCSIID, 1098 pfp.MaxDevices); 1099 } 1100 1101 if (!(pfp.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR)) { 1102 mpt_prt(mpt, "initiator role unsupported"); 1103 return (ENXIO); 1104 } 1105 1106 switch (pfp.PortType) { 1107 case MPI_PORTFACTS_PORTTYPE_FC: 1108 mpt->is_fc = 1; 1109 mpt->mpt_max_devices = 255; 1110 break; 1111 case MPI_PORTFACTS_PORTTYPE_SCSI: 1112 mpt->is_scsi = 1; 1113 /* some SPI controllers (VMWare, Sun) lie */ 1114 mpt->mpt_max_devices = 16; 1115 break; 1116 case MPI_PORTFACTS_PORTTYPE_SAS: 1117 mpt->is_sas = 1; 1118 break; 1119 default: 1120 mpt_prt(mpt, "Unsupported Port Type (%x)", 1121 pfp.PortType); 1122 return (ENXIO); 1123 } 1124 1125 mpt->mpt_ini_id = pfp.PortSCSIID; 1126 1127 if (mpt_send_ioc_init(mpt, who) != MPT_OK) { 1128 mpt_prt(mpt, "mpt_send_ioc_init failed"); 1129 continue; 1130 } 1131 1132 if (mpt->verbose > 1) { 1133 mpt_prt(mpt, "mpt_send_ioc_init ok"); 1134 } 1135 1136 if (mpt_wait_state(mpt, MPT_DB_STATE_RUNNING) != MPT_OK) { 1137 mpt_prt(mpt, "IOC failed to go to run state"); 1138 continue; 1139 } 1140 if (mpt->verbose > 1) { 1141 mpt_prt(mpt, "IOC now at RUNSTATE"); 1142 } 1143 1144 /* 1145 * Give it reply buffers 1146 * 1147 * Do *not* except global credits. 1148 */ 1149 for (val = 0, pptr = mpt->reply_phys; 1150 (pptr + MPT_REPLY_SIZE) < (mpt->reply_phys + PAGE_SIZE); 1151 pptr += MPT_REPLY_SIZE) { 1152 mpt_free_reply(mpt, pptr); 1153 if (++val == mpt->mpt_global_credits - 1) 1154 break; 1155 } 1156 1157 /* 1158 * Enable asynchronous event reporting 1159 */ 1160 mpt_send_event_request(mpt, 1); 1161 1162 1163 /* 1164 * Read set up initial configuration information 1165 * (SPI only for now) 1166 */ 1167 1168 if (mpt->is_scsi) { 1169 if (mpt_read_config_info_spi(mpt)) { 1170 return (EIO); 1171 } 1172 if (mpt_set_initial_config_spi(mpt)) { 1173 return (EIO); 1174 } 1175 } 1176 1177 /* 1178 * Now enable the port 1179 */ 1180 if (mpt_send_port_enable(mpt, 0) != MPT_OK) { 1181 mpt_prt(mpt, "failed to enable port 0"); 1182 continue; 1183 } 1184 1185 if (mpt->verbose > 1) { 1186 mpt_prt(mpt, "enabled port 0"); 1187 } 1188 1189 /* Everything worked */ 1190 break; 1191 } 1192 1193 if (try >= MPT_MAX_TRYS) { 1194 mpt_prt(mpt, "failed to initialize IOC"); 1195 return (EIO); 1196 } 1197 1198 if (mpt->verbose > 1) { 1199 mpt_prt(mpt, "enabling interrupts"); 1200 } 1201 1202 mpt_enable_ints(mpt); 1203 return (0); 1204 } 1205