diff options
author | mjacob <mjacob@FreeBSD.org> | 2006-02-28 07:44:50 +0000 |
---|---|---|
committer | mjacob <mjacob@FreeBSD.org> | 2006-02-28 07:44:50 +0000 |
commit | adf2710156bebb8ca1c1cb58183280cb024d37f5 (patch) | |
tree | 2d1345fb0b6bb6e7b2edd0a5d11f26885516100f | |
parent | 3acbd90cd9bdcf9c3d7197a4e3007284977f8c59 (diff) | |
download | FreeBSD-src-adf2710156bebb8ca1c1cb58183280cb024d37f5.zip FreeBSD-src-adf2710156bebb8ca1c1cb58183280cb024d37f5.tar.gz |
Fix mpt_reset to try mpt_hard_reset more than once, and to try
mpt_soft_reset more than once. And to wait for MPT_DB_STATE_READY
twice. I mean, this is crucial- give the IOC a chance to get
ready.
If mpt_reset is called to reinit things, and we succeed, make
sure to re-enable interrupts. This is what has mostly led to
system lockup after having to hard reset the chip. Also, if
we think that interrupts aren't function in mpt_cam_timeout,
for goodness sake, turn them on again.
In read_cfg_header, return distinguishing errnos so the caller
can decide what's an error. It's *not* an error to fail to
read a RAID page from a non-RAID capable device like the FC929X.
Some whitespace fixes (removing spaces from ends of lines).
-rw-r--r-- | sys/dev/mpt/mpt.c | 128 | ||||
-rw-r--r-- | sys/dev/mpt/mpt_cam.c | 1 |
2 files changed, 86 insertions, 43 deletions
diff --git a/sys/dev/mpt/mpt.c b/sys/dev/mpt/mpt.c index 86fe96b..89d9eaf 100644 --- a/sys/dev/mpt/mpt.c +++ b/sys/dev/mpt/mpt.c @@ -28,7 +28,7 @@ /*- * Copyright (c) 2002, 2006 by Matthew Jacob * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: @@ -42,7 +42,7 @@ * 3. Neither the names of the above listed copyright holders nor the names * of any contributors may be used to endorse or promote products derived * from this software without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -63,7 +63,7 @@ * Copyright (c) 2005, WHEEL Sp. z o.o. * Copyright (c) 2004, 2005 Justin T. Gibbs * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: @@ -77,7 +77,7 @@ * 3. Neither the names of the above listed copyright holders nor the names * of any contributors may be used to endorse or promote products derived * from this software without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -669,14 +669,14 @@ mpt_complete_request_chain(struct mpt_softc *mpt, struct req_queue *chain, bzero(&ioc_status_frame, sizeof(ioc_status_frame)); ioc_status_frame.MsgLength = roundup2(sizeof(ioc_status_frame), 4); - ioc_status_frame.IOCStatus = iocstatus; + ioc_status_frame.IOCStatus = iocstatus; while((req = TAILQ_FIRST(chain)) != NULL) { MSG_REQUEST_HEADER *msg_hdr; u_int cb_index; msg_hdr = (MSG_REQUEST_HEADER *)req->req_vbuf; - ioc_status_frame.Function = msg_hdr->Function; - ioc_status_frame.MsgContext = msg_hdr->MsgContext; + ioc_status_frame.Function = msg_hdr->Function; + ioc_status_frame.MsgContext = msg_hdr->MsgContext; cb_index = MPT_CONTEXT_TO_CBI(le32toh(msg_hdr->MsgContext)); mpt_reply_handlers[cb_index](mpt, req, &ioc_status_frame); } @@ -844,7 +844,7 @@ mpt_disable_diag_mode(struct mpt_softc *mpt) } /* This is a magic diagnostic reset that resets all the ARM - * processors in the chip. + * processors in the chip. */ static void mpt_hard_reset(struct mpt_softc *mpt) @@ -935,30 +935,58 @@ mpt_reset(struct mpt_softc *mpt, int reinit) { struct mpt_personality *pers; int ret; + int retry_cnt = 0; - /* Try a soft reset */ + /* + * Try a soft reset. If that fails, get out the big hammer. + */ + again: if ((ret = mpt_soft_reset(mpt)) != MPT_OK) { - /* Failed; do a hard reset */ - mpt_hard_reset(mpt); + int cnt; + for (cnt = 0; cnt < 5; cnt++) { + /* Failed; do a hard reset */ + mpt_hard_reset(mpt); - /* Wait for the IOC to reload and come out of reset state */ - ret = mpt_wait_state(mpt, MPT_DB_STATE_READY); - if (ret != MPT_OK) - mpt_prt(mpt, "failed to reset device\n"); + /* + * Wait for the IOC to reload + * and come out of reset state + */ + ret = mpt_wait_state(mpt, MPT_DB_STATE_READY); + if (ret == MPT_OK) { + break; + } + /* + * Okay- try to check again... + */ + ret = mpt_wait_state(mpt, MPT_DB_STATE_READY); + if (ret == MPT_OK) { + break; + } + mpt_prt(mpt, "mpt_reset: failed hard reset (%d:%d)\n", + retry_cnt, cnt); + } } - /* - * Invoke reset handlers. We bump the reset count so - * that mpt_wait_req() understands that regardless of - * the specified wait condition, it should stop its wait. - */ - mpt->reset_cnt++; - MPT_PERS_FOREACH(mpt, pers) - pers->reset(mpt, ret); - - if (reinit != 0) - mpt_enable_ioc(mpt); + if (retry_cnt == 0) { + /* + * Invoke reset handlers. We bump the reset count so + * that mpt_wait_req() understands that regardless of + * the specified wait condition, it should stop its wait. + */ + mpt->reset_cnt++; + MPT_PERS_FOREACH(mpt, pers) + pers->reset(mpt, ret); + } + if (reinit != 0) { + ret = mpt_enable_ioc(mpt); + if (ret == MPT_OK) { + mpt_enable_ints(mpt); + } + } + if (ret != MPT_OK && retry_cnt++ < 2) { + goto again; + } return ret; } @@ -1166,7 +1194,7 @@ mpt_send_handshake_cmd(struct mpt_softc *mpt, size_t len, void *cmd) for (i = 0; i < len; i++) { mpt_write(mpt, MPT_OFFSET_DOORBELL, *data32++); if (mpt_wait_db_ack(mpt) != MPT_OK) { - mpt_prt(mpt, + mpt_prt(mpt, "mpt_send_handshake_cmd timeout! index = %d\n", i); return (ETIMEDOUT); @@ -1363,12 +1391,13 @@ mpt_read_cfg_header(struct mpt_softc *mpt, int PageType, int PageNumber, int sleep_ok, int timeout_ms) { request_t *req; + MSG_CONFIG *cfgp; int error; req = mpt_get_request(mpt, sleep_ok); if (req == NULL) { mpt_prt(mpt, "mpt_read_cfg_header: Get request failed!\n"); - return (-1); + return (ENOMEM); } error = mpt_issue_cfg_req(mpt, req, MPI_CONFIG_ACTION_PAGE_HEADER, @@ -1376,20 +1405,28 @@ mpt_read_cfg_header(struct mpt_softc *mpt, int PageType, int PageNumber, PageType, PageAddress, /*addr*/0, /*len*/0, sleep_ok, timeout_ms); if (error != 0) { + mpt_free_request(mpt, req); mpt_prt(mpt, "read_cfg_header timed out\n"); - return (-1); + return (ETIMEDOUT); } - if ((req->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) { - mpt_prt(mpt, "mpt_read_cfg_header: Config Info Status %x\n", - req->IOCStatus); - error = -1; - } else { - MSG_CONFIG *cfgp; - + switch (req->IOCStatus & MPI_IOCSTATUS_MASK) { + case MPI_IOCSTATUS_SUCCESS: cfgp = req->req_vbuf; bcopy(&cfgp->Header, rslt, sizeof(*rslt)); error = 0; + break; + case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: + mpt_lprt(mpt, MPT_PRT_DEBUG, + "Invalid Page Type %d Number %d Addr 0x%0x\n", + PageType, PageNumber, PageAddress); + error = EINVAL; + break; + default: + mpt_prt(mpt, "mpt_read_cfg_header: Config Info Status %x\n", + req->IOCStatus); + error = EIO; + break; } mpt_free_request(mpt, req); return (error); @@ -1495,8 +1532,13 @@ mpt_read_config_info_ioc(struct mpt_softc *mpt) rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_IOC, /*PageNumber*/2, /*PageAddress*/0, &hdr, /*sleep_ok*/FALSE, /*timeout_ms*/5000); + /* + * If it's an invalid page, so what? Not a supported function.... + */ + if (rv == EINVAL) + return (0); if (rv) - return (EIO); + return (rv); mpt_lprt(mpt, MPT_PRT_DEBUG, "IOC Page 2 Header: ver %x, len %x, " "num %x, type %x\n", hdr.PageVersion, @@ -1939,7 +1981,7 @@ void mpt_disable_ints(struct mpt_softc *mpt) { /* Mask all interrupts */ - mpt_write(mpt, MPT_OFFSET_INTR_MASK, + mpt_write(mpt, MPT_OFFSET_INTR_MASK, MPT_INTR_REPLY_MASK | MPT_INTR_DB_MASK); } @@ -1949,7 +1991,7 @@ mpt_sysctl_attach(struct mpt_softc *mpt) struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(mpt->dev); struct sysctl_oid *tree = device_get_sysctl_tree(mpt->dev); - SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, + SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "debug", CTLFLAG_RW, &mpt->verbose, 0, "Debugging/Verbose level"); } @@ -2213,7 +2255,7 @@ mpt_configure_ioc(struct mpt_softc *mpt) * Force reset if initialization failed previously. * Note that a hard_reset of the second channel of a '929 * will stop operation of the first channel. Hopefully, if the - * first channel is ok, the second will not require a hard + * first channel is ok, the second will not require a hard * reset. */ if (needreset || (mpt_rd_db(mpt) & MPT_DB_STATE_MASK) != @@ -2442,8 +2484,8 @@ mpt_enable_ioc(struct mpt_softc *mpt) * * Do *not* exceed global credits. */ - for (val = 0, pptr = mpt->reply_phys; - (pptr + MPT_REPLY_SIZE) < (mpt->reply_phys + PAGE_SIZE); + for (val = 0, pptr = mpt->reply_phys; + (pptr + MPT_REPLY_SIZE) < (mpt->reply_phys + PAGE_SIZE); pptr += MPT_REPLY_SIZE) { mpt_free_reply(mpt, pptr); if (++val == mpt->mpt_global_credits - 1) @@ -2465,5 +2507,5 @@ mpt_enable_ioc(struct mpt_softc *mpt) mpt_lprt(mpt, MPT_PRT_DEBUG, "enabled port 0\n"); - return (0); + return (MPT_OK); } diff --git a/sys/dev/mpt/mpt_cam.c b/sys/dev/mpt/mpt_cam.c index 46c79d2..c617da7 100644 --- a/sys/dev/mpt/mpt_cam.c +++ b/sys/dev/mpt/mpt_cam.c @@ -2063,6 +2063,7 @@ mpt_recover_commands(struct mpt_softc *mpt) */ mpt_prt(mpt, "Timedout requests already complete. " "Interrupts may not be functioning.\n"); + mpt_enable_ints(mpt); MPT_UNLOCK(mpt); return; } |