Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys Device driver for the LSI Logic Fusion-MPT based SCSI an...



details:   https://anonhg.NetBSD.org/src/rev/c1fc704c62ff
branches:  trunk
changeset: 545828:c1fc704c62ff
user:      thorpej <thorpej%NetBSD.org@localhost>
date:      Wed Apr 16 22:02:59 2003 +0000

description:
Device driver for the LSI Logic Fusion-MPT based SCSI and Fibre Channel
adapters.  Currently supports:

* LSI 53c1030 Ultra320 SCSI
* LSI FC909, FC909A, FC919, and FC929 Fibre Channel

Ported from the FreeBSD "mpt" driver, written by Greg Ansley.  Thanks
to Frank van der Linden for testing and some bug finding.

This work was sponsored by Wasabi Systems, Inc.

diffstat:

 sys/conf/files          |    10 +-
 sys/dev/ic/mpt.c        |  1195 +++++++++++++
 sys/dev/ic/mpt.h        |   189 ++
 sys/dev/ic/mpt_debug.c  |   604 ++++++
 sys/dev/ic/mpt_mpilib.h |  4249 +++++++++++++++++++++++++++++++++++++++++++++++
 sys/dev/ic/mpt_netbsd.c |  1317 ++++++++++++++
 sys/dev/ic/mpt_netbsd.h |   261 ++
 sys/dev/pci/files.pci   |     6 +-
 sys/dev/pci/mpt_pci.c   |   366 ++++
 9 files changed, 8189 insertions(+), 8 deletions(-)

diffs (truncated from 8253 to 300 lines):

diff -r 147ee6d743a5 -r c1fc704c62ff sys/conf/files
--- a/sys/conf/files    Wed Apr 16 21:44:18 2003 +0000
+++ b/sys/conf/files    Wed Apr 16 22:02:59 2003 +0000
@@ -1,4 +1,4 @@
-#      $NetBSD: files,v 1.607 2003/04/11 14:45:27 drochner Exp $
+#      $NetBSD: files,v 1.608 2003/04/16 22:02:59 thorpej Exp $
 
 #      @(#)files.newconf       7.5 (Berkeley) 5/10/93
 
@@ -379,10 +379,10 @@
 
 # LSILogic Fusion-MPT I/O Processor SCSI/FC Controllers
 #
-device lfmiop { port=-1 }
-device lfmport: scsi
-attach lfmport at lfmiop
-file   dev/ic/lfmiop.c                 lfmiop
+device mpt: scsi
+file   dev/ic/mpt.c                    mpt
+file   dev/ic/mpt_debug.c              mpt
+file   dev/ic/mpt_netbsd.c             mpt
 
 # Symbios/NCR 53c700 SCSI controllers
 device oosiop: scsi
