diff options
-rw-r--r-- | sys/dev/ic/aic7xxx.c | 1670 | ||||
-rw-r--r-- | sys/dev/ic/aic7xxx.h | 80 | ||||
-rw-r--r-- | sys/dev/ic/aic7xxx_cam.h | 174 | ||||
-rw-r--r-- | sys/dev/ic/aic7xxx_inline.h | 208 | ||||
-rw-r--r-- | sys/dev/ic/aic7xxx_openbsd.c | 1454 | ||||
-rw-r--r-- | sys/dev/ic/aic7xxx_openbsd.h | 715 | ||||
-rw-r--r-- | sys/dev/ic/aic7xxx_seeprom.c | 777 | ||||
-rw-r--r-- | sys/dev/pci/ahc_pci.c | 2387 |
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 *)≻ - 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); } |