diff options
author | Justin T. Gibbs <gibbs@FreeBSD.org> | 2000-07-18 20:12:14 +0000 |
---|---|---|
committer | Justin T. Gibbs <gibbs@FreeBSD.org> | 2000-07-18 20:12:14 +0000 |
commit | aa6dfd9d3d70c9c1792c36267bc36438bbbaa82c (patch) | |
tree | 0d2ba2074eaf288baf3000ae0617656eaf6dcc9a /sys/dev/aic7xxx/aic7xxx.c | |
parent | d4e2be3050a69e8ffdfeac1919e63f8f0ec411b6 (diff) | |
download | src-aa6dfd9d3d70c9c1792c36267bc36438bbbaa82c.tar.gz src-aa6dfd9d3d70c9c1792c36267bc36438bbbaa82c.zip |
o Convert to <inttypes.h> style fixed sized types to facilitate porting to
other systems.
o Normalize copyright text.
o Clean up probe code function interfaces by passing around a single
structure of common arguments instead of passing "too many" args
in each function call.
o Add support for the AAA-131 as a SCSI adapter.
o Add support for the AHA-4944 courtesy of "Matthew N. Dodd" <winter@jurai.net
o Correct manual termination support for PCI cards. The bit definitions
for manual termination control in the SEEPROM were incorrect.
o Add support for extracting NVRAM information from SCB 2 for BIOSen
that use this mechanism to pass this data to OS drivers.
o Properly set the STPWLEVEL bit in PCI config space based on the
setting in an SEEPROM.
o Go back to useing 32byte SCBs for all controllers. The current
firmware allows us to embed 12byte cdbs on all controllers in
a 32byte SCB, and larger cdbs are rarely used, so it is a
better use of this space to offer more SCBs (32).
o Add support for U160 transfers.
o Add an idle loop executed during data transfers that prefetches
S/G segments on controllers that have a secondary DMA engine
(aic789X).
o Improve the performance of reselections by avoiding an extra
one byte DMA in the case of an SCB lookup miss for the reselecting
target. We now keep a 16byte "untagged target" array on the card
for dealing with untagged reselections. If the controller has
external SCB ram and can support 64byte SCBs, then we use an
"untagged target/lun" array to maximize concurrency. Without
external SCB ram, the controller is limited to one untagged
transaction per target, auto-request sense operations excluded.
o Correct the setup of the STPWEN bit in SXFRCTL1. This control
line is tri-stated until set to one, so set it to one and then
set it to the desired value.
o Add tagged queuing support to our target role implementation.
o Handle the common cases of the ignore wide residue message
in firmware.
o Add preliminary support for 39bit addressing.
o Add support for assembling on big-endian machines. Big-endian
support is not complete in the driver.
o Correctly remove SCBs in the waiting for selection queue when
freezing a device queue.
o Now that we understand more about the autoflush bug on the
aic7890, only use the workaround on devices that need it.
o Add a workaround for the "aic7890 hangs the system when you
attempt to pause it" problem. We can now pause the aic7890
safely regardless of what instruction it is executing.
Notes
Notes:
svn path=/head/; revision=63457
Diffstat (limited to 'sys/dev/aic7xxx/aic7xxx.c')
-rw-r--r-- | sys/dev/aic7xxx/aic7xxx.c | 1960 |
1 files changed, 1238 insertions, 722 deletions
diff --git a/sys/dev/aic7xxx/aic7xxx.c b/sys/dev/aic7xxx/aic7xxx.c index e89434ae2e00..3859c190042c 100644 --- a/sys/dev/aic7xxx/aic7xxx.c +++ b/sys/dev/aic7xxx/aic7xxx.c @@ -18,7 +18,7 @@ * derived from this software without specific prior written permission. * * Alternatively, this software may be distributed under the terms of the - * the GNU Public License ("GPL"). + * GNU 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 @@ -110,6 +110,7 @@ #include <machine/bus_pio.h> #include <machine/bus.h> #include <machine/clock.h> +#include <machine/endian.h> #include <sys/rman.h> #include <vm/vm.h> @@ -117,7 +118,7 @@ #include <vm/pmap.h> #include <dev/aic7xxx/aic7xxx.h> -#include <dev/aic7xxx/sequencer.h> +#include <dev/aic7xxx/aicasm_insformat.h> #include <aic7xxx_reg.h> #include <aic7xxx_seq.h> @@ -142,24 +143,36 @@ (((sim) == ahc->sim_b) ? ahc->our_id_b : ahc->our_id) #define SIM_PATH(ahc, sim) \ (((sim) == ahc->sim_b) ? ahc->path_b : ahc->path) -#define SCB_IS_SCSIBUS_B(scb) \ - (((scb)->hscb->tcl & SELBUSB) != 0) -#define SCB_TARGET(scb) \ - (((scb)->hscb->tcl & TID) >> 4) -#define SCB_CHANNEL(scb) \ - (SCB_IS_SCSIBUS_B(scb) ? 'B' : 'A') -#define SCB_LUN(scb) \ - ((scb)->hscb->tcl & LID) -#define SCB_TARGET_OFFSET(scb) \ - (SCB_TARGET(scb) + (SCB_IS_SCSIBUS_B(scb) ? 8 : 0)) -#define SCB_TARGET_MASK(scb) \ - (0x01 << (SCB_TARGET_OFFSET(scb))) -#define TCL_CHANNEL(ahc, tcl) \ - ((((ahc)->features & AHC_TWIN) && ((tcl) & SELBUSB)) ? 'B' : 'A') -#define TCL_SCSI_ID(ahc, tcl) \ - (TCL_CHANNEL((ahc), (tcl)) == 'B' ? (ahc)->our_id_b : (ahc)->our_id) -#define TCL_TARGET(tcl) (((tcl) & TID) >> TCL_TARGET_SHIFT) -#define TCL_LUN(tcl) ((tcl) & LID) +#define SCSIID_TARGET(ahc, scsiid) \ + (((scsiid) & ((((ahc)->features & AHC_TWIN) != 0) ? TWIN_TID : TID)) \ + >> TID_SHIFT) +#define SCSIID_OUR_ID(scsiid) \ + ((scsiid) & OID) +#define SCSIID_CHANNEL(ahc, scsiid) \ + ((((ahc)->features & AHC_TWIN) != 0) \ + ? ((((scsiid) & TWIN_CHNLB) != 0) ? 'B' : 'A') \ + : 'A') +#define SCB_IS_SCSIBUS_B(ahc, scb) \ + (SCSIID_CHANNEL(ahc, (scb)->hscb->scsiid) == 'B') +#define SCB_GET_OUR_ID(scb) \ + SCSIID_OUR_ID((scb)->hscb->scsiid) +#define SCB_GET_TARGET(ahc, scb) \ + SCSIID_TARGET((ahc), (scb)->hscb->scsiid) +#define SCB_GET_CHANNEL(ahc, scb) \ + SCSIID_CHANNEL(ahc, (scb)->hscb->scsiid) +#define SCB_GET_LUN(scb) \ + ((scb)->hscb->lun) +#define SCB_GET_TARGET_OFFSET(ahc, scb) \ + (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))) +#define TCL_TARGET_OFFSET(tcl) \ + ((((tcl) >> 4) & TID) >> 4) +#define BUILD_TCL(scsiid, lun) \ + ((lun) | (((scsiid) & TID) >> 4)) +#define BUILD_SCSIID(ahc, sim, target_id, our_id) \ + ((((target_id) << TID_SHIFT) & TID) | (our_id) \ + | (SIM_IS_SCSIBUS_B(ahc, sim) ? TWIN_CHNLB : 0)) #define ccb_scb_ptr spriv_ptr0 #define ccb_ahc_ptr spriv_ptr1 @@ -174,10 +187,10 @@ char *ahc_chip_names[] = "aic7860", "aic7870", "aic7880", - "aic7890/91", - "aic7892", "aic7895", + "aic7890/91", "aic7896/97", + "aic7892", "aic7899" }; @@ -190,9 +203,9 @@ typedef enum { struct ahc_devinfo { int our_scsiid; int target_offset; - u_int16_t target_mask; - u_int8_t target; - u_int8_t lun; + uint16_t target_mask; + uint8_t target; + uint8_t lun; char channel; role_t role; /* * Only guaranteed to be correct if not @@ -230,7 +243,7 @@ static cam_status struct tmode_lstate **lstate, int notfound_failure); static void ahc_action(struct cam_sim *sim, union ccb *ccb); -static void ahc_async(void *callback_arg, u_int32_t code, +static void ahc_async(void *callback_arg, uint32_t code, struct cam_path *path, void *arg); static void ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments, int error); @@ -249,7 +262,7 @@ static void ahc_fetch_devinfo(struct ahc_softc *ahc, static void ahc_compile_devinfo(struct ahc_devinfo *devinfo, u_int our_id, u_int target, u_int lun, char channel, role_t role); -static u_int ahc_abort_wscb(struct ahc_softc *ahc, u_int scbpos, u_int prev); +static u_int ahc_rem_wscb(struct ahc_softc *ahc, u_int scbpos, u_int prev); static void ahc_done(struct ahc_softc *ahc, struct scb *scbp); static struct tmode_tstate * ahc_alloc_tstate(struct ahc_softc *ahc, @@ -296,17 +309,18 @@ static void ahc_dumpseq(struct ahc_softc *ahc); static void ahc_loadseq(struct ahc_softc *ahc); static int ahc_check_patch(struct ahc_softc *ahc, struct patch **start_patch, - int start_instr, int *skip_addr); + u_int start_instr, u_int *skip_addr); static void ahc_download_instr(struct ahc_softc *ahc, - int instrptr, u_int8_t *dconsts); -static int ahc_match_scb(struct scb *scb, int target, char channel, - int lun, u_int tag, role_t role); + u_int instrptr, uint8_t *dconsts); +static int ahc_match_scb(struct ahc_softc *ahc, struct scb *scb, + int target, char channel, int lun, u_int tag, + role_t role); #ifdef AHC_DEBUG static void ahc_print_scb(struct scb *scb); #endif static int ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel, int lun, u_int tag, - role_t role, u_int32_t status, + role_t role, uint32_t status, ahc_search_action action); static void ahc_abort_ccb(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb); @@ -314,7 +328,7 @@ static int ahc_reset_channel(struct ahc_softc *ahc, char channel, int initiate_reset); static int ahc_abort_scbs(struct ahc_softc *ahc, int target, char channel, int lun, u_int tag, role_t role, - u_int32_t status); + uint32_t status); static int ahc_search_disc_list(struct ahc_softc *ahc, int target, char channel, int lun, u_int tag, int stop_on_first, int remove, @@ -325,15 +339,17 @@ static void ahc_add_curscb_to_free_list(struct ahc_softc *ahc); static void ahc_clear_intstat(struct ahc_softc *ahc); static void ahc_reset_current_bus(struct ahc_softc *ahc); static struct ahc_syncrate * - ahc_devlimited_syncrate(struct ahc_softc *ahc, u_int *period); + ahc_devlimited_syncrate(struct ahc_softc *ahc, u_int *period, + u_int *ppr_options); static struct ahc_syncrate * ahc_find_syncrate(struct ahc_softc *ahc, u_int *period, - u_int maxsync); + u_int *ppr_options, u_int maxsync); static u_int ahc_find_period(struct ahc_softc *ahc, u_int scsirate, u_int maxsync); static void ahc_validate_offset(struct ahc_softc *ahc, struct ahc_syncrate *syncrate, u_int *offset, int wide); +static void ahc_validate_width(struct ahc_softc *ahc, u_int *bus_width); static void ahc_update_target_msg_request(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, struct ahc_initiator_tinfo *tinfo, @@ -345,7 +361,8 @@ static void ahc_set_syncrate(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, struct cam_path *path, struct ahc_syncrate *syncrate, - u_int period, u_int offset, u_int type, + u_int period, u_int offset, + u_int ppr_options, u_int type, int paused); static void ahc_set_width(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, @@ -358,7 +375,11 @@ static void ahc_construct_sdtr(struct ahc_softc *ahc, u_int period, u_int offset); static void ahc_construct_wdtr(struct ahc_softc *ahc, u_int bus_width); +static void ahc_construct_ppr(struct ahc_softc *ahc, u_int period, + u_int offset, u_int bus_width, + u_int ppr_options); +static __inline int ahc_check_residual(struct scb *scb); static void ahc_calc_residual(struct scb *scb); static void ahc_update_pending_syncrates(struct ahc_softc *ahc); @@ -373,19 +394,17 @@ static void ahc_queue_lstate_event(struct ahc_softc *ahc, u_int event_arg); static void ahc_send_lstate_events(struct ahc_softc *ahc, struct tmode_lstate *lstate); -static __inline int sequencer_paused(struct ahc_softc *ahc); -static __inline void pause_sequencer(struct ahc_softc *ahc); -static __inline void unpause_sequencer(struct ahc_softc *ahc); static void restart_sequencer(struct ahc_softc *ahc); static __inline u_int ahc_index_busy_tcl(struct ahc_softc *ahc, u_int tcl, int unbusy); -static __inline void ahc_busy_tcl(struct ahc_softc *ahc, struct scb *scb); - static __inline void ahc_freeze_ccb(union ccb* ccb); static __inline cam_status ahc_ccb_status(union ccb* ccb); static __inline void ahcsetccbstatus(union ccb* ccb, cam_status status); +static void ahc_run_untagged_queues(struct ahc_softc *); +static void ahc_run_untagged_queue(struct ahc_softc *, + struct scb_tailq *); static void ahc_run_tqinfifo(struct ahc_softc *ahc, int paused); static void ahc_run_qoutfifo(struct ahc_softc *ahc); @@ -394,43 +413,27 @@ static __inline struct ahc_initiator_tinfo * char channel, u_int our_id, u_int target, struct tmode_tstate **tstate); +static __inline struct ahc_dma_seg * + ahc_sg_bus_to_virt(struct scb *scb, + uint32_t sg_busaddr); +static __inline uint32_t + ahc_sg_virt_to_bus(struct scb *scb, + struct ahc_dma_seg *sg); +static __inline void ahc_queue_scb(struct ahc_softc *ahc, + struct scb *scb); static void ahcfreescb(struct ahc_softc *ahc, struct scb *scb); static __inline struct scb *ahcgetscb(struct ahc_softc *ahc); +static __inline void ahc_freeze_untagged_queues(struct ahc_softc *ahc); +static __inline void ahc_release_untagged_queues(struct ahc_softc *ahc); -static __inline u_int32_t +static __inline uint32_t ahc_hscb_busaddr(struct ahc_softc *ahc, u_int index) { return (ahc->scb_data->hscb_busaddr + (sizeof(struct hardware_scb) * index)); } -#define AHC_BUSRESET_DELAY 25 /* Reset delay in us */ - -static __inline int -sequencer_paused(struct ahc_softc *ahc) -{ - return ((ahc_inb(ahc, HCNTRL) & PAUSE) != 0); -} - -static __inline void -pause_sequencer(struct ahc_softc *ahc) -{ - ahc_outb(ahc, HCNTRL, ahc->pause); - - /* - * Since the sequencer can disable pausing in a critical section, we - * must loop until it actually stops. - */ - while (sequencer_paused(ahc) == 0) - ; -} - -static __inline void -unpause_sequencer(struct ahc_softc *ahc) -{ - if ((ahc_inb(ahc, INTSTAT) & (SCSIINT | SEQINT | BRKADRINT)) == 0) - ahc_outb(ahc, HCNTRL, ahc->unpause); -} +#define AHC_BUSRESET_DELAY 250 /* Reset delay in us */ /* * Restart the sequencer program from address zero @@ -457,8 +460,9 @@ restart_sequencer(struct ahc_softc *ahc) for (i = 0; i < ahc->scb_data->maxhscbs; i++) { ahc_outb(ahc, SCBPTR, i); - if (ahc_inb(ahc, SCB_TAG) == SCB_LIST_NULL) + if (ahc_inb(ahc, SCB_TAG) == SCB_LIST_NULL) { ahc_add_curscb_to_free_list(ahc); + } } ahc_outb(ahc, SEQCTL, FASTMODE|SEQRESET); unpause_sequencer(ahc); @@ -468,18 +472,25 @@ static __inline u_int ahc_index_busy_tcl(struct ahc_softc *ahc, u_int tcl, int unbusy) { u_int scbid; + u_int target_offset; - scbid = ahc->untagged_scbs[tcl]; + target_offset = TCL_TARGET_OFFSET(tcl); + scbid = ahc_inb(ahc, BUSY_TARGETS + target_offset); if (unbusy) - ahc->untagged_scbs[tcl] = SCB_LIST_NULL; + ahc_outb(ahc, BUSY_TARGETS + target_offset, SCB_LIST_NULL); return (scbid); } -static __inline void -ahc_busy_tcl(struct ahc_softc *ahc, struct scb *scb) +static __inline int +ahc_check_residual(struct scb *scb) { - ahc->untagged_scbs[scb->hscb->tcl] = scb->hscb->tag; + struct status_pkt *sp; + + sp = &scb->hscb->shared_data.status; + if ((scb->hscb->sgptr & SG_RESID_VALID) != 0) + return (1); + return (0); } static __inline void @@ -520,6 +531,83 @@ ahc_fetch_transinfo(struct ahc_softc *ahc, char channel, u_int our_id, return (&(*tstate)->transinfo[remote_id]); } +static __inline struct ahc_dma_seg * +ahc_sg_bus_to_virt(struct scb *scb, uint32_t sg_busaddr) +{ + int sg_index; + + sg_index = (sg_busaddr - scb->sg_list_phys)/sizeof(struct ahc_dma_seg); + /* sg_list_phys points to entry 1, not 0 */ + sg_index++; + + return (&scb->sg_list[sg_index]); +} + +static __inline uint32_t +ahc_sg_virt_to_bus(struct scb *scb, struct ahc_dma_seg *sg) +{ + int sg_index; + + /* sg_list_phys points to entry 1, not 0 */ + sg_index = sg - &scb->sg_list[1]; + + return (scb->sg_list_phys + (sg_index * sizeof(*scb->sg_list))); +} + +static __inline void +ahc_queue_scb(struct ahc_softc *ahc, struct scb *scb) +{ + ahc->qinfifo[ahc->qinfifonext++] = scb->hscb->tag; + if ((ahc->features & AHC_QUEUE_REGS) != 0) { + ahc_outb(ahc, HNSCB_QOFF, ahc->qinfifonext); + } else { + pause_sequencer(ahc); + ahc_outb(ahc, KERNEL_QINPOS, ahc->qinfifonext); + unpause_sequencer(ahc); + } +} + +static __inline void +ahc_freeze_untagged_queues(struct ahc_softc *ahc) +{ + if ((ahc->features & AHC_SCB_BTT) == 0) + ahc->untagged_queue_lock++; +} + +static __inline void +ahc_release_untagged_queues(struct ahc_softc *ahc) +{ + if ((ahc->features & AHC_SCB_BTT) == 0) { + ahc->untagged_queue_lock--; + if (ahc->untagged_queue_lock == 0) + ahc_run_untagged_queues(ahc); + } +} + +static void +ahc_run_untagged_queues(struct ahc_softc *ahc) +{ + int i; + + for (i = 0; i < 16; i++) + ahc_run_untagged_queue(ahc, &ahc->untagged_queues[i]); +} + +static void +ahc_run_untagged_queue(struct ahc_softc *ahc, struct scb_tailq *queue) +{ + struct scb *scb; + + if (ahc->untagged_queue_lock != 0) + return; + + if ((scb = TAILQ_FIRST(queue)) != NULL + && (scb->flags & SCB_ACTIVE) == 0) { + scb->flags |= SCB_ACTIVE; + ahc_queue_scb(ahc, scb); + } +} + static void ahc_run_tqinfifo(struct ahc_softc *ahc, int paused) { @@ -529,7 +617,7 @@ ahc_run_tqinfifo(struct ahc_softc *ahc, int paused) /* * Only advance through the queue if we - * had the resources to process the command. + * have the resources to process the command. */ if (ahc_handle_target_cmd(ahc, cmd) != 0) break; @@ -585,7 +673,7 @@ ahc_run_qoutfifo(struct ahc_softc *ahc) * Save off the residual * if there is one. */ - if (scb->hscb->residual_SG_count != 0) + if (ahc_check_residual(scb) != 0) ahc_calc_residual(scb); else scb->ccb->csio.resid = 0; @@ -595,8 +683,7 @@ ahc_run_qoutfifo(struct ahc_softc *ahc) /* - * An scb (and hence an scb entry on the board) is put onto the - * free list. + * Return an SCB resource to the free list. */ static void ahcfreescb(struct ahc_softc *ahc, struct scb *scb) @@ -617,17 +704,13 @@ ahcfreescb(struct ahc_softc *ahc, struct scb *scb) /* Clean up for the next user */ scb->flags = SCB_FREE; hscb->control = 0; - hscb->status = 0; - SLIST_INSERT_HEAD(&ahc->scb_data->free_scbs, scb, links); + SLIST_INSERT_HEAD(&ahc->scb_data->free_scbs, scb, links.sle); splx(opri); } /* - * Get a free scb, either one already assigned to a hardware slot - * on the adapter or one that will require an SCB to be paged out before - * use. If there are none, see if we can allocate a new SCB. Otherwise - * either return an error or sleep. + * Get a free scb. If there are none, see if we can allocate a new SCB. */ static __inline struct scb * ahcgetscb(struct ahc_softc *ahc) @@ -637,12 +720,12 @@ ahcgetscb(struct ahc_softc *ahc) opri = splcam(); if ((scbp = SLIST_FIRST(&ahc->scb_data->free_scbs))) { - SLIST_REMOVE_HEAD(&ahc->scb_data->free_scbs, links); + SLIST_REMOVE_HEAD(&ahc->scb_data->free_scbs, links.sle); } else { ahcallocscbs(ahc); scbp = SLIST_FIRST(&ahc->scb_data->free_scbs); if (scbp != NULL) - SLIST_REMOVE_HEAD(&ahc->scb_data->free_scbs, links); + SLIST_REMOVE_HEAD(&ahc->scb_data->free_scbs, links.sle); } splx(opri); @@ -663,32 +746,50 @@ ahc_name(struct ahc_softc *ahc) static void ahc_print_scb(struct scb *scb) { + int i; + struct hardware_scb *hscb = scb->hscb; - printf("scb:%p control:0x%x tcl:0x%x cmdlen:%d cmdpointer:0x%x\n", - scb, - hscb->control, - hscb->tcl, - hscb->cmdlen, - hscb->cmdpointer); - printf(" datlen:%d data:0x%x segs:0x%x segp:0x%x\n", - hscb->datalen, - hscb->data, - hscb->SG_count, - hscb->SG_pointer); - printf(" sg_addr:%x sg_len:%d\n", - scb->sg_list[0].addr, - scb->sg_list[0].len); - printf(" cdb:%x %x %x %x %x %x %x %x %x %x %x %x\n", - hscb->cmdstore[0], hscb->cmdstore[1], hscb->cmdstore[2], - hscb->cmdstore[3], hscb->cmdstore[4], hscb->cmdstore[5], - hscb->cmdstore[6], hscb->cmdstore[7], hscb->cmdstore[8], - hscb->cmdstore[9], hscb->cmdstore[10], hscb->cmdstore[11]); + printf("scb:%p control:0x%x scsiid:0x%x lun:%d cdb_len:%d\n", + scb, + hscb->control, + hscb->scsiid, + hscb->lun, + hscb->cdb_len); + i = 0; + printf("Shared Data: %#02x %#02x %#02x %#02x\n", + hscb->shared_data.cdb[i++], + hscb->shared_data.cdb[i++], + hscb->shared_data.cdb[i++], + hscb->shared_data.cdb[i++]); + printf(" %#02x %#02x %#02x %#02x\n", + hscb->shared_data.cdb[i++], + hscb->shared_data.cdb[i++], + hscb->shared_data.cdb[i++], + hscb->shared_data.cdb[i++]); + printf(" %#02x %#02x %#02x %#02x\n", + hscb->shared_data.cdb[i++], + hscb->shared_data.cdb[i++], + hscb->shared_data.cdb[i++], + hscb->shared_data.cdb[i++]); + printf(" dataptr:%#x datacnt:%#x sgptr:%#x tag:%#x\n", + hscb->dataptr, + hscb->datacnt, + hscb->sgptr, + hscb->tag); + if (scb->sg_count > 0) { + for (i = 0; i < scb->sg_count; i++) { + printf("sg[%d] - Addr 0x%x : Length %d\n", + i, + scb->sg_list[i].addr, + scb->sg_list[i].len); + } + } } #endif static struct { - u_int8_t errno; + uint8_t errno; char *errmesg; } hard_error[] = { { ILLHADDR, "Illegal Host Access" }, @@ -703,8 +804,8 @@ static struct { static const int num_errors = sizeof(hard_error)/sizeof(hard_error[0]); static struct { - u_int8_t phase; - u_int8_t mesg_out; /* Message response to parity errors */ + uint8_t phase; + uint8_t mesg_out; /* Message response to parity errors */ char *phasemsg; } phase_table[] = { { P_DATAOUT, MSG_NOOP, "in Data-out phase" }, @@ -716,7 +817,8 @@ static struct { { P_BUSFREE, MSG_NOOP, "while idle" }, { 0, MSG_NOOP, "in unknown phase" } }; -static const int num_phases = (sizeof(phase_table)/sizeof(phase_table[0])) - 1; +static const u_int num_phases = + (sizeof(phase_table)/sizeof(phase_table[0])) - 1; /* * Valid SCSIRATE values. (p. 3-17) @@ -746,22 +848,35 @@ static struct ahc_syncrate ahc_syncrates[] = { { 0x00, 0x000, 0, NULL } }; +void +ahc_init_probe_config(struct ahc_probe_config *probe_config) +{ + probe_config->description = NULL; + probe_config->channel = 'A'; + probe_config->channel_b = 'B'; + probe_config->chip = AHC_NONE; + probe_config->features = AHC_FENONE; + probe_config->bugs = AHC_BUGNONE; + probe_config->flags = AHC_FNONE; +} + /* * Allocate a controller structure for a new device and initialize it. */ struct ahc_softc * ahc_alloc(device_t dev, struct resource *regs, int regs_type, int regs_id, - bus_dma_tag_t parent_dmat, ahc_chip chip, ahc_feature features, - ahc_flag flags, struct scb_data *scb_data) + bus_dma_tag_t parent_dmat, struct ahc_probe_config *config, + struct scb_data *scb_data) { /* * find unit and check we have that many defined */ struct ahc_softc *ahc; size_t alloc_size; + int i; /* - * Allocate a storage area for us + * Allocate a storage area for us. */ if (scb_data == NULL) /* @@ -786,9 +901,14 @@ ahc_alloc(device_t dev, struct resource *regs, int regs_type, int regs_id, ahc->tag = rman_get_bustag(regs); ahc->bsh = rman_get_bushandle(regs); ahc->parent_dmat = parent_dmat; - ahc->chip = chip; - ahc->features = features; - ahc->flags = flags; + ahc->chip = config->chip; + ahc->features = config->features; + ahc->bugs = config->bugs; + ahc->flags = config->flags; + ahc->channel = config->channel; + for (i = 0; i < 16; i++) + TAILQ_INIT(&ahc->untagged_queues[i]); + if (scb_data == NULL) { struct full_ahc_softc* full_softc = (struct full_ahc_softc*)ahc; ahc->scb_data = &full_softc->scb_data_storage; @@ -1046,12 +1166,17 @@ int ahc_reset(struct ahc_softc *ahc) { u_int sblkctl; + u_int sxfrctl1; int wait; #ifdef AHC_DUMP_SEQ if (ahc->init_level == 0) ahc_dumpseq(ahc); #endif + + /* Cache STPWEN. It is cleared by a chip reset */ + pause_sequencer(ahc); + sxfrctl1 = ahc_inb(ahc, SXFRCTL1) & STPWEN; ahc_outb(ahc, HCNTRL, CHIPRST | ahc->pause); /* * Ensure that the reset has finished @@ -1066,6 +1191,21 @@ ahc_reset(struct ahc_softc *ahc) "Trying to initialize anyway.\n", ahc_name(ahc)); } ahc_outb(ahc, HCNTRL, ahc->pause); + /* + * Reload sxfrctl1 with the cached value of STPWEN + * to minimize the amount of time our terminators + * are disabled. If a BIOS has initialized the chip, + * then sxfrctl1 will have the correct value. If + * not, STPWEN will be false (the value after a POST) + * and this action will be harmless. + * + * We must actually always initialize STPWEN to 1 + * before we restore the saved value. STPWEN is + * initialized to a tri-state condition which is + * only be cleared by turning it on. + */ + ahc_outb(ahc, SXFRCTL1, sxfrctl1|STPWEN); + ahc_outb(ahc, SXFRCTL1, sxfrctl1); /* Determine channel configuration */ sblkctl = ahc_inb(ahc, SBLKCTL) & (SELBUSB|SELWIDE); @@ -1098,22 +1238,25 @@ ahc_reset(struct ahc_softc *ahc) * by the capabilities of the bus connectivity of the target. */ static struct ahc_syncrate * -ahc_devlimited_syncrate(struct ahc_softc *ahc, u_int *period) { +ahc_devlimited_syncrate(struct ahc_softc *ahc, u_int *period, + u_int *ppr_options) { u_int maxsync; if ((ahc->features & AHC_ULTRA2) != 0) { if ((ahc_inb(ahc, SBLKCTL) & ENAB40) != 0 && (ahc_inb(ahc, SSTAT2) & EXP_ACTIVE) == 0) { - maxsync = AHC_SYNCRATE_ULTRA2; + maxsync = AHC_SYNCRATE_DT; } else { maxsync = AHC_SYNCRATE_ULTRA; + /* Can't do DT on an SE bus */ + *ppr_options &= ~MSG_EXT_PPR_DT_REQ; } } else if ((ahc->features & AHC_ULTRA) != 0) { maxsync = AHC_SYNCRATE_ULTRA; } else { maxsync = AHC_SYNCRATE_FAST; } - return (ahc_find_syncrate(ahc, period, maxsync)); + return (ahc_find_syncrate(ahc, period, ppr_options, maxsync)); } /* @@ -1122,14 +1265,30 @@ ahc_devlimited_syncrate(struct ahc_softc *ahc, u_int *period) { * if this was the beginning of an SDTR. */ static struct ahc_syncrate * -ahc_find_syncrate(struct ahc_softc *ahc, u_int *period, u_int maxsync) +ahc_find_syncrate(struct ahc_softc *ahc, u_int *period, + u_int *ppr_options, u_int maxsync) { struct ahc_syncrate *syncrate; - syncrate = &ahc_syncrates[maxsync]; - while ((syncrate->rate != NULL) - && ((ahc->features & AHC_ULTRA2) == 0 - || (syncrate->sxfr_u2 != 0))) { + if ((ahc->features & AHC_DT) == 0) + *ppr_options &= ~MSG_EXT_PPR_DT_REQ; + + for (syncrate = &ahc_syncrates[maxsync]; + syncrate->rate != NULL; + syncrate++) { + + /* + * The Ultra2 table doesn't go as low + * as for the Fast/Ultra cards. + */ + if ((ahc->features & AHC_ULTRA2) != 0 + && (syncrate->sxfr_u2 == 0)) + break; + + /* Skip any DT entries if DT is not available */ + if ((*ppr_options & MSG_EXT_PPR_DT_REQ) == 0 + && (syncrate->sxfr_u2 & DT_SXFR) != 0) + continue; if (*period <= syncrate->period) { /* @@ -1145,9 +1304,15 @@ ahc_find_syncrate(struct ahc_softc *ahc, u_int *period, u_int maxsync) */ if (syncrate == &ahc_syncrates[maxsync]) *period = syncrate->period; + + /* + * At some speeds, we only support + * ST transfers. + */ + if ((syncrate->sxfr_u2 & ST_SXFR) != 0) + *ppr_options &= ~MSG_EXT_PPR_DT_REQ; break; } - syncrate++; } if ((*period == 0) @@ -1157,6 +1322,7 @@ ahc_find_syncrate(struct ahc_softc *ahc, u_int *period, u_int maxsync) /* Use asynchronous transfers. */ *period = 0; syncrate = NULL; + *ppr_options &= ~MSG_EXT_PPR_DT_REQ; } return (syncrate); } @@ -1207,6 +1373,24 @@ ahc_validate_offset(struct ahc_softc *ahc, struct ahc_syncrate *syncrate, *offset = MIN(*offset, maxoffset); } + +static void +ahc_validate_width(struct ahc_softc *ahc, u_int *bus_width) +{ + switch (*bus_width) { + default: + if (ahc->features & AHC_WIDE) { + /* Respond Wide */ + *bus_width = MSG_EXT_WDTR_BUS_16_BIT; + break; + } + /* FALLTHROUGH */ + case MSG_EXT_WDTR_BUS_8_BIT: + bus_width = MSG_EXT_WDTR_BUS_8_BIT; + break; + } +} + static void ahc_update_target_msg_request(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, @@ -1228,28 +1412,16 @@ ahc_update_target_msg_request(struct ahc_softc *ahc, if (ahc->targ_msg_req != targ_msg_req_orig) { /* Update the message request bit for this target */ - if ((ahc->features & AHC_HS_MAILBOX) != 0) { - if (paused) { - ahc_outb(ahc, TARGET_MSG_REQUEST, - ahc->targ_msg_req & 0xFF); - ahc_outb(ahc, TARGET_MSG_REQUEST + 1, - (ahc->targ_msg_req >> 8) & 0xFF); - } else { - ahc_outb(ahc, HS_MAILBOX, - 0x01 << HOST_MAILBOX_SHIFT); - } - } else { - if (!paused) - pause_sequencer(ahc); + if (!paused) + pause_sequencer(ahc); - ahc_outb(ahc, TARGET_MSG_REQUEST, - ahc->targ_msg_req & 0xFF); - ahc_outb(ahc, TARGET_MSG_REQUEST + 1, - (ahc->targ_msg_req >> 8) & 0xFF); + ahc_outb(ahc, TARGET_MSG_REQUEST, + ahc->targ_msg_req & 0xFF); + ahc_outb(ahc, TARGET_MSG_REQUEST + 1, + (ahc->targ_msg_req >> 8) & 0xFF); - if (!paused) - unpause_sequencer(ahc); - } + if (!paused) + unpause_sequencer(ahc); } } @@ -1272,7 +1444,8 @@ ahc_create_path(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, static void ahc_set_syncrate(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, struct cam_path *path, struct ahc_syncrate *syncrate, - u_int period, u_int offset, u_int type, int paused) + u_int period, u_int offset, u_int ppr_options, + u_int type, int paused) { struct ahc_initiator_tinfo *tinfo; struct tmode_tstate *tstate; @@ -1298,12 +1471,14 @@ ahc_set_syncrate(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, scsirate = tinfo->scsirate; if ((ahc->features & AHC_ULTRA2) != 0) { - /* XXX */ - /* Force single edge until DT is fully implemented */ scsirate &= ~(SXFR_ULTRA2|SINGLE_EDGE|ENABLE_CRC); - if (syncrate != NULL) - scsirate |= syncrate->sxfr_u2|SINGLE_EDGE; - + if (syncrate != NULL) { + scsirate |= syncrate->sxfr_u2; + if ((ppr_options & MSG_EXT_PPR_DT_REQ) != 0) + scsirate |= ENABLE_CRC; + else + scsirate |= SINGLE_EDGE; + } if (active) ahc_outb(ahc, SCSIOFFSET, offset); } else { @@ -1338,6 +1513,7 @@ ahc_set_syncrate(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, tinfo->scsirate = scsirate; tinfo->current.period = period; tinfo->current.offset = offset; + tinfo->current.ppr_options = ppr_options; /* Update the syncrates in any pending scbs */ ahc_update_pending_syncrates(ahc); @@ -1361,6 +1537,7 @@ ahc_set_syncrate(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, if (path != NULL) { struct ccb_trans_settings neg; + neg.flags = CCB_TRANS_CURRENT_SETTINGS; neg.sync_period = period; neg.sync_offset = offset; neg.valid = CCB_TRANS_SYNC_RATE_VALID @@ -1374,9 +1551,11 @@ ahc_set_syncrate(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, if (bootverbose) { if (offset != 0) { - printf("%s: target %d synchronous at %sMHz, " + printf("%s: target %d synchronous at %sMHz%s, " "offset = 0x%x\n", ahc_name(ahc), - devinfo->target, syncrate->rate, offset); + devinfo->target, syncrate->rate, + (ppr_options & MSG_EXT_PPR_DT_REQ) + ? " DT" : "", offset); } else { printf("%s: target %d using " "asynchronous transfers\n", @@ -1388,11 +1567,13 @@ ahc_set_syncrate(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, if ((type & AHC_TRANS_GOAL) != 0) { tinfo->goal.period = period; tinfo->goal.offset = offset; + tinfo->goal.ppr_options = ppr_options; } if ((type & AHC_TRANS_USER) != 0) { tinfo->user.period = period; tinfo->user.offset = offset; + tinfo->user.ppr_options = ppr_options; } ahc_update_target_msg_request(ahc, devinfo, tinfo, @@ -1444,6 +1625,7 @@ ahc_set_width(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, if (path != NULL) { struct ccb_trans_settings neg; + neg.flags = CCB_TRANS_CURRENT_SETTINGS; neg.bus_width = width; neg.valid = CCB_TRANS_BUS_WIDTH_VALID; xpt_setup_ccb(&neg.ccb_h, path, /*priority*/1); @@ -1634,18 +1816,18 @@ ahc_scb_devinfo(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, our_id = scb->ccb->ccb_h.target_id; role = ROLE_TARGET; } else { - our_id = SCB_CHANNEL(scb) == 'B' ? ahc->our_id_b : ahc->our_id; + our_id = SCB_GET_CHANNEL(scb) == 'B' ? ahc->our_id_b : ahc->our_id; role = ROLE_INITIATOR; } - ahc_compile_devinfo(devinfo, our_id, SCB_TARGET(scb), - SCB_LUN(scb), SCB_CHANNEL(scb), role); + ahc_compile_devinfo(devinfo, our_id, SCB_GET_TARGET(ahc, scb), + SCB_GET_LUN(scb), SCB_GET_CHANNEL(scb), role); } #endif static void ahc_fetch_devinfo(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) { - u_int saved_tcl; + u_int saved_scsiid; role_t role; int our_id; @@ -1664,9 +1846,12 @@ ahc_fetch_devinfo(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) else our_id = ahc_inb(ahc, SCSIID) & OID; - saved_tcl = ahc_inb(ahc, SAVED_TCL); - ahc_compile_devinfo(devinfo, our_id, TCL_TARGET(saved_tcl), - TCL_LUN(saved_tcl), TCL_CHANNEL(ahc, saved_tcl), + saved_scsiid = ahc_inb(ahc, SAVED_SCSIID); + ahc_compile_devinfo(devinfo, + our_id, + SCSIID_TARGET(ahc, saved_scsiid), + ahc_inb(ahc, SAVED_LUN), + SCSIID_CHANNEL(ahc, saved_scsiid), role); } @@ -1723,9 +1908,8 @@ ahc_intr(void *arg) if (intstat & CMDCMPLT) { ahc_outb(ahc, CLRINT, CLRCMDINT); ahc_run_qoutfifo(ahc); - if ((ahc->flags & AHC_TARGETMODE) != 0) { + if ((ahc->flags & AHC_TARGETMODE) != 0) ahc_run_tqinfifo(ahc, /*paused*/FALSE); - } } if (intstat & BRKADRINT) { /* @@ -1748,10 +1932,14 @@ ahc_intr(void *arg) CAM_LUN_WILDCARD, SCB_LIST_NULL, ROLE_UNKNOWN, CAM_NO_HBA); } - if (intstat & SEQINT) + + if ((intstat & (SEQINT|SCSIINT)) != 0) + ahc_pause_bug_fix(ahc); + + if ((intstat & SEQINT) != 0) ahc_handle_seqint(ahc, intstat); - if (intstat & SCSIINT) + if ((intstat & SCSIINT) != 0) ahc_handle_scsiint(ahc, intstat); } @@ -1826,8 +2014,8 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb) struct tmode_lstate *lstate; struct ccb_en_lun *cel; cam_status status; - int target; - int lun; + u_int target; + u_int lun; u_int target_mask; char channel; int s; @@ -1922,7 +2110,7 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb) ahc_update_scsiid(ahc, targid_mask); } else { - int our_id; + u_int our_id; char channel; channel = SIM_CHANNEL(ahc, sim); @@ -2113,19 +2301,19 @@ ahc_handle_target_cmd(struct ahc_softc *ahc, struct target_cmd *cmd) struct tmode_tstate *tstate; struct tmode_lstate *lstate; struct ccb_accept_tio *atio; - u_int8_t *byte; + uint8_t *byte; int initiator; int target; int lun; - initiator = cmd->initiator_channel >> 4; - target = cmd->targ_id; + initiator = SCSIID_TARGET(ahc, cmd->scsiid); + target = SCSIID_OUR_ID(cmd->scsiid); lun = (cmd->identify & MSG_IDENTIFY_LUNMASK); byte = cmd->bytes; tstate = ahc->enabled_targets[target]; lstate = NULL; - if (tstate != NULL && lun < 8) + if (tstate != NULL) lstate = tstate->enabled_luns[lun]; /* @@ -2168,9 +2356,9 @@ ahc_handle_target_cmd(struct ahc_softc *ahc, struct target_cmd *cmd) atio->tag_id = *byte++; atio->ccb_h.flags = CAM_TAG_ACTION_VALID; } else { - byte++; atio->ccb_h.flags = 0; } + byte++; /* Okay. Now determine the cdb size based on the command code */ switch (*byte >> CMD_GROUP_CODE_SHIFT) { @@ -2210,6 +2398,8 @@ ahc_handle_target_cmd(struct ahc_softc *ahc, struct target_cmd *cmd) initiator, target, lun, ahc->pending_device); #endif ahc->pending_device = lstate; + ahc_freeze_ccb((union ccb *)atio); + atio->ccb_h.flags |= CAM_DIS_DISCONNECT; } xpt_done((union ccb*)atio); return (0); @@ -2231,81 +2421,6 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) */ ahc_outb(ahc, CLRINT, CLRSEQINT); switch (intstat & SEQINT_MASK) { - case NO_MATCH: - { - /* Ensure we don't leave the selection hardware on */ - ahc_outb(ahc, SCSISEQ, - ahc_inb(ahc, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP)); - - printf("%s:%c:%d: no active SCB for reconnecting " - "target - issuing BUS DEVICE RESET\n", - ahc_name(ahc), devinfo.channel, devinfo.target); - printf("SAVED_TCL == 0x%x, ARG_1 == 0x%x, SEQ_FLAGS == 0x%x\n", - ahc_inb(ahc, SAVED_TCL), ahc_inb(ahc, ARG_1), - ahc_inb(ahc, SEQ_FLAGS)); - ahc->msgout_buf[0] = MSG_BUS_DEV_RESET; - ahc->msgout_len = 1; - ahc->msgout_index = 0; - ahc->msg_type = MSG_TYPE_INITIATOR_MSGOUT; - ahc_outb(ahc, MSG_OUT, HOST_MSG); - ahc_outb(ahc, SCSISIGO, ahc_inb(ahc, LASTPHASE) | ATNO); - break; - } - case UPDATE_TMSG_REQ: - ahc_outb(ahc, TARGET_MSG_REQUEST, ahc->targ_msg_req & 0xFF); - ahc_outb(ahc, TARGET_MSG_REQUEST + 1, - (ahc->targ_msg_req >> 8) & 0xFF); - ahc_outb(ahc, HS_MAILBOX, 0); - break; - case SEND_REJECT: - { - u_int rejbyte = ahc_inb(ahc, ACCUM); - printf("%s:%c:%d: Warning - unknown message received from " - "target (0x%x). Rejecting\n", - ahc_name(ahc), devinfo.channel, devinfo.target, rejbyte); - break; - } - case NO_IDENT: - { - /* - * The reconnecting target either did not send an identify - * message, or did, but we didn't find and 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_TCL == 0x%x\n", - ahc_name(ahc), devinfo.channel, devinfo.target, - ahc_inb(ahc, LASTPHASE), ahc_inb(ahc, SAVED_TCL)); - 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; - } - case BAD_PHASE: - { - u_int lastphase; - - lastphase = ahc_inb(ahc, LASTPHASE); - if (lastphase == P_BUSFREE) { - printf("%s:%c:%d: Missed busfree. Curphase = 0x%x\n", - ahc_name(ahc), devinfo.channel, devinfo.target, - ahc_inb(ahc, SCSISIGI)); - restart_sequencer(ahc); - return; - } else { - printf("%s:%c:%d: unknown scsi bus phase %x. " - "Attempting to continue\n", - ahc_name(ahc), devinfo.channel, devinfo.target, - ahc_inb(ahc, SCSISIGI)); - } - break; - } case BAD_STATUS: { u_int scb_index; @@ -2352,12 +2467,12 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) break; } ahcsetccbstatus(scb->ccb, CAM_SCSI_STATUS_ERROR); - /* Freeze the queue unit the client sees the error. */ + /* Freeze the queue until the client sees the error. */ ahc_freeze_devq(ahc, scb->ccb->ccb_h.path); ahc_freeze_ccb(scb->ccb); csio = &scb->ccb->csio; - csio->scsi_status = hscb->status; - switch (hscb->status) { + csio->scsi_status = hscb->shared_data.status.scsi_status; + switch (csio->scsi_status) { case SCSI_STATUS_OK: printf("%s: Interrupted for staus of 0???\n", ahc_name(ahc)); @@ -2371,19 +2486,27 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) scb->hscb->tag); } #endif - if ((csio->ccb_h.flags & CAM_DIS_AUTOSENSE) == 0) { struct ahc_dma_seg *sg; struct scsi_sense *sc; - struct ahc_initiator_tinfo *tinfo; + struct ahc_initiator_tinfo *targ_info; struct tmode_tstate *tstate; - + struct ahc_transinfo *tinfo; + + targ_info = + ahc_fetch_transinfo(ahc, + devinfo.channel, + devinfo.our_scsiid, + devinfo.target, + &tstate); + tinfo = &targ_info->current; sg = scb->sg_list; - sc = (struct scsi_sense *)(&hscb->cmdstore); + sc = (struct scsi_sense *) + (&hscb->shared_data.cdb); /* * Save off the residual if there is one. */ - if (hscb->residual_SG_count != 0) + if (ahc_check_residual(scb)) ahc_calc_residual(scb); else scb->ccb->csio.resid = 0; @@ -2398,9 +2521,13 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) + (hscb->tag*sizeof(struct scsi_sense_data)); sg->len = MIN(sizeof(struct scsi_sense_data), csio->sense_len); + sg->len |= AHC_DMA_LAST_SEG; sc->opcode = REQUEST_SENSE; - sc->byte2 = SCB_LUN(scb) << 5; + sc->byte2 = 0; + if (tinfo->protocol_version <= SCSI_REV_2 + && SCB_GET_LUN(scb) < 8) + sc->byte2 = SCB_GET_LUN(scb) << 5; sc->unused[0] = 0; sc->unused[1] = 0; sc->length = sg->len; @@ -2408,7 +2535,8 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) /* * Would be nice to preserve DISCENB here, - * but due to the way we page SCBs, we can't. + * but due to the way we manage busy targets, + * we can't. */ hscb->control = 0; @@ -2420,34 +2548,20 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) * errors will be reported before any data * phases occur. */ - ahc_calc_residual(scb); if (scb->ccb->csio.resid == scb->ccb->csio.dxfer_len) { - tinfo = ahc_fetch_transinfo(ahc, - devinfo.channel, - devinfo.our_scsiid, - devinfo.target, - &tstate); ahc_update_target_msg_request(ahc, &devinfo, - tinfo, + targ_info, /*force*/TRUE, /*paused*/TRUE); } - hscb->status = 0; - hscb->SG_count = 1; - hscb->SG_pointer = scb->sg_list_phys; - hscb->data = sg->addr; - hscb->datalen = sg->len; - hscb->cmdpointer = hscb->cmdstore_busaddr; - hscb->cmdlen = sizeof(*sc); - scb->sg_count = hscb->SG_count; + hscb->cdb_len = sizeof(*sc); + hscb->dataptr = sg->addr; + hscb->datacnt = sg->len; + hscb->sgptr = scb->sg_list_phys | SG_FULL_RESID; + scb->sg_count = 1; scb->flags |= SCB_SENSE; - /* - * Ensure the target is busy since this - * will be an untagged request. - */ - ahc_busy_tcl(ahc, scb); ahc_outb(ahc, RETURN_1, SEND_SENSE); /* @@ -2460,29 +2574,89 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) timeout(ahc_timeout, (caddr_t)scb, 5 * hz); } break; - case SCSI_STATUS_BUSY: - case SCSI_STATUS_QUEUE_FULL: - /* - * Requeue any transactions that haven't been - * sent yet. - */ - ahc_freeze_devq(ahc, scb->ccb->ccb_h.path); - ahc_freeze_ccb(scb->ccb); + default: break; } break; } - case TRACE_POINT: + case NO_MATCH: { - printf("SSTAT2 = 0x%x DFCNTRL = 0x%x\n", ahc_inb(ahc, SSTAT2), - ahc_inb(ahc, DFCNTRL)); - printf("SSTAT3 = 0x%x DSTATUS = 0x%x\n", ahc_inb(ahc, SSTAT3), - ahc_inb(ahc, DFSTATUS)); - printf("SSTAT0 = 0x%x, SCB_DATACNT = 0x%x\n", - ahc_inb(ahc, SSTAT0), - ahc_inb(ahc, SCB_DATACNT)); + /* Ensure we don't leave the selection hardware on */ + ahc_outb(ahc, SCSISEQ, + ahc_inb(ahc, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP)); + + 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%x, SAVED_LUN == 0x%x, " + "ARG_1 == 0x%x ARG_2 = 0x%x, SEQ_FLAGS == 0x%x\n", + ahc_inb(ahc, SAVED_SCSIID), ahc_inb(ahc, SAVED_LUN), + ahc_inb(ahc, ARG_1), ahc_inb(ahc, ARG_2), + ahc_inb(ahc, SEQ_FLAGS)); + printf("SCB_SCSIID == 0x%x, SCB_LUN == 0x%x, " + "SCB_TAG == 0x%x\n", + ahc_inb(ahc, SCB_SCSIID), ahc_inb(ahc, SCB_LUN), + ahc_inb(ahc, SCB_TAG)); + ahc->msgout_buf[0] = MSG_BUS_DEV_RESET; + ahc->msgout_len = 1; + ahc->msgout_index = 0; + ahc->msg_type = MSG_TYPE_INITIATOR_MSGOUT; + ahc_outb(ahc, MSG_OUT, HOST_MSG); + ahc_outb(ahc, SCSISIGO, ahc_inb(ahc, LASTPHASE) | ATNO); break; } + case SEND_REJECT: + { + u_int rejbyte = ahc_inb(ahc, ACCUM); + printf("%s:%c:%d: Warning - unknown message received from " + "target (0x%x). Rejecting\n", + ahc_name(ahc), devinfo.channel, devinfo.target, rejbyte); + break; + } + case NO_IDENT: + { + /* + * 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; + } + case IGN_WIDE_RES: + ahc_handle_ign_wide_residue(ahc, &devinfo); + break; + case BAD_PHASE: + { + u_int lastphase; + + lastphase = ahc_inb(ahc, LASTPHASE); + if (lastphase == P_BUSFREE) { + printf("%s:%c:%d: Missed busfree. Curphase = 0x%x\n", + ahc_name(ahc), devinfo.channel, devinfo.target, + ahc_inb(ahc, SCSISIGI)); + restart_sequencer(ahc); + return; + } else { + printf("%s:%c:%d: unknown scsi bus phase %x. " + "Attempting to continue\n", + ahc_name(ahc), devinfo.channel, devinfo.target, + ahc_inb(ahc, SCSISIGI)); + } + break; + } case HOST_MSG_LOOP: { /* @@ -2490,10 +2664,11 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) * that requires host assistance for completion. * While handling the message phase(s), we will be * notified by the sequencer after each byte is - * transfered so we can track bus phases. + * transfered so we can track bus phase changes. * - * If this is the first time we've seen a HOST_MSG_LOOP, - * initialize the state of the host message loop. + * If this is the first time we've seen a HOST_MSG_LOOP + * interrupt, initialize the state of the host message + * loop. */ if (ahc->msg_type == MSG_TYPE_NONE) { u_int bus_phase; @@ -2510,6 +2685,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) */ ahc_clear_intstat(ahc); restart_sequencer(ahc); + return; } if (devinfo.role == ROLE_INITIATOR) { @@ -2585,7 +2761,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) */ u_int scbindex = ahc_inb(ahc, SCB_TAG); u_int lastphase = ahc_inb(ahc, LASTPHASE); - int i; + u_int i; scb = &ahc->scb_data->scbarray[scbindex]; for (i = 0; i < num_phases; i++) { @@ -2606,11 +2782,11 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) printf("sg[%d] - Addr 0x%x : Length %d\n", i, scb->sg_list[i].addr, - scb->sg_list[i].len); + scb->sg_list[i].len & AHC_SG_LEN_MASK); } } /* - * Set this and it will take affect when the + * Set this and it will take effect when the * target does a command complete. */ ahc_freeze_devq(ahc, scb->ccb->ccb_h.path); @@ -2620,7 +2796,79 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) } case TRACEPOINT: { - printf("TRACEPOINT: RETURN_2 = %d\n", ahc_inb(ahc, RETURN_2)); + printf("SAVED_SCSIID %x, SAVED_LUN %x, SCBPTR %x\n", + ahc_inb(ahc, SAVED_SCSIID), ahc_inb(ahc, SAVED_LUN), + ahc_inb(ahc, SCBPTR)); +#if 0 + printf("%s: SCB_DATAPTR = %x, SCB_DATACNT = %x\n", + ahc_name(ahc), + ahc_inb(ahc, SCB_DATAPTR) + | (ahc_inb(ahc, SCB_DATAPTR + 1) << 8) + | (ahc_inb(ahc, SCB_DATAPTR + 2) << 16) + | (ahc_inb(ahc, SCB_DATAPTR + 3) << 24), + ahc_inb(ahc, SCB_DATACNT) + | (ahc_inb(ahc, SCB_DATACNT + 1) << 8) + | (ahc_inb(ahc, SCB_DATACNT + 2) << 16) + | (ahc_inb(ahc, SCB_DATACNT + 3) << 24)); + printf("SCSIRATE = %x\n", ahc_inb(ahc, SCSIRATE)); + printf("SG_CACHEPTR = %x\n", ahc_inb(ahc, SINDEX)); + printf("DFCNTRL = %x, DFSTATUS = %x\n", + ahc_inb(ahc, DFCNTRL), + ahc_inb(ahc, DFSTATUS)); + if ((ahc->features & AHC_CMD_CHAN) != 0) { + printf("CCHADDR = 0x%x\n", + ahc_inb(ahc, CCHADDR) + | (ahc_inb(ahc, CCHADDR + 1) << 8) + | (ahc_inb(ahc, CCHADDR + 2) << 16) + | (ahc_inb(ahc, CCHADDR + 3) << 24)); + } else { + printf("HADDR = 0x%x\n", + ahc_inb(ahc, HADDR) + | (ahc_inb(ahc, HADDR + 1) << 8) + | (ahc_inb(ahc, HADDR + 2) << 16) + | (ahc_inb(ahc, HADDR + 3) << 24)); + } + +#endif + break; + } + case TRACEPOINT2: + { + printf("SINDEX = %x\n", ahc_inb(ahc, SINDEX)); + printf("SCSIRATE = %x\n", ahc_inb(ahc, SCSIRATE)); +#if 0 + printf("SCB_RESIDUAL_SGPTR = %x, SCB_RESIDUAL_DATACNT = %x\n", + ahc_inb(ahc, SCB_RESIDUAL_SGPTR) + | (ahc_inb(ahc, SCB_RESIDUAL_SGPTR + 1) << 8) + | (ahc_inb(ahc, SCB_RESIDUAL_SGPTR + 2) << 16) + | (ahc_inb(ahc, SCB_RESIDUAL_SGPTR + 3) << 24), + ahc_inb(ahc, SCB_RESIDUAL_DATACNT) + | (ahc_inb(ahc, SCB_RESIDUAL_DATACNT + 1) << 8) + | (ahc_inb(ahc, SCB_RESIDUAL_DATACNT + 2) << 16) + | (ahc_inb(ahc, SCB_RESIDUAL_DATACNT + 3) << 24)); + printf("DATA_COUNT_ODD = %x\n", ahc_inb(ahc, DATA_COUNT_ODD)); + printf("SINDEX = %x\n", ahc_inb(ahc, SINDEX)); + printf("SCB_SGPTR %x, SCB_RESIDUAL_SGPTR %x\n", + ahc_inb(ahc, SCB_SGPTR), + ahc_inb(ahc, SCB_RESIDUAL_SGPTR)); + printf("SAVED_SCSIID %x, SAVED_LUN %d, " + "DISCONNECTED_SCBH %d\n", + ahc_inb(ahc, SAVED_SCSIID), + ahc_inb(ahc, SAVED_LUN), + ahc_inb(ahc, DISCONNECTED_SCBH)); + int i; + + if (ahc->unit != 1) + break; + for (i = 0; i < 32;) { + printf("0x%x 0x%x 0x%x 0x%x\n", + ahc_inb(ahc, SCB_CONTROL + i), + ahc_inb(ahc, SCB_CONTROL + i + 1), + ahc_inb(ahc, SCB_CONTROL + i + 2), + ahc_inb(ahc, SCB_CONTROL + i + 3)); + i += 4; + } +#endif #if 0 printf("SSTAT1 == 0x%x\n", ahc_inb(ahc, SSTAT1)); printf("SSTAT0 == 0x%x\n", ahc_inb(ahc, SSTAT0)); @@ -2642,13 +2890,6 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) #endif break; } -#if NOT_YET - /* XXX Fill these in later */ - case MESG_BUFFER_BUSY: - break; - case MSGIN_PHASEMIS: - break; -#endif default: printf("ahc_intr: seqint, " "intstat == 0x%x, scsisigi = 0x%x\n", @@ -2724,7 +2965,7 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) u_int curphase; u_int errorphase; u_int lastphase; - int i; + u_int i; lastphase = ahc_inb(ahc, LASTPHASE); curphase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK; @@ -2756,7 +2997,7 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) else printf("%s:%c:%d: ", ahc_name(ahc), intr_channel, - TCL_TARGET(ahc_inb(ahc, SAVED_TCL))); + SCSIID_TARGET(ahc, ahc_inb(ahc, SAVED_SCSIID))); printf("parity error detected %s. " "SEQADDR(0x%x) SCSIRATE(0x%x)\n", @@ -2788,10 +3029,11 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) * our abort requests. */ u_int lastphase = ahc_inb(ahc, LASTPHASE); - u_int saved_tcl = ahc_inb(ahc, SAVED_TCL); - u_int target = TCL_TARGET(saved_tcl); - u_int initiator_role_id = TCL_SCSI_ID(ahc, saved_tcl); - char channel = TCL_CHANNEL(ahc, saved_tcl); + u_int saved_scsiid = ahc_inb(ahc, SAVED_SCSIID); + u_int saved_lun = ahc_inb(ahc, SAVED_LUN); + u_int target = SCSIID_TARGET(ahc, saved_scsiid); + u_int initiator_role_id = SCSIID_OUR_ID(saved_scsiid); + char channel = SCSIID_CHANNEL(ahc, saved_scsiid); int printerror = 1; ahc_outb(ahc, SCSISEQ, @@ -2812,7 +3054,7 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) scb->hscb->tag, tag == SCB_LIST_NULL ? "" : "Tag"); ahc_abort_scbs(ahc, target, channel, - TCL_LUN(saved_tcl), tag, + saved_lun, tag, ROLE_INITIATOR, CAM_REQ_ABORTED); printerror = 0; @@ -2828,8 +3070,8 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) */ if (scb != NULL && scb->ccb->ccb_h.func_code == XPT_RESET_DEV - && ahc_match_scb(scb, target, channel, - TCL_LUN(saved_tcl), + && ahc_match_scb(ahc, scb, target, channel, + saved_lun, SCB_LIST_NULL, ROLE_INITIATOR)) { ahcsetccbstatus(scb->ccb, CAM_REQ_CMP); @@ -2837,7 +3079,7 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) ahc_compile_devinfo(&devinfo, initiator_role_id, target, - TCL_LUN(saved_tcl), + saved_lun, channel, ROLE_INITIATOR); ahc_handle_devreset(ahc, &devinfo, @@ -2852,7 +3094,7 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) } } if (printerror != 0) { - int i; + u_int i; if (scb != NULL) { u_int tag; @@ -2862,7 +3104,7 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) else tag = SCB_LIST_NULL; ahc_abort_scbs(ahc, target, channel, - SCB_LUN(scb), tag, + SCB_GET_LUN(scb), tag, ROLE_INITIATOR, CAM_UNEXP_BUSFREE); xpt_print_path(scb->ccb->ccb_h.path); @@ -2906,15 +3148,8 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) "valid during SELTO scb(%d, %d)\n", ahc_name(ahc), scbptr, scb_index); } else { - u_int tag; - - tag = SCB_LIST_NULL; - if ((scb->hscb->control & MSG_SIMPLE_Q_TAG) != 0) - tag = scb->hscb->tag; - - ahc_abort_scbs(ahc, SCB_TARGET(scb), SCB_CHANNEL(scb), - SCB_LUN(scb), tag, - ROLE_INITIATOR, CAM_SEL_TIMEOUT); + ahcsetccbstatus(scb->ccb, CAM_SEL_TIMEOUT); + ahc_freeze_devq(ahc, scb->ccb->ccb_h.path); } /* Stop the selection */ ahc_outb(ahc, SCSISEQ, 0); @@ -2926,7 +3161,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 sucessful - * selection, so we must manually clear it to ensure + * 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). */ @@ -2955,35 +3190,47 @@ ahc_build_transfer_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) */ struct ahc_initiator_tinfo *tinfo; struct 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; tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid, devinfo->target, &tstate); dowide = tinfo->current.width != tinfo->goal.width; dosync = tinfo->current.period != tinfo->goal.period; + doppr = tinfo->current.ppr_options != tinfo->goal.ppr_options; - if (!dowide && !dosync) { + 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; } - if (dowide) { + if (!dowide && !dosync && !doppr) { + panic("ahc_intr: AWAITING_MSG for negotiation, " + "but no negotiation needed\n"); + } + + use_ppr = (tinfo->current.transport_version >= 3) || doppr; + if (use_ppr) { + ahc_construct_ppr(ahc, tinfo->goal.period, tinfo->goal.offset, + tinfo->goal.width, tinfo->goal.ppr_options); + } else if (dowide) { ahc_construct_wdtr(ahc, tinfo->goal.width); } else if (dosync) { - struct ahc_syncrate *rate; - u_int period; - u_int offset; period = tinfo->goal.period; - rate = ahc_devlimited_syncrate(ahc, &period); + ppr_options = 0; + rate = ahc_devlimited_syncrate(ahc, &period, &ppr_options); offset = tinfo->goal.offset; ahc_validate_offset(ahc, rate, &offset, tinfo->current.width); ahc_construct_sdtr(ahc, period, offset); - } else { - panic("ahc_intr: AWAITING_MSG for negotiation, " - "but no negotiation needed\n"); } } @@ -3003,7 +3250,7 @@ ahc_setup_initiator_msgout(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, && ahc_inb(ahc, MSG_OUT) == MSG_IDENTIFYFLAG) { u_int identify_msg; - identify_msg = MSG_IDENTIFYFLAG | SCB_LUN(scb); + identify_msg = MSG_IDENTIFYFLAG | SCB_GET_LUN(scb); if ((scb->hscb->control & DISCENB) != 0) identify_msg |= MSG_IDENTIFY_DISCFLAG; ahc->msgout_buf[ahc->msgout_index++] = identify_msg; @@ -3022,7 +3269,7 @@ ahc_setup_initiator_msgout(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, ahc->msgout_len++; xpt_print_path(scb->ccb->ccb_h.path); printf("Bus Device Reset Message Sent\n"); - } else if (scb->flags & SCB_ABORT) { + } else if ((scb->flags & SCB_ABORT) != 0) { if ((scb->hscb->control & TAG_ENB) != 0) ahc->msgout_buf[ahc->msgout_index++] = MSG_ABORT_TAG; else @@ -3030,11 +3277,14 @@ ahc_setup_initiator_msgout(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, ahc->msgout_len++; xpt_print_path(scb->ccb->ccb_h.path); printf("Abort Message Sent\n"); - } else if ((ahc->targ_msg_req & devinfo->target_mask) != 0) { + } else if ((ahc->targ_msg_req & devinfo->target_mask) != 0 + || (scb->flags & SCB_NEGOTIATE) != 0) { ahc_build_transfer_msg(ahc, devinfo); } else { printf("ahc_intr: AWAITING_MSG for an SCB that " - "does not have a waiting message"); + "does not have a waiting message\n"); + printf("SCSIID = %x, target_mask = %x\n", scb->hscb->scsiid, + devinfo->target_mask); panic("SCB = %d, SCB Control = %x, MSG_OUT = %x " "SCB flags = %x", scb->hscb->tag, scb->hscb->control, ahc_inb(ahc, MSG_OUT), scb->flags); @@ -3079,6 +3329,8 @@ ahc_handle_msg_reject(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) * the target is refusing negotiation. */ struct scb *scb; + struct ahc_initiator_tinfo *tinfo; + struct tmode_tstate *tstate; u_int scb_index; u_int last_msg; int response = 0; @@ -3086,12 +3338,13 @@ ahc_handle_msg_reject(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) scb_index = ahc_inb(ahc, SCB_TAG); scb = &ahc->scb_data->scbarray[scb_index]; + tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, + devinfo->our_scsiid, + devinfo->target, &tstate); /* Might be necessary */ last_msg = ahc_inb(ahc, LAST_MSG); if (ahc_sent_msg(ahc, MSG_EXT_WDTR, /*full*/FALSE)) { - struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; /* note 8bit xfers */ printf("%s:%c:%d: refuses WIDE negotiation. Using " @@ -3108,15 +3361,14 @@ 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. */ - tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, - devinfo->our_scsiid, - devinfo->target, &tstate); if (tinfo->goal.period) { u_int period; + u_int ppr_options; /* Start the sync negotiation */ period = tinfo->goal.period; - ahc_devlimited_syncrate(ahc, &period); + ppr_options = 0; + ahc_devlimited_syncrate(ahc, &period, &ppr_options); ahc->msgout_index = 0; ahc->msgout_len = 0; ahc_construct_sdtr(ahc, period, tinfo->goal.offset); @@ -3127,7 +3379,7 @@ ahc_handle_msg_reject(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) /* note asynch xfers and clear flag */ ahc_set_syncrate(ahc, devinfo, scb->ccb->ccb_h.path, /*syncrate*/NULL, /*period*/0, - /*offset*/0, + /*offset*/0, /*ppr_options*/0, AHC_TRANS_ACTIVE|AHC_TRANS_GOAL, /*paused*/TRUE); printf("%s:%c:%d: refuses synchronous negotiation. " @@ -3142,7 +3394,7 @@ ahc_handle_msg_reject(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) devinfo->channel, devinfo->target); ahc_set_tags(ahc, devinfo, FALSE); - neg.flags = 0; + neg.flags = CCB_TRANS_CURRENT_SETTINGS; neg.valid = CCB_TRANS_TQ_VALID; xpt_setup_ccb(&neg.ccb_h, scb->ccb->ccb_h.path, /*priority*/1); xpt_async(AC_TRANSFER_NEG, scb->ccb->ccb_h.path, &neg); @@ -3163,8 +3415,9 @@ ahc_handle_msg_reject(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) * currently in our posession so they can be * converted to untagged commands. */ - ahc_search_qinfifo(ahc, SCB_TARGET(scb), SCB_CHANNEL(scb), - SCB_LUN(scb), /*tag*/SCB_LIST_NULL, + ahc_search_qinfifo(ahc, SCB_GET_TARGET(ahc, scb), + SCB_GET_CHANNEL(ahc, scb), + SCB_GET_LUN(scb), /*tag*/SCB_LIST_NULL, ROLE_INITIATOR, CAM_REQUEUE_REQ, SEARCH_COMPLETE); } else { @@ -3444,7 +3697,7 @@ static int ahc_sent_msg(struct ahc_softc *ahc, u_int msgtype, int full) { int found; - int index; + u_int index; found = FALSE; index = 0; @@ -3514,19 +3767,6 @@ ahc_parse_msg(struct ahc_softc *ahc, struct cam_path *path, case MSG_NOOP: done = MSGLOOP_MSGCOMPLETE; break; - case MSG_IGN_WIDE_RESIDUE: - { - /* Wait for the whole message */ - if (ahc->msgin_index >= 1) { - if (ahc->msgin_buf[1] != 1 - || tinfo->current.width == MSG_EXT_WDTR_BUS_8_BIT) { - reject = TRUE; - done = MSGLOOP_MSGCOMPLETE; - } else - ahc_handle_ign_wide_residue(ahc, devinfo); - } - break; - } case MSG_EXTENDED: { /* Wait for enough of the message to begin validation */ @@ -3537,6 +3777,7 @@ ahc_parse_msg(struct ahc_softc *ahc, struct cam_path *path, { struct ahc_syncrate *syncrate; u_int period; + u_int ppr_options; u_int offset; u_int saved_offset; @@ -3556,12 +3797,15 @@ ahc_parse_msg(struct ahc_softc *ahc, struct cam_path *path, break; period = ahc->msgin_buf[3]; + ppr_options = 0; saved_offset = offset = ahc->msgin_buf[4]; - syncrate = ahc_devlimited_syncrate(ahc, &period); + syncrate = ahc_devlimited_syncrate(ahc, &period, + &ppr_options); ahc_validate_offset(ahc, syncrate, &offset, targ_scsirate & WIDEXFER); ahc_set_syncrate(ahc, devinfo, path, - syncrate, period, offset, + syncrate, period, + offset, ppr_options, AHC_TRANS_ACTIVE|AHC_TRANS_GOAL, /*paused*/TRUE); @@ -3593,8 +3837,9 @@ ahc_parse_msg(struct ahc_softc *ahc, struct cam_path *path, } case MSG_EXT_WDTR: { - u_int bus_width; - u_int sending_reply; + u_int bus_width; + u_int saved_width; + u_int sending_reply; sending_reply = FALSE; if (ahc->msgin_buf[1] != MSG_EXT_WDTR_LEN) { @@ -3613,29 +3858,23 @@ ahc_parse_msg(struct ahc_softc *ahc, struct cam_path *path, break; bus_width = ahc->msgin_buf[3]; + saved_width = bus_width; + ahc_validate_width(ahc, &bus_width); + if (ahc_sent_msg(ahc, MSG_EXT_WDTR, /*full*/TRUE)) { /* * Don't send a WDTR back to the * target, since we asked first. + * If the width went higher than our + * request, reject it. */ - switch (bus_width){ - default: - /* - * How can we do anything greater - * than 16bit transfers on a 16bit - * bus? - */ + if (saved_width > bus_width) { reject = TRUE; printf("%s: target %d requested %dBit " "transfers. Rejecting...\n", ahc_name(ahc), devinfo->target, 8 * (0x01 << bus_width)); - /* FALLTHROUGH */ - case MSG_EXT_WDTR_BUS_8_BIT: - bus_width = MSG_EXT_WDTR_BUS_8_BIT; - break; - case MSG_EXT_WDTR_BUS_16_BIT: - break; + bus_width = 0; } } else { /* @@ -3643,19 +3882,6 @@ ahc_parse_msg(struct ahc_softc *ahc, struct cam_path *path, */ if (bootverbose) printf("Sending WDTR!\n"); - switch (bus_width) { - default: - if (ahc->features & AHC_WIDE) { - /* Respond Wide */ - bus_width = - MSG_EXT_WDTR_BUS_16_BIT; - break; - } - /* FALLTHROUGH */ - case MSG_EXT_WDTR_BUS_8_BIT: - bus_width = MSG_EXT_WDTR_BUS_8_BIT; - break; - } ahc->msgout_index = 0; ahc->msgout_len = 0; ahc_construct_wdtr(ahc, bus_width); @@ -3670,19 +3896,23 @@ ahc_parse_msg(struct ahc_softc *ahc, struct cam_path *path, /* After a wide message, we are async */ ahc_set_syncrate(ahc, devinfo, path, /*syncrate*/NULL, /*period*/0, - /*offset*/0, AHC_TRANS_ACTIVE, - /*paused*/TRUE); + /*offset*/0, /*ppr_options*/0, + AHC_TRANS_ACTIVE, /*paused*/TRUE); if (sending_reply == FALSE && reject == FALSE) { + /* XXX functionalize */ if (tinfo->goal.period) { struct ahc_syncrate *rate; u_int period; + u_int ppr; u_int offset; /* Start the sync negotiation */ period = tinfo->goal.period; + ppr = 0; rate = ahc_devlimited_syncrate(ahc, - &period); + &period, + &ppr); offset = tinfo->goal.offset; ahc_validate_offset(ahc, rate, &offset, tinfo->current.width); @@ -3696,6 +3926,86 @@ ahc_parse_msg(struct ahc_softc *ahc, struct cam_path *path, done = MSGLOOP_MSGCOMPLETE; break; } + case MSG_EXT_PPR: + { + struct ahc_syncrate *syncrate; + u_int period; + u_int offset; + u_int bus_width; + u_int ppr_options; + u_int saved_width; + u_int saved_offset; + u_int saved_ppr_options; + + if (ahc->msgin_buf[1] != MSG_EXT_PPR_LEN) { + reject = TRUE; + break; + } + + /* + * Wait until we have all args before validating + * and acting on this message. + * + * Add one to MSG_EXT_PPR_LEN to account for + * the extended message preamble. + */ + if (ahc->msgin_index < (MSG_EXT_PPR_LEN + 1)) + break; + + period = ahc->msgin_buf[3]; + offset = ahc->msgin_buf[5]; + bus_width = ahc->msgin_buf[6]; + saved_width = bus_width; + ppr_options = ahc->msgin_buf[7]; + /* + * According to the spec, a DT only + * period factor with no DT option + * set implies async. + */ + if ((ppr_options & MSG_EXT_PPR_DT_REQ) == 0 + && period == 9) + offset = 0; + saved_ppr_options = ppr_options; + saved_offset = offset; + + /* + * Mask out any options we don't support + * on any controller. Transfer options are + * only available if we are negotiating wide. + */ + ppr_options &= MSG_EXT_PPR_DT_REQ; + if (bus_width == 0) + ppr_options = 0; + + ahc_validate_width(ahc, &bus_width); + syncrate = ahc_devlimited_syncrate(ahc, &period, + &ppr_options); + ahc_validate_offset(ahc, syncrate, &offset, bus_width); + + if (ahc_sent_msg(ahc, MSG_EXT_PPR, /*full*/TRUE)) { + /* + * If we are unable to do any of the + * requested options (we went too low), + * then we'll have to reject the message. + */ + if (saved_width > bus_width + || saved_offset != offset + || saved_ppr_options != ppr_options) + reject = TRUE; + } else { + printf("Target Initated PPR detected!\n"); + response = TRUE; + } + ahc_set_syncrate(ahc, devinfo, path, + syncrate, period, + offset, ppr_options, + AHC_TRANS_ACTIVE|AHC_TRANS_GOAL, + /*paused*/TRUE); + ahc_set_width(ahc, devinfo, path, bus_width, + AHC_TRANS_ACTIVE|AHC_TRANS_GOAL, + /*paused*/TRUE); + break; + } default: /* Unknown extended message. Reject it. */ reject = TRUE; @@ -3787,10 +4097,10 @@ ahc_handle_ign_wide_residue(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) * nothing. Otherwise, subtract a byte * and update the residual count accordingly. */ - u_int resid_sgcnt; + uint32_t sgptr; - resid_sgcnt = ahc_inb(ahc, SCB_RESID_SGCNT); - if (resid_sgcnt == 0 + sgptr = ahc_inb(ahc, SCB_RESIDUAL_SGPTR); + if ((sgptr & SG_LIST_NULL) != 0 && ahc_inb(ahc, DATA_COUNT_ODD) == 1) { /* * If the residual occurred on the last @@ -3799,13 +4109,18 @@ ahc_handle_ign_wide_residue(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) * nothing. */ } else { - u_int data_cnt; - u_int data_addr; - u_int sg_index; - - data_cnt = (ahc_inb(ahc, SCB_RESID_DCNT + 2) << 16) - | (ahc_inb(ahc, SCB_RESID_DCNT + 1) << 8) - | (ahc_inb(ahc, SCB_RESID_DCNT)); + struct ahc_dma_seg *sg; + uint32_t data_cnt; + uint32_t data_addr; + + /* Pull in the rest of the sgptr */ + sgptr |= (ahc_inb(ahc, SCB_RESIDUAL_SGPTR + 3) << 24) + | (ahc_inb(ahc, SCB_RESIDUAL_SGPTR + 2) << 16) + | (ahc_inb(ahc, SCB_RESIDUAL_SGPTR + 1) << 8); + sgptr &= SG_PTR_MASK; + data_cnt = (ahc_inb(ahc, SCB_RESIDUAL_DATACNT+2) << 16) + | (ahc_inb(ahc, SCB_RESIDUAL_DATACNT+1) << 8) + | (ahc_inb(ahc, SCB_RESIDUAL_DATACNT)); data_addr = (ahc_inb(ahc, SHADDR + 3) << 24) | (ahc_inb(ahc, SHADDR + 2) << 16) @@ -3815,38 +4130,56 @@ ahc_handle_ign_wide_residue(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) data_cnt += 1; data_addr -= 1; - sg_index = scb->sg_count - resid_sgcnt; + sg = ahc_sg_bus_to_virt(scb, sgptr); + /* + * The residual sg ptr points to the next S/G + * to load so we must go back one. + */ + sg--; + if (sg != scb->sg_list + && (sg->len & AHC_SG_LEN_MASK) < data_cnt) { - if (sg_index != 0 - && (scb->sg_list[sg_index].len < data_cnt)) { - u_int sg_addr; + sg--; + data_cnt = 1 | (sg->len & AHC_DMA_LAST_SEG); + data_addr = sg->addr + + (sg->len & AHC_SG_LEN_MASK) - 1; - sg_index--; - data_cnt = 1; - data_addr = scb->sg_list[sg_index].addr - + scb->sg_list[sg_index].len - 1; - /* - * The physical address base points to the - * second entry as it is always used for - * calculating the "next S/G pointer". + * Increment sg so it points to the + * "next" sg. */ - sg_addr = scb->sg_list_phys - + (sg_index* sizeof(*scb->sg_list)); - ahc_outb(ahc, SG_NEXT + 3, sg_addr >> 24); - ahc_outb(ahc, SG_NEXT + 2, sg_addr >> 16); - ahc_outb(ahc, SG_NEXT + 1, sg_addr >> 8); - ahc_outb(ahc, SG_NEXT, sg_addr); + sg++; + sgptr = ahc_sg_virt_to_bus(scb, sg); + ahc_outb(ahc, SCB_RESIDUAL_SGPTR + 3, + sgptr >> 24); + ahc_outb(ahc, SCB_RESIDUAL_SGPTR + 2, + sgptr >> 16); + ahc_outb(ahc, SCB_RESIDUAL_SGPTR + 1, + sgptr >> 8); + ahc_outb(ahc, SCB_RESIDUAL_SGPTR, sgptr); } - ahc_outb(ahc, SCB_RESID_DCNT + 2, data_cnt >> 16); - ahc_outb(ahc, SCB_RESID_DCNT + 1, data_cnt >> 8); - ahc_outb(ahc, SCB_RESID_DCNT, data_cnt); +/* XXX What about high address byte??? */ + ahc_outb(ahc, SCB_RESIDUAL_DATACNT + 3, data_cnt >> 24); + ahc_outb(ahc, SCB_RESIDUAL_DATACNT + 2, data_cnt >> 16); + ahc_outb(ahc, SCB_RESIDUAL_DATACNT + 1, data_cnt >> 8); + ahc_outb(ahc, SCB_RESIDUAL_DATACNT, data_cnt); - ahc_outb(ahc, SHADDR + 3, data_addr >> 24); - ahc_outb(ahc, SHADDR + 2, data_addr >> 16); - ahc_outb(ahc, SHADDR + 1, data_addr >> 8); - ahc_outb(ahc, SHADDR, data_addr); +/* XXX Perhaps better to just keep the saved address in sram */ + if ((ahc->features & AHC_ULTRA2) != 0) { + ahc_outb(ahc, HADDR + 3, data_addr >> 24); + ahc_outb(ahc, HADDR + 2, data_addr >> 16); + ahc_outb(ahc, HADDR + 1, data_addr >> 8); + ahc_outb(ahc, HADDR, data_addr); + ahc_outb(ahc, DFCNTRL, PRELOADEN); + ahc_outb(ahc, SXFRCTL0, + ahc_inb(ahc, SXFRCTL0) | CLRCHN); + } else { + ahc_outb(ahc, SHADDR + 3, data_addr >> 24); + ahc_outb(ahc, SHADDR + 2, data_addr >> 16); + ahc_outb(ahc, SHADDR + 1, data_addr >> 8); + ahc_outb(ahc, SHADDR, data_addr); + } } } } @@ -3895,8 +4228,8 @@ ahc_handle_devreset(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, ahc_set_width(ahc, devinfo, path, MSG_EXT_WDTR_BUS_8_BIT, AHC_TRANS_CUR, /*paused*/TRUE); ahc_set_syncrate(ahc, devinfo, path, /*syncrate*/NULL, - /*period*/0, /*offset*/0, AHC_TRANS_CUR, - /*paused*/TRUE); + /*period*/0, /*offset*/0, /*ppr_options*/0, + AHC_TRANS_CUR, /*paused*/TRUE); if (error == CAM_REQ_CMP && acode != 0) xpt_async(AC_SENT_BDR, path, NULL); @@ -3925,6 +4258,16 @@ ahc_done(struct ahc_softc *ahc, struct scb *scb) ccb = scb->ccb; LIST_REMOVE(&ccb->ccb_h, sim_links.le); + if (ccb->ccb_h.func_code == XPT_SCSI_IO + && ((ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) == 0 + || ccb->csio.tag_action == CAM_TAG_ACTION_NONE) + && (ahc->features & AHC_SCB_BTT) == 0) { + struct scb_tailq *untagged_q; + + untagged_q = &ahc->untagged_queues[ccb->ccb_h.target_id]; + TAILQ_REMOVE(untagged_q, scb, links.tqe); + ahc_run_untagged_queue(ahc, untagged_q); + } untimeout(ahc_timeout, (caddr_t)scb, ccb->ccb_h.timeout_ch); @@ -3939,13 +4282,6 @@ ahc_done(struct ahc_softc *ahc, struct scb *scb) 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. - */ - ahc_index_busy_tcl(ahc, scb->hscb->tcl, /*unbusy*/TRUE); - if (ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) { if (ahc_ccb_status(ccb) == CAM_REQ_INPROG) ccb->ccb_h.status |= CAM_REQ_CMP; @@ -3983,8 +4319,9 @@ ahc_done(struct ahc_softc *ahc, struct scb *scb) * Ensure that we didn't put a second instance of this * SCB into the QINFIFO. */ - ahc_search_qinfifo(ahc, SCB_TARGET(scb), SCB_CHANNEL(scb), - SCB_LUN(scb), scb->hscb->tag, + ahc_search_qinfifo(ahc, SCB_GET_TARGET(ahc, scb), + SCB_GET_CHANNEL(ahc, scb), + SCB_GET_LUN(scb), scb->hscb->tag, ROLE_INITIATOR, /*status*/0, SEARCH_REMOVE); if (ahc_ccb_status(ccb) == CAM_BDR_SENT @@ -4012,7 +4349,8 @@ ahc_done(struct ahc_softc *ahc, struct scb *scb) */ bzero(&ccb->csio.sense_data, sizeof(ccb->csio.sense_data)); bcopy(&ahc->scb_data->sense[scb->hscb->tag], - &ccb->csio.sense_data, scb->sg_list->len); + &ccb->csio.sense_data, + scb->sg_list->len & AHC_SG_LEN_MASK); scb->ccb->ccb_h.status |= CAM_AUTOSNS_VALID; } ccb->ccb_h.status &= ~CAM_SIM_QUEUED; @@ -4054,7 +4392,7 @@ ahc_init(struct ahc_softc *ahc) u_int discenable; u_int tagenable; size_t driver_data_size; - u_int32_t physaddr; + uint32_t physaddr; #ifdef AHC_PRINT_SRAM printf("Scratch Ram:"); @@ -4121,13 +4459,13 @@ ahc_init(struct ahc_softc *ahc) /* * 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 qinfifo, qoutfifo, - * and untagged_scb arrays each of which are composed of 256 - * 1 byte elements. When providing for the target mode role, - * we additionally must provide space for the incoming target - * command fifo. + * roles, we need to allocate space for the the qinfifo and qoutfifo. + * The qinfifo and qoutfifo are composed of 256 1 byte elements. + * When providing for the target mode role, we additionally must + * provide space for the incoming target command fifo and an extra + * byte to deal with a dma bug in some chip versions. */ - driver_data_size = 3 * 256 * sizeof(u_int8_t); + driver_data_size = 2 * 256 * sizeof(uint8_t); if ((ahc->flags & AHC_TARGETMODE) != 0) driver_data_size += AHC_TMODE_CMDS * sizeof(struct target_cmd) + /*DMA WideOdd Bug Buffer*/1; @@ -4145,7 +4483,8 @@ ahc_init(struct ahc_softc *ahc) ahc->init_level++; /* Allocation of driver data */ - if (bus_dmamem_alloc(ahc->shared_data_dmat, (void **)&ahc->qoutfifo, + if (bus_dmamem_alloc(ahc->shared_data_dmat, + (void **)&ahc->qoutfifo, BUS_DMA_NOWAIT, &ahc->shared_data_dmamap) != 0) { return (ENOMEM); } @@ -4154,8 +4493,23 @@ ahc_init(struct ahc_softc *ahc) /* And permanently map it in */ bus_dmamap_load(ahc->shared_data_dmat, ahc->shared_data_dmamap, - ahc->qoutfifo, driver_data_size, - ahcdmamapcb, &ahc->shared_data_busaddr, /*flags*/0); + ahc->qoutfifo, driver_data_size, ahcdmamapcb, + &ahc->shared_data_busaddr, /*flags*/0); + + if ((ahc->flags & AHC_TARGETMODE) != 0) { + ahc->targetcmds = (struct target_cmd *)ahc->qoutfifo; + ahc->qoutfifo = (uint8_t *)&ahc->targetcmds[256]; + ahc->dma_bug_buf = ahc->shared_data_busaddr + + driver_data_size - 1; + /* All target command blocks start out invalid. */ + for (i = 0; i < AHC_TMODE_CMDS; i++) + ahc->targetcmds[i].cmd_valid = 0; + ahc->tqinfifonext = 1; + ahc_outb(ahc, KERNEL_TQINPOS, ahc->tqinfifonext - 1); + ahc_outb(ahc, TQINPOS, ahc->tqinfifonext); + ahc->qoutfifo = (uint8_t *)&ahc->targetcmds[256]; + } + ahc->qinfifo = &ahc->qoutfifo[256]; ahc->init_level++; @@ -4164,34 +4518,23 @@ ahc_init(struct ahc_softc *ahc) if (ahcinitscbdata(ahc) != 0) return (ENOMEM); - ahc->qinfifo = &ahc->qoutfifo[256]; - ahc->untagged_scbs = &ahc->qinfifo[256]; /* There are no untagged SCBs active yet. */ - for (i = 0; i < 256; i++) - ahc->untagged_scbs[i] = SCB_LIST_NULL; + /* XXX will need to change for SCB ram approach */ + for (i = 0; i < 16; i++) + ahc_index_busy_tcl(ahc, BUILD_TCL(i << 4, 0), /*unbusy*/TRUE); /* All of our queues are empty */ for (i = 0; i < 256; i++) ahc->qoutfifo[i] = SCB_LIST_NULL; + for (i = 0; i < 256; i++) + ahc->qinfifo[i] = SCB_LIST_NULL; + if ((ahc->features & AHC_MULTI_TID) != 0) { ahc_outb(ahc, TARGID, 0); ahc_outb(ahc, TARGID + 1, 0); } - if ((ahc->flags & AHC_TARGETMODE) != 0) { - - ahc->targetcmds = (struct target_cmd *)&ahc->untagged_scbs[256]; - ahc->dma_bug_buf = ahc->shared_data_busaddr - + driver_data_size - 1; - /* All target command blocks start out invalid. */ - for (i = 0; i < AHC_TMODE_CMDS; i++) - ahc->targetcmds[i].cmd_valid = 0; - ahc->tqinfifonext = 1; - ahc_outb(ahc, KERNEL_TQINPOS, ahc->tqinfifonext - 1); - ahc_outb(ahc, TQINPOS, ahc->tqinfifonext); - } - /* * Allocate a tstate to house information for our * initiator presence on the bus as well as the user @@ -4341,7 +4684,7 @@ ahc_init(struct ahc_softc *ahc) tinfo->user.offset = ~0; } else { u_int scsirate; - u_int16_t mask; + uint16_t mask; /* Take the settings leftover in scratch RAM. */ scsirate = ahc_inb(ahc, TARG_SCSIRATE + i); @@ -4371,6 +4714,10 @@ ahc_init(struct ahc_softc *ahc) tinfo->user.period = 0; else tinfo->user.offset = ~0; + if ((scsirate & SXFR_ULTRA2) <= 8/*10MHz*/ + && (ahc->features & AHC_DT) != 0) + tinfo->user.ppr_options = + MSG_EXT_PPR_DT_REQ; } else if ((scsirate & SOFS) != 0) { tinfo->user.period = ahc_find_period(ahc, scsirate, @@ -4383,6 +4730,15 @@ ahc_init(struct ahc_softc *ahc) if ((scsirate & WIDEXFER) != 0 && (ahc->features & AHC_WIDE) != 0) tinfo->user.width = MSG_EXT_WDTR_BUS_16_BIT; + tinfo->user.protocol_version = 4; + if ((ahc->features & AHC_DT) != 0) + tinfo->user.transport_version = 3; + else + tinfo->user.transport_version = 2; + tinfo->goal.protocol_version = 2; + tinfo->goal.transport_version = 2; + tinfo->current.protocol_version = 2; + tinfo->current.transport_version = 2; } tstate->ultraenb = ultraenb; tstate->discenable = discenable; @@ -4401,17 +4757,10 @@ ahc_init(struct ahc_softc *ahc) ahc_outb(ahc, HSCB_ADDR + 3, (physaddr >> 24) & 0xFF); physaddr = ahc->shared_data_busaddr; - ahc_outb(ahc, SCBID_ADDR, physaddr & 0xFF); - ahc_outb(ahc, SCBID_ADDR + 1, (physaddr >> 8) & 0xFF); - ahc_outb(ahc, SCBID_ADDR + 2, (physaddr >> 16) & 0xFF); - ahc_outb(ahc, SCBID_ADDR + 3, (physaddr >> 24) & 0xFF); - - /* Target mode incomding command fifo */ - physaddr += 3 * 256 * sizeof(u_int8_t); - ahc_outb(ahc, TMODE_CMDADDR, physaddr & 0xFF); - ahc_outb(ahc, TMODE_CMDADDR + 1, (physaddr >> 8) & 0xFF); - ahc_outb(ahc, TMODE_CMDADDR + 2, (physaddr >> 16) & 0xFF); - ahc_outb(ahc, TMODE_CMDADDR + 3, (physaddr >> 24) & 0xFF); + ahc_outb(ahc, SHARED_DATA_ADDR, physaddr & 0xFF); + ahc_outb(ahc, SHARED_DATA_ADDR + 1, (physaddr >> 8) & 0xFF); + ahc_outb(ahc, SHARED_DATA_ADDR + 2, (physaddr >> 16) & 0xFF); + ahc_outb(ahc, SHARED_DATA_ADDR + 3, (physaddr >> 24) & 0xFF); /* * Initialize the group code to command length table. @@ -4481,6 +4830,24 @@ ahc_init(struct ahc_softc *ahc) EVENTHANDLER_REGISTER(shutdown_final, ahc_shutdown, ahc, SHUTDOWN_PRI_DEFAULT); + if ((ahc->features & AHC_ULTRA2) != 0) { + int wait; + + /* + * Wait for up to 500ms for our transceivers + * to settle. If the adapter does not have + * a cable attached, the tranceivers may + * never settle, so don't complain if we + * fail here. + */ + pause_sequencer(ahc); + for (wait = 5000; + (ahc_inb(ahc, SBLKCTL) & (ENAB40|ENAB20)) == 0 && wait; + wait--) + DELAY(100); + unpause_sequencer(ahc); + } + return (0); } @@ -4489,7 +4856,7 @@ ahc_find_tmode_devs(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb, struct tmode_tstate **tstate, struct tmode_lstate **lstate, int notfound_failure) { - int our_id; + u_int our_id; /* * If we are not configured for target mode, someone @@ -4628,7 +4995,7 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) struct hardware_scb *hscb; struct ahc_initiator_tinfo *tinfo; struct tmode_tstate *tstate; - u_int16_t mask; + uint16_t mask; /* * get an scb to use. @@ -4659,11 +5026,10 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) /* * Put all the arguments for the xfer in the scb */ - hscb->tcl = ((target_id << 4) & 0xF0) - | (SIM_IS_SCSIBUS_B(ahc, sim) ? SELBUSB : 0) - | (ccb->ccb_h.target_lun & 0x07); - - mask = SCB_TARGET_MASK(scb); + hscb->control = 0; + hscb->scsiid = BUILD_SCSIID(ahc, sim, target_id, our_id); + hscb->lun = ccb->ccb_h.target_lun; + mask = SCB_GET_TARGET_MASK(ahc, scb); tinfo = ahc_fetch_transinfo(ahc, SIM_CHANNEL(ahc, sim), our_id, target_id, &tstate); @@ -4675,33 +5041,35 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) if ((tstate->discenable & mask) != 0 && (ccb->ccb_h.flags & CAM_DIS_DISCONNECT) == 0) hscb->control |= DISCENB; - + + if ((ccb->ccb_h.flags & CAM_NEGOTIATE) != 0 + && (tinfo->current.width != 0 || tinfo->current.period != 0)) { + scb->flags |= SCB_NEGOTIATE; + hscb->control |= MK_MESSAGE; + } + if (ccb->ccb_h.func_code == XPT_RESET_DEV) { - hscb->cmdpointer = NULL; + hscb->cdb_len = 0; scb->flags |= SCB_DEVICE_RESET; hscb->control |= MK_MESSAGE; ahc_execute_scb(scb, NULL, 0, 0); } else { if (ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) { + struct target_data *tdata; + + tdata = &hscb->shared_data.tdata; if (ahc->pending_device == lstate) { scb->flags |= SCB_TARGET_IMMEDIATE; ahc->pending_device = NULL; } hscb->control |= TARGET_SCB; - hscb->cmdpointer = IDENTIFY_SEEN; + tdata->target_phases = IDENTIFY_SEEN; if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) { - hscb->cmdpointer |= SPHASE_PENDING; - hscb->status = ccb->csio.scsi_status; + tdata->target_phases |= SPHASE_PENDING; + tdata->scsi_status = + ccb->csio.scsi_status; } - - /* Overloaded with tag ID */ - hscb->cmdlen = ccb->csio.tag_id; - /* - * Overloaded with the value to place - * in SCSIID for reselection. - */ - hscb->cmdpointer |= - (our_id|(hscb->tcl & 0xF0)) << 16; + tdata->initiator_tag = ccb->csio.tag_id; } if (ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) hscb->control |= ccb->csio.tag_action; @@ -4742,14 +5110,14 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) } case XPT_SET_TRAN_SETTINGS: { - struct ahc_devinfo devinfo; - struct ccb_trans_settings *cts; - struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; - u_int16_t *discenable; - u_int16_t *tagenable; - u_int update_type; - int s; + struct ahc_devinfo devinfo; + struct ccb_trans_settings *cts; + struct ahc_initiator_tinfo *tinfo; + struct tmode_tstate *tstate; + uint16_t *discenable; + uint16_t *tagenable; + u_int update_type; + int s; cts = &ccb->cts; ahc_compile_devinfo(&devinfo, SIM_SCSI_ID(ahc, sim), @@ -4792,62 +5160,69 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) } if ((cts->valid & CCB_TRANS_BUS_WIDTH_VALID) != 0) { - switch (cts->bus_width) { - case MSG_EXT_WDTR_BUS_16_BIT: - if ((ahc->features & AHC_WIDE) != 0) - break; - /* FALLTHROUGH to 8bit */ - case MSG_EXT_WDTR_BUS_32_BIT: - case MSG_EXT_WDTR_BUS_8_BIT: - default: - cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; - break; - } + ahc_validate_width(ahc, &cts->bus_width); ahc_set_width(ahc, &devinfo, cts->ccb_h.path, cts->bus_width, update_type, /*paused*/FALSE); } + if ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) == 0) { + if (update_type == AHC_TRANS_USER) + cts->sync_offset = tinfo->user.offset; + else + cts->sync_offset = tinfo->goal.offset; + } + + if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) == 0) { + if (update_type == AHC_TRANS_USER) + cts->sync_period = tinfo->user.period; + else + cts->sync_period = tinfo->goal.period; + } + if (((cts->valid & CCB_TRANS_SYNC_RATE_VALID) != 0) || ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0)) { struct ahc_syncrate *syncrate; + u_int ppr_options; u_int maxsync; if ((ahc->features & AHC_ULTRA2) != 0) - maxsync = AHC_SYNCRATE_ULTRA2; + maxsync = AHC_SYNCRATE_DT; else if ((ahc->features & AHC_ULTRA) != 0) maxsync = AHC_SYNCRATE_ULTRA; else maxsync = AHC_SYNCRATE_FAST; - if ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) == 0) { - if (update_type & AHC_TRANS_USER) - cts->sync_offset = tinfo->user.offset; - else - cts->sync_offset = tinfo->goal.offset; - } - - if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) == 0) { - if (update_type & AHC_TRANS_USER) - cts->sync_period = tinfo->user.period; - else - cts->sync_period = tinfo->goal.period; - } + ppr_options = 0; + if (cts->sync_period <= 9) + ppr_options = MSG_EXT_PPR_DT_REQ; syncrate = ahc_find_syncrate(ahc, &cts->sync_period, + &ppr_options, maxsync); ahc_validate_offset(ahc, syncrate, &cts->sync_offset, MSG_EXT_WDTR_BUS_8_BIT); /* We use a period of 0 to represent async */ - if (cts->sync_offset == 0) + if (cts->sync_offset == 0) { cts->sync_period = 0; + ppr_options = 0; + } + if (ppr_options == MSG_EXT_PPR_DT_REQ + && tinfo->user.transport_version >= 3) { + tinfo->goal.transport_version = + tinfo->user.transport_version; + tinfo->current.transport_version = + tinfo->user.transport_version; + } + ahc_set_syncrate(ahc, &devinfo, cts->ccb_h.path, syncrate, cts->sync_period, - cts->sync_offset, update_type, - /*paused*/FALSE); + cts->sync_offset, ppr_options, + update_type, /*paused*/FALSE); } + splx(s); ccb->ccb_h.status = CAM_REQ_CMP; xpt_done(ccb); @@ -4881,7 +5256,7 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) s = splcam(); cts->flags &= ~(CCB_TRANS_DISC_ENB|CCB_TRANS_TAG_ENB); - if ((cts->flags & CCB_TRANS_USER_SETTINGS) != 0) { + if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0) { if ((ahc->user_discenable & devinfo.target_mask) != 0) cts->flags |= CCB_TRANS_DISC_ENB; @@ -4894,7 +5269,6 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) if ((tstate->tagenable & devinfo.target_mask) != 0) cts->flags |= CCB_TRANS_TAG_ENB; } - cts->sync_period = tinfo->period; cts->sync_offset = tinfo->offset; cts->bus_width = tinfo->width; @@ -4914,8 +5288,8 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) case XPT_CALC_GEOMETRY: { struct ccb_calc_geometry *ccg; - u_int32_t size_mb; - u_int32_t secs_per_cylinder; + uint32_t size_mb; + uint32_t secs_per_cylinder; int extended; ccg = &ccb->ccg; @@ -4946,7 +5320,7 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) found = ahc_reset_channel(ahc, SIM_CHANNEL(ahc, sim), /*initiate reset*/TRUE); splx(s); - if (bootverbose) { + if (1 || bootverbose) { xpt_print_path(SIM_PATH(ahc, sim)); printf("SCSI bus reset delivered. " "%d SCBs aborted.\n", found); @@ -4979,7 +5353,7 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) ? 0 : PIM_NOINITIATOR; cpi->hba_eng_cnt = 0; cpi->max_target = (ahc->features & AHC_WIDE) ? 15 : 7; - cpi->max_lun = 7; + cpi->max_lun = 64; if (SIM_IS_SCSIBUS_B(ahc, sim)) { cpi->initiator_id = ahc->our_id_b; if ((ahc->flags & AHC_RESET_BUS_B) == 0) @@ -5007,7 +5381,7 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) } static void -ahc_async(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg) +ahc_async(void *callback_arg, uint32_t code, struct cam_path *path, void *arg) { struct ahc_softc *ahc; struct cam_sim *sim; @@ -5035,7 +5409,7 @@ ahc_async(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg) AHC_TRANS_GOAL|AHC_TRANS_CUR, /*paused*/FALSE); ahc_set_syncrate(ahc, &devinfo, path, /*syncrate*/NULL, - /*period*/0, /*offset*/0, + /*period*/0, /*offset*/0, /*ppr_options*/0, AHC_TRANS_GOAL|AHC_TRANS_CUR, /*paused*/FALSE); splx(s); @@ -5077,21 +5451,23 @@ ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments, end_seg = dm_segs + nsegments; - /* Copy the first SG into the data pointer area */ - scb->hscb->data = dm_segs->ds_addr; - scb->hscb->datalen = dm_segs->ds_len; - /* Copy the segments into our SG list */ sg = scb->sg_list; while (dm_segs < end_seg) { sg->addr = dm_segs->ds_addr; +/* XXX Add in the 5th byte of the address later. */ sg->len = dm_segs->ds_len; sg++; dm_segs++; } - - /* Note where to find the SG entries in bus space */ - scb->hscb->SG_pointer = scb->sg_list_phys; + + /* + * Note where to find the SG entries in bus space. + * We also set the full residual flag which the + * sequencer will clear as soon as a data transfer + * occurs. + */ + scb->hscb->sgptr = scb->sg_list_phys | SG_FULL_RESID; if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) op = BUS_DMASYNC_PREREAD; @@ -5101,9 +5477,14 @@ ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments, bus_dmamap_sync(ahc->buffer_dmat, scb->dmamap, op); if (ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) { - scb->hscb->cmdpointer |= DPHASE_PENDING; - if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) - scb->hscb->cmdpointer |= (TARGET_DATA_IN << 8); + struct target_data *tdata; + + tdata = &scb->hscb->shared_data.tdata; + tdata->target_phases |= DPHASE_PENDING; + if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) + tdata->data_phase = P_DATAOUT; + else + tdata->data_phase = P_DATAIN; /* * If the transfer is of an odd length and in the @@ -5115,9 +5496,9 @@ ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments, * negotiated wide as negotiation could occur before * this command is executed. */ - if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN + if ((ahc->bugs & AHC_TMODE_WIDEODD_BUG) != 0 && (ccb->csio.dxfer_len & 0x1) != 0 - && (ahc->features & AHC_TARG_DMABUG) != 0) { + && (ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { nsegments++; if (nsegments > AHC_NSEG) { @@ -5132,15 +5513,22 @@ ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments, } sg->addr = ahc->dma_bug_buf; sg->len = 1; + sg++; } } + sg--; + sg->len |= AHC_DMA_LAST_SEG; + + /* Copy the first SG into the "current" data pointer area */ + scb->hscb->dataptr = scb->sg_list->addr; + scb->hscb->datacnt = scb->sg_list->len; } else { - scb->hscb->SG_pointer = 0; - scb->hscb->data = 0; - scb->hscb->datalen = 0; + scb->hscb->sgptr = SG_LIST_NULL; + scb->hscb->dataptr = 0; + scb->hscb->datacnt = 0; } - scb->sg_count = scb->hscb->SG_count = nsegments; + scb->sg_count = nsegments; s = splcam(); @@ -5157,14 +5545,9 @@ ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments, return; } - /* Busy this tcl if we are untagged */ - if ((scb->hscb->control & TAG_ENB) == 0) - ahc_busy_tcl(ahc, scb); - LIST_INSERT_HEAD(&ahc->pending_ccbs, &ccb->ccb_h, sim_links.le); - scb->flags |= SCB_ACTIVE; ccb->ccb_h.status |= CAM_SIM_QUEUED; if (ccb->ccb_h.timeout != CAM_TIME_INFINITY) { @@ -5175,6 +5558,25 @@ ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments, (ccb->ccb_h.timeout * hz) / 1000); } + /* + * We only allow one untagged transaction + * per target in the initiator role unless + * we are storing a full busy target *lun* + * table in SCB space. + */ + if ((scb->hscb->control & (TARGET_SCB|TAG_ENB)) == 0 + && (ahc->features & AHC_SCB_BTT) == 0) { + struct scb_tailq *untagged_q; + + untagged_q = &(ahc->untagged_queues[ccb->ccb_h.target_id]); + TAILQ_INSERT_TAIL(untagged_q, scb, links.tqe); + if (TAILQ_FIRST(untagged_q) != scb) { + splx(s); + return; + } + } + scb->flags |= SCB_ACTIVE; + if ((scb->flags & SCB_TARGET_IMMEDIATE) != 0) { #if 0 printf("Continueing Immediate Command %d:%d\n", @@ -5187,16 +5589,7 @@ ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments, ahc_outb(ahc, RETURN_1, CONT_MSG_LOOP); unpause_sequencer(ahc); } else { - - ahc->qinfifo[ahc->qinfifonext++] = scb->hscb->tag; - - if ((ahc->features & AHC_QUEUE_REGS) != 0) { - ahc_outb(ahc, HNSCB_QOFF, ahc->qinfifonext); - } else { - pause_sequencer(ahc); - ahc_outb(ahc, KERNEL_QINPOS, ahc->qinfifonext); - unpause_sequencer(ahc); - } + ahc_queue_scb(ahc, scb); } splx(s); @@ -5219,33 +5612,42 @@ ahc_setup_data(struct ahc_softc *ahc, struct ccb_scsiio *csio, ccb_h = &csio->ccb_h; if (ccb_h->func_code == XPT_SCSI_IO) { - hscb->cmdlen = csio->cdb_len; + hscb->cdb_len = csio->cdb_len; if ((ccb_h->flags & CAM_CDB_POINTER) != 0) { - if ((ccb_h->flags & CAM_CDB_PHYS) == 0) - if (hscb->cmdlen <= 16) { - memcpy(hscb->cmdstore, - csio->cdb_io.cdb_ptr, - hscb->cmdlen); - hscb->cmdpointer = - hscb->cmdstore_busaddr; - } else { - ahcsetccbstatus(scb->ccb, - CAM_REQ_INVALID); - xpt_done(scb->ccb); - ahcfreescb(ahc, scb); - return; + + if (hscb->cdb_len > sizeof(hscb->cdb32) + || (ccb_h->flags & CAM_CDB_PHYS) != 0) { + ahcsetccbstatus(scb->ccb, CAM_REQ_INVALID); + xpt_done(scb->ccb); + ahcfreescb(ahc, scb); + return; + } + if (hscb->cdb_len > 12) { + memcpy(hscb->cdb32, + csio->cdb_io.cdb_ptr, + hscb->cdb_len); + if ((ahc->flags & AHC_CMD_CHAN) == 0) { + hscb->shared_data.cdb_ptr = + scb->cdb32_busaddr; } - else - hscb->cmdpointer = - ((intptr_t)csio->cdb_io.cdb_ptr) & 0xffffffff; + } else { + memcpy(hscb->shared_data.cdb, + csio->cdb_io.cdb_ptr, + hscb->cdb_len); + } } else { - /* - * CCB CDB Data Storage area is only 16 bytes - * so no additional testing is required - */ - memcpy(hscb->cmdstore, csio->cdb_io.cdb_bytes, - hscb->cmdlen); - hscb->cmdpointer = hscb->cmdstore_busaddr; + if (hscb->cdb_len > 12) { + memcpy(hscb->cdb32, csio->cdb_io.cdb_bytes, + hscb->cdb_len); + if ((ahc->flags & AHC_CMD_CHAN) == 0) { + hscb->shared_data.cdb_ptr = + scb->cdb32_busaddr; + } + } else { + memcpy(hscb->shared_data.cdb, + csio->cdb_io.cdb_bytes, + hscb->cdb_len); + } } } @@ -5381,10 +5783,11 @@ ahcallocscbs(struct ahc_softc *ahc) break; next_scb->hscb = &scb_data->hscbs[scb_data->numscbs]; next_scb->hscb->tag = ahc->scb_data->numscbs; - next_scb->hscb->cmdstore_busaddr = + next_scb->cdb32_busaddr = ahc_hscb_busaddr(ahc, next_scb->hscb->tag) - + offsetof(struct hardware_scb, cmdstore); - SLIST_INSERT_HEAD(&ahc->scb_data->free_scbs, next_scb, links); + + offsetof(struct hardware_scb, cdb32); + 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++; @@ -5410,7 +5813,7 @@ ahc_dumpseq(struct ahc_softc* ahc) ahc_outb(ahc, SEQADDR0, 0); ahc_outb(ahc, SEQADDR1, 0); for (i = 0; i < max_prog; i++) { - u_int8_t ins_bytes[4]; + uint8_t ins_bytes[4]; ahc_insb(ahc, SEQRAM, ins_bytes, 4); printf("0x%08x\n", ins_bytes[0] << 24 @@ -5425,16 +5828,16 @@ static void ahc_loadseq(struct ahc_softc *ahc) { struct patch *cur_patch; - int i; + u_int i; int downloaded; - int skip_addr; - u_int8_t download_consts[4]; + u_int skip_addr; + uint8_t download_consts[2]; /* Setup downloadable constant table */ -#if 0 - /* No downloaded constants are currently defined. */ - download_consts[TMODE_NUMCMDS] = ahc->num_targetcmds; -#endif + download_consts[QOUTFIFO_OFFSET] = 0; + if (ahc->targetcmds != NULL) + download_consts[QOUTFIFO_OFFSET] += 32; + download_consts[QINFIFO_OFFSET] = download_consts[QOUTFIFO_OFFSET] + 1; cur_patch = patches; downloaded = 0; @@ -5463,11 +5866,11 @@ ahc_loadseq(struct ahc_softc *ahc) static int ahc_check_patch(struct ahc_softc *ahc, struct patch **start_patch, - int start_instr, int *skip_addr) + u_int start_instr, u_int *skip_addr) { struct patch *cur_patch; struct patch *last_patch; - int num_patches; + u_int num_patches; num_patches = sizeof(patches)/sizeof(struct patch); last_patch = &patches[num_patches]; @@ -5498,7 +5901,7 @@ ahc_check_patch(struct ahc_softc *ahc, struct patch **start_patch, } static void -ahc_download_instr(struct ahc_softc *ahc, int instrptr, u_int8_t *dconsts) +ahc_download_instr(struct ahc_softc *ahc, u_int instrptr, uint8_t *dconsts) { union ins_formats instr; struct ins_format1 *fmt1_ins; @@ -5508,6 +5911,15 @@ ahc_download_instr(struct ahc_softc *ahc, int instrptr, u_int8_t *dconsts) /* Structure copy */ instr = *(union ins_formats*)&seqprog[instrptr * 4]; +#if BYTE_ORDER == BIG_ENDIAN + opcode = instr.format.bytes[0]; + instr.format.bytes[0] = instr.format.bytes[3]; + instr.format.bytes[3] = opcode; + opcode = instr.format.bytes[1]; + instr.format.bytes[1] = instr.format.bytes[2]; + instr.format.bytes[2] = opcode; +#endif + fmt1_ins = &instr.format1; fmt3_ins = NULL; @@ -5526,8 +5938,8 @@ ahc_download_instr(struct ahc_softc *ahc, int instrptr, u_int8_t *dconsts) struct patch *cur_patch; int address_offset; u_int address; - int skip_addr; - int i; + u_int skip_addr; + u_int i; fmt3_ins = &instr.format3; address_offset = 0; @@ -5570,7 +5982,7 @@ ahc_download_instr(struct ahc_softc *ahc, int instrptr, u_int8_t *dconsts) /* Calculate odd parity for the instruction */ for (i = 0, count = 0; i < 31; i++) { - u_int32_t mask; + uint32_t mask; mask = 0x01 << i; if ((instr.integer & mask) != 0) @@ -5595,6 +6007,14 @@ ahc_download_instr(struct ahc_softc *ahc, int instrptr, u_int8_t *dconsts) | (fmt1_ins->opcode << 25); } } +#if BYTE_ORDER == BIG_ENDIAN + opcode = instr.format.bytes[0]; + instr.format.bytes[0] = instr.format.bytes[3]; + instr.format.bytes[3] = opcode; + opcode = instr.format.bytes[1]; + instr.format.bytes[1] = instr.format.bytes[2]; + instr.format.bytes[2] = opcode; +#endif ahc_outsb(ahc, SEQRAM, instr.bytes, 4); break; default: @@ -5665,19 +6085,20 @@ ahc_timeout(void *arg) pause_sequencer(ahc); } while (ahc_inb(ahc, INTSTAT) & INT_PEND); + xpt_print_path(scb->ccb->ccb_h.path); if ((scb->flags & SCB_ACTIVE) == 0) { /* Previous timeout took care of me already */ - printf("Timedout SCB handled by another timeout\n"); + printf("Timedout SCB %d handled by another timeout\n", + scb->hscb->tag); unpause_sequencer(ahc); splx(s); return; } - target = SCB_TARGET(scb); - channel = SCB_CHANNEL(scb); - lun = SCB_LUN(scb); + target = SCB_GET_TARGET(ahc, scb); + channel = SCB_GET_CHANNEL(ahc, scb); + lun = SCB_GET_LUN(scb); - xpt_print_path(scb->ccb->ccb_h.path); printf("SCB 0x%x - timed out ", scb->hscb->tag); /* * Take a snapshot of the bus state and print out @@ -5771,7 +6192,8 @@ bus_reset: * taking additional action. */ active_scb = &ahc->scb_data->scbarray[active_scb_index]; - if (active_scb->hscb->tcl != scb->hscb->tcl) { + if (active_scb->hscb->scsiid != scb->hscb->scsiid + || active_scb->hscb->lun != scb->hscb->lun) { struct ccb_hdr *ccbh; u_int newtimeout; @@ -5871,8 +6293,6 @@ bus_reset: ahc_outb(ahc, SCB_CONTROL, scb_control); } ahc_outb(ahc, SCBPTR, active_scb); - ahc_index_busy_tcl(ahc, scb->hscb->tcl, - /*unbusy*/TRUE); /* * Actually re-queue this SCB in case we can @@ -5881,8 +6301,9 @@ bus_reset: * so we are the next SCB for this target * to run. */ - ahc_search_qinfifo(ahc, SCB_TARGET(scb), - channel, SCB_LUN(scb), + ahc_search_qinfifo(ahc, + SCB_GET_TARGET(ahc, scb), + channel, SCB_GET_LUN(scb), SCB_LIST_NULL, ROLE_INITIATOR, CAM_REQUEUE_REQ, @@ -5918,18 +6339,28 @@ bus_reset: static int ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel, - int lun, u_int tag, role_t role, u_int32_t status, + int lun, u_int tag, role_t role, uint32_t status, ahc_search_action action) { struct scb *scbp; - u_int8_t qinpos; - u_int8_t qintail; + uint8_t qinpos; + uint8_t qintail; + uint8_t next, prev; + uint8_t curscbptr; int found; qinpos = ahc_inb(ahc, QINPOS); qintail = ahc->qinfifonext; found = 0; + 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); + } + /* * Start with an empty queue. Entries that are not chosen * for removal will be re-added to the queue as we go. @@ -5938,10 +6369,11 @@ ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel, while (qinpos != qintail) { scbp = &ahc->scb_data->scbarray[ahc->qinfifo[qinpos]]; - if (ahc_match_scb(scbp, target, channel, lun, tag, role)) { + if (ahc_match_scb(ahc, scbp, target, channel, lun, tag, role)) { /* - * We found an scb that needs to be removed. + * We found an scb that needs to be acted on. */ + found++; switch (action) { case SEARCH_COMPLETE: if (ahc_ccb_status(scbp->ccb) == CAM_REQ_INPROG) @@ -5956,7 +6388,6 @@ ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel, case SEARCH_REMOVE: break; } - found++; } else { ahc->qinfifo[ahc->qinfifonext++] = scbp->hscb->tag; } @@ -5969,6 +6400,56 @@ ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel, ahc_outb(ahc, KERNEL_QINPOS, ahc->qinfifonext); } + /* + * Search waiting for selection list. + */ + curscbptr = ahc_inb(ahc, SCBPTR); + next = ahc_inb(ahc, WAITING_SCBH); /* Start at head of list. */ + prev = SCB_LIST_NULL; + + while (next != SCB_LIST_NULL) { + uint8_t scb_index; + + ahc_outb(ahc, SCBPTR, next); + scb_index = ahc_inb(ahc, SCB_TAG); + if (scb_index >= ahc->scb_data->numscbs) { + panic("Waiting List inconsistency. " + "SCB index == %d, yet numscbs == %d.", + scb_index, ahc->scb_data->numscbs); + } + scbp = &ahc->scb_data->scbarray[scb_index]; + if (ahc_match_scb(ahc, scbp, target, channel, + lun, SCB_LIST_NULL, role)) { + /* + * We found an scb that needs to be acted on. + */ + found++; + switch (action) { + case SEARCH_REMOVE: + next = ahc_rem_wscb(ahc, next, prev); + break; + case SEARCH_COMPLETE: + next = ahc_rem_wscb(ahc, next, prev); + if (ahc_ccb_status(scbp->ccb) == CAM_REQ_INPROG) + ahcsetccbstatus(scbp->ccb, status); + ahc_freeze_ccb(scbp->ccb); + ahc_done(ahc, scbp); + break; + case SEARCH_COUNT: + prev = next; + next = ahc_inb(ahc, SCB_NEXT); + break; + } + } else { + + prev = next; + next = ahc_inb(ahc, SCB_NEXT); + } + } + ahc_outb(ahc, SCBPTR, curscbptr); + + if (action == SEARCH_COMPLETE) + ahc_release_untagged_queues(ahc); return (found); } @@ -6063,13 +6544,20 @@ ahc_abort_ccb(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb) */ static int ahc_abort_scbs(struct ahc_softc *ahc, int target, char channel, - int lun, u_int tag, role_t role, u_int32_t status) + int lun, u_int tag, role_t role, uint32_t status) { struct scb *scbp; u_int active_scb; int i; + int maxtarget; int found; + /* + * Don't attempt to run any queued untagged transactions + * until we are done with the abort process. + */ + ahc_freeze_untagged_queues(ahc); + /* restore this when we're done */ active_scb = ahc_inb(ahc, SCBPTR); @@ -6077,36 +6565,28 @@ ahc_abort_scbs(struct ahc_softc *ahc, int target, char channel, role, CAM_REQUEUE_REQ, SEARCH_COMPLETE); /* - * Search waiting for selection list. + * Clean out the busy target table for any untagged commands. */ - { - u_int8_t next, prev; - - next = ahc_inb(ahc, WAITING_SCBH); /* Start at head of list. */ - prev = SCB_LIST_NULL; - - while (next != SCB_LIST_NULL) { - u_int8_t scb_index; + i = 0; + maxtarget = 16; + if (target != CAM_TARGET_WILDCARD) { + i = target; + maxtarget = target + 1; + } - ahc_outb(ahc, SCBPTR, next); - scb_index = ahc_inb(ahc, SCB_TAG); - if (scb_index >= ahc->scb_data->numscbs) { - panic("Waiting List inconsistency. " - "SCB index == %d, yet numscbs == %d.", - scb_index, ahc->scb_data->numscbs); - } - scbp = &ahc->scb_data->scbarray[scb_index]; - if (ahc_match_scb(scbp, target, channel, - lun, SCB_LIST_NULL, role)) { + for (;i < maxtarget; i++) { + u_int scbid; - next = ahc_abort_wscb(ahc, next, prev); - } else { - - prev = next; - next = ahc_inb(ahc, SCB_NEXT); - } - } + /* XXX Will need lun loop for SCB ram version */ + scbid = ahc_index_busy_tcl(ahc, BUILD_TCL(i << 4, 0), + /*unbusy*/FALSE); + scbp = &ahc->scb_data->scbarray[scbid]; + if (scbid < ahc->scb_data->numscbs + && ahc_match_scb(ahc, scbp, target, channel, lun, tag, role)) + ahc_index_busy_tcl(ahc, BUILD_TCL(i << 4, 0), + /*unbusy*/TRUE); } + /* * Go through the disconnected list and remove any entries we * have queued for completion, 0'ing their control byte too. @@ -6128,7 +6608,7 @@ ahc_abort_scbs(struct ahc_softc *ahc, int target, char channel, scbid = ahc_inb(ahc, SCB_TAG); scbp = &ahc->scb_data->scbarray[scbid]; if (scbid < ahc->scb_data->numscbs - && ahc_match_scb(scbp, target, channel, lun, tag, role)) + && ahc_match_scb(ahc, scbp, target, channel, lun, tag, role)) ahc_add_curscb_to_free_list(ahc); } @@ -6145,7 +6625,7 @@ ahc_abort_scbs(struct ahc_softc *ahc, int target, char channel, while (ccb_h != NULL) { scbp = (struct scb *)ccb_h->ccb_scb_ptr; ccb_h = ccb_h->sim_links.le.le_next; - if (ahc_match_scb(scbp, target, channel, + if (ahc_match_scb(ahc, scbp, target, channel, lun, tag, role)) { if (ahc_ccb_status(scbp->ccb) == CAM_REQ_INPROG) ahcsetccbstatus(scbp->ccb, status); @@ -6156,6 +6636,7 @@ ahc_abort_scbs(struct ahc_softc *ahc, int target, char channel, } } ahc_outb(ahc, SCBPTR, active_scb); + ahc_release_untagged_queues(ahc); return found; } @@ -6191,8 +6672,14 @@ ahc_search_disc_list(struct ahc_softc *ahc, int target, char channel, "SCB index == %d, yet numscbs == %d.", scb_index, ahc->scb_data->numscbs); } + + if (next == prev) { + panic("Disconnected List Loop. " + "cur SCBPTR == %x, prev SCBPTR == %x.", + next, prev); + } scbp = &ahc->scb_data->scbarray[scb_index]; - if (ahc_match_scb(scbp, target, channel, lun, + if (ahc_match_scb(ahc, scbp, target, channel, lun, tag, ROLE_INITIATOR)) { count++; if (remove) { @@ -6250,7 +6737,7 @@ ahc_add_curscb_to_free_list(struct ahc_softc *ahc) * scb that follows the one that we remove. */ static u_int -ahc_abort_wscb(struct ahc_softc *ahc, u_int scbpos, u_int prev) +ahc_rem_wscb(struct ahc_softc *ahc, u_int scbpos, u_int prev) { u_int curscb, next; @@ -6307,7 +6794,7 @@ ahc_clear_intstat(struct ahc_softc *ahc) static void ahc_reset_current_bus(struct ahc_softc *ahc) { - u_int8_t scsiseq; + uint8_t scsiseq; ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) & ~ENSCSIRST); scsiseq = ahc_inb(ahc, SCSISEQ); @@ -6466,8 +6953,8 @@ ahc_reset_channel(struct ahc_softc *ahc, char channel, int initiate_reset) AHC_TRANS_CUR, /*paused*/TRUE); ahc_set_syncrate(ahc, &devinfo, path, /*syncrate*/NULL, /*period*/0, - /*offset*/0, AHC_TRANS_CUR, - /*paused*/TRUE); + /*offset*/0, /*ppr_options*/0, + AHC_TRANS_CUR, /*paused*/TRUE); } } @@ -6479,12 +6966,12 @@ ahc_reset_channel(struct ahc_softc *ahc, char channel, int initiate_reset) } static int -ahc_match_scb(struct scb *scb, int target, char channel, - int lun, u_int tag, role_t role) +ahc_match_scb(struct ahc_softc *ahc, struct scb *scb, int target, + char channel, int lun, u_int tag, role_t role) { - int targ = SCB_TARGET(scb); - char chan = SCB_CHANNEL(scb); - int slun = SCB_LUN(scb); + int targ = SCB_GET_TARGET(ahc, scb); + char chan = SCB_GET_CHANNEL(ahc, scb); + int slun = SCB_GET_LUN(scb); int match; match = ((chan == channel) || (channel == ALL_CHANNELS)); @@ -6532,64 +7019,93 @@ ahc_construct_wdtr(struct ahc_softc *ahc, u_int bus_width) } static void -ahc_calc_residual(struct scb *scb) +ahc_construct_ppr(struct ahc_softc *ahc, u_int period, u_int offset, + u_int bus_width, u_int ppr_options) { - struct hardware_scb *hscb; + 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; + ahc->msgout_buf[ahc->msgout_index++] = period; + ahc->msgout_buf[ahc->msgout_index++] = 0; + ahc->msgout_buf[ahc->msgout_index++] = offset; + ahc->msgout_buf[ahc->msgout_index++] = bus_width; + ahc->msgout_buf[ahc->msgout_index++] = ppr_options; + ahc->msgout_len += 8; +} - hscb = scb->hscb; +static void +ahc_calc_residual(struct scb *scb) +{ + struct hardware_scb *hscb; + struct status_pkt *spkt; + uint32_t resid; /* - * If the disconnected flag is still set, this is bogus - * residual information left over from a sequencer - * pagin/pageout, so ignore this case. + * 4 cases. + * 1) No residual. + * SG_RESID_VALID clear in sgptr. + * 2) Transferless command + * 3) Never performed any transfers. + * sgptr has SG_FULL_RESID set. + * 4) We have a partial residual. + * Use residual_sgptr to determine + * where we are. */ - if ((scb->hscb->control & DISCONNECTED) == 0) { - u_int32_t resid; - int resid_sgs; - int sg; - + + /* Cases 1, 2 & 3 are easy. Check them first. */ + hscb = scb->hscb; + if ((hscb->sgptr & SG_RESID_VALID) == 0) + return; + hscb->sgptr &= ~SG_RESID_VALID; + + if ((hscb->sgptr & SG_LIST_NULL) != 0) + return; + + spkt = &hscb->shared_data.status; + if ((hscb->sgptr & SG_FULL_RESID) != 0) + resid = scb->ccb->csio.dxfer_len; + else if ((hscb->sgptr & ~SG_PTR_MASK) != 0) + panic("Bogus sgptr value 0x%x\n", hscb->sgptr); + else if ((spkt->residual_sg_ptr & ~SG_PTR_MASK) != 0) + panic("Bogus resid sgptr value 0x%x\n", spkt->residual_sg_ptr); + else { + struct ahc_dma_seg *sg; + /* * Remainder of the SG where the transfer - * stopped. + * stopped. */ - resid = (hscb->residual_data_count[2] << 16) - | (hscb->residual_data_count[1] <<8) - | (hscb->residual_data_count[0]); + resid = spkt->residual_datacnt & AHC_SG_LEN_MASK; + sg = ahc_sg_bus_to_virt(scb, + spkt->residual_sg_ptr & SG_PTR_MASK); + + /* The residual sg_ptr always points to the next sg */ + sg--; /* * Add up the contents of all residual * SG segments that are after the SG where * the transfer stopped. */ - resid_sgs = scb->hscb->residual_SG_count - 1/*current*/; - sg = scb->sg_count - resid_sgs; - while (resid_sgs > 0) { - - resid += scb->sg_list[sg].len; + while ((sg->len & AHC_DMA_LAST_SEG) == 0) { sg++; - resid_sgs--; + resid += sg->len & AHC_SG_LEN_MASK; } - if ((scb->flags & SCB_SENSE) == 0) { + } + if ((scb->flags & SCB_SENSE) == 0) { - scb->ccb->csio.resid = resid; - } else { + scb->ccb->csio.resid = resid; + } else { - scb->ccb->csio.sense_resid = resid; - } + scb->ccb->csio.sense_resid = resid; + } #ifdef AHC_DEBUG - if (ahc_debug & AHC_SHOWMISC) { - xpt_print_path(scb->ccb->ccb_h.path); - printf("Handled Residual of %d bytes\n", resid); - } -#endif + if (ahc_debug & AHC_SHOWMISC) { + xpt_print_path(scb->ccb->ccb_h.path); + printf("Handled Residual of %d bytes\n", resid); } - - /* - * Clean out the residual information in this SCB for its - * next consumer. - */ - hscb->residual_SG_count = 0; +#endif } static void @@ -6622,13 +7138,13 @@ ahc_update_pending_syncrates(struct ahc_softc *ahc) our_id = ccb->ccb_h.target_id; remote_id = ccb->ctio.init_id; } else { - our_id = SCB_IS_SCSIBUS_B(pending_scb) + our_id = SCB_IS_SCSIBUS_B(ahc, pending_scb) ? ahc->our_id_b : ahc->our_id; remote_id = ccb->ccb_h.target_id; } ahc_compile_devinfo(&devinfo, our_id, remote_id, - SCB_LUN(pending_scb), - SCB_CHANNEL(pending_scb), + SCB_GET_LUN(pending_scb), + SCB_GET_CHANNEL(ahc, pending_scb), ROLE_UNKNOWN); tinfo = ahc_fetch_transinfo(ahc, devinfo.channel, our_id, remote_id, &tstate); @@ -6670,13 +7186,13 @@ ahc_update_pending_syncrates(struct ahc_softc *ahc) our_id = ccb->ccb_h.target_id; remote_id = ccb->ctio.init_id; } else { - our_id = SCB_IS_SCSIBUS_B(pending_scb) + our_id = SCB_IS_SCSIBUS_B(ahc, pending_scb) ? ahc->our_id_b : ahc->our_id; remote_id = ccb->ccb_h.target_id; } ahc_compile_devinfo(&devinfo, our_id, remote_id, - SCB_LUN(pending_scb), - SCB_CHANNEL(pending_scb), + SCB_GET_LUN(pending_scb), + SCB_GET_CHANNEL(ahc, pending_scb), ROLE_UNKNOWN); tinfo = ahc_fetch_transinfo(ahc, devinfo.channel, our_id, remote_id, &tstate); @@ -6696,8 +7212,8 @@ ahc_update_pending_syncrates(struct ahc_softc *ahc) static void ahc_dump_targcmd(struct target_cmd *cmd) { - u_int8_t *byte; - u_int8_t *last_byte; + uint8_t *byte; + uint8_t *last_byte; int i; byte = &cmd->initiator_channel; |