diff -r 147ee6d743a5 -r c1fc704c62ff sys/dev/ic/mpt.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/dev/ic/mpt.c  Wed Apr 16 22:02:59 2003 +0000
@@ -0,0 +1,1195 @@
+/*     $NetBSD: mpt.c,v 1.1 2003/04/16 22:02:59 thorpej Exp $  */
+
+/*
+ * Copyright (c) 2000, 2001 by Greg Ansley
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice immediately at the beginning of the file, without modification,
+ *    this list of conditions, and the following disclaimer.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * Additional Copyright (c) 2002 by Matthew Jacob under same license.
+ */
+
+/*
+ * mpt.c:
+ *
+ * Generic routines for LSI Fusion adapters.
+ *
+ * Adapted from the FreeBSD "mpt" driver by Jason R. Thorpe for
+ * Wasabi Systems, Inc.
+ */
+
+#include <dev/ic/mpt.h>
+
+#define MPT_MAX_TRYS 3
+#define MPT_MAX_WAIT 300000
+
+static int maxwait_ack = 0;
+static int maxwait_int = 0;
+static int maxwait_state = 0;
+
+static __inline u_int32_t
+mpt_rd_db(mpt_softc_t *mpt)
+{
+       return mpt_read(mpt, MPT_OFFSET_DOORBELL);
+}
+
+static __inline u_int32_t
+mpt_rd_intr(mpt_softc_t *mpt)
+{
+       return mpt_read(mpt, MPT_OFFSET_INTR_STATUS);
+}
+
+/* Busy wait for a door bell to be read by IOC */
+static int
+mpt_wait_db_ack(mpt_softc_t *mpt)
+{
+       int i;
+       for (i=0; i < MPT_MAX_WAIT; i++) {
+               if (!MPT_DB_IS_BUSY(mpt_rd_intr(mpt))) {
+                       maxwait_ack = i > maxwait_ack ? i : maxwait_ack;
+                       return MPT_OK;
+               }
+
+               DELAY(100);
+       }
+       return MPT_FAIL;
+}
+
+/* Busy wait for a door bell interrupt */
+static int
+mpt_wait_db_int(mpt_softc_t *mpt)
+{
+       int i;
+       for (i=0; i < MPT_MAX_WAIT; i++) {
+               if (MPT_DB_INTR(mpt_rd_intr(mpt))) {
+                       maxwait_int = i > maxwait_int ? i : maxwait_int;
+                       return MPT_OK;
+               }
+               DELAY(100);
+       }
+       return MPT_FAIL;
+}
+
+/* Wait for IOC to transition to a give state */
+void
+mpt_check_doorbell(mpt_softc_t *mpt)
+{
+       u_int32_t db = mpt_rd_db(mpt);
+       if (MPT_STATE(db) != MPT_DB_STATE_RUNNING) {
+               mpt_prt(mpt, "Device not running");
+               mpt_print_db(db);
+       }
+}
+
+/* Wait for IOC to transition to a give state */
+static int
+mpt_wait_state(mpt_softc_t *mpt, enum DB_STATE_BITS state)
+{
+       int i;
+
+       for (i = 0; i < MPT_MAX_WAIT; i++) {
+               u_int32_t db = mpt_rd_db(mpt);
+               if (MPT_STATE(db) == state) {
+                       maxwait_state = i > maxwait_state ? i : maxwait_state;
+                       return (MPT_OK);
+               }
+               DELAY(100);
+       }
+       return (MPT_FAIL);
+}
+
+
+/* Issue the reset COMMAND to the IOC */
+int
+mpt_soft_reset(mpt_softc_t *mpt)
+{
+       if (mpt->verbose) {
+               mpt_prt(mpt, "soft reset");
+       }
+
+       /* Have to use hard reset if we are not in Running state */
+       if (MPT_STATE(mpt_rd_db(mpt)) != MPT_DB_STATE_RUNNING) {
+               mpt_prt(mpt, "soft reset failed: device not running");
+               return MPT_FAIL;
+       }
+
+       /* If door bell is in use we don't have a chance of getting
+        * a word in since the IOC probably crashed in message
+        * processing. So don't waste our time.
+        */
+       if (MPT_DB_IS_IN_USE(mpt_rd_db(mpt))) {
+               mpt_prt(mpt, "soft reset failed: doorbell wedged");
+               return MPT_FAIL;
+       }
+
+       /* Send the reset request to the IOC */
+       mpt_write(mpt, MPT_OFFSET_DOORBELL,
+           MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET << MPI_DOORBELL_FUNCTION_SHIFT);
+       if (mpt_wait_db_ack(mpt) != MPT_OK) {
+               mpt_prt(mpt, "soft reset failed: ack timeout");
+               return MPT_FAIL;
+       }
+
+       /* Wait for the IOC to reload and come out of reset state */
+       if (mpt_wait_state(mpt, MPT_DB_STATE_READY) != MPT_OK) {
+               mpt_prt(mpt, "soft reset failed: device did not start running");
+               return MPT_FAIL;
+       }
+
+       return MPT_OK;
+}
+
+/* This is a magic diagnostic reset that resets all the ARM
+ * processors in the chip. 
+ */
+void
+mpt_hard_reset(mpt_softc_t *mpt)
+{
+       /* This extra read comes for the Linux source
+        * released by LSI. It's function is undocumented!
+        */
+       if (mpt->verbose) {
+               mpt_prt(mpt, "hard reset");
+       }
+       mpt_read(mpt, MPT_OFFSET_FUBAR);
+
+       /* Enable diagnostic registers */
+       mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_1);
+       mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_2);
+       mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_3);
+       mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_4);
+       mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_5);
+
+       /* Diag. port is now active so we can now hit the reset bit */
+       mpt_write(mpt, MPT_OFFSET_DIAGNOSTIC, MPT_DIAG_RESET_IOC);
+
+       DELAY(10000);
+
+       /* Disable Diagnostic Register */
+       mpt_write(mpt, MPT_OFFSET_SEQUENCE, 0xFF);
+
+       /* Restore the config register values */
+       /*   Hard resets are known to screw up the BAR for diagnostic
+            memory accesses (Mem1). */
+       mpt_set_config_regs(mpt);
+       if (mpt->mpt2 != NULL) {
+               mpt_set_config_regs(mpt->mpt2);
+       }
+
+       /* Note that if there is no valid firmware to run, the doorbell will
+          remain in the reset state (0x00000000) */
+}
+
+/*
+ * Reset the IOC when needed. Try software command first then if needed
+ * poke at the magic diagnostic reset. Note that a hard reset resets
+ * *both* IOCs on dual function chips (FC929 && LSI1030) as well as
+ * fouls up the PCI configuration registers.
+ */
+int
+mpt_reset(mpt_softc_t *mpt)
+{
+       int ret;
+
+       /* Try a soft reset */
+       if ((ret = mpt_soft_reset(mpt)) != MPT_OK) {
+               /* 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");
+               }
+       }
+
+       return ret;
+}
+
+/* Return a command buffer to the free queue */
+void
+mpt_free_request(mpt_softc_t *mpt, request_t *req)
+{
+       if (req == NULL || req != &mpt->request_pool[req->index]) {
+               panic("mpt_free_request bad req ptr\n");
+               return;
+       }
+       req->sequence = 0;
+       req->xfer = NULL;
+       req->debug = REQ_FREE;
+       SLIST_INSERT_HEAD(&mpt->request_free_list, req, link);
+}
+
+/* Get a command buffer from the free queue */
+request_t *
+mpt_get_request(mpt_softc_t *mpt)
+{
+       request_t *req;
+       req = SLIST_FIRST(&mpt->request_free_list);
+       if (req != NULL) {
+               if (req != &mpt->request_pool[req->index]) {
+                       panic("mpt_get_request: corrupted request free list\n");
+               }
+               if (req->xfer != NULL) {
+                       panic("mpt_get_request: corrupted request free list (xfer)\n");
+               }
+               SLIST_REMOVE_HEAD(&mpt->request_free_list, link);
+               req->debug = REQ_IN_PROGRESS;
+       }
+       return req;
+}
+
+/* Pass the command to the IOC */
+void
+mpt_send_cmd(mpt_softc_t *mpt, request_t *req)
+{
+       req->sequence = mpt->sequence++;
+       if (mpt->verbose > 1) {
+               u_int32_t *pReq;
+               pReq = req->req_vbuf;
+               mpt_prt(mpt, "Send Request %d (0x%x):",
+                   req->index, req->req_pbuf);
+               mpt_prt(mpt, "%08x %08x %08x %08x",
+                   pReq[0], pReq[1], pReq[2], pReq[3]);



Home | Main Index | Thread Index | Old Index