mpt.c revision 102199
1101704Smjacob/* $FreeBSD: head/sys/dev/mpt/mpt.c 102199 2002-08-20 23:04:08Z mjacob $ */ 2101704Smjacob/* 3101704Smjacob * Generic routines for LSI '909 FC adapters. 4101704Smjacob * FreeBSD Version. 5101704Smjacob * 6101704Smjacob * Copyright (c) 2000, 2001 by Greg Ansley 7101704Smjacob * 8101704Smjacob * Redistribution and use in source and binary forms, with or without 9101704Smjacob * modification, are permitted provided that the following conditions 10101704Smjacob * are met: 11101704Smjacob * 1. Redistributions of source code must retain the above copyright 12101704Smjacob * notice immediately at the beginning of the file, without modification, 13101704Smjacob * this list of conditions, and the following disclaimer. 14101704Smjacob * 2. The name of the author may not be used to endorse or promote products 15101704Smjacob * derived from this software without specific prior written permission. 16101704Smjacob * 17101704Smjacob * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18101704Smjacob * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19101704Smjacob * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20101704Smjacob * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 21101704Smjacob * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22101704Smjacob * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23101704Smjacob * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24101704Smjacob * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25101704Smjacob * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26101704Smjacob * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27101704Smjacob * SUCH DAMAGE. 28101704Smjacob */ 29101704Smjacob/* 30101704Smjacob * Additional Copyright (c) 2002 by Matthew Jacob under same license. 31101704Smjacob */ 32101704Smjacob 33101704Smjacob#include <dev/mpt/mpt_freebsd.h> 34102199Smjacob 35101704Smjacob#define MPT_MAX_TRYS 3 36101704Smjacob#define MPT_MAX_WAIT 300000 37101704Smjacob 38101704Smjacobstatic int maxwait_ack = 0; 39101704Smjacobstatic int maxwait_int = 0; 40101704Smjacobstatic int maxwait_state = 0; 41101704Smjacob 42102199Smjacobstatic __inline u_int32_t mpt_rd_db(mpt_softc_t *mpt); 43102199Smjacobstatic __inline u_int32_t mpt_rd_intr(mpt_softc_t *mpt); 44101704Smjacob 45101704Smjacobstatic __inline u_int32_t 46102199Smjacobmpt_rd_db(mpt_softc_t *mpt) 47101704Smjacob{ 48101704Smjacob return mpt_read(mpt, MPT_OFFSET_DOORBELL); 49101704Smjacob} 50101704Smjacob 51101704Smjacobstatic __inline u_int32_t 52102199Smjacobmpt_rd_intr(mpt_softc_t *mpt) 53101704Smjacob{ 54101704Smjacob return mpt_read(mpt, MPT_OFFSET_INTR_STATUS); 55101704Smjacob} 56101704Smjacob 57101704Smjacob/* Busy wait for a door bell to be read by IOC */ 58101704Smjacobstatic int 59102199Smjacobmpt_wait_db_ack(mpt_softc_t *mpt) 60101704Smjacob{ 61101704Smjacob int i; 62101704Smjacob for (i=0; i < MPT_MAX_WAIT; i++) { 63101704Smjacob if (!MPT_DB_IS_BUSY(mpt_rd_intr(mpt))) { 64101704Smjacob maxwait_ack = i > maxwait_ack ? i : maxwait_ack; 65101704Smjacob return MPT_OK; 66101704Smjacob } 67101704Smjacob 68101704Smjacob DELAY(100); 69101704Smjacob } 70101704Smjacob return MPT_FAIL; 71101704Smjacob} 72101704Smjacob 73101704Smjacob/* Busy wait for a door bell interrupt */ 74101704Smjacobstatic int 75102199Smjacobmpt_wait_db_int(mpt_softc_t *mpt) 76101704Smjacob{ 77101704Smjacob int i; 78101704Smjacob for (i=0; i < MPT_MAX_WAIT; i++) { 79101704Smjacob if (MPT_DB_INTR(mpt_rd_intr(mpt))) { 80101704Smjacob maxwait_int = i > maxwait_int ? i : maxwait_int; 81101704Smjacob return MPT_OK; 82101704Smjacob } 83101704Smjacob DELAY(100); 84101704Smjacob } 85101704Smjacob return MPT_FAIL; 86101704Smjacob} 87101704Smjacob 88101704Smjacob/* Wait for IOC to transition to a give state */ 89101704Smjacobvoid 90102199Smjacobmpt_check_doorbell(mpt_softc_t *mpt) 91101704Smjacob{ 92101704Smjacob u_int32_t db = mpt_rd_db(mpt); 93101704Smjacob if (MPT_STATE(db) != MPT_DB_STATE_RUNNING) { 94101704Smjacob device_printf(mpt->dev, "Device not running!\n"); 95101704Smjacob mpt_print_db(db); 96101704Smjacob } 97101704Smjacob} 98101704Smjacob 99101704Smjacob/* Wait for IOC to transition to a give state */ 100101704Smjacobstatic int 101102199Smjacobmpt_wait_state(mpt_softc_t *mpt, enum DB_STATE_BITS state) 102101704Smjacob{ 103101704Smjacob int i; 104101704Smjacob 105101704Smjacob for (i = 0; i < MPT_MAX_WAIT; i++) { 106101704Smjacob u_int32_t db = mpt_rd_db(mpt); 107101704Smjacob if (MPT_STATE(db) == state) { 108101704Smjacob maxwait_state = i > maxwait_state ? i : maxwait_state; 109101704Smjacob return (MPT_OK); 110101704Smjacob } 111101704Smjacob DELAY(100); 112101704Smjacob } 113101704Smjacob return (MPT_FAIL); 114101704Smjacob} 115101704Smjacob 116101704Smjacob 117101704Smjacob/* Issue the reset COMMAND to the IOC */ 118101704Smjacobint 119102199Smjacobmpt_soft_reset(mpt_softc_t *mpt) 120101704Smjacob{ 121101704Smjacob if (mpt->verbose) { 122101704Smjacob device_printf(mpt->dev,"soft reset\n"); 123101704Smjacob } 124101704Smjacob 125101704Smjacob /* Have to use hard reset if we are not in Running state */ 126101704Smjacob if (MPT_STATE(mpt_rd_db(mpt)) != MPT_DB_STATE_RUNNING) { 127101704Smjacob device_printf(mpt->dev, 128101704Smjacob "soft reset failed: device not running\n"); 129101704Smjacob return MPT_FAIL; 130101704Smjacob } 131101704Smjacob 132101704Smjacob /* If door bell is in use we don't have a chance of getting 133101704Smjacob * a word in since the IOC probably crashed in message 134101704Smjacob * processing. So don't waste our time. 135101704Smjacob */ 136101704Smjacob if (MPT_DB_IS_IN_USE(mpt_rd_db(mpt))) { 137101704Smjacob device_printf(mpt->dev, "soft reset failed: doorbell wedged\n"); 138101704Smjacob return MPT_FAIL; 139101704Smjacob } 140101704Smjacob 141101704Smjacob /* Send the reset request to the IOC */ 142101704Smjacob mpt_write(mpt, MPT_OFFSET_DOORBELL, 143101704Smjacob MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET << MPI_DOORBELL_FUNCTION_SHIFT); 144101704Smjacob if (mpt_wait_db_ack(mpt) != MPT_OK) { 145101704Smjacob device_printf(mpt->dev, "soft reset failed: ack timeout\n"); 146101704Smjacob return MPT_FAIL; 147101704Smjacob } 148101704Smjacob 149101704Smjacob /* Wait for the IOC to reload and come out of reset state */ 150101704Smjacob if (mpt_wait_state(mpt, MPT_DB_STATE_READY) != MPT_OK) { 151101704Smjacob device_printf(mpt->dev, 152101704Smjacob "soft reset failed: device did not start running\n"); 153101704Smjacob return MPT_FAIL; 154101704Smjacob } 155101704Smjacob 156101704Smjacob return MPT_OK; 157101704Smjacob} 158101704Smjacob 159101704Smjacob/* This is a magic diagnostic reset that resets all the ARM 160101704Smjacob * processors in the chip. 161101704Smjacob */ 162101704Smjacobvoid 163102199Smjacobmpt_hard_reset(mpt_softc_t *mpt) 164101704Smjacob{ 165101704Smjacob /* This extra read comes for the Linux source 166101704Smjacob * released by LSI. It's function is undocumented! 167101704Smjacob */ 168101704Smjacob if (mpt->verbose) { 169101704Smjacob device_printf(mpt->dev, "hard reset\n"); 170101704Smjacob } 171101704Smjacob mpt_read(mpt, MPT_OFFSET_FUBAR); 172101704Smjacob 173101704Smjacob /* Enable diagnostic registers */ 174101704Smjacob mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_1); 175101704Smjacob mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_2); 176101704Smjacob mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_3); 177101704Smjacob mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_4); 178101704Smjacob mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_5); 179101704Smjacob 180101704Smjacob /* Diag. port is now active so we can now hit the reset bit */ 181101704Smjacob mpt_write(mpt, MPT_OFFSET_DIAGNOSTIC, MPT_DIAG_RESET_IOC); 182101704Smjacob 183101704Smjacob DELAY(10000); 184101704Smjacob 185101704Smjacob /* Disable Diagnostic Register */ 186101704Smjacob mpt_write(mpt, MPT_OFFSET_SEQUENCE, 0xFF); 187101704Smjacob 188101704Smjacob /* Restore the config register values */ 189101704Smjacob /* Hard resets are known to screw up the BAR for diagnostic 190101704Smjacob memory accesses (Mem1). */ 191101704Smjacob mpt_set_config_regs(mpt); 192101704Smjacob if (mpt->mpt2 != NULL) { 193101704Smjacob mpt_set_config_regs(mpt->mpt2); 194101704Smjacob } 195101704Smjacob 196101704Smjacob /* Note that if there is no valid firmware to run, the doorbell will 197101704Smjacob remain in the reset state (0x00000000) */ 198101704Smjacob} 199101704Smjacob 200101704Smjacob/* 201101704Smjacob * Reset the IOC when needed. Try software command first then if needed 202101704Smjacob * poke at the magic diagnostic reset. Note that a hard reset resets 203101704Smjacob * *both* IOCs on dual function chips (FC929 && LSI1030) as well as 204101704Smjacob * fouls up the PCI configuration registers. 205101704Smjacob */ 206101704Smjacobint 207102199Smjacobmpt_reset(mpt_softc_t *mpt) 208101704Smjacob{ 209101704Smjacob int ret; 210101704Smjacob 211101704Smjacob /* Try a soft reset */ 212101704Smjacob if ((ret = mpt_soft_reset(mpt)) != MPT_OK) { 213101704Smjacob /* Failed; do a hard reset */ 214101704Smjacob mpt_hard_reset(mpt); 215101704Smjacob 216101704Smjacob /* Wait for the IOC to reload and come out of reset state */ 217101704Smjacob ret = mpt_wait_state(mpt, MPT_DB_STATE_READY); 218101704Smjacob if (ret != MPT_OK) { 219101704Smjacob device_printf(mpt->dev, "failed to reset device\n"); 220101704Smjacob } 221101704Smjacob } 222101704Smjacob 223101704Smjacob return ret; 224101704Smjacob} 225101704Smjacob 226101704Smjacob/* Return a command buffer to the free queue */ 227101704Smjacobvoid 228102199Smjacobmpt_free_request(mpt_softc_t *mpt, request_t *req) 229101704Smjacob{ 230101704Smjacob if (req == NULL || req != &mpt->requests[req->index]) { 231101704Smjacob panic("mpt_free_request bad req ptr\n"); 232101704Smjacob return; 233101704Smjacob } 234101704Smjacob req->ccb = NULL; 235101704Smjacob req->debug = REQ_FREE; 236101704Smjacob SLIST_INSERT_HEAD(&mpt->request_free_list, req, link); 237101704Smjacob} 238101704Smjacob 239101704Smjacob/* Get a command buffer from the free queue */ 240101704Smjacobrequest_t * 241102199Smjacobmpt_get_request(mpt_softc_t *mpt) 242101704Smjacob{ 243101704Smjacob request_t *req; 244101704Smjacob req = SLIST_FIRST(&mpt->request_free_list); 245101704Smjacob if (req != NULL) { 246101704Smjacob if (req != &mpt->requests[req->index]) { 247101704Smjacob panic("mpt_get_request: corrupted request free list\n"); 248101704Smjacob } 249101704Smjacob if (req->ccb != NULL) { 250101704Smjacob panic("mpt_get_request: corrupted request free list (ccb)\n"); 251101704Smjacob } 252101704Smjacob SLIST_REMOVE_HEAD(&mpt->request_free_list, link); 253101704Smjacob req->debug = REQ_IN_PROGRESS; 254101704Smjacob } 255101704Smjacob return req; 256101704Smjacob} 257101704Smjacob 258101704Smjacob/* Pass the command to the IOC */ 259101704Smjacobvoid 260102199Smjacobmpt_send_cmd(mpt_softc_t *mpt, request_t *req) 261101704Smjacob{ 262101704Smjacob req->sequence = mpt->sequence++; 263101704Smjacob if (mpt->verbose > 1) { 264101704Smjacob u_int32_t *pReq; 265101704Smjacob pReq = req->req_vbuf; 266101704Smjacob device_printf(mpt->dev, "Send Request %d (0x%x):\n", 267101704Smjacob req->index, req->req_pbuf); 268101704Smjacob device_printf(mpt->dev, "%08X %08X %08X %08X\n", 269101704Smjacob pReq[0], pReq[1], pReq[2], pReq[3]); 270101704Smjacob device_printf(mpt->dev, "%08X %08X %08X %08X\n", 271101704Smjacob pReq[4], pReq[5], pReq[6], pReq[7]); 272101704Smjacob device_printf(mpt->dev, "%08X %08X %08X %08X\n", 273101704Smjacob pReq[8], pReq[9], pReq[10], pReq[11]); 274101704Smjacob device_printf(mpt->dev, "%08X %08X %08X %08X\n", 275101704Smjacob pReq[12], pReq[13], pReq[14], pReq[15]); 276101704Smjacob } 277101704Smjacob bus_dmamap_sync(mpt->request_dmat, mpt->request_dmap, 278101704Smjacob BUS_DMASYNC_PREWRITE); 279101704Smjacob req->debug = REQ_ON_CHIP; 280101704Smjacob mpt_write(mpt, MPT_OFFSET_REQUEST_Q, (u_int32_t) req->req_pbuf); 281101704Smjacob} 282101704Smjacob 283101704Smjacob/* 284101704Smjacob * Give the reply buffer back to the IOC after we have 285101704Smjacob * finished processing it. 286101704Smjacob */ 287101704Smjacobvoid 288102199Smjacobmpt_free_reply(mpt_softc_t *mpt, u_int32_t ptr) 289101704Smjacob{ 290101704Smjacob mpt_write(mpt, MPT_OFFSET_REPLY_Q, ptr); 291101704Smjacob} 292101704Smjacob 293101704Smjacob/* Get a reply from the IOC */ 294101704Smjacobu_int32_t 295102199Smjacobmpt_pop_reply_queue(mpt_softc_t *mpt) 296101704Smjacob{ 297101704Smjacob return mpt_read(mpt, MPT_OFFSET_REPLY_Q); 298101704Smjacob} 299101704Smjacob 300101704Smjacob/* 301101704Smjacob * Send a command to the IOC via the handshake register. 302101704Smjacob * 303101704Smjacob * Only done at initialization time and for certain unusual 304101704Smjacob * commands such as device/bus reset as specified by LSI. 305101704Smjacob */ 306101704Smjacobint 307102199Smjacobmpt_send_handshake_cmd(mpt_softc_t *mpt, size_t len, void *cmd) 308101704Smjacob{ 309101704Smjacob int i; 310101704Smjacob u_int32_t data, *data32; 311101704Smjacob 312101704Smjacob /* Check condition of the IOC */ 313101704Smjacob data = mpt_rd_db(mpt); 314101704Smjacob if (((MPT_STATE(data) != MPT_DB_STATE_READY) && 315101704Smjacob (MPT_STATE(data) != MPT_DB_STATE_RUNNING) && 316101704Smjacob (MPT_STATE(data) != MPT_DB_STATE_FAULT)) || 317101704Smjacob ( MPT_DB_IS_IN_USE(data) )) { 318101704Smjacob device_printf(mpt->dev, 319101704Smjacob "handshake aborted due to invalid doorbell state\n"); 320101704Smjacob mpt_print_db(data); 321101704Smjacob return(EBUSY); 322101704Smjacob } 323101704Smjacob 324101704Smjacob /* We move things in 32 bit chunks */ 325101704Smjacob len = (len + 3) >> 2; 326101704Smjacob data32 = cmd; 327101704Smjacob 328101704Smjacob /* Clear any left over pending doorbell interupts */ 329101704Smjacob if (MPT_DB_INTR(mpt_rd_intr(mpt))) 330101704Smjacob mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0); 331101704Smjacob 332101704Smjacob /* 333101704Smjacob * Tell the handshake reg. we are going to send a command 334101704Smjacob * and how long it is going to be. 335101704Smjacob */ 336101704Smjacob data = (MPI_FUNCTION_HANDSHAKE << MPI_DOORBELL_FUNCTION_SHIFT) | 337101704Smjacob (len << MPI_DOORBELL_ADD_DWORDS_SHIFT); 338101704Smjacob mpt_write(mpt, MPT_OFFSET_DOORBELL, data); 339101704Smjacob 340101704Smjacob /* Wait for the chip to notice */ 341101704Smjacob if (mpt_wait_db_int(mpt) != MPT_OK) { 342101704Smjacob device_printf(mpt->dev, "mpt_send_handshake_cmd timeout1!\n"); 343101704Smjacob return ETIMEDOUT; 344101704Smjacob } 345101704Smjacob 346101704Smjacob /* Clear the interrupt */ 347101704Smjacob mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0); 348101704Smjacob 349101704Smjacob if (mpt_wait_db_ack(mpt) != MPT_OK) { 350101704Smjacob device_printf(mpt->dev, "mpt_send_handshake_cmd timeout2!\n"); 351101704Smjacob return ETIMEDOUT; 352101704Smjacob } 353101704Smjacob 354101704Smjacob /* Send the command */ 355101704Smjacob for (i = 0; i < len; i++) { 356101704Smjacob mpt_write(mpt, MPT_OFFSET_DOORBELL, *data32++); 357101704Smjacob if (mpt_wait_db_ack(mpt) != MPT_OK) { 358101704Smjacob device_printf(mpt->dev, 359101704Smjacob "mpt_send_handshake_cmd timeout! index = %d\n", i); 360101704Smjacob return ETIMEDOUT; 361101704Smjacob } 362101704Smjacob } 363101704Smjacob return MPT_OK; 364101704Smjacob} 365101704Smjacob 366101704Smjacob/* Get the response from the handshake register */ 367101704Smjacobint 368102199Smjacobmpt_recv_handshake_reply(mpt_softc_t *mpt, size_t reply_len, void *reply) 369101704Smjacob{ 370101704Smjacob int left, reply_left; 371101704Smjacob u_int16_t *data16; 372101704Smjacob MSG_DEFAULT_REPLY *hdr; 373101704Smjacob 374101704Smjacob /* We move things out in 16 bit chunks */ 375101704Smjacob reply_len >>= 1; 376101704Smjacob data16 = (u_int16_t *)reply; 377101704Smjacob 378101704Smjacob hdr = (MSG_DEFAULT_REPLY *)reply; 379101704Smjacob 380101704Smjacob /* Get first word */ 381101704Smjacob if (mpt_wait_db_int(mpt) != MPT_OK) { 382101704Smjacob device_printf(mpt->dev, "mpt_recv_handshake_cmd timeout1!\n"); 383101704Smjacob return ETIMEDOUT; 384101704Smjacob } 385101704Smjacob *data16++ = mpt_read(mpt, MPT_OFFSET_DOORBELL) & MPT_DB_DATA_MASK; 386101704Smjacob mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0); 387101704Smjacob 388101704Smjacob /* Get Second Word */ 389101704Smjacob if (mpt_wait_db_int(mpt) != MPT_OK) { 390101704Smjacob device_printf(mpt->dev, "mpt_recv_handshake_cmd timeout2!\n"); 391101704Smjacob return ETIMEDOUT; 392101704Smjacob } 393101704Smjacob *data16++ = mpt_read(mpt, MPT_OFFSET_DOORBELL) & MPT_DB_DATA_MASK; 394101704Smjacob mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0); 395101704Smjacob 396101704Smjacob /* With the second word, we can now look at the length */ 397101704Smjacob if (mpt->verbose > 1 && ((reply_len >> 1) != hdr->MsgLength)) { 398101704Smjacob device_printf(mpt->dev, 399101704Smjacob "reply length does not match message length: " 400101704Smjacob "got 0x%02x, expected 0x%02x\n", 401101704Smjacob hdr->MsgLength << 2, reply_len << 1); 402101704Smjacob } 403101704Smjacob 404101704Smjacob /* Get rest of the reply; but don't overflow the provided buffer */ 405101704Smjacob left = (hdr->MsgLength << 1) - 2; 406101704Smjacob reply_left = reply_len - 2; 407101704Smjacob while (left--) { 408101704Smjacob u_int16_t datum; 409101704Smjacob 410101704Smjacob if (mpt_wait_db_int(mpt) != MPT_OK) { 411101704Smjacob device_printf(mpt->dev, 412101704Smjacob "mpt_recv_handshake_cmd timeout3!\n"); 413101704Smjacob return ETIMEDOUT; 414101704Smjacob } 415101704Smjacob datum = mpt_read(mpt, MPT_OFFSET_DOORBELL); 416101704Smjacob 417101704Smjacob if (reply_left-- > 0) 418101704Smjacob *data16++ = datum & MPT_DB_DATA_MASK; 419101704Smjacob 420101704Smjacob mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0); 421101704Smjacob } 422101704Smjacob 423101704Smjacob /* One more wait & clear at the end */ 424101704Smjacob if (mpt_wait_db_int(mpt) != MPT_OK) { 425101704Smjacob device_printf(mpt->dev, "mpt_recv_handshake_cmd timeout4!\n"); 426101704Smjacob return ETIMEDOUT; 427101704Smjacob } 428101704Smjacob mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0); 429101704Smjacob 430101704Smjacob if ((hdr->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) { 431101704Smjacob if (mpt->verbose > 1) 432101704Smjacob mpt_print_reply(hdr); 433101704Smjacob return (MPT_FAIL | hdr->IOCStatus); 434101704Smjacob } 435101704Smjacob 436101704Smjacob return (0); 437101704Smjacob} 438101704Smjacob 439101704Smjacobstatic int 440102199Smjacobmpt_get_iocfacts(mpt_softc_t *mpt, MSG_IOC_FACTS_REPLY *freplp) 441101704Smjacob{ 442101704Smjacob MSG_IOC_FACTS f_req; 443101704Smjacob int error; 444101704Smjacob 445101704Smjacob bzero(&f_req, sizeof f_req); 446101704Smjacob f_req.Function = MPI_FUNCTION_IOC_FACTS; 447101704Smjacob f_req.MsgContext = 0x12071942; 448101704Smjacob error = mpt_send_handshake_cmd(mpt, sizeof f_req, &f_req); 449101704Smjacob if (error) 450101704Smjacob return(error); 451101704Smjacob error = mpt_recv_handshake_reply(mpt, sizeof (*freplp), freplp); 452101704Smjacob return (error); 453101704Smjacob} 454101704Smjacob 455102199Smjacobstatic int 456102199Smjacobmpt_get_portfacts(mpt_softc_t *mpt, MSG_PORT_FACTS_REPLY *freplp) 457102199Smjacob{ 458102199Smjacob MSG_PORT_FACTS f_req; 459102199Smjacob int error; 460102199Smjacob 461102199Smjacob /* XXX: Only getting PORT FACTS for Port 0 */ 462102199Smjacob bzero(&f_req, sizeof f_req); 463102199Smjacob f_req.Function = MPI_FUNCTION_PORT_FACTS; 464102199Smjacob f_req.MsgContext = 0x12071943; 465102199Smjacob error = mpt_send_handshake_cmd(mpt, sizeof f_req, &f_req); 466102199Smjacob if (error) 467102199Smjacob return(error); 468102199Smjacob error = mpt_recv_handshake_reply(mpt, sizeof (*freplp), freplp); 469102199Smjacob return (error); 470102199Smjacob} 471102199Smjacob 472101704Smjacob/* 473101704Smjacob * Send the initialization request. This is where we specify how many 474101704Smjacob * SCSI busses and how many devices per bus we wish to emulate. 475101704Smjacob * This is also the command that specifies the max size of the reply 476101704Smjacob * frames from the IOC that we will be allocating. 477101704Smjacob */ 478101704Smjacobstatic int 479102199Smjacobmpt_send_ioc_init(mpt_softc_t *mpt, u_int32_t who) 480101704Smjacob{ 481101704Smjacob int error = 0; 482101704Smjacob MSG_IOC_INIT init; 483101704Smjacob MSG_IOC_INIT_REPLY reply; 484101704Smjacob 485101704Smjacob bzero(&init, sizeof init); 486101704Smjacob init.WhoInit = who; 487101704Smjacob init.Function = MPI_FUNCTION_IOC_INIT; 488101704Smjacob if (mpt->is_fc) { 489101704Smjacob init.MaxDevices = 255; 490101704Smjacob } else { 491101704Smjacob init.MaxDevices = 16; 492101704Smjacob } 493101704Smjacob init.MaxBuses = 1; 494101704Smjacob init.ReplyFrameSize = MPT_REPLY_SIZE; 495101704Smjacob init.MsgContext = 0x12071941; 496101704Smjacob 497101704Smjacob if ((error = mpt_send_handshake_cmd(mpt, sizeof init, &init)) != 0) { 498101704Smjacob return(error); 499101704Smjacob } 500101704Smjacob 501101704Smjacob error = mpt_recv_handshake_reply(mpt, sizeof reply, &reply); 502101704Smjacob return (error); 503101704Smjacob} 504101704Smjacob 505102199Smjacob 506102199Smjacob/* 507102199Smjacob * Utiltity routine to read configuration headers and pages 508102199Smjacob */ 509102199Smjacob 510101704Smjacobstatic int 511102199Smjacobmpt_read_cfg_header(mpt_softc_t *, int, int, int, fCONFIG_PAGE_HEADER *); 512102199Smjacobstatic int 513102199Smjacobmpt_read_cfg_page(mpt_softc_t *, int, fCONFIG_PAGE_HEADER *); 514102199Smjacobstatic int 515102199Smjacobmpt_write_cfg_page(mpt_softc_t *, int, fCONFIG_PAGE_HEADER *); 516102199Smjacob 517102199Smjacobstatic int 518102199Smjacobmpt_read_cfg_header(mpt_softc_t *mpt, int PageType, int PageNumber, 519102199Smjacob int PageAddress, fCONFIG_PAGE_HEADER *rslt) 520101704Smjacob{ 521101704Smjacob int count; 522101704Smjacob request_t *req; 523102199Smjacob MSG_CONFIG *cfgp; 524102199Smjacob MSG_CONFIG_REPLY *reply; 525102199Smjacob 526102199Smjacob req = mpt_get_request(mpt); 527102199Smjacob 528102199Smjacob cfgp = req->req_vbuf; 529102199Smjacob bzero(cfgp, sizeof *cfgp); 530102199Smjacob 531102199Smjacob cfgp->Action = MPI_CONFIG_ACTION_PAGE_HEADER; 532102199Smjacob cfgp->Function = MPI_FUNCTION_CONFIG; 533102199Smjacob cfgp->Header.PageNumber = (U8) PageNumber; 534102199Smjacob cfgp->Header.PageType = (U8) PageType; 535102199Smjacob cfgp->PageAddress = PageAddress; 536102199Smjacob MPI_pSGE_SET_FLAGS(((SGE_SIMPLE32 *) &cfgp->PageBufferSGE), 537102199Smjacob (MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER | 538102199Smjacob MPI_SGE_FLAGS_SIMPLE_ELEMENT | MPI_SGE_FLAGS_END_OF_LIST)); 539102199Smjacob cfgp->MsgContext = req->index | 0x80000000; 540102199Smjacob 541102199Smjacob mpt_check_doorbell(mpt); 542102199Smjacob mpt_send_cmd(mpt, req); 543102199Smjacob count = 0; 544102199Smjacob do { 545102199Smjacob DELAY(500); 546102199Smjacob mpt_intr(mpt); 547102199Smjacob if (++count == 1000) { 548102199Smjacob device_printf(mpt->dev, "read_cfg_header timed out\n"); 549102199Smjacob return (-1); 550102199Smjacob } 551102199Smjacob } while (req->debug == REQ_ON_CHIP); 552102199Smjacob 553102199Smjacob reply = (MSG_CONFIG_REPLY *) MPT_REPLY_PTOV(mpt, req->sequence); 554102199Smjacob if ((reply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) { 555102199Smjacob device_printf(mpt->dev, 556102199Smjacob "mpt_read_cfg_header: Config Info Status %x\n", 557102199Smjacob reply->IOCStatus); 558102199Smjacob return (-1); 559102199Smjacob } 560102199Smjacob bcopy(&reply->Header, rslt, sizeof (fCONFIG_PAGE_HEADER)); 561102199Smjacob mpt_free_reply(mpt, (req->sequence << 1)); 562102199Smjacob mpt_free_request(mpt, req); 563102199Smjacob return (0); 564102199Smjacob} 565102199Smjacob 566102199Smjacob#define CFG_DATA_OFF 40 567102199Smjacob 568102199Smjacobstatic int 569102199Smjacobmpt_read_cfg_page(mpt_softc_t *mpt, int PageAddress, fCONFIG_PAGE_HEADER *hdr) 570102199Smjacob{ 571102199Smjacob int count; 572102199Smjacob request_t *req; 573102199Smjacob SGE_SIMPLE32 *se; 574102199Smjacob MSG_CONFIG *cfgp; 575102199Smjacob size_t amt; 576102199Smjacob MSG_CONFIG_REPLY *reply; 577102199Smjacob 578102199Smjacob req = mpt_get_request(mpt); 579102199Smjacob 580102199Smjacob cfgp = req->req_vbuf; 581102199Smjacob amt = (cfgp->Header.PageLength * sizeof (uint32_t)); 582102199Smjacob bzero(cfgp, sizeof *cfgp); 583102199Smjacob cfgp->Action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; 584102199Smjacob cfgp->Function = MPI_FUNCTION_CONFIG; 585102199Smjacob cfgp->Header = *hdr; 586102199Smjacob cfgp->Header.PageType &= MPI_CONFIG_PAGETYPE_MASK; 587102199Smjacob cfgp->PageAddress = PageAddress; 588102199Smjacob se = (SGE_SIMPLE32 *) &cfgp->PageBufferSGE; 589102199Smjacob se->Address = req->req_pbuf + CFG_DATA_OFF; 590102199Smjacob MPI_pSGE_SET_LENGTH(se, amt); 591102199Smjacob MPI_pSGE_SET_FLAGS(se, (MPI_SGE_FLAGS_SIMPLE_ELEMENT | 592102199Smjacob MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER | 593102199Smjacob MPI_SGE_FLAGS_END_OF_LIST)); 594102199Smjacob 595102199Smjacob cfgp->MsgContext = req->index | 0x80000000; 596102199Smjacob 597102199Smjacob mpt_check_doorbell(mpt); 598102199Smjacob mpt_send_cmd(mpt, req); 599102199Smjacob count = 0; 600102199Smjacob do { 601102199Smjacob DELAY(500); 602102199Smjacob mpt_intr(mpt); 603102199Smjacob if (++count == 1000) { 604102199Smjacob device_printf(mpt->dev, "read_cfg_page timed out\n"); 605102199Smjacob return (-1); 606102199Smjacob } 607102199Smjacob } while (req->debug == REQ_ON_CHIP); 608102199Smjacob 609102199Smjacob reply = (MSG_CONFIG_REPLY *) MPT_REPLY_PTOV(mpt, req->sequence); 610102199Smjacob if ((reply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) { 611102199Smjacob device_printf(mpt->dev, 612102199Smjacob "mpt_read_cfg_page: Config Info Status %x\n", 613102199Smjacob reply->IOCStatus); 614102199Smjacob return (-1); 615102199Smjacob } 616102199Smjacob mpt_free_reply(mpt, (req->sequence << 1)); 617102199Smjacob bus_dmamap_sync(mpt->request_dmat, mpt->request_dmap, 618102199Smjacob BUS_DMASYNC_POSTREAD); 619102199Smjacob if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT && 620102199Smjacob cfgp->Header.PageNumber == 0) { 621102199Smjacob amt = sizeof (fCONFIG_PAGE_SCSI_PORT_0); 622102199Smjacob } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT && 623102199Smjacob cfgp->Header.PageNumber == 1) { 624102199Smjacob amt = sizeof (fCONFIG_PAGE_SCSI_PORT_1); 625102199Smjacob } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT && 626102199Smjacob cfgp->Header.PageNumber == 2) { 627102199Smjacob amt = sizeof (fCONFIG_PAGE_SCSI_PORT_2); 628102199Smjacob } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE && 629102199Smjacob cfgp->Header.PageNumber == 0) { 630102199Smjacob amt = sizeof (fCONFIG_PAGE_SCSI_DEVICE_0); 631102199Smjacob } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE && 632102199Smjacob cfgp->Header.PageNumber == 1) { 633102199Smjacob amt = sizeof (fCONFIG_PAGE_SCSI_DEVICE_1); 634102199Smjacob } 635102199Smjacob bcopy(((caddr_t)req->req_vbuf)+CFG_DATA_OFF, hdr, amt); 636102199Smjacob mpt_free_request(mpt, req); 637102199Smjacob return (0); 638102199Smjacob} 639102199Smjacob 640102199Smjacobstatic int 641102199Smjacobmpt_write_cfg_page(mpt_softc_t *mpt, int PageAddress, fCONFIG_PAGE_HEADER *hdr) 642102199Smjacob{ 643102199Smjacob int count, hdr_attr; 644102199Smjacob request_t *req; 645102199Smjacob SGE_SIMPLE32 *se; 646102199Smjacob MSG_CONFIG *cfgp; 647102199Smjacob size_t amt; 648102199Smjacob MSG_CONFIG_REPLY *reply; 649102199Smjacob 650102199Smjacob req = mpt_get_request(mpt); 651102199Smjacob 652102199Smjacob cfgp = req->req_vbuf; 653102199Smjacob bzero(cfgp, sizeof *cfgp); 654102199Smjacob 655102199Smjacob hdr_attr = hdr->PageType & MPI_CONFIG_PAGEATTR_MASK; 656102199Smjacob if (hdr_attr != MPI_CONFIG_PAGEATTR_CHANGEABLE && 657102199Smjacob hdr_attr != MPI_CONFIG_PAGEATTR_PERSISTENT) { 658102199Smjacob device_printf(mpt->dev, "page type 0x%x not changeable\n", 659102199Smjacob hdr->PageType & MPI_CONFIG_PAGETYPE_MASK); 660102199Smjacob return (-1); 661102199Smjacob } 662102199Smjacob hdr->PageType &= MPI_CONFIG_PAGETYPE_MASK; 663102199Smjacob 664102199Smjacob amt = (cfgp->Header.PageLength * sizeof (uint32_t)); 665102199Smjacob cfgp->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT; 666102199Smjacob cfgp->Function = MPI_FUNCTION_CONFIG; 667102199Smjacob cfgp->Header = *hdr; 668102199Smjacob cfgp->PageAddress = PageAddress; 669102199Smjacob 670102199Smjacob se = (SGE_SIMPLE32 *) &cfgp->PageBufferSGE; 671102199Smjacob se->Address = req->req_pbuf + CFG_DATA_OFF; 672102199Smjacob MPI_pSGE_SET_LENGTH(se, amt); 673102199Smjacob MPI_pSGE_SET_FLAGS(se, (MPI_SGE_FLAGS_SIMPLE_ELEMENT | 674102199Smjacob MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER | 675102199Smjacob MPI_SGE_FLAGS_END_OF_LIST | MPI_SGE_FLAGS_HOST_TO_IOC)); 676102199Smjacob 677102199Smjacob cfgp->MsgContext = req->index | 0x80000000; 678102199Smjacob 679102199Smjacob if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT && 680102199Smjacob cfgp->Header.PageNumber == 0) { 681102199Smjacob amt = sizeof (fCONFIG_PAGE_SCSI_PORT_0); 682102199Smjacob } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT && 683102199Smjacob cfgp->Header.PageNumber == 1) { 684102199Smjacob amt = sizeof (fCONFIG_PAGE_SCSI_PORT_1); 685102199Smjacob } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT && 686102199Smjacob cfgp->Header.PageNumber == 2) { 687102199Smjacob amt = sizeof (fCONFIG_PAGE_SCSI_PORT_2); 688102199Smjacob } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE && 689102199Smjacob cfgp->Header.PageNumber == 0) { 690102199Smjacob amt = sizeof (fCONFIG_PAGE_SCSI_DEVICE_0); 691102199Smjacob } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE && 692102199Smjacob cfgp->Header.PageNumber == 1) { 693102199Smjacob amt = sizeof (fCONFIG_PAGE_SCSI_DEVICE_1); 694102199Smjacob } 695102199Smjacob bcopy(hdr, ((caddr_t)req->req_vbuf)+CFG_DATA_OFF, amt); 696102199Smjacob 697102199Smjacob mpt_check_doorbell(mpt); 698102199Smjacob mpt_send_cmd(mpt, req); 699102199Smjacob count = 0; 700102199Smjacob do { 701102199Smjacob DELAY(500); 702102199Smjacob mpt_intr(mpt); 703102199Smjacob if (++count == 1000) { 704102199Smjacob hdr->PageType |= hdr_attr; 705102199Smjacob device_printf(mpt->dev, 706102199Smjacob "mpt_write_cfg_page timed out\n"); 707102199Smjacob return (-1); 708102199Smjacob } 709102199Smjacob } while (req->debug == REQ_ON_CHIP); 710102199Smjacob 711102199Smjacob reply = (MSG_CONFIG_REPLY *) MPT_REPLY_PTOV(mpt, req->sequence); 712102199Smjacob if ((reply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) { 713102199Smjacob device_printf(mpt->dev, 714102199Smjacob "mpt_write_cfg_page: Config Info Status %x\n", 715102199Smjacob reply->IOCStatus); 716102199Smjacob return (-1); 717102199Smjacob } 718102199Smjacob mpt_free_reply(mpt, (req->sequence << 1)); 719102199Smjacob 720102199Smjacob /* 721102199Smjacob * Restore stripped out attributes 722102199Smjacob */ 723102199Smjacob hdr->PageType |= hdr_attr; 724102199Smjacob mpt_free_request(mpt, req); 725102199Smjacob return (0); 726102199Smjacob} 727102199Smjacob 728102199Smjacob/* 729102199Smjacob * Read SCSI configuration information 730102199Smjacob */ 731102199Smjacobstatic int 732102199Smjacobmpt_read_config_info_spi(mpt_softc_t *mpt) 733102199Smjacob{ 734102199Smjacob int rv, i; 735102199Smjacob 736102199Smjacob rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_PORT, 0, 737102199Smjacob 0, &mpt->mpt_port_page0.Header); 738102199Smjacob if (rv) { 739102199Smjacob return (-1); 740102199Smjacob } 741102199Smjacob if (mpt->verbose > 1) { 742102199Smjacob device_printf(mpt->dev, "SPI Port Page 0 Header: %x %x %x %x\n", 743102199Smjacob mpt->mpt_port_page0.Header.PageVersion, 744102199Smjacob mpt->mpt_port_page0.Header.PageLength, 745102199Smjacob mpt->mpt_port_page0.Header.PageNumber, 746102199Smjacob mpt->mpt_port_page0.Header.PageType); 747102199Smjacob } 748102199Smjacob 749102199Smjacob rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_PORT, 1, 750102199Smjacob 0, &mpt->mpt_port_page1.Header); 751102199Smjacob if (rv) { 752102199Smjacob return (-1); 753102199Smjacob } 754102199Smjacob if (mpt->verbose > 1) { 755102199Smjacob device_printf(mpt->dev, "SPI Port Page 1 Header: %x %x %x %x\n", 756102199Smjacob mpt->mpt_port_page1.Header.PageVersion, 757102199Smjacob mpt->mpt_port_page1.Header.PageLength, 758102199Smjacob mpt->mpt_port_page1.Header.PageNumber, 759102199Smjacob mpt->mpt_port_page1.Header.PageType); 760102199Smjacob } 761102199Smjacob 762102199Smjacob rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_PORT, 2, 763102199Smjacob 0, &mpt->mpt_port_page2.Header); 764102199Smjacob if (rv) { 765102199Smjacob return (-1); 766102199Smjacob } 767102199Smjacob 768102199Smjacob if (mpt->verbose > 1) { 769102199Smjacob device_printf(mpt->dev, "SPI Port Page 2 Header: %x %x %x %x\n", 770102199Smjacob mpt->mpt_port_page1.Header.PageVersion, 771102199Smjacob mpt->mpt_port_page1.Header.PageLength, 772102199Smjacob mpt->mpt_port_page1.Header.PageNumber, 773102199Smjacob mpt->mpt_port_page1.Header.PageType); 774102199Smjacob } 775102199Smjacob 776102199Smjacob for (i = 0; i < 16; i++) { 777102199Smjacob rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_DEVICE, 778102199Smjacob 0, i, &mpt->mpt_dev_page0[i].Header); 779102199Smjacob if (rv) { 780102199Smjacob return (-1); 781102199Smjacob } 782102199Smjacob if (mpt->verbose > 1) { 783102199Smjacob device_printf(mpt->dev, 784102199Smjacob "SPI Target %d Device Page 0 Header: %x %x %x %x\n", 785102199Smjacob i, mpt->mpt_dev_page0[i].Header.PageVersion, 786102199Smjacob mpt->mpt_dev_page0[i].Header.PageLength, 787102199Smjacob mpt->mpt_dev_page0[i].Header.PageNumber, 788102199Smjacob mpt->mpt_dev_page0[i].Header.PageType); 789102199Smjacob } 790102199Smjacob 791102199Smjacob rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_DEVICE, 792102199Smjacob 1, i, &mpt->mpt_dev_page1[i].Header); 793102199Smjacob if (rv) { 794102199Smjacob return (-1); 795102199Smjacob } 796102199Smjacob if (mpt->verbose > 1) { 797102199Smjacob device_printf(mpt->dev, 798102199Smjacob "SPI Target %d Device Page 1 Header: %x %x %x %x\n", 799102199Smjacob i, mpt->mpt_dev_page1[i].Header.PageVersion, 800102199Smjacob mpt->mpt_dev_page1[i].Header.PageLength, 801102199Smjacob mpt->mpt_dev_page1[i].Header.PageNumber, 802102199Smjacob mpt->mpt_dev_page1[i].Header.PageType); 803102199Smjacob } 804102199Smjacob } 805102199Smjacob 806102199Smjacob /* 807102199Smjacob * At this point, we don't *have* to fail. As long as we have 808102199Smjacob * valid config header information, we can (barely) lurch 809102199Smjacob * along. 810102199Smjacob */ 811102199Smjacob 812102199Smjacob rv = mpt_read_cfg_page(mpt, 0, &mpt->mpt_port_page0.Header); 813102199Smjacob if (rv) { 814102199Smjacob device_printf(mpt->dev, "failed to read SPI Port Page 0\n"); 815102199Smjacob } else if (mpt->verbose > 1) { 816102199Smjacob device_printf(mpt->dev, 817102199Smjacob "SPI Port Page 0: Capabilities %x PhysicalInterface %x\n", 818102199Smjacob mpt->mpt_port_page0.Capabilities, 819102199Smjacob mpt->mpt_port_page0.PhysicalInterface); 820102199Smjacob } 821102199Smjacob 822102199Smjacob rv = mpt_read_cfg_page(mpt, 0, &mpt->mpt_port_page1.Header); 823102199Smjacob if (rv) { 824102199Smjacob device_printf(mpt->dev, "failed to read SPI Port Page 1\n"); 825102199Smjacob } else if (mpt->verbose > 1) { 826102199Smjacob device_printf(mpt->dev, 827102199Smjacob "SPI Port Page 1: Configuration %x OnBusTimerValue %x\n", 828102199Smjacob mpt->mpt_port_page1.Configuration, 829102199Smjacob mpt->mpt_port_page1.OnBusTimerValue); 830102199Smjacob } 831102199Smjacob 832102199Smjacob rv = mpt_read_cfg_page(mpt, 0, &mpt->mpt_port_page2.Header); 833102199Smjacob if (rv) { 834102199Smjacob device_printf(mpt->dev, "failed to read SPI Port Page 2\n"); 835102199Smjacob } else if (mpt->verbose > 1) { 836102199Smjacob device_printf(mpt->dev, 837102199Smjacob "SPI Port Page 2: Flags %x Settings %x\n", 838102199Smjacob mpt->mpt_port_page2.PortFlags, 839102199Smjacob mpt->mpt_port_page2.PortSettings); 840102199Smjacob for (i = 0; i < 16; i++) { 841102199Smjacob device_printf(mpt->dev, 842102199Smjacob "SPI Port Page 2 Tgt %d: timo %x SF %x Flags %x\n", 843102199Smjacob i, mpt->mpt_port_page2.DeviceSettings[i].Timeout, 844102199Smjacob mpt->mpt_port_page2.DeviceSettings[i].SyncFactor, 845102199Smjacob mpt->mpt_port_page2.DeviceSettings[i].DeviceFlags); 846102199Smjacob } 847102199Smjacob } 848102199Smjacob 849102199Smjacob for (i = 0; i < 16; i++) { 850102199Smjacob rv = mpt_read_cfg_page(mpt, i, &mpt->mpt_dev_page0[i].Header); 851102199Smjacob if (rv) { 852102199Smjacob device_printf(mpt->dev, 853102199Smjacob "cannot read SPI Tgt %d Device Page 0\n", i); 854102199Smjacob continue; 855102199Smjacob } 856102199Smjacob if (mpt->verbose > 1) { 857102199Smjacob device_printf(mpt->dev, 858102199Smjacob "SPI Tgt %d Page 0: NParms %x Information %x\n", 859102199Smjacob i, mpt->mpt_dev_page0[i].NegotiatedParameters, 860102199Smjacob mpt->mpt_dev_page0[i].Information); 861102199Smjacob } 862102199Smjacob rv = mpt_read_cfg_page(mpt, i, &mpt->mpt_dev_page1[i].Header); 863102199Smjacob if (rv) { 864102199Smjacob device_printf(mpt->dev, 865102199Smjacob "cannot read SPI Tgt %d Device Page 1\n", i); 866102199Smjacob continue; 867102199Smjacob } 868102199Smjacob if (mpt->verbose > 1) { 869102199Smjacob device_printf(mpt->dev, 870102199Smjacob "SPI Tgt %d Page 1: RParms %x Configuration %x\n", 871102199Smjacob i, mpt->mpt_dev_page1[i].RequestedParameters, 872102199Smjacob mpt->mpt_dev_page1[i].Configuration); 873102199Smjacob } 874102199Smjacob } 875102199Smjacob return (0); 876102199Smjacob} 877102199Smjacob 878102199Smjacob/* 879102199Smjacob * Validate SPI configuration information. 880102199Smjacob * 881102199Smjacob * In particular, validate SPI Port Page 1. 882102199Smjacob */ 883102199Smjacobstatic int 884102199Smjacobmpt_set_initial_config_spi(mpt_softc_t *mpt) 885102199Smjacob{ 886102199Smjacob int i, pp1val = ((1 << mpt->mpt_ini_id) << 16) | mpt->mpt_ini_id; 887102199Smjacob 888102199Smjacob if (mpt->mpt_port_page1.Configuration != pp1val) { 889102199Smjacob fCONFIG_PAGE_SCSI_PORT_1 tmp; 890102199Smjacob device_printf(mpt->dev, 891102199Smjacob "SPI Port Page 1 Config value bad (%x)- should be %x\n", 892102199Smjacob mpt->mpt_port_page1.Configuration, pp1val); 893102199Smjacob tmp = mpt->mpt_port_page1; 894102199Smjacob tmp.Configuration = pp1val; 895102199Smjacob if (mpt_write_cfg_page(mpt, 0, &tmp.Header)) { 896102199Smjacob return (-1); 897102199Smjacob } 898102199Smjacob if (mpt_read_cfg_page(mpt, 0, &tmp.Header)) { 899102199Smjacob return (-1); 900102199Smjacob } 901102199Smjacob if (tmp.Configuration != pp1val) { 902102199Smjacob device_printf(mpt->dev, 903102199Smjacob "failed to reset SPI Port Page 1 Config value\n"); 904102199Smjacob return (-1); 905102199Smjacob } 906102199Smjacob mpt->mpt_port_page1 = tmp; 907102199Smjacob } 908102199Smjacob 909102199Smjacob#if 1 910102199Smjacob i = i; 911102199Smjacob#else 912102199Smjacob for (i = 0; i < 16; i++) { 913102199Smjacob fCONFIG_PAGE_SCSI_DEVICE_1 tmp; 914102199Smjacob tmp = mpt->mpt_dev_page1[i]; 915102199Smjacob tmp.RequestedParameters = 0; 916102199Smjacob tmp.Configuration = 0; 917102199Smjacob if (mpt->verbose > 1) { 918102199Smjacob device_printf(mpt->dev, 919102199Smjacob "Set Tgt %d SPI DevicePage 1 values to %x 0 %x\n", 920102199Smjacob i, tmp.RequestedParameters, tmp.Configuration); 921102199Smjacob } 922102199Smjacob if (mpt_write_cfg_page(mpt, i, &tmp.Header)) { 923102199Smjacob return (-1); 924102199Smjacob } 925102199Smjacob if (mpt_read_cfg_page(mpt, i, &tmp.Header)) { 926102199Smjacob return (-1); 927102199Smjacob } 928102199Smjacob mpt->mpt_dev_page1[i] = tmp; 929102199Smjacob if (mpt->verbose > 1) { 930102199Smjacob device_printf(mpt->dev, 931102199Smjacob "SPI Tgt %d Page 1: RParm %x Configuration %x\n", i, 932102199Smjacob mpt->mpt_dev_page1[i].RequestedParameters, 933102199Smjacob mpt->mpt_dev_page1[i].Configuration); 934102199Smjacob } 935102199Smjacob } 936102199Smjacob#endif 937102199Smjacob return (0); 938102199Smjacob} 939102199Smjacob 940102199Smjacob/* 941102199Smjacob * Enable IOC port 942102199Smjacob */ 943102199Smjacobstatic int 944102199Smjacobmpt_send_port_enable(mpt_softc_t *mpt, int port) 945102199Smjacob{ 946102199Smjacob int count; 947102199Smjacob request_t *req; 948101704Smjacob MSG_PORT_ENABLE *enable_req; 949101704Smjacob 950101704Smjacob req = mpt_get_request(mpt); 951101704Smjacob 952101704Smjacob enable_req = req->req_vbuf; 953101704Smjacob bzero(enable_req, sizeof *enable_req); 954101704Smjacob 955101704Smjacob enable_req->Function = MPI_FUNCTION_PORT_ENABLE; 956101704Smjacob enable_req->MsgContext = req->index | 0x80000000; 957101704Smjacob enable_req->PortNumber = port; 958101704Smjacob 959101704Smjacob mpt_check_doorbell(mpt); 960101704Smjacob if (mpt->verbose > 1) { 961101704Smjacob device_printf(mpt->dev, "enabling port %d\n", port); 962101704Smjacob } 963101704Smjacob mpt_send_cmd(mpt, req); 964101704Smjacob 965101704Smjacob count = 0; 966101704Smjacob do { 967101704Smjacob DELAY(500); 968101704Smjacob mpt_intr(mpt); 969101704Smjacob if (++count == 1000) { 970101704Smjacob device_printf(mpt->dev, "port enable timed out\n"); 971101704Smjacob return (-1); 972101704Smjacob } 973101704Smjacob } while (req->debug == REQ_ON_CHIP); 974101704Smjacob mpt_free_request(mpt, req); 975101704Smjacob return (0); 976101704Smjacob} 977101704Smjacob 978101704Smjacob/* 979101704Smjacob * Enable/Disable asynchronous event reporting. 980101704Smjacob * 981101704Smjacob * NB: this is the first command we send via shared memory 982101704Smjacob * instead of the handshake register. 983101704Smjacob */ 984101704Smjacobstatic int 985102199Smjacobmpt_send_event_request(mpt_softc_t *mpt, int onoff) 986101704Smjacob{ 987101704Smjacob request_t *req; 988101704Smjacob MSG_EVENT_NOTIFY *enable_req; 989101704Smjacob 990101704Smjacob req = mpt_get_request(mpt); 991101704Smjacob 992101704Smjacob enable_req = req->req_vbuf; 993101704Smjacob bzero(enable_req, sizeof *enable_req); 994101704Smjacob 995101704Smjacob enable_req->Function = MPI_FUNCTION_EVENT_NOTIFICATION; 996101704Smjacob enable_req->MsgContext = req->index | 0x80000000; 997101704Smjacob enable_req->Switch = onoff; 998101704Smjacob 999101704Smjacob mpt_check_doorbell(mpt); 1000101704Smjacob if (mpt->verbose > 1) { 1001101704Smjacob device_printf(mpt->dev, "%sabling async events\n", 1002101704Smjacob onoff? "en" : "dis"); 1003101704Smjacob } 1004101704Smjacob mpt_send_cmd(mpt, req); 1005101704Smjacob 1006101704Smjacob return (0); 1007101704Smjacob} 1008101704Smjacob 1009101704Smjacob/* 1010101704Smjacob * Un-mask the interupts on the chip. 1011101704Smjacob */ 1012101704Smjacobvoid 1013102199Smjacobmpt_enable_ints(mpt_softc_t *mpt) 1014101704Smjacob{ 1015101704Smjacob /* Unmask every thing except door bell int */ 1016101704Smjacob mpt_write(mpt, MPT_OFFSET_INTR_MASK, MPT_INTR_DB_MASK); 1017101704Smjacob} 1018101704Smjacob 1019101704Smjacob/* 1020101704Smjacob * Mask the interupts on the chip. 1021101704Smjacob */ 1022101704Smjacobvoid 1023102199Smjacobmpt_disable_ints(mpt_softc_t *mpt) 1024101704Smjacob{ 1025101704Smjacob /* Mask all interrupts */ 1026101704Smjacob mpt_write(mpt, MPT_OFFSET_INTR_MASK, 1027101704Smjacob MPT_INTR_REPLY_MASK | MPT_INTR_DB_MASK); 1028101704Smjacob} 1029101704Smjacob 1030101704Smjacob/* (Re)Initialize the chip for use */ 1031101704Smjacobint 1032102199Smjacobmpt_init(mpt_softc_t *mpt, u_int32_t who) 1033101704Smjacob{ 1034101704Smjacob int try; 1035101704Smjacob MSG_IOC_FACTS_REPLY facts; 1036102199Smjacob MSG_PORT_FACTS_REPLY pfp; 1037101704Smjacob u_int32_t pptr; 1038101704Smjacob int val; 1039101704Smjacob 1040101704Smjacob /* Put all request buffers (back) on the free list */ 1041101704Smjacob SLIST_INIT(&mpt->request_free_list); 1042101704Smjacob for (val = 0; val < MPT_MAX_REQUESTS; val++) { 1043101704Smjacob mpt_free_request(mpt, &mpt->requests[val]); 1044101704Smjacob } 1045101704Smjacob 1046101704Smjacob if (mpt->verbose > 1) { 1047101704Smjacob device_printf(mpt->dev, "doorbell req = %s\n", 1048101704Smjacob mpt_ioc_diag(mpt_read(mpt, MPT_OFFSET_DOORBELL))); 1049101704Smjacob } 1050101704Smjacob 1051101704Smjacob /* 1052101704Smjacob * Start by making sure we're not at FAULT or RESET state 1053101704Smjacob */ 1054101704Smjacob switch (mpt_rd_db(mpt) & MPT_DB_STATE_MASK) { 1055101704Smjacob case MPT_DB_STATE_RESET: 1056101704Smjacob case MPT_DB_STATE_FAULT: 1057101704Smjacob if (mpt_reset(mpt) != MPT_OK) { 1058101704Smjacob return (EIO); 1059101704Smjacob } 1060101704Smjacob default: 1061101704Smjacob break; 1062101704Smjacob } 1063101704Smjacob 1064101704Smjacob 1065101704Smjacob for (try = 0; try < MPT_MAX_TRYS; try++) { 1066101704Smjacob /* 1067101704Smjacob * No need to reset if the IOC is already in the READY state. 1068101704Smjacob * 1069101704Smjacob * Force reset if initialization failed previously. 1070101704Smjacob * Note that a hard_reset of the second channel of a '929 1071101704Smjacob * will stop operation of the first channel. Hopefully, if the 1072101704Smjacob * first channel is ok, the second will not require a hard 1073101704Smjacob * reset. 1074101704Smjacob */ 1075101704Smjacob if ((mpt_rd_db(mpt) & MPT_DB_STATE_MASK) != 1076101704Smjacob MPT_DB_STATE_READY) { 1077101704Smjacob if (mpt_reset(mpt) != MPT_OK) { 1078101704Smjacob DELAY(10000); 1079101704Smjacob continue; 1080101704Smjacob } 1081101704Smjacob } 1082101704Smjacob 1083101704Smjacob if (mpt_get_iocfacts(mpt, &facts) != MPT_OK) { 1084101704Smjacob device_printf(mpt->dev, "mpt_get_iocfacts failed\n"); 1085101704Smjacob continue; 1086102199Smjacob } 1087102199Smjacob 1088102199Smjacob if (mpt->verbose > 1) { 1089101704Smjacob device_printf(mpt->dev, 1090101704Smjacob "mpt_get_iocfacts: GlobalCredits=%d BlockSize=%u " 1091101704Smjacob "Request Frame Size %u\n", facts.GlobalCredits, 1092101704Smjacob facts.BlockSize, facts.RequestFrameSize); 1093101704Smjacob } 1094101704Smjacob mpt->mpt_global_credits = facts.GlobalCredits; 1095101704Smjacob mpt->request_frame_size = facts.RequestFrameSize; 1096101704Smjacob 1097102199Smjacob if (mpt_get_portfacts(mpt, &pfp) != MPT_OK) { 1098102199Smjacob device_printf(mpt->dev, "mpt_get_portfacts failed\n"); 1099102199Smjacob continue; 1100102199Smjacob } 1101102199Smjacob 1102102199Smjacob if (mpt->verbose > 1) { 1103102199Smjacob device_printf(mpt->dev, 1104102199Smjacob "mpt_get_portfacts: Type %x PFlags %x IID %d\n", 1105102199Smjacob pfp.PortType, pfp.ProtocolFlags, pfp.PortSCSIID); 1106102199Smjacob } 1107102199Smjacob 1108102199Smjacob if (pfp.PortType != MPI_PORTFACTS_PORTTYPE_SCSI && 1109102199Smjacob pfp.PortType != MPI_PORTFACTS_PORTTYPE_FC) { 1110102199Smjacob device_printf(mpt->dev, "Unsupported Port Type (%x)\n", 1111102199Smjacob pfp.PortType); 1112102199Smjacob return (ENXIO); 1113102199Smjacob } 1114102199Smjacob if (!(pfp.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR)) { 1115102199Smjacob device_printf(mpt->dev, "initiator role unsupported\n"); 1116102199Smjacob return (ENXIO); 1117102199Smjacob } 1118102199Smjacob if (pfp.PortType == MPI_PORTFACTS_PORTTYPE_FC) { 1119102199Smjacob mpt->is_fc = 1; 1120102199Smjacob } else { 1121102199Smjacob mpt->is_fc = 0; 1122102199Smjacob } 1123102199Smjacob mpt->mpt_ini_id = pfp.PortSCSIID; 1124102199Smjacob 1125101704Smjacob if (mpt_send_ioc_init(mpt, who) != MPT_OK) { 1126101704Smjacob device_printf(mpt->dev, "mpt_send_ioc_init failed\n"); 1127101704Smjacob continue; 1128102199Smjacob } 1129102199Smjacob 1130102199Smjacob if (mpt->verbose > 1) { 1131101704Smjacob device_printf(mpt->dev, "mpt_send_ioc_init ok\n"); 1132101704Smjacob } 1133101704Smjacob 1134101704Smjacob if (mpt_wait_state(mpt, MPT_DB_STATE_RUNNING) != MPT_OK) { 1135101704Smjacob device_printf(mpt->dev, 1136101704Smjacob "IOC failed to go to run state\n"); 1137101704Smjacob continue; 1138102199Smjacob } 1139102199Smjacob if (mpt->verbose > 1) { 1140101704Smjacob device_printf(mpt->dev, "IOC now at RUNSTATE\n"); 1141101704Smjacob } 1142101704Smjacob 1143101704Smjacob /* 1144101704Smjacob * Give it reply buffers 1145101704Smjacob * 1146101704Smjacob * Do *not* except global credits. 1147101704Smjacob */ 1148101704Smjacob for (val = 0, pptr = mpt->reply_phys; 1149101704Smjacob (pptr + MPT_REPLY_SIZE) < (mpt->reply_phys + PAGE_SIZE); 1150101704Smjacob pptr += MPT_REPLY_SIZE) { 1151101704Smjacob mpt_free_reply(mpt, pptr); 1152101704Smjacob if (++val == mpt->mpt_global_credits - 1) 1153101704Smjacob break; 1154101704Smjacob } 1155101704Smjacob 1156102199Smjacob /* 1157102199Smjacob * Enable asynchronous event reporting 1158102199Smjacob */ 1159101704Smjacob mpt_send_event_request(mpt, 1); 1160101704Smjacob 1161102199Smjacob 1162102199Smjacob /* 1163102199Smjacob * Read set up initial configuration information 1164102199Smjacob * (SPI only for now) 1165102199Smjacob */ 1166102199Smjacob 1167102199Smjacob if (mpt->is_fc == 0) { 1168102199Smjacob if (mpt_read_config_info_spi(mpt)) { 1169102199Smjacob return (EIO); 1170102199Smjacob } 1171102199Smjacob if (mpt_set_initial_config_spi(mpt)) { 1172102199Smjacob return (EIO); 1173102199Smjacob } 1174102199Smjacob } 1175102199Smjacob 1176102199Smjacob /* 1177102199Smjacob * Now enable the port 1178102199Smjacob */ 1179101704Smjacob if (mpt_send_port_enable(mpt, 0) != MPT_OK) { 1180101704Smjacob device_printf(mpt->dev, "failed to enable port 0\n"); 1181101704Smjacob continue; 1182102199Smjacob } 1183102199Smjacob 1184102199Smjacob if (mpt->verbose > 1) { 1185101704Smjacob device_printf(mpt->dev, "enabled port 0\n"); 1186101704Smjacob } 1187101704Smjacob 1188101704Smjacob /* Everything worked */ 1189101704Smjacob break; 1190101704Smjacob } 1191101704Smjacob 1192101704Smjacob if (try >= MPT_MAX_TRYS) { 1193101704Smjacob device_printf(mpt->dev, "failed to initialize IOC\n"); 1194101704Smjacob return (EIO); 1195101704Smjacob } 1196101704Smjacob 1197101704Smjacob if (mpt->verbose > 1) { 1198101704Smjacob device_printf(mpt->dev, "enabling interrupts\n"); 1199101704Smjacob } 1200101704Smjacob 1201101704Smjacob mpt_enable_ints(mpt); 1202101704Smjacob return (0); 1203101704Smjacob} 1204