summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorKenneth R Westerback <krw@cvs.openbsd.org>2003-12-24 22:45:46 +0000
committerKenneth R Westerback <krw@cvs.openbsd.org>2003-12-24 22:45:46 +0000
commit5b156d44dd8236cd26c977490c958658eafcdca6 (patch)
tree7ef4dfa6c4f8fb64f9f910339f02ab668f271d85 /sys
parent5b78bc9ec37dd0ce858345ede4e4690aec39bdb6 (diff)
Sync ahc with NetBSD, which was in turn updated from FreeBSD by Pascal
Renauld of Network Storage Solutions, Inc. Many fixes, wider device support. In particular, the notorious 'Target 0' problem seems to be fixed. Does *not* include any updates to isa or eisa code beyond what was necessary to compile. Known issues: 1) Tagged Queuing is probably not optimal. 2) PPR negotiation may not be fully functional. 3) No support yet for freezing devices or channels. 4) The mechanism for preventing 'A' and 'B' channel confusion during probe can fail if scsibus > 254 found. 5) Requeuing I/O's not working. A workaround will be committed almost immediately. At the moment timeouts, SCSI message rejects, aborting SCB's and trying to freeze a device may cause incomplete i/o's to be reported as complete. 6) Verbosity and probe messages need work. 7) Last disk on bus seems to go through an extra re-negotiation. 8) >16 devices on an adapter will trigger the usual problems of total openings exceeding available SCB's under heavy load. Tested by deraadt@, beck@, miod@, naddy@, drahn@, marc@ amoung others. ok deraadt@.
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/ic/aic7xxx.c1670
-rw-r--r--sys/dev/ic/aic7xxx.h80
-rw-r--r--sys/dev/ic/aic7xxx_cam.h174
-rw-r--r--sys/dev/ic/aic7xxx_inline.h208
-rw-r--r--sys/dev/ic/aic7xxx_openbsd.c1454
-rw-r--r--sys/dev/ic/aic7xxx_openbsd.h715
-rw-r--r--sys/dev/ic/aic7xxx_seeprom.c777
-rw-r--r--sys/dev/pci/ahc_pci.c2387
8 files changed, 3950 insertions, 3515 deletions
diff --git a/sys/dev/ic/aic7xxx.c b/sys/dev/ic/aic7xxx.c
index 0c9ff90bbbd..955cdadee2d 100644
--- a/sys/dev/ic/aic7xxx.c
+++ b/sys/dev/ic/aic7xxx.c
@@ -1,7 +1,11 @@
+/* $OpenBSD: aic7xxx.c,v 1.52 2003/12/24 22:45:45 krw Exp $ */
+/* $NetBSD: aic7xxx.c,v 1.108 2003/11/02 11:07:44 wiz Exp $ */
+
/*
* Core routines and tables shareable across OS platforms.
*
- * Copyright (c) 1994-2001 Justin T. Gibbs.
+ * Copyright (c) 1994-2002 Justin T. Gibbs.
+ * Copyright (c) 2000-2002 Adaptec Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -10,40 +14,49 @@
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer,
* without modification.
- * 2. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 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.
*
* Alternatively, this software may be distributed under the terms of the
- * GNU Public License ("GPL").
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
*
- * 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
+ * NO WARRANTY
+ * 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 MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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.
+ * 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 DAMAGES.
+ *
+ * $Id: aic7xxx.c,v 1.52 2003/12/24 22:45:45 krw Exp $
*
- * $Id: aic7xxx.c,v 1.51 2003/10/21 18:58:48 jmc Exp $
+ * //depot/aic7xxx/aic7xxx/aic7xxx.c#112 $
*
- * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.c,v 1.80 2001/12/16 17:38:30 gibbs Exp $
- * $OpenBSD: aic7xxx.c,v 1.51 2003/10/21 18:58:48 jmc Exp $
+ * $FreeBSD: /repoman/r/ncvs/src/sys/dev/aic7xxx/aic7xxx.c,v 1.88 2003/01/20 20:44:55 gibbs Exp $
+ */
+/*
+ * Ported from FreeBSD by Pascal Renauld, Network Storage Solutions, Inc. - April 2003
*/
-#ifdef __OpenBSD__
+#include <sys/cdefs.h>
+/* __KERNEL_RCSID(0, "$NetBSD: aic7xxx.c,v 1.108 2003/11/02 11:07:44 wiz Exp $"); */
+
#include <dev/ic/aic7xxx_openbsd.h>
#include <dev/ic/aic7xxx_inline.h>
-#include <dev/microcode/aic7xxx/sequencer.h>
-#endif
-#ifdef __FreeBSD__
-#include <dev/aic7xxx/aic7xxx_freebsd.h>
-#include <dev/aic7xxx/aic7xxx_inline.h>
-#include <dev/aic7xxx/aicasm/aicasm_insformat.h>
-#endif
+#include <dev/microcode/aic7xxx/aicasm_insformat.h>
+
/****************************** Softc Data ************************************/
struct ahc_softc_tailq ahc_tailq = TAILQ_HEAD_INITIALIZER(ahc_tailq);
@@ -65,7 +78,6 @@ char *ahc_chip_names[] =
"aic7892",
"aic7899"
};
-static const u_int num_chip_names = NUM_ELEMENTS(ahc_chip_names);
/*
* Hardware error codes.
@@ -133,13 +145,10 @@ static struct ahc_syncrate ahc_syncrates[] =
};
/* Our Sequencer Program */
-#ifdef __OpenBSD__
#include <dev/microcode/aic7xxx/aic7xxx_seq.h>
-#else
-#include "aic7xxx_seq.h"
-#endif
/**************************** Function Declarations ***************************/
+static void ahc_force_renegotiation(struct ahc_softc *);
static struct ahc_tmode_tstate*
ahc_alloc_tstate(struct ahc_softc *ahc,
u_int scsi_id, char channel);
@@ -156,9 +165,6 @@ static struct ahc_syncrate*
static void ahc_update_pending_scbs(struct ahc_softc *ahc);
static void ahc_fetch_devinfo(struct ahc_softc *ahc,
struct ahc_devinfo *devinfo);
-static void ahc_scb_devinfo(struct ahc_softc *ahc,
- struct ahc_devinfo *devinfo,
- struct scb *scb);
static void ahc_assert_atn(struct ahc_softc *ahc);
static void ahc_setup_initiator_msgout(struct ahc_softc *ahc,
struct ahc_devinfo *devinfo,
@@ -176,6 +182,7 @@ static void ahc_construct_ppr(struct ahc_softc *ahc,
u_int period, u_int offset,
u_int bus_width, u_int ppr_options);
static void ahc_clear_msg_state(struct ahc_softc *ahc);
+static void ahc_handle_proto_violation(struct ahc_softc *ahc);
static void ahc_handle_message_phase(struct ahc_softc *ahc);
typedef enum {
AHCMSG_1B,
@@ -201,17 +208,10 @@ static void ahc_setup_target_msgin(struct ahc_softc *ahc,
struct scb *scb);
#endif
-#ifdef __OpenBSD__
-int ahc_init_scbdata(struct ahc_softc *ahc);
-void ahc_fini_scbdata(struct ahc_softc *ahc);
-void ahc_build_free_scb_list(struct ahc_softc *ahc);
-#else
-static bus_dmamap_callback_t ahc_dmamap_cb;
-static int ahc_init_scbdata(struct ahc_softc *ahc);
-static void ahc_fini_scbdata(struct ahc_softc *ahc);
-static void ahc_build_free_scb_list(struct ahc_softc *ahc);
-#endif
-
+//static bus_dmamap_callback_t ahc_dmamap_cb;
+static void ahc_build_free_scb_list(struct ahc_softc *ahc);
+static int ahc_init_scbdata(struct ahc_softc *ahc);
+static void ahc_fini_scbdata(struct ahc_softc *ahc);
static void ahc_qinfifo_requeue(struct ahc_softc *ahc,
struct scb *prev_scb,
struct scb *scb);
@@ -221,9 +221,6 @@ static u_int ahc_rem_scb_from_disc_list(struct ahc_softc *ahc,
static void ahc_add_curscb_to_free_list(struct ahc_softc *ahc);
static u_int ahc_rem_wscb(struct ahc_softc *ahc,
u_int scbpos, u_int prev);
-static int ahc_abort_scbs(struct ahc_softc *ahc, int target,
- char channel, int lun, u_int tag,
- role_t role, uint32_t status);
static void ahc_reset_current_bus(struct ahc_softc *ahc);
#ifdef AHC_DUMP_SEQ
static void ahc_dumpseq(struct ahc_softc *ahc);
@@ -245,6 +242,24 @@ static void ahc_update_scsiid(struct ahc_softc *ahc,
static int ahc_handle_target_cmd(struct ahc_softc *ahc,
struct target_cmd *cmd);
#endif
+
+/************************** Added for porting to NetBSD ***********************/
+static int ahc_createdmamem(bus_dma_tag_t tag,
+ int size,
+ int flags,
+ bus_dmamap_t *mapp,
+ caddr_t *vaddr,
+ bus_addr_t *baddr,
+ bus_dma_segment_t *seg,
+ int *nseg,
+ const char *myname, const char *what);
+static void ahc_freedmamem(bus_dma_tag_t tag,
+ int size,
+ bus_dmamap_t map,
+ caddr_t vaddr,
+ bus_dma_segment_t *seg,
+ int nseg);
+
/************************* Sequencer Execution Control ************************/
/*
* Restart the sequencer program from address zero
@@ -255,9 +270,15 @@ ahc_restart(struct ahc_softc *ahc)
ahc_pause(ahc);
+ /* No more pending messages. */
+ ahc_clear_msg_state(ahc);
+
ahc_outb(ahc, SCSISIGO, 0); /* De-assert BSY */
ahc_outb(ahc, MSG_OUT, MSG_NOOP); /* No message to send */
ahc_outb(ahc, SXFRCTL1, ahc_inb(ahc, SXFRCTL1) & ~BITBUCKET);
+ ahc_outb(ahc, LASTPHASE, P_BUSFREE);
+ ahc_outb(ahc, SAVED_SCSIID, 0xFF);
+ ahc_outb(ahc, SAVED_LUN, 0xFF);
/*
* Ensure that the sequencer's idea of TQINPOS
@@ -317,7 +338,7 @@ ahc_run_qoutfifo(struct ahc_softc *ahc)
*/
modnext = ahc->qoutfifonext & ~0x3;
*((uint32_t *)(&ahc->qoutfifo[modnext])) = 0xFFFFFFFFUL;
- ahc_dmamap_sync(ahc, ahc->shared_data_dmat,
+ ahc_dmamap_sync(ahc, ahc->parent_dmat /*shared_data_dmat*/,
ahc->shared_data_dmamap,
/*offset*/modnext, /*len*/4,
BUS_DMASYNC_PREREAD);
@@ -329,7 +350,7 @@ ahc_run_qoutfifo(struct ahc_softc *ahc)
printf("%s: WARNING no command for scb %d "
"(cmdcmplt)\nQOUTPOS = %d\n",
ahc_name(ahc), scb_index,
- ahc->qoutfifonext - 1);
+ (ahc->qoutfifonext - 1) & 0xFF);
continue;
}
@@ -337,7 +358,7 @@ ahc_run_qoutfifo(struct ahc_softc *ahc)
* Save off the residual
* if there is one.
*/
- ahc_update_residual(scb);
+ ahc_update_residual(ahc, scb);
ahc_done(ahc, scb);
}
}
@@ -360,7 +381,7 @@ ahc_run_untagged_queue(struct ahc_softc *ahc, struct scb_tailq *queue)
return;
if ((scb = TAILQ_FIRST(queue)) != NULL
- && (scb->flags & SCB_ACTIVE) == 0) {
+ && (scb->flags & SCB_ACTIVE) == 0) {
scb->flags |= SCB_ACTIVE;
ahc_queue_scb(ahc, scb);
}
@@ -430,16 +451,16 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
* the kernel. This allows us to leave the sequencer
* running in the common case of command completes
* without error. The sequencer will already have
- * dma'd the SCB back up to us, so we can reference
+ * DMA'd the SCB back up to us, so we can reference
* the in kernel copy directly.
*/
scb_index = ahc_inb(ahc, SCB_TAG);
scb = ahc_lookup_scb(ahc, scb_index);
if (scb == NULL) {
- printf("%s:%c:%d: ahc_intr - referenced scb "
+ ahc_print_devinfo(ahc, &devinfo);
+ printf("ahc_intr - referenced scb "
"not valid during seqint 0x%x scb(%d)\n",
- ahc_name(ahc), devinfo.channel,
- devinfo.target, intstat, scb_index);
+ intstat, scb_index);
ahc_dump_card_state(ahc);
panic("for safety");
goto unpause;
@@ -455,17 +476,15 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
* complete.
*/
scb->flags &= ~SCB_SENSE;
- ahc_set_transaction_status(scb, CAM_AUTOSENSE_FAIL);
break;
}
- ahc_set_transaction_status(scb, CAM_SCSI_STATUS_ERROR);
/* Freeze the queue until the client sees the error. */
ahc_freeze_devq(ahc, scb);
ahc_freeze_scb(scb);
ahc_set_scsi_status(scb, hscb->shared_data.status.scsi_status);
switch (hscb->shared_data.status.scsi_status) {
case SCSI_STATUS_OK:
- printf("%s: Interrupted for staus of 0???\n",
+ printf("%s: Interrupted for status of 0 (?)\n",
ahc_name(ahc));
break;
case SCSI_STATUS_CMD_TERMINATED:
@@ -477,13 +496,13 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
struct ahc_tmode_tstate *tstate;
struct ahc_transinfo *tinfo;
#ifdef AHC_DEBUG
- if (ahc_debug & AHC_SHOWSENSE) {
+ if (ahc_debug & AHC_SHOW_SENSE) {
ahc_print_path(ahc, scb);
printf("SCB %d: requests Check Status\n",
scb->hscb->tag);
}
#endif
-
+
if (ahc_perform_autosense(scb) == 0)
break;
@@ -497,10 +516,10 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
sc = (struct scsi_sense *)(&hscb->shared_data.cdb);
/*
* Save off the residual if there is one.
- */
- ahc_update_residual(scb);
+ */
+ ahc_update_residual(ahc, scb);
#ifdef AHC_DEBUG
- if (ahc_debug & AHC_SHOWSENSE) {
+ if (ahc_debug & AHC_SHOW_SENSE) {
ahc_print_path(ahc, scb);
printf("Sending Sense\n");
}
@@ -508,7 +527,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
sg->addr = ahc_get_sense_bufaddr(ahc, scb);
sg->len = ahc_get_sense_bufsize(ahc, scb);
sg->len |= AHC_DMA_LAST_SEG;
-
+
/* Fixup byte order */
sg->addr = ahc_htole32(sg->addr);
sg->len = ahc_htole32(sg->len);
@@ -516,7 +535,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
sc->opcode = REQUEST_SENSE;
sc->byte2 = 0;
if (tinfo->protocol_version <= SCSI_REV_2
- && SCB_GET_LUN(scb) < 8)
+ && SCB_GET_LUN(scb) < 8)
sc->byte2 = SCB_GET_LUN(scb) << 5;
sc->unused[0] = 0;
sc->unused[1] = 0;
@@ -540,17 +559,12 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
* errors will be reported before any data
* phases occur.
*/
-#ifdef __OpenBSD__
if (ahc_get_transfer_length(scb) > 0 &&
- ahc_get_residual(scb) ==
- ahc_get_transfer_length(scb)) {
-#else
- if (ahc_get_residual(scb)
- == ahc_get_transfer_length(scb)) {
-#endif
+ ahc_get_residual(scb)
+ == ahc_get_transfer_length(scb)) {
ahc_update_neg_request(ahc, &devinfo,
tstate, targ_info,
- /*force*/TRUE);
+ AHC_NEG_IF_NON_ASYNC);
}
if (tstate->auto_negotiate & devinfo.target_mask) {
hscb->control |= MK_MESSAGE;
@@ -563,17 +577,17 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
hscb->sgptr = scb->sg_list_phys | SG_FULL_RESID;
hscb->sgptr = ahc_htole32(hscb->sgptr);
#ifdef __OpenBSD__
- bus_dmamap_sync(ahc->scb_data->sense_dmat,
+ bus_dmamap_sync(ahc->parent_dmat,
ahc->scb_data->sense_dmamap,
(scb - ahc->scb_data->scbarray) *
sizeof(struct scsi_sense_data),
sizeof(struct scsi_sense_data),
BUS_DMASYNC_PREREAD);
- bus_dmamap_sync(ahc->scb_data->sg_dmat,
+ bus_dmamap_sync(ahc->parent_dmat,
scb->sg_map->sg_dmamap,
0, scb->sg_map->sg_dmamap->dm_mapsize,
BUS_DMASYNC_PREWRITE);
- bus_dmamap_sync(ahc->scb_data->hscb_dmat,
+ bus_dmamap_sync(ahc->parent_dmat,
ahc->scb_data->hscb_dmamap,
0, ahc->scb_data->hscb_dmamap->dm_mapsize,
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
@@ -582,20 +596,11 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
scb->flags |= SCB_SENSE;
ahc_qinfifo_requeue_tail(ahc, scb);
ahc_outb(ahc, RETURN_1, SEND_SENSE);
-#ifdef __OpenBSD__
- if (!(scb->io_ctx->flags & SCSI_POLL))
- timeout_add(&scb->io_ctx->stimeout, 5 * hz);
-#endif
-#ifdef __FreeBSD__
/*
* Ensure we have enough time to actually
* retrieve the sense.
*/
- untimeout(ahc_timeout, (caddr_t)scb,
- scb->io_ctx->ccb_h.timeout_ch);
- scb->io_ctx->ccb_h.timeout_ch =
- timeout(ahc_timeout, (caddr_t)scb, 5 * hz);
-#endif
+ ahc_scb_timer_reset(scb, 5 * 1000000);
break;
}
default:
@@ -612,7 +617,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
printf("%s:%c:%d: no active SCB for reconnecting "
"target - issuing BUS DEVICE RESET\n",
ahc_name(ahc), devinfo.channel, devinfo.target);
- printf("SAVED_SCSIID == 0x%02x, SAVED_LUN == 0x%x, "
+ printf("SAVED_SCSIID == 0x%x, SAVED_LUN == 0x%x, "
"ARG_1 == 0x%x ACCUM = 0x%x\n",
ahc_inb(ahc, SAVED_SCSIID), ahc_inb(ahc, SAVED_LUN),
ahc_inb(ahc, ARG_1), ahc_inb(ahc, ACCUM));
@@ -649,27 +654,10 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
ahc_name(ahc), devinfo.channel, devinfo.target, rejbyte);
break;
}
- case NO_IDENT:
+ case PROTO_VIOLATION:
{
- /*
- * The reconnecting target either did not send an identify
- * message, or did, but we didn't find an SCB to match and
- * before it could respond to our ATN/abort, it hit a dataphase.
- * The only safe thing to do is to blow it away with a bus
- * reset.
- */
- int found;
-
- printf("%s:%c:%d: Target did not send an IDENTIFY message. "
- "LASTPHASE = 0x%x, SAVED_SCSIID == 0x%x\n",
- ahc_name(ahc), devinfo.channel, devinfo.target,
- ahc_inb(ahc, LASTPHASE), ahc_inb(ahc, SAVED_SCSIID));
- found = ahc_reset_channel(ahc, devinfo.channel,
- /*initiate reset*/TRUE);
- printf("%s: Issued Channel %c Bus Reset. "
- "%d SCBs aborted\n", ahc_name(ahc), devinfo.channel,
- found);
- return;
+ ahc_handle_proto_violation(ahc);
+ break;
}
case IGN_WIDE_RES:
ahc_handle_ign_wide_residue(ahc, &devinfo);
@@ -738,7 +726,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
if (devinfo.role == ROLE_INITIATOR) {
if (scb == NULL)
panic("HOST_MSG_LOOP with "
- "invalid SCB %x", scb_index);
+ "invalid SCB %x\n", scb_index);
if (bus_phase == P_MESGOUT)
ahc_setup_initiator_msgout(ahc,
@@ -749,19 +737,20 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
MSG_TYPE_INITIATOR_MSGIN;
ahc->msgin_index = 0;
}
- } else {
+ }
+#if AHC_TARGET_MODE
+ else {
if (bus_phase == P_MESGOUT) {
ahc->msg_type =
MSG_TYPE_TARGET_MSGOUT;
ahc->msgin_index = 0;
}
-#if AHC_TARGET_MODE
else
ahc_setup_target_msgin(ahc,
&devinfo,
scb);
-#endif
}
+#endif
}
ahc_handle_message_phase(ahc);
@@ -796,7 +785,44 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
ahc_outb(ahc, LASTPHASE, curphase);
ahc_outb(ahc, SCSISIGO, curphase);
}
- ahc_inb(ahc, SCSIDATL);
+ if ((ahc_inb(ahc, SCSISIGI) & (CDI|MSGI)) == 0) {
+ int wait;
+
+ /*
+ * In a data phase. Faster to bitbucket
+ * the data than to individually ack each
+ * byte. This is also the only strategy
+ * that will work with AUTOACK enabled.
+ */
+ ahc_outb(ahc, SXFRCTL1,
+ ahc_inb(ahc, SXFRCTL1) | BITBUCKET);
+ wait = 5000;
+ while (--wait != 0) {
+ if ((ahc_inb(ahc, SCSISIGI)
+ & (CDI|MSGI)) != 0)
+ break;
+ ahc_delay(100);
+ }
+ ahc_outb(ahc, SXFRCTL1,
+ ahc_inb(ahc, SXFRCTL1) & ~BITBUCKET);
+ if (wait == 0) {
+ struct scb *scb;
+ u_int scb_index;
+
+ ahc_print_devinfo(ahc, &devinfo);
+ printf("Unable to clear parity error. "
+ "Resetting bus.\n");
+ scb_index = ahc_inb(ahc, SCB_TAG);
+ scb = ahc_lookup_scb(ahc, scb_index);
+ if (scb != NULL)
+ ahc_set_transaction_status(scb,
+ CAM_UNCOR_PARITY);
+ ahc_reset_channel(ahc, devinfo.channel,
+ /*init reset*/TRUE);
+ }
+ } else {
+ ahc_inb(ahc, SCSIDATL);
+ }
}
break;
}
@@ -845,7 +871,12 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
* target does a command complete.
*/
ahc_freeze_devq(ahc, scb);
- ahc_set_transaction_status(scb, CAM_DATA_RUN_ERR);
+ if ((scb->flags & SCB_SENSE) == 0) {
+ ahc_set_transaction_status(scb, CAM_DATA_RUN_ERR);
+ } else {
+ scb->flags &= ~SCB_SENSE;
+ ahc_set_transaction_status(scb, CAM_AUTOSENSE_FAIL);
+ }
ahc_freeze_scb(scb);
if ((ahc->features & AHC_ULTRA2) != 0) {
@@ -961,11 +992,8 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
char cur_channel;
char intr_channel;
- /* Make sure the sequencer is in a safe location. */
- ahc_clear_critical_section(ahc);
-
if ((ahc->features & AHC_TWIN) != 0
- && ((ahc_inb(ahc, SBLKCTL) & SELBUSB) != 0))
+ && ((ahc_inb(ahc, SBLKCTL) & SELBUSB) != 0))
cur_channel = 'B';
else
cur_channel = 'A';
@@ -992,10 +1020,13 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
}
}
+ /* Make sure the sequencer is in a safe location. */
+ ahc_clear_critical_section(ahc);
+
scb_index = ahc_inb(ahc, SCB_TAG);
scb = ahc_lookup_scb(ahc, scb_index);
if (scb != NULL
- && (ahc_inb(ahc, SEQ_FLAGS) & IDENTIFY_SEEN) == 0)
+ && (ahc_inb(ahc, SEQ_FLAGS) & NOT_IDENTIFIED) != 0)
scb = NULL;
if ((ahc->features & AHC_ULTRA2) != 0
@@ -1042,6 +1073,7 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
u_int scsirate;
u_int i;
u_int sstat2;
+ int silent;
lastphase = ahc_inb(ahc, LASTPHASE);
curphase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK;
@@ -1069,29 +1101,47 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
break;
}
mesg_out = ahc_phase_table[i].mesg_out;
- if (scb != NULL)
- ahc_print_path(ahc, scb);
- else
+ silent = FALSE;
+ if (scb != NULL) {
+ if (SCB_IS_SILENT(scb))
+ silent = TRUE;
+ else
+ ahc_print_path(ahc, scb);
+ scb->flags |= SCB_TRANSMISSION_ERROR;
+ } else
printf("%s:%c:%d: ", ahc_name(ahc), intr_channel,
SCSIID_TARGET(ahc, ahc_inb(ahc, SAVED_SCSIID)));
scsirate = ahc_inb(ahc, SCSIRATE);
- printf("parity error detected %s. "
- "SEQADDR(0x%x) SCSIRATE(0x%x)\n",
- ahc_phase_table[i].phasemsg,
- ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8),
- scsirate);
-
- if ((ahc->features & AHC_DT) != 0) {
+ if (silent == FALSE) {
+ printf("parity error detected %s. "
+ "SEQADDR(0x%x) SCSIRATE(0x%x)\n",
+ ahc_phase_table[i].phasemsg,
+ ahc_inw(ahc, SEQADDR0),
+ scsirate);
+ if ((ahc->features & AHC_DT) != 0) {
+ if ((sstat2 & CRCVALERR) != 0)
+ printf("\tCRC Value Mismatch\n");
+ if ((sstat2 & CRCENDERR) != 0)
+ printf("\tNo terminal CRC packet "
+ "recevied\n");
+ if ((sstat2 & CRCREQERR) != 0)
+ printf("\tIllegal CRC packet "
+ "request\n");
+ if ((sstat2 & DUAL_EDGE_ERR) != 0)
+ printf("\tUnexpected %sDT Data Phase\n",
+ (scsirate & SINGLE_EDGE)
+ ? "" : "non-");
+ }
+ }
- if ((sstat2 & CRCVALERR) != 0)
- printf("\tCRC Value Mismatch\n");
- if ((sstat2 & CRCENDERR) != 0)
- printf("\tNo terminal CRC packet recevied\n");
- if ((sstat2 & CRCREQERR) != 0)
- printf("\tIllegal CRC packet request\n");
- if ((sstat2 & DUAL_EDGE_ERR) != 0)
- printf("\tUnexpected %sDT Data Phase\n",
- (scsirate & SINGLE_EDGE) ? "" : "non-");
+ if ((ahc->features & AHC_DT) != 0
+ && (sstat2 & DUAL_EDGE_ERR) != 0) {
+ /*
+ * This error applies regardless of
+ * data direction, so ignore the value
+ * in the phase table.
+ */
+ mesg_out = MSG_INITIATOR_DET_ERR;
}
/*
@@ -1107,10 +1157,16 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
else
ahc_outb(ahc, MSG_OUT, mesg_out);
}
+ /*
+ * Force a renegotiation with this target just in
+ * case we are out of sync for some external reason
+ * unknown (or unreported) by the target.
+ */
+ ahc_force_renegotiation(ahc);
ahc_outb(ahc, CLRINT, CLRSCSIINT);
ahc_unpause(ahc);
} else if ((status & SELTO) != 0) {
- u_int scbptr;
+ u_int scbptr;
/* Stop the selection */
ahc_outb(ahc, SCSISEQ, 0);
@@ -1125,7 +1181,7 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
/*
* Although the driver does not care about the
* 'Selection in Progress' status bit, the busy
- * LED does. SELINGO is only cleared by a successful
+ * LED does. SELINGO is only cleared by a sucessfull
* selection, so we must manually clear it to insure
* the LED turns off just incase no future successful
* selections occur (e.g. no devices on the bus).
@@ -1141,7 +1197,25 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
printf("%s: ahc_intr - referenced scb not "
"valid during SELTO scb(%d, %d)\n",
ahc_name(ahc), scbptr, scb_index);
+ ahc_dump_card_state(ahc);
} else {
+#ifdef AHC_DEBUG
+ if ((ahc_debug & AHC_SHOW_SELTO) != 0) {
+ ahc_print_path(ahc, scb);
+ printf("Saw Selection Timeout for SCB 0x%x\n",
+ scb_index);
+ }
+#endif
+ /*
+ * Force a renegotiation with this target just in
+ * case the cable was pulled and will later be
+ * re-attached. The target may forget its negotiation
+ * settings with us should it attempt to reselect
+ * during the interruption. The target will not issue
+ * a unit attention in this case, so we must always
+ * renegotiate.
+ */
+ ahc_force_renegotiation(ahc);
ahc_set_transaction_status(scb, CAM_SEL_TIMEOUT);
ahc_freeze_devq(ahc, scb);
}
@@ -1196,10 +1270,10 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
ahc_fetch_devinfo(ahc, &devinfo);
tag = SCB_LIST_NULL;
if (ahc_sent_msg(ahc, AHCMSG_1B, MSG_ABORT_TAG, TRUE)
- || ahc_sent_msg(ahc, AHCMSG_1B, MSG_ABORT, TRUE)) {
+ || ahc_sent_msg(ahc, AHCMSG_1B, MSG_ABORT, TRUE)) {
if (ahc->msgout_buf[ahc->msgout_index - 1]
- == MSG_ABORT_TAG)
- tag = scb->hscb->tag;
+ == MSG_ABORT_TAG)
+ tag = scb->hscb->tag;
ahc_print_path(ahc, scb);
printf("SCB %d - Abort%s Completed.\n",
scb->hscb->tag, tag == SCB_LIST_NULL ?
@@ -1211,7 +1285,6 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
printerror = 0;
} else if (ahc_sent_msg(ahc, AHCMSG_1B,
MSG_BUS_DEV_RESET, TRUE)) {
- struct ahc_devinfo devinfo;
#ifdef __FreeBSD__
/*
* Don't mark the user's request for this BDR
@@ -1305,13 +1378,19 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
if (lastphase == ahc_phase_table[i].phase)
break;
}
+ /*
+ * Renegotiate with this device at the
+ * next opportunity just in case this busfree
+ * is due to a negotiation mismatch with the
+ * device.
+ */
+ ahc_force_renegotiation(ahc);
printf("Unexpected busfree %s\n"
"SEQADDR == 0x%x\n",
ahc_phase_table[i].phasemsg,
ahc_inb(ahc, SEQADDR0)
| (ahc_inb(ahc, SEQADDR1) << 8));
}
- ahc_clear_msg_state(ahc);
ahc_outb(ahc, CLRINT, CLRSCSIINT);
ahc_restart(ahc);
} else {
@@ -1321,6 +1400,27 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
}
}
+/*
+ * Force renegotiation to occur the next time we initiate
+ * a command to the current device.
+ */
+void
+ahc_force_renegotiation(struct ahc_softc *ahc)
+{
+ struct ahc_devinfo devinfo;
+ struct ahc_initiator_tinfo *targ_info;
+ struct ahc_tmode_tstate *tstate;
+
+ ahc_fetch_devinfo(ahc, &devinfo);
+ targ_info = ahc_fetch_transinfo(ahc,
+ devinfo.channel,
+ devinfo.our_scsiid,
+ devinfo.target,
+ &tstate);
+ ahc_update_neg_request(ahc, &devinfo, tstate,
+ targ_info, AHC_NEG_IF_NON_ASYNC);
+}
+
#define AHC_MAX_STEPS 2000
void
ahc_clear_critical_section(struct ahc_softc *ahc)
@@ -1381,15 +1481,29 @@ ahc_clear_critical_section(struct ahc_softc *ahc)
simode0 = ahc_inb(ahc, SIMODE0);
ahc_outb(ahc, SIMODE0, 0);
simode1 = ahc_inb(ahc, SIMODE1);
- ahc_outb(ahc, SIMODE1, 0);
+ if ((ahc->features & AHC_DT) != 0)
+ /*
+ * On DT class controllers, we
+ * use the enhanced busfree logic.
+ * Unfortunately we cannot re-enable
+ * busfree detection within the
+ * current connection, so we must
+ * leave it on while single stepping.
+ */
+ ahc_outb(ahc, SIMODE1, ENBUSFREE);
+ else
+ ahc_outb(ahc, SIMODE1, 0);
ahc_outb(ahc, CLRINT, CLRSCSIINT);
ahc_outb(ahc, SEQCTL, ahc_inb(ahc, SEQCTL) | STEP);
stepping = TRUE;
}
+ if ((ahc->features & AHC_DT) != 0) {
+ ahc_outb(ahc, CLRSINT1, CLRBUSFREE);
+ ahc_outb(ahc, CLRINT, CLRSCSIINT);
+ }
ahc_outb(ahc, HCNTRL, ahc->unpause);
- do {
+ while (!ahc_is_paused(ahc))
ahc_delay(200);
- } while (!ahc_is_paused(ahc));
}
if (stepping) {
ahc_outb(ahc, SIMODE0, simode0);
@@ -1411,12 +1525,16 @@ ahc_clear_intstat(struct ahc_softc *ahc)
CLRREQINIT);
ahc_flush_device_writes(ahc);
ahc_outb(ahc, CLRSINT0, CLRSELDO|CLRSELDI|CLRSELINGO);
- ahc_flush_device_writes(ahc);
+ ahc_flush_device_writes(ahc);
ahc_outb(ahc, CLRINT, CLRSCSIINT);
ahc_flush_device_writes(ahc);
}
/**************************** Debugging Routines ******************************/
+#ifdef AHC_DEBUG
+uint32_t ahc_debug = 0; /* AHC_SHOW_MISC|AHC_SHOW_SENSE|AHC_DEBUG_OPTS;*/
+#endif
+
void
ahc_print_scb(struct scb *scb)
{
@@ -1468,10 +1586,11 @@ ahc_alloc_tstate(struct ahc_softc *ahc, u_int scsi_id, char channel)
master_tstate = ahc->enabled_targets[ahc->our_id_b + 8];
}
if (ahc->enabled_targets[scsi_id] != NULL
- && ahc->enabled_targets[scsi_id] != master_tstate)
+ && ahc->enabled_targets[scsi_id] != master_tstate)
panic("%s: ahc_alloc_tstate - Target already allocated",
ahc_name(ahc));
- tstate = malloc(sizeof(*tstate), M_DEVBUF, M_NOWAIT);
+ tstate = (struct ahc_tmode_tstate*)malloc(sizeof(*tstate),
+ M_DEVBUF, M_NOWAIT);
if (tstate == NULL)
return (NULL);
@@ -1485,7 +1604,7 @@ ahc_alloc_tstate(struct ahc_softc *ahc, u_int scsi_id, char channel)
memcpy(tstate, master_tstate, sizeof(*tstate));
memset(tstate->enabled_luns, 0, sizeof(tstate->enabled_luns));
tstate->ultraenb = 0;
- for (i = 0; i < 16; i++) {
+ for (i = 0; i < AHC_NUM_TARGETS; i++) {
memset(&tstate->transinfo[i].curr, 0,
sizeof(tstate->transinfo[i].curr));
memset(&tstate->transinfo[i].goal, 0,
@@ -1534,7 +1653,8 @@ ahc_free_tstate(struct ahc_softc *ahc, u_int scsi_id, char channel, int force)
struct ahc_syncrate *
ahc_devlimited_syncrate(struct ahc_softc *ahc,
struct ahc_initiator_tinfo *tinfo,
- u_int *period, u_int *ppr_options, role_t role) {
+ u_int *period, u_int *ppr_options, role_t role)
+{
struct ahc_transinfo *transinfo;
u_int maxsync;
@@ -1567,6 +1687,10 @@ ahc_devlimited_syncrate(struct ahc_softc *ahc,
else
transinfo = &tinfo->goal;
*ppr_options &= transinfo->ppr_options;
+ if (transinfo->width == MSG_EXT_WDTR_BUS_8_BIT) {
+ maxsync = MAX(maxsync, AHC_SYNCRATE_ULTRA2);
+ *ppr_options &= ~MSG_EXT_PPR_DT_REQ;
+ }
if (transinfo->period == 0) {
*period = 0;
*ppr_options = 0;
@@ -1743,17 +1867,29 @@ ahc_validate_width(struct ahc_softc *ahc, struct ahc_initiator_tinfo *tinfo,
int
ahc_update_neg_request(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
struct ahc_tmode_tstate *tstate,
- struct ahc_initiator_tinfo *tinfo, int force)
+ struct ahc_initiator_tinfo *tinfo, ahc_neg_type neg_type)
{
u_int auto_negotiate_orig;
auto_negotiate_orig = tstate->auto_negotiate;
+ if (neg_type == AHC_NEG_ALWAYS) {
+ /*
+ * Force our "current" settings to be
+ * unknown so that unless a bus reset
+ * occurs the need to renegotiate is
+ * recorded persistently.
+ */
+ if ((ahc->features & AHC_WIDE) != 0)
+ tinfo->curr.width = AHC_WIDTH_UNKNOWN;
+ tinfo->curr.period = AHC_PERIOD_UNKNOWN;
+ tinfo->curr.offset = AHC_OFFSET_UNKNOWN;
+ }
if (tinfo->curr.period != tinfo->goal.period
|| tinfo->curr.width != tinfo->goal.width
|| tinfo->curr.offset != tinfo->goal.offset
|| tinfo->curr.ppr_options != tinfo->goal.ppr_options
- || (force
- && (tinfo->goal.period != 0
+ || (neg_type == AHC_NEG_IF_NON_ASYNC
+ && (tinfo->goal.offset != 0
|| tinfo->goal.width != MSG_EXT_WDTR_BUS_8_BIT
|| tinfo->goal.ppr_options != 0)))
tstate->auto_negotiate |= devinfo->target_mask;
@@ -1867,8 +2003,8 @@ ahc_set_syncrate(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
tinfo->curr.ppr_options = ppr_options;
ahc_send_async(ahc, devinfo->channel, devinfo->target,
- CAM_LUN_WILDCARD, AC_TRANSFER_NEG, NULL);
- if (1 /*bootverbose*/) {
+ CAM_LUN_WILDCARD, AC_TRANSFER_NEG, NULL);
+ if (1 /*bootverbose*/ ) {
if (offset != 0) {
printf("%s: target %d synchronous at %sMHz%s, "
"offset = 0x%x\n", ahc_name(ahc),
@@ -1884,7 +2020,7 @@ ahc_set_syncrate(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
}
update_needed += ahc_update_neg_request(ahc, devinfo, tstate,
- tinfo, /*force*/FALSE);
+ tinfo, AHC_NEG_TO_GOAL);
if (update_needed)
ahc_update_pending_scbs(ahc);
@@ -1946,7 +2082,7 @@ ahc_set_width(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
}
update_needed += ahc_update_neg_request(ahc, devinfo, tstate,
- tinfo, /*force*/FALSE);
+ tinfo, AHC_NEG_TO_GOAL);
if (update_needed)
ahc_update_pending_scbs(ahc);
}
@@ -1959,8 +2095,6 @@ ahc_set_tags(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
ahc_queue_alg alg)
{
ahc_platform_set_tags(ahc, devinfo, alg);
- ahc_send_async(ahc, devinfo->channel, devinfo->target,
- devinfo->lun, AC_TRANSFER_NEG, &alg);
}
/*
@@ -2060,7 +2194,8 @@ ahc_fetch_devinfo(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
if (role == ROLE_TARGET
&& (ahc->features & AHC_MULTI_TID) != 0
- && (ahc_inb(ahc, SEQ_FLAGS) & CMDPHASE_PENDING) != 0) {
+ && (ahc_inb(ahc, SEQ_FLAGS)
+ & (CMDPHASE_PENDING|TARG_CMD_PENDING|NO_DISCONNECT)) != 0) {
/* We were selected, so pull our id from TARGIDIN */
our_id = ahc_inb(ahc, TARGIDIN) & OID;
} else if ((ahc->features & AHC_ULTRA2) != 0)
@@ -2110,7 +2245,14 @@ ahc_compile_devinfo(struct ahc_devinfo *devinfo, u_int our_id, u_int target,
devinfo->target_mask = (0x01 << devinfo->target_offset);
}
-static void
+void
+ahc_print_devinfo(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
+{
+ printf("%s:%c:%d:%d: ", ahc_name(ahc), devinfo->channel,
+ devinfo->target, devinfo->lun);
+}
+
+void
ahc_scb_devinfo(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
struct scb *scb)
{
@@ -2119,7 +2261,7 @@ ahc_scb_devinfo(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
our_id = SCSIID_OUR_ID(scb->hscb->scsiid);
role = ROLE_INITIATOR;
- if ((scb->hscb->control & TARGET_SCB) != 0)
+ if ((scb->flags & SCB_TARGET_SCB) != 0)
role = ROLE_TARGET;
ahc_compile_devinfo(devinfo, our_id, SCB_GET_TARGET(ahc, scb),
SCB_GET_LUN(scb), SCB_GET_CHANNEL(ahc, scb), role);
@@ -2141,18 +2283,18 @@ ahc_assert_atn(struct ahc_softc *ahc)
/*
* When an initiator transaction with the MK_MESSAGE flag either reconnects
* or enters the initial message out phase, we are interrupted. Fill our
- * outgoing message buffer with the appropriate message and begin handling
+ * outgoing message buffer with the appropriate message and begin handing
* the message phase(s) manually.
*/
static void
ahc_setup_initiator_msgout(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
struct scb *scb)
{
- /*
+ /*
* To facilitate adding multiple messages together,
* each routine should increment the index and len
* variables instead of setting them explicitly.
- */
+ */
ahc->msgout_index = 0;
ahc->msgout_len = 0;
@@ -2233,18 +2375,17 @@ ahc_setup_initiator_msgout(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
static void
ahc_build_transfer_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
{
- /*
+ /*
* We need to initiate transfer negotiations.
* If our current and goal settings are identical,
* we want to renegotiate due to a check condition.
- */
+ */
struct ahc_initiator_tinfo *tinfo;
struct ahc_tmode_tstate *tstate;
struct ahc_syncrate *rate;
int dowide;
int dosync;
int doppr;
- int use_ppr;
u_int period;
u_int ppr_options;
u_int offset;
@@ -2266,23 +2407,37 @@ ahc_build_transfer_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
&ppr_options, devinfo->role);
dowide = tinfo->curr.width != tinfo->goal.width;
dosync = tinfo->curr.period != period;
- doppr = tinfo->curr.ppr_options != ppr_options;
+ /*
+ * Only use PPR if we have options that need it, even if the device
+ * claims to support it. There might be an expander in the way
+ * that doesn't.
+ */
+ doppr = ppr_options != 0;
if (!dowide && !dosync && !doppr) {
dowide = tinfo->goal.width != MSG_EXT_WDTR_BUS_8_BIT;
- dosync = tinfo->goal.period != 0;
- doppr = tinfo->goal.ppr_options != 0;
+ dosync = tinfo->goal.offset != 0;
}
if (!dowide && !dosync && !doppr) {
- panic("ahc_intr: AWAITING_MSG for negotiation, "
- "but no negotiation needed");
+ /*
+ * Force async with a WDTR message if we have a wide bus,
+ * or just issue an SDTR with a 0 offset.
+ */
+ if ((ahc->features & AHC_WIDE) != 0)
+ dowide = 1;
+ else
+ dosync = 1;
+
+ if (bootverbose) {
+ ahc_print_devinfo(ahc, devinfo);
+ printf("Ensuring async\n");
+ }
}
- use_ppr = (tinfo->curr.transport_version >= 3) || doppr;
/* Target initiated PPR is not allowed in the SCSI spec */
if (devinfo->role == ROLE_TARGET)
- use_ppr = 0;
+ doppr = 0;
/*
* Both the PPR message and SDTR message require the
@@ -2292,14 +2447,14 @@ ahc_build_transfer_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
* Regardless, guarantee that if we are using WDTR and SDTR
* messages that WDTR comes first.
*/
- if (use_ppr || (dosync && !dowide)) {
+ if (doppr || (dosync && !dowide)) {
offset = tinfo->goal.offset;
ahc_validate_offset(ahc, tinfo, rate, &offset,
- use_ppr ? tinfo->goal.width
- : tinfo->curr.width,
+ doppr ? tinfo->goal.width
+ : tinfo->curr.width,
devinfo->role);
- if (use_ppr) {
+ if (doppr) {
ahc_construct_ppr(ahc, devinfo, period, offset,
tinfo->goal.width, ppr_options);
} else {
@@ -2318,6 +2473,8 @@ static void
ahc_construct_sdtr(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
u_int period, u_int offset)
{
+ if (offset == 0)
+ period = AHC_ASYNC_XFER_PERIOD;
ahc->msgout_buf[ahc->msgout_index++] = MSG_EXTENDED;
ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_SDTR_LEN;
ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_SDTR;
@@ -2360,6 +2517,8 @@ ahc_construct_ppr(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
u_int period, u_int offset, u_int bus_width,
u_int ppr_options)
{
+ if (offset == 0)
+ period = AHC_ASYNC_XFER_PERIOD;
ahc->msgout_buf[ahc->msgout_index++] = MSG_EXTENDED;
ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_PPR_LEN;
ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_PPR;
@@ -2394,6 +2553,102 @@ ahc_clear_msg_state(struct ahc_softc *ahc)
ahc_outb(ahc, CLRSINT1, CLRATNO);
}
ahc_outb(ahc, MSG_OUT, MSG_NOOP);
+ ahc_outb(ahc, SEQ_FLAGS2,
+ ahc_inb(ahc, SEQ_FLAGS2) & ~TARGET_MSG_PENDING);
+}
+
+static void
+ahc_handle_proto_violation(struct ahc_softc *ahc)
+{
+ struct ahc_devinfo devinfo;
+ struct scb *scb;
+ u_int scbid;
+ u_int seq_flags;
+ u_int curphase;
+ u_int lastphase;
+ int found;
+
+ ahc_fetch_devinfo(ahc, &devinfo);
+ scbid = ahc_inb(ahc, SCB_TAG);
+ scb = ahc_lookup_scb(ahc, scbid);
+ seq_flags = ahc_inb(ahc, SEQ_FLAGS);
+ curphase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK;
+ lastphase = ahc_inb(ahc, LASTPHASE);
+ if ((seq_flags & NOT_IDENTIFIED) != 0) {
+
+ /*
+ * The reconnecting target either did not send an
+ * identify message, or did, but we didn't find an SCB
+ * to match.
+ */
+ ahc_print_devinfo(ahc, &devinfo);
+ printf("Target did not send an IDENTIFY message. "
+ "LASTPHASE = 0x%x.\n", lastphase);
+ scb = NULL;
+ } else if (scb == NULL) {
+ /*
+ * We don't seem to have an SCB active for this
+ * transaction. Print an error and reset the bus.
+ */
+ ahc_print_devinfo(ahc, &devinfo);
+ printf("No SCB found during protocol violation\n");
+ goto proto_violation_reset;
+ } else {
+ ahc_set_transaction_status(scb, CAM_SEQUENCE_FAIL);
+ if ((seq_flags & NO_CDB_SENT) != 0) {
+ ahc_print_path(ahc, scb);
+ printf("No or incomplete CDB sent to device.\n");
+ } else if ((ahc_inb(ahc, SCB_CONTROL) & STATUS_RCVD) == 0) {
+ /*
+ * The target never bothered to provide status to
+ * us prior to completing the command. Since we don't
+ * know the disposition of this command, we must attempt
+ * to abort it. Assert ATN and prepare to send an abort
+ * message.
+ */
+ ahc_print_path(ahc, scb);
+ printf("Completed command without status.\n");
+ } else {
+ ahc_print_path(ahc, scb);
+ printf("Unknown protocol violation.\n");
+ ahc_dump_card_state(ahc);
+ }
+ }
+ if ((lastphase & ~P_DATAIN_DT) == 0
+ || lastphase == P_COMMAND) {
+proto_violation_reset:
+ /*
+ * Target either went directly to data/command
+ * phase or didn't respond to our ATN.
+ * The only safe thing to do is to blow
+ * it away with a bus reset.
+ */
+ found = ahc_reset_channel(ahc, 'A', TRUE);
+ printf("%s: Issued Channel %c Bus Reset. "
+ "%d SCBs aborted\n", ahc_name(ahc), 'A', found);
+ } else {
+ /*
+ * Leave the selection hardware off in case
+ * this abort attempt will affect yet to
+ * be sent commands.
+ */
+ ahc_outb(ahc, SCSISEQ,
+ ahc_inb(ahc, SCSISEQ) & ~ENSELO);
+ ahc_assert_atn(ahc);
+ ahc_outb(ahc, MSG_OUT, HOST_MSG);
+ if (scb == NULL) {
+ ahc_print_devinfo(ahc, &devinfo);
+ ahc->msgout_buf[0] = MSG_ABORT_TASK;
+ ahc->msgout_len = 1;
+ ahc->msgout_index = 0;
+ ahc->msg_type = MSG_TYPE_INITIATOR_MSGOUT;
+ } else {
+ ahc_print_path(ahc, scb);
+ scb->flags |= SCB_ABORT;
+ }
+ printf("Protocol violation %s. Attempting to abort.\n",
+ ahc_lookup_phase_entry(curphase)->phasemsg);
+ }
}
/*
@@ -2421,8 +2676,21 @@ reswitch:
if (ahc->msgout_len == 0)
panic("HOST_MSG_LOOP interrupt with no active message");
+#ifdef AHC_DEBUG
+ if ((ahc_debug & AHC_SHOW_MESSAGES) != 0) {
+ ahc_print_devinfo(ahc, &devinfo);
+ printf("INITIATOR_MSG_OUT");
+ }
+#endif
phasemis = bus_phase != P_MESGOUT;
if (phasemis) {
+#ifdef AHC_DEBUG
+ if ((ahc_debug & AHC_SHOW_MESSAGES) != 0) {
+ printf(" PHASEMIS %s\n",
+ ahc_lookup_phase_entry(bus_phase)
+ ->phasemsg);
+ }
+#endif
if (bus_phase == P_MESGIN) {
/*
* Change gears and see if
@@ -2443,6 +2711,10 @@ reswitch:
if (ahc->send_msg_perror) {
ahc_outb(ahc, CLRSINT1, CLRATNO);
ahc_outb(ahc, CLRSINT1, CLRREQINIT);
+#ifdef AHC_DEBUG
+ if ((ahc_debug & AHC_SHOW_MESSAGES) != 0)
+ printf(" byte 0x%x\n", ahc->send_msg_perror);
+#endif
ahc_outb(ahc, SCSIDATL, MSG_PARITY_ERROR);
break;
}
@@ -2469,6 +2741,11 @@ reswitch:
* the next byte on the bus.
*/
ahc_outb(ahc, CLRSINT1, CLRREQINIT);
+#ifdef AHC_DEBUG
+ if ((ahc_debug & AHC_SHOW_MESSAGES) != 0)
+ printf(" byte 0x%x\n",
+ ahc->msgout_buf[ahc->msgout_index]);
+#endif
ahc_outb(ahc, SCSIDATL, ahc->msgout_buf[ahc->msgout_index++]);
break;
}
@@ -2477,9 +2754,21 @@ reswitch:
int phasemis;
int message_done;
+#ifdef AHC_DEBUG
+ if ((ahc_debug & AHC_SHOW_MESSAGES) != 0) {
+ ahc_print_devinfo(ahc, &devinfo);
+ printf("INITIATOR_MSG_IN");
+ }
+#endif
phasemis = bus_phase != P_MESGIN;
-
if (phasemis) {
+#ifdef AHC_DEBUG
+ if ((ahc_debug & AHC_SHOW_MESSAGES) != 0) {
+ printf(" PHASEMIS %s\n",
+ ahc_lookup_phase_entry(bus_phase)
+ ->phasemsg);
+ }
+#endif
ahc->msgin_index = 0;
if (bus_phase == P_MESGOUT
&& (ahc->send_msg_perror == TRUE
@@ -2494,6 +2783,11 @@ reswitch:
/* Pull the byte in without acking it */
ahc->msgin_buf[ahc->msgin_index] = ahc_inb(ahc, SCSIBUSL);
+#ifdef AHC_DEBUG
+ if ((ahc_debug & AHC_SHOW_MESSAGES) != 0)
+ printf(" byte 0x%x\n",
+ ahc->msgin_buf[ahc->msgin_index]);
+#endif
message_done = ahc_parse_msg(ahc, &devinfo);
@@ -2509,14 +2803,25 @@ reswitch:
* assert ATN so the target takes us to the
* message out phase.
*/
- if (ahc->msgout_len != 0)
+ if (ahc->msgout_len != 0) {
+#ifdef AHC_DEBUG
+ if ((ahc_debug & AHC_SHOW_MESSAGES) != 0) {
+ ahc_print_devinfo(ahc, &devinfo);
+ printf("Asserting ATN for response\n");
+ }
+#endif
ahc_assert_atn(ahc);
+ }
} else
ahc->msgin_index++;
- /* Ack the byte */
- ahc_outb(ahc, CLRSINT1, CLRREQINIT);
- ahc_inb(ahc, SCSIDATL);
+ if (message_done == MSGLOOP_TERMINATED) {
+ end_session = TRUE;
+ } else {
+ /* Ack the byte */
+ ahc_outb(ahc, CLRSINT1, CLRREQINIT);
+ ahc_inb(ahc, SCSIDATL);
+ }
break;
}
case MSG_TYPE_TARGET_MSGIN:
@@ -2718,7 +3023,7 @@ ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
/*
* Parse as much of the message as is available,
* rejecting it if we don't support it. When
- * the entire message is availible and has been
+ * the entire message is available and has been
* handled, return MSGLOOP_MSGCOMPLETE, indicating
* that we have parsed an entire message.
*
@@ -2727,6 +3032,17 @@ ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
* extended message type.
*/
switch (ahc->msgin_buf[0]) {
+ case MSG_DISCONNECT:
+ case MSG_SAVEDATAPOINTER:
+ case MSG_CMDCOMPLETE:
+ case MSG_RESTOREPOINTERS:
+ case MSG_IGN_WIDE_RESIDUE:
+ /*
+ * End our message loop as these are messages
+ * the sequencer handles on its own.
+ */
+ done = MSGLOOP_TERMINATED;
+ break;
case MSG_MESSAGE_REJECT:
response = ahc_handle_msg_reject(ahc, devinfo);
/* FALLTHROUGH */
@@ -2780,7 +3096,7 @@ ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
ahc->msgin_buf[3], saved_offset,
period, offset);
}
- ahc_set_syncrate(ahc, devinfo,
+ ahc_set_syncrate(ahc, devinfo,
syncrate, period,
offset, ppr_options,
AHC_TRANS_ACTIVE|AHC_TRANS_GOAL,
@@ -2896,7 +3212,7 @@ ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
AHC_TRANS_ACTIVE, /*paused*/TRUE);
if (sending_reply == FALSE && reject == FALSE) {
- if (tinfo->goal.period) {
+ if (tinfo->goal.offset) {
ahc->msgout_index = 0;
ahc->msgout_len = 0;
ahc_build_transfer_msg(ahc, devinfo);
@@ -3030,6 +3346,7 @@ ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
}
break;
}
+#ifdef AHC_TARGET_MODE
case MSG_BUS_DEV_RESET:
ahc_handle_devreset(ahc, devinfo,
CAM_BDR_SENT,
@@ -3041,18 +3358,20 @@ ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
case MSG_ABORT_TAG:
case MSG_ABORT:
case MSG_CLEAR_QUEUE:
-#ifdef AHC_TARGET_MODE
+ {
+ int tag;
+
/* Target mode messages */
if (devinfo->role != ROLE_TARGET) {
reject = TRUE;
break;
}
+ tag = SCB_LIST_NULL;
+ if (ahc->msgin_buf[0] == MSG_ABORT_TAG)
+ tag = ahc_inb(ahc, INITIATOR_TAG);
ahc_abort_scbs(ahc, devinfo->target, devinfo->channel,
- devinfo->lun,
- ahc->msgin_buf[0] == MSG_ABORT_TAG
- ? SCB_LIST_NULL
- : ahc_inb(ahc, INITIATOR_TAG),
- ROLE_TARGET, CAM_REQ_ABORTED);
+ devinfo->lun, tag, ROLE_TARGET,
+ CAM_REQ_ABORTED);
tstate = ahc->enabled_targets[devinfo->our_scsiid];
if (tstate != NULL) {
@@ -3063,12 +3382,14 @@ ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
ahc_queue_lstate_event(ahc, lstate,
devinfo->our_scsiid,
ahc->msgin_buf[0],
- /*arg*/0);
+ /*arg*/tag);
ahc_send_lstate_events(ahc, lstate);
}
}
- done = MSGLOOP_MSGCOMPLETE;
+ ahc_restart(ahc);
+ done = MSGLOOP_TERMINATED;
break;
+ }
#endif
case MSG_TERM_IO_PROC:
default:
@@ -3156,7 +3477,7 @@ ahc_handle_msg_reject(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
* but rejected our response, we already cleared the
* sync rate before sending our WDTR.
*/
- if (tinfo->goal.period) {
+ if (tinfo->goal.offset != tinfo->curr.offset) {
/* Start the sync negotiation */
ahc->msgout_index = 0;
@@ -3426,7 +3747,7 @@ ahc_handle_devreset(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
found = ahc_abort_scbs(ahc, devinfo->target, devinfo->channel,
CAM_LUN_WILDCARD, SCB_LIST_NULL, devinfo->role,
status);
-
+
#ifdef AHC_TARGET_MODE
/*
* Send an immediate notify ccb to all target mord peripheral
@@ -3458,7 +3779,7 @@ ahc_handle_devreset(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
AHC_TRANS_CUR, /*paused*/TRUE);
ahc_send_async(ahc, devinfo->channel, devinfo->target,
- CAM_LUN_WILDCARD, AC_SENT_BDR, NULL);
+ CAM_LUN_WILDCARD, AC_SENT_BDR, NULL);
if (message != NULL
&& (verbose_level <= bootverbose))
@@ -3489,52 +3810,6 @@ ahc_setup_target_msgin(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
ahc->msg_type = MSG_TYPE_TARGET_MSGIN;
}
#endif
-/**************************** Initialization **********************************/
-/*
- * Allocate a controller structure for a new device
- * and perform initial initialization.
- */
-struct ahc_softc *
-ahc_alloc(void *platform_arg, char *name)
-{
- struct ahc_softc *ahc;
- int i;
-
-#ifdef __OpenBSD__ /* OpenBSD provides softc! */
- ahc = (struct ahc_softc *)platform_arg;
-#else
-#ifndef __FreeBSD__
- ahc = malloc(sizeof(*ahc), M_DEVBUF, M_NOWAIT);
- if (!ahc) {
- printf("aic7xxx: cannot malloc softc!\n");
- free(name, M_DEVBUF);
- return NULL;
- }
-#else
- ahc = device_get_softc((device_t)platform_arg);
-#endif
- memset(ahc, 0, sizeof(*ahc));
-#endif
- LIST_INIT(&ahc->pending_scbs);
- /* We don't know our unit number until the OSM sets it */
- ahc->name = name;
- ahc->unit = -1;
- ahc->description = NULL;
- ahc->channel = 'A';
- ahc->channel_b = 'B';
- ahc->chip = AHC_NONE;
- ahc->features = AHC_FENONE;
- ahc->bugs = AHC_BUGNONE;
- ahc->flags = AHC_FNONE;
-
- for (i = 0; i < 16; i++)
- TAILQ_INIT(&ahc->untagged_queues[i]);
- if (ahc_platform_alloc(ahc, platform_arg) != 0) {
- ahc_free(ahc);
- ahc = NULL;
- }
- return (ahc);
-}
int
ahc_softc_init(struct ahc_softc *ahc)
@@ -3614,6 +3889,22 @@ ahc_softc_insert(struct ahc_softc *ahc)
ahc->init_level++;
}
+/*
+ * Verify that the passed in softc pointer is for a
+ * controller that is still configured.
+ */
+struct ahc_softc *
+ahc_find_softc(struct ahc_softc *ahc)
+{
+ struct ahc_softc *list_ahc;
+
+ TAILQ_FOREACH(list_ahc, &ahc_tailq, links) {
+ if (list_ahc == ahc)
+ return (ahc);
+ }
+ return (NULL);
+}
+
void
ahc_set_unit(struct ahc_softc *ahc, int unit)
{
@@ -3628,7 +3919,6 @@ ahc_set_name(struct ahc_softc *ahc, char *name)
ahc->name = name;
}
-#ifndef __OpenBSD__
void
ahc_free(struct ahc_softc *ahc)
{
@@ -3637,34 +3927,20 @@ ahc_free(struct ahc_softc *ahc)
ahc_fini_scbdata(ahc);
switch (ahc->init_level) {
default:
- case 5:
+ case 2:
ahc_shutdown(ahc);
- TAILQ_REMOVE(&ahc_tailq, ahc, links);
- /* FALLTHROUGH */
- case 4:
- ahc_dmamap_unload(ahc, ahc->shared_data_dmat,
- ahc->shared_data_dmamap);
- /* FALLTHROUGH */
- case 3:
- ahc_dmamem_free(ahc, ahc->shared_data_dmat, ahc->qoutfifo,
- ahc->shared_data_dmamap);
- ahc_dmamap_destroy(ahc, ahc->shared_data_dmat,
- ahc->shared_data_dmamap);
+ /* TAILQ_REMOVE(&ahc_tailq, ahc, links); XXX */
/* FALLTHROUGH */
- case 2:
- ahc_dma_tag_destroy(ahc, ahc->shared_data_dmat);
case 1:
-#ifndef __linux__
- ahc_dma_tag_destroy(ahc, ahc->buffer_dmat);
-#endif
+ bus_dmamap_unload(ahc->parent_dmat, ahc->shared_data_dmamap);
+ bus_dmamap_destroy(ahc->parent_dmat, ahc->shared_data_dmamap);
+ bus_dmamem_unmap(ahc->parent_dmat, (caddr_t)ahc->qoutfifo, ahc->shared_data_size);
+ bus_dmamem_free(ahc->parent_dmat, &ahc->shared_data_seg, ahc->shared_data_nseg);
break;
case 0:
break;
}
-#ifndef __linux__
- ahc_dma_tag_destroy(ahc, ahc->parent_dmat);
-#endif
ahc_platform_free(ahc);
for (i = 0; i < AHC_NUM_TARGETS; i++) {
struct ahc_tmode_tstate *tstate;
@@ -3679,7 +3955,7 @@ ahc_free(struct ahc_softc *ahc)
lstate = tstate->enabled_luns[j];
if (lstate != NULL) {
- xpt_free_path(lstate->path);
+ /*xpt_free_path(lstate->path);*/
free(lstate, M_DEVBUF);
}
}
@@ -3689,18 +3965,21 @@ ahc_free(struct ahc_softc *ahc)
}
#if AHC_TARGET_MODE
if (ahc->black_hole != NULL) {
- xpt_free_path(ahc->black_hole->path);
+ /*xpt_free_path(ahc->black_hole->path);*/
free(ahc->black_hole, M_DEVBUF);
}
#endif
+#ifndef __NetBSD__
if (ahc->name != NULL)
free(ahc->name, M_DEVBUF);
+#endif
+ if (ahc->seep_config != NULL)
+ free(ahc->seep_config, M_DEVBUF);
#ifndef __FreeBSD__
free(ahc, M_DEVBUF);
#endif
return;
}
-#endif /* __OpenBSD__ */
void
ahc_shutdown(void *arg)
@@ -3716,7 +3995,7 @@ ahc_shutdown(void *arg)
ahc_outb(ahc, SXFRCTL0, 0);
ahc_outb(ahc, DSPCISTATUS, 0);
- for (i = TARG_SCSIRATE; i < HA_274_BIOSCTRL; i++)
+ for (i = TARG_SCSIRATE; i < SCSICONF; i++)
ahc_outb(ahc, i, 0);
}
@@ -3737,6 +4016,14 @@ ahc_reset(struct ahc_softc *ahc)
* to disturb the integrity of the bus.
*/
ahc_pause(ahc);
+ if ((ahc_inb(ahc, HCNTRL) & CHIPRST) != 0) {
+ /*
+ * The chip has not been initialized since
+ * PCI/EISA/VLB bus reset. Don't trust
+ * "left over BIOS data".
+ */
+ ahc->flags |= AHC_NO_BIOS_INIT;
+ }
sxfrctl1_b = 0;
if ((ahc->chip & AHC_CHIPID_MASK) == AHC_AIC7770) {
u_int sblkctl;
@@ -3755,7 +4042,10 @@ ahc_reset(struct ahc_softc *ahc)
ahc_outb(ahc, HCNTRL, CHIPRST | ahc->pause);
/*
- * Ensure that the reset has finished
+ * Ensure that the reset has finished. We delay 1000us
+ * prior to reading the register to make sure the chip
+ * has sufficiently completed its reset to handle register
+ * accesses.
*/
wait = 1000;
do {
@@ -3786,7 +4076,7 @@ ahc_reset(struct ahc_softc *ahc)
ahc->features |= AHC_TWIN;
break;
default:
- printf(" Unsupported adapter type. Ignoring\n");
+ printf(" Unsupported adapter type (0x%x). Ignoring\n", sblkctl);
return(-1);
}
@@ -3836,7 +4126,7 @@ ahc_probe_scbs(struct ahc_softc *ahc) {
return (i);
}
-#ifndef __OpenBSD__
+#if 0
static void
ahc_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
{
@@ -3845,20 +4135,31 @@ ahc_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
baddr = (bus_addr_t *)arg;
*baddr = segs->ds_addr;
}
-#endif
+#endif
-#ifndef __OpenBSD__
static void
-#else
-void
-#endif
ahc_build_free_scb_list(struct ahc_softc *ahc)
{
+ int scbsize;
int i;
+ scbsize = 32;
+ if ((ahc->flags & AHC_LSCBS_ENABLED) != 0)
+ scbsize = 64;
+
for (i = 0; i < ahc->scb_data->maxhscbs; i++) {
+ int j;
+
ahc_outb(ahc, SCBPTR, i);
+ /*
+ * Touch all SCB bytes to avoid parity errors
+ * should one of our debugging routines read
+ * an otherwise uninitiatlized byte.
+ */
+ for (j = 0; j < scbsize; j++)
+ ahc_outb(ahc, SCB_BASE+j, 0xFF);
+
/* Clear the control byte. */
ahc_outb(ahc, SCB_CONTROL, 0);
@@ -3868,20 +4169,17 @@ ahc_build_free_scb_list(struct ahc_softc *ahc)
else
ahc_outb(ahc, SCB_NEXT, SCB_LIST_NULL);
- /* Make the tag number invalid */
+ /* Make the tag number, SCSIID, and lun invalid */
ahc_outb(ahc, SCB_TAG, SCB_LIST_NULL);
+ ahc_outb(ahc, SCB_SCSIID, 0xFF);
+ ahc_outb(ahc, SCB_LUN, 0xFF);
}
/* Make sure that the last SCB terminates the free list */
ahc_outb(ahc, SCBPTR, i-1);
ahc_outb(ahc, SCB_NEXT, SCB_LIST_NULL);
-
- /* Ensure we clear the 0 SCB's control byte. */
- ahc_outb(ahc, SCBPTR, 0);
- ahc_outb(ahc, SCB_CONTROL, 0);
}
-#ifndef __OpenBSD__
static int
ahc_init_scbdata(struct ahc_softc *ahc)
{
@@ -3893,11 +4191,11 @@ ahc_init_scbdata(struct ahc_softc *ahc)
/* Allocate SCB resources */
scb_data->scbarray =
- (struct scb *)malloc(sizeof(struct scb) * AHC_SCB_MAX,
+ (struct scb *)malloc(sizeof(struct scb) * AHC_SCB_MAX_ALLOC,
M_DEVBUF, M_NOWAIT);
if (scb_data->scbarray == NULL)
return (ENOMEM);
- memset(scb_data->scbarray, 0, sizeof(struct scb) * AHC_SCB_MAX);
+ memset(scb_data->scbarray, 0, sizeof(struct scb) * AHC_SCB_MAX_ALLOC);
/* Determine the number of hardware SCBs and initialize them */
@@ -3926,87 +4224,30 @@ ahc_init_scbdata(struct ahc_softc *ahc)
* use of MAXADDR and MAXSIZE.
*/
- /* DMA tag for our hardware scb structures */
- if (ahc_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/1,
- /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1,
- /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
- /*highaddr*/BUS_SPACE_MAXADDR,
- /*filter*/NULL, /*filterarg*/NULL,
- AHC_SCB_MAX * sizeof(struct hardware_scb),
- /*nsegments*/1,
- /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
- /*flags*/0, &scb_data->hscb_dmat) != 0) {
+ if (ahc_createdmamem(ahc->parent_dmat,
+ AHC_SCB_MAX * sizeof(struct hardware_scb), ahc->sc_dmaflags,
+ &scb_data->hscb_dmamap,
+ (caddr_t *)&scb_data->hscbs, &scb_data->hscb_busaddr,
+ &scb_data->hscb_seg, &scb_data->hscb_nseg, ahc_name(ahc),
+ "hardware SCB structures") < 0)
goto error_exit;
- }
scb_data->init_level++;
- /* Allocation for our hscbs */
- if (ahc_dmamem_alloc(ahc, scb_data->hscb_dmat,
- (void **)&scb_data->hscbs,
- BUS_DMA_NOWAIT, &scb_data->hscb_dmamap) != 0) {
+ if (ahc_createdmamem(ahc->parent_dmat,
+ AHC_SCB_MAX * sizeof(struct scsi_sense_data), ahc->sc_dmaflags,
+ &scb_data->sense_dmamap, (caddr_t *)&scb_data->sense,
+ &scb_data->sense_busaddr, &scb_data->sense_seg,
+ &scb_data->sense_nseg, ahc_name(ahc), "sense buffers") < 0)
goto error_exit;
- }
-
- scb_data->init_level++;
-
- /* And permanently map them */
- ahc_dmamap_load(ahc, scb_data->hscb_dmat, scb_data->hscb_dmamap,
- scb_data->hscbs,
- AHC_SCB_MAX * sizeof(struct hardware_scb),
- ahc_dmamap_cb, &scb_data->hscb_busaddr, /*flags*/0);
-
- scb_data->init_level++;
-
- /* DMA tag for our sense buffers */
- if (ahc_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/1,
- /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1,
- /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
- /*highaddr*/BUS_SPACE_MAXADDR,
- /*filter*/NULL, /*filterarg*/NULL,
- AHC_SCB_MAX * sizeof(struct scsi_sense_data),
- /*nsegments*/1,
- /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
- /*flags*/0, &scb_data->sense_dmat) != 0) {
- goto error_exit;
- }
-
- scb_data->init_level++;
-
- /* Allocate them */
- if (ahc_dmamem_alloc(ahc, scb_data->sense_dmat,
- (void **)&scb_data->sense,
- BUS_DMA_NOWAIT, &scb_data->sense_dmamap) != 0) {
- goto error_exit;
- }
-
- scb_data->init_level++;
-
- /* And permanently map them */
- ahc_dmamap_load(ahc, scb_data->sense_dmat, scb_data->sense_dmamap,
- scb_data->sense,
- AHC_SCB_MAX * sizeof(struct scsi_sense_data),
- ahc_dmamap_cb, &scb_data->sense_busaddr, /*flags*/0);
-
- scb_data->init_level++;
-
- /* DMA tag for our S/G structures. We allocate in page sized chunks */
- if (ahc_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/1,
- /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1,
- /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
- /*highaddr*/BUS_SPACE_MAXADDR,
- /*filter*/NULL, /*filterarg*/NULL,
- PAGE_SIZE, /*nsegments*/1,
- /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
- /*flags*/0, &scb_data->sg_dmat) != 0) {
- goto error_exit;
- }
scb_data->init_level++;
/* Perform initial CCB allocation */
- memset(scb_data->hscbs, 0, AHC_SCB_MAX * sizeof(struct hardware_scb));
+ memset(scb_data->hscbs, 0,
+ AHC_SCB_MAX_ALLOC * sizeof(struct hardware_scb));
ahc_alloc_scbs(ahc);
+ scb_data->init_level++;
if (scb_data->numscbs == 0) {
printf("%s: ahc_init_scbdata - "
@@ -4022,7 +4263,7 @@ ahc_init_scbdata(struct ahc_softc *ahc)
ahc_outb(ahc, NEXT_QUEUED_SCB, ahc->next_queued_scb->hscb->tag);
/*
- * Note that we were successful
+ * Note that we were successfull
*/
return (0);
@@ -4042,42 +4283,33 @@ ahc_fini_scbdata(struct ahc_softc *ahc)
switch (scb_data->init_level) {
default:
- case 7:
+ case 5:
{
struct sg_map_node *sg_map;
while ((sg_map = SLIST_FIRST(&scb_data->sg_maps))!= NULL) {
SLIST_REMOVE_HEAD(&scb_data->sg_maps, links);
- ahc_dmamap_unload(ahc, scb_data->sg_dmat,
- sg_map->sg_dmamap);
- ahc_dmamem_free(ahc, scb_data->sg_dmat,
- sg_map->sg_vaddr,
- sg_map->sg_dmamap);
+ ahc_freedmamem(ahc->parent_dmat, PAGE_SIZE,
+ sg_map->sg_dmamap, (caddr_t)sg_map->sg_vaddr,
+ &sg_map->sg_dmasegs, sg_map->sg_nseg);
free(sg_map, M_DEVBUF);
}
- ahc_dma_tag_destroy(ahc, scb_data->sg_dmat);
}
- case 6:
- ahc_dmamap_unload(ahc, scb_data->sense_dmat,
- scb_data->sense_dmamap);
- case 5:
- ahc_dmamem_free(ahc, scb_data->sense_dmat, scb_data->sense,
- scb_data->sense_dmamap);
- ahc_dmamap_destroy(ahc, scb_data->sense_dmat,
- scb_data->sense_dmamap);
+ /*FALLTHROUGH*/
case 4:
- ahc_dma_tag_destroy(ahc, scb_data->sense_dmat);
+ ahc_freedmamem(ahc->parent_dmat,
+ AHC_SCB_MAX * sizeof(struct scsipi_sense_data),
+ scb_data->sense_dmamap, (caddr_t)scb_data->sense,
+ &scb_data->sense_seg, scb_data->sense_nseg);
+ /*FALLTHROUGH*/
case 3:
- ahc_dmamap_unload(ahc, scb_data->hscb_dmat,
- scb_data->hscb_dmamap);
+ ahc_freedmamem(ahc->parent_dmat,
+ AHC_SCB_MAX * sizeof(struct hardware_scb),
+ scb_data->hscb_dmamap, (caddr_t)scb_data->hscbs,
+ &scb_data->hscb_seg, scb_data->hscb_nseg);
+ /*FALLTHROUGH*/
case 2:
- ahc_dmamem_free(ahc, scb_data->hscb_dmat, scb_data->hscbs,
- scb_data->hscb_dmamap);
- ahc_dmamap_destroy(ahc, scb_data->hscb_dmat,
- scb_data->hscb_dmamap);
case 1:
- ahc_dma_tag_destroy(ahc, scb_data->hscb_dmat);
- break;
case 0:
break;
}
@@ -4097,7 +4329,7 @@ ahc_alloc_scbs(struct ahc_softc *ahc)
int i;
scb_data = ahc->scb_data;
- if (scb_data->numscbs >= AHC_SCB_MAX)
+ if (scb_data->numscbs >= AHC_SCB_MAX_ALLOC)
/* Can't allocate any more */
return;
@@ -4109,32 +4341,34 @@ ahc_alloc_scbs(struct ahc_softc *ahc)
return;
/* Allocate S/G space for the next batch of SCBS */
- if (ahc_dmamem_alloc(ahc, scb_data->sg_dmat,
- (void **)&sg_map->sg_vaddr,
- BUS_DMA_NOWAIT, &sg_map->sg_dmamap) != 0) {
+ if (ahc_createdmamem(ahc->parent_dmat, PAGE_SIZE, ahc->sc_dmaflags,
+ &sg_map->sg_dmamap,
+ (caddr_t *)&sg_map->sg_vaddr, &sg_map->sg_physaddr,
+ &sg_map->sg_dmasegs, &sg_map->sg_nseg, ahc_name(ahc),
+ "SG space") < 0) {
free(sg_map, M_DEVBUF);
return;
}
SLIST_INSERT_HEAD(&scb_data->sg_maps, sg_map, links);
- ahc_dmamap_load(ahc, scb_data->sg_dmat, sg_map->sg_dmamap,
- sg_map->sg_vaddr, PAGE_SIZE, ahc_dmamap_cb,
- &sg_map->sg_physaddr, /*flags*/0);
-
segs = sg_map->sg_vaddr;
physaddr = sg_map->sg_physaddr;
newcount = (PAGE_SIZE / (AHC_NSEG * sizeof(struct ahc_dma_seg)));
- for (i = 0; scb_data->numscbs < AHC_SCB_MAX && i < newcount; i++) {
- struct scb_platform_data *pdata;
-#ifndef __linux__
+ newcount = MIN(newcount, (AHC_SCB_MAX_ALLOC - scb_data->numscbs));
+ for (i = 0; i < newcount; i++) {
+ struct scb_platform_data *pdata = NULL;
int error;
-#endif
- pdata = (struct scb_platform_data *)malloc(sizeof(*pdata),
- M_DEVBUF, M_NOWAIT);
- if (pdata == NULL)
- break;
+
+ if (sizeof(*pdata) > 0) {
+ pdata = (struct scb_platform_data *)
+ malloc(sizeof(*pdata), M_DEVBUF, M_NOWAIT);
+ if (pdata == NULL)
+ break;
+ bzero(pdata, sizeof(*pdata));
+ }
+
next_scb->platform_data = pdata;
next_scb->sg_map = sg_map;
next_scb->sg_list = segs;
@@ -4145,12 +4379,14 @@ ahc_alloc_scbs(struct ahc_softc *ahc)
next_scb->sg_list_phys = physaddr + sizeof(struct ahc_dma_seg);
next_scb->ahc_softc = ahc;
next_scb->flags = SCB_FREE;
-#ifndef __linux__
- error = ahc_dmamap_create(ahc, ahc->buffer_dmat, /*flags*/0,
- &next_scb->dmamap);
+
+ error = bus_dmamap_create(ahc->parent_dmat,
+ AHC_MAXTRANSFER_SIZE, AHC_NSEG, MAXPHYS, 0,
+ BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW|ahc->sc_dmaflags,
+ &next_scb->dmamap);
if (error != 0)
break;
-#endif
+
next_scb->hscb = &scb_data->hscbs[scb_data->numscbs];
next_scb->hscb->tag = ahc->scb_data->numscbs;
SLIST_INSERT_HEAD(&ahc->scb_data->free_scbs,
@@ -4161,7 +4397,6 @@ ahc_alloc_scbs(struct ahc_softc *ahc)
ahc->scb_data->numscbs++;
}
}
-#endif /* __OpenBSD__ */
void
ahc_controller_info(struct ahc_softc *ahc, char *buf, size_t buf_len)
@@ -4224,9 +4459,9 @@ ahc_init(struct ahc_softc *ahc)
size_t driver_data_size;
uint32_t physaddr;
-#define AHC_DEBUG_SEQUENCER
-#ifdef AHC_DEBUG_SEQUENCER
- ahc->flags |= AHC_SEQUENCER_DEBUG;
+#ifdef AHC_DEBUG
+ if ((ahc_debug & AHC_DEBUG_SEQUENCER) != 0)
+ ahc->flags |= AHC_SEQUENCER_DEBUG;
#endif
#ifdef AHC_PRINT_SRAM
@@ -4246,8 +4481,15 @@ ahc_init(struct ahc_softc *ahc)
}
}
printf ("\n");
+ /*
+ * Reading uninitialized scratch ram may
+ * generate parity errors.
+ */
+ ahc_outb(ahc, CLRINT, CLRPARERR);
+ ahc_outb(ahc, CLRINT, CLRBRKADRINT);
#endif
max_targ = 15;
+
/*
* Assume we have a board at this stage and it has been reset.
*/
@@ -4262,76 +4504,32 @@ ahc_init(struct ahc_softc *ahc)
/*
* Only allow target mode features if this unit has them enabled.
*/
- if ((AHC_TMODE_ENABLE & (0x1 << ahc->unit)) == 0)
+ //if ((AHC_TMODE_ENABLE & (0x1 << ahc->unit)) == 0)
ahc->features &= ~AHC_TARGETMODE;
-#if !defined(__linux__) && !defined(__OpenBSD__)
- /* DMA tag for mapping buffers into device visible space. */
- if (ahc_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/1,
- /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1,
- /*lowaddr*/BUS_SPACE_MAXADDR,
- /*highaddr*/BUS_SPACE_MAXADDR,
- /*filter*/NULL, /*filterarg*/NULL,
- /*maxsize*/MAXBSIZE, /*nsegments*/AHC_NSEG,
- /*maxsegsz*/AHC_MAXTRANSFER_SIZE,
- /*flags*/BUS_DMA_ALLOCNOW,
- &ahc->buffer_dmat) != 0) {
- return (ENOMEM);
- }
-#endif
-
- ahc->init_level++;
-
/*
* DMA tag for our command fifos and other data in system memory
* the card's sequencer must be able to access. For initiator
- * roles, we need to allocate space for the the qinfifo and qoutfifo.
+ * roles, we need to allocate space for the qinfifo and qoutfifo.
* The qinfifo and qoutfifo are composed of 256 1 byte elements.
* When providing for the target mode role, we must additionally
* provide space for the incoming target command fifo and an extra
- * byte to deal with a dma bug in some chip versions.
+ * byte to deal with a DMA bug in some chip versions.
*/
driver_data_size = 2 * 256 * sizeof(uint8_t);
-#ifdef __OpenBSD__
- if (ahc_createdmamem(ahc, ahc->shared_data_dmat, driver_data_size,
- &ahc->shared_data_dmamap, (caddr_t *)&ahc->qoutfifo,
- &ahc->shared_data_busaddr, &ahc->shared_data_seg,
- &ahc->shared_data_nseg, "shared data") < 0)
- return (ENOMEM);
-
- ahc->init_level++;
-#else
-
if ((ahc->features & AHC_TARGETMODE) != 0)
driver_data_size += AHC_TMODE_CMDS * sizeof(struct target_cmd)
+ /*DMA WideOdd Bug Buffer*/1;
- if (ahc_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/1,
- /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1,
- /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
- /*highaddr*/BUS_SPACE_MAXADDR,
- /*filter*/NULL, /*filterarg*/NULL,
- driver_data_size,
- /*nsegments*/1,
- /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
- /*flags*/0, &ahc->shared_data_dmat) != 0) {
- return (ENOMEM);
- }
-
- ahc->init_level++;
- /* Allocation of driver data */
- if (ahc_dmamem_alloc(ahc, ahc->shared_data_dmat,
- (void **)&ahc->qoutfifo,
- BUS_DMA_NOWAIT, &ahc->shared_data_dmamap) != 0) {
+ if (ahc_createdmamem(ahc->parent_dmat, driver_data_size,
+ ahc->sc_dmaflags,
+ &ahc->shared_data_dmamap, (caddr_t *)&ahc->qoutfifo,
+ &ahc->shared_data_busaddr, &ahc->shared_data_seg,
+ &ahc->shared_data_nseg, ahc_name(ahc), "shared data") < 0)
return (ENOMEM);
- }
ahc->init_level++;
- /* And permanently map it in */
- ahc_dmamap_load(ahc, ahc->shared_data_dmat, ahc->shared_data_dmamap,
- ahc->qoutfifo, driver_data_size, ahc_dmamap_cb,
- &ahc->shared_data_busaddr, /*flags*/0);
if ((ahc->features & AHC_TARGETMODE) != 0) {
ahc->targetcmds = (struct target_cmd *)ahc->qoutfifo;
ahc->qoutfifo = (uint8_t *)&ahc->targetcmds[AHC_TMODE_CMDS];
@@ -4346,7 +4544,6 @@ ahc_init(struct ahc_softc *ahc)
ahc_outb(ahc, TQINPOS, ahc->tqinfifonext);
ahc->qoutfifo = (uint8_t *)&ahc->targetcmds[256];
}
-#endif
ahc->qinfifo = &ahc->qoutfifo[256];
ahc->init_level++;
@@ -4354,7 +4551,11 @@ ahc_init(struct ahc_softc *ahc)
/* Allocate SCB data now that buffer_dmat is initialized */
if (ahc->scb_data->maxhscbs == 0)
if (ahc_init_scbdata(ahc) != 0)
- return (ENOMEM);
+ return (ENOMEM);
+
+ if (bootverbose)
+ printf("%s: found %d SCBs\n", ahc_name(ahc),
+ ahc->scb_data->maxhscbs);
/*
* Allocate a tstate to house information for our
@@ -4378,20 +4579,20 @@ ahc_init(struct ahc_softc *ahc)
ahc_outb(ahc, SEQ_FLAGS, 0);
ahc_outb(ahc, SEQ_FLAGS2, 0);
- if (ahc->scb_data->maxhscbs < AHC_SCB_MAX) {
+ if (ahc->scb_data->maxhscbs < AHC_SCB_MAX_ALLOC) {
ahc->flags |= AHC_PAGESCBS;
} else {
ahc->flags &= ~AHC_PAGESCBS;
}
#ifdef AHC_DEBUG
- if (ahc_debug & AHC_SHOWMISC) {
- printf("%s: hardware scb %d bytes; kernel scb %d bytes; "
- "ahc_dma %d bytes\n",
+ if (ahc_debug & AHC_SHOW_MISC) {
+ printf("%s: hardware scb %lu bytes; kernel scb %lu bytes; "
+ "ahc_dma %lu bytes\n",
ahc_name(ahc),
- sizeof(struct hardware_scb),
- sizeof(struct scb),
- sizeof(struct ahc_dma_seg));
+ (u_long)sizeof(struct hardware_scb),
+ (u_long)sizeof(struct scb),
+ (u_long)sizeof(struct ahc_dma_seg));
}
#endif /* AHC_DEBUG */
@@ -4420,7 +4621,7 @@ ahc_init(struct ahc_softc *ahc)
/* Select Channel A */
ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) & ~SELBUSB);
}
-
+
term = (ahc->flags & AHC_TERM_ENB_A) != 0 ? STPWEN : 0;
if ((ahc->features & AHC_ULTRA2) != 0)
ahc_outb(ahc, SCSIID_ULTRA2, ahc->our_id);
@@ -4447,7 +4648,7 @@ ahc_init(struct ahc_softc *ahc)
tagenable = ALL_TARGETS_MASK;
/* Grab the disconnection disable table and invert it for our needs */
- if (ahc->flags & AHC_USEDEFAULTS) {
+ if ((ahc->flags & AHC_USEDEFAULTS) != 0) {
printf("%s: Host Adapter Bios disabled. Using default SCSI "
"device parameters\n", ahc_name(ahc));
ahc->flags |= AHC_EXTENDED_TRANS_A|AHC_EXTENDED_TRANS_B|
@@ -4564,7 +4765,8 @@ ahc_init(struct ahc_softc *ahc)
tinfo->curr.protocol_version = 2;
tinfo->curr.transport_version = 2;
}
- tstate->ultraenb = ultraenb;
+ tstate->ultraenb = 0;
+ tstate->discenable = discenable;
}
ahc->user_discenable = discenable;
ahc->user_tagenable = tagenable;
@@ -4587,7 +4789,7 @@ ahc_init(struct ahc_softc *ahc)
/* All of our queues are empty */
for (i = 0; i < 256; i++)
ahc->qoutfifo[i] = SCB_LIST_NULL;
-
+
ahc_sync_qoutfifo(ahc, BUS_DMASYNC_PREREAD);
for (i = 0; i < 256; i++)
@@ -4599,7 +4801,7 @@ ahc_init(struct ahc_softc *ahc)
ahc_outb(ahc, TARGID, 0);
ahc_outb(ahc, TARGID + 1, 0);
}
-
+
/*
* Tell the sequencer where it can find our arrays in memory.
*/
@@ -4645,6 +4847,7 @@ ahc_init(struct ahc_softc *ahc)
ahc_outb(ahc, HNSCB_QOFF, 0);
}
+
/* We don't have any waiting selections */
ahc_outb(ahc, WAITING_SCBH, SCB_LIST_NULL);
@@ -4667,7 +4870,7 @@ ahc_init(struct ahc_softc *ahc)
/*
* Load the Sequencer program and Enable the adapter
* in "fast" mode.
- */
+ */
if (bootverbose)
printf("%s: Downloading Sequencer Program...",
ahc_name(ahc));
@@ -4723,21 +4926,28 @@ ahc_pause_and_flushwork(struct ahc_softc *ahc)
{
int intstat;
int maxloops;
+ int paused;
maxloops = 1000;
ahc->flags |= AHC_ALL_INTERRUPTS;
intstat = 0;
+ paused = FALSE;
do {
+ if (paused)
+ ahc_unpause(ahc);
ahc_intr(ahc);
ahc_pause(ahc);
+ paused = TRUE;
+ ahc_outb(ahc, SCSISEQ, ahc_inb(ahc, SCSISEQ) & ~ENSELO);
ahc_clear_critical_section(ahc);
if (intstat == 0xFF && (ahc->features & AHC_REMOVABLE) != 0)
break;
- maxloops--;
- } while (((intstat = ahc_inb(ahc, INTSTAT)) & INT_PEND) && --maxloops);
+ } while (--maxloops
+ && (((intstat = ahc_inb(ahc, INTSTAT)) & INT_PEND) != 0
+ || (ahc_inb(ahc, SSTAT0) & (SELDO|SELINGO))));
if (maxloops == 0) {
printf("Infinite interrupt loop, INTSTAT = %x",
- ahc_inb(ahc, INTSTAT));
+ ahc_inb(ahc, INTSTAT));
}
ahc_platform_flushwork(ahc);
ahc->flags &= ~AHC_ALL_INTERRUPTS;
@@ -4763,7 +4973,7 @@ ahc_suspend(struct ahc_softc *ahc)
if (ahc->pending_device != NULL)
return (EBUSY);
#endif
-
+
/* Save volatile registers */
if ((ahc->features & AHC_TWIN) != 0) {
ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) | SELBUSB);
@@ -4990,6 +5200,7 @@ ahc_match_scb(struct ahc_softc *ahc, struct scb *scb, int target,
if (match != 0)
match = ((lun == slun) || (lun == CAM_LUN_WILDCARD));
if (match != 0) {
+#if 0
#if AHC_TARGET_MODE
int group;
@@ -5006,6 +5217,7 @@ ahc_match_scb(struct ahc_softc *ahc, struct scb *scb, int target,
#else /* !AHC_TARGET_MODE */
match = ((tag == scb->hscb->tag) || (tag == SCB_LIST_NULL));
#endif /* AHC_TARGET_MODE */
+#endif
}
return match;
@@ -5063,7 +5275,7 @@ ahc_qinfifo_requeue(struct ahc_softc *ahc, struct scb *prev_scb,
BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
}
ahc->qinfifo[ahc->qinfifonext] = scb->hscb->tag;
- ahc_dmamap_sync(ahc, ahc->shared_data_dmat, ahc->shared_data_dmamap,
+ ahc_dmamap_sync(ahc, ahc->parent_dmat, ahc->shared_data_dmamap,
/*offset*/ahc->qinfifonext+256, /*len*/1,
BUS_DMASYNC_PREWRITE);
ahc->qinfifonext++;
@@ -5074,8 +5286,8 @@ ahc_qinfifo_requeue(struct ahc_softc *ahc, struct scb *prev_scb,
static int
ahc_qinfifo_count(struct ahc_softc *ahc)
{
- u_int8_t qinpos;
- u_int8_t diff;
+ uint8_t qinpos;
+ uint8_t diff;
if ((ahc->features & AHC_QUEUE_REGS) != 0) {
qinpos = ahc_inb(ahc, SNSCB_QOFF);
@@ -5096,15 +5308,12 @@ ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel,
uint8_t qinstart;
uint8_t qinpos;
uint8_t qintail;
- uint8_t next, prev;
+ uint8_t next;
+ uint8_t prev;
uint8_t curscbptr;
int found;
- int maxtarget;
- int i;
int have_qregs;
- ahc_sync_qinfifo(ahc, BUS_DMASYNC_POSTWRITE);
-
qintail = ahc->qinfifonext;
have_qregs = (ahc->features & AHC_QUEUE_REGS) != 0;
if (have_qregs) {
@@ -5113,10 +5322,9 @@ ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel,
} else
qinstart = ahc_inb(ahc, QINPOS);
qinpos = qinstart;
- next = ahc_inb(ahc, NEXT_QUEUED_SCB);
found = 0;
prev_scb = NULL;
-
+
if (action == SEARCH_COMPLETE) {
/*
* Don't attempt to run any queued untagged transactions
@@ -5153,14 +5361,14 @@ ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel,
ostat = ahc_get_transaction_status(scb);
if (ostat == CAM_REQ_INPROG)
- ahc_set_transaction_status(scb,
- status);
+ ahc_set_transaction_status(scb, status);
cstat = ahc_get_transaction_status(scb);
if (cstat != CAM_REQ_CMP)
ahc_freeze_scb(scb);
if ((scb->flags & SCB_ACTIVE) == 0)
printf("Inactive SCB in qinfifo\n");
ahc_done(ahc, scb);
+
/* FALLTHROUGH */
}
case SEARCH_REMOVE:
@@ -5187,15 +5395,15 @@ ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel,
&& (found != 0)
&& (qinstart != ahc->qinfifonext)) {
/*
- * The sequencer may be in the process of dmaing
+ * The sequencer may be in the process of DMA'ing
* down the SCB at the beginning of the queue.
* This could be problematic if either the first,
* or the second SCB is removed from the queue
* (the first SCB includes a pointer to the "next"
- * SCB to dma). If we have removed any entries, swap
+ * SCB to DMA). If we have removed any entries, swap
* the first element in the queue with the next HSCB
* so the sequencer will notice that NEXT_QUEUED_SCB
- * has changed during its dma attempt and will retry
+ * has changed during its DMA attempt and will retry
* the DMA.
*/
scb = ahc_lookup_scb(ahc, ahc->qinfifo[qinstart]);
@@ -5265,8 +5473,7 @@ ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel,
ostat = ahc_get_transaction_status(scb);
if (ostat == CAM_REQ_INPROG)
- ahc_set_transaction_status(scb,
- status);
+ ahc_set_transaction_status(scb, status);
cstat = ahc_get_transaction_status(scb);
if (cstat != CAM_REQ_CMP)
ahc_freeze_scb(scb);
@@ -5291,9 +5498,33 @@ ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel,
}
ahc_outb(ahc, SCBPTR, curscbptr);
- /*
- * And lastly, the untagged holding queues.
- */
+ found += ahc_search_untagged_queues(ahc, /*ahc_io_ctx_t*/NULL, target,
+ channel, lun, status, action);
+
+ if (action == SEARCH_COMPLETE)
+ ahc_release_untagged_queues(ahc);
+ return (found);
+}
+
+int
+ahc_search_untagged_queues(struct ahc_softc *ahc, struct scsi_xfer *xs,
+ int target, char channel, int lun, uint32_t status,
+ ahc_search_action action)
+{
+ struct scb *scb;
+ int maxtarget;
+ int found;
+ int i;
+
+ if (action == SEARCH_COMPLETE) {
+ /*
+ * Don't attempt to run any queued untagged transactions
+ * until we are done with the abort process.
+ */
+ ahc_freeze_untagged_queues(ahc);
+ }
+
+ found = 0;
i = 0;
if ((ahc->flags & AHC_SCB_BTT) == 0) {
@@ -5332,37 +5563,38 @@ ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel,
if ((scb->flags & SCB_ACTIVE) != 0)
continue;
- if (ahc_match_scb(ahc, scb, target, channel,
- lun, SCB_LIST_NULL, role)) {
- /*
- * We found an scb that needs to be acted on.
- */
- found++;
- switch (action) {
- case SEARCH_COMPLETE:
- {
- cam_status ostat;
- cam_status cstat;
-
- ostat = ahc_get_transaction_status(scb);
- if (ostat == CAM_REQ_INPROG)
- ahc_set_transaction_status(scb,
- status);
- cstat = ahc_get_transaction_status(scb);
- if (cstat != CAM_REQ_CMP)
- ahc_freeze_scb(scb);
- if ((scb->flags & SCB_ACTIVE) == 0)
- printf("Inactive SCB in untaggedQ\n");
- ahc_done(ahc, scb);
- break;
- }
- case SEARCH_REMOVE:
- TAILQ_REMOVE(untagged_q, scb,
- links.tqe);
- break;
- case SEARCH_COUNT:
- break;
- }
+ if (ahc_match_scb(ahc, scb, target, channel, lun,
+ SCB_LIST_NULL, ROLE_INITIATOR) == 0
+ /*|| (ctx != NULL && ctx != scb->io_ctx)*/)
+ continue;
+
+ /*
+ * We found an scb that needs to be acted on.
+ */
+ found++;
+ switch (action) {
+ case SEARCH_COMPLETE:
+ {
+ cam_status ostat;
+ cam_status cstat;
+
+ ostat = ahc_get_transaction_status(scb);
+ if (ostat == CAM_REQ_INPROG)
+ ahc_set_transaction_status(scb, status);
+ cstat = ahc_get_transaction_status(scb);
+ if (cstat != CAM_REQ_CMP)
+ ahc_freeze_scb(scb);
+ if ((scb->flags & SCB_ACTIVE) == 0)
+ printf("Inactive SCB in untaggedQ\n");
+ ahc_done(ahc, scb);
+ break;
+ }
+ case SEARCH_REMOVE:
+ scb->flags &= ~SCB_UNTAGGEDQ;
+ TAILQ_REMOVE(untagged_q, scb, links.tqe);
+ break;
+ case SEARCH_COUNT:
+ break;
}
}
}
@@ -5590,24 +5822,40 @@ ahc_abort_scbs(struct ahc_softc *ahc, int target, char channel,
maxlun = lun + 1;
}
- for (;i < maxtarget; i++) {
- for (j = minlun;j < maxlun; j++)
- ahc_unbusy_tcl(ahc, BUILD_TCL(i << 4, j));
- }
+ if (role != ROLE_TARGET) {
+ for (;i < maxtarget; i++) {
+ for (j = minlun;j < maxlun; j++) {
+ u_int scbid;
+ u_int tcl;
- /*
- * Go through the disconnected list and remove any entries we
- * have queued for completion, 0'ing their control byte too.
- * We save the active SCB and restore it ourselves, so there
- * is no reason for this search to restore it too.
- */
- ahc_search_disc_list(ahc, target, channel, lun, tag,
- /*stop_on_first*/FALSE, /*remove*/TRUE,
- /*save_state*/FALSE);
+ tcl = BUILD_TCL(i << 4, j);
+ scbid = ahc_index_busy_tcl(ahc, tcl);
+ scbp = ahc_lookup_scb(ahc, scbid);
+ if (scbp == NULL
+ || ahc_match_scb(ahc, scbp, target, channel,
+ lun, tag, role) == 0)
+ continue;
+ ahc_unbusy_tcl(ahc, BUILD_TCL(i << 4, j));
+ }
+ }
+
+ /*
+ * Go through the disconnected list and remove any entries we
+ * have queued for completion, 0'ing their control byte too.
+ * We save the active SCB and restore it ourselves, so there
+ * is no reason for this search to restore it too.
+ */
+ ahc_search_disc_list(ahc, target, channel, lun, tag,
+ /*stop_on_first*/FALSE, /*remove*/TRUE,
+ /*save_state*/FALSE);
+ }
/*
* Go through the hardware SCB array looking for commands that
- * were active but not on any list.
+ * were active but not on any list. In some cases, these remnants
+ * might not still have mappings in the scbindex array (e.g. unexpected
+ * bus free with the same scb queued for an abort). Don't hold this
+ * against them.
*/
for (i = 0; i < ahc->scb_data->maxhscbs; i++) {
u_int scbid;
@@ -5615,8 +5863,9 @@ ahc_abort_scbs(struct ahc_softc *ahc, int target, char channel,
ahc_outb(ahc, SCBPTR, i);
scbid = ahc_inb(ahc, SCB_TAG);
scbp = ahc_lookup_scb(ahc, scbid);
- if (scbp != NULL
- && ahc_match_scb(ahc, scbp, target, channel, lun, tag, role))
+ if ((scbp == NULL && scbid != SCB_LIST_NULL)
+ || (scbp != NULL
+ && ahc_match_scb(ahc, scbp, target, channel, lun, tag, role)))
ahc_add_curscb_to_free_list(ahc);
}
@@ -5700,6 +5949,16 @@ ahc_reset_channel(struct ahc_softc *ahc, char channel, int initiate_reset)
*/
ahc_run_qoutfifo(ahc);
#if AHC_TARGET_MODE
+ /*
+ * XXX - In Twin mode, the tqinfifo may have commands
+ * for an unaffected channel in it. However, if
+ * we have run out of ATIO resources to drain that
+ * queue, we may not get them all out here. Further,
+ * the blocked transactions for the reset channel
+ * should just be killed off, irrespecitve of whether
+ * we are blocked on ATIO resources. Write a routine
+ * to compact the tqinfifo appropriately.
+ */
if ((ahc->flags & AHC_TARGETROLE) != 0) {
ahc_run_tqinfifo(ahc, /*paused*/TRUE);
}
@@ -5721,10 +5980,6 @@ ahc_reset_channel(struct ahc_softc *ahc, char channel, int initiate_reset)
*/
ahc_outb(ahc, SBLKCTL, sblkctl ^ SELBUSB);
simode1 = ahc_inb(ahc, SIMODE1) & ~(ENBUSFREE|ENSCSIRST);
- ahc_outb(ahc, SIMODE1, simode1);
- if (initiate_reset)
- ahc_reset_current_bus(ahc);
- ahc_clear_intstat(ahc);
#if AHC_TARGET_MODE
/*
* Bus resets clear ENSELI, so we cannot
@@ -5732,19 +5987,18 @@ ahc_reset_channel(struct ahc_softc *ahc, char channel, int initiate_reset)
* if we are in target mode.
*/
if ((ahc->flags & AHC_TARGETROLE) != 0)
- ahc_outb(ahc, SIMODE1, simode1 | ENSCSIRST);
+ simode1 |= ENSCSIRST;
#endif
+ ahc_outb(ahc, SIMODE1, simode1);
+ if (initiate_reset)
+ ahc_reset_current_bus(ahc);
+ ahc_clear_intstat(ahc);
ahc_outb(ahc, SCSISEQ, scsiseq & (ENSELI|ENRSELI|ENAUTOATNP));
ahc_outb(ahc, SBLKCTL, sblkctl);
restart_needed = FALSE;
} else {
/* Case 2: A command from this bus is active or we're idle */
- ahc_clear_msg_state(ahc);
simode1 = ahc_inb(ahc, SIMODE1) & ~(ENBUSFREE|ENSCSIRST);
- ahc_outb(ahc, SIMODE1, simode1);
- if (initiate_reset)
- ahc_reset_current_bus(ahc);
- ahc_clear_intstat(ahc);
#if AHC_TARGET_MODE
/*
* Bus resets clear ENSELI, so we cannot
@@ -5752,8 +6006,12 @@ ahc_reset_channel(struct ahc_softc *ahc, char channel, int initiate_reset)
* if we are in target mode.
*/
if ((ahc->flags & AHC_TARGETROLE) != 0)
- ahc_outb(ahc, SIMODE1, simode1 | ENSCSIRST);
+ simode1 |= ENSCSIRST;
#endif
+ ahc_outb(ahc, SIMODE1, simode1);
+ if (initiate_reset)
+ ahc_reset_current_bus(ahc);
+ ahc_clear_intstat(ahc);
ahc_outb(ahc, SCSISEQ, scsiseq & (ENSELI|ENRSELI|ENAUTOATNP));
restart_needed = TRUE;
}
@@ -5767,7 +6025,7 @@ ahc_reset_channel(struct ahc_softc *ahc, char channel, int initiate_reset)
ROLE_UNKNOWN, CAM_SCSI_BUS_RESET);
max_scsiid = (ahc->features & AHC_WIDE) ? 15 : 7;
-
+
#ifdef AHC_TARGET_MODE
/*
* Send an immediate notify ccb to all target more peripheral
@@ -5793,10 +6051,6 @@ ahc_reset_channel(struct ahc_softc *ahc, char channel, int initiate_reset)
}
}
#endif
- /* Notify the XPT that a bus reset occurred */
- ahc_send_async(ahc, devinfo.channel, CAM_TARGET_WILDCARD,
- CAM_LUN_WILDCARD, AC_BUS_RESET, NULL);
-
/*
* Revert to async/narrow transfers until we renegotiate.
*/
@@ -5832,7 +6086,7 @@ ahc_reset_channel(struct ahc_softc *ahc, char channel, int initiate_reset)
* Calculate the residual for a just completed SCB.
*/
void
-ahc_calc_residual(struct scb *scb)
+ahc_calc_residual(struct ahc_softc *ahc, struct scb *scb)
{
struct hardware_scb *hscb;
struct status_pkt *spkt;
@@ -5876,13 +6130,13 @@ ahc_calc_residual(struct scb *scb)
/* Case 4 */
return;
} else if ((resid_sgptr & ~SG_PTR_MASK) != 0) {
- panic("Bogus resid sgptr value 0x%x", resid_sgptr);
+ panic("Bogus resid sgptr value 0x%x\n", resid_sgptr);
} else {
struct ahc_dma_seg *sg;
/*
* Remainder of the SG where the transfer
- * stopped.
+ * stopped.
*/
resid = ahc_le32toh(spkt->residual_datacnt) & AHC_SG_LEN_MASK;
sg = ahc_sg_bus_to_virt(scb, resid_sgptr & SG_PTR_MASK);
@@ -5906,9 +6160,10 @@ ahc_calc_residual(struct scb *scb)
ahc_set_sense_residual(scb, resid);
#ifdef AHC_DEBUG
- if (ahc_debug & AHC_SHOWMISC) {
- ahc_print_path(scb->ahc_softc, scb);
- printf("Handled Residual of %d bytes\n", resid);
+ if ((ahc_debug & AHC_SHOW_MISC) != 0) {
+ ahc_print_path(ahc, scb);
+ printf("Handled %sResidual of %d bytes\n",
+ (scb->flags & SCB_SENSE) ? "Sense " : "", resid);
}
#endif
}
@@ -6123,8 +6378,11 @@ ahc_loadseq(struct ahc_softc *ahc)
ahc_outb(ahc, SEQCTL, PERRORDIS|FAILDIS|FASTMODE);
ahc_restart(ahc);
- if (bootverbose)
+ if (bootverbose) {
printf(" %d instructions downloaded\n", downloaded);
+ printf("%s: Features 0x%x, Bugs 0x%x, Flags 0x%x\n",
+ ahc_name(ahc), ahc->features, ahc->bugs, ahc->flags);
+ }
}
static int
@@ -6202,9 +6460,7 @@ ahc_download_instr(struct ahc_softc *ahc, u_int instrptr, uint8_t *dconsts)
address = fmt3_ins->address;
cur_patch = patches;
skip_addr = 0;
-
for (i = 0; i < address;) {
-
ahc_check_patch(ahc, &cur_patch, i, &skip_addr);
if (skip_addr > i) {
@@ -6288,14 +6544,74 @@ ahc_download_instr(struct ahc_softc *ahc, u_int instrptr, uint8_t *dconsts)
}
}
+int
+ahc_print_register(ahc_reg_parse_entry_t *table, u_int num_entries,
+ const char *name, u_int address, u_int value,
+ u_int *cur_column, u_int wrap_point)
+{
+ int printed;
+ u_int printed_mask;
+ char line[1024];
+
+ line[0] = 0;
+
+ if (cur_column != NULL && *cur_column >= wrap_point) {
+ printf("\n");
+ *cur_column = 0;
+ }
+ printed = snprintf(line, sizeof(line), "%s[0x%x]", name, value);
+ if (table == NULL) {
+ printed += snprintf(&line[printed], (sizeof line) - printed,
+ " ");
+ printf("%s", line);
+ if (cur_column != NULL)
+ *cur_column += printed;
+ return (printed);
+ }
+ printed_mask = 0;
+ while (printed_mask != 0xFF) {
+ int entry;
+
+ for (entry = 0; entry < num_entries; entry++) {
+ if (((value & table[entry].mask)
+ != table[entry].value)
+ || ((printed_mask & table[entry].mask)
+ == table[entry].mask))
+ continue;
+ printed += snprintf(&line[printed],
+ (sizeof line) - printed, "%s%s",
+ printed_mask == 0 ? ":(" : "|",
+ table[entry].name);
+ printed_mask |= table[entry].mask;
+
+ break;
+ }
+ if (entry >= num_entries)
+ break;
+ }
+ if (printed_mask != 0)
+ printed += snprintf(&line[printed],
+ (sizeof line) - printed, ") ");
+ else
+ printed += snprintf(&line[printed],
+ (sizeof line) - printed, " ");
+ if (cur_column != NULL)
+ *cur_column += printed;
+ printf("%s", line);
+
+ return (printed);
+}
+
void
ahc_dump_card_state(struct ahc_softc *ahc)
{
- struct scb *scb;
- struct scb_tailq *untagged_q;
- int target;
- int maxtarget;
- int i;
+ struct scb *scb;
+ struct scb_tailq *untagged_q;
+ u_int cur_col;
+ int paused;
+ int target;
+ int maxtarget;
+ int i;
uint8_t last_phase;
uint8_t qinpos;
uint8_t qintail;
@@ -6303,32 +6619,53 @@ ahc_dump_card_state(struct ahc_softc *ahc)
uint8_t scb_index;
uint8_t saved_scbptr;
- saved_scbptr = ahc_inb(ahc, SCBPTR);
+ if (ahc_is_paused(ahc)) {
+ paused = 1;
+ } else {
+ paused = 0;
+ ahc_pause(ahc);
+ }
+ saved_scbptr = ahc_inb(ahc, SCBPTR);
last_phase = ahc_inb(ahc, LASTPHASE);
- printf("%s: Dumping Card State %s, at SEQADDR 0x%x\n",
+ printf(">>>>>>>>>>>>>>>>>> Dump Card State Begins <<<<<<<<<<<<<<<<<\n"
+ "%s: Dumping Card State %s, at SEQADDR 0x%x\n",
ahc_name(ahc), ahc_lookup_phase_entry(last_phase)->phasemsg,
ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8));
+ if (paused)
+ printf("Card was paused\n");
printf("ACCUM = 0x%x, SINDEX = 0x%x, DINDEX = 0x%x, ARG_2 = 0x%x\n",
ahc_inb(ahc, ACCUM), ahc_inb(ahc, SINDEX), ahc_inb(ahc, DINDEX),
ahc_inb(ahc, ARG_2));
- printf("HCNT = 0x%x\n", ahc_inb(ahc, HCNT));
- printf("SCSISEQ = 0x%x, SBLKCTL = 0x%x\n",
- ahc_inb(ahc, SCSISEQ), ahc_inb(ahc, SBLKCTL));
- printf(" DFCNTRL = 0x%x, DFSTATUS = 0x%x\n",
- ahc_inb(ahc, DFCNTRL), ahc_inb(ahc, DFSTATUS));
- printf("LASTPHASE = 0x%x, SCSISIGI = 0x%x, SXFRCTL0 = 0x%x\n",
- last_phase, ahc_inb(ahc, SCSISIGI), ahc_inb(ahc, SXFRCTL0));
- printf("SSTAT0 = 0x%x, SSTAT1 = 0x%x\n",
- ahc_inb(ahc, SSTAT0), ahc_inb(ahc, SSTAT1));
+ printf("HCNT = 0x%x SCBPTR = 0x%x\n", ahc_inb(ahc, HCNT),
+ ahc_inb(ahc, SCBPTR));
+ cur_col = 0;
if ((ahc->features & AHC_DT) != 0)
- printf("SCSIPHASE = 0x%x\n", ahc_inb(ahc, SCSIPHASE));
- printf("STACK == 0x%x, 0x%x, 0x%x, 0x%x\n",
- ahc_inb(ahc, STACK) | (ahc_inb(ahc, STACK) << 8),
- ahc_inb(ahc, STACK) | (ahc_inb(ahc, STACK) << 8),
- ahc_inb(ahc, STACK) | (ahc_inb(ahc, STACK) << 8),
- ahc_inb(ahc, STACK) | (ahc_inb(ahc, STACK) << 8));
- printf("SCB count = %d\n", ahc->scb_data->numscbs);
+ ahc_scsiphase_print(ahc_inb(ahc, SCSIPHASE), &cur_col, 50);
+ ahc_scsisigi_print(ahc_inb(ahc, SCSISIGI), &cur_col, 50);
+ ahc_error_print(ahc_inb(ahc, ERROR), &cur_col, 50);
+ ahc_scsibusl_print(ahc_inb(ahc, SCSIBUSL), &cur_col, 50);
+ ahc_lastphase_print(ahc_inb(ahc, LASTPHASE), &cur_col, 50);
+ ahc_scsiseq_print(ahc_inb(ahc, SCSISEQ), &cur_col, 50);
+ ahc_sblkctl_print(ahc_inb(ahc, SBLKCTL), &cur_col, 50);
+ ahc_scsirate_print(ahc_inb(ahc, SCSIRATE), &cur_col, 50);
+ ahc_seqctl_print(ahc_inb(ahc, SEQCTL), &cur_col, 50);
+ ahc_seq_flags_print(ahc_inb(ahc, SEQ_FLAGS), &cur_col, 50);
+ ahc_sstat0_print(ahc_inb(ahc, SSTAT0), &cur_col, 50);
+ ahc_sstat1_print(ahc_inb(ahc, SSTAT1), &cur_col, 50);
+ ahc_sstat2_print(ahc_inb(ahc, SSTAT2), &cur_col, 50);
+ ahc_sstat3_print(ahc_inb(ahc, SSTAT3), &cur_col, 50);
+ ahc_simode0_print(ahc_inb(ahc, SIMODE0), &cur_col, 50);
+ ahc_simode1_print(ahc_inb(ahc, SIMODE1), &cur_col, 50);
+ ahc_sxfrctl0_print(ahc_inb(ahc, SXFRCTL0), &cur_col, 50);
+ ahc_dfcntrl_print(ahc_inb(ahc, DFCNTRL), &cur_col, 50);
+ ahc_dfstatus_print(ahc_inb(ahc, DFSTATUS), &cur_col, 50);
+ if (cur_col != 0)
+ printf("\n");
+ printf("STACK:");
+ for (i = 0; i < STACK_SIZE; i++)
+ printf(" 0x%x", ahc_inb(ahc, STACK)|(ahc_inb(ahc, STACK) << 8));
+ printf("\nSCB count = %d\n", ahc->scb_data->numscbs);
printf("Kernel NEXTQSCB = %d\n", ahc->next_queued_scb->hscb->tag);
printf("Card NEXTQSCB = %d\n", ahc_inb(ahc, NEXT_QUEUED_SCB));
/* QINFIFO */
@@ -6385,18 +6722,34 @@ ahc_dump_card_state(struct ahc_softc *ahc)
}
printf("\n");
+ printf("Sequencer SCB Info: ");
+ for (i = 0; i < ahc->scb_data->maxhscbs; i++) {
+ ahc_outb(ahc, SCBPTR, i);
+ /*cur_col =*/ printf("\n%3d ", i);
+
+ ahc_scb_control_print(ahc_inb(ahc, SCB_CONTROL), &cur_col, 60);
+ ahc_scb_scsiid_print(ahc_inb(ahc, SCB_SCSIID), &cur_col, 60);
+ ahc_scb_lun_print(ahc_inb(ahc, SCB_LUN), &cur_col, 60);
+ ahc_scb_tag_print(ahc_inb(ahc, SCB_TAG), &cur_col, 60);
+ }
+ printf("\n");
+
printf("Pending list: ");
i = 0;
LIST_FOREACH(scb, &ahc->pending_scbs, pending_links) {
if (i++ > 256)
break;
- if (scb != LIST_FIRST(&ahc->pending_scbs))
- printf(", ");
- printf("%d", scb->hscb->tag);
+ /*cur_col =*/ printf("\n%3d ", scb->hscb->tag);
+ ahc_scb_control_print(scb->hscb->control, &cur_col, 60);
+ ahc_scb_scsiid_print(scb->hscb->scsiid, &cur_col, 60);
+ ahc_scb_lun_print(scb->hscb->lun, &cur_col, 60);
if ((ahc->flags & AHC_PAGESCBS) == 0) {
ahc_outb(ahc, SCBPTR, scb->hscb->tag);
- printf("(0x%x, 0x%x)", ahc_inb(ahc, SCB_CONTROL),
- ahc_inb(ahc, SCB_TAG));
+ printf("(");
+ ahc_scb_control_print(ahc_inb(ahc, SCB_CONTROL),
+ &cur_col, 60);
+ ahc_scb_tag_print(ahc_inb(ahc, SCB_TAG), &cur_col, 60);
+ printf(")");
}
}
printf("\n");
@@ -6426,7 +6779,10 @@ ahc_dump_card_state(struct ahc_softc *ahc)
}
ahc_platform_dump_card_state(ahc);
+ printf("\n<<<<<<<<<<<<<<<<< Dump Card State Ends >>>>>>>>>>>>>>>>>>\n");
ahc_outb(ahc, SCBPTR, saved_scbptr);
+ if (paused == 0)
+ ahc_unpause(ahc);
}
/************************* Target Mode ****************************************/
@@ -6482,6 +6838,7 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb)
u_int target;
u_int lun;
u_int target_mask;
+ u_int our_id;
u_long s;
char channel;
@@ -6493,15 +6850,33 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb)
return;
}
- if ((ahc->features & AHC_MULTIROLE) != 0) {
- u_int our_id;
+ if (cam_sim_bus(sim) == 0)
+ our_id = ahc->our_id;
+ else
+ our_id = ahc->our_id_b;
- if (cam_sim_bus(sim) == 0)
- our_id = ahc->our_id;
- else
- our_id = ahc->our_id_b;
+ if (ccb->ccb_h.target_id != our_id) {
+ /*
+ * our_id represents our initiator ID, or
+ * the ID of the first target to have an
+ * enabled lun in target mode. There are
+ * two cases that may preclude enabling a
+ * target id other than our_id.
+ *
+ * o our_id is for an active initiator role.
+ * Since the hardware does not support
+ * reselections to the initiator role at
+ * anything other than our_id, and our_id
+ * is used by the hardware to indicate the
+ * ID to use for both select-out and
+ * reselect-out operations, the only target
+ * ID we can support in this mode is our_id.
+ *
+ * o The MULTARGID feature is not available and
+ * a previous target mode ID has been enabled.
+ */
+ if ((ahc->features & AHC_MULTIROLE) != 0) {
- if (ccb->ccb_h.target_id != our_id) {
if ((ahc->features & AHC_MULTI_TID) != 0
&& (ahc->flags & AHC_INITIATORROLE) != 0) {
/*
@@ -6523,12 +6898,16 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb)
*/
status = CAM_TID_INVALID;
}
+ } else if ((ahc->features & AHC_MULTI_TID) == 0
+ && ahc->enabled_luns > 0) {
+
+ status = CAM_TID_INVALID;
}
}
if (status != CAM_REQ_CMP) {
ccb->ccb_h.status = status;
- return;
+ return;
}
/*
@@ -6583,7 +6962,7 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb)
return;
}
- /*
+ /*
* Seems to be okay.
* Setup our data structures.
*/
@@ -6804,7 +7183,7 @@ ahc_update_scsiid(struct ahc_softc *ahc, u_int targid_mask)
panic("ahc_update_scsiid called on non-multitid unit");
/*
- * Since we will rely on the the TARGID mask
+ * Since we will rely on the TARGID mask
* for selection enables, ensure that OID
* in SCSIID is not set to some other ID
* that we don't want to allow selections on.
@@ -6856,7 +7235,7 @@ ahc_run_tqinfifo(struct ahc_softc *ahc, int paused)
break;
cmd->cmd_valid = 0;
- ahc_dmamap_sync(ahc, ahc->shared_data_dmat,
+ ahc_dmamap_sync(ahc, ahc->parent_dmat/*shared_data_dmat*/,
ahc->shared_data_dmamap,
ahc_targetcmd_offset(ahc, ahc->tqinfifonext),
sizeof(struct target_cmd),
@@ -6920,6 +7299,8 @@ ahc_handle_target_cmd(struct ahc_softc *ahc, struct target_cmd *cmd)
/*
* Wait for more ATIOs from the peripheral driver for this lun.
*/
+ if (bootverbose)
+ printf("%s: ATIOs exhausted\n", ahc_name(ahc));
return (1);
} else
ahc->flags &= ~AHC_TQINFIFO_BLOCKED;
@@ -6997,5 +7378,76 @@ ahc_handle_target_cmd(struct ahc_softc *ahc, struct target_cmd *cmd)
xpt_done((union ccb*)atio);
return (0);
}
-
#endif
+
+static int
+ahc_createdmamem(bus_dma_tag_t tag, int size, int flags, bus_dmamap_t *mapp,
+ caddr_t *vaddr, bus_addr_t *baddr, bus_dma_segment_t *seg, int *nseg,
+ const char *myname, const char *what)
+{
+ int error, level = 0;
+
+ if ((error = bus_dmamem_alloc(tag, size, PAGE_SIZE, 0,
+ seg, 1, nseg, BUS_DMA_NOWAIT)) != 0) {
+ printf("%s: failed to allocate DMA mem for %s, error = %d\n",
+ myname, what, error);
+ goto out;
+ }
+ level++;
+
+ if ((error = bus_dmamem_map(tag, seg, *nseg, size, vaddr,
+ BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) != 0) {
+ printf("%s: failed to map DMA mem for %s, error = %d\n",
+ myname, what, error);
+ goto out;
+ }
+ level++;
+
+ if ((error = bus_dmamap_create(tag, size, 1, size, 0,
+ BUS_DMA_NOWAIT | flags, mapp)) != 0) {
+ printf("%s: failed to create DMA map for %s, error = %d\n",
+ myname, what, error);
+ goto out;
+ }
+ level++;
+
+
+ if ((error = bus_dmamap_load(tag, *mapp, *vaddr, size, NULL,
+ BUS_DMA_NOWAIT)) != 0) {
+ printf("%s: failed to load DMA map for %s, error = %d\n",
+ myname, what, error);
+ goto out;
+ }
+
+ *baddr = (*mapp)->dm_segs[0].ds_addr;
+
+ return 0;
+out:
+ printf("ahc_createdmamem error (%d)\n", level);
+ switch (level) {
+ case 3:
+ bus_dmamap_destroy(tag, *mapp);
+ /* FALLTHROUGH */
+ case 2:
+ bus_dmamem_unmap(tag, *vaddr, size);
+ /* FALLTHROUGH */
+ case 1:
+ bus_dmamem_free(tag, seg, *nseg);
+ break;
+ default:
+ break;
+ }
+
+ return error;
+}
+
+static void
+ahc_freedmamem(bus_dma_tag_t tag, int size, bus_dmamap_t map, caddr_t vaddr,
+ bus_dma_segment_t *seg, int nseg)
+{
+
+ bus_dmamap_unload(tag, map);
+ bus_dmamap_destroy(tag, map);
+ bus_dmamem_unmap(tag, vaddr, size);
+ bus_dmamem_free(tag, seg, nseg);
+}
diff --git a/sys/dev/ic/aic7xxx.h b/sys/dev/ic/aic7xxx.h
index 7a0a4c423fb..5527c1f4d3a 100644
--- a/sys/dev/ic/aic7xxx.h
+++ b/sys/dev/ic/aic7xxx.h
@@ -1,5 +1,5 @@
/*
- * $OpenBSD: aic7xxx.h,v 1.8 2003/10/21 18:58:48 jmc Exp $
+ * $OpenBSD: aic7xxx.h,v 1.9 2003/12/24 22:45:45 krw Exp $
* Core definitions and data structures shareable across OS platforms.
*
* Copyright (c) 1994-2001 Justin T. Gibbs.
@@ -29,7 +29,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: aic7xxx.h,v 1.8 2003/10/21 18:58:48 jmc Exp $
+ * $Id: aic7xxx.h,v 1.9 2003/12/24 22:45:45 krw Exp $
*
* $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.h,v 1.40 2001/07/18 21:39:47 gibbs Exp $
*/
@@ -38,11 +38,14 @@
#define _AIC7XXX_H_
/* Register Definitions */
-#include "aic7xxxreg.h"
+#include "dev/microcode/aic7xxx/aic7xxx_reg.h"
+
+#include "dev/ic/aic7xxx_cam.h"
/************************* Forward Declarations *******************************/
struct ahc_platform_data;
struct scb_platform_data;
+struct seeprom_descriptor;
/****************************** Useful Macros *********************************/
#ifndef MAX
@@ -89,6 +92,14 @@ struct scb_platform_data;
(SCB_GET_TARGET(ahc, scb) + (SCB_IS_SCSIBUS_B(ahc, scb) ? 8 : 0))
#define SCB_GET_TARGET_MASK(ahc, scb) \
(0x01 << (SCB_GET_TARGET_OFFSET(ahc, scb)))
+#ifdef AHC_DEBUG
+#define SCB_IS_SILENT(scb) \
+ ((ahc_debug & AHC_SHOW_MASKED_ERRORS) == 0 \
+ && (((scb)->flags & SCB_SILENT) != 0))
+#else
+#define SCB_IS_SILENT(scb) \
+ (((scb)->flags & SCB_SILENT) != 0)
+#endif
#define TCL_TARGET_OFFSET(tcl) \
((((tcl) >> 4) & TID) >> 4)
#define TCL_LUN(tcl) \
@@ -337,7 +348,11 @@ typedef enum {
AHC_ALL_INTERRUPTS = 0x100000,
AHC_PAGESCBS = 0x400000, /* Enable SCB paging */
AHC_EDGE_INTERRUPT = 0x800000, /* Device uses edge triggered ints */
- AHC_39BIT_ADDRESSING = 0x1000000 /* Use 39 bit addressing scheme. */
+ AHC_39BIT_ADDRESSING = 0x1000000, /* Use 39 bit addressing scheme. */
+ AHC_LSCBS_ENABLED = 0x2000000, /* 64Byte SCBs enabled */
+ AHC_SCB_CONFIG_USED = 0x4000000, /* No SEEPROM but SCB2 had info. */
+ AHC_NO_BIOS_INIT = 0x8000000, /* No BIOS left over settings. */
+ AHC_DISABLE_PCI_PERR = 0x10000000
} ahc_flag;
/************************* Hardware SCB Definition ***************************/
@@ -499,6 +514,14 @@ struct sg_map_node {
#endif
};
+struct ahc_pci_busdata {
+ pci_chipset_tag_t pc;
+ pcitag_t tag;
+ u_int dev;
+ u_int func;
+ pcireg_t class;
+};
+
/*
* The current state of this SCB.
*/
@@ -521,7 +544,24 @@ typedef enum {
SCB_ABORT = 0x1000,
SCB_UNTAGGEDQ = 0x2000,
SCB_ACTIVE = 0x4000,
- SCB_TARGET_IMMEDIATE = 0x8000
+ SCB_TARGET_IMMEDIATE = 0x8000,
+ SCB_TRANSMISSION_ERROR = 0x1000,/*
+ * We detected a parity or CRC
+ * error that has effected the
+ * payload of the command. This
+ * flag is checked when normal
+ * status is returned to catch
+ * the case of a target not
+ * responding to our attempt
+ * to report the error.
+ */
+ SCB_TARGET_SCB = 0x2000,
+ SCB_SILENT = 0x4000 /*
+ * Be quiet about transmission type
+ * errors. They are expected and we
+ * don't want to upset the user. This
+ * flag is typically used during DV.
+ */
} scb_flag;
struct scb {
@@ -557,7 +597,6 @@ struct scb_data {
/*
* "Bus" addresses of our data structures.
*/
- bus_dma_tag_t hscb_dmat; /* dmat for our hardware SCB array */
bus_dmamap_t hscb_dmamap;
bus_addr_t hscb_busaddr;
#ifdef __OpenBSD__
@@ -573,7 +612,6 @@ struct scb_data {
int sense_nseg;
int sense_size;
#endif
- bus_dma_tag_t sg_dmat; /* dmat for our sg segments */
SLIST_HEAD(, sg_map_node) sg_maps;
uint8_t numscbs;
uint8_t maxhscbs; /* Number of SCBs on the card */
@@ -707,6 +745,10 @@ struct ahc_syncrate {
*/
extern struct ahc_syncrate ahc_syncrates[];
+/* Safe and valid period for async negotiations. */
+#define AHC_ASYNC_XFER_PERIOD 0x45
+#define AHC_ULTRA2_XFER_PERIOD 0x0a
+
/*
* Indexes into our table of synchronous transfer rates.
*/
@@ -934,6 +976,8 @@ struct ahc_softc {
ahc_bug bugs;
ahc_flag flags;
+ struct seeprom_config *seep_config;
+
/* Values to store in the SEQCTL register for pause and unpause */
uint8_t unpause;
uint8_t pause;
@@ -986,7 +1030,6 @@ struct ahc_softc {
* between the sequencer and kernel.
*/
bus_dma_tag_t parent_dmat;
- bus_dma_tag_t shared_data_dmat;
bus_dmamap_t shared_data_dmamap;
bus_addr_t shared_data_busaddr;
@@ -1020,6 +1063,8 @@ struct ahc_softc {
uint16_t user_discenable;/* Disconnection allowed */
uint16_t user_tagenable;/* Tagged Queuing allowed */
+
+ struct ahc_pci_busdata *bd;
};
TAILQ_HEAD(ahc_softc_tailq, ahc_softc);
@@ -1078,7 +1123,7 @@ void ahc_busy_tcl(struct ahc_softc *ahc,
u_int tcl, u_int busyid);
/***************************** PCI Front End *********************************/
-struct ahc_pci_identity *ahc_find_pci_device(ahc_dev_softc_t);
+const struct ahc_pci_identity *ahc_find_pci_device(pcireg_t, pcireg_t, u_int);
int ahc_pci_config(struct ahc_softc *,
struct ahc_pci_identity *);
@@ -1109,6 +1154,7 @@ void ahc_pause_and_flushwork(struct ahc_softc *ahc);
int ahc_suspend(struct ahc_softc *ahc);
int ahc_resume(struct ahc_softc *ahc);
void ahc_softc_insert(struct ahc_softc *);
+struct ahc_softc *ahc_find_softc(struct ahc_softc *);
void ahc_set_unit(struct ahc_softc *, int);
void ahc_set_name(struct ahc_softc *, char *);
void ahc_alloc_scbs(struct ahc_softc *ahc);
@@ -1139,6 +1185,9 @@ int ahc_search_qinfifo(struct ahc_softc *ahc, int target,
char channel, int lun, u_int tag,
role_t role, uint32_t status,
ahc_search_action action);
+int ahc_search_untagged_queues(struct ahc_softc *,
+ struct scsi_xfer *, int, char, int, uint32_t,
+ ahc_search_action);
int ahc_search_disc_list(struct ahc_softc *ahc, int target,
char channel, int lun, u_int tag,
int stop_on_first, int remove,
@@ -1147,7 +1196,7 @@ void ahc_freeze_devq(struct ahc_softc *ahc, struct scb *scb);
int ahc_reset_channel(struct ahc_softc *ahc, char channel,
int initiate_reset);
void ahc_restart(struct ahc_softc *ahc);
-void ahc_calc_residual(struct scb *scb);
+void ahc_calc_residual(struct ahc_softc *ahc, struct scb *scb);
/*************************** Utility Functions ********************************/
struct ahc_phase_table_entry*
ahc_lookup_phase_entry(int phase);
@@ -1209,7 +1258,16 @@ cam_status ahc_find_tmode_devs(struct ahc_softc *ahc,
#endif
#endif
/******************************* Debug ***************************************/
+void ahc_print_devinfo(struct ahc_softc *,
+ struct ahc_devinfo *);
void ahc_print_scb(struct scb *scb);
void ahc_dump_card_state(struct ahc_softc *ahc);
+int ahc_print_register(ahc_reg_parse_entry_t *, u_int,
+ const char *, u_int, u_int, u_int *, u_int);
+/******************************* SEEPROM *************************************/
+int ahc_acquire_seeprom(struct ahc_softc *,
+ struct seeprom_descriptor *);
+void ahc_release_seeprom(struct seeprom_descriptor *);
+
+void ahc_check_extport(struct ahc_softc *, u_int *);
#endif /* _AIC7XXX_H_ */
-
diff --git a/sys/dev/ic/aic7xxx_cam.h b/sys/dev/ic/aic7xxx_cam.h
new file mode 100644
index 00000000000..dee3c3b7e68
--- /dev/null
+++ b/sys/dev/ic/aic7xxx_cam.h
@@ -0,0 +1,174 @@
+/* $OpenBSD: aic7xxx_cam.h,v 1.1 2003/12/24 22:45:45 krw Exp $ */
+/* $NetBSD: aic7xxx_cam.h,v 1.3 2003/04/20 11:17:20 fvdl Exp $ */
+
+/*
+ * Data structures and definitions for the CAM system.
+ *
+ * Copyright (c) 1997 Justin T. Gibbs.
+ * Copyright (c) 2000 Adaptec Inc.
+ * All rights reserved.
+ *
+ * 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, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL").
+ *
+ * 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.
+ *
+ */
+/*
+ * Ported from FreeBSD by Pascal Renauld, Network Storage Solutions, Inc. - April 2003
+ */
+
+#ifndef _AIC7XXX_CAM_H
+#define _AIC7XXX_CAM_H
+
+#define SCSI_REV_2 2
+
+
+#define CAM_BUS_WILDCARD ((u_int)~0)
+#define CAM_TARGET_WILDCARD ((u_int)~0)
+#define CAM_LUN_WILDCARD -1
+
+/*
+ * XXX translate FreeBSD SCSI status byte values to NetBSD, and define
+ * a few more.
+ */
+#define SCSI_STATUS_OK SCSI_OK
+#define SCSI_STATUS_CHECK_COND SCSI_CHECK
+#define SCSI_STATUS_COND_MET SCSI_COND_MET
+#define SCSI_STATUS_BUSY SCSI_BUSY
+#define SCSI_STATUS_INTERMED SCSI_INTERM
+#define SCSI_STATUS_INTERMED_COND_MET SCSI_INTERMED_COND_MET
+#define SCSI_STATUS_RESERV_CONFLICT SCSI_RESERV_CONFLICT
+#define SCSI_STATUS_CMD_TERMINATED SCSI_TERMINATED
+#define SCSI_STATUS_QUEUE_FULL SCSI_QUEUE_FULL
+
+#define XS_STS_DONE ITSDONE
+#define XS_CTL_DATA_IN SCSI_DATA_IN
+#define XS_CTL_DATA_OUT SCSI_DATA_OUT
+#define XS_CTL_POLL SCSI_POLL
+#define XS_CTL_SILENT SCSI_SILENT
+#define XS_CTL_NOSLEEP SCSI_NOSLEEP
+#define XS_CTL_RESET SCSI_RESET
+
+#define MSG_EXT_PPR_DT_REQ MSG_EXT_PPR_PROT_DT
+#define MSG_ORDERED_TASK MSG_ORDERED_Q_TAG
+#define MSG_SIMPLE_TASK MSG_SIMPLE_Q_TAG
+#define MSG_ABORT_TASK MSG_ABORT_TAG
+
+#define scsipi_channel scsi_link
+#define scsipi_xfer scsi_xfer
+#define scsipi_adapter scsi_adapter
+#define scsipi_sense_data scsi_sense_data
+#define scsipi_sense scsi_sense
+#define scsipi_periph scsi_link
+#define scsipi_adapter_req_t int
+
+#define scsipi_periph_freeze(a, b)
+#define scsipi_periph_thaw(a, b)
+#define scsipi_channel_freeze(a, b)
+#define scsipi_channel_thaw(a, b)
+#define scsipi_printaddr(sc_link) sc_print_addr(sc_link)
+#define scsipi_done(xs) scsi_done(xs)
+
+#define callout_reset(timer, timeout, func, arg) timeout_add(timer, (timeout))
+
+#define xs_control flags
+#define xs_callout stimeout
+#define xs_status status
+#define xs_periph sc_link
+
+#define periph_target target
+#define periph_lun lun
+
+#define chan_ntargets adapter_buswidth
+#define chan_nluns luns
+#define chan_id adapter_target
+
+#define adapt_request scsi_cmd
+#define adapt_minphys scsi_minphys
+#define adapt_ioctl ioctl
+#define adapt_openings openings
+
+/* CAM Status field values */
+typedef enum {
+ CAM_REQ_INPROG, /* CCB request is in progress */
+ CAM_REQ_CMP, /* CCB request completed without error */
+ CAM_REQ_ABORTED, /* CCB request aborted by the host */
+ CAM_UA_ABORT, /* Unable to abort CCB request */
+ CAM_REQ_CMP_ERR, /* CCB request completed with an error */
+ CAM_BUSY, /* CAM subsytem is busy */
+ CAM_REQ_INVALID, /* CCB request was invalid */
+ CAM_PATH_INVALID, /* Supplied Path ID is invalid */
+ CAM_SEL_TIMEOUT, /* Target Selection Timeout */
+ CAM_CMD_TIMEOUT, /* Command timeout */
+ CAM_SCSI_STATUS_ERROR, /* SCSI error, look at error code in CCB */
+ CAM_SCSI_BUS_RESET, /* SCSI Bus Reset Sent/Received */
+ CAM_UNCOR_PARITY, /* Uncorrectable parity error occurred */
+ CAM_AUTOSENSE_FAIL, /* Autosense: request sense cmd fail */
+ CAM_NO_HBA, /* No HBA Detected Error */
+ CAM_DATA_RUN_ERR, /* Data Overrun error */
+ CAM_UNEXP_BUSFREE, /* Unexpected Bus Free */
+ CAM_SEQUENCE_FAIL, /* Protocol Violation */
+ CAM_CCB_LEN_ERR, /* CCB length supplied is inadequate */
+ CAM_PROVIDE_FAIL, /* Unable to provide requested capability */
+ CAM_BDR_SENT, /* A SCSI BDR msg was sent to target */
+ CAM_REQ_TERMIO, /* CCB request terminated by the host */
+ CAM_UNREC_HBA_ERROR, /* Unrecoverable Host Bus Adapter Error */
+ CAM_REQ_TOO_BIG, /* The request was too large for this host */
+ CAM_UA_TERMIO, /* Unable to terminate I/O CCB request */
+ CAM_MSG_REJECT_REC, /* Message Reject Received */
+ CAM_DEV_NOT_THERE, /* SCSI Device Not Installed/there */
+ CAM_RESRC_UNAVAIL, /* Resource Unavailable */
+ /*
+ * This request should be requeued to preserve
+ * transaction ordering. This typically occurs
+ * when the SIM recognizes an error that should
+ * freeze the queue and must place additional
+ * requests for the target at the sim level
+ * back into the XPT queue.
+ */
+ CAM_REQUEUE_REQ,
+ CAM_DEV_QFRZN = 0x40,
+
+ CAM_STATUS_MASK = 0x3F
+} cam_status;
+
+typedef enum {
+ CAM_DIR_IN = XS_CTL_DATA_IN,
+ CAM_DIR_OUT = XS_CTL_DATA_OUT,
+} ccb_flags;
+
+typedef enum {
+ AC_BUS_RESET = 0x001,
+ AC_UNSOL_RESEL = 0x002,
+ AC_SCSI_AEN = 0x008,
+ AC_SENT_BDR = 0x010,
+ AC_PATH_REGISTERED = 0x020,
+ AC_PATH_DEREGISTERED = 0x040,
+ AC_FOUND_DEVICE = 0x080,
+ AC_LOST_DEVICE = 0x100,
+ AC_TRANSFER_NEG = 0x200,
+ AC_INQ_CHANGED = 0x400,
+ AC_GETDEV_CHANGED = 0x800,
+} ac_code;
+
+#endif /* _AIC7XXX_CAM_H */
diff --git a/sys/dev/ic/aic7xxx_inline.h b/sys/dev/ic/aic7xxx_inline.h
index e0820d0467f..6f7cbc3cfdf 100644
--- a/sys/dev/ic/aic7xxx_inline.h
+++ b/sys/dev/ic/aic7xxx_inline.h
@@ -1,7 +1,11 @@
+/* $OpenBSD: aic7xxx_inline.h,v 1.7 2003/12/24 22:45:45 krw Exp $ */
+/* $NetBSD: aic7xxx_inline.h,v 1.4 2003/11/02 11:07:44 wiz Exp $ */
+
/*
* Inline routines shareable across OS platforms.
*
* Copyright (c) 1994-2001 Justin T. Gibbs.
+ * Copyright (c) 2000-2001 Adaptec Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -10,27 +14,38 @@
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer,
* without modification.
- * 2. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 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.
*
* Alternatively, this software may be distributed under the terms of the
- * GNU Public License ("GPL").
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
*
- * 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
+ * NO WARRANTY
+ * 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 MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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.
+ * 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 DAMAGES.
*
- * $Id: aic7xxx_inline.h,v 1.6 2003/10/21 18:58:48 jmc Exp $
+ * //depot/aic7xxx/aic7xxx/aic7xxx_inline.h#39 $
*
- * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx_inline.h,v 1.17 2001/07/18 21:39:47 gibbs Exp $
+ * $FreeBSD: /repoman/r/ncvs/src/sys/dev/aic7xxx/aic7xxx_inline.h,v 1.20 2003/01/20 20:44:55 gibbs Exp $
+ */
+/*
+ * Ported from FreeBSD by Pascal Renauld, Network Storage Solutions, Inc. - April 2003
*/
#ifndef _AIC7XXX_INLINE_H_
@@ -187,7 +202,7 @@ ahc_hscb_busaddr(struct ahc_softc *ahc, u_int index)
static __inline void
ahc_sync_scb(struct ahc_softc *ahc, struct scb *scb, int op)
{
- ahc_dmamap_sync(ahc, ahc->scb_data->hscb_dmat,
+ ahc_dmamap_sync(ahc, ahc->parent_dmat,
ahc->scb_data->hscb_dmamap,
/*offset*/(scb->hscb - ahc->scb_data->hscbs) * sizeof(*scb->hscb),
/*len*/sizeof(*scb->hscb), op);
@@ -199,7 +214,7 @@ ahc_sync_sglist(struct ahc_softc *ahc, struct scb *scb, int op)
if (scb->sg_count == 0)
return;
- ahc_dmamap_sync(ahc, ahc->scb_data->sg_dmat, scb->sg_map->sg_dmamap,
+ ahc_dmamap_sync(ahc, ahc->parent_dmat, scb->sg_map->sg_dmamap,
/*offset*/(scb->sg_list - scb->sg_map->sg_vaddr)
* sizeof(struct ahc_dma_seg),
/*len*/sizeof(struct ahc_dma_seg) * scb->sg_count, op);
@@ -220,14 +235,27 @@ ahc_name(struct ahc_softc *ahc)
return (ahc->name);
}
-/*********************** Miscellaneous Support Functions **********************/
+/*********************** Miscellaneous Support Functions ***********************/
-static __inline void ahc_update_residual(struct scb *scb);
+static __inline void ahc_update_residual(struct ahc_softc *ahc,
+ struct scb *scb);
static __inline struct ahc_initiator_tinfo *
ahc_fetch_transinfo(struct ahc_softc *ahc,
char channel, u_int our_id,
u_int remote_id,
struct ahc_tmode_tstate **tstate);
+static __inline uint16_t
+ ahc_inw(struct ahc_softc *ahc, u_int port);
+static __inline void ahc_outw(struct ahc_softc *ahc, u_int port,
+ u_int value);
+static __inline uint32_t
+ ahc_inl(struct ahc_softc *ahc, u_int port);
+static __inline void ahc_outl(struct ahc_softc *ahc, u_int port,
+ uint32_t value);
+static __inline uint64_t
+ ahc_inq(struct ahc_softc *ahc, u_int port);
+static __inline void ahc_outq(struct ahc_softc *ahc, u_int port,
+ uint64_t value);
static __inline struct scb*
ahc_get_scb(struct ahc_softc *ahc);
static __inline void ahc_free_scb(struct ahc_softc *ahc, struct scb *scb);
@@ -246,13 +274,13 @@ static __inline uint32_t
* for this SCB/transaction.
*/
static __inline void
-ahc_update_residual(struct scb *scb)
+ahc_update_residual(struct ahc_softc *ahc, struct scb *scb)
{
uint32_t sgptr;
sgptr = ahc_le32toh(scb->hscb->sgptr);
if ((sgptr & SG_RESID_VALID) != 0)
- ahc_calc_residual(scb);
+ ahc_calc_residual(ahc, scb);
}
/*
@@ -269,12 +297,69 @@ ahc_fetch_transinfo(struct ahc_softc *ahc, char channel, u_int our_id,
* in the initiator role to a given target are the same as
* when the roles are reversed, we pretend we are the target.
*/
- if (channel == 'B')
- our_id += 8;
+ /*if (channel == 'B')
+ our_id += 8;*/
*tstate = ahc->enabled_targets[our_id];
return (&(*tstate)->transinfo[remote_id]);
}
+static __inline uint16_t
+ahc_inw(struct ahc_softc *ahc, u_int port)
+{
+ return ((ahc_inb(ahc, port+1) << 8) | ahc_inb(ahc, port));
+}
+
+static __inline void
+ahc_outw(struct ahc_softc *ahc, u_int port, u_int value)
+{
+ ahc_outb(ahc, port, value & 0xFF);
+ ahc_outb(ahc, port+1, (value >> 8) & 0xFF);
+}
+
+static __inline uint32_t
+ahc_inl(struct ahc_softc *ahc, u_int port)
+{
+ return ((ahc_inb(ahc, port))
+ | (ahc_inb(ahc, port+1) << 8)
+ | (ahc_inb(ahc, port+2) << 16)
+ | (ahc_inb(ahc, port+3) << 24));
+}
+
+static __inline void
+ahc_outl(struct ahc_softc *ahc, u_int port, uint32_t value)
+{
+ ahc_outb(ahc, port, (value) & 0xFF);
+ ahc_outb(ahc, port+1, ((value) >> 8) & 0xFF);
+ ahc_outb(ahc, port+2, ((value) >> 16) & 0xFF);
+ ahc_outb(ahc, port+3, ((value) >> 24) & 0xFF);
+}
+
+static __inline uint64_t
+ahc_inq(struct ahc_softc *ahc, u_int port)
+{
+ return ((ahc_inb(ahc, port))
+ | (ahc_inb(ahc, port+1) << 8)
+ | (ahc_inb(ahc, port+2) << 16)
+ | (ahc_inb(ahc, port+3) << 24)
+ | (((uint64_t)ahc_inb(ahc, port+4)) << 32)
+ | (((uint64_t)ahc_inb(ahc, port+5)) << 40)
+ | (((uint64_t)ahc_inb(ahc, port+6)) << 48)
+ | (((uint64_t)ahc_inb(ahc, port+7)) << 56));
+}
+
+static __inline void
+ahc_outq(struct ahc_softc *ahc, u_int port, uint64_t value)
+{
+ ahc_outb(ahc, port, value & 0xFF);
+ ahc_outb(ahc, port+1, (value >> 8) & 0xFF);
+ ahc_outb(ahc, port+2, (value >> 16) & 0xFF);
+ ahc_outb(ahc, port+3, (value >> 24) & 0xFF);
+ ahc_outb(ahc, port+4, (value >> 32) & 0xFF);
+ ahc_outb(ahc, port+5, (value >> 40) & 0xFF);
+ ahc_outb(ahc, port+6, (value >> 48) & 0xFF);
+ ahc_outb(ahc, port+7, (value >> 56) & 0xFF);
+}
+
/*
* Get a free scb. If there are none, see if we can allocate a new SCB.
*/
@@ -348,8 +433,8 @@ ahc_swap_with_next_hscb(struct ahc_softc *ahc, struct scb *scb)
memcpy(q_hscb, scb->hscb, sizeof(*scb->hscb));
if ((scb->flags & SCB_CDB32_PTR) != 0) {
q_hscb->shared_data.cdb_ptr =
- ahc_hscb_busaddr(ahc, q_hscb->tag)
- + offsetof(struct hardware_scb, cdb32);
+ ahc_htole32(ahc_hscb_busaddr(ahc, q_hscb->tag)
+ + offsetof(struct hardware_scb, cdb32));
}
q_hscb->tag = saved_tag;
q_hscb->next = scb->hscb->tag;
@@ -372,14 +457,13 @@ ahc_queue_scb(struct ahc_softc *ahc, struct scb *scb)
if (scb->hscb->tag == SCB_LIST_NULL
|| scb->hscb->next == SCB_LIST_NULL)
- panic("Attempt to queue invalid SCB tag %x:%x",
+ panic("Attempt to queue invalid SCB tag %x:%x\n",
scb->hscb->tag, scb->hscb->next);
-
/*
* Keep a history of SCBs we've downloaded in the qinfifo.
*/
ahc->qinfifo[ahc->qinfifonext] = scb->hscb->tag;
- ahc_dmamap_sync(ahc, ahc->shared_data_dmat, ahc->shared_data_dmamap,
+ ahc_dmamap_sync(ahc, ahc->parent_dmat, ahc->shared_data_dmamap,
/*offset*/ahc->qinfifonext+256, /*len*/1,
BUS_DMASYNC_PREWRITE);
ahc->qinfifonext++;
@@ -426,19 +510,19 @@ static __inline void ahc_sync_qoutfifo(struct ahc_softc *ahc, int op);
static __inline void ahc_sync_qinfifo(struct ahc_softc *ahc, int op);
static __inline void ahc_sync_tqinfifo(struct ahc_softc *ahc, int op);
static __inline u_int ahc_check_cmdcmpltqueues(struct ahc_softc *ahc);
-static __inline void ahc_intr(struct ahc_softc *ahc);
+static __inline int ahc_intr(struct ahc_softc *ahc);
static __inline void
ahc_sync_qoutfifo(struct ahc_softc *ahc, int op)
{
- ahc_dmamap_sync(ahc, ahc->shared_data_dmat, ahc->shared_data_dmamap,
+ ahc_dmamap_sync(ahc, ahc->parent_dmat, ahc->shared_data_dmamap,
/*offset*/0, /*len*/256, op);
}
static __inline void
ahc_sync_qinfifo(struct ahc_softc *ahc, int op)
{
- ahc_dmamap_sync(ahc, ahc->shared_data_dmat, ahc->shared_data_dmamap,
+ ahc_dmamap_sync(ahc, ahc->parent_dmat, ahc->shared_data_dmamap,
/*offset*/256, /*len*/256, op);
}
@@ -447,7 +531,7 @@ ahc_sync_tqinfifo(struct ahc_softc *ahc, int op)
{
#ifdef AHC_TARGET_MODE
if ((ahc->flags & AHC_TARGETROLE) != 0) {
- ahc_dmamap_sync(ahc, ahc->shared_data_dmat,
+ ahc_dmamap_sync(ahc, ahc->parent_dmat /*shared_data_dmat*/,
ahc->shared_data_dmamap,
ahc_targetcmd_offset(ahc, 0),
sizeof(struct target_cmd) * AHC_TMODE_CMDS,
@@ -468,18 +552,19 @@ ahc_check_cmdcmpltqueues(struct ahc_softc *ahc)
u_int retval;
retval = 0;
- ahc_dmamap_sync(ahc, ahc->shared_data_dmat, ahc->shared_data_dmamap,
+ ahc_dmamap_sync(ahc, ahc->parent_dmat /*shared_data_dmat*/, ahc->shared_data_dmamap,
/*offset*/ahc->qoutfifonext, /*len*/1,
BUS_DMASYNC_POSTREAD);
if (ahc->qoutfifo[ahc->qoutfifonext] != SCB_LIST_NULL)
retval |= AHC_RUN_QOUTFIFO;
#ifdef AHC_TARGET_MODE
- if ((ahc->flags & AHC_TARGETROLE) != 0) {
- ahc_dmamap_sync(ahc, ahc->shared_data_dmat,
- ahc->shared_data_dmamap,
- ahc_targetcmd_offset(ahc, ahc->tqinfifofnext),
- /*len*/sizeof(struct target_cmd),
- BUS_DMASYNC_POSTREAD);
+ if ((ahc->flags & AHC_TARGETROLE) != 0
+ && (ahc->flags & AHC_TQINFIFO_BLOCKED) == 0) {
+ ahc_dmamap_sync(ahc, ahc->parent_dmat /*shared_data_dmat*/,
+ ahc->shared_data_dmamap,
+ ahc_targetcmd_offset(ahc, ahc->tqinfifonext),
+ /*len*/sizeof(struct target_cmd),
+ BUS_DMASYNC_POSTREAD);
if (ahc->targetcmds[ahc->tqinfifonext].cmd_valid != 0)
retval |= AHC_RUN_TQINFIFO;
}
@@ -490,12 +575,20 @@ ahc_check_cmdcmpltqueues(struct ahc_softc *ahc)
/*
* Catch an interrupt from the adapter
*/
-static __inline void
+static __inline int
ahc_intr(struct ahc_softc *ahc)
{
u_int intstat;
- u_int queuestat;
+ if ((ahc->pause & INTEN) == 0) {
+ /*
+ * Our interrupt is not enabled on the chip
+ * and may be disabled for re-entrancy reasons,
+ * so just return. This is likely just a shared
+ * interrupt.
+ */
+ return 0;
+ }
/*
* Instead of directly reading the interrupt status register,
* infer the cause of the interrupt by checking our in-core
@@ -503,20 +596,14 @@ ahc_intr(struct ahc_softc *ahc)
* most cases.
*/
if ((ahc->flags & (AHC_ALL_INTERRUPTS|AHC_EDGE_INTERRUPT)) == 0
- && (queuestat = ahc_check_cmdcmpltqueues(ahc)) != 0)
- intstat = CMDCMPLT;
- else {
- intstat = ahc_inb(ahc, INTSTAT);
- queuestat = AHC_RUN_QOUTFIFO;
-#ifdef AHC_TARGET_MODE
- if ((ahc->flags & AHC_TARGETROLE) != 0)
- queuestat |= AHC_RUN_TQINFIFO;
-#endif
- }
+ && (ahc_check_cmdcmpltqueues(ahc) != 0))
+ intstat = CMDCMPLT;
+ else {
+ intstat = ahc_inb(ahc, INTSTAT);
+ }
- if (intstat & CMDCMPLT) {
+ if (intstat & CMDCMPLT) {
ahc_outb(ahc, CLRINT, CLRCMDINT);
-
/*
* Ensure that the chip sees that we've cleared
* this interrupt before we walk the output fifo.
@@ -526,19 +613,16 @@ ahc_intr(struct ahc_softc *ahc)
* and asserted the interrupt again.
*/
ahc_flush_device_writes(ahc);
+ ahc_run_qoutfifo(ahc);
#ifdef AHC_TARGET_MODE
- if ((queuestat & AHC_RUN_QOUTFIFO) != 0)
-#endif
- ahc_run_qoutfifo(ahc);
-#ifdef AHC_TARGET_MODE
- if ((queuestat & AHC_RUN_TQINFIFO) != 0)
+ if ((ahc->flags & AHC_TARGETROLE) != 0)
ahc_run_tqinfifo(ahc, /*paused*/FALSE);
#endif
}
if (intstat == 0xFF && (ahc->features & AHC_REMOVABLE) != 0)
/* Hot eject */
- return;
+ return 1;
if ((intstat & INT_PEND) == 0) {
#if AHC_PCI_CONFIG > 0
@@ -548,16 +632,16 @@ ahc_intr(struct ahc_softc *ahc)
&& (ahc_inb(ahc, ERROR) & PCIERRSTAT) != 0)
ahc->bus_intr(ahc);
}
-#endif
ahc->unsolicited_ints++;
- return;
+#endif
+ return 0;
}
ahc->unsolicited_ints = 0;
if (intstat & BRKADRINT) {
ahc_handle_brkadrint(ahc);
/* Fatal error, no more interrupts to handle. */
- return;
+ return 1;
}
if ((intstat & (SEQINT|SCSIINT)) != 0)
@@ -568,6 +652,8 @@ ahc_intr(struct ahc_softc *ahc)
if ((intstat & SCSIINT) != 0)
ahc_handle_scsiint(ahc, intstat);
+
+ return 1;
}
#endif /* _AIC7XXX_INLINE_H_ */
diff --git a/sys/dev/ic/aic7xxx_openbsd.c b/sys/dev/ic/aic7xxx_openbsd.c
index f61bd2f1370..57e62599823 100644
--- a/sys/dev/ic/aic7xxx_openbsd.c
+++ b/sys/dev/ic/aic7xxx_openbsd.c
@@ -1,3 +1,6 @@
+/* $OpenBSD: aic7xxx_openbsd.c,v 1.15 2003/12/24 22:45:45 krw Exp $ */
+/* $NetBSD: aic7xxx_osm.c,v 1.14 2003/11/02 11:07:44 wiz Exp $ */
+
/*
* Bus independent OpenBSD shim for the aic7xxx based adaptec SCSI controllers
*
@@ -29,22 +32,41 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: aic7xxx_openbsd.c,v 1.14 2003/10/21 18:58:48 jmc Exp $
+ * //depot/aic7xxx/freebsd/dev/aic7xxx/aic7xxx_osm.c#12 $
*
- * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx_freebsd.c,v 1.26 2001/07/18 21:39:47 gibbs Exp $
- * $OpenBSD: aic7xxx_openbsd.c,v 1.14 2003/10/21 18:58:48 jmc Exp $
+ * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx_osm.c,v 1.31 2002/11/30 19:08:58 scottl Exp $
+ */
+/*
+ * Ported from FreeBSD by Pascal Renauld, Network Storage Solutions, Inc. - April 2003
*/
+#include <sys/cdefs.h>
+/* __KERNEL_RCSID(0, "$NetBSD: aic7xxx_osm.c,v 1.14 2003/11/02 11:07:44 wiz Exp $"); */
+
#include <dev/ic/aic7xxx_openbsd.h>
#include <dev/ic/aic7xxx_inline.h>
+#ifndef AHC_TMODE_ENABLE
+#define AHC_TMODE_ENABLE 0
+#endif
+
+
+int32_t ahc_action(struct scsi_xfer *);
+int ahc_execute_scb(void *, bus_dma_segment_t *, int);
+int ahc_poll(struct ahc_softc *, int);
+int ahc_setup_data(struct ahc_softc *, struct scsi_xfer *,
+ struct scb *);
+void ahc_set_recoveryscb(struct ahc_softc *, struct scb *);
+
+static void ahc_minphys(struct buf *);
+void ahc_adapter_req_set_xfer_mode(struct ahc_softc *, struct scb *);
+
+
+
struct cfdriver ahc_cd = {
NULL, "ahc", DV_DULL
};
-int32_t ahc_action(struct scsi_xfer *xs);
-static void ahc_minphys(struct buf *bp);
-
static struct scsi_adapter ahc_switch =
{
ahc_action,
@@ -62,559 +84,92 @@ static struct scsi_device ahc_dev =
NULL, /* Use default 'done' routine */
};
-#ifndef AHC_TMODE_ENABLE
-#define AHC_TMODE_ENABLE 0
-#endif
-
-#define ccb_scb_ptr spriv_ptr0
-
-#ifdef AHC_DEBUG
-int ahc_debug = AHC_DEBUG;
-#endif
-
-#if UNUSED
-static void ahc_dump_targcmd(struct target_cmd *cmd);
-#endif
-void ahc_build_free_scb_list(struct ahc_softc *ahc);
-int ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs,
- int nsegments);
-int ahc_poll(struct ahc_softc *ahc, int wait);
-void ahc_timeout(void *);
-int ahc_setup_data(struct ahc_softc *ahc,
- struct scsi_xfer *xs,
- struct scb *scb);
-void ahc_set_recoveryscb(struct ahc_softc *ahc,
- struct scb *scb);
-int ahc_init_scbdata(struct ahc_softc *ahc);
-void ahc_fini_scbdata(struct ahc_softc *ahc);
-int ahc_istagged_device(struct ahc_softc *ahc,
- struct scsi_xfer *xs,
- int nocmdcheck);
-void ahc_check_tags(struct ahc_softc *ahc,
- struct scsi_xfer *xs);
-
-/*
- * Routines to manage busy targets. The old driver didn't need to
- * pause the sequencer because no device registers were accessed. Now
- * busy targets are controlled via the device registers and thus, we
- * have to pause the sequencer for chips that don't have the
- * auto-pause feature. XXX smurph
- */
-u_int ahc_pause_index_busy_tcl(struct ahc_softc *ahc, u_int tcl);
-void ahc_pause_unbusy_tcl(struct ahc_softc *ahc, u_int tcl);
-void ahc_pause_busy_tcl(struct ahc_softc *ahc, u_int tcl, u_int busyid);
-
-u_int
-ahc_pause_index_busy_tcl(ahc, tcl)
- struct ahc_softc *ahc;
- u_int tcl;
-{
- u_int retval;
- if (ahc->features & AHC_AUTOPAUSE) {
- retval = ahc_index_busy_tcl(ahc, tcl);
- } else {
- ahc_pause(ahc);
- retval = ahc_index_busy_tcl(ahc, tcl);
- ahc_unpause(ahc);
- }
- return retval;
-}
-
-void
-ahc_pause_unbusy_tcl(ahc, tcl)
- struct ahc_softc *ahc;
- u_int tcl;
-{
- if (ahc->features & AHC_AUTOPAUSE) {
- ahc_unbusy_tcl(ahc, tcl);
- } else {
- ahc_pause(ahc);
- ahc_unbusy_tcl(ahc, tcl);
- ahc_unpause(ahc);
- }
-}
-
-void
-ahc_pause_busy_tcl(ahc, tcl, busyid)
- struct ahc_softc *ahc;
- u_int tcl;
- u_int busyid;
-{
- if (ahc->features & AHC_AUTOPAUSE) {
- ahc_busy_tcl(ahc, tcl, busyid);
- } else {
- ahc_pause(ahc);
- ahc_busy_tcl(ahc, tcl, busyid);
- ahc_unpause(ahc);
- }
-}
-
-/* Special routine to force negotiation for OpenBSD */
-void
-ahc_force_neg(ahc)
- struct ahc_softc *ahc;
-{
- int num_targets = AHC_NUM_TARGETS;
- int i;
-
- if ((ahc->features & (AHC_WIDE|AHC_TWIN)) == 0)
- num_targets = 8;
-
- for (i = 0; i < num_targets; i++) {
- struct ahc_initiator_tinfo *tinfo;
- struct ahc_tmode_tstate *tstate;
- u_int our_id;
- u_int target_id;
- char channel;
-
- channel = 'A';
- our_id = ahc->our_id;
- target_id = i;
- if (i > 7 && (ahc->features & AHC_TWIN) != 0) {
- channel = 'B';
- our_id = ahc->our_id_b;
- target_id = i % 8;
- }
- tinfo = ahc_fetch_transinfo(ahc, channel, our_id,
- target_id, &tstate);
- tinfo->goal = tinfo->user; /* force negotiation */
- tstate->discenable = ahc->user_discenable;
- }
-}
-
-int
-ahc_createdmamem(ahc, dmat, size, mapp, vaddr, baddr, seg, nseg, what)
- struct ahc_softc *ahc;
- bus_dma_tag_t dmat;
- int size;
- bus_dmamap_t *mapp;
- caddr_t *vaddr;
- bus_addr_t *baddr;
- bus_dma_segment_t *seg;
- int *nseg;
- const char *what;
-{
- int error, level = 0;
- int dma_flags = BUS_DMA_NOWAIT;
-
- dmat = ahc->parent_dmat;
-
- if ((ahc->chip & AHC_VL) !=0)
- dma_flags |= ISABUS_DMA_32BIT;
-
- if ((error = bus_dmamem_alloc(dmat, size, NBPG, 0,
- seg, 1, nseg, BUS_DMA_NOWAIT)) != 0) {
- printf("%s: failed to %s DMA map for %s, error = %d\n",
- "allocate", ahc_name(ahc), what, error);
- goto out;
- }
- level++;
-
- if ((error = bus_dmamem_map(dmat, seg, *nseg, size, vaddr,
- BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) != 0) {
- printf("%s: failed to %s DMA map for %s, error = %d\n",
- "map", ahc_name(ahc), what, error);
- goto out;
- }
- level++;
-
- if ((error = bus_dmamap_create(dmat, size, 1, size, 0,
- dma_flags, mapp)) != 0) {
- printf("%s: failed to %s DMA map for %s, error = %d\n",
- "create", ahc_name(ahc), what, error);
- goto out;
- }
- level++;
-
- if ((error = bus_dmamap_load(dmat, *mapp, *vaddr, size, NULL,
- BUS_DMA_NOWAIT)) != 0) {
- printf("%s: failed to %s DMA map for %s, error = %d\n",
- "load", ahc_name(ahc), what, error);
- goto out;
- }
-
- *baddr = (*mapp)->dm_segs[0].ds_addr;
- return 0;
-out:
- switch (level) {
- case 3:
- bus_dmamap_destroy(dmat, *mapp);
- /* FALLTHROUGH */
- case 2:
- bus_dmamem_unmap(dmat, *vaddr, size);
- /* FALLTHROUGH */
- case 1:
- bus_dmamem_free(dmat, seg, *nseg);
- break;
- default:
- break;
- }
-
- return error;
-}
-
-void
-ahc_freedmamem(tag, size, map, vaddr, seg, nseg)
- bus_dma_tag_t tag;
- int size;
- bus_dmamap_t map;
- caddr_t vaddr;
- bus_dma_segment_t *seg;
- int nseg;
-{
- bus_dmamap_unload(tag, map);
- bus_dmamap_destroy(tag, map);
- bus_dmamem_unmap(tag, vaddr, size);
- bus_dmamem_free(tag, seg, nseg);
-}
-
-void
-ahc_alloc_scbs(ahc)
- struct ahc_softc *ahc;
-{
- struct scb_data *scb_data;
- struct scb *next_scb;
- struct sg_map_node *sg_map;
- bus_addr_t physaddr;
- struct ahc_dma_seg *segs;
- int newcount;
- int i;
- int dma_flags = 0;
-
- scb_data = ahc->scb_data;
- if (scb_data->numscbs >= AHC_SCB_MAX)
- /* Can't allocate any more */
- return;
-
- next_scb = &scb_data->scbarray[scb_data->numscbs];
-
- sg_map = malloc(sizeof(*sg_map), M_DEVBUF, M_NOWAIT);
-
- if (sg_map == NULL)
- return;
-
- if (ahc_createdmamem(ahc, scb_data->sg_dmat, PAGE_SIZE,
- &sg_map->sg_dmamap, (caddr_t *)&sg_map->sg_vaddr,
- &sg_map->sg_physaddr, &sg_map->sg_dmasegs,
- &sg_map->sg_nseg, "SG space") < 0) {
- free(sg_map, M_DEVBUF);
- return;
- }
-
- SLIST_INSERT_HEAD(&scb_data->sg_maps, sg_map, links);
-
- segs = sg_map->sg_vaddr;
- physaddr = sg_map->sg_physaddr;
-
- newcount = (PAGE_SIZE / (AHC_NSEG * sizeof(struct ahc_dma_seg)));
- for (i = 0; scb_data->numscbs < AHC_SCB_MAX && i < newcount; i++) {
- struct scb_platform_data *pdata;
- int error;
-
- pdata = (struct scb_platform_data *)malloc(sizeof(*pdata),
- M_DEVBUF, M_NOWAIT);
- if (pdata == NULL)
- break;
- bzero(pdata, sizeof(*pdata));
- next_scb->platform_data = pdata;
- next_scb->sg_map = sg_map;
- next_scb->sg_list = segs;
- /*
- * The sequencer always starts with the second entry.
- * The first entry is embedded in the scb.
- */
- next_scb->sg_list_phys = physaddr + sizeof(struct ahc_dma_seg);
- next_scb->ahc_softc = ahc;
- next_scb->flags = SCB_FREE;
-
- /* set up AHA-284x correctly. */
- dma_flags = ((ahc->chip & AHC_VL) !=0) ?
- BUS_DMA_NOWAIT|ISABUS_DMA_32BIT :
- BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW;
-
- ahc->buffer_dmat = ahc->parent_dmat;
- error = bus_dmamap_create(ahc->buffer_dmat,
- AHC_MAXTRANSFER_SIZE, AHC_NSEG,
- MAXBSIZE, 0, dma_flags,
- &next_scb->dmamap);
- if (error !=0)
- break;
-
- next_scb->hscb = &scb_data->hscbs[scb_data->numscbs];
- next_scb->hscb->tag = ahc->scb_data->numscbs;
- SLIST_INSERT_HEAD(&ahc->scb_data->free_scbs,
- next_scb, links.sle);
- segs += AHC_NSEG;
- physaddr += (AHC_NSEG * sizeof(struct ahc_dma_seg));
- next_scb++;
- ahc->scb_data->numscbs++;
- }
-}
-
-int
-ahc_init_scbdata(ahc)
- struct ahc_softc *ahc;
-{
- struct scb_data *scb_data;
-
- scb_data = ahc->scb_data;
- scb_data->init_level = 0;
- SLIST_INIT(&scb_data->free_scbs);
- SLIST_INIT(&scb_data->sg_maps);
-
- /* Allocate SCB resources */
- scb_data->scbarray =
- (struct scb *)malloc(sizeof(struct scb) * AHC_SCB_MAX,
- M_DEVBUF, M_NOWAIT);
- if (scb_data->scbarray == NULL)
- return (ENOMEM);
- memset(scb_data->scbarray, 0, sizeof(struct scb) * AHC_SCB_MAX);
-
- /* set dma tags */
- scb_data->hscb_dmat = ahc->parent_dmat;
- scb_data->sense_dmat = ahc->parent_dmat;
- scb_data->sg_dmat = ahc->parent_dmat;
-
- /* Determine the number of hardware SCBs and initialize them */
- scb_data->maxhscbs = ahc_probe_scbs(ahc);
- if ((ahc->flags & AHC_PAGESCBS) != 0) {
- /* SCB 0 heads the free list */
- ahc_outb(ahc, FREE_SCBH, 0);
- } else {
- ahc_outb(ahc, FREE_SCBH, SCB_LIST_NULL);
- }
-
- if (ahc->scb_data->maxhscbs == 0) {
- printf("%s: No SCB space found\n", ahc_name(ahc));
- return (ENXIO);
- }
-
- ahc_build_free_scb_list(ahc);
-
- /*
- * Create our DMA mappings. These tags define the kinds of device
- * accessible memory allocations and memory mappings we will
- * need to perform during normal operation.
- *
- * Unless we need to further restrict the allocation, we rely
- * on the restrictions of the parent dmat, hence the common
- * use of MAXADDR and MAXSIZE.
- */
- if (ahc_createdmamem(ahc, scb_data->hscb_dmat,
- AHC_SCB_MAX * sizeof(struct hardware_scb),
- &scb_data->hscb_dmamap, (caddr_t *)&scb_data->hscbs,
- &scb_data->hscb_busaddr, &scb_data->hscb_seg,
- &scb_data->hscb_nseg, "hardware SCB structures") < 0)
- goto error_exit;
-
- scb_data->init_level++;
-
- /* DMA for our sense buffers */
- if (ahc_createdmamem(ahc, scb_data->sense_dmat,
- AHC_SCB_MAX * sizeof(struct scsi_sense_data),
- &scb_data->sense_dmamap, (caddr_t *)&scb_data->sense,
- &scb_data->sense_busaddr, &scb_data->sense_seg,
- &scb_data->sense_nseg, "sense buffers") < 0)
- goto error_exit;
-
- scb_data->init_level++;
-
- /* Perform initial CCB allocation */
- memset(scb_data->hscbs, 0, AHC_SCB_MAX * sizeof(struct hardware_scb));
- ahc_alloc_scbs(ahc);
-
- if (scb_data->numscbs == 0) {
- printf("%s: Unable to allocate initial scbs\n",
- ahc_name(ahc));
- goto error_exit;
- }
- scb_data->init_level++;
-
- /*
- * Tell the sequencer which SCB will be the next one it receives.
- */
- ahc->next_queued_scb = ahc_get_scb(ahc);
- ahc_outb(ahc, NEXT_QUEUED_SCB, ahc->next_queued_scb->hscb->tag);
-
- /*
- * Note that we were successful
- */
- return (0);
-
-error_exit:
-
- return (ENOMEM);
-}
-
-void
-ahc_fini_scbdata(ahc)
- struct ahc_softc *ahc;
-{
- struct scb_data *scb_data;
-
- scb_data = ahc->scb_data;
-
- switch (scb_data->init_level) {
- default:
- case 3:
- {
- struct sg_map_node *sg_map;
-
- while ((sg_map = SLIST_FIRST(&scb_data->sg_maps))!= NULL) {
- SLIST_REMOVE_HEAD(&scb_data->sg_maps, links);
- ahc_freedmamem(ahc->parent_dmat, PAGE_SIZE,
- sg_map->sg_dmamap,
- (caddr_t)sg_map->sg_vaddr,
- &sg_map->sg_dmasegs, sg_map->sg_nseg);
- free(sg_map, M_DEVBUF);
- }
- }
- /*FALLTHROUGH*/
- case 2:
- ahc_freedmamem(ahc->parent_dmat,
- AHC_SCB_MAX * sizeof(struct scsi_sense_data),
- scb_data->sense_dmamap, (caddr_t)scb_data->sense,
- &scb_data->sense_seg, scb_data->sense_nseg);
- /*FALLTHROUGH*/
- case 1:
- ahc_freedmamem(ahc->parent_dmat,
- AHC_SCB_MAX * sizeof(struct hardware_scb),
- scb_data->hscb_dmamap, (caddr_t)scb_data->hscbs,
- &scb_data->hscb_seg, scb_data->hscb_nseg);
- /*FALLTHROUGH*/
- }
- if (scb_data->scbarray != NULL)
- free(scb_data->scbarray, M_DEVBUF);
-}
-
-void
-ahc_free(ahc)
- struct ahc_softc *ahc;
-{
- ahc_fini_scbdata(ahc);
- if (ahc->init_level != 0)
- ahc_freedmamem(ahc->parent_dmat, ahc->shared_data_size,
- ahc->shared_data_dmamap, ahc->qoutfifo,
- &ahc->shared_data_seg, ahc->shared_data_nseg);
-
- if (ahc->scb_data != NULL)
- free(ahc->scb_data, M_DEVBUF);
- return;
-}
-
/*
* Attach all the sub-devices we can find
*/
int
-ahc_attach(ahc)
- struct ahc_softc *ahc;
+ahc_attach(struct ahc_softc *ahc)
{
- char ahc_info[256];
- int s;
- ahc_lock(ahc, &s);
+ char ahc_info[256];
+ int i, s;
- ahc_controller_info(ahc, ahc_info, sizeof ahc_info);
- printf("%s: %s\n", ahc_name(ahc), ahc_info);
- /*
- * Initialize the software queue.
- */
- LIST_INIT(&ahc->platform_data->sc_xxxq);
+ LIST_INIT(&ahc->pending_scbs);
+ for (i = 0; i < AHC_NUM_TARGETS; i++)
+ TAILQ_INIT(&ahc->untagged_queues[i]);
+
+ ahc_lock(ahc, &s);
-#ifdef AHC_BROKEN_CACHE
- if (cpu_class == CPUCLASS_386) /* doesn't have "wbinvd" instruction */
- ahc_broken_cache = 0;
-#endif
/*
* fill in the prototype scsi_links.
*/
- ahc->platform_data->sc_link.adapter_target = ahc->our_id;
+ ahc->sc_channel.adapter_target = ahc->our_id;
if (ahc->features & AHC_WIDE)
- ahc->platform_data->sc_link.adapter_buswidth = 16;
- ahc->platform_data->sc_link.adapter_softc = ahc;
- ahc->platform_data->sc_link.adapter = &ahc_switch;
- ahc->platform_data->sc_link.openings = 2;
- ahc->platform_data->sc_link.device = &ahc_dev;
- ahc->platform_data->sc_link.flags = SCSIDEBUG_LEVEL;
+ ahc->sc_channel.adapter_buswidth = 16;
+ ahc->sc_channel.adapter_softc = ahc;
+ ahc->sc_channel.adapter = &ahc_switch;
+ ahc->sc_channel.openings = 16;
+ ahc->sc_channel.device = &ahc_dev;
+ ahc->sc_channel.flags = SCSIDEBUG_LEVEL;
if (ahc->features & AHC_TWIN) {
/* Configure the second scsi bus */
- ahc->platform_data->sc_link_b = ahc->platform_data->sc_link;
- ahc->platform_data->sc_link_b.adapter_target = ahc->our_id_b;
- if (ahc->features & AHC_WIDE)
- ahc->platform_data->sc_link.adapter_buswidth = 16;
- ahc->platform_data->sc_link_b.adapter_softc = ahc;
- ahc->platform_data->sc_link_b.adapter = &ahc_switch;
- ahc->platform_data->sc_link_b.openings = 2;
- ahc->platform_data->sc_link_b.device = &ahc_dev;
- ahc->platform_data->sc_link_b.flags = SCSIDEBUG_LEVEL;
+ ahc->sc_channel_b = ahc->sc_channel;
+ ahc->sc_channel_b.adapter_target = ahc->our_id_b;
}
- /*
- * ask the adapter what subunits are present
- */
- if (ahc->platform_data->channel_b_primary == FALSE) {
- /* make SCSI_IS_SCSIBUS_B() == false, while probing channel A */
- ahc->platform_data->sc_link_b.scsibus = 0xff;
- config_found((void *)ahc, &ahc->platform_data->sc_link, scsiprint);
+ ahc_controller_info(ahc, ahc_info, sizeof ahc_info);
+ printf("%s: %s\n", ahc->sc_dev.dv_xname, ahc_info);
+
+ ahc_intr_enable(ahc, TRUE);
+
+ if (ahc->flags & AHC_RESET_BUS_A)
+ ahc_reset_channel(ahc, 'A', TRUE);
+ if ((ahc->features & AHC_TWIN) && ahc->flags & AHC_RESET_BUS_B)
+ ahc_reset_channel(ahc, 'B', TRUE);
+
+ if ((ahc->flags & AHC_PRIMARY_CHANNEL) == 0) {
+ /*
+ * Ensure SCSI_IS_SCSIBUS_B() returns false for sc_channel
+ * until sc_channel_b has been properly initialized by scsi
+ * layer.
+ */
+ ahc->sc_channel_b.scsibus = 0xff;
+ ahc->sc_child = config_found((void *)&ahc->sc_dev,
+ &ahc->sc_channel, scsiprint);
if (ahc->features & AHC_TWIN)
- config_found((void *)ahc, &ahc->platform_data->sc_link_b, scsiprint);
+ ahc->sc_child_b = config_found((void *)&ahc->sc_dev,
+ &ahc->sc_channel_b, scsiprint);
} else {
/*
- * if implementation of SCSI_IS_SCSIBUS_B() is changed to use
- * ahc->sc_link.scsibus, then "ahc->sc_link.scsibus = 0xff;"
- * is needed, here.
+ * Ensure SCSI_IS_SCSIBUS_B() returns false for sc_channel_b
+ * until sc_channel has been properly initialized by scsi
+ * layer.
*/
+ ahc->sc_channel.scsibus = 0xff;
if (ahc->features & AHC_TWIN)
- config_found((void *)ahc, &ahc->platform_data->sc_link_b, scsiprint);
- config_found((void *)ahc, &ahc->platform_data->sc_link, scsiprint);
+ ahc->sc_child = config_found((void *)&ahc->sc_dev,
+ &ahc->sc_channel_b, scsiprint);
+ ahc->sc_child_b = config_found((void *)&ahc->sc_dev,
+ &ahc->sc_channel, scsiprint);
}
+
ahc_unlock(ahc, &s);
- return 1;
+ return (1);
}
/*
* Catch an interrupt from the adapter
*/
int
-ahc_platform_intr(arg)
- void *arg;
+ahc_platform_intr(void *arg)
{
- struct ahc_softc *ahc;
- u_int intstat = 0;
- u_int errstat = 0;
-
- /*
- * Any interrupts to process?
- */
- ahc = (struct ahc_softc *)arg;
+ struct ahc_softc *ahc = (struct ahc_softc *)arg;
- intstat = ahc_inb(ahc, INTSTAT);
-
- /* Only check PCI error on PCI cards */
- if ((ahc->chip & AHC_PCI) != 0) {
- errstat = ahc_inb(ahc, ERROR);
- if ((intstat & INT_PEND) == 0 && (errstat & PCIERRSTAT)) {
- if (ahc->unsolicited_ints > 500) {
- ahc->unsolicited_ints = 0;
- ahc->bus_intr(ahc);
- }
- ahc->unsolicited_ints++;
- /* claim the interrupt */
- return 1;
- }
- }
-
- if ((intstat & INT_PEND) == 0){
- /* This interrupt is not for us */
- return 0;
- }
-
- bus_dmamap_sync(ahc->scb_data->hscb_dmat, ahc->scb_data->hscb_dmamap,
+ bus_dmamap_sync(ahc->parent_dmat, ahc->scb_data->hscb_dmamap,
0, ahc->scb_data->hscb_dmamap->dm_mapsize,
BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
- ahc_intr(ahc);
- return 1;
+ return ahc_intr(ahc);
}
/*
@@ -623,32 +178,15 @@ ahc_platform_intr(arg)
* went.
*/
void
-ahc_done(ahc, scb)
- struct ahc_softc *ahc;
- struct scb *scb;
+ahc_done(struct ahc_softc *ahc, struct scb *scb)
{
- struct scsi_xfer *xs = scb->io_ctx;
- struct scsi_link *sc_link = xs->sc_link;
- int requeue = 0;
- int target;
- int lun;
-
- SC_DEBUG(xs->sc_link, SDEV_DB2, ("ahc_done\n"));
+ struct scsi_xfer *xs = scb->xs;
+ int s;
- bus_dmamap_sync(ahc->scb_data->hscb_dmat, ahc->scb_data->hscb_dmamap,
+ bus_dmamap_sync(ahc->parent_dmat, ahc->scb_data->hscb_dmamap,
0, ahc->scb_data->hscb_dmamap->dm_mapsize,
BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
-#ifdef maybe_not_such_a_good_idea
- /* Don't smash a disconnected SCB */
- if ((scb->hscb->control & DISCONNECTED) != 0){
- printf("disconnected sbc (tag %d) in ahc_done(ahc)!!!\n");
- if ((xs = ahc->platform_data->sc_xxxq.lh_first) != NULL)
- (void) ahc_action(xs);
- return;
- }
-#endif
-
LIST_REMOVE(scb, pending_links);
if ((scb->flags & SCB_UNTAGGEDQ) != 0) {
struct scb_tailq *untagged_q;
@@ -663,18 +201,6 @@ ahc_done(ahc, scb)
timeout_del(&xs->stimeout);
-#ifdef AHC_DEBUG
- if ((ahc_debug & AHC_SHOWCMDS)) {
- ahc_print_path(ahc, scb);
- printf("ahc_done: opcode 0x%x tag %x flags %x status %d error %d\n",
- xs->cmdstore.opcode, scb->hscb->tag,
- scb->flags, xs->status, xs->error);
- }
-#endif
-
- target = sc_link->target;
- lun = sc_link->lun;
-
if (xs->datalen) {
int op;
@@ -682,20 +208,9 @@ ahc_done(ahc, scb)
op = BUS_DMASYNC_POSTREAD;
else
op = BUS_DMASYNC_POSTWRITE;
- ahc->buffer_dmat = ahc->parent_dmat;
- bus_dmamap_sync(ahc->buffer_dmat, scb->dmamap,
- 0, scb->dmamap->dm_mapsize, op);
-
- bus_dmamap_unload(ahc->buffer_dmat, scb->dmamap);
- }
-
- /*
- * Unbusy this target/channel/lun.
- * XXX if we are holding two commands per lun,
- * send the next command.
- */
- if (!(scb->hscb->control & TAG_ENB)){
- ahc_pause_unbusy_tcl(ahc, XS_TCL(xs));
+ bus_dmamap_sync(ahc->parent_dmat, scb->dmamap, 0,
+ scb->dmamap->dm_mapsize, op);
+ bus_dmamap_unload(ahc->parent_dmat, scb->dmamap);
}
/*
@@ -711,77 +226,75 @@ ahc_done(ahc, scb)
* commands.
*/
LIST_FOREACH(list_scb, &ahc->pending_scbs, pending_links) {
- struct scsi_xfer *txs = list_scb->io_ctx;
+ struct scsi_xfer *txs = list_scb->xs;
if (!(txs->flags & SCSI_POLL))
- timeout_add(&list_scb->io_ctx->stimeout,
- (list_scb->io_ctx->timeout * hz)/1000);
+ timeout_add(&list_scb->xs->stimeout,
+ (list_scb->xs->timeout * hz)/1000);
}
- if (xs->error != XS_NOERROR)
+ if (xs->error != CAM_REQ_INPROG)
ahc_set_transaction_status(scb, CAM_CMD_TIMEOUT);
ahc_print_path(ahc, scb);
printf("no longer in timeout, status = %x\n", xs->status);
}
+ /* Translate the CAM status code to a SCSI error code. */
+ switch (xs->error) {
+ case CAM_REQ_INPROG:
+ case CAM_REQ_CMP:
+ xs->error = XS_NOERROR;
+ break;
+ case CAM_BUSY:
+ xs->error = XS_BUSY;
+ break;
+ case CAM_CMD_TIMEOUT:
+ xs->error = XS_TIMEOUT;
+ break;
+ case CAM_BDR_SENT:
+ case CAM_SCSI_BUS_RESET:
+ xs->error = XS_RESET;
+ break;
+ case CAM_SEL_TIMEOUT:
+ xs->error = XS_SELTIMEOUT;
+ break;
+ case CAM_REQUEUE_REQ:
+ scb->flags |= SCB_REQUEUE;
+ xs->error = XS_NOERROR;
+ break;
+ default:
+ xs->error = XS_DRIVER_STUFFUP;
+ break;
+ }
+
+ /* Don't clobber any existing error state */
if (xs->error != XS_NOERROR) {
- /* Don't clobber any existing error state */
+ /* Don't clobber any existing error state */
} else if ((scb->flags & SCB_SENSE) != 0) {
/*
* We performed autosense retrieval.
*
- * Zero the sense data before having
- * the drive fill it. The SCSI spec mandates
- * that any untransferred data should be
- * assumed to be zero. Complete the 'bounce'
- * of sense information through buffers accessible
- * via bus-space by copying it into the clients
- * csio.
+ * Zero any sense not transferred by the
+ * device. The SCSI spec mandates that any
+ * untransferred data should be assumed to be
+ * zero. Complete the 'bounce' of sense information
+ * through buffers accessible via bus-space by
+ * copying it into the clients csio.
*/
memset(&xs->sense, 0, sizeof(struct scsi_sense_data));
memcpy(&xs->sense, ahc_get_sense_buf(ahc, scb),
ahc_le32toh(scb->sg_list->len) & AHC_SG_LEN_MASK);
xs->error = XS_SENSE;
}
-
- if (scb->platform_data->flags & SCB_FREEZE_QUEUE) {
- /* keep negs from happening */
- if (ahc->platform_data->devqueue_blocked[target] > 0) {
- ahc->platform_data->devqueue_blocked[target]--;
- }
- scb->platform_data->flags &= ~SCB_FREEZE_QUEUE;
+ if (scb->flags & SCB_FREEZE_QUEUE) {
+ scb->flags &= ~SCB_FREEZE_QUEUE;
}
- requeue = scb->platform_data->flags & SCB_REQUEUE;
+ ahc_lock(ahc, &s);
ahc_free_scb(ahc, scb);
+ ahc_unlock(ahc, &s);
- if (requeue) {
- /*
- * Re-insert at the front of the private queue to
- * preserve order.
- */
- int s;
- ahc_lock(ahc, &s);
- ahc_list_insert_head(ahc, xs);
- ahc_unlock(ahc, &s);
- } else {
- if ((xs->sc_link->lun == 0) &&
- (xs->flags & SCSI_POLL) &&
- (xs->error == XS_NOERROR))
- ahc_check_tags(ahc, xs);
- xs->flags |= ITSDONE;
- scsi_done(xs);
- }
-
- /*
- * If there are entries in the software queue, try to
- * run the first one. We should be more or less guaranteed
- * to succeed, since we just freed an SCB.
- *
- * NOTE: ahc_action() relies on our calling it with
- * the first entry in the queue.
- */
- if ((xs = ahc->platform_data->sc_xxxq.lh_first) != NULL)
- (void) ahc_action(xs);
+ xs->flags |= ITSDONE;
+ scsi_done(xs);
}
static void
@@ -802,236 +315,82 @@ ahc_minphys(bp)
}
int32_t
-ahc_action(xs)
- struct scsi_xfer *xs;
+ahc_action(struct scsi_xfer *xs)
{
- struct scsi_xfer *first_xs, *next_xs = NULL;
struct ahc_softc *ahc;
struct scb *scb;
struct hardware_scb *hscb;
- struct ahc_initiator_tinfo *tinfo;
- struct ahc_tmode_tstate *tstate;
u_int target_id;
u_int our_id;
- char channel;
- int s, tcl;
- u_int16_t mask;
- int dontqueue = 0, fromqueue = 0;
+ int s;
+ int dontqueue = 0;
SC_DEBUG(xs->sc_link, SDEV_DB3, ("ahc_action\n"));
ahc = (struct ahc_softc *)xs->sc_link->adapter_softc;
- /* must protect the queue */
- ahc_lock(ahc, &s);
-
- if (xs == ahc->platform_data->sc_xxxq.lh_first) {
- /*
- * Called from ahc_done. Calling with the first entry in
- * the queue is really just a way of seeing where we're
- * called from. Now, find the first eligible SCB to send,
- * e.g. one which will be accepted immediately.
- */
- if (ahc->platform_data->queue_blocked) {
- ahc_unlock(ahc, &s);
- return (TRY_AGAIN_LATER);
- }
-
- xs = ahc_first_xs(ahc);
- if (xs == NULL) {
- ahc_unlock(ahc, &s);
- return (TRY_AGAIN_LATER);
- }
-
- next_xs = ahc_list_next(ahc, xs);
- ahc_list_remove(ahc, xs);
- fromqueue = 1;
- goto get_scb;
- }
-
/* determine safety of software queueing */
dontqueue = xs->flags & SCSI_POLL;
- /*
- * If no new requests are accepted, just insert into the
- * private queue to wait for our turn.
- */
- tcl = XS_TCL(xs);
-
- if (ahc->platform_data->queue_blocked ||
- ahc->platform_data->devqueue_blocked[xs->sc_link->target] ||
- (!ahc_istagged_device(ahc, xs, 0) &&
- ahc_pause_index_busy_tcl(ahc, tcl) != SCB_LIST_NULL)) {
- if (dontqueue) {
- ahc_unlock(ahc, &s);
- xs->error = XS_DRIVER_STUFFUP;
- return TRY_AGAIN_LATER;
- }
- ahc_list_insert_tail(ahc, xs);
- ahc_unlock(ahc, &s);
- return SUCCESSFULLY_QUEUED;
- }
-
- first_xs = ahc_first_xs(ahc);
-
- /* determine safety of software queueing */
- dontqueue = xs->flags & SCSI_POLL;
-
- /*
- * Handle situations where there's already entries in the
- * queue.
- */
- if (first_xs != NULL) {
- /*
- * If we can't queue, we have to abort, since
- * we have to preserve order.
- */
- if (dontqueue) {
- ahc_unlock(ahc, &s);
- xs->error = XS_DRIVER_STUFFUP;
- return (TRY_AGAIN_LATER);
- }
-
- /*
- * Swap with the first queue entry.
- */
- ahc_list_insert_tail(ahc, xs);
- xs = first_xs;
- next_xs = ahc_list_next(ahc, xs);
- ahc_list_remove(ahc, xs);
- fromqueue = 1;
- }
-
-get_scb:
-
target_id = xs->sc_link->target;
our_id = SCSI_SCSI_ID(ahc, xs->sc_link);
/*
* get an scb to use.
*/
+ ahc_lock(ahc, &s);
if ((scb = ahc_get_scb(ahc)) == NULL) {
- if (dontqueue) {
- ahc_unlock(ahc, &s);
- xs->error = XS_DRIVER_STUFFUP;
- return (TRY_AGAIN_LATER);
- }
-
- /*
- * If we were pulled off the queue, put ourselves
- * back to where we came from, otherwise tack ourselves
- * onto the end.
- */
- if (fromqueue && next_xs != NULL)
- ahc_list_insert_before(ahc, xs, next_xs);
- else
- ahc_list_insert_tail(ahc, xs);
-
ahc_unlock(ahc, &s);
- return (SUCCESSFULLY_QUEUED);
+ xs->error = XS_DRIVER_STUFFUP;
+ return (TRY_AGAIN_LATER);
}
+ ahc_unlock(ahc, &s);
- tcl = XS_TCL(xs);
-
-#ifdef DIAGNOSTIC
- if (!ahc_istagged_device(ahc, xs, 0) &&
- ahc_pause_index_busy_tcl(ahc, tcl) != SCB_LIST_NULL)
- panic("ahc: queuing for busy target");
-#endif
-
- scb->io_ctx = xs;
hscb = scb->hscb;
- hscb->control = 0;
-
- timeout_set(&xs->stimeout, ahc_timeout, scb);
-
- if (ahc_istagged_device(ahc, xs, 0)){
- hscb->control |= TAG_ENB;
- } else {
- ahc_pause_busy_tcl(ahc, tcl, scb->hscb->tag);
- }
-
- ahc_unlock(ahc, &s);
-
- channel = SCSI_CHANNEL(ahc, xs->sc_link);
- if (ahc->platform_data->inited_channels[channel - 'A'] == 0) {
- if ((channel == 'A' && (ahc->flags & AHC_RESET_BUS_A)) ||
- (channel == 'B' && (ahc->flags & AHC_RESET_BUS_B))) {
- ahc_lock(ahc, &s);
- ahc_reset_channel(ahc, channel, TRUE);
- ahc_unlock(ahc, &s);
- }
- ahc->platform_data->inited_channels[channel - 'A'] = 1;
- }
+ SC_DEBUG(periph, SCSIPI_DB3, ("start scb(%p)\n", scb));
+ scb->xs = xs;
/*
* Put all the arguments for the xfer in the scb
*/
+ hscb->control = 0;
hscb->scsiid = BUILD_SCSIID(ahc, xs->sc_link, target_id, our_id);
- hscb->lun = XS_LUN(xs);
-
- mask = SCB_GET_TARGET_MASK(ahc, scb);
- tinfo = ahc_fetch_transinfo(ahc, SCSI_CHANNEL(ahc, xs->sc_link), our_id,
- target_id, &tstate);
-
- if (ahc->platform_data->inited_targets[target_id] == 0) {
- struct ahc_devinfo devinfo;
-
- ahc_lock(ahc, &s);
- ahc_compile_devinfo(&devinfo, our_id, target_id,
- XS_LUN(xs), SCSI_CHANNEL(ahc, xs->sc_link),
- ROLE_INITIATOR);
- ahc_update_neg_request(ahc, &devinfo, tstate, tinfo,
- /*force*/TRUE);
- ahc->platform_data->inited_targets[target_id] = 1;
- ahc_unlock(ahc, &s);
- }
-
- hscb->scsirate = tinfo->scsirate;
- hscb->scsioffset = tinfo->curr.offset;
- if ((tstate->ultraenb & mask) != 0)
- hscb->control |= ULTRAENB;
-
- if ((tstate->discenable & mask) != 0)
- hscb->control |= DISCENB;
-
- if ((tstate->auto_negotiate & mask) != 0) {
- scb->flags |= SCB_AUTO_NEGOTIATE;
- hscb->control |= MK_MESSAGE;
- }
-
- if (xs->flags & SCSI_RESET) {
+ hscb->lun = xs->sc_link->lun;
+ if (xs->xs_control & XS_CTL_RESET) {
+ hscb->cdb_len = 0;
scb->flags |= SCB_DEVICE_RESET;
hscb->control |= MK_MESSAGE;
- return ahc_execute_scb(scb, NULL, 0);
+ ahc_execute_scb(scb, NULL, 0);
}
+ timeout_set(&xs->stimeout, ahc_timeout, scb);
+
return ahc_setup_data(ahc, xs, scb);
}
int
-ahc_execute_scb(arg, dm_segs, nsegments)
- void *arg;
- bus_dma_segment_t *dm_segs;
- int nsegments;
+ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments)
{
struct scb *scb;
struct scsi_xfer *xs;
struct ahc_softc *ahc;
struct ahc_initiator_tinfo *tinfo;
struct ahc_tmode_tstate *tstate;
+
u_int mask;
- int s;
+ int s, target;
scb = (struct scb *)arg;
- xs = scb->io_ctx;
+ xs = scb->xs;
+ xs->error = CAM_REQ_INPROG;
+ xs->status = 0;
ahc = (struct ahc_softc *)xs->sc_link->adapter_softc;
if (nsegments != 0) {
struct ahc_dma_seg *sg;
bus_dma_segment_t *end_seg;
int op;
-
+
end_seg = dm_segs + nsegments;
/* Copy the segments into our SG list */
@@ -1049,7 +408,7 @@ ahc_execute_scb(arg, dm_segs, nsegments)
/*
* Note where to find the SG entries in bus space.
- * We also set the full residual flag which the
+ * We also set the full residual flag which the
* sequencer will clear as soon as a data transfer
* occurs.
*/
@@ -1060,14 +419,13 @@ ahc_execute_scb(arg, dm_segs, nsegments)
else
op = BUS_DMASYNC_PREWRITE;
- ahc->buffer_dmat = ahc->parent_dmat;
- bus_dmamap_sync(ahc->buffer_dmat, scb->dmamap,
- 0, scb->dmamap->dm_mapsize, op);
+ bus_dmamap_sync(ahc->parent_dmat, scb->dmamap, 0,
+ scb->dmamap->dm_mapsize, op);
sg--;
sg->len |= ahc_htole32(AHC_DMA_LAST_SEG);
- bus_dmamap_sync(ahc->scb_data->sg_dmat, scb->sg_map->sg_dmamap,
+ bus_dmamap_sync(ahc->parent_dmat, scb->sg_map->sg_dmamap,
0, scb->sg_map->sg_dmamap->dm_mapsize,
BUS_DMASYNC_PREWRITE);
@@ -1089,24 +447,14 @@ ahc_execute_scb(arg, dm_segs, nsegments)
* be aborted.
*/
if (xs->flags & ITSDONE) {
-
- if (!ahc_istagged_device(ahc, xs, 0)){
- ahc_pause_unbusy_tcl(ahc, XS_TCL(xs));
- }
-
if (nsegments != 0)
- bus_dmamap_unload(ahc->buffer_dmat, scb->dmamap);
+ bus_dmamap_unload(ahc->parent_dmat, scb->dmamap);
ahc_free_scb(ahc, scb);
ahc_unlock(ahc, &s);
return (COMPLETE);
}
-#ifdef DIAGNOSTIC
- if (scb->sg_count > 255)
- panic("ahc bad sg_count");
-#endif
-
tinfo = ahc_fetch_transinfo(ahc, SCSIID_CHANNEL(ahc, scb->hscb->scsiid),
SCSIID_OUR_ID(scb->hscb->scsiid),
SCSIID_TARGET(ahc, scb->hscb->scsiid),
@@ -1115,34 +463,39 @@ ahc_execute_scb(arg, dm_segs, nsegments)
mask = SCB_GET_TARGET_MASK(ahc, scb);
scb->hscb->scsirate = tinfo->scsirate;
scb->hscb->scsioffset = tinfo->curr.offset;
+
if ((tstate->ultraenb & mask) != 0)
scb->hscb->control |= ULTRAENB;
if ((tstate->discenable & mask) != 0)
- scb->hscb->control |= DISCENB;
+ scb->hscb->control |= DISCENB;
if ((tstate->auto_negotiate & mask) != 0) {
scb->flags |= SCB_AUTO_NEGOTIATE;
scb->hscb->control |= MK_MESSAGE;
}
- bus_dmamap_sync(ahc->scb_data->hscb_dmat, ahc->scb_data->hscb_dmamap,
+ if ((tstate->tagenable & mask) != 0) {
+ switch (xs->cmd->opcode) {
+ case INQUIRY:
+ case TEST_UNIT_READY:
+ case REQUEST_SENSE:
+ /* Don't use tagged i/o on these commands */
+ break;
+ default:
+ scb->hscb->control |= TAG_ENB;
+ break;
+ }
+ }
+
+ bus_dmamap_sync(ahc->parent_dmat, ahc->scb_data->hscb_dmamap,
0, ahc->scb_data->hscb_dmamap->dm_mapsize,
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
LIST_INSERT_HEAD(&ahc->pending_scbs, scb, pending_links);
-#ifdef AHC_DEBUG
- if ((ahc_debug & AHC_SHOWCMDS)) {
- ahc_print_path(ahc, scb);
- printf("opcode 0x%x tag %x len %d flags %x "
- "control %x fpos %u rate %x\n",
- xs->cmdstore.opcode, scb->hscb->tag,
- scb->hscb->cdb_len, scb->flags,
- scb->hscb->control, ahc->qinfifonext,
- scb->hscb->scsirate);
- }
-#endif
+ if (!(xs->flags & SCSI_POLL))
+ timeout_add(&xs->stimeout, (xs->timeout * hz) / 1000);
/*
* We only allow one untagged transaction
@@ -1155,7 +508,7 @@ ahc_execute_scb(arg, dm_segs, nsegments)
* in ahc_done(). XXX smurph
*/
if ((scb->hscb->control & (TARGET_SCB|TAG_ENB)) == 0
- && (ahc->flags & AHC_SCB_BTT) == 0) {
+ && (ahc->flags & AHC_SCB_BTT) == 0) {
struct scb_tailq *untagged_q;
int target_offset;
@@ -1168,26 +521,20 @@ ahc_execute_scb(arg, dm_segs, nsegments)
return (SUCCESSFULLY_QUEUED);
}
}
-
scb->flags |= SCB_ACTIVE;
- if (!(xs->flags & SCSI_POLL))
- timeout_add(&xs->stimeout, (xs->timeout * hz) / 1000);
-
if ((scb->flags & SCB_TARGET_IMMEDIATE) != 0) {
/* Define a mapping from our tag to the SCB. */
ahc->scb_data->scbindex[scb->hscb->tag] = scb;
ahc_pause(ahc);
if ((ahc->flags & AHC_PAGESCBS) == 0)
ahc_outb(ahc, SCBPTR, scb->hscb->tag);
- ahc_outb(ahc, SCB_TAG, scb->hscb->tag);
- ahc_outb(ahc, RETURN_1, CONT_MSG_LOOP);
+ ahc_outb(ahc, TARG_IMMEDIATE_SCB, scb->hscb->tag);
ahc_unpause(ahc);
} else {
ahc_queue_scb(ahc, scb);
}
-
if (!(xs->flags & SCSI_POLL)) {
ahc_unlock(ahc, &s);
return (SUCCESSFULLY_QUEUED);
@@ -1197,6 +544,24 @@ ahc_execute_scb(arg, dm_segs, nsegments)
* If we can't use interrupts, poll for completion
*/
SC_DEBUG(xs->sc_link, SDEV_DB3, ("cmd_poll\n"));
+
+ target = xs->sc_link->target;
+ if (ahc->inited_target[target] == INITED_TARGET_INQUIRYOK) {
+ struct ahc_initiator_tinfo *tinfo;
+ struct ahc_tmode_tstate *tstate;
+ struct ahc_devinfo devinfo;
+
+ ahc_adapter_req_set_xfer_mode(ahc, scb);
+
+ ahc_scb_devinfo(ahc, &devinfo, scb);
+ tinfo = ahc_fetch_transinfo(ahc, devinfo.channel,
+ devinfo.our_scsiid, devinfo.target, &tstate);
+ ahc_update_neg_request(ahc, &devinfo, tstate, tinfo,
+ AHC_NEG_IF_NON_ASYNC);
+
+ ahc->inited_target[target] = INITED_TARGET_MODEOK;
+ }
+
do {
if (ahc_poll(ahc, xs->timeout)) {
if (!(xs->flags & SCSI_SILENT))
@@ -1205,19 +570,21 @@ ahc_execute_scb(arg, dm_segs, nsegments)
break;
}
} while (!(xs->flags & ITSDONE));
+
+ if (ahc->inited_target[target] == INITED_TARGET_START) {
+ if ((xs->cmd->opcode == INQUIRY) && (xs->error == XS_NOERROR))
+ ahc->inited_target[target] = INITED_TARGET_INQUIRYOK;
+ }
+
ahc_unlock(ahc, &s);
return (COMPLETE);
}
int
-ahc_poll(ahc, wait)
- struct ahc_softc *ahc;
- int wait; /* in msec */
+ahc_poll(struct ahc_softc *ahc, int wait)
{
while (--wait) {
DELAY(1000);
- if ((ahc->chip & AHC_PCI) != 0 && (ahc_inb(ahc, ERROR) & PCIERRSTAT) != 0)
- ahc->bus_intr(ahc);
if (ahc_inb(ahc, INTSTAT) & INT_PEND)
break;
}
@@ -1228,50 +595,57 @@ ahc_poll(ahc, wait)
}
ahc_intr((void *)ahc);
-
return (0);
}
int
-ahc_setup_data(ahc, xs, scb)
- struct ahc_softc *ahc;
- struct scsi_xfer *xs;
- struct scb *scb;
+ahc_setup_data(struct ahc_softc *ahc, struct scsi_xfer *xs,
+ struct scb *scb)
{
struct hardware_scb *hscb;
-
+
hscb = scb->hscb;
xs->resid = xs->status = 0;
- xs->error = XS_NOERROR;
+ xs->error = CAM_REQ_INPROG;
hscb->cdb_len = xs->cmdlen;
+ if (hscb->cdb_len > sizeof(hscb->cdb32)) {
+ int s;
+
+ ahc_set_transaction_status(scb, CAM_REQ_INVALID);
+ ahc_lock(ahc, &s);
+ ahc_free_scb(ahc, scb);
+ ahc_unlock(ahc, &s);
+ scsi_done(xs);
+ return (COMPLETE);
+ }
if (hscb->cdb_len > 12) {
- memcpy(hscb->cdb32, xs->cmd,
- hscb->cdb_len);
+ memcpy(hscb->cdb32, xs->cmd, hscb->cdb_len);
scb->flags |= SCB_CDB32_PTR;
} else {
- memcpy(hscb->shared_data.cdb,
- xs->cmd,
- hscb->cdb_len);
+ memcpy(hscb->shared_data.cdb, xs->cmd, hscb->cdb_len);
}
-
+
/* Only use S/G if there is a transfer */
if (xs->datalen) {
int error;
- ahc->buffer_dmat = ahc->parent_dmat;
- error = bus_dmamap_load(ahc->buffer_dmat,
+ error = bus_dmamap_load(ahc->parent_dmat,
scb->dmamap, xs->data,
xs->datalen, NULL,
(xs->flags & SCSI_NOSLEEP) ?
BUS_DMA_NOWAIT : BUS_DMA_WAITOK);
if (error) {
- if (!ahc_istagged_device(ahc, xs, 0)) {
- ahc_pause_unbusy_tcl(ahc, XS_TCL(xs));
- }
+#ifdef AHC_DEBUG
+ printf("%s: in ahc_setup_data(): bus_dmamap_load() "
+ "= %d\n",
+ ahc_name(ahc), error);
+#endif
+ xs->error = XS_BUSY;
+ scsi_done(xs);
return (TRY_AGAIN_LATER); /* XXX fvdl */
- }
+}
error = ahc_execute_scb(scb,
scb->dmamap->dm_segs,
scb->dmamap->dm_nsegs);
@@ -1282,10 +656,7 @@ ahc_setup_data(ahc, xs, scb)
}
void
-ahc_set_recoveryscb(ahc, scb)
- struct ahc_softc *ahc;
- struct scb *scb;
-{
+ahc_set_recoveryscb(struct ahc_softc *ahc, struct scb *scb) {
if ((scb->flags & SCB_RECOVERY_SCB) == 0) {
struct scb *list_scb;
@@ -1293,30 +664,23 @@ ahc_set_recoveryscb(ahc, scb)
scb->flags |= SCB_RECOVERY_SCB;
/*
- * Take all queued, but not sent SCBs out of the equation.
- * Also ensure that no new CCBs are queued to us while we
- * try to fix this problem.
- */
- ahc->platform_data->queue_blocked = 1;
-
- /*
* Go through all of our pending SCBs and remove
* any scheduled timeouts for them. We will reschedule
* them after we've successfully fixed this problem.
*/
LIST_FOREACH(list_scb, &ahc->pending_scbs, pending_links) {
- timeout_del(&list_scb->io_ctx->stimeout);
+ timeout_del(&list_scb->xs->stimeout);
}
}
}
void
-ahc_timeout(arg)
- void *arg;
+ahc_timeout(void *arg)
{
struct scb *scb;
struct ahc_softc *ahc;
- int s, found;
+ int s;
+ int found;
u_int last_phase;
int target;
int lun;
@@ -1324,16 +688,10 @@ ahc_timeout(arg)
char channel;
scb = (struct scb *)arg;
- ahc = (struct ahc_softc *)scb->io_ctx->sc_link->adapter_softc;
+ ahc = (struct ahc_softc *)scb->xs->sc_link->adapter_softc;
ahc_lock(ahc, &s);
- /*
- * Ensure that the card doesn't do anything
- * behind our back. Also make sure that we
- * didn't "just" miss an interrupt that would
- * affect this timeout.
- */
ahc_pause_and_flushwork(ahc);
if ((scb->flags & SCB_ACTIVE) == 0) {
@@ -1351,14 +709,8 @@ ahc_timeout(arg)
ahc_print_path(ahc, scb);
printf("SCB 0x%x - timed out\n", scb->hscb->tag);
-
- /*
- * Take a snapshot of the bus state and print out
- * some information so we can track down driver bugs.
- */
ahc_dump_card_state(ahc);
last_phase = ahc_inb(ahc, LASTPHASE);
-
if (scb->sg_count > 0) {
for (i = 0; i < scb->sg_count; i++) {
printf("sg[%d] - Addr 0x%x : Length %d\n",
@@ -1367,7 +719,6 @@ ahc_timeout(arg)
scb->sg_list[i].len & AHC_SG_LEN_MASK);
}
}
-
if (scb->flags & (SCB_DEVICE_RESET|SCB_ABORT)) {
/*
* Been down this road before.
@@ -1382,7 +733,7 @@ bus_reset:
/*
* If we are a target, transition to bus free and report
* the timeout.
- *
+ *
* The target/initiator that is holding up the bus may not
* be the same as the one that triggered this timeout
* (different commands have different timeout lengths).
@@ -1404,7 +755,7 @@ bus_reset:
u_int active_scb_index;
u_int saved_scbptr;
- bus_dmamap_sync(ahc->scb_data->hscb_dmat,
+ bus_dmamap_sync(ahc->parent_dmat,
ahc->scb_data->hscb_dmamap,
0, ahc->scb_data->hscb_dmamap->dm_mapsize,
BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
@@ -1412,47 +763,47 @@ bus_reset:
saved_scbptr = ahc_inb(ahc, SCBPTR);
active_scb_index = ahc_inb(ahc, SCB_TAG);
- if (last_phase != P_BUSFREE
- && (ahc_inb(ahc, SEQ_FLAGS) & IDENTIFY_SEEN) != 0
+ if ((ahc_inb(ahc, SEQ_FLAGS) & NOT_IDENTIFIED) == 0
&& (active_scb_index < ahc->scb_data->numscbs)) {
struct scb *active_scb;
/*
- * If the active SCB is not from our device,
- * assume that another device is hogging the bus
- * and wait for it's timeout to expire before
- * taking additional action.
- */
+ * If the active SCB is not us, assume that
+ * the active SCB has a longer timeout than
+ * the timedout SCB, and wait for the active
+ * SCB to timeout.
+ */
active_scb = ahc_lookup_scb(ahc, active_scb_index);
if (active_scb != scb) {
u_int newtimeout;
ahc_print_path(ahc, active_scb);
printf("Other SCB Timeout%s",
- (scb->flags & SCB_OTHERTCL_TIMEOUT) != 0
+ (scb->flags & SCB_OTHERTCL_TIMEOUT) != 0
? " again\n" : "\n");
scb->flags |= SCB_OTHERTCL_TIMEOUT;
- newtimeout = MAX(active_scb->io_ctx->timeout,
- scb->io_ctx->timeout);
- timeout_add(&scb->io_ctx->stimeout,
+ newtimeout = MAX(active_scb->xs->timeout,
+ scb->xs->timeout);
+ timeout_add(&scb->xs->stimeout,
(newtimeout * hz) / 1000);
ahc_unpause(ahc);
ahc_unlock(ahc, &s);
return;
- }
+ }
/* It's us */
- if ((scb->hscb->control & TARGET_SCB) != 0) {
+ if ((scb->flags & SCB_TARGET_SCB) != 0) {
/*
* Send back any queued up transactions
* and properly record the error condition.
*/
- ahc_freeze_devq(ahc, scb);
- ahc_set_transaction_status(scb,
- CAM_CMD_TIMEOUT);
- ahc_freeze_scb(scb);
- ahc_done(ahc, scb);
+ ahc_abort_scbs(ahc, SCB_GET_TARGET(ahc, scb),
+ SCB_GET_CHANNEL(ahc, scb),
+ SCB_GET_LUN(scb),
+ scb->hscb->tag,
+ ROLE_TARGET,
+ CAM_CMD_TIMEOUT);
/* Will clear us from the bus */
ahc_restart(ahc);
@@ -1461,22 +812,22 @@ bus_reset:
}
ahc_set_recoveryscb(ahc, active_scb);
- ahc_outb(ahc, MSG_OUT, MSG_BUS_DEV_RESET);
+ ahc_outb(ahc, MSG_OUT, HOST_MSG);
ahc_outb(ahc, SCSISIGO, last_phase|ATNO);
ahc_print_path(ahc, active_scb);
printf("BDR message in message buffer\n");
active_scb->flags |= SCB_DEVICE_RESET;
- timeout_add(&active_scb->io_ctx->stimeout, 2 * hz);
+ timeout_add(&active_scb->xs->stimeout, 2 * hz);
ahc_unpause(ahc);
} else {
int disconnected;
- bus_dmamap_sync(ahc->scb_data->hscb_dmat,
+ bus_dmamap_sync(ahc->parent_dmat,
ahc->scb_data->hscb_dmamap,
0, ahc->scb_data->hscb_dmamap->dm_mapsize,
BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
/* XXX Shouldn't panic. Just punt instead */
- if ((scb->hscb->control & TARGET_SCB) != 0)
+ if ((scb->flags & SCB_TARGET_SCB) != 0)
panic("Timed-out target SCB but bus idle");
if (last_phase != P_BUSFREE
@@ -1489,6 +840,7 @@ bus_reset:
ahc_unlock(ahc, &s);
return;
}
+
if (ahc_search_qinfifo(ahc, target, channel, lun,
scb->hscb->tag, ROLE_INITIATOR,
/*status*/0, SEARCH_COUNT) > 0) {
@@ -1517,8 +869,7 @@ bus_reset:
* an unsolicited reselection occurred.
*/
scb->hscb->control |= MK_MESSAGE|DISCONNECTED;
- scb->flags |= /*SCB_QUEUED_MSG | */
- SCB_DEVICE_RESET;
+ scb->flags |= SCB_DEVICE_RESET;
/*
* Remove any cached copy of this SCB in the
@@ -1546,6 +897,7 @@ bus_reset:
ahc_inb(ahc, SCB_CONTROL)
| MK_MESSAGE);
}
+
/*
* Clear out any entries in the QINFIFO first
* so we are the next SCB for this target
@@ -1562,7 +914,7 @@ bus_reset:
printf("Queuing a BDR SCB\n");
ahc_qinfifo_requeue_tail(ahc, scb);
ahc_outb(ahc, SCBPTR, saved_scbptr);
- timeout_add(&scb->io_ctx->stimeout, 2 * hz);
+ timeout_add(&scb->xs->stimeout, 2 * hz);
ahc_unpause(ahc);
} else {
/* Go "immediatly" to the bus reset */
@@ -1579,29 +931,17 @@ bus_reset:
ahc_unlock(ahc, &s);
}
-void
-ahc_send_async(ahc, channel, target, lun, code, opt_arg)
- struct ahc_softc *ahc;
- char channel;
- u_int target, lun, code;
- void *opt_arg;
-{
- /* Nothing to do here for OpenBSD */
-}
void
-ahc_platform_set_tags(ahc, devinfo, alg)
- struct ahc_softc *ahc;
- struct ahc_devinfo *devinfo;
- ahc_queue_alg alg;
+ahc_platform_set_tags(struct ahc_softc *ahc,
+ struct ahc_devinfo *devinfo, int alg)
{
- struct ahc_initiator_tinfo *tinfo;
struct ahc_tmode_tstate *tstate;
- tinfo = ahc_fetch_transinfo(ahc, devinfo->channel,
- devinfo->our_scsiid,
- devinfo->target,
- &tstate);
+ ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid,
+ devinfo->target, &tstate);
+
+ /* XXXX Need to check quirks before doing this! XXXX */
switch (alg) {
case AHC_QUEUE_BASIC:
@@ -1615,223 +955,109 @@ ahc_platform_set_tags(ahc, devinfo, alg)
}
int
-ahc_platform_alloc(ahc, platform_arg)
- struct ahc_softc *ahc;
- void *platform_arg;
+ahc_platform_alloc(struct ahc_softc *ahc, void *platform_arg)
{
- ahc->platform_data = malloc(sizeof(struct ahc_platform_data), M_DEVBUF,
- M_NOWAIT);
- if (ahc->platform_data == NULL)
- return (ENOMEM);
- bzero(ahc->platform_data, sizeof(struct ahc_platform_data));
-
- /* Just do some initialization... */
- ahc->scb_data = NULL;
- ahc->platform_data->ih = NULL;
- ahc->platform_data->channel_b_primary = FALSE;
+ if (sizeof(struct ahc_platform_data) > 0) {
+ ahc->platform_data = malloc(sizeof(struct ahc_platform_data),
+ M_DEVBUF, M_NOWAIT);
+ if (ahc->platform_data == NULL)
+ return (ENOMEM);
+ bzero(ahc->platform_data, sizeof(struct ahc_platform_data));
+ }
return (0);
}
void
-ahc_platform_free(ahc)
- struct ahc_softc *ahc;
+ahc_platform_free(struct ahc_softc *ahc)
{
- free(ahc->platform_data, M_DEVBUF);
+ if (sizeof(struct ahc_platform_data) > 0)
+ free(ahc->platform_data, M_DEVBUF);
}
int
-ahc_softc_comp(lahc, rahc)
- struct ahc_softc *lahc;
- struct ahc_softc *rahc;
+ahc_softc_comp(struct ahc_softc *lahc, struct ahc_softc *rahc)
{
- /* We don't sort softcs under OpenBSD so report equal always */
return (0);
}
void
-ahc_check_tags(ahc, xs)
- struct ahc_softc *ahc;
- struct scsi_xfer *xs;
+ahc_send_async(struct ahc_softc *ahc, char channel, u_int target, u_int lun,
+ u_int code, void *opt_arg)
{
- struct ahc_devinfo devinfo;
-
- if (xs->sc_link->quirks & SDEV_NOTAGS)
- return;
-
- if (ahc_istagged_device(ahc, xs, 1))
- return;
-
- ahc_compile_devinfo(&devinfo,
- SCSI_SCSI_ID(ahc, xs->sc_link),
- XS_SCSI_ID(xs),
- XS_LUN(xs),
- SCSI_CHANNEL(ahc, xs->sc_link),
- ROLE_INITIATOR);
-
- ahc_set_tags(ahc, &devinfo, AHC_QUEUE_TAGGED);
-
- printf("%s: target %d using tagged queuing\n",
- ahc_name(ahc), XS_SCSI_ID(xs));
-
- if (ahc->scb_data->maxhscbs >= 16 ||
- (ahc->flags & AHC_PAGESCBS)) {
- /* Default to 16 tags */
- xs->sc_link->openings += 14;
- } else {
- /*
- * Default to 4 tags on whimpy
- * cards that don't have much SCB
- * space and can't page. This prevents
- * a single device from hogging all
- * slots. We should really have a better
- * way of providing fairness.
- */
- xs->sc_link->openings += 2;
- }
+ /* Nothing to do here for OpenBSD */
}
-int
-ahc_istagged_device(ahc, xs, nocmdcheck)
- struct ahc_softc *ahc;
- struct scsi_xfer *xs;
- int nocmdcheck;
+void
+ahc_adapter_req_set_xfer_mode(struct ahc_softc *ahc, struct scb *scb)
{
- char channel;
- u_int our_id, target;
+ struct ahc_initiator_tinfo *tinfo;
struct ahc_tmode_tstate *tstate;
+ struct ahc_syncrate *syncrate;
struct ahc_devinfo devinfo;
+ u_int16_t quirks;
+ u_int width, ppr_options, period, offset;
+ int s;
- if (xs->sc_link->quirks & SDEV_NOTAGS)
- return 0;
+ s = splbio();
- /*
- * XXX never do these commands with tags. Should really be
- * in a higher layer.
- */
- if (!nocmdcheck && (xs->cmd->opcode == INQUIRY ||
- xs->cmd->opcode == TEST_UNIT_READY ||
- xs->cmd->opcode == REQUEST_SENSE))
- return 0;
+ ahc_scb_devinfo(ahc, &devinfo, scb);
+ quirks = scb->xs->sc_link->quirks;
+ tinfo = ahc_fetch_transinfo(ahc, devinfo.channel,
+ devinfo.our_scsiid, devinfo.target, &tstate);
- channel = SCSI_CHANNEL(ahc, xs->sc_link);
- our_id = SCSI_SCSI_ID(ahc, xs->sc_link);
- target = XS_SCSI_ID(xs);
- (void)ahc_fetch_transinfo(ahc, channel, our_id, target, &tstate);
+ tstate->discenable |= (ahc->user_discenable & devinfo.target_mask);
- ahc_compile_devinfo(&devinfo, our_id, target, XS_LUN(xs),
- channel, ROLE_INITIATOR);
+ if (quirks & SDEV_NOTAGS)
+ tstate->tagenable &= ~devinfo.target_mask;
+ else if (ahc->user_tagenable & devinfo.target_mask)
+ tstate->tagenable |= devinfo.target_mask;
- return (tstate->tagenable & devinfo.target_mask);
-}
+ if (quirks & SDEV_NOWIDE)
+ width = MSG_EXT_WDTR_BUS_8_BIT;
+ else
+ width = MSG_EXT_WDTR_BUS_16_BIT;
-#if UNUSED
-static void
-ahc_dump_targcmd(cmd)
- struct target_cmd *cmd;
-{
- uint8_t *byte;
- uint8_t *last_byte;
- int i;
-
- byte = &cmd->initiator_channel;
- /* Debugging info for received commands */
- last_byte = &cmd[1].initiator_channel;
-
- i = 0;
- while (byte < last_byte) {
- if (i == 0)
- printf("\t");
- printf("%#x", *byte++);
- i++;
- if (i == 8) {
- printf("\n");
- i = 0;
- } else {
- printf(", ");
- }
- }
-}
-#endif
+ ahc_validate_width(ahc, NULL, &width, ROLE_UNKNOWN);
+ if (width > tinfo->user.width)
+ width = tinfo->user.width;
+ ahc_set_width(ahc, &devinfo, width, AHC_TRANS_GOAL, FALSE);
-#ifndef AHC_INLINES
-/*
- * This is a hack to keep from modifying the main
- * driver code as much as possible. This function
- * does CAM to SCSI api stuff.
- */
-void ahc_set_transaction_status(scb, status)
- struct scb *scb;
- uint32_t status;
-{
- /* don't wipe the error */
- if (scb->io_ctx->error == XS_NOERROR){
- switch (status) {
- case CAM_CMD_TIMEOUT:
- status = XS_TIMEOUT;
- break;
- case CAM_BDR_SENT:
- case CAM_SCSI_BUS_RESET:
- status = XS_RESET;
- break;
- case CAM_UNEXP_BUSFREE:
- case CAM_REQ_TOO_BIG:
- case CAM_REQ_ABORTED:
- case CAM_AUTOSENSE_FAIL:
- case CAM_NO_HBA:
- status = XS_DRIVER_STUFFUP;
- break;
- case CAM_SEL_TIMEOUT:
- status = XS_SELTIMEOUT;
- break;
- case CAM_REQUEUE_REQ:
- scb->platform_data->flags |= SCB_REQUEUE;
- scb->io_ctx->error = XS_NOERROR;
- break;
- case CAM_SCSI_STATUS_ERROR:
- default:
- status = scb->io_ctx->error;
- break;
- }
+ if (quirks & SDEV_NOSYNC) {
+ period = 0;
+ offset = 0;
} else {
- status = scb->io_ctx->error;
+ period = tinfo->user.period;
+ offset = tinfo->user.offset;
}
- scb->io_ctx->error = status;
-}
-void ahc_set_transaction_tag(scb, enabled, type)
- struct scb *scb;
- int enabled;
- u_int type;
-{
- struct scsi_xfer *xs = scb->io_ctx;
- switch (type) {
- case MSG_SIMPLE_TASK:
- case MSG_ORDERED_TASK:
- if (enabled)
- xs->sc_link->quirks &= ~SDEV_NOTAGS;
- else
- xs->sc_link->quirks |= SDEV_NOTAGS;
- break;
- }
-}
+ /* XXX Look at saved INQUIRY flags for PPR capabilities XXX */
+ ppr_options = tinfo->user.ppr_options;
+ /* XXX Other reasons to avoid ppr? XXX */
+ if (width < MSG_EXT_WDTR_BUS_16_BIT)
+ ppr_options = 0;
-void ahc_platform_scb_free(ahc, scb)
- struct ahc_softc *ahc;
- struct scb *scb;
-{
- int s;
+ if ((tstate->discenable & devinfo.target_mask) == 0 ||
+ (tstate->tagenable & devinfo.target_mask) == 0)
+ ppr_options &= ~MSG_EXT_PPR_PROT_IUS;
- ahc_lock(ahc, &s);
+ syncrate = ahc_find_syncrate(ahc, &period, &ppr_options,
+ AHC_SYNCRATE_MAX);
+ ahc_validate_offset(ahc, NULL, syncrate, &offset, width,
+ ROLE_UNKNOWN);
- if ((ahc->flags & AHC_RESOURCE_SHORTAGE) != 0 ||
- (scb->flags & SCB_RECOVERY_SCB) != 0) {
- ahc->flags &= ~AHC_RESOURCE_SHORTAGE;
- ahc->platform_data->queue_blocked = 0;
+ if (offset == 0) {
+ period = 0;
+ ppr_options = 0;
}
- timeout_del(&scb->io_ctx->stimeout);
+ if (ppr_options != 0 && tinfo->user.transport_version >= 3) {
+ tinfo->goal.transport_version = tinfo->user.transport_version;
+ tinfo->curr.transport_version = tinfo->user.transport_version;
+ }
- ahc_unlock(ahc, &s);
+ ahc_set_syncrate(ahc, &devinfo, syncrate, period, offset, ppr_options,
+ AHC_TRANS_GOAL, FALSE);
+
+ splx(s);
}
-#endif
diff --git a/sys/dev/ic/aic7xxx_openbsd.h b/sys/dev/ic/aic7xxx_openbsd.h
index 617845f47c8..bb52f81791d 100644
--- a/sys/dev/ic/aic7xxx_openbsd.h
+++ b/sys/dev/ic/aic7xxx_openbsd.h
@@ -1,3 +1,6 @@
+/* $OpenBSD: aic7xxx_openbsd.h,v 1.9 2003/12/24 22:45:45 krw Exp $ */
+/* $NetBSD: aic7xxx_osm.h,v 1.7 2003/11/02 11:07:44 wiz Exp $ */
+
/*
* OpenBSD platform specific driver option settings, data structures,
* function declarations and includes.
@@ -30,10 +33,12 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: aic7xxx_openbsd.h,v 1.8 2003/10/21 18:58:48 jmc Exp $
+ * //depot/aic7xxx/freebsd/dev/aic7xxx/aic7xxx_osm.h#14 $
*
- * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx_freebsd.h,v 1.12 2001/07/18 21:39:47 gibbs Exp $
- * $OpenBSD: aic7xxx_openbsd.h,v 1.8 2003/10/21 18:58:48 jmc Exp $
+ * $FreeBSD: /repoman/r/ncvs/src/sys/dev/aic7xxx/aic7xxx_osm.h,v 1.20 2002/12/04 22:51:29 scottl Exp $
+ */
+/*
+ * Ported from FreeBSD by Pascal Renauld, Network Storage Solutions, Inc. - April 2003
*/
#ifndef _AIC7XXX_OPENBSD_H_
@@ -42,19 +47,20 @@
#include "pci.h" /* for config options */
#include <sys/param.h>
-#include <sys/systm.h>
#include <sys/kernel.h>
+#include <sys/systm.h>
#include <sys/device.h>
-#include <machine/bus.h>
-#include <machine/intr.h>
-
-#include <dev/pci/pcivar.h>
-
#include <sys/malloc.h>
#include <sys/buf.h>
#include <sys/proc.h>
#include <sys/queue.h>
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+
+#include <machine/bus.h>
+#include <machine/intr.h>
+
#include <scsi/scsi_all.h>
#include <scsi/scsi_message.h>
#include <scsi/scsi_debug.h>
@@ -62,18 +68,15 @@
#include <uvm/uvm_extern.h>
-#define AHC_SHOWSENSE 0x01
-#define AHC_SHOWMISC 0x02
-#define AHC_SHOWCMDS 0x04
+#ifdef CAM_NEW_TRAN_CODE
+#define AHC_NEW_TRAN_SETTINGS
+#endif /* CAM_NEW_TRAN_CODE */
#if NPCI > 0
#define AHC_PCI_CONFIG 1
#endif
-#if 0
-#define AHC_DEBUG AHC_SHOWSENSE | AHC_SHOWMISC | AHC_SHOWCMDS
-extern int ahc_debug;
-#endif
+#define AHC_DEBUG AHC_SHOW_SENSE | AHC_SHOW_MISC | AHC_SHOW_CMDS
#ifdef DEBUG
#define bootverbose 1
@@ -83,138 +86,29 @@ extern int ahc_debug;
/****************************** Platform Macros *******************************/
#define SCSI_IS_SCSIBUS_B(ahc, sc_link) \
- ((sc_link)->scsibus == (ahc)->platform_data->sc_link_b.scsibus)
+ ((sc_link)->scsibus == (ahc)->sc_channel_b.scsibus)
#define SCSI_SCSI_ID(ahc, sc_link) \
(SCSI_IS_SCSIBUS_B(ahc, sc_link) ? ahc->our_id_b : ahc->our_id)
#define SCSI_CHANNEL(ahc, sc_link) \
(SCSI_IS_SCSIBUS_B(ahc, sc_link) ? 'B' : 'A')
#define BUILD_SCSIID(ahc, sc_link, target_id, our_id) \
- ((((target_id) << TID_SHIFT) & TID) | (our_id) \
- | (SCSI_IS_SCSIBUS_B(ahc, sc_link) ? TWIN_CHNLB : 0))
-#define XS_SCSI_ID(xs) \
- ((xs)->sc_link->target)
-#define XS_LUN(xs) \
- ((xs)->sc_link->lun)
-#define XS_TCL(xs) \
- BUILD_TCL(XS_SCSI_ID(xs), XS_LUN(xs))
+ ((((target_id) << TID_SHIFT) & TID) | (our_id))
#ifndef offsetof
#define offsetof(type, member) ((size_t)(&((type *)0)->member))
#endif
-
-/* COMPAT CAM to XS stuff */
-#define CAM_DIR_IN SCSI_DATA_IN
-#define AC_TRANSFER_NEG 0
-#define AC_SENT_BDR 0
-#define AC_BUS_RESET 0
-#define CAM_BUS_WILDCARD ((int)~0)
-#define CAM_TARGET_WILDCARD ((int)~0)
-#define CAM_LUN_WILDCARD ((int)~0)
-
-/* SPI-3 definitions */
-#ifndef MSG_SIMPLE_TASK
-#define MSG_SIMPLE_TASK MSG_SIMPLE_Q_TAG
-#endif
-#ifndef MSG_ORDERED_TASK
-#define MSG_ORDERED_TASK MSG_ORDERED_Q_TAG
-#endif
-
-/* FreeBSD to OpenBSD message defs */
-#define MSG_EXT_PPR_QAS_REQ MSG_EXT_PPR_PROT_QAS
-#define MSG_EXT_PPR_DT_REQ MSG_EXT_PPR_PROT_DT
-#define MSG_EXT_PPR_IU_REQ MSG_EXT_PPR_PROT_IUS
-
-/* FreeBSD bus_space defines */
-#define BUS_SPACE_MAXSIZE_24BIT 0xFFFFFF
-#define BUS_SPACE_MAXSIZE_32BIT 0xFFFFFFFF
-#define BUS_SPACE_MAXSIZE (64 * 1024) /* Maximum supported size */
-#define BUS_SPACE_MAXADDR_24BIT 0xFFFFFF
-#define BUS_SPACE_MAXADDR_32BIT 0xFFFFFFFF
-#define BUS_SPACE_MAXADDR 0xFFFFFFFF
-
-/* CAM Status field values (From FreeBSD cam.h 1.10 */
-typedef enum {
- CAM_REQ_INPROG, /* CCB request is in progress */
- CAM_REQ_CMP, /* CCB request completed without error */
- CAM_REQ_ABORTED, /* CCB request aborted by the host */
- CAM_UA_ABORT, /* Unable to abort CCB request */
- CAM_REQ_CMP_ERR, /* CCB request completed with an error */
- CAM_BUSY, /* CAM subsystem is busy */
- CAM_REQ_INVALID, /* CCB request was invalid */
- CAM_PATH_INVALID, /* Supplied Path ID is invalid */
- CAM_DEV_NOT_THERE, /* SCSI Device Not Installed/there */
- CAM_UA_TERMIO, /* Unable to terminate I/O CCB request */
- CAM_SEL_TIMEOUT, /* Target Selection Timeout */
- CAM_CMD_TIMEOUT, /* Command timeout */
- CAM_SCSI_STATUS_ERROR, /* SCSI error, look at error code in CCB */
- CAM_MSG_REJECT_REC, /* Message Reject Received */
- CAM_SCSI_BUS_RESET, /* SCSI Bus Reset Sent/Received */
- CAM_UNCOR_PARITY, /* Uncorrectable parity error occurred */
- CAM_AUTOSENSE_FAIL = 0x10,/* Autosense: request sense cmd fail */
- CAM_NO_HBA, /* No HBA Detected error */
- CAM_DATA_RUN_ERR, /* Data Overrun error */
- CAM_UNEXP_BUSFREE, /* Unexpected Bus Free */
- CAM_SEQUENCE_FAIL, /* Target Bus Phase Sequence Failure */
- CAM_CCB_LEN_ERR, /* CCB length supplied is inadequate */
- CAM_PROVIDE_FAIL, /* Unable to provide requested capability */
- CAM_BDR_SENT, /* A SCSI BDR msg was sent to target */
- CAM_REQ_TERMIO, /* CCB request terminated by the host */
- CAM_UNREC_HBA_ERROR, /* Unrecoverable Host Bus Adapter Error */
- CAM_REQ_TOO_BIG, /* The request was too large for this host */
- CAM_REQUEUE_REQ, /*
- * This request should be requeued to preserve
- * transaction ordering. This typically occurs
- * when the SIM recognizes an error that should
- * freeze the queue and must place additional
- * requests for the target at the sim level
- * back into the XPT queue.
- */
- CAM_IDE = 0x33, /* Initiator Detected Error */
- CAM_RESRC_UNAVAIL, /* Resource Unavailable */
- CAM_UNACKED_EVENT, /* Unacknowledged Event by Host */
- CAM_MESSAGE_RECV, /* Message Received in Host Target Mode */
- CAM_INVALID_CDB, /* Invalid CDB received in Host Target Mode */
- CAM_LUN_INVALID, /* Lun supplied is invalid */
- CAM_TID_INVALID, /* Target ID supplied is invalid */
- CAM_FUNC_NOTAVAIL, /* The requested function is not available */
- CAM_NO_NEXUS, /* Nexus is not established */
- CAM_IID_INVALID, /* The initiator ID is invalid */
- CAM_CDB_RECVD, /* The SCSI CDB has been received */
- CAM_LUN_ALRDY_ENA, /* The LUN is already enabled for target mode */
- CAM_SCSI_BUSY, /* SCSI Bus Busy */
-
- CAM_DEV_QFRZN = 0x40, /* The DEV queue is frozen w/this err */
-
- /* Autosense data valid for target */
- CAM_AUTOSNS_VALID = 0x80,
- CAM_RELEASE_SIMQ = 0x100,/* SIM ready to take more commands */
- CAM_SIM_QUEUED = 0x200,/* SIM has this command in it's queue */
-
- CAM_STATUS_MASK = 0x3F, /* Mask bits for just the status # */
-
- /* Target Specific Adjunct Status */
- CAM_SENT_SENSE = 0x40000000 /* sent sense with status */
-} cam_status;
-
-/* FreeBSD to OpenBSD status defs */
-#define SCSI_STATUS_CHECK_COND SCSI_CHECK
-#define SCSI_STATUS_CMD_TERMINATED SCSI_TERMINATED
-#define SCSI_STATUS_OK SCSI_OK
-#define SCSI_REV_2 SC_SCSI_2
-
/************************* Forward Declarations *******************************/
typedef struct pci_attach_args * ahc_dev_softc_t;
-typedef struct scsi_xfer * ahc_io_ctx_t;
/***************************** Bus Space/DMA **********************************/
/* XXX Need to update Bus DMA for partial map syncs */
-#define ahc_dmamap_sync(ahc, dma_tag, dmamap, offset, len, op) \
+#define ahc_dmamap_sync(ahc, dma_tag, dmamap, offset, len, op) \
bus_dmamap_sync(dma_tag, dmamap, offset, len, op)
/************************ Tunable Driver Parameters **************************/
/*
- * The number of dma segments supported. The sequencer can handle any number
+ * The number of DMA segments supported. The sequencer can handle any number
* of physically contiguous S/G entrys. To reduce the driver's memory
* consumption, we limit the number supported to be sufficient to handle
* the largest mapping supported by the kernel, MAXPHYS. Assuming the
@@ -227,49 +121,16 @@ typedef struct scsi_xfer * ahc_io_ctx_t;
*/
#define AHC_NSEG (roundup(btoc(MAXPHYS) + 1, 16))
-/* This driver does NOT supports target mode */
-#ifdef AHC_TARGET_MODE
-#undef AHC_TARGET_MODE
-#endif
+/* This driver supports target mode */
+//#define AHC_TARGET_MODE 1
-/***************************** Core Includes **********************************/
-#include <dev/ic/aic7xxx.h>
+#include <dev/ic/aic7xxxvar.h>
/************************** Softc/SCB Platform Data ***************************/
struct ahc_platform_data {
- bus_dma_segment_t pshared_data_seg;
- int pshared_data_nseg;
- int pshared_data_size;
-#define shared_data_seg platform_data->pshared_data_seg
-#define shared_data_nseg platform_data->pshared_data_nseg
-#define shared_data_size platform_data->pshared_data_size
- /*
- * Hooks into the XPT.
- */
- struct scsi_link sc_link;
- /* Second bus for Twin channel cards */
- struct scsi_link sc_link_b;
-
- void *ih;
- int channel_b_primary;
-
- /* queue management */
- int queue_blocked;
- u_int16_t devqueue_blocked[AHC_NUM_TARGETS];
- LIST_HEAD(, scsi_xfer) sc_xxxq; /* XXX software request queue */
- struct scsi_xfer *sc_xxxqlast; /* last entry in queue */
-
- u_int8_t inited_targets[AHC_NUM_TARGETS];
- u_int8_t inited_channels[2];
};
-typedef enum {
- SCB_FREEZE_QUEUE = 0x0001,
- SCB_REQUEUE = 0x0002
-} scb_pflag;
-
struct scb_platform_data {
- scb_pflag flags;
};
/*
@@ -295,6 +156,37 @@ struct scb_platform_data {
#define ahc_le32toh(x) letoh32(x)
#define ahc_le64toh(x) letoh64(x)
+/************************** Timer DataStructures ******************************/
+typedef struct timeout ahc_timer_t;
+
+/***************************** Core Includes **********************************/
+#if AHC_REG_PRETTY_PRINT
+#define AIC_DEBUG_REGISTERS 1
+#else
+#define AIC_DEBUG_REGISTERS 0
+#endif
+
+/***************************** Timer Facilities *******************************/
+void ahc_timeout(void*);
+
+#define ahc_timer_init callout_init
+#define ahc_timer_stop callout_stop
+
+static __inline void
+ahc_timer_reset(ahc_timer_t *timer, u_int usec, ahc_callback_t *func, void *arg)
+{
+ callout_reset(timer, (usec * hz)/1000000, func, arg);
+}
+
+static __inline void
+ahc_scb_timer_reset(struct scb *scb, u_int usec)
+{
+ if (!(scb->xs->xs_control & XS_CTL_POLL)) {
+ callout_reset(&scb->xs->xs_callout,
+ (usec * hz)/1000000, ahc_timeout, scb);
+ }
+}
+
/*************************** Device Access ************************************/
#define ahc_inb(ahc, port) \
bus_space_read_1((ahc)->tag, (ahc)->bsh, port)
@@ -308,12 +200,10 @@ struct scb_platform_data {
#define ahc_insb(ahc, port, valp, count) \
bus_space_read_multi_1((ahc)->tag, (ahc)->bsh, port, valp, count)
-
static __inline void ahc_flush_device_writes(struct ahc_softc *);
static __inline void
-ahc_flush_device_writes(ahc)
- struct ahc_softc *ahc;
+ahc_flush_device_writes(struct ahc_softc *ahc)
{
/* XXX Is this sufficient for all architectures??? */
ahc_inb(ahc, INTSTAT);
@@ -321,292 +211,192 @@ ahc_flush_device_writes(ahc)
/**************************** Locking Primitives ******************************/
/* Lock protecting internal data structures */
-#ifdef AHC_INLINES
static __inline void ahc_lockinit(struct ahc_softc *);
-static __inline void ahc_lock(struct ahc_softc *, int *flags);
-static __inline void ahc_unlock(struct ahc_softc *, int *flags);
+static __inline void ahc_lock(struct ahc_softc *, int *);
+static __inline void ahc_unlock(struct ahc_softc *, int *);
/* Lock held during command completion to the upper layer */
static __inline void ahc_done_lockinit(struct ahc_softc *);
-static __inline void ahc_done_lock(struct ahc_softc *, int *flags);
-static __inline void ahc_done_unlock(struct ahc_softc *, int *flags);
+static __inline void ahc_done_lock(struct ahc_softc *, int *);
+static __inline void ahc_done_unlock(struct ahc_softc *, int *);
+
+/* Lock held during ahc_list manipulation and ahc softc frees */
+static __inline void ahc_list_lockinit(void);
+static __inline void ahc_list_lock(int *);
+static __inline void ahc_list_unlock(int *);
static __inline void
-ahc_lockinit(ahc)
- struct ahc_softc *ahc;
+ahc_lockinit(struct ahc_softc *ahc)
{
- /* Nothing to do here for OpenBSD */
}
static __inline void
-ahc_lock(ahc, flags)
- struct ahc_softc *ahc;
- int *flags;
+ahc_lock(struct ahc_softc *ahc, int *flags)
{
*flags = splbio();
}
static __inline void
-ahc_unlock(ahc, flags)
- struct ahc_softc *ahc;
- int *flags;
+ahc_unlock(struct ahc_softc *ahc, int *flags)
{
splx(*flags);
}
/* Lock held during command completion to the upper layer */
static __inline void
-ahc_done_lockinit(ahc)
- struct ahc_softc *ahc;
+ahc_done_lockinit(struct ahc_softc *ahc)
{
- /* Nothing to do here for OpenBSD */
}
static __inline void
-ahc_done_lock(ahc, flags)
- struct ahc_softc *ahc;
- int *flags;
+ahc_done_lock(struct ahc_softc *ahc, int *flags)
{
- /* Nothing to do here for OpenBSD */
}
static __inline void
-ahc_done_unlock(ahc, flags)
- struct ahc_softc *ahc;
- int *flags;
+ahc_done_unlock(struct ahc_softc *ahc, int *flags)
{
- /* Nothing to do here for OpenBSD */
}
-#else
-
-#define ahc_lockinit(ahc);
-#define ahc_lock(ahc, flags) *(flags) = splbio()
-#define ahc_unlock(ahc, flags) splx(*(flags))
-#define ahc_done_lockinit(ahc);
-#define ahc_done_lock(ahc, flags);
-#define ahc_done_unlock(ahc, flags);
+/* Lock held during ahc_list manipulation and ahc softc frees */
+static __inline void
+ahc_list_lockinit()
+{
+}
-#endif
+static __inline void
+ahc_list_lock(int *flags)
+{
+}
+static __inline void
+ahc_list_unlock(int *flags)
+{
+}
/****************************** OS Primitives *********************************/
-#define ahc_delay delay
+#define ahc_delay DELAY
/************************** Transaction Operations ****************************/
-
-#ifdef AHC_INLINES
static __inline void ahc_set_transaction_status(struct scb *, uint32_t);
-static __inline void ahc_set_transaction_tag(struct scb *, int, u_int);
-static __inline void ahc_platform_scb_free(struct ahc_softc *ahc,
- struct scb *scb);
-#else
-void ahc_set_transaction_status(struct scb *, uint32_t);
-void ahc_set_transaction_tag(struct scb *, int, u_int);
-void ahc_platform_scb_free(struct ahc_softc *ahc,
- struct scb *scb);
-#endif
-
static __inline void ahc_set_scsi_status(struct scb *, uint32_t);
static __inline uint32_t ahc_get_transaction_status(struct scb *);
static __inline uint32_t ahc_get_scsi_status(struct scb *);
+static __inline void ahc_set_transaction_tag(struct scb *, int, u_int);
static __inline u_long ahc_get_transfer_length(struct scb *);
static __inline int ahc_get_transfer_dir(struct scb *);
static __inline void ahc_set_residual(struct scb *, u_long);
static __inline void ahc_set_sense_residual(struct scb *, u_long);
static __inline u_long ahc_get_residual(struct scb *);
static __inline int ahc_perform_autosense(struct scb *);
-static __inline uint32_t ahc_get_sense_bufsize(struct ahc_softc*, struct scb*);
-static __inline void ahc_freeze_scb(struct scb *scb);
+static __inline uint32_t ahc_get_sense_bufsize(struct ahc_softc *,
+ struct scb *);
+static __inline void ahc_freeze_scb(struct scb *);
static __inline void ahc_platform_freeze_devq(struct ahc_softc *, struct scb *);
-static __inline int ahc_platform_abort_scbs(struct ahc_softc *ahc, int target,
- char channel, int lun, u_int tag,
- role_t role, uint32_t status);
-/*
- * This is a hack to keep from modifying the main
- * driver code as much as possible. This function
- * does CAM to SCSI api stuff.
- */
-#ifdef AHC_INLINES
+static __inline int ahc_platform_abort_scbs(struct ahc_softc *, int, char,
+ int, u_int, role_t, uint32_t);
+
static __inline
-void ahc_set_transaction_status(scb, status)
- struct scb *scb;
- uint32_t status;
-{
- /* don't wipe the error */
- if (scb->io_ctx->error == XS_NOERROR){
- switch (status) {
- case CAM_CMD_TIMEOUT:
- status = XS_TIMEOUT;
- break;
- case CAM_BDR_SENT:
- case CAM_SCSI_BUS_RESET:
- status = XS_RESET;
- break;
- case CAM_UNEXP_BUSFREE:
- case CAM_REQ_TOO_BIG:
- case CAM_REQ_ABORTED:
- case CAM_AUTOSENSE_FAIL:
- case CAM_NO_HBA:
- status = XS_DRIVER_STUFFUP;
- break;
- case CAM_SEL_TIMEOUT:
- status = XS_SELTIMEOUT;
- break;
- case CAM_REQUEUE_REQ:
- scb->platform_data->flags |= SCB_REQUEUE;
- scb->io_ctx->error = XS_NOERROR;
- break;
- case CAM_SCSI_STATUS_ERROR:
- default:
- status = scb->io_ctx->error;
- break;
- }
- } else {
- status = scb->io_ctx->error;
- }
- scb->io_ctx->error = status;
+void ahc_set_transaction_status(struct scb *scb, uint32_t status)
+{
+ scb->xs->error = status;
}
-#endif
+
static __inline
-void ahc_set_scsi_status(scb, status)
- struct scb *scb;
- uint32_t status;
+void ahc_set_scsi_status(struct scb *scb, uint32_t status)
{
- scb->io_ctx->status = status;
+ scb->xs->status = status;
}
-/*
- * This is a hack to keep from modifying the main
- * driver code as much as possible.
- * This function ONLY needs to return weather
- * a scsi_xfer is in progress or not. XXX smurph
- */
static __inline
-uint32_t ahc_get_transaction_status(scb)
- struct scb *scb;
+uint32_t ahc_get_transaction_status(struct scb *scb)
{
- return (scb->io_ctx->flags & ITSDONE ? CAM_REQ_CMP : CAM_REQ_INPROG);
+ if (scb->xs->flags & ITSDONE)
+ return CAM_REQ_CMP;
+ else
+ return scb->xs->error;
}
static __inline
-uint32_t ahc_get_scsi_status(scb)
- struct scb *scb;
+uint32_t ahc_get_scsi_status(struct scb *scb)
{
- return (scb->io_ctx->status);
+ return (scb->xs->status);
}
-#ifdef AHC_INLINE
static __inline
-void ahc_set_transaction_tag(scb, enabled, type)
- struct scb *scb;
- int enabled;
- u_int type;
-{
- struct scsi_xfer *xs = scb->io_ctx;
- switch (type) {
- case MSG_SIMPLE_TASK:
- if (enabled)
- xs->sc_link->quirks &= ~SDEV_NOTAGS;
- else
- xs->sc_link->quirks |= SDEV_NOTAGS;
- break;
- }
+void ahc_set_transaction_tag(struct scb *scb, int enabled, u_int type)
+{
}
-#endif
+
static __inline
-u_long ahc_get_transfer_length(scb)
- struct scb *scb;
+u_long ahc_get_transfer_length(struct scb *scb)
{
- return (scb->io_ctx->datalen);
+ return (scb->xs->datalen);
}
static __inline
-int ahc_get_transfer_dir(scb)
- struct scb *scb;
+int ahc_get_transfer_dir(struct scb *scb)
{
- return (scb->io_ctx->flags & (SCSI_DATA_IN | SCSI_DATA_OUT));
+ return (scb->xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT));
}
static __inline
-void ahc_set_residual(scb, resid)
- struct scb *scb;
- u_long resid;
+void ahc_set_residual(struct scb *scb, u_long resid)
{
- scb->io_ctx->resid = resid;
+ scb->xs->resid = resid;
}
static __inline
-void ahc_set_sense_residual(scb, resid)
- struct scb *scb;
- u_long resid;
+void ahc_set_sense_residual(struct scb *scb, u_long resid)
{
- scb->io_ctx->resid = resid;
+ scb->xs->resid = resid;
}
static __inline
-u_long ahc_get_residual(scb)
- struct scb *scb;
+u_long ahc_get_residual(struct scb *scb)
{
- return (scb->io_ctx->resid);
+ return (scb->xs->resid);
}
static __inline
-int ahc_perform_autosense(scb)
- struct scb *scb;
+int ahc_perform_autosense(struct scb *scb)
{
/* Return true for OpenBSD */
return (1);
}
static __inline uint32_t
-ahc_get_sense_bufsize(ahc, scb)
- struct ahc_softc *ahc;
- struct scb *scb;
+ahc_get_sense_bufsize(struct ahc_softc *ahc, struct scb *scb)
{
return (sizeof(struct scsi_sense_data));
}
static __inline void
-ahc_freeze_scb(scb)
- struct scb *scb;
+ahc_freeze_scb(struct scb *scb)
{
- struct scsi_xfer *xs = scb->io_ctx;
- struct ahc_softc *ahc = (struct ahc_softc *)xs->sc_link->adapter_softc;
+ struct scsi_xfer *xs = scb->xs;
int target;
target = xs->sc_link->target;
- if (!(scb->platform_data->flags & SCB_FREEZE_QUEUE)) {
- ahc->platform_data->devqueue_blocked[target]++;
- scb->platform_data->flags |= SCB_FREEZE_QUEUE;
+ if (!(scb->flags & SCB_FREEZE_QUEUE)) {
+ scb->flags |= SCB_FREEZE_QUEUE;
}
}
static __inline void
-ahc_platform_freeze_devq(ahc, scb)
- struct ahc_softc *ahc;
- struct scb *scb;
+ahc_platform_freeze_devq(struct ahc_softc *ahc, struct scb *scb)
{
- /* Nothing to do here for OpenBSD */
}
static __inline int
-ahc_platform_abort_scbs(ahc, target, channel, lun, tag, role, status)
- struct ahc_softc *ahc;
- int target, lun;
- char channel;
- u_int tag;
- role_t role;
- uint32_t status;
+ahc_platform_abort_scbs(struct ahc_softc *ahc, int target,
+ char channel, int lun, u_int tag,
+ role_t role, uint32_t status)
{
- /* Nothing to do here for OpenBSD */
return (0);
}
-#ifdef AHC_INLINE
static __inline void
-ahc_platform_scb_free(ahc, scb)
- struct ahc_softc *ahc;
- struct scb *scb;
+ahc_platform_scb_free(struct ahc_softc *ahc, struct scb *scb)
{
int s;
@@ -615,247 +405,110 @@ ahc_platform_scb_free(ahc, scb)
if ((ahc->flags & AHC_RESOURCE_SHORTAGE) != 0 ||
(scb->flags & SCB_RECOVERY_SCB) != 0) {
ahc->flags &= ~AHC_RESOURCE_SHORTAGE;
- ahc->platform_data->queue_blocked = 0;
}
- timeout_del(&scb->io_ctx->stimeout);
+ timeout_del(&scb->xs->stimeout);
ahc_unlock(ahc, &s);
}
-#endif
/********************************** PCI ***************************************/
#ifdef AHC_PCI_CONFIG
-int ahc_pci_map_registers(struct ahc_softc *ahc);
-int ahc_pci_map_int(struct ahc_softc *ahc);
-
-typedef enum
-{
- AHC_POWER_STATE_D0,
- AHC_POWER_STATE_D1,
- AHC_POWER_STATE_D2,
- AHC_POWER_STATE_D3
-} ahc_power_state;
-
-void ahc_power_state_change(struct ahc_softc *ahc,
- ahc_power_state new_state);
-
-static __inline uint32_t ahc_pci_read_config(ahc_dev_softc_t pci,
- int reg, int width);
-static __inline void ahc_pci_write_config(ahc_dev_softc_t pci,
- int reg, uint32_t value,
- int width);
-static __inline u_int ahc_get_pci_function(ahc_dev_softc_t);
-static __inline u_int ahc_get_pci_slot(ahc_dev_softc_t);
-static __inline u_int ahc_get_pci_bus(ahc_dev_softc_t);
+static __inline uint32_t ahc_pci_read_config(ahc_dev_softc_t, int, int);
+static __inline void ahc_pci_write_config(ahc_dev_softc_t, int, uint32_t,
+ int);
+static __inline int ahc_get_pci_function(ahc_dev_softc_t);
+static __inline int ahc_get_pci_slot(ahc_dev_softc_t);
+static __inline int ahc_get_pci_bus(ahc_dev_softc_t);
+int ahc_pci_map_registers(struct ahc_softc *);
+int ahc_pci_map_int(struct ahc_softc *);
static __inline uint32_t
-ahc_pci_read_config(pa, reg, width)
- ahc_dev_softc_t pa;
- int reg, width;
+ahc_pci_read_config(ahc_dev_softc_t pci, int reg, int width)
{
- return (pci_conf_read(pa->pa_pc, pa->pa_tag, reg));
+ return (pci_conf_read(pci->pa_pc, pci->pa_tag, reg));
}
static __inline void
-ahc_pci_write_config(pa, reg, value, width)
- ahc_dev_softc_t pa;
- uint32_t value;
- int reg, width;
+ahc_pci_write_config(ahc_dev_softc_t pci, int reg, uint32_t value, int width)
{
- pci_conf_write(pa->pa_pc, pa->pa_tag, reg, value);
+ pci_conf_write(pci->pa_pc, pci->pa_tag, reg, value);
}
-static __inline u_int
-ahc_get_pci_function(pa)
- ahc_dev_softc_t pa;
+static __inline int
+ahc_get_pci_function(ahc_dev_softc_t pci)
{
- return (pa->pa_function);
+ return (pci->pa_function);
}
-static __inline u_int
-ahc_get_pci_slot(pa)
- ahc_dev_softc_t pa;
+static __inline int
+ahc_get_pci_slot(ahc_dev_softc_t pci)
{
- return (pa->pa_device);
+ return (pci->pa_device);
}
-static __inline u_int
-ahc_get_pci_bus(pa)
- ahc_dev_softc_t pa;
+static __inline int
+ahc_get_pci_bus(ahc_dev_softc_t pci)
{
- return (pa->pa_bus);
+ return (pci->pa_bus);
}
-#endif
+typedef enum
+{
+ AHC_POWER_STATE_D0,
+ AHC_POWER_STATE_D1,
+ AHC_POWER_STATE_D2,
+ AHC_POWER_STATE_D3
+} ahc_power_state;
+
+void ahc_power_state_change(struct ahc_softc *, ahc_power_state);
+#endif
/******************************** VL/EISA *************************************/
-int aic7770_map_registers(struct ahc_softc *ahc);
-int aic7770_map_int(struct ahc_softc *ahc, int irq);
+int aic7770_map_registers(struct ahc_softc *, u_int);
+int aic7770_map_int(struct ahc_softc *, int);
/********************************* Debug **************************************/
-static __inline void ahc_print_path(struct ahc_softc *, struct scb *);
-static __inline void ahc_platform_dump_card_state(struct ahc_softc *ahc);
+static __inline void ahc_print_path(struct ahc_softc *, struct scb *);
+static __inline void ahc_platform_dump_card_state(struct ahc_softc *);
static __inline void
-ahc_print_path(ahc, scb)
- struct ahc_softc *ahc;
- struct scb *scb;
+ahc_print_path(struct ahc_softc *ahc, struct scb *scb)
{
- sc_print_addr(scb->io_ctx->sc_link);
+ sc_print_addr(scb->xs->sc_link);
}
static __inline void
-ahc_platform_dump_card_state(ahc)
- struct ahc_softc *ahc;
+ahc_platform_dump_card_state(struct ahc_softc *ahc)
{
/* Nothing to do here for OpenBSD */
printf("FEATURES = 0x%x, FLAGS = 0x%x, CHIP = 0x%x BUGS =0x%x\n",
ahc->features, ahc->flags, ahc->chip, ahc->bugs);
}
/**************************** Transfer Settings *******************************/
-void ahc_notify_xfer_settings_change(struct ahc_softc *,
- struct ahc_devinfo *);
-void ahc_platform_set_tags(struct ahc_softc *, struct ahc_devinfo *,
- ahc_queue_alg);
+void ahc_notify_xfer_settings_change(struct ahc_softc *,
+ struct ahc_devinfo *);
+void ahc_platform_set_tags(struct ahc_softc *, struct ahc_devinfo *, int);
/************************* Initialization/Teardown ****************************/
-int ahc_platform_alloc(struct ahc_softc *ahc, void *platform_arg);
-void ahc_platform_free(struct ahc_softc *ahc);
-int ahc_attach(struct ahc_softc *);
-int ahc_softc_comp(struct ahc_softc *lahc, struct ahc_softc *rahc);
+int ahc_platform_alloc(struct ahc_softc *, void *);
+void ahc_platform_free(struct ahc_softc *);
+int ahc_map_int(struct ahc_softc *);
+int ahc_attach(struct ahc_softc *);
+int ahc_softc_comp(struct ahc_softc *, struct ahc_softc *);
+int ahc_detach(struct device *, int);
/****************************** Interrupts ************************************/
int ahc_platform_intr(void *);
-static __inline void ahc_platform_flushwork(struct ahc_softc *ahc);
-
+static __inline void ahc_platform_flushwork(struct ahc_softc *);
static __inline void
-ahc_platform_flushwork(ahc)
- struct ahc_softc *ahc;
+ahc_platform_flushwork(struct ahc_softc *ahc)
{
- /* Nothing to do here for OpenBSD */
}
/************************ Misc Function Declarations **************************/
-void ahc_done(struct ahc_softc *ahc, struct scb *scb);
-void ahc_send_async(struct ahc_softc *, char /*channel*/,
- u_int /*target*/, u_int /*lun*/, u_int, void *arg);
-
-int ahc_createdmamem(struct ahc_softc *ahc, bus_dma_tag_t dmat,
- int size, bus_dmamap_t *mapp, caddr_t *vaddr,
- bus_addr_t *baddr, bus_dma_segment_t *segs,
- int *nseg, const char *what);
-void ahc_freedmamem(bus_dma_tag_t tag, int size,
- bus_dmamap_t map, caddr_t vaddr,
- bus_dma_segment_t *seg, int nseg);
-void ahc_force_neg(struct ahc_softc *ahc);
-
-/*
- * Routines to manage a scsi_xfer into the software queue.
- * We overload xs->free_list to to ensure we don't run into a queue
- * resource shortage, and keep a pointer to the last entry around
- * to make insertion O(C).
- */
-static __inline void ahc_list_insert_before(struct ahc_softc *ahc,
- struct scsi_xfer *xs,
- struct scsi_xfer *next_xs);
-static __inline void ahc_list_insert_head(struct ahc_softc *ahc,
- struct scsi_xfer *xs);
-static __inline void ahc_list_insert_tail(struct ahc_softc *ahc,
- struct scsi_xfer *xs);
-static __inline void ahc_list_remove(struct ahc_softc *ahc,
- struct scsi_xfer *xs);
-static __inline struct scsi_xfer *ahc_list_next(struct ahc_softc *ahc,
- struct scsi_xfer *xs);
-static __inline struct scsi_xfer *ahc_first_xs(struct ahc_softc *);
-
-static __inline void
-ahc_list_insert_before(ahc, xs, next_xs)
- struct ahc_softc *ahc;
- struct scsi_xfer *xs;
- struct scsi_xfer *next_xs;
-{
- LIST_INSERT_BEFORE(xs, next_xs, free_list);
-
-}
+void ahc_done(struct ahc_softc *, struct scb *);
+void ahc_send_async(struct ahc_softc *, char, u_int, u_int, ac_code,
+ void *);
-static __inline void
-ahc_list_insert_head(ahc, xs)
- struct ahc_softc *ahc;
- struct scsi_xfer *xs;
-{
- if (ahc->platform_data->sc_xxxq.lh_first == NULL)
- ahc->platform_data->sc_xxxqlast = xs;
- LIST_INSERT_HEAD(&ahc->platform_data->sc_xxxq, xs, free_list);
- return;
-}
-
-static __inline void
-ahc_list_insert_tail(ahc, xs)
- struct ahc_softc *ahc;
- struct scsi_xfer *xs;
-{
- if (ahc->platform_data->sc_xxxq.lh_first == NULL){
- ahc->platform_data->sc_xxxqlast = xs;
- LIST_INSERT_HEAD(&ahc->platform_data->sc_xxxq, xs, free_list);
- return;
- }
- LIST_INSERT_AFTER(ahc->platform_data->sc_xxxqlast, xs, free_list);
- ahc->platform_data->sc_xxxqlast = xs;
-}
-
-static __inline void
-ahc_list_remove(ahc, xs)
- struct ahc_softc *ahc;
- struct scsi_xfer *xs;
-{
- struct scsi_xfer *lxs;
- if (xs == ahc->platform_data->sc_xxxqlast) {
- lxs = ahc->platform_data->sc_xxxq.lh_first;
- while (lxs != NULL) {
- if (LIST_NEXT(lxs, free_list) == ahc->platform_data->sc_xxxqlast) {
- ahc->platform_data->sc_xxxqlast = lxs;
- break;
- }
- lxs = LIST_NEXT(xs, free_list);
- }
- }
-
- LIST_REMOVE(xs, free_list);
- if (ahc->platform_data->sc_xxxq.lh_first == NULL)
- ahc->platform_data->sc_xxxqlast = NULL;
-}
-
-static __inline struct scsi_xfer *
-ahc_list_next(ahc, xs)
- struct ahc_softc *ahc;
- struct scsi_xfer *xs;
-{
- return(LIST_NEXT(xs, free_list));
-}
-
-/*
- * Pick the first xs for a non-blocked target.
- */
-static __inline struct scsi_xfer *
-ahc_first_xs(ahc)
- struct ahc_softc *ahc;
-{
- int target;
- struct scsi_xfer *xs = ahc->platform_data->sc_xxxq.lh_first;
-
- if (ahc->platform_data->queue_blocked)
- return NULL;
-
- while (xs != NULL) {
- target = xs->sc_link->target;
- if (ahc->platform_data->devqueue_blocked[target] == 0 &&
- ahc_index_busy_tcl(ahc, XS_TCL(xs)) == SCB_LIST_NULL)
- break;
- xs = LIST_NEXT(xs, free_list);
- }
-
- return xs;
-}
#endif /* _AIC7XXX_OPENBSD_H_ */
-
diff --git a/sys/dev/ic/aic7xxx_seeprom.c b/sys/dev/ic/aic7xxx_seeprom.c
new file mode 100644
index 00000000000..8f33d8eef8e
--- /dev/null
+++ b/sys/dev/ic/aic7xxx_seeprom.c
@@ -0,0 +1,777 @@
+/* $OpenBSD: aic7xxx_seeprom.c,v 1.1 2003/12/24 22:45:45 krw Exp $ */
+/* $NetBSD: aic7xxx_seeprom.c,v 1.8 2003/05/02 19:12:19 dyoung Exp $ */
+
+/*
+ * Product specific probe and attach routines for:
+ * 3940, 2940, aic7895, aic7890, aic7880,
+ * aic7870, aic7860 and aic7850 SCSI controllers
+ *
+ * Copyright (c) 1994-2001 Justin T. Gibbs.
+ * Copyright (c) 2000-2001 Adaptec Inc.
+ * All rights reserved.
+ *
+ * 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, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 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.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * 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 MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ *
+ * This file was originally split off from the PCI code by
+ * Jason Thorpe <thorpej@netbsd.org>. This version was split off
+ * from the FreeBSD source file aic7xxx_pci.c by Frank van der Linden
+ * <fvdl@netbsd.org>
+ *
+ * $Id: aic7xxx_seeprom.c,v 1.1 2003/12/24 22:45:45 krw Exp $
+ *
+ * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx_pci.c,v 1.22 2003/01/20 20:44:55 gibbs Exp $
+ */
+
+#include <sys/cdefs.h>
+/* __KERNEL_RCSID(0, "$NetBSD: aic7xxx_seeprom.c,v 1.8 2003/05/02 19:12:19 dyoung Exp $"); */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/queue.h>
+#include <sys/device.h>
+#include <sys/reboot.h> /* for AB_* needed by bootverbose */
+
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+
+#include <dev/ic/aic7xxx_openbsd.h>
+#include <dev/ic/aic7xxx_inline.h>
+
+#include <dev/ic/smc93cx6var.h>
+
+#define DEVCONFIG 0x40
+#define STPWLEVEL 0x00000002
+
+static void configure_termination(struct ahc_softc *,
+ struct seeprom_descriptor *, u_int, u_int *);
+static int verify_seeprom_cksum(struct seeprom_config *sc);
+
+static void ahc_new_term_detect(struct ahc_softc *, int *, int *, int *,
+ int *, int *);
+static void aic787X_cable_detect(struct ahc_softc *, int *, int *, int *,
+ int *);
+static void aic785X_cable_detect(struct ahc_softc *, int *, int *, int *);
+static void write_brdctl(struct ahc_softc *, u_int8_t);
+static u_int8_t read_brdctl(struct ahc_softc *);
+static void ahc_parse_pci_eeprom(struct ahc_softc *, struct seeprom_config *);
+
+/*
+ * Check the external port logic for a serial eeprom
+ * and termination/cable detection contrls.
+ */
+void
+ahc_check_extport(struct ahc_softc *ahc, u_int *sxfrctl1)
+{
+ struct seeprom_descriptor sd;
+ struct seeprom_config *sc;
+ int have_seeprom;
+ int have_autoterm;
+
+ sd.sd_tag = ahc->tag;
+ sd.sd_bsh = ahc->bsh;
+ sd.sd_regsize = 1;
+ sd.sd_control_offset = SEECTL;
+ sd.sd_status_offset = SEECTL;
+ sd.sd_dataout_offset = SEECTL;
+ sc = ahc->seep_config;
+
+ /*
+ * For some multi-channel devices, the c46 is simply too
+ * small to work. For the other controller types, we can
+ * get our information from either SEEPROM type. Set the
+ * type to start our probe with accordingly.
+ */
+ if (ahc->flags & AHC_LARGE_SEEPROM)
+ sd.sd_chip = C56_66;
+ else
+ sd.sd_chip = C46;
+
+ sd.sd_MS = SEEMS;
+ sd.sd_RDY = SEERDY;
+ sd.sd_CS = SEECS;
+ sd.sd_CK = SEECK;
+ sd.sd_DO = SEEDO;
+ sd.sd_DI = SEEDI;
+
+ have_seeprom = ahc_acquire_seeprom(ahc, &sd);
+ if (have_seeprom) {
+
+ if (bootverbose)
+ printf("%s: Reading SEEPROM...", ahc_name(ahc));
+
+ for (;;) {
+ u_int start_addr;
+
+ start_addr = 32 * (ahc->channel - 'A');
+ have_seeprom = read_seeprom(&sd, (uint16_t *)sc,
+ start_addr,
+ sizeof(*sc)/2);
+
+ if (have_seeprom)
+ have_seeprom = verify_seeprom_cksum(sc);
+
+ if (have_seeprom != 0 || sd.sd_chip == C56_66) {
+ if (bootverbose) {
+ if (have_seeprom == 0)
+ printf ("checksum error\n");
+ else
+ printf ("done.\n");
+ }
+ break;
+ }
+ sd.sd_chip = C56_66;
+ }
+ ahc_release_seeprom(&sd);
+ }
+
+ if (!have_seeprom) {
+ /*
+ * Pull scratch ram settings and treat them as
+ * if they are the contents of an seeprom if
+ * the 'ADPT' signature is found in SCB2.
+ * We manually compose the data as 16bit values
+ * to avoid endian issues.
+ */
+ ahc_outb(ahc, SCBPTR, 2);
+ if (ahc_inb(ahc, SCB_BASE) == 'A'
+ && ahc_inb(ahc, SCB_BASE + 1) == 'D'
+ && ahc_inb(ahc, SCB_BASE + 2) == 'P'
+ && ahc_inb(ahc, SCB_BASE + 3) == 'T') {
+ uint16_t *sc_data;
+ int i;
+
+ sc_data = (uint16_t *)sc;
+ for (i = 0; i < 32; i++, sc_data++) {
+ int j;
+
+ j = i * 2;
+ *sc_data = ahc_inb(ahc, SRAM_BASE + j)
+ | ahc_inb(ahc, SRAM_BASE + j + 1) << 8;
+ }
+ have_seeprom = verify_seeprom_cksum(sc);
+ if (have_seeprom)
+ ahc->flags |= AHC_SCB_CONFIG_USED;
+ }
+ /*
+ * Clear any SCB parity errors in case this data and
+ * its associated parity was not initialized by the BIOS
+ */
+ ahc_outb(ahc, CLRINT, CLRPARERR);
+ ahc_outb(ahc, CLRINT, CLRBRKADRINT);
+ }
+
+ if (!have_seeprom) {
+ if (bootverbose)
+ printf("%s: No SEEPROM available.\n", ahc_name(ahc));
+ ahc->flags |= AHC_USEDEFAULTS;
+ free(ahc->seep_config, M_DEVBUF);
+ ahc->seep_config = NULL;
+ sc = NULL;
+ } else {
+ ahc_parse_pci_eeprom(ahc, sc);
+ }
+
+ /*
+ * Cards that have the external logic necessary to talk to
+ * a SEEPROM, are almost certain to have the remaining logic
+ * necessary for auto-termination control. This assumption
+ * hasn't failed yet...
+ */
+ have_autoterm = have_seeprom;
+
+ /*
+ * Some low-cost chips have SEEPROM and auto-term control built
+ * in, instead of using a GAL. They can tell us directly
+ * if the termination logic is enabled.
+ */
+ if ((ahc->features & AHC_SPIOCAP) != 0) {
+ if ((ahc_inb(ahc, SPIOCAP) & SSPIOCPS) == 0)
+ have_autoterm = FALSE;
+ }
+
+ if (have_autoterm) {
+ ahc_acquire_seeprom(ahc, &sd);
+ configure_termination(ahc, &sd, sc->adapter_control, sxfrctl1);
+ ahc_release_seeprom(&sd);
+ } else if (have_seeprom) {
+ *sxfrctl1 &= ~STPWEN;
+ if ((sc->adapter_control & CFSTERM) != 0)
+ *sxfrctl1 |= STPWEN;
+ if (bootverbose)
+ printf("%s: Low byte termination %sabled\n",
+ ahc_name(ahc),
+ (*sxfrctl1 & STPWEN) ? "en" : "dis");
+ }
+}
+
+static void
+ahc_parse_pci_eeprom(struct ahc_softc *ahc, struct seeprom_config *sc)
+{
+ /*
+ * Put the data we've collected down into SRAM
+ * where ahc_init will find it.
+ */
+ int i;
+ int max_targ = sc->max_targets & CFMAXTARG;
+ u_int scsi_conf;
+ uint16_t discenable;
+ uint16_t ultraenb;
+
+ discenable = 0;
+ ultraenb = 0;
+ if ((sc->adapter_control & CFULTRAEN) != 0) {
+ /*
+ * Determine if this adapter has a "newstyle"
+ * SEEPROM format.
+ */
+ for (i = 0; i < max_targ; i++) {
+ if ((sc->device_flags[i] & CFSYNCHISULTRA) != 0) {
+ ahc->flags |= AHC_NEWEEPROM_FMT;
+ break;
+ }
+ }
+ }
+
+ for (i = 0; i < max_targ; i++) {
+ u_int scsirate;
+ uint16_t target_mask;
+
+ target_mask = 0x01 << i;
+ if (sc->device_flags[i] & CFDISC)
+ discenable |= target_mask;
+ if ((ahc->flags & AHC_NEWEEPROM_FMT) != 0) {
+ if ((sc->device_flags[i] & CFSYNCHISULTRA) != 0)
+ ultraenb |= target_mask;
+ } else if ((sc->adapter_control & CFULTRAEN) != 0) {
+ ultraenb |= target_mask;
+ }
+ if ((sc->device_flags[i] & CFXFER) == 0x04
+ && (ultraenb & target_mask) != 0) {
+ /* Treat 10MHz as a non-ultra speed */
+ sc->device_flags[i] &= ~CFXFER;
+ ultraenb &= ~target_mask;
+ }
+ if ((ahc->features & AHC_ULTRA2) != 0) {
+ u_int offset;
+
+ if (sc->device_flags[i] & CFSYNCH)
+ offset = MAX_OFFSET_ULTRA2;
+ else
+ offset = 0;
+ ahc_outb(ahc, TARG_OFFSET + i, offset);
+
+ /*
+ * The ultra enable bits contain the
+ * high bit of the ultra2 sync rate
+ * field.
+ */
+ scsirate = (sc->device_flags[i] & CFXFER)
+ | ((ultraenb & target_mask) ? 0x8 : 0x0);
+ if (sc->device_flags[i] & CFWIDEB)
+ scsirate |= WIDEXFER;
+ } else {
+ scsirate = (sc->device_flags[i] & CFXFER) << 4;
+ if (sc->device_flags[i] & CFSYNCH)
+ scsirate |= SOFS;
+ if (sc->device_flags[i] & CFWIDEB)
+ scsirate |= WIDEXFER;
+ }
+ ahc_outb(ahc, TARG_SCSIRATE + i, scsirate);
+ }
+ ahc->our_id = sc->brtime_id & CFSCSIID;
+
+ scsi_conf = (ahc->our_id & 0x7);
+ if (sc->adapter_control & CFSPARITY)
+ scsi_conf |= ENSPCHK;
+ if (sc->adapter_control & CFRESETB)
+ scsi_conf |= RESET_SCSI;
+
+ ahc->flags |= (sc->adapter_control & CFBOOTCHAN) >> CFBOOTCHANSHIFT;
+
+ if (sc->bios_control & CFEXTEND)
+ ahc->flags |= AHC_EXTENDED_TRANS_A;
+
+ if (sc->bios_control & CFBIOSEN)
+ ahc->flags |= AHC_BIOS_ENABLED;
+ if (ahc->features & AHC_ULTRA
+ && (ahc->flags & AHC_NEWEEPROM_FMT) == 0) {
+ /* Should we enable Ultra mode? */
+ if (!(sc->adapter_control & CFULTRAEN))
+ /* Treat us as a non-ultra card */
+ ultraenb = 0;
+ }
+
+ if (sc->signature == CFSIGNATURE
+ || sc->signature == CFSIGNATURE2) {
+ uint32_t devconfig;
+
+ /* Honor the STPWLEVEL settings */
+ devconfig = pci_conf_read(ahc->bd->pc, ahc->bd->tag, DEVCONFIG);
+ devconfig &= ~STPWLEVEL;
+ if ((sc->bios_control & CFSTPWLEVEL) != 0)
+ devconfig |= STPWLEVEL;
+ pci_conf_write(ahc->bd->pc, ahc->bd->tag, DEVCONFIG, devconfig);
+ }
+ /* Set SCSICONF info */
+ ahc_outb(ahc, SCSICONF, scsi_conf);
+ ahc_outb(ahc, DISC_DSB, ~(discenable & 0xff));
+ ahc_outb(ahc, DISC_DSB + 1, ~((discenable >> 8) & 0xff));
+ ahc_outb(ahc, ULTRA_ENB, ultraenb & 0xff);
+ ahc_outb(ahc, ULTRA_ENB + 1, (ultraenb >> 8) & 0xff);
+}
+
+static void
+configure_termination(struct ahc_softc *ahc,
+ struct seeprom_descriptor *sd,
+ u_int adapter_control,
+ u_int *sxfrctl1)
+{
+ uint8_t brddat;
+
+ brddat = 0;
+
+ /*
+ * Update the settings in sxfrctl1 to match the
+ * termination settings
+ */
+ *sxfrctl1 = 0;
+
+ /*
+ * SEECS must be on for the GALS to latch
+ * the data properly. Be sure to leave MS
+ * on or we will release the seeprom.
+ */
+ SEEPROM_OUTB(sd, sd->sd_MS | sd->sd_CS);
+ if ((adapter_control & CFAUTOTERM) != 0
+ || (ahc->features & AHC_NEW_TERMCTL) != 0) {
+ int internal50_present;
+ int internal68_present;
+ int externalcable_present;
+ int eeprom_present;
+ int enableSEC_low;
+ int enableSEC_high;
+ int enablePRI_low;
+ int enablePRI_high;
+ int sum;
+
+ enableSEC_low = 0;
+ enableSEC_high = 0;
+ enablePRI_low = 0;
+ enablePRI_high = 0;
+ if ((ahc->features & AHC_NEW_TERMCTL) != 0) {
+ ahc_new_term_detect(ahc, &enableSEC_low,
+ &enableSEC_high,
+ &enablePRI_low,
+ &enablePRI_high,
+ &eeprom_present);
+ if ((adapter_control & CFSEAUTOTERM) == 0) {
+ if (bootverbose)
+ printf("%s: Manual SE Termination\n",
+ ahc_name(ahc));
+ enableSEC_low = (adapter_control & CFSELOWTERM);
+ enableSEC_high =
+ (adapter_control & CFSEHIGHTERM);
+ }
+ if ((adapter_control & CFAUTOTERM) == 0) {
+ if (bootverbose)
+ printf("%s: Manual LVD Termination\n",
+ ahc_name(ahc));
+ enablePRI_low = (adapter_control & CFSTERM);
+ enablePRI_high = (adapter_control & CFWSTERM);
+ }
+ /* Make the table calculations below happy */
+ internal50_present = 0;
+ internal68_present = 1;
+ externalcable_present = 1;
+ } else if ((ahc->features & AHC_SPIOCAP) != 0) {
+ aic785X_cable_detect(ahc, &internal50_present,
+ &externalcable_present,
+ &eeprom_present);
+ /* Can never support a wide connector. */
+ internal68_present = 0;
+ } else {
+ aic787X_cable_detect(ahc, &internal50_present,
+ &internal68_present,
+ &externalcable_present,
+ &eeprom_present);
+ }
+
+ if ((ahc->features & AHC_WIDE) == 0)
+ internal68_present = 0;
+
+ if (bootverbose
+ && (ahc->features & AHC_ULTRA2) == 0) {
+ printf("%s: internal 50 cable %s present",
+ ahc_name(ahc),
+ internal50_present ? "is":"not");
+
+ if ((ahc->features & AHC_WIDE) != 0)
+ printf(", internal 68 cable %s present",
+ internal68_present ? "is":"not");
+ printf("\n%s: external cable %s present\n",
+ ahc_name(ahc),
+ externalcable_present ? "is":"not");
+ }
+ if (bootverbose)
+ printf("%s: BIOS eeprom %s present\n",
+ ahc_name(ahc), eeprom_present ? "is" : "not");
+
+ if ((ahc->flags & AHC_INT50_SPEEDFLEX) != 0) {
+ /*
+ * The 50 pin connector is a separate bus,
+ * so force it to always be terminated.
+ * In the future, perform current sensing
+ * to determine if we are in the middle of
+ * a properly terminated bus.
+ */
+ internal50_present = 0;
+ }
+
+ /*
+ * Now set the termination based on what
+ * we found.
+ * Flash Enable = BRDDAT7
+ * Secondary High Term Enable = BRDDAT6
+ * Secondary Low Term Enable = BRDDAT5 (7890)
+ * Primary High Term Enable = BRDDAT4 (7890)
+ */
+ if ((ahc->features & AHC_ULTRA2) == 0
+ && (internal50_present != 0)
+ && (internal68_present != 0)
+ && (externalcable_present != 0)) {
+ printf("%s: Illegal cable configuration!!. "
+ "Only two connectors on the "
+ "adapter may be used at a "
+ "time!\n", ahc_name(ahc));
+
+ /*
+ * Pretend there are no cables in the hope
+ * that having all of the termination on
+ * gives us a more stable bus.
+ */
+ internal50_present = 0;
+ internal68_present = 0;
+ externalcable_present = 0;
+ }
+
+ if ((ahc->features & AHC_WIDE) != 0
+ && ((externalcable_present == 0)
+ || (internal68_present == 0)
+ || (enableSEC_high != 0))) {
+ brddat |= BRDDAT6;
+ if (bootverbose) {
+ if ((ahc->flags & AHC_INT50_SPEEDFLEX) != 0)
+ printf("%s: 68 pin termination "
+ "Enabled\n", ahc_name(ahc));
+ else
+ printf("%s: %sHigh byte termination "
+ "Enabled\n", ahc_name(ahc),
+ enableSEC_high ? "Secondary "
+ : "");
+ }
+ }
+
+ sum = internal50_present + internal68_present
+ + externalcable_present;
+ if (sum < 2 || (enableSEC_low != 0)) {
+ if ((ahc->features & AHC_ULTRA2) != 0)
+ brddat |= BRDDAT5;
+ else
+ *sxfrctl1 |= STPWEN;
+ if (bootverbose) {
+ if ((ahc->flags & AHC_INT50_SPEEDFLEX) != 0)
+ printf("%s: 50 pin termination "
+ "Enabled\n", ahc_name(ahc));
+ else
+ printf("%s: %sLow byte termination "
+ "Enabled\n", ahc_name(ahc),
+ enableSEC_low ? "Secondary "
+ : "");
+ }
+ }
+
+ if (enablePRI_low != 0) {
+ *sxfrctl1 |= STPWEN;
+ if (bootverbose)
+ printf("%s: Primary Low Byte termination "
+ "Enabled\n", ahc_name(ahc));
+ }
+
+ /*
+ * Setup STPWEN before setting up the rest of
+ * the termination per the tech note on the U160 cards.
+ */
+ ahc_outb(ahc, SXFRCTL1, *sxfrctl1);
+
+ if (enablePRI_high != 0) {
+ brddat |= BRDDAT4;
+ if (bootverbose)
+ printf("%s: Primary High Byte "
+ "termination Enabled\n",
+ ahc_name(ahc));
+ }
+
+ write_brdctl(ahc, brddat);
+
+ } else {
+ if ((adapter_control & CFSTERM) != 0) {
+ *sxfrctl1 |= STPWEN;
+
+ if (bootverbose)
+ printf("%s: %sLow byte termination Enabled\n",
+ ahc_name(ahc),
+ (ahc->features & AHC_ULTRA2) ? "Primary "
+ : "");
+ }
+
+ if ((adapter_control & CFWSTERM) != 0
+ && (ahc->features & AHC_WIDE) != 0) {
+ brddat |= BRDDAT6;
+ if (bootverbose)
+ printf("%s: %sHigh byte termination Enabled\n",
+ ahc_name(ahc),
+ (ahc->features & AHC_ULTRA2)
+ ? "Secondary " : "");
+ }
+
+ /*
+ * Setup STPWEN before setting up the rest of
+ * the termination per the tech note on the U160 cards.
+ */
+ ahc_outb(ahc, SXFRCTL1, *sxfrctl1);
+
+ if ((ahc->features & AHC_WIDE) != 0)
+ write_brdctl(ahc, brddat);
+ }
+ SEEPROM_OUTB(sd, sd->sd_MS); /* Clear CS */
+}
+
+static void
+ahc_new_term_detect(struct ahc_softc *ahc, int *enableSEC_low,
+ int *enableSEC_high, int *enablePRI_low,
+ int *enablePRI_high, int *eeprom_present)
+{
+ uint8_t brdctl;
+
+ /*
+ * BRDDAT7 = Eeprom
+ * BRDDAT6 = Enable Secondary High Byte termination
+ * BRDDAT5 = Enable Secondary Low Byte termination
+ * BRDDAT4 = Enable Primary high byte termination
+ * BRDDAT3 = Enable Primary low byte termination
+ */
+ brdctl = read_brdctl(ahc);
+ *eeprom_present = brdctl & BRDDAT7;
+ *enableSEC_high = (brdctl & BRDDAT6);
+ *enableSEC_low = (brdctl & BRDDAT5);
+ *enablePRI_high = (brdctl & BRDDAT4);
+ *enablePRI_low = (brdctl & BRDDAT3);
+}
+
+static void
+aic787X_cable_detect(struct ahc_softc *ahc, int *internal50_present,
+ int *internal68_present, int *externalcable_present,
+ int *eeprom_present)
+{
+ uint8_t brdctl;
+
+ /*
+ * First read the status of our cables.
+ * Set the rom bank to 0 since the
+ * bank setting serves as a multiplexor
+ * for the cable detection logic.
+ * BRDDAT5 controls the bank switch.
+ */
+ write_brdctl(ahc, 0);
+
+ /*
+ * Now read the state of the internal
+ * connectors. BRDDAT6 is INT50 and
+ * BRDDAT7 is INT68.
+ */
+ brdctl = read_brdctl(ahc);
+ *internal50_present = (brdctl & BRDDAT6) ? 0 : 1;
+ *internal68_present = (brdctl & BRDDAT7) ? 0 : 1;
+
+ /*
+ * Set the rom bank to 1 and determine
+ * the other signals.
+ */
+ write_brdctl(ahc, BRDDAT5);
+
+ /*
+ * Now read the state of the external
+ * connectors. BRDDAT6 is EXT68 and
+ * BRDDAT7 is EPROMPS.
+ */
+ brdctl = read_brdctl(ahc);
+ *externalcable_present = (brdctl & BRDDAT6) ? 0 : 1;
+ *eeprom_present = (brdctl & BRDDAT7) ? 1 : 0;
+}
+
+static void
+aic785X_cable_detect(struct ahc_softc *ahc, int *internal50_present,
+ int *externalcable_present, int *eeprom_present)
+{
+ uint8_t brdctl;
+ uint8_t spiocap;
+
+ spiocap = ahc_inb(ahc, SPIOCAP);
+ spiocap &= ~SOFTCMDEN;
+ spiocap |= EXT_BRDCTL;
+ ahc_outb(ahc, SPIOCAP, spiocap);
+ ahc_outb(ahc, BRDCTL, BRDRW|BRDCS);
+ ahc_outb(ahc, BRDCTL, 0);
+ brdctl = ahc_inb(ahc, BRDCTL);
+ *internal50_present = (brdctl & BRDDAT5) ? 0 : 1;
+ *externalcable_present = (brdctl & BRDDAT6) ? 0 : 1;
+
+ *eeprom_present = (ahc_inb(ahc, SPIOCAP) & EEPROM) ? 1 : 0;
+}
+
+int
+ahc_acquire_seeprom(struct ahc_softc *ahc, struct seeprom_descriptor *sd)
+{
+ int wait;
+
+ if ((ahc->features & AHC_SPIOCAP) != 0
+ && (ahc_inb(ahc, SPIOCAP) & SEEPROM) == 0)
+ return (0);
+
+ /*
+ * Request access of the memory port. When access is
+ * granted, SEERDY will go high. We use a 1 second
+ * timeout which should be near 1 second more than
+ * is needed. Reason: after the chip reset, there
+ * should be no contention.
+ */
+ SEEPROM_OUTB(sd, sd->sd_MS);
+ wait = 1000; /* 1 second timeout in msec */
+ while (--wait && ((SEEPROM_STATUS_INB(sd) & sd->sd_RDY) == 0)) {
+ ahc_delay(1000); /* delay 1 msec */
+ }
+ if ((SEEPROM_STATUS_INB(sd) & sd->sd_RDY) == 0) {
+ SEEPROM_OUTB(sd, 0);
+ return (0);
+ }
+ return(1);
+}
+
+void
+ahc_release_seeprom(struct seeprom_descriptor *sd)
+{
+ /* Release access to the memory port and the serial EEPROM. */
+ SEEPROM_OUTB(sd, 0);
+}
+
+static void
+write_brdctl(struct ahc_softc *ahc, uint8_t value)
+{
+ uint8_t brdctl;
+
+ if ((ahc->chip & AHC_CHIPID_MASK) == AHC_AIC7895) {
+ brdctl = BRDSTB;
+ if (ahc->channel == 'B')
+ brdctl |= BRDCS;
+ } else if ((ahc->features & AHC_ULTRA2) != 0) {
+ brdctl = 0;
+ } else {
+ brdctl = BRDSTB|BRDCS;
+ }
+ ahc_outb(ahc, BRDCTL, brdctl);
+ ahc_flush_device_writes(ahc);
+ brdctl |= value;
+ ahc_outb(ahc, BRDCTL, brdctl);
+ ahc_flush_device_writes(ahc);
+ if ((ahc->features & AHC_ULTRA2) != 0)
+ brdctl |= BRDSTB_ULTRA2;
+ else
+ brdctl &= ~BRDSTB;
+ ahc_outb(ahc, BRDCTL, brdctl);
+ ahc_flush_device_writes(ahc);
+ if ((ahc->features & AHC_ULTRA2) != 0)
+ brdctl = 0;
+ else
+ brdctl &= ~BRDCS;
+ ahc_outb(ahc, BRDCTL, brdctl);
+}
+
+static uint8_t
+read_brdctl(ahc)
+ struct ahc_softc *ahc;
+{
+ uint8_t brdctl;
+ uint8_t value;
+
+ if ((ahc->chip & AHC_CHIPID_MASK) == AHC_AIC7895) {
+ brdctl = BRDRW;
+ if (ahc->channel == 'B')
+ brdctl |= BRDCS;
+ } else if ((ahc->features & AHC_ULTRA2) != 0) {
+ brdctl = BRDRW_ULTRA2;
+ } else {
+ brdctl = BRDRW|BRDCS;
+ }
+ ahc_outb(ahc, BRDCTL, brdctl);
+ ahc_flush_device_writes(ahc);
+ value = ahc_inb(ahc, BRDCTL);
+ ahc_outb(ahc, BRDCTL, 0);
+ return (value);
+}
+
+static int
+verify_seeprom_cksum(struct seeprom_config *sc)
+{
+ int i;
+ int maxaddr;
+ uint32_t checksum;
+ uint16_t *scarray;
+
+ maxaddr = (sizeof(*sc)/2) - 1;
+ checksum = 0;
+ scarray = (uint16_t *)sc;
+
+ for (i = 0; i < maxaddr; i++)
+ checksum = checksum + scarray[i];
+ if (checksum == 0
+ || (checksum & 0xFFFF) != sc->checksum) {
+ return (0);
+ } else {
+ return(1);
+ }
+}
diff --git a/sys/dev/pci/ahc_pci.c b/sys/dev/pci/ahc_pci.c
index 3e17732547c..b15714f84a0 100644
--- a/sys/dev/pci/ahc_pci.c
+++ b/sys/dev/pci/ahc_pci.c
@@ -1,87 +1,597 @@
-/* $OpenBSD: ahc_pci.c,v 1.41 2003/09/25 07:11:15 deraadt Exp $ */
-/* $NetBSD: ahc_pci.c,v 1.9 1996/10/21 22:56:24 thorpej Exp $ */
-
+/* $OpenBSD: ahc_pci.c,v 1.42 2003/12/24 22:45:45 krw Exp $ */
/*
* Product specific probe and attach routines for:
- * 3940, 2940, aic7880, aic7870, aic7860 and aic7850 SCSI controllers
+ * 3940, 2940, aic7895, aic7890, aic7880,
+ * aic7870, aic7860 and aic7850 SCSI controllers
*
- * Copyright (c) 1995, 1996 Justin T. Gibbs.
+ * Copyright (c) 1994-2001 Justin T. Gibbs.
+ * Copyright (c) 2000-2001 Adaptec Inc.
* All rights reserved.
*
* 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. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 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.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
*
- * 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
+ * NO WARRANTY
+ * 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 MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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.
+ * 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 DAMAGES.
+ *
+ * $Id: ahc_pci.c,v 1.42 2003/12/24 22:45:45 krw Exp $
+ *
+ * //depot/aic7xxx/aic7xxx/aic7xxx_pci.c#57 $
+ *
+ * $FreeBSD: /repoman/r/ncvs/src/sys/dev/aic7xxx/aic7xxx_pci.c,v 1.22 2003/01/20 20:44:55 gibbs Exp $
+ */
+/*
+ * Ported from FreeBSD by Pascal Renauld, Network Storage Solutions, Inc. - April 2003
*/
+#include <sys/cdefs.h>
+/* __KERNEL_RCSID(0, "$NetBSD: ahc_pci.c,v 1.43 2003/08/18 09:16:22 taca Exp $"); */
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/kernel.h>
#include <sys/queue.h>
#include <sys/device.h>
+#include <sys/reboot.h>
+
#include <machine/bus.h>
#include <machine/intr.h>
-#include <scsi/scsi_all.h>
-#include <scsi/scsiconf.h>
-
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
-#include <dev/pci/pcidevs.h>
#define AHC_PCI_IOADDR PCI_MAPREG_START /* I/O Address */
#define AHC_PCI_MEMADDR (PCI_MAPREG_START + 4) /* Mem I/O Address */
-#include <dev/ic/aic7xxxreg.h>
#include <dev/ic/aic7xxx_openbsd.h>
#include <dev/ic/aic7xxx_inline.h>
+
#include <dev/ic/smc93cx6var.h>
-/*
- * XXX memory-mapped is busted on some i386 on-board chips.
- * for i386, we don't even try it. Also, suppress the damn
- * PCI bus errors messages on i386. They are not fatal, and are
- * usually caused by some other device on the PCI bus. But some
- * ahc cards won't work without ACKing them. So just ACK and go!
- * XXX- smurph
- */
-#ifndef i386
-#define AHC_ALLOW_MEMIO
-#define AHC_SHOW_PCI_ERRORS
-#endif
+static __inline uint64_t
+ahc_compose_id(u_int device, u_int vendor, u_int subdevice, u_int subvendor)
+{
+ uint64_t id;
+
+ id = subvendor
+ | (subdevice << 16)
+ | ((uint64_t)vendor << 32)
+ | ((uint64_t)device << 48);
+
+ return (id);
+}
+
+#define ID_ALL_MASK 0xFFFFFFFFFFFFFFFFull
+#define ID_DEV_VENDOR_MASK 0xFFFFFFFF00000000ull
+#define ID_9005_GENERIC_MASK 0xFFF0FFFF00000000ull
+#define ID_9005_SISL_MASK 0x000FFFFF00000000ull
+#define ID_9005_SISL_ID 0x0005900500000000ull
+#define ID_AIC7850 0x5078900400000000ull
+#define ID_AHA_2902_04_10_15_20_30C 0x5078900478509004ull
+#define ID_AIC7855 0x5578900400000000ull
+#define ID_AIC7859 0x3860900400000000ull
+#define ID_AHA_2930CU 0x3860900438699004ull
+#define ID_AIC7860 0x6078900400000000ull
+#define ID_AIC7860C 0x6078900478609004ull
+#define ID_AHA_1480A 0x6075900400000000ull
+#define ID_AHA_2940AU_0 0x6178900400000000ull
+#define ID_AHA_2940AU_1 0x6178900478619004ull
+#define ID_AHA_2940AU_CN 0x2178900478219004ull
+#define ID_AHA_2930C_VAR 0x6038900438689004ull
+
+#define ID_AIC7870 0x7078900400000000ull
+#define ID_AHA_2940 0x7178900400000000ull
+#define ID_AHA_3940 0x7278900400000000ull
+#define ID_AHA_398X 0x7378900400000000ull
+#define ID_AHA_2944 0x7478900400000000ull
+#define ID_AHA_3944 0x7578900400000000ull
+#define ID_AHA_4944 0x7678900400000000ull
+
+#define ID_AIC7880 0x8078900400000000ull
+#define ID_AIC7880_B 0x8078900478809004ull
+#define ID_AHA_2940U 0x8178900400000000ull
+#define ID_AHA_3940U 0x8278900400000000ull
+#define ID_AHA_2944U 0x8478900400000000ull
+#define ID_AHA_3944U 0x8578900400000000ull
+#define ID_AHA_398XU 0x8378900400000000ull
+#define ID_AHA_4944U 0x8678900400000000ull
+#define ID_AHA_2940UB 0x8178900478819004ull
+#define ID_AHA_2930U 0x8878900478889004ull
+#define ID_AHA_2940U_PRO 0x8778900478879004ull
+#define ID_AHA_2940U_CN 0x0078900478009004ull
+
+#define ID_AIC7895 0x7895900478959004ull
+#define ID_AIC7895_ARO 0x7890900478939004ull
+#define ID_AIC7895_ARO_MASK 0xFFF0FFFFFFFFFFFFull
+#define ID_AHA_2940U_DUAL 0x7895900478919004ull
+#define ID_AHA_3940AU 0x7895900478929004ull
+#define ID_AHA_3944AU 0x7895900478949004ull
+
+#define ID_AIC7890 0x001F9005000F9005ull
+#define ID_AIC7890_ARO 0x00139005000F9005ull
+#define ID_AAA_131U2 0x0013900500039005ull
+#define ID_AHA_2930U2 0x0011900501819005ull
+#define ID_AHA_2940U2B 0x00109005A1009005ull
+#define ID_AHA_2940U2_OEM 0x0010900521809005ull
+#define ID_AHA_2940U2 0x00109005A1809005ull
+#define ID_AHA_2950U2B 0x00109005E1009005ull
+
+#define ID_AIC7892 0x008F9005FFFF9005ull
+#define ID_AIC7892_ARO 0x00839005FFFF9005ull
+#define ID_AHA_2915LP 0x0082900502109005ull
+#define ID_AHA_29160 0x00809005E2A09005ull
+#define ID_AHA_29160_CPQ 0x00809005E2A00E11ull
+#define ID_AHA_29160N 0x0080900562A09005ull
+#define ID_AHA_29160C 0x0080900562209005ull
+#define ID_AHA_29160B 0x00809005E2209005ull
+#define ID_AHA_19160B 0x0081900562A19005ull
+
+#define ID_AIC7896 0x005F9005FFFF9005ull
+#define ID_AIC7896_ARO 0x00539005FFFF9005ull
+#define ID_AHA_3950U2B_0 0x00509005FFFF9005ull
+#define ID_AHA_3950U2B_1 0x00509005F5009005ull
+#define ID_AHA_3950U2D_0 0x00519005FFFF9005ull
+#define ID_AHA_3950U2D_1 0x00519005B5009005ull
+
+#define ID_AIC7899 0x00CF9005FFFF9005ull
+#define ID_AIC7899_ARO 0x00C39005FFFF9005ull
+#define ID_AHA_3960D 0x00C09005F6209005ull
+#define ID_AHA_3960D_CPQ 0x00C09005F6200E11ull
+
+#define ID_AIC7810 0x1078900400000000ull
+#define ID_AIC7815 0x7815900400000000ull
+
+#define DEVID_9005_TYPE(id) ((id) & 0xF)
+#define DEVID_9005_TYPE_HBA 0x0 /* Standard Card */
+#define DEVID_9005_TYPE_AAA 0x3 /* RAID Card */
+#define DEVID_9005_TYPE_SISL 0x5 /* Container ROMB */
+#define DEVID_9005_TYPE_MB 0xF /* On Motherboard */
+
+#define DEVID_9005_MAXRATE(id) (((id) & 0x30) >> 4)
+#define DEVID_9005_MAXRATE_U160 0x0
+#define DEVID_9005_MAXRATE_ULTRA2 0x1
+#define DEVID_9005_MAXRATE_ULTRA 0x2
+#define DEVID_9005_MAXRATE_FAST 0x3
+
+#define DEVID_9005_MFUNC(id) (((id) & 0x40) >> 6)
+
+#define DEVID_9005_CLASS(id) (((id) & 0xFF00) >> 8)
+#define DEVID_9005_CLASS_SPI 0x0 /* Parallel SCSI */
+
+#define SUBID_9005_TYPE(id) ((id) & 0xF)
+#define SUBID_9005_TYPE_MB 0xF /* On Motherboard */
+#define SUBID_9005_TYPE_CARD 0x0 /* Standard Card */
+#define SUBID_9005_TYPE_LCCARD 0x1 /* Low Cost Card */
+#define SUBID_9005_TYPE_RAID 0x3 /* Combined with Raid */
+
+#define SUBID_9005_TYPE_KNOWN(id) \
+ ((((id) & 0xF) == SUBID_9005_TYPE_MB) \
+ || (((id) & 0xF) == SUBID_9005_TYPE_CARD) \
+ || (((id) & 0xF) == SUBID_9005_TYPE_LCCARD) \
+ || (((id) & 0xF) == SUBID_9005_TYPE_RAID))
+
+#define SUBID_9005_MAXRATE(id) (((id) & 0x30) >> 4)
+#define SUBID_9005_MAXRATE_ULTRA2 0x0
+#define SUBID_9005_MAXRATE_ULTRA 0x1
+#define SUBID_9005_MAXRATE_U160 0x2
+#define SUBID_9005_MAXRATE_RESERVED 0x3
+
+#define SUBID_9005_SEEPTYPE(id) \
+ ((SUBID_9005_TYPE(id) == SUBID_9005_TYPE_MB) \
+ ? ((id) & 0xC0) >> 6 \
+ : ((id) & 0x300) >> 8)
+#define SUBID_9005_SEEPTYPE_NONE 0x0
+#define SUBID_9005_SEEPTYPE_1K 0x1
+#define SUBID_9005_SEEPTYPE_2K_4K 0x2
+#define SUBID_9005_SEEPTYPE_RESERVED 0x3
+#define SUBID_9005_AUTOTERM(id) \
+ ((SUBID_9005_TYPE(id) == SUBID_9005_TYPE_MB) \
+ ? (((id) & 0x400) >> 10) == 0 \
+ : (((id) & 0x40) >> 6) == 0)
+
+#define SUBID_9005_NUMCHAN(id) \
+ ((SUBID_9005_TYPE(id) == SUBID_9005_TYPE_MB) \
+ ? ((id) & 0x300) >> 8 \
+ : ((id) & 0xC00) >> 10)
+
+#define SUBID_9005_LEGACYCONN(id) \
+ ((SUBID_9005_TYPE(id) == SUBID_9005_TYPE_MB) \
+ ? 0 \
+ : ((id) & 0x80) >> 7)
+
+#define SUBID_9005_MFUNCENB(id) \
+ ((SUBID_9005_TYPE(id) == SUBID_9005_TYPE_MB) \
+ ? ((id) & 0x800) >> 11 \
+ : ((id) & 0x1000) >> 12)
/*
- * Under normal circumstances, these messages are unnecessary
- * and not terribly cosmetic.
+ * Informational only. Should use chip register to be
+ * certain, but may be use in identification strings.
*/
-#ifdef DEBUG
-#define bootverbose 1
-#else
-#define bootverbose 0
-#endif
-
-#define PCI_BASEADR0 PCI_MAPREG_START
+#define SUBID_9005_CARD_SCSIWIDTH_MASK 0x2000
+#define SUBID_9005_CARD_PCIWIDTH_MASK 0x4000
+#define SUBID_9005_CARD_SEDIFF_MASK 0x8000
+
+static ahc_device_setup_t ahc_aic785X_setup;
+static ahc_device_setup_t ahc_aic7860_setup;
+static ahc_device_setup_t ahc_apa1480_setup;
+static ahc_device_setup_t ahc_aic7870_setup;
+static ahc_device_setup_t ahc_aha394X_setup;
+static ahc_device_setup_t ahc_aha494X_setup;
+static ahc_device_setup_t ahc_aha398X_setup;
+static ahc_device_setup_t ahc_aic7880_setup;
+static ahc_device_setup_t ahc_aha2940Pro_setup;
+static ahc_device_setup_t ahc_aha394XU_setup;
+static ahc_device_setup_t ahc_aha398XU_setup;
+static ahc_device_setup_t ahc_aic7890_setup;
+static ahc_device_setup_t ahc_aic7892_setup;
+static ahc_device_setup_t ahc_aic7895_setup;
+static ahc_device_setup_t ahc_aic7896_setup;
+static ahc_device_setup_t ahc_aic7899_setup;
+static ahc_device_setup_t ahc_aha29160C_setup;
+static ahc_device_setup_t ahc_raid_setup;
+static ahc_device_setup_t ahc_aha394XX_setup;
+static ahc_device_setup_t ahc_aha494XX_setup;
+static ahc_device_setup_t ahc_aha398XX_setup;
+
+struct ahc_pci_identity ahc_pci_ident_table [] =
+{
+ /* aic7850 based controllers */
+ {
+ ID_AHA_2902_04_10_15_20_30C,
+ ID_ALL_MASK,
+ ahc_aic785X_setup
+ },
+ /* aic7860 based controllers */
+ {
+ ID_AHA_2930CU,
+ ID_ALL_MASK,
+ ahc_aic7860_setup
+ },
+ {
+ ID_AHA_1480A & ID_DEV_VENDOR_MASK,
+ ID_DEV_VENDOR_MASK,
+ ahc_apa1480_setup
+ },
+ {
+ ID_AHA_2940AU_0 & ID_DEV_VENDOR_MASK,
+ ID_DEV_VENDOR_MASK,
+ ahc_aic7860_setup
+ },
+ {
+ ID_AHA_2940AU_CN & ID_DEV_VENDOR_MASK,
+ ID_DEV_VENDOR_MASK,
+ ahc_aic7860_setup
+ },
+ {
+ ID_AHA_2930C_VAR & ID_DEV_VENDOR_MASK,
+ ID_DEV_VENDOR_MASK,
+ ahc_aic7860_setup
+ },
+ /* aic7870 based controllers */
+ {
+ ID_AHA_2940,
+ ID_ALL_MASK,
+ ahc_aic7870_setup
+ },
+ {
+ ID_AHA_3940,
+ ID_ALL_MASK,
+ ahc_aha394X_setup
+ },
+ {
+ ID_AHA_398X,
+ ID_ALL_MASK,
+ ahc_aha398X_setup
+ },
+ {
+ ID_AHA_2944,
+ ID_ALL_MASK,
+ ahc_aic7870_setup
+ },
+ {
+ ID_AHA_3944,
+ ID_ALL_MASK,
+ ahc_aha394X_setup
+ },
+ {
+ ID_AHA_4944,
+ ID_ALL_MASK,
+ ahc_aha494X_setup
+ },
+ /* aic7880 based controllers */
+ {
+ ID_AHA_2940U & ID_DEV_VENDOR_MASK,
+ ID_DEV_VENDOR_MASK,
+ ahc_aic7880_setup
+ },
+ {
+ ID_AHA_3940U & ID_DEV_VENDOR_MASK,
+ ID_DEV_VENDOR_MASK,
+ ahc_aha394XU_setup
+ },
+ {
+ ID_AHA_2944U & ID_DEV_VENDOR_MASK,
+ ID_DEV_VENDOR_MASK,
+ ahc_aic7880_setup
+ },
+ {
+ ID_AHA_3944U & ID_DEV_VENDOR_MASK,
+ ID_DEV_VENDOR_MASK,
+ ahc_aha394XU_setup
+ },
+ {
+ ID_AHA_398XU & ID_DEV_VENDOR_MASK,
+ ID_DEV_VENDOR_MASK,
+ ahc_aha398XU_setup
+ },
+ {
+ /*
+ * XXX Don't know the slot numbers
+ * so we can't identify channels
+ */
+ ID_AHA_4944U & ID_DEV_VENDOR_MASK,
+ ID_DEV_VENDOR_MASK,
+ ahc_aic7880_setup
+ },
+ {
+ ID_AHA_2930U & ID_DEV_VENDOR_MASK,
+ ID_DEV_VENDOR_MASK,
+ ahc_aic7880_setup
+ },
+ {
+ ID_AHA_2940U_PRO & ID_DEV_VENDOR_MASK,
+ ID_DEV_VENDOR_MASK,
+ ahc_aha2940Pro_setup
+ },
+ {
+ ID_AHA_2940U_CN & ID_DEV_VENDOR_MASK,
+ ID_DEV_VENDOR_MASK,
+ ahc_aic7880_setup
+ },
+ /* Ignore all SISL (AAC on MB) based controllers. */
+ {
+ ID_9005_SISL_ID,
+ ID_9005_SISL_MASK,
+ NULL
+ },
+ /* aic7890 based controllers */
+ {
+ ID_AHA_2930U2,
+ ID_ALL_MASK,
+ ahc_aic7890_setup
+ },
+ {
+ ID_AHA_2940U2B,
+ ID_ALL_MASK,
+ ahc_aic7890_setup
+ },
+ {
+ ID_AHA_2940U2_OEM,
+ ID_ALL_MASK,
+ ahc_aic7890_setup
+ },
+ {
+ ID_AHA_2940U2,
+ ID_ALL_MASK,
+ ahc_aic7890_setup
+ },
+ {
+ ID_AHA_2950U2B,
+ ID_ALL_MASK,
+ ahc_aic7890_setup
+ },
+ {
+ ID_AIC7890_ARO,
+ ID_ALL_MASK,
+ ahc_aic7890_setup
+ },
+ {
+ ID_AAA_131U2,
+ ID_ALL_MASK,
+ ahc_aic7890_setup
+ },
+ /* aic7892 based controllers */
+ {
+ ID_AHA_29160,
+ ID_ALL_MASK,
+ ahc_aic7892_setup
+ },
+ {
+ ID_AHA_29160_CPQ,
+ ID_ALL_MASK,
+ ahc_aic7892_setup
+ },
+ {
+ ID_AHA_29160N,
+ ID_ALL_MASK,
+ ahc_aic7892_setup
+ },
+ {
+ ID_AHA_29160C,
+ ID_ALL_MASK,
+ ahc_aha29160C_setup
+ },
+ {
+ ID_AHA_29160B,
+ ID_ALL_MASK,
+ ahc_aic7892_setup
+ },
+ {
+ ID_AHA_19160B,
+ ID_ALL_MASK,
+ ahc_aic7892_setup
+ },
+ {
+ ID_AIC7892_ARO,
+ ID_ALL_MASK,
+ ahc_aic7892_setup
+ },
+ {
+ ID_AHA_2915LP,
+ ID_ALL_MASK,
+ ahc_aic7892_setup
+ },
+ /* aic7895 based controllers */
+ {
+ ID_AHA_2940U_DUAL,
+ ID_ALL_MASK,
+ ahc_aic7895_setup
+ },
+ {
+ ID_AHA_3940AU,
+ ID_ALL_MASK,
+ ahc_aic7895_setup
+ },
+ {
+ ID_AHA_3944AU,
+ ID_ALL_MASK,
+ ahc_aic7895_setup
+ },
+ {
+ ID_AIC7895_ARO,
+ ID_AIC7895_ARO_MASK,
+ ahc_aic7895_setup
+ },
+ /* aic7896/97 based controllers */
+ {
+ ID_AHA_3950U2B_0,
+ ID_ALL_MASK,
+ ahc_aic7896_setup
+ },
+ {
+ ID_AHA_3950U2B_1,
+ ID_ALL_MASK,
+ ahc_aic7896_setup
+ },
+ {
+ ID_AHA_3950U2D_0,
+ ID_ALL_MASK,
+ ahc_aic7896_setup
+ },
+ {
+ ID_AHA_3950U2D_1,
+ ID_ALL_MASK,
+ ahc_aic7896_setup
+ },
+ {
+ ID_AIC7896_ARO,
+ ID_ALL_MASK,
+ ahc_aic7896_setup
+ },
+ /* aic7899 based controllers */
+ {
+ ID_AHA_3960D,
+ ID_ALL_MASK,
+ ahc_aic7899_setup
+ },
+ {
+ ID_AHA_3960D_CPQ,
+ ID_ALL_MASK,
+ ahc_aic7899_setup
+ },
+ {
+ ID_AIC7899_ARO,
+ ID_ALL_MASK,
+ ahc_aic7899_setup
+ },
+ /* Generic chip probes for devices we don't know 'exactly' */
+ {
+ ID_AIC7850 & ID_DEV_VENDOR_MASK,
+ ID_DEV_VENDOR_MASK,
+ ahc_aic785X_setup
+ },
+ {
+ ID_AIC7855 & ID_DEV_VENDOR_MASK,
+ ID_DEV_VENDOR_MASK,
+ ahc_aic785X_setup
+ },
+ {
+ ID_AIC7859 & ID_DEV_VENDOR_MASK,
+ ID_DEV_VENDOR_MASK,
+ ahc_aic7860_setup
+ },
+ {
+ ID_AIC7860 & ID_DEV_VENDOR_MASK,
+ ID_DEV_VENDOR_MASK,
+ ahc_aic7860_setup
+ },
+ {
+ ID_AIC7870 & ID_DEV_VENDOR_MASK,
+ ID_DEV_VENDOR_MASK,
+ ahc_aic7870_setup
+ },
+ {
+ ID_AIC7880 & ID_DEV_VENDOR_MASK,
+ ID_DEV_VENDOR_MASK,
+ ahc_aic7880_setup
+ },
+ {
+ ID_AIC7890 & ID_9005_GENERIC_MASK,
+ ID_9005_GENERIC_MASK,
+ ahc_aic7890_setup
+ },
+ {
+ ID_AIC7892 & ID_9005_GENERIC_MASK,
+ ID_9005_GENERIC_MASK,
+ ahc_aic7892_setup
+ },
+ {
+ ID_AIC7895 & ID_DEV_VENDOR_MASK,
+ ID_DEV_VENDOR_MASK,
+ ahc_aic7895_setup
+ },
+ {
+ ID_AIC7896 & ID_9005_GENERIC_MASK,
+ ID_9005_GENERIC_MASK,
+ ahc_aic7896_setup
+ },
+ {
+ ID_AIC7899 & ID_9005_GENERIC_MASK,
+ ID_9005_GENERIC_MASK,
+ ahc_aic7899_setup
+ },
+ {
+ ID_AIC7810 & ID_DEV_VENDOR_MASK,
+ ID_DEV_VENDOR_MASK,
+ ahc_raid_setup
+ },
+ {
+ ID_AIC7815 & ID_DEV_VENDOR_MASK,
+ ID_DEV_VENDOR_MASK,
+ ahc_raid_setup
+ }
+};
+const u_int ahc_num_pci_devs = NUM_ELEMENTS(ahc_pci_ident_table);
+
#define AHC_394X_SLOT_CHANNEL_A 4
#define AHC_394X_SLOT_CHANNEL_B 5
@@ -89,425 +599,201 @@
#define AHC_398X_SLOT_CHANNEL_B 8
#define AHC_398X_SLOT_CHANNEL_C 12
-#define EXROMBADR 0x30
-#define EXROMEN 0x00000001UL /* External Rom Enable */
+#define AHC_494X_SLOT_CHANNEL_A 4
+#define AHC_494X_SLOT_CHANNEL_B 5
+#define AHC_494X_SLOT_CHANNEL_C 6
+#define AHC_494X_SLOT_CHANNEL_D 7
#define DEVCONFIG 0x40
-#define SCBSIZE32 0x00010000UL /* aic789X only */
-#define REXTVALID 0x00001000UL /* ultra cards only */
-#define MPORTMODE 0x00000400UL /* aic7870+ only */
-#define RAMPSM 0x00000200UL /* aic7870+ only */
-#define VOLSENSE 0x00000100UL
-#define PCI64BIT 0x00000080UL /* 64Bit PCI bus (Ultra2 Only)*/
-#define SCBRAMSEL 0x00000080UL
-#define MRDCEN 0x00000040UL
-#define EXTSCBTIME 0x00000020UL /* aic7870 only */
-#define EXTSCBPEN 0x00000010UL /* aic7870 only */
-#define BERREN 0x00000008UL
-#define DACEN 0x00000004UL
-#define STPWLEVEL 0x00000002UL
-#define DIFACTNEGEN 0x00000001UL /* aic7870 only */
+#define PCIERRGENDIS 0x80000000ul
+#define SCBSIZE32 0x00010000ul /* aic789X only */
+#define REXTVALID 0x00001000ul /* ultra cards only */
+#define MPORTMODE 0x00000400ul /* aic7870+ only */
+#define RAMPSM 0x00000200ul /* aic7870+ only */
+#define VOLSENSE 0x00000100ul
+#define PCI64BIT 0x00000080ul /* 64Bit PCI bus (Ultra2 Only)*/
+#define SCBRAMSEL 0x00000080ul
+#define MRDCEN 0x00000040ul
+#define EXTSCBTIME 0x00000020ul /* aic7870 only */
+#define EXTSCBPEN 0x00000010ul /* aic7870 only */
+#define BERREN 0x00000008ul
+#define DACEN 0x00000004ul
+#define STPWLEVEL 0x00000002ul
+#define DIFACTNEGEN 0x00000001ul /* aic7870 only */
#define CSIZE_LATTIME 0x0c
-#define CACHESIZE 0x0000003fUL /* only 5 bits */
-#define LATTIME 0x0000ff00UL
-
-static int ahc_ext_scbram_present(struct ahc_softc *ahc);
+#define CACHESIZE 0x0000003ful /* only 5 bits */
+#define LATTIME 0x0000ff00ul
+
+/* PCI STATUS definitions */
+#define DPE 0x80
+#define SSE 0x40
+#define RMA 0x20
+#define RTA 0x10
+#define STA 0x08
+#define DPR 0x01
+
+static int ahc_9005_subdevinfo_valid(uint16_t vendor, uint16_t device,
+ uint16_t subvendor, uint16_t subdevice);
+static int ahc_ext_scbram_present(struct ahc_softc *ahc);
static void ahc_scbram_config(struct ahc_softc *ahc, int enable,
int pcheck, int fast, int large);
static void ahc_probe_ext_scbram(struct ahc_softc *ahc);
-static void check_extport(struct ahc_softc *ahc, u_int *sxfrctl1);
-static void configure_termination(struct ahc_softc *ahc,
- struct seeprom_descriptor *sd,
- u_int adapter_control,
- u_int *sxfrctl1);
-static void ahc_new_term_detect(struct ahc_softc *ahc,
- int *enableSEC_low,
- int *enableSEC_high,
- int *enablePRI_low,
- int *enablePRI_high,
- int *eeprom_present);
-static void aic787X_cable_detect(struct ahc_softc *ahc,
- int *internal50_present,
- int *internal68_present,
- int *externalcable_present,
- int *eeprom_present);
-static void aic785X_cable_detect(struct ahc_softc *ahc,
- int *internal50_present,
- int *externalcable_present,
- int *eeprom_present);
-static void write_brdctl(struct ahc_softc *ahc, u_int8_t value);
-static u_int8_t read_brdctl(struct ahc_softc *ahc);
-
-int ahc_do_pci_config(struct ahc_softc *ahc);
-
-void load_seeprom(struct ahc_softc *ahc);
-static int acquire_seeprom(struct ahc_softc *ahc,
- struct seeprom_descriptor *sd);
-static void release_seeprom(struct seeprom_descriptor *sd);
-static int verify_cksum(struct seeprom_config *);
-int ahc_probe_scbs(struct ahc_softc *ahc);
-
-static u_char aic3940_count;
int ahc_pci_probe(struct device *, void *, void *);
void ahc_pci_attach(struct device *, struct device *, void *);
+
struct cfattach ahc_pci_ca = {
sizeof(struct ahc_softc), ahc_pci_probe, ahc_pci_attach
};
-const struct pci_matchid ahc_pci_devices[] = {
- { PCI_VENDOR_ADP, PCI_PRODUCT_ADP_AIC7810 },
- { PCI_VENDOR_ADP, PCI_PRODUCT_ADP_AIC7850 },
- { PCI_VENDOR_ADP, PCI_PRODUCT_ADP_AIC7855 },
- { PCI_VENDOR_ADP, PCI_PRODUCT_ADP_AIC7860 },
- { PCI_VENDOR_ADP, PCI_PRODUCT_ADP_2940AU },
- { PCI_VENDOR_ADP, PCI_PRODUCT_ADP_AIC7870 },
- { PCI_VENDOR_ADP, PCI_PRODUCT_ADP_2930CU },
- { PCI_VENDOR_ADP, PCI_PRODUCT_ADP_2940 },
- { PCI_VENDOR_ADP, PCI_PRODUCT_ADP_3940 },
- { PCI_VENDOR_ADP, PCI_PRODUCT_ADP_3985 },
- { PCI_VENDOR_ADP, PCI_PRODUCT_ADP_2944 },
- { PCI_VENDOR_ADP, PCI_PRODUCT_ADP_AIC7880 },
- { PCI_VENDOR_ADP, PCI_PRODUCT_ADP_2940U },
- { PCI_VENDOR_ADP, PCI_PRODUCT_ADP_3940U },
- { PCI_VENDOR_ADP, PCI_PRODUCT_ADP_398XU },
- { PCI_VENDOR_ADP, PCI_PRODUCT_ADP_2944U },
- { PCI_VENDOR_ADP, PCI_PRODUCT_ADP_2940UWPro },
- { PCI_VENDOR_ADP, PCI_PRODUCT_ADP_7895 },
- { PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_AAA131U2 },
- { PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_AIC7890 },
- { PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_2940U2 },
- { PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_2930U2 },
- { PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_AIC7892 },
- { PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_29160 },
- { PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_19160B },
- { PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_3950U2B },
- { PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_3950U2D },
- { PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_AIC7896 },
- { PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_AIC7899B },
- { PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_AIC7899D },
- { PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_AIC7899F },
- { PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_AIC7899 },
- { PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_3960D },
-};
+const struct ahc_pci_identity *
+ahc_find_pci_device(id, subid, func)
+ pcireg_t id, subid;
+ u_int func;
+{
+ u_int64_t full_id;
+ const struct ahc_pci_identity *entry;
+ u_int i;
+
+ full_id = ahc_compose_id(PCI_PRODUCT(id), PCI_VENDOR(id),
+ PCI_PRODUCT(subid), PCI_VENDOR(subid));
+
+ /*
+ * If the second function is not hooked up, ignore it.
+ * Unfortunately, not all MB vendors implement the
+ * subdevice ID as per the Adaptec spec, so do our best
+ * to sanity check it prior to accepting the subdevice
+ * ID as valid.
+ */
+ if (func > 0
+ && ahc_9005_subdevinfo_valid(PCI_VENDOR(id), PCI_PRODUCT(id),
+ PCI_VENDOR(subid), PCI_PRODUCT(subid))
+ && SUBID_9005_MFUNCENB(PCI_PRODUCT(subid)) == 0)
+ return (NULL);
+
+ for (i = 0; i < ahc_num_pci_devs; i++) {
+ entry = &ahc_pci_ident_table[i];
+ if (entry->full_id == (full_id & entry->id_mask))
+ return (entry);
+ }
+ return (NULL);
+}
int
ahc_pci_probe(parent, match, aux)
-struct device *parent;
-void *match, *aux;
+ struct device *parent;
+ void *match, *aux;
{
- return (pci_matchbyid((struct pci_attach_args *)aux, ahc_pci_devices,
- sizeof(ahc_pci_devices)/sizeof(ahc_pci_devices[0])));
+ struct pci_attach_args *pa = aux;
+ const struct ahc_pci_identity *entry;
+ pcireg_t subid;
+
+ subid = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG);
+ entry = ahc_find_pci_device(pa->pa_id, subid, pa->pa_function);
+ return (entry != NULL && entry->setup != NULL) ? 1 : 0;
}
void
ahc_pci_attach(parent, self, aux)
-struct device *parent, *self;
-void *aux;
+ struct device *parent, *self;
+ void *aux;
{
struct pci_attach_args *pa = aux;
- struct ahc_softc *ahc = (void *)self;
- pcireg_t devconfig;
- pcireg_t command;
+ const struct ahc_pci_identity *entry;
+ struct ahc_softc *ahc = (void *)self;
+ pcireg_t command;
+ u_int our_id = 0;
+ u_int sxfrctl1;
+ u_int scsiseq;
+ u_int sblkctl;
+ uint8_t dscommand0;
+ uint32_t devconfig;
+ int error;
+ pcireg_t subid;
+ int ioh_valid, memh_valid;
+ bus_space_tag_t st, iot;
+ bus_space_handle_t sh, ioh;
+#ifdef AHC_ALLOW_MEMIO
+ bus_space_tag_t memt;
+ bus_space_handle_t memh;
+ pcireg_t memtype;
+#endif
+ pci_intr_handle_t ih;
+ const char *intrstr;
+ struct ahc_pci_busdata *bd;
- /* setup the PCI stuff */
ahc->dev_softc = pa;
- /*
- * We really don't allocate our softc, but
- * we need to do the initialization. And this
- * also allocates the platform_data structure.
- */
- ahc_alloc(ahc, NULL);
ahc_set_name(ahc, ahc->sc_dev.dv_xname);
- ahc_set_unit(ahc, ahc->sc_dev.dv_unit);
-
- /* set dma tags */
ahc->parent_dmat = pa->pa_dmat;
- ahc->buffer_dmat = pa->pa_dmat;
- ahc->shared_data_dmat = pa->pa_dmat;
-
- /* card specific setup */
- switch (PCI_VENDOR(pa->pa_id)) {
- case PCI_VENDOR_ADP:
- switch (PCI_PRODUCT(pa->pa_id)) {
- case PCI_PRODUCT_ADP_7895:
- ahc->channel = pa->pa_function == 1 ? 'B' : 'A';
- /* The 'C' revision of the aic7895
- has a few additional features */
- if (PCI_REVISION(pa->pa_class) >= 4){
- ahc->chip |= AHC_AIC7895C;
- } else {
- ahc->chip |= AHC_AIC7895;
- }
- break;
- case PCI_PRODUCT_ADP_3940U:
- case PCI_PRODUCT_ADP_3940:
- if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ADP_3940U) {
- ahc->chip |= AHC_AIC7880;
- } else {
- ahc->chip |= AHC_AIC7870;
- }
- aic3940_count++;
- if (!(aic3940_count & 0x01))
- /* Even count implies second channel */
- ahc->channel = 'B';
- break;
- case PCI_PRODUCT_ADP_2940UWPro:
- ahc->flags |= AHC_INT50_SPEEDFLEX;
- /* fall through */
- case PCI_PRODUCT_ADP_AIC7880:
- case PCI_PRODUCT_ADP_398XU: /* XXX */
- case PCI_PRODUCT_ADP_2944U:
- case PCI_PRODUCT_ADP_2940U:
- ahc->chip |= AHC_AIC7880;
- break;
- case PCI_PRODUCT_ADP_AIC7870:
- case PCI_PRODUCT_ADP_2944:
- case PCI_PRODUCT_ADP_2940:
- ahc->chip |= AHC_AIC7870;
- break;
- case PCI_PRODUCT_ADP_AIC7860:
- case PCI_PRODUCT_ADP_2940AU:
- ahc->chip |= AHC_AIC7860;
- break;
- case PCI_PRODUCT_ADP_AIC7855:
- case PCI_PRODUCT_ADP_AIC7850:
- ahc->chip |= AHC_AIC7850;
- break;
- default:
- /* TTT */
- break;
- }
- break;
- case PCI_VENDOR_ADP2:
- switch (PCI_PRODUCT(pa->pa_id)) {
- case PCI_PRODUCT_ADP2_AIC7890:
- case PCI_PRODUCT_ADP2_2940U2:
- case PCI_PRODUCT_ADP2_2930U2:
- case PCI_PRODUCT_ADP2_AAA131U2:
- ahc->chip |= AHC_AIC7890;
- break;
- case PCI_PRODUCT_ADP2_AIC7892:
- case PCI_PRODUCT_ADP2_29160:
- case PCI_PRODUCT_ADP2_19160B:
- ahc->chip |= AHC_AIC7892;
- break;
- case PCI_PRODUCT_ADP2_3950U2B:
- case PCI_PRODUCT_ADP2_3950U2D:
- case PCI_PRODUCT_ADP2_AIC7896:
- ahc->chip |= AHC_AIC7896;
- ahc->channel = pa->pa_function == 1 ? 'B' : 'A';
- devconfig = ahc_pci_read_config(ahc->dev_softc,
- DEVCONFIG, 4);
- /* turn off 64 bit for now XXX smurph */
- devconfig &= ~PCI64BIT;
- ahc_pci_write_config(ahc->dev_softc,
- DEVCONFIG, devconfig, 4);
- break;
- case PCI_PRODUCT_ADP2_AIC7899:
- case PCI_PRODUCT_ADP2_3960D:
- ahc->chip |= AHC_AIC7899;
- ahc->channel = pa->pa_function == 1 ? 'B' : 'A';
- break;
- default:
- /* TTT */
- break;
- }
- }
-
- /* chip specific setup */
- switch(ahc->chip){
- case AHC_AIC7850:
- case AHC_AIC7855:
- case AHC_AIC7859:
- ahc->features = AHC_AIC7850_FE;
- ahc->bugs |= AHC_TMODE_WIDEODD_BUG|AHC_CACHETHEN_BUG|AHC_PCI_MWI_BUG;
- if (PCI_REVISION(pa->pa_class) >= 1)
- ahc->bugs |= AHC_PCI_2_1_RETRY_BUG;
- break;
- case AHC_AIC7860:
- ahc->features = AHC_AIC7860_FE;
- ahc->bugs |= AHC_TMODE_WIDEODD_BUG|AHC_CACHETHEN_BUG|AHC_PCI_MWI_BUG;
- if (PCI_REVISION(pa->pa_class) >= 1)
- ahc->bugs |= AHC_PCI_2_1_RETRY_BUG;
- break;
- case AHC_AIC7870:
- ahc->features = AHC_AIC7870_FE;
- ahc->bugs |= AHC_TMODE_WIDEODD_BUG|AHC_CACHETHEN_BUG|AHC_PCI_MWI_BUG;
- break;
- case AHC_AIC7880:
- ahc->features = AHC_AIC7880_FE;
- ahc->bugs |= AHC_TMODE_WIDEODD_BUG;
- if (PCI_REVISION(pa->pa_class) >= 1) {
- ahc->bugs |= AHC_PCI_2_1_RETRY_BUG;
- } else {
- ahc->bugs |= AHC_CACHETHEN_BUG|AHC_PCI_MWI_BUG;
- }
- break;
- case AHC_AIC7895:
- ahc->features = AHC_AIC7895_FE;
- ahc->flags |= AHC_NEWEEPROM_FMT;
- /*
- * The BIOS disables the use of MWI transactions
- * since it does not have the MWI bug work around
- * we have. Disabling MWI reduces performance, so
- * turn it on again.
- */
- command = pci_conf_read(pa->pa_pc, pa->pa_tag,
- PCI_COMMAND_STATUS_REG);
- command |= PCI_COMMAND_INVALIDATE_ENABLE;
- pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
- command);
- ahc->bugs |= AHC_TMODE_WIDEODD_BUG|AHC_PCI_2_1_RETRY_BUG
- | AHC_CACHETHEN_BUG | AHC_PCI_MWI_BUG;
- break;
- case AHC_AIC7895C:
- ahc->features = AHC_AIC7895C_FE;
- ahc->flags |= AHC_NEWEEPROM_FMT;
- ahc->bugs |= AHC_TMODE_WIDEODD_BUG|AHC_PCI_2_1_RETRY_BUG
- | AHC_CACHETHEN_BUG;
- break;
- case AHC_AIC7890:
- ahc->features = AHC_AIC7890_FE;
- ahc->flags |= AHC_NEWEEPROM_FMT;
- if (PCI_REVISION(pa->pa_class) == 0)
- ahc->bugs |= AHC_AUTOFLUSH_BUG|AHC_CACHETHEN_BUG;
- break;
- case AHC_AIC7892:
- ahc->features = AHC_AIC7892_FE;
- ahc->flags |= AHC_NEWEEPROM_FMT;
- ahc->bugs |= AHC_SCBCHAN_UPLOAD_BUG;
- break;
- case AHC_AIC7896:
- ahc->features = AHC_AIC7896_FE;
- ahc->flags |= AHC_NEWEEPROM_FMT;
- ahc->bugs |= AHC_CACHETHEN_DIS_BUG;
- break;
- case AHC_AIC7899:
- ahc->features = AHC_AIC7899_FE;
- ahc->flags |= AHC_NEWEEPROM_FMT;
- ahc->bugs |= AHC_SCBCHAN_UPLOAD_BUG;
- break;
- default:
- break;
- }
- /* setup the PCI interrupt */
- ahc->bus_intr = ahc_pci_intr;
- ahc->unsolicited_ints = 0;
+ command = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
+ subid = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG);
+ entry = ahc_find_pci_device(pa->pa_id, subid, pa->pa_function);
+ if (entry == NULL)
+ return;
- if(ahc_do_pci_config(ahc)){
- ahc_free(ahc);
+ /* Keep information about the PCI bus */
+ bd = malloc(sizeof (struct ahc_pci_busdata), M_DEVBUF, M_NOWAIT);
+ if (bd == NULL) {
+ printf("%s: unable to allocate bus-specific data\n", ahc_name(ahc));
return;
}
-
- ahc_attach(ahc);
-}
+ memset(bd, 0, sizeof(struct ahc_pci_busdata));
+
+ bd->pc = pa->pa_pc;
+ bd->tag = pa->pa_tag;
+ bd->func = pa->pa_function;
+ bd->dev = pa->pa_device;
+ bd->class = pa->pa_class;
+
+ ahc->bd = bd;
+
+ error = entry->setup(ahc);
+ if (error != 0)
+ return;
+
+ ioh_valid = memh_valid = 0;
-int
-ahc_pci_map_registers(ahc)
- struct ahc_softc *ahc;
-{
- pcireg_t command;
- int ioh_valid;
- bus_space_tag_t iot;
- bus_space_handle_t ioh;
- struct pci_attach_args *pa = ahc->dev_softc;
-
- command = ahc_pci_read_config(ahc->dev_softc,
- PCI_COMMAND_STATUS_REG, 4);
#ifdef AHC_ALLOW_MEMIO
- /*
- * attempt to use memory mapping on hardware that supports it.
- * e.g powerpc XXX - smurph
- *
- * Note: If this fails, IO mapping is used.
- */
- if ((command & PCI_COMMAND_MEM_ENABLE) != 0) {
- pcireg_t memtype;
- memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, AHC_PCI_MEMADDR);
- switch (memtype) {
- case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT:
- case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT:
- ioh_valid = (pci_mapreg_map(pa, AHC_PCI_MEMADDR,
- memtype, 0, &iot, &ioh, NULL, NULL, 0) == 0);
- break;
- default:
- ioh_valid = 0;
- }
- if (ioh_valid) {
- /*
- * Do a quick test to see if memory mapped
- * I/O is functioning correctly.
- */
- ahc->tag = iot;
- ahc->bsh = ioh;
- if (ahc_inb(ahc, HCNTRL) == 0xFF) {
- /* nope, use I/O mapping */
- ioh_valid = 0;
- } else {
- /* Using memory mapping, disable I/O mapping */
- command &= ~PCI_COMMAND_IO_ENABLE;
- ahc_pci_write_config(ahc->dev_softc,
- PCI_COMMAND_STATUS_REG,
- command, 4);
- }
- }
+ memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, AHC_PCI_MEMADDR);
+ switch (memtype) {
+ case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT:
+ case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT:
+ memh_valid = (pci_mapreg_map(pa, AHC_PCI_MEMADDR,
+ memtype, 0, &memt, &memh, NULL, NULL, 0) == 0);
+ break;
+ default:
+ memh_valid = 0;
}
-
- if (!ioh_valid) /* try to drop back to IO mapping */
#endif
- {
- ioh_valid = (pci_mapreg_map(pa, AHC_PCI_IOADDR,
- PCI_MAPREG_TYPE_IO, 0, &iot, &ioh, NULL, NULL, 0) == 0);
-
- /* Using I/O mapping, disable memory mapping */
- command &= ~PCI_COMMAND_MEM_ENABLE;
- ahc_pci_write_config(ahc->dev_softc,
- PCI_COMMAND_STATUS_REG,
- command, 4);
- }
+ ioh_valid = (pci_mapreg_map(pa, AHC_PCI_IOADDR,
+ PCI_MAPREG_TYPE_IO, 0, &iot,
+ &ioh, NULL, NULL, 0) == 0);
+#if 0
+ printf("%s: mem mapping: memt 0x%x, memh 0x%x, iot 0x%x, ioh 0x%lx\n",
+ ahc_name(ahc), memt, (u_int32_t)memh, (u_int32_t)iot, ioh);
+#endif
- if (!ioh_valid) {
- /* Game Over. Insert coin... */
+ if (ioh_valid) {
+ st = iot;
+ sh = ioh;
+#ifdef AHC_ALLOW_MEMIO
+ } else if (memh_valid) {
+ st = memt;
+ sh = memh;
+#endif
+ } else {
printf(": unable to map registers\n");
- return (1);
+ return;
}
- ahc->tag = iot;
- ahc->bsh = ioh;
- return (0);
-}
-
-int
-ahc_do_pci_config(ahc)
- struct ahc_softc *ahc;
-{
- pcireg_t command;
- u_int our_id = 0;
- u_int sxfrctl1;
- u_int scsiseq;
- u_int dscommand0;
- int error;
- int opri;
- uint8_t sblkctl;
-
+ ahc->tag = st;
+ ahc->bsh = sh;
ahc->chip |= AHC_PCI;
-#if 0
- ahc_power_state_change(ahc, AHC_POWER_STATE_D0);
-#endif
- error = ahc_pci_map_registers(ahc);
- if (error != 0)
- return (error);
- /*
- * Registers are mapped. Now it is safe to use
- * the ahc_inb and ahc_outb macros.
- */
-
- /*
+ /*
* Before we continue probing the card, ensure that
* its interrupts are *disabled*. We don't want
* a misstep to hang the machine in an interrupt
@@ -516,34 +802,53 @@ ahc_do_pci_config(ahc)
ahc_intr_enable(ahc, FALSE);
/*
+ * XXX somehow reading this once fails on some sparc64 systems.
+ * This may be a problem in the sparc64 PCI code. Doing it
+ * twice works around it.
+ */
+ devconfig = pci_conf_read(pa->pa_pc, pa->pa_tag, DEVCONFIG);
+ devconfig = pci_conf_read(pa->pa_pc, pa->pa_tag, DEVCONFIG);
+
+ /*
* If we need to support high memory, enable dual
* address cycles. This bit must be set to enable
* high address bit generation even if we are on a
* 64bit bus (PCI64BIT set in devconfig).
*/
if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) {
- pcireg_t devconfig;
- if (bootverbose)
+ if (1/*bootverbose*/)
printf("%s: Enabling 39Bit Addressing\n",
ahc_name(ahc));
- devconfig = ahc_pci_read_config(ahc->dev_softc, DEVCONFIG, 4);
devconfig |= DACEN;
- ahc_pci_write_config(ahc->dev_softc, DEVCONFIG, devconfig, 4);
}
+ /* Ensure that pci error generation, a test feature, is disabled. */
+ devconfig |= PCIERRGENDIS;
+
+ pci_conf_write(pa->pa_pc, pa->pa_tag, DEVCONFIG, devconfig);
+
/* Ensure busmastering is enabled */
- command = ahc_pci_read_config(ahc->dev_softc, PCI_COMMAND_STATUS_REG, 4);
- command |= PCI_COMMAND_MASTER_ENABLE;
+ command |= PCI_COMMAND_MASTER_ENABLE;;
+ pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, command);
+
+ /*
+ * Disable PCI parity error reporting. Users typically
+ * do this to work around broken PCI chipsets that get
+ * the parity timing wrong and thus generate lots of spurious
+ * errors.
+ */
+ if ((ahc->flags & AHC_DISABLE_PCI_PERR) != 0)
+ command &= ~PCI_COMMAND_PARITY_ENABLE;
+ pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, command);
- ahc_pci_write_config(ahc->dev_softc, PCI_COMMAND_STATUS_REG, command, 4);
-
/* On all PCI adapters, we allow SCB paging */
ahc->flags |= AHC_PAGESCBS;
-
error = ahc_softc_init(ahc);
if (error != 0)
- return (error);
+ goto error_out;
+
+ ahc->bus_intr = ahc_pci_intr;
/* Remember how the card was setup in case there is no SEEPROM */
if ((ahc_inb(ahc, HCNTRL) & POWRDN) == 0) {
@@ -562,7 +867,7 @@ ahc_do_pci_config(ahc)
error = ahc_reset(ahc);
if (error != 0)
- return (ENXIO);
+ goto error_out;
if ((ahc->features & AHC_DT) != 0) {
u_int sfunct;
@@ -579,12 +884,27 @@ ahc_do_pci_config(ahc)
|TARGCRCENDEN);
}
- /*
- * Protect ourself from spurrious interrupts during
- * initialization.
- */
- opri = splbio();
-
+ if (pci_intr_map(pa, &ih)) {
+ printf("%s: couldn't map interrupt\n", ahc_name(ahc));
+ ahc_free(ahc);
+ return;
+ }
+ intrstr = pci_intr_string(pa->pa_pc, ih);
+ ahc->ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO,
+ ahc_platform_intr, ahc, ahc->sc_dev.dv_xname);
+ if (ahc->ih == NULL) {
+ printf("%s: couldn't establish interrupt",
+ ahc->sc_dev.dv_xname);
+ if (intrstr != NULL)
+ printf(" at %s", intrstr);
+ printf("\n");
+ ahc_free(ahc);
+ return;
+ }
+ printf("\n");
+ if (intrstr != NULL)
+ printf("%s: interrupting at %s\n", ahc_name(ahc), intrstr);
+
dscommand0 = ahc_inb(ahc, DSCOMMAND0);
dscommand0 |= MPARCKEN|CACHETHEN;
if ((ahc->features & AHC_ULTRA2) != 0) {
@@ -607,34 +927,38 @@ ahc_do_pci_config(ahc)
dscommand0 &= ~CACHETHEN;
ahc_outb(ahc, DSCOMMAND0, dscommand0);
-
- ahc->pci_cachesize = ahc_pci_read_config(ahc->dev_softc,
- CSIZE_LATTIME, 4) & CACHESIZE;
+
+ ahc->pci_cachesize =
+ pci_conf_read(pa->pa_pc, pa->pa_tag, CSIZE_LATTIME) & CACHESIZE;
ahc->pci_cachesize *= 4;
if ((ahc->bugs & AHC_PCI_2_1_RETRY_BUG) != 0
- && ahc->pci_cachesize == 4) {
- u_int csl = ahc_pci_read_config(ahc->dev_softc,
- CSIZE_LATTIME, 4);
- csl &= ~CACHESIZE;
- ahc_pci_write_config(ahc->dev_softc, CSIZE_LATTIME, csl, 4);
+ && ahc->pci_cachesize == 4) {
+ pci_conf_write(pa->pa_pc, pa->pa_tag, CSIZE_LATTIME, 0);
ahc->pci_cachesize = 0;
}
/*
- * We cannot perform ULTRA speeds without the presense
+ * We cannot perform ULTRA speeds without the presence
* of the external precision resistor.
*/
if ((ahc->features & AHC_ULTRA) != 0) {
uint32_t devconfig;
- devconfig = ahc_pci_read_config(ahc->dev_softc, DEVCONFIG, 4);
+ devconfig = pci_conf_read(pa->pa_pc, pa->pa_tag, DEVCONFIG);
if ((devconfig & REXTVALID) == 0)
ahc->features &= ~AHC_ULTRA;
}
+ ahc->seep_config = malloc(sizeof(*ahc->seep_config),
+ M_DEVBUF, M_NOWAIT);
+ if (ahc->seep_config == NULL)
+ goto error_out;
+
+ memset(ahc->seep_config, 0, sizeof(*ahc->seep_config));
+
/* See if we have a SEEPROM and perform auto-term */
- check_extport(ahc, &sxfrctl1);
+ ahc_check_extport(ahc, &sxfrctl1);
/*
* Take the LED out of diagnostic mode
@@ -655,7 +979,8 @@ ahc_do_pci_config(ahc)
* a SEEPROM.
*/
/* See if someone else set us up already */
- if (scsiseq != 0) {
+ if ((ahc->flags & AHC_NO_BIOS_INIT) == 0
+ && scsiseq != 0) {
printf("%s: Using left over BIOS settings\n",
ahc_name(ahc));
ahc->flags &= ~AHC_USEDEFAULTS;
@@ -687,63 +1012,53 @@ ahc_do_pci_config(ahc)
if ((sxfrctl1 & STPWEN) != 0)
ahc->flags |= AHC_TERM_ENB_A;
- /* Core initialization */
- error = ahc_init(ahc);
- if (error != 0)
- return (error);
-
- /* Special func to force negotiation */
- ahc_force_neg(ahc);
-
- /*
- * Link this softc in with all other ahc instances.
- */
- ahc_softc_insert(ahc);
+ if (ahc_init(ahc))
+ goto error_out;
- /*
- * Allow interrupts now that we are completely setup.
- */
- error = ahc_pci_map_int(ahc);
- if (error != 0)
- return (error);
+ ahc_attach(ahc);
- ahc_intr_enable(ahc, TRUE);
- splx(opri);
+ return;
- return (0);
+ error_out:
+ ahc_free(ahc);
+ return;
}
-int
-ahc_pci_map_int(ahc)
- struct ahc_softc *ahc;
+static int
+ahc_9005_subdevinfo_valid(uint16_t device, uint16_t vendor,
+ uint16_t subdevice, uint16_t subvendor)
{
- const char *intrstr = NULL;
- pci_intr_handle_t ih;
- struct pci_attach_args *pa = ahc->dev_softc;
-
- if (pci_intr_map(pa, &ih)) {
- printf(": couldn't map interrupt\n");
- return 1;
- }
- intrstr = pci_intr_string(pa->pa_pc, ih);
-
- ahc->platform_data->ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO,
- ahc_platform_intr, ahc,
- ahc->sc_dev.dv_xname);
-
- if (ahc->platform_data->ih == NULL) {
- printf(": couldn't establish interrupt");
- if (intrstr != NULL)
- printf(" at %s", intrstr);
- printf("\n");
- return 1;
+ int result;
+
+ /* Default to invalid. */
+ result = 0;
+ if (vendor == 0x9005
+ && subvendor == 0x9005
+ && subdevice != device
+ && SUBID_9005_TYPE_KNOWN(subdevice) != 0) {
+
+ switch (SUBID_9005_TYPE(subdevice)) {
+ case SUBID_9005_TYPE_MB:
+ break;
+ case SUBID_9005_TYPE_CARD:
+ case SUBID_9005_TYPE_LCCARD:
+ /*
+ * Currently only trust Adaptec cards to
+ * get the sub device info correct.
+ */
+ if (DEVID_9005_TYPE(device) == DEVID_9005_TYPE_HBA)
+ result = 1;
+ break;
+ case SUBID_9005_TYPE_RAID:
+ break;
+ default:
+ break;
+ }
}
-
- if (intrstr != NULL)
- printf(": %s\n", intrstr);
- return 0;
+ return (result);
}
+
/*
* Test for the presense of external sram in an
* "unshared" configuration.
@@ -755,15 +1070,21 @@ ahc_ext_scbram_present(struct ahc_softc *ahc)
int ramps;
int single_user;
uint32_t devconfig;
-
- chip = ahc->chip & AHC_CHIPID_MASK;
-
- devconfig = ahc_pci_read_config(ahc->dev_softc, DEVCONFIG, 4);
+ chip = ahc->chip & AHC_CHIPID_MASK;
+ devconfig = pci_conf_read(ahc->bd->pc, ahc->bd->tag, DEVCONFIG);
single_user = (devconfig & MPORTMODE) != 0;
if ((ahc->features & AHC_ULTRA2) != 0)
ramps = (ahc_inb(ahc, DSCOMMAND0) & RAMPS) != 0;
+ else if (chip == AHC_AIC7895 || chip == AHC_AIC7895C)
+ /*
+ * External SCBRAM arbitration is flakey
+ * on these chips. Unfortunately this means
+ * we don't use the extra SCB ram space on the
+ * 3940AUW.
+ */
+ ramps = 0;
else if (chip >= AHC_AIC7870)
ramps = (devconfig & RAMPSM) != 0;
else
@@ -778,24 +1099,23 @@ ahc_ext_scbram_present(struct ahc_softc *ahc)
* Enable external scbram.
*/
static void
-ahc_scbram_config(ahc, enable, pcheck, fast, large)
- struct ahc_softc *ahc;
- int enable;
- int pcheck;
- int fast;
- int large;
+ahc_scbram_config(struct ahc_softc *ahc, int enable, int pcheck,
+ int fast, int large)
{
- pcireg_t devconfig;
+ uint32_t devconfig;
if (ahc->features & AHC_MULTI_FUNC) {
/*
* Set the SCB Base addr (highest address bit)
* depending on which channel we are.
*/
- ahc_outb(ahc, SCBBADDR, ahc_get_pci_function(ahc->dev_softc));
+ ahc_outb(ahc, SCBBADDR, ahc->bd->func);
}
- devconfig = ahc_pci_read_config(ahc->dev_softc, DEVCONFIG, 4);
+ ahc->flags &= ~AHC_LSCBS_ENABLED;
+ if (large)
+ ahc->flags |= AHC_LSCBS_ENABLED;
+ devconfig = pci_conf_read(ahc->bd->pc, ahc->bd->tag, DEVCONFIG);
if ((ahc->features & AHC_ULTRA2) != 0) {
u_int dscommand0;
@@ -828,7 +1148,7 @@ ahc_scbram_config(ahc, enable, pcheck, fast, large)
else
devconfig &= ~EXTSCBPEN;
- ahc_pci_write_config(ahc->dev_softc, DEVCONFIG, devconfig, 4);
+ pci_conf_write(ahc->bd->pc, ahc->bd->tag, DEVCONFIG, devconfig);
}
/*
@@ -837,8 +1157,7 @@ ahc_scbram_config(ahc, enable, pcheck, fast, large)
* shared among multiple controllers.
*/
static void
-ahc_probe_ext_scbram(ahc)
- struct ahc_softc *ahc;
+ahc_probe_ext_scbram(struct ahc_softc *ahc)
{
int num_scbs;
int test_num_scbs;
@@ -925,7 +1244,7 @@ done:
/* Clear any latched parity error */
ahc_outb(ahc, CLRINT, CLRPARERR);
ahc_outb(ahc, CLRINT, CLRBRKADRINT);
- if (bootverbose && enable) {
+ if (1/*bootverbose*/ && enable) {
printf("%s: External SRAM, %s access%s, %dbytes/SCB\n",
ahc_name(ahc), fast ? "fast" : "slow",
pcheck ? ", parity checking enabled" : "",
@@ -934,759 +1253,449 @@ done:
ahc_scbram_config(ahc, enable, pcheck, fast, large);
}
+#if 0
/*
- * Check the external port logic for a serial eeprom
- * and termination/cable detection contrls.
+ * Perform some simple tests that should catch situations where
+ * our registers are invalidly mapped.
*/
-static void
-check_extport(ahc, sxfrctl1)
- struct ahc_softc *ahc;
- u_int *sxfrctl1;
+int
+ahc_pci_test_register_access(struct ahc_softc *ahc)
{
- struct seeprom_descriptor sd;
- struct seeprom_config sc;
- u_int scsi_conf;
- u_int adapter_control;
- int have_seeprom;
- int have_autoterm;
-
- sd.sd_tag = ahc->tag;
- sd.sd_bsh = ahc->bsh;
- sd.sd_regsize = 1;
- sd.sd_control_offset = SEECTL;
- sd.sd_status_offset = SEECTL;
- sd.sd_dataout_offset = SEECTL;
+ int error;
+ u_int status1;
+ uint32_t cmd;
+ uint8_t hcntrl;
+
+ error = EIO;
/*
- * For some multi-channel devices, the c46 is simply too
- * small to work. For the other controller types, we can
- * get our information from either SEEPROM type. Set the
- * type to start our probe with accordingly.
+ * Enable PCI error interrupt status, but suppress NMIs
+ * generated by SERR raised due to target aborts.
*/
- if (ahc->flags & AHC_LARGE_SEEPROM)
- sd.sd_chip = C56_66;
- else
- sd.sd_chip = C46;
-
- sd.sd_MS = SEEMS;
- sd.sd_RDY = SEERDY;
- sd.sd_CS = SEECS;
- sd.sd_CK = SEECK;
- sd.sd_DO = SEEDO;
- sd.sd_DI = SEEDI;
+ cmd = pci_conf_read(ahc->bd->pc, ahc->bd->tag, PCIR_COMMAND);
+ pci_conf_write(ahc->bd->pc, ahc->bd->tag, PCIR_COMMAND,
+ cmd & ~PCIM_CMD_SERRESPEN);
- have_seeprom = acquire_seeprom(ahc, &sd);
- if (have_seeprom) {
+ /*
+ * First a simple test to see if any
+ * registers can be read. Reading
+ * HCNTRL has no side effects and has
+ * at least one bit that is guaranteed to
+ * be zero so it is a good register to
+ * use for this test.
+ */
+ hcntrl = ahc_inb(ahc, HCNTRL);
+ if (hcntrl == 0xFF)
+ goto fail;
- if (bootverbose)
- printf("%s: Reading SEEPROM...", ahc_name(ahc));
+ /*
+ * Next create a situation where write combining
+ * or read prefetching could be initiated by the
+ * CPU or host bridge. Our device does not support
+ * either, so look for data corruption and/or flagged
+ * PCI errors.
+ */
+ ahc_outb(ahc, HCNTRL, hcntrl|PAUSE);
+ while (ahc_is_paused(ahc) == 0)
+ ;
+ ahc_outb(ahc, SEQCTL, PERRORDIS);
+ ahc_outb(ahc, SCBPTR, 0);
+ ahc_outl(ahc, SCB_BASE, 0x5aa555aa);
+ if (ahc_inl(ahc, SCB_BASE) != 0x5aa555aa)
+ goto fail;
+
+ status1 = pci_conf_read(ahc->bd->pc, ahc->bd->tag,
+ PCI_COMMAND_STATUS_REG + 1);
+ if ((status1 & STA) != 0)
+ goto fail;
+
+ error = 0;
+
+fail:
+ /* Silently clear any latched errors. */
+ status1 = pci_conf_read(ahc->bd->pc, ahc->bd->tag, PCI_COMMAND_STATUS_REG + 1);
+ ahc_pci_write_config(ahc->dev_softc, PCIR_STATUS + 1,
+ status1, /*bytes*/1);
+ ahc_outb(ahc, CLRINT, CLRPARERR);
+ ahc_outb(ahc, SEQCTL, PERRORDIS|FAILDIS);
+ ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, cmd, /*bytes*/2);
+ return (error);
+}
+#endif
- for (;;) {
- u_int start_addr;
+void
+ahc_pci_intr(struct ahc_softc *ahc)
+{
+ u_int error;
+ u_int status1;
- start_addr = 32 * (ahc->channel - 'A');
+ error = ahc_inb(ahc, ERROR);
+ if ((error & PCIERRSTAT) == 0)
+ return;
- have_seeprom = read_seeprom(&sd, (uint16_t *)&sc,
- start_addr, sizeof(sc)/2);
+ status1 = pci_conf_read(ahc->bd->pc, ahc->bd->tag, PCI_COMMAND_STATUS_REG);
- if (have_seeprom)
- have_seeprom = verify_cksum(&sc);
+ printf("%s: PCI error Interrupt at seqaddr = 0x%x\n",
+ ahc_name(ahc),
+ ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8));
- if (have_seeprom != 0 || sd.sd_chip == C56_66) {
- if (bootverbose) {
- if (have_seeprom == 0)
- printf ("checksum error\n");
- else
- printf ("done.\n");
- }
- break;
- }
- sd.sd_chip = C56_66;
- }
- release_seeprom(&sd);
+ if (status1 & DPE) {
+ printf("%s: Data Parity Error Detected during address "
+ "or write data phase\n", ahc_name(ahc));
}
-
- if (!have_seeprom) {
- /*
- * Pull scratch ram settings and treat them as
- * if they are the contents of an seeprom if
- * the 'ADPT' signature is found in SCB2.
- * We manually compose the data as 16bit values
- * to avoid endian issues.
- */
- ahc_outb(ahc, SCBPTR, 2);
- if (ahc_inb(ahc, SCB_BASE) == 'A'
- && ahc_inb(ahc, SCB_BASE + 1) == 'D'
- && ahc_inb(ahc, SCB_BASE + 2) == 'P'
- && ahc_inb(ahc, SCB_BASE + 3) == 'T') {
- uint16_t *sc_data;
- int i;
-
- sc_data = (uint16_t *)&sc;
- for (i = 0; i < 32; i++) {
- uint16_t val;
- int j;
-
- j = i * 2;
- val = ahc_inb(ahc, SRAM_BASE + j)
- | ahc_inb(ahc, SRAM_BASE + j + 1) << 8;
- }
- have_seeprom = verify_cksum(&sc);
- }
- /*
- * Clear any SCB parity errors in case this data and
- * its associated parity was not initialized by the BIOS
- */
- ahc_outb(ahc, CLRINT, CLRPARERR);
- ahc_outb(ahc, CLRINT, CLRBRKADRINT);
+ if (status1 & SSE) {
+ printf("%s: Signal System Error Detected\n", ahc_name(ahc));
+ }
+ if (status1 & RMA) {
+ printf("%s: Received a Master Abort\n", ahc_name(ahc));
+ }
+ if (status1 & RTA) {
+ printf("%s: Received a Target Abort\n", ahc_name(ahc));
+ }
+ if (status1 & STA) {
+ printf("%s: Signaled a Target Abort\n", ahc_name(ahc));
+ }
+ if (status1 & DPR) {
+ printf("%s: Data Parity Error has been reported via PERR#\n",
+ ahc_name(ahc));
}
- if (!have_seeprom) {
- if (bootverbose)
- printf("%s: No SEEPROM available.\n", ahc_name(ahc));
- ahc->flags |= AHC_USEDEFAULTS;
- } else {
- /*
- * Put the data we've collected down into SRAM
- * where ahc_init will find it.
- */
- int i;
- int max_targ = sc.max_targets & CFMAXTARG;
- uint16_t discenable;
- uint16_t ultraenb;
-
- discenable = 0;
- ultraenb = 0;
- if ((sc.adapter_control & CFULTRAEN) != 0) {
- /*
- * Determine if this adapter has a "newstyle"
- * SEEPROM format.
- */
- for (i = 0; i < max_targ; i++) {
- if ((sc.device_flags[i] & CFSYNCHISULTRA) != 0){
- ahc->flags |= AHC_NEWEEPROM_FMT;
- break;
- }
- }
- }
-
- for (i = 0; i < max_targ; i++) {
- u_int scsirate;
- uint16_t target_mask;
-
- target_mask = 0x01 << i;
- if (sc.device_flags[i] & CFDISC)
- discenable |= target_mask;
- if ((ahc->flags & AHC_NEWEEPROM_FMT) != 0) {
- if ((sc.device_flags[i] & CFSYNCHISULTRA) != 0)
- ultraenb |= target_mask;
- } else if ((sc.adapter_control & CFULTRAEN) != 0) {
- ultraenb |= target_mask;
- }
- if ((sc.device_flags[i] & CFXFER) == 0x04
- && (ultraenb & target_mask) != 0) {
- /* Treat 10MHz as a non-ultra speed */
- sc.device_flags[i] &= ~CFXFER;
- ultraenb &= ~target_mask;
- }
- if ((ahc->features & AHC_ULTRA2) != 0) {
- u_int offset;
-
- if (sc.device_flags[i] & CFSYNCH)
- offset = MAX_OFFSET_ULTRA2;
- else
- offset = 0;
- ahc_outb(ahc, TARG_OFFSET + i, offset);
-
- /*
- * The ultra enable bits contain the
- * high bit of the ultra2 sync rate
- * field.
- */
- scsirate = (sc.device_flags[i] & CFXFER)
- | ((ultraenb & target_mask)
- ? 0x8 : 0x0);
- if (sc.device_flags[i] & CFWIDEB)
- scsirate |= WIDEXFER;
- } else {
- scsirate = (sc.device_flags[i] & CFXFER) << 4;
- if (sc.device_flags[i] & CFSYNCH)
- scsirate |= SOFS;
- if (sc.device_flags[i] & CFWIDEB)
- scsirate |= WIDEXFER;
- }
- ahc_outb(ahc, TARG_SCSIRATE + i, scsirate);
- }
- ahc->our_id = sc.brtime_id & CFSCSIID;
+ /* Clear latched errors. */
+ pci_conf_write(ahc->bd->pc, ahc->bd->tag, PCI_COMMAND_STATUS_REG, status1);
- scsi_conf = (ahc->our_id & 0x7);
- if (sc.adapter_control & CFSPARITY)
- scsi_conf |= ENSPCHK;
- if (sc.adapter_control & CFRESETB)
- scsi_conf |= RESET_SCSI;
+ if ((status1 & (DPE|SSE|RMA|RTA|STA|DPR)) == 0) {
+ printf("%s: Latched PCIERR interrupt with "
+ "no status bits set\n", ahc_name(ahc));
+ } else {
+ ahc_outb(ahc, CLRINT, CLRPARERR);
+ }
- ahc->flags |=
- (sc.adapter_control & CFBOOTCHAN) >> CFBOOTCHANSHIFT;
+ ahc_unpause(ahc);
+}
- if (sc.bios_control & CFEXTEND)
- ahc->flags |= AHC_EXTENDED_TRANS_A;
+static int
+ahc_aic785X_setup(struct ahc_softc *ahc)
+{
+ uint8_t rev;
+
+ ahc->channel = 'A';
+ ahc->chip = AHC_AIC7850;
+ ahc->features = AHC_AIC7850_FE;
+ ahc->bugs |= AHC_TMODE_WIDEODD_BUG|AHC_CACHETHEN_BUG|AHC_PCI_MWI_BUG;
+ rev = PCI_REVISION(ahc->bd->class);
+ if (rev >= 1)
+ ahc->bugs |= AHC_PCI_2_1_RETRY_BUG;
+ return (0);
+}
- if (sc.bios_control & CFBIOSEN)
- ahc->flags |= AHC_BIOS_ENABLED;
- if (ahc->features & AHC_ULTRA
- && (ahc->flags & AHC_NEWEEPROM_FMT) == 0) {
- /* Should we enable Ultra mode? */
- if (!(sc.adapter_control & CFULTRAEN))
- /* Treat us as a non-ultra card */
- ultraenb = 0;
- }
+static int
+ahc_aic7860_setup(struct ahc_softc *ahc)
+{
+ uint8_t rev;
+
+ ahc->channel = 'A';
+ ahc->chip = AHC_AIC7860;
+ ahc->features = AHC_AIC7860_FE;
+ ahc->bugs |= AHC_TMODE_WIDEODD_BUG|AHC_CACHETHEN_BUG|AHC_PCI_MWI_BUG;
+ rev = PCI_REVISION(ahc->bd->class);
+ if (rev >= 1)
+ ahc->bugs |= AHC_PCI_2_1_RETRY_BUG;
+ return (0);
+}
- if (sc.signature == CFSIGNATURE
- || sc.signature == CFSIGNATURE2) {
- pcireg_t devconfig;
-
- /* Honor the STPWLEVEL settings */
- devconfig = ahc_pci_read_config(ahc->dev_softc,
- DEVCONFIG, 4);
- devconfig &= ~STPWLEVEL;
- if ((sc.bios_control & CFSTPWLEVEL) != 0)
- devconfig |= STPWLEVEL;
- ahc_pci_write_config(ahc->dev_softc,
- DEVCONFIG, devconfig, 4);
- }
- /* Set SCSICONF info */
- ahc_outb(ahc, SCSICONF, scsi_conf);
- ahc_outb(ahc, DISC_DSB, ~(discenable & 0xff));
- ahc_outb(ahc, DISC_DSB + 1, ~((discenable >> 8) & 0xff));
- ahc_outb(ahc, ULTRA_ENB, ultraenb & 0xff);
- ahc_outb(ahc, ULTRA_ENB + 1, (ultraenb >> 8) & 0xff);
- }
+static int
+ahc_apa1480_setup(struct ahc_softc *ahc)
+{
+ int error;
- /*
- * Cards that have the external logic necessary to talk to
- * a SEEPROM, are almost certain to have the remaining logic
- * necessary for auto-termination control. This assumption
- * hasn't failed yet...
- */
- have_autoterm = have_seeprom;
- if (have_seeprom)
- adapter_control = sc.adapter_control;
- else
- adapter_control = CFAUTOTERM;
+ error = ahc_aic7860_setup(ahc);
+ if (error != 0)
+ return (error);
+ ahc->features |= AHC_REMOVABLE;
+ return (0);
+}
- /*
- * Some low-cost chips have SEEPROM and auto-term control built
- * in, instead of using a GAL. They can tell us directly
- * if the termination logic is enabled.
- */
- if ((ahc->features & AHC_SPIOCAP) != 0) {
- if ((ahc_inb(ahc, SPIOCAP) & SSPIOCPS) != 0)
- have_autoterm = TRUE;
- else
- have_autoterm = FALSE;
- }
+static int
+ahc_aic7870_setup(struct ahc_softc *ahc)
+{
- if (have_autoterm) {
- acquire_seeprom(ahc, &sd);
- configure_termination(ahc, &sd, adapter_control, sxfrctl1);
- release_seeprom(&sd);
- }
+ ahc->channel = 'A';
+ ahc->chip = AHC_AIC7870;
+ ahc->features = AHC_AIC7870_FE;
+ ahc->bugs |= AHC_TMODE_WIDEODD_BUG|AHC_CACHETHEN_BUG|AHC_PCI_MWI_BUG;
+ return (0);
}
-static void
-configure_termination(struct ahc_softc *ahc,
- struct seeprom_descriptor *sd,
- u_int adapter_control,
- u_int *sxfrctl1)
+static int
+ahc_aha394X_setup(struct ahc_softc *ahc)
{
- uint8_t brddat;
-
- brddat = 0;
+ int error;
- /*
- * Update the settings in sxfrctl1 to match the
- * termination settings
- */
- *sxfrctl1 = 0;
-
- /*
- * SEECS must be on for the GALS to latch
- * the data properly. Be sure to leave MS
- * on or we will release the seeprom.
- */
- SEEPROM_OUTB(sd, sd->sd_MS | sd->sd_CS);
- if ((adapter_control & CFAUTOTERM) != 0
- || (ahc->features & AHC_NEW_TERMCTL) != 0) {
- int internal50_present;
- int internal68_present;
- int externalcable_present;
- int eeprom_present;
- int enableSEC_low;
- int enableSEC_high;
- int enablePRI_low;
- int enablePRI_high;
- int sum;
-
- enableSEC_low = 0;
- enableSEC_high = 0;
- enablePRI_low = 0;
- enablePRI_high = 0;
- if ((ahc->features & AHC_NEW_TERMCTL) != 0) {
- ahc_new_term_detect(ahc, &enableSEC_low,
- &enableSEC_high,
- &enablePRI_low,
- &enablePRI_high,
- &eeprom_present);
- if ((adapter_control & CFSEAUTOTERM) == 0) {
- if (bootverbose)
- printf("%s: Manual SE Termination\n",
- ahc_name(ahc));
- enableSEC_low = (adapter_control & CFSELOWTERM);
- enableSEC_high =
- (adapter_control & CFSEHIGHTERM);
- }
- if ((adapter_control & CFAUTOTERM) == 0) {
- if (bootverbose)
- printf("%s: Manual LVD Termination\n",
- ahc_name(ahc));
- enablePRI_low = (adapter_control & CFSTERM);
- enablePRI_high = (adapter_control & CFWSTERM);
- }
- /* Make the table calculations below happy */
- internal50_present = 0;
- internal68_present = 1;
- externalcable_present = 1;
- } else if ((ahc->features & AHC_SPIOCAP) != 0) {
- aic785X_cable_detect(ahc, &internal50_present,
- &externalcable_present,
- &eeprom_present);
- } else {
- aic787X_cable_detect(ahc, &internal50_present,
- &internal68_present,
- &externalcable_present,
- &eeprom_present);
- }
+ error = ahc_aic7870_setup(ahc);
+ if (error == 0)
+ error = ahc_aha394XX_setup(ahc);
+ return (error);
+}
- if ((ahc->features & AHC_WIDE) == 0)
- internal68_present = 0;
-
- if (bootverbose
- && (ahc->features & AHC_ULTRA2) == 0) {
- printf("%s: internal 50 cable %s present",
- ahc_name(ahc),
- internal50_present ? "is":"not");
-
- if ((ahc->features & AHC_WIDE) != 0)
- printf(", internal 68 cable %s present",
- internal68_present ? "is":"not");
- printf("\n%s: external cable %s present\n",
- ahc_name(ahc),
- externalcable_present ? "is":"not");
- }
- if (bootverbose)
- printf("%s: BIOS eeprom %s present\n",
- ahc_name(ahc), eeprom_present ? "is" : "not");
+static int
+ahc_aha398X_setup(struct ahc_softc *ahc)
+{
+ int error;
- if ((ahc->flags & AHC_INT50_SPEEDFLEX) != 0) {
- /*
- * The 50 pin connector is a separate bus,
- * so force it to always be terminated.
- * In the future, perform current sensing
- * to determine if we are in the middle of
- * a properly terminated bus.
- */
- internal50_present = 0;
- }
+ error = ahc_aic7870_setup(ahc);
+ if (error == 0)
+ error = ahc_aha398XX_setup(ahc);
+ return (error);
+}
- /*
- * Now set the termination based on what
- * we found.
- * Flash Enable = BRDDAT7
- * Secondary High Term Enable = BRDDAT6
- * Secondary Low Term Enable = BRDDAT5 (7890)
- * Primary High Term Enable = BRDDAT4 (7890)
- */
- if ((ahc->features & AHC_ULTRA2) == 0
- && (internal50_present != 0)
- && (internal68_present != 0)
- && (externalcable_present != 0)) {
- printf("%s: Illegal cable configuration!!. "
- "Only two connectors on the "
- "adapter may be used at a "
- "time!\n", ahc_name(ahc));
+static int
+ahc_aha494X_setup(struct ahc_softc *ahc)
+{
+ int error;
- /*
- * Pretend there are no cables in the hope
- * that having all of the termination on
- * gives us a more stable bus.
- */
- internal50_present = 0;
- internal68_present = 0;
- externalcable_present = 0;
- }
+ error = ahc_aic7870_setup(ahc);
+ if (error == 0)
+ error = ahc_aha494XX_setup(ahc);
+ return (error);
+}
- if ((ahc->features & AHC_WIDE) != 0
- && ((externalcable_present == 0)
- || (internal68_present == 0)
- || (enableSEC_high != 0))) {
- brddat |= BRDDAT6;
- if (bootverbose) {
- if ((ahc->flags & AHC_INT50_SPEEDFLEX) != 0)
- printf("%s: 68 pin termination "
- "Enabled\n", ahc_name(ahc));
- else
- printf("%s: %sHigh byte termination "
- "Enabled\n", ahc_name(ahc),
- enableSEC_high ? "Secondary "
- : "");
- }
- }
+static int
+ahc_aic7880_setup(struct ahc_softc *ahc)
+{
+ uint8_t rev;
+
+ ahc->channel = 'A';
+ ahc->chip = AHC_AIC7880;
+ ahc->features = AHC_AIC7880_FE;
+ ahc->bugs |= AHC_TMODE_WIDEODD_BUG;
+ rev = PCI_REVISION(ahc->bd->class);
+ if (rev >= 1) {
+ ahc->bugs |= AHC_PCI_2_1_RETRY_BUG;
+ } else {
+ ahc->bugs |= AHC_CACHETHEN_BUG|AHC_PCI_MWI_BUG;
+ }
+ return (0);
+}
- sum = internal50_present + internal68_present
- + externalcable_present;
- if (sum < 2 || (enableSEC_low != 0)) {
- if ((ahc->features & AHC_ULTRA2) != 0)
- brddat |= BRDDAT5;
- else
- *sxfrctl1 |= STPWEN;
- if (bootverbose) {
- if ((ahc->flags & AHC_INT50_SPEEDFLEX) != 0)
- printf("%s: 50 pin termination "
- "Enabled\n", ahc_name(ahc));
- else
- printf("%s: %sLow byte termination "
- "Enabled\n", ahc_name(ahc),
- enableSEC_low ? "Secondary "
- : "");
- }
- }
+static int
+ahc_aha2940Pro_setup(struct ahc_softc *ahc)
+{
- if (enablePRI_low != 0) {
- *sxfrctl1 |= STPWEN;
- if (bootverbose)
- printf("%s: Primary Low Byte termination "
- "Enabled\n", ahc_name(ahc));
- }
+ ahc->flags |= AHC_INT50_SPEEDFLEX;
+ return (ahc_aic7880_setup(ahc));
+}
- /*
- * Setup STPWEN before setting up the rest of
- * the termination per the tech note on the U160 cards.
- */
- ahc_outb(ahc, SXFRCTL1, *sxfrctl1);
-
- if (enablePRI_high != 0) {
- brddat |= BRDDAT4;
- if (bootverbose)
- printf("%s: Primary High Byte "
- "termination Enabled\n",
- ahc_name(ahc));
- }
-
- write_brdctl(ahc, brddat);
+static int
+ahc_aha394XU_setup(struct ahc_softc *ahc)
+{
+ int error;
- } else {
- if ((adapter_control & CFSTERM) != 0) {
- *sxfrctl1 |= STPWEN;
-
- if (bootverbose)
- printf("%s: %sLow byte termination Enabled\n",
- ahc_name(ahc),
- (ahc->features & AHC_ULTRA2) ? "Primary "
- : "");
- }
+ error = ahc_aic7880_setup(ahc);
+ if (error == 0)
+ error = ahc_aha394XX_setup(ahc);
+ return (error);
+}
- if ((adapter_control & CFWSTERM) != 0
- && (ahc->features & AHC_WIDE) != 0) {
- brddat |= BRDDAT6;
- if (bootverbose)
- printf("%s: %sHigh byte termination Enabled\n",
- ahc_name(ahc),
- (ahc->features & AHC_ULTRA2)
- ? "Secondary " : "");
- }
+static int
+ahc_aha398XU_setup(struct ahc_softc *ahc)
+{
+ int error;
- /*
- * Setup STPWEN before setting up the rest of
- * the termination per the tech note on the U160 cards.
- */
- ahc_outb(ahc, SXFRCTL1, *sxfrctl1);
+ error = ahc_aic7880_setup(ahc);
+ if (error == 0)
+ error = ahc_aha398XX_setup(ahc);
+ return (error);
+}
- if ((ahc->features & AHC_WIDE) != 0)
- write_brdctl(ahc, brddat);
- }
- SEEPROM_OUTB(sd, sd->sd_MS); /* Clear CS */
+static int
+ahc_aic7890_setup(struct ahc_softc *ahc)
+{
+ uint8_t rev;
+
+ ahc->channel = 'A';
+ ahc->chip = AHC_AIC7890;
+ ahc->features = AHC_AIC7890_FE;
+ ahc->flags |= AHC_NEWEEPROM_FMT;
+ rev = PCI_REVISION(ahc->bd->class);
+ if (rev == 0)
+ ahc->bugs |= AHC_AUTOFLUSH_BUG|AHC_CACHETHEN_BUG;
+ return (0);
}
-static void
-ahc_new_term_detect(ahc, enableSEC_low, enableSEC_high, enablePRI_low,
- enablePRI_high, eeprom_present)
- struct ahc_softc *ahc;
- int *enableSEC_low;
- int *enableSEC_high;
- int *enablePRI_low;
- int *enablePRI_high;
- int *eeprom_present;
+static int
+ahc_aic7892_setup(struct ahc_softc *ahc)
{
- u_int8_t brdctl;
- /*
- * BRDDAT7 = Eeprom
- * BRDDAT6 = Enable Secondary High Byte termination
- * BRDDAT5 = Enable Secondary Low Byte termination
- * BRDDAT4 = Enable Primary high byte termination
- * BRDDAT3 = Enable Primary low byte termination
- */
- brdctl = read_brdctl(ahc);
- *eeprom_present = brdctl & BRDDAT7;
- *enableSEC_high = (brdctl & BRDDAT6);
- *enableSEC_low = (brdctl & BRDDAT5);
- *enablePRI_high = (brdctl & BRDDAT4);
- *enablePRI_low = (brdctl & BRDDAT3);
+ ahc->channel = 'A';
+ ahc->chip = AHC_AIC7892;
+ ahc->features = AHC_AIC7892_FE;
+ ahc->flags |= AHC_NEWEEPROM_FMT;
+ ahc->bugs |= AHC_SCBCHAN_UPLOAD_BUG;
+ return (0);
}
-static void
-aic787X_cable_detect(ahc, internal50_present, internal68_present,
- externalcable_present, eeprom_present)
- struct ahc_softc *ahc;
- int *internal50_present;
- int *internal68_present;
- int *externalcable_present;
- int *eeprom_present;
+static int
+ahc_aic7895_setup(struct ahc_softc *ahc)
{
- u_int8_t brdctl;
+ uint8_t rev;
+ ahc->channel = (ahc->bd->func == 1) ? 'B' : 'A';
/*
- * First read the status of our cables.
- * Set the rom bank to 0 since the
- * bank setting serves as a multiplexor
- * for the cable detection logic.
- * BRDDAT5 controls the bank switch.
+ * The 'C' revision of the aic7895 has a few additional features.
*/
- write_brdctl(ahc, 0);
+ rev = PCI_REVISION(ahc->bd->class);
+ if (rev >= 4) {
+ ahc->chip = AHC_AIC7895C;
+ ahc->features = AHC_AIC7895C_FE;
+ } else {
+ u_int command;
- /*
- * Now read the state of the internal
- * connectors. BRDDAT6 is INT50 and
- * BRDDAT7 is INT68.
- */
- brdctl = read_brdctl(ahc);
- *internal50_present = (brdctl & BRDDAT6) ? 0 : 1;
- *internal68_present = (brdctl & BRDDAT7) ? 0 : 1;
+ ahc->chip = AHC_AIC7895;
+ ahc->features = AHC_AIC7895_FE;
+ /*
+ * The BIOS disables the use of MWI transactions
+ * since it does not have the MWI bug work around
+ * we have. Disabling MWI reduces performance, so
+ * turn it on again.
+ */
+ command = pci_conf_read(ahc->bd->pc, ahc->bd->tag, PCI_COMMAND_STATUS_REG);
+ command |= PCI_COMMAND_INVALIDATE_ENABLE;
+ pci_conf_write(ahc->bd->pc, ahc->bd->tag, PCI_COMMAND_STATUS_REG, command);
+ ahc->bugs |= AHC_PCI_MWI_BUG;
+ }
/*
- * Set the rom bank to 1 and determine
- * the other signals.
+ * XXX Does CACHETHEN really not work??? What about PCI retry?
+ * on C level chips. Need to test, but for now, play it safe.
*/
- write_brdctl(ahc, BRDDAT5);
+ ahc->bugs |= AHC_TMODE_WIDEODD_BUG|AHC_PCI_2_1_RETRY_BUG
+ | AHC_CACHETHEN_BUG;
+
+#if 0
+ uint32_t devconfig;
/*
- * Now read the state of the external
- * connectors. BRDDAT6 is EXT68 and
- * BRDDAT7 is EPROMPS.
+ * Cachesize must also be zero due to stray DAC
+ * problem when sitting behind some bridges.
*/
- brdctl = read_brdctl(ahc);
- *externalcable_present = (brdctl & BRDDAT6) ? 0 : 1;
- *eeprom_present = (brdctl & BRDDAT7) ? 1 : 0;
-}
-
-static void
-aic785X_cable_detect(ahc, internal50_present, externalcable_present,
- eeprom_present)
- struct ahc_softc *ahc;
- int *internal50_present;
- int *externalcable_present;
- int *eeprom_present;
-{
- u_int8_t brdctl;
-
- ahc_outb(ahc, BRDCTL, BRDRW|BRDCS);
- ahc_outb(ahc, BRDCTL, 0);
- brdctl = ahc_inb(ahc, BRDCTL);
- *internal50_present = (brdctl & BRDDAT5) ? 0 : 1;
- *externalcable_present = (brdctl & BRDDAT6) ? 0 : 1;
-
- *eeprom_present = (ahc_inb(ahc, SPIOCAP) & EEPROM) ? 1 : 0;
+ pci_conf_write(ahc->bd->pc, ahc->bd->tag, CSIZE_LATTIME, 0);
+ devconfig = pci_conf_read(ahc->bd->pc, ahc->bd->tag, DEVCONFIG);
+ devconfig |= MRDCEN;
+ pci_conf_write(ahc->bd->pc, ahc->bd->tag, DEVCONFIG, devconfig);
+#endif
+ ahc->flags |= AHC_NEWEEPROM_FMT;
+ return (0);
}
-static void
-write_brdctl(ahc, value)
- struct ahc_softc *ahc;
- u_int8_t value;
+static int
+ahc_aic7896_setup(struct ahc_softc *ahc)
{
- u_int8_t brdctl;
-
- if ((ahc->chip & AHC_CHIPID_MASK) == AHC_AIC7895) {
- brdctl = BRDSTB;
- if (ahc->channel == 'B')
- brdctl |= BRDCS;
- } else if ((ahc->features & AHC_ULTRA2) != 0) {
- brdctl = 0;
- } else {
- brdctl = BRDSTB|BRDCS;
- }
- ahc_outb(ahc, BRDCTL, brdctl);
- ahc_flush_device_writes(ahc);
- brdctl |= value;
- ahc_outb(ahc, BRDCTL, brdctl);
- ahc_flush_device_writes(ahc);
- if ((ahc->features & AHC_ULTRA2) != 0)
- brdctl |= BRDSTB_ULTRA2;
- else
- brdctl &= ~BRDSTB;
- ahc_outb(ahc, BRDCTL, brdctl);
- ahc_flush_device_writes(ahc);
- if ((ahc->features & AHC_ULTRA2) != 0)
- brdctl = 0;
- else
- brdctl &= ~BRDCS;
- ahc_outb(ahc, BRDCTL, brdctl);
+ ahc->channel = (ahc->bd->func == 1) ? 'B' : 'A';
+ ahc->chip = AHC_AIC7896;
+ ahc->features = AHC_AIC7896_FE;
+ ahc->flags |= AHC_NEWEEPROM_FMT;
+ ahc->bugs |= AHC_CACHETHEN_DIS_BUG;
+ return (0);
}
-static u_int8_t
-read_brdctl(ahc)
- struct ahc_softc *ahc;
+static int
+ahc_aic7899_setup(struct ahc_softc *ahc)
{
- u_int8_t brdctl;
- u_int8_t value;
-
- if ((ahc->chip & AHC_CHIPID_MASK) == AHC_AIC7895) {
- brdctl = BRDRW;
- if (ahc->channel == 'B')
- brdctl |= BRDCS;
- } else if ((ahc->features & AHC_ULTRA2) != 0) {
- brdctl = BRDRW_ULTRA2;
- } else {
- brdctl = BRDRW|BRDCS;
- }
- ahc_outb(ahc, BRDCTL, brdctl);
- ahc_flush_device_writes(ahc);
- value = ahc_inb(ahc, BRDCTL);
- ahc_outb(ahc, BRDCTL, 0);
- return (value);
+ ahc->channel = (ahc->bd->func == 1) ? 'B' : 'A';
+ ahc->chip = AHC_AIC7899;
+ ahc->features = AHC_AIC7899_FE;
+ ahc->flags |= AHC_NEWEEPROM_FMT;
+ ahc->bugs |= AHC_SCBCHAN_UPLOAD_BUG;
+ return (0);
}
static int
-acquire_seeprom(ahc, sd)
- struct ahc_softc *ahc;
- struct seeprom_descriptor *sd;
+ahc_aha29160C_setup(struct ahc_softc *ahc)
{
- int wait;
-
- if ((ahc->features & AHC_SPIOCAP) != 0
- && (ahc_inb(ahc, SPIOCAP) & SEEPROM) == 0)
- return (0);
+ int error;
- /*
- * Request access of the memory port. When access is
- * granted, SEERDY will go high. We use a 1 second
- * timeout which should be near 1 second more than
- * is needed. Reason: after the chip reset, there
- * should be no contention.
- */
- SEEPROM_OUTB(sd, sd->sd_MS);
- wait = 1000; /* 1 second timeout in msec */
- while (--wait && ((SEEPROM_STATUS_INB(sd) & sd->sd_RDY) == 0)) {
- DELAY(1000); /* delay 1 msec */
- }
- if ((SEEPROM_STATUS_INB(sd) & sd->sd_RDY) == 0) {
- SEEPROM_OUTB(sd, 0);
- return (0);
- }
- return (1);
+ error = ahc_aic7899_setup(ahc);
+ if (error != 0)
+ return (error);
+ ahc->features |= AHC_REMOVABLE;
+ return (0);
}
-static void
-release_seeprom(sd)
- struct seeprom_descriptor *sd;
+static int
+ahc_raid_setup(struct ahc_softc *ahc)
{
- /* Release access to the memory port and the serial EEPROM. */
- SEEPROM_OUTB(sd, 0);
+ printf("RAID functionality unsupported\n");
+ return (ENXIO);
}
-#define DPE PCI_STATUS_PARITY_DETECT
-#define SSE PCI_STATUS_SPECIAL_ERROR
-#define RMA PCI_STATUS_MASTER_ABORT
-#define RTA PCI_STATUS_MASTER_TARGET_ABORT
-#define STA PCI_STATUS_TARGET_TARGET_ABORT
-#define DPR PCI_STATUS_PARITY_ERROR
-
-#define PCIDEBUG
-#ifdef PCIDEBUG
-#define PCI_PRINT(Printstuff) printf Printstuff
-#else
-#define PCI_PRINT(Printstuff)
-#endif
-
-void
-ahc_pci_intr(ahc)
- struct ahc_softc *ahc;
+static int
+ahc_aha394XX_setup(struct ahc_softc *ahc)
{
- pcireg_t status1;
- if ((ahc_inb(ahc, ERROR) & PCIERRSTAT) == 0)
- return;
- PCI_PRINT(("%s: PCI error Interrupt at seqaddr = 0x%x\n",
- ahc_name(ahc),
- ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8)));
-
- status1 = ahc_pci_read_config(ahc->dev_softc, PCI_COMMAND_STATUS_REG, 4);
-
-/* define AHC_SHOW_PCI_ERRORS to get painful errors on your i386 console */
-#ifdef AHC_SHOW_PCI_ERRORS
- if (status1 & DPE) {
- PCI_PRINT(("%s: Data Parity Error Detected during address "
- "or write data phase\n", ahc_name(ahc)));
- }
-#endif
- if (status1 & SSE) {
- PCI_PRINT(("%s: Signal System Error Detected\n", ahc_name(ahc)));
- }
- if (status1 & RMA) {
- PCI_PRINT(("%s: Received a Master Abort\n", ahc_name(ahc)));
- }
- if (status1 & RTA) {
- PCI_PRINT(("%s: Received a Target Abort\n", ahc_name(ahc)));
- }
- if (status1 & STA) {
- PCI_PRINT(("%s: Signaled a Target Abort\n", ahc_name(ahc)));
- }
- if (status1 & DPR) {
- PCI_PRINT(("%s: Data Parity Error has been reported via PERR#\n",
- ahc_name(ahc)));
+ switch (ahc->bd->dev) {
+ case AHC_394X_SLOT_CHANNEL_A:
+ ahc->channel = 'A';
+ break;
+ case AHC_394X_SLOT_CHANNEL_B:
+ ahc->channel = 'B';
+ break;
+ default:
+ printf("adapter at unexpected slot %d\n"
+ "unable to map to a channel\n",
+ ahc->bd->dev);
+ ahc->channel = 'A';
}
-
- ahc_pci_write_config(ahc->dev_softc, PCI_COMMAND_STATUS_REG, status1, 4);
+ return (0);
+}
- if ((status1 & (DPE|SSE|RMA|RTA|STA|DPR)) == 0) {
- printf("%s: Latched PCIERR interrupt with "
- "no status bits set\n", ahc_name(ahc));
- } else {
- ahc_outb(ahc, CLRINT, CLRPARERR);
- }
-
- ahc_unpause(ahc);
+static int
+ahc_aha398XX_setup(struct ahc_softc *ahc)
+{
- return;
+ switch (ahc->bd->dev) {
+ case AHC_398X_SLOT_CHANNEL_A:
+ ahc->channel = 'A';
+ break;
+ case AHC_398X_SLOT_CHANNEL_B:
+ ahc->channel = 'B';
+ break;
+ case AHC_398X_SLOT_CHANNEL_C:
+ ahc->channel = 'C';
+ break;
+ default:
+ printf("adapter at unexpected slot %d\n"
+ "unable to map to a channel\n",
+ ahc->bd->dev);
+ ahc->channel = 'A';
+ break;
+ }
+ ahc->flags |= AHC_LARGE_SEEPROM;
+ return (0);
}
static int
-verify_cksum(struct seeprom_config *sc)
+ahc_aha494XX_setup(struct ahc_softc *ahc)
{
- int i;
- int maxaddr;
- u_int32_t checksum;
- u_int16_t *scarray;
-
- maxaddr = (sizeof(*sc)/2) - 1;
- checksum = 0;
- scarray = (uint16_t *)sc;
-
- for (i = 0; i < maxaddr; i++)
- checksum = checksum + scarray[i];
- if (checksum == 0 ||
- (checksum & 0xFFFF) != sc->checksum) {
- return (0);
- } else {
- return (1);
+
+ switch (ahc->bd->dev) {
+ case AHC_494X_SLOT_CHANNEL_A:
+ ahc->channel = 'A';
+ break;
+ case AHC_494X_SLOT_CHANNEL_B:
+ ahc->channel = 'B';
+ break;
+ case AHC_494X_SLOT_CHANNEL_C:
+ ahc->channel = 'C';
+ break;
+ case AHC_494X_SLOT_CHANNEL_D:
+ ahc->channel = 'D';
+ break;
+ default:
+ printf("adapter at unexpected slot %d\n"
+ "unable to map to a channel\n",
+ ahc->bd->dev);
+ ahc->channel = 'A';
}
+ ahc->flags |= AHC_LARGE_SEEPROM;
+ return (0);
}