#include "aic79xx_osm.h"
#include "aic79xx_inline.h"
#include "aicasm/aicasm_insformat.h"
static const char *const ahd_chip_names[] = …;
struct ahd_hard_error_entry { … };
static const struct ahd_hard_error_entry ahd_hard_errors[] = …;
static const u_int num_errors = …;
static const struct ahd_phase_table_entry ahd_phase_table[] = …;
static const u_int num_phases = …;
#include "aic79xx_seq.h"
static void ahd_handle_transmission_error(struct ahd_softc *ahd);
static void ahd_handle_lqiphase_error(struct ahd_softc *ahd,
u_int lqistat1);
static int ahd_handle_pkt_busfree(struct ahd_softc *ahd,
u_int busfreetime);
static int ahd_handle_nonpkt_busfree(struct ahd_softc *ahd);
static void ahd_handle_proto_violation(struct ahd_softc *ahd);
static void ahd_force_renegotiation(struct ahd_softc *ahd,
struct ahd_devinfo *devinfo);
static struct ahd_tmode_tstate*
ahd_alloc_tstate(struct ahd_softc *ahd,
u_int scsi_id, char channel);
#ifdef AHD_TARGET_MODE
static void ahd_free_tstate(struct ahd_softc *ahd,
u_int scsi_id, char channel, int force);
#endif
static void ahd_devlimited_syncrate(struct ahd_softc *ahd,
struct ahd_initiator_tinfo *,
u_int *period,
u_int *ppr_options,
role_t role);
static void ahd_update_neg_table(struct ahd_softc *ahd,
struct ahd_devinfo *devinfo,
struct ahd_transinfo *tinfo);
static void ahd_update_pending_scbs(struct ahd_softc *ahd);
static void ahd_fetch_devinfo(struct ahd_softc *ahd,
struct ahd_devinfo *devinfo);
static void ahd_scb_devinfo(struct ahd_softc *ahd,
struct ahd_devinfo *devinfo,
struct scb *scb);
static void ahd_setup_initiator_msgout(struct ahd_softc *ahd,
struct ahd_devinfo *devinfo,
struct scb *scb);
static void ahd_build_transfer_msg(struct ahd_softc *ahd,
struct ahd_devinfo *devinfo);
static void ahd_construct_sdtr(struct ahd_softc *ahd,
struct ahd_devinfo *devinfo,
u_int period, u_int offset);
static void ahd_construct_wdtr(struct ahd_softc *ahd,
struct ahd_devinfo *devinfo,
u_int bus_width);
static void ahd_construct_ppr(struct ahd_softc *ahd,
struct ahd_devinfo *devinfo,
u_int period, u_int offset,
u_int bus_width, u_int ppr_options);
static void ahd_clear_msg_state(struct ahd_softc *ahd);
static void ahd_handle_message_phase(struct ahd_softc *ahd);
ahd_msgtype;
static int ahd_sent_msg(struct ahd_softc *ahd, ahd_msgtype type,
u_int msgval, int full);
static int ahd_parse_msg(struct ahd_softc *ahd,
struct ahd_devinfo *devinfo);
static int ahd_handle_msg_reject(struct ahd_softc *ahd,
struct ahd_devinfo *devinfo);
static void ahd_handle_ign_wide_residue(struct ahd_softc *ahd,
struct ahd_devinfo *devinfo);
static void ahd_reinitialize_dataptrs(struct ahd_softc *ahd);
static void ahd_handle_devreset(struct ahd_softc *ahd,
struct ahd_devinfo *devinfo,
u_int lun, cam_status status,
char *message, int verbose_level);
#ifdef AHD_TARGET_MODE
static void ahd_setup_target_msgin(struct ahd_softc *ahd,
struct ahd_devinfo *devinfo,
struct scb *scb);
#endif
static u_int ahd_sglist_size(struct ahd_softc *ahd);
static u_int ahd_sglist_allocsize(struct ahd_softc *ahd);
static bus_dmamap_callback_t
ahd_dmamap_cb;
static void ahd_initialize_hscbs(struct ahd_softc *ahd);
static int ahd_init_scbdata(struct ahd_softc *ahd);
static void ahd_fini_scbdata(struct ahd_softc *ahd);
static void ahd_setup_iocell_workaround(struct ahd_softc *ahd);
static void ahd_iocell_first_selection(struct ahd_softc *ahd);
static void ahd_add_col_list(struct ahd_softc *ahd,
struct scb *scb, u_int col_idx);
static void ahd_rem_col_list(struct ahd_softc *ahd,
struct scb *scb);
static void ahd_chip_init(struct ahd_softc *ahd);
static void ahd_qinfifo_requeue(struct ahd_softc *ahd,
struct scb *prev_scb,
struct scb *scb);
static int ahd_qinfifo_count(struct ahd_softc *ahd);
static int ahd_search_scb_list(struct ahd_softc *ahd, int target,
char channel, int lun, u_int tag,
role_t role, uint32_t status,
ahd_search_action action,
u_int *list_head, u_int *list_tail,
u_int tid);
static void ahd_stitch_tid_list(struct ahd_softc *ahd,
u_int tid_prev, u_int tid_cur,
u_int tid_next);
static void ahd_add_scb_to_free_list(struct ahd_softc *ahd,
u_int scbid);
static u_int ahd_rem_wscb(struct ahd_softc *ahd, u_int scbid,
u_int prev, u_int next, u_int tid);
static void ahd_reset_current_bus(struct ahd_softc *ahd);
static void ahd_stat_timer(struct timer_list *t);
#ifdef AHD_DUMP_SEQ
static void ahd_dumpseq(struct ahd_softc *ahd);
#endif
static void ahd_loadseq(struct ahd_softc *ahd);
static int ahd_check_patch(struct ahd_softc *ahd,
const struct patch **start_patch,
u_int start_instr, u_int *skip_addr);
static u_int ahd_resolve_seqaddr(struct ahd_softc *ahd,
u_int address);
static void ahd_download_instr(struct ahd_softc *ahd,
u_int instrptr, uint8_t *dconsts);
static int ahd_probe_stack_size(struct ahd_softc *ahd);
static int ahd_scb_active_in_fifo(struct ahd_softc *ahd,
struct scb *scb);
static void ahd_run_data_fifo(struct ahd_softc *ahd,
struct scb *scb);
#ifdef AHD_TARGET_MODE
static void ahd_queue_lstate_event(struct ahd_softc *ahd,
struct ahd_tmode_lstate *lstate,
u_int initiator_id,
u_int event_type,
u_int event_arg);
static void ahd_update_scsiid(struct ahd_softc *ahd,
u_int targid_mask);
static int ahd_handle_target_cmd(struct ahd_softc *ahd,
struct target_cmd *cmd);
#endif
static int ahd_abort_scbs(struct ahd_softc *ahd, int target,
char channel, int lun, u_int tag,
role_t role, uint32_t status);
static void ahd_alloc_scbs(struct ahd_softc *ahd);
static void ahd_busy_tcl(struct ahd_softc *ahd, u_int tcl,
u_int scbid);
static void ahd_calc_residual(struct ahd_softc *ahd,
struct scb *scb);
static void ahd_clear_critical_section(struct ahd_softc *ahd);
static void ahd_clear_intstat(struct ahd_softc *ahd);
static void ahd_enable_coalescing(struct ahd_softc *ahd,
int enable);
static u_int ahd_find_busy_tcl(struct ahd_softc *ahd, u_int tcl);
static void ahd_freeze_devq(struct ahd_softc *ahd,
struct scb *scb);
static void ahd_handle_scb_status(struct ahd_softc *ahd,
struct scb *scb);
static const struct ahd_phase_table_entry* ahd_lookup_phase_entry(int phase);
static void ahd_shutdown(void *arg);
static void ahd_update_coalescing_values(struct ahd_softc *ahd,
u_int timer,
u_int maxcmds,
u_int mincmds);
static int ahd_verify_vpd_cksum(struct vpd_config *vpd);
static int ahd_wait_seeprom(struct ahd_softc *ahd);
static int ahd_match_scb(struct ahd_softc *ahd, struct scb *scb,
int target, char channel, int lun,
u_int tag, role_t role);
static void ahd_reset_cmds_pending(struct ahd_softc *ahd);
static void ahd_run_qoutfifo(struct ahd_softc *ahd);
#ifdef AHD_TARGET_MODE
static void ahd_run_tqinfifo(struct ahd_softc *ahd, int paused);
#endif
static void ahd_handle_hwerrint(struct ahd_softc *ahd);
static void ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat);
static void ahd_handle_scsiint(struct ahd_softc *ahd,
u_int intstat);
void
ahd_set_modes(struct ahd_softc *ahd, ahd_mode src, ahd_mode dst)
{ … }
static void
ahd_update_modes(struct ahd_softc *ahd)
{ … }
static void
ahd_assert_modes(struct ahd_softc *ahd, ahd_mode srcmode,
ahd_mode dstmode, const char *file, int line)
{ … }
#define AHD_ASSERT_MODES(ahd, source, dest) …
ahd_mode_state
ahd_save_modes(struct ahd_softc *ahd)
{ … }
void
ahd_restore_modes(struct ahd_softc *ahd, ahd_mode_state state)
{ … }
int
ahd_is_paused(struct ahd_softc *ahd)
{ … }
void
ahd_pause(struct ahd_softc *ahd)
{ … }
void
ahd_unpause(struct ahd_softc *ahd)
{ … }
void *
ahd_sg_setup(struct ahd_softc *ahd, struct scb *scb,
void *sgptr, dma_addr_t addr, bus_size_t len, int last)
{ … }
static void
ahd_setup_scb_common(struct ahd_softc *ahd, struct scb *scb)
{ … }
static void
ahd_setup_data_scb(struct ahd_softc *ahd, struct scb *scb)
{ … }
static void
ahd_setup_noxfer_scb(struct ahd_softc *ahd, struct scb *scb)
{ … }
static void *
ahd_sg_bus_to_virt(struct ahd_softc *ahd, struct scb *scb, uint32_t sg_busaddr)
{ … }
static uint32_t
ahd_sg_virt_to_bus(struct ahd_softc *ahd, struct scb *scb, void *sg)
{ … }
static void
ahd_sync_scb(struct ahd_softc *ahd, struct scb *scb, int op)
{ … }
void
ahd_sync_sglist(struct ahd_softc *ahd, struct scb *scb, int op)
{ … }
static void
ahd_sync_sense(struct ahd_softc *ahd, struct scb *scb, int op)
{ … }
#ifdef AHD_TARGET_MODE
static uint32_t
ahd_targetcmd_offset(struct ahd_softc *ahd, u_int index)
{
return (((uint8_t *)&ahd->targetcmds[index])
- (uint8_t *)ahd->qoutfifo);
}
#endif
struct ahd_initiator_tinfo *
ahd_fetch_transinfo(struct ahd_softc *ahd, char channel, u_int our_id,
u_int remote_id, struct ahd_tmode_tstate **tstate)
{ … }
uint16_t
ahd_inw(struct ahd_softc *ahd, u_int port)
{ … }
void
ahd_outw(struct ahd_softc *ahd, u_int port, u_int value)
{ … }
uint32_t
ahd_inl(struct ahd_softc *ahd, u_int port)
{ … }
void
ahd_outl(struct ahd_softc *ahd, u_int port, uint32_t value)
{ … }
uint64_t
ahd_inq(struct ahd_softc *ahd, u_int port)
{ … }
void
ahd_outq(struct ahd_softc *ahd, u_int port, uint64_t value)
{ … }
u_int
ahd_get_scbptr(struct ahd_softc *ahd)
{ … }
void
ahd_set_scbptr(struct ahd_softc *ahd, u_int scbptr)
{ … }
#if 0
static u_int
ahd_get_hnscb_qoff(struct ahd_softc *ahd)
{
return (ahd_inw_atomic(ahd, HNSCB_QOFF));
}
#endif
static void
ahd_set_hnscb_qoff(struct ahd_softc *ahd, u_int value)
{ … }
#if 0
static u_int
ahd_get_hescb_qoff(struct ahd_softc *ahd)
{
return (ahd_inb(ahd, HESCB_QOFF));
}
#endif
static void
ahd_set_hescb_qoff(struct ahd_softc *ahd, u_int value)
{ … }
static u_int
ahd_get_snscb_qoff(struct ahd_softc *ahd)
{ … }
static void
ahd_set_snscb_qoff(struct ahd_softc *ahd, u_int value)
{ … }
#if 0
static u_int
ahd_get_sescb_qoff(struct ahd_softc *ahd)
{
AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
return (ahd_inb(ahd, SESCB_QOFF));
}
#endif
static void
ahd_set_sescb_qoff(struct ahd_softc *ahd, u_int value)
{ … }
#if 0
static u_int
ahd_get_sdscb_qoff(struct ahd_softc *ahd)
{
AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
return (ahd_inb(ahd, SDSCB_QOFF) | (ahd_inb(ahd, SDSCB_QOFF + 1) << 8));
}
#endif
static void
ahd_set_sdscb_qoff(struct ahd_softc *ahd, u_int value)
{ … }
u_int
ahd_inb_scbram(struct ahd_softc *ahd, u_int offset)
{ … }
u_int
ahd_inw_scbram(struct ahd_softc *ahd, u_int offset)
{ … }
static uint32_t
ahd_inl_scbram(struct ahd_softc *ahd, u_int offset)
{ … }
static uint64_t
ahd_inq_scbram(struct ahd_softc *ahd, u_int offset)
{ … }
struct scb *
ahd_lookup_scb(struct ahd_softc *ahd, u_int tag)
{ … }
static void
ahd_swap_with_next_hscb(struct ahd_softc *ahd, struct scb *scb)
{ … }
void
ahd_queue_scb(struct ahd_softc *ahd, struct scb *scb)
{ … }
static void
ahd_sync_qoutfifo(struct ahd_softc *ahd, int op)
{ … }
static void
ahd_sync_tqinfifo(struct ahd_softc *ahd, int op)
{ … }
#define AHD_RUN_QOUTFIFO …
#define AHD_RUN_TQINFIFO …
static u_int
ahd_check_cmdcmpltqueues(struct ahd_softc *ahd)
{ … }
int
ahd_intr(struct ahd_softc *ahd)
{ … }
static inline void
ahd_assert_atn(struct ahd_softc *ahd)
{ … }
static int
ahd_currently_packetized(struct ahd_softc *ahd)
{ … }
static inline int
ahd_set_active_fifo(struct ahd_softc *ahd)
{ … }
static inline void
ahd_unbusy_tcl(struct ahd_softc *ahd, u_int tcl)
{ … }
static inline void
ahd_update_residual(struct ahd_softc *ahd, struct scb *scb)
{ … }
static inline void
ahd_complete_scb(struct ahd_softc *ahd, struct scb *scb)
{ … }
static void
ahd_restart(struct ahd_softc *ahd)
{ … }
static void
ahd_clear_fifo(struct ahd_softc *ahd, u_int fifo)
{ … }
static void
ahd_flush_qoutfifo(struct ahd_softc *ahd)
{ … }
static int
ahd_scb_active_in_fifo(struct ahd_softc *ahd, struct scb *scb)
{ … }
static void
ahd_run_data_fifo(struct ahd_softc *ahd, struct scb *scb)
{ … }
static void
ahd_run_qoutfifo(struct ahd_softc *ahd)
{ … }
static void
ahd_handle_hwerrint(struct ahd_softc *ahd)
{ … }
#ifdef AHD_DEBUG
static void
ahd_dump_sglist(struct scb *scb)
{ … }
#endif
static void
ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat)
{ … }
static void
ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat)
{ … }
static void
ahd_handle_transmission_error(struct ahd_softc *ahd)
{ … }
static void
ahd_handle_lqiphase_error(struct ahd_softc *ahd, u_int lqistat1)
{ … }
static int
ahd_handle_pkt_busfree(struct ahd_softc *ahd, u_int busfreetime)
{ … }
static int
ahd_handle_nonpkt_busfree(struct ahd_softc *ahd)
{ … }
static void
ahd_handle_proto_violation(struct ahd_softc *ahd)
{ … }
static void
ahd_force_renegotiation(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
{ … }
#define AHD_MAX_STEPS …
static void
ahd_clear_critical_section(struct ahd_softc *ahd)
{ … }
static void
ahd_clear_intstat(struct ahd_softc *ahd)
{ … }
#ifdef AHD_DEBUG
uint32_t ahd_debug = …;
#endif
#if 0
void
ahd_print_scb(struct scb *scb)
{
struct hardware_scb *hscb;
int i;
hscb = scb->hscb;
printk("scb:%p control:0x%x scsiid:0x%x lun:%d cdb_len:%d\n",
(void *)scb,
hscb->control,
hscb->scsiid,
hscb->lun,
hscb->cdb_len);
printk("Shared Data: ");
for (i = 0; i < sizeof(hscb->shared_data.idata.cdb); i++)
printk("%#02x", hscb->shared_data.idata.cdb[i]);
printk(" dataptr:%#x%x datacnt:%#x sgptr:%#x tag:%#x\n",
(uint32_t)((ahd_le64toh(hscb->dataptr) >> 32) & 0xFFFFFFFF),
(uint32_t)(ahd_le64toh(hscb->dataptr) & 0xFFFFFFFF),
ahd_le32toh(hscb->datacnt),
ahd_le32toh(hscb->sgptr),
SCB_GET_TAG(scb));
ahd_dump_sglist(scb);
}
#endif
static struct ahd_tmode_tstate *
ahd_alloc_tstate(struct ahd_softc *ahd, u_int scsi_id, char channel)
{ … }
#ifdef AHD_TARGET_MODE
static void
ahd_free_tstate(struct ahd_softc *ahd, u_int scsi_id, char channel, int force)
{
struct ahd_tmode_tstate *tstate;
if (scsi_id == ahd->our_id
&& force == FALSE)
return;
tstate = ahd->enabled_targets[scsi_id];
kfree(tstate);
ahd->enabled_targets[scsi_id] = NULL;
}
#endif
static void
ahd_devlimited_syncrate(struct ahd_softc *ahd,
struct ahd_initiator_tinfo *tinfo,
u_int *period, u_int *ppr_options, role_t role)
{ … }
void
ahd_find_syncrate(struct ahd_softc *ahd, u_int *period,
u_int *ppr_options, u_int maxsync)
{ … }
static void
ahd_validate_offset(struct ahd_softc *ahd,
struct ahd_initiator_tinfo *tinfo,
u_int period, u_int *offset, int wide,
role_t role)
{ … }
static void
ahd_validate_width(struct ahd_softc *ahd, struct ahd_initiator_tinfo *tinfo,
u_int *bus_width, role_t role)
{ … }
int
ahd_update_neg_request(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
struct ahd_tmode_tstate *tstate,
struct ahd_initiator_tinfo *tinfo, ahd_neg_type neg_type)
{ … }
void
ahd_set_syncrate(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
u_int period, u_int offset, u_int ppr_options,
u_int type, int paused)
{ … }
void
ahd_set_width(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
u_int width, u_int type, int paused)
{ … }
static void
ahd_set_tags(struct ahd_softc *ahd, struct scsi_cmnd *cmd,
struct ahd_devinfo *devinfo, ahd_queue_alg alg)
{ … }
static void
ahd_update_neg_table(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
struct ahd_transinfo *tinfo)
{ … }
static void
ahd_update_pending_scbs(struct ahd_softc *ahd)
{ … }
static void
ahd_fetch_devinfo(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
{ … }
void
ahd_print_devinfo(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
{ … }
static const struct ahd_phase_table_entry*
ahd_lookup_phase_entry(int phase)
{ … }
void
ahd_compile_devinfo(struct ahd_devinfo *devinfo, u_int our_id, u_int target,
u_int lun, char channel, role_t role)
{ … }
static void
ahd_scb_devinfo(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
struct scb *scb)
{ … }
static void
ahd_setup_initiator_msgout(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
struct scb *scb)
{ … }
static void
ahd_build_transfer_msg(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
{ … }
static void
ahd_construct_sdtr(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
u_int period, u_int offset)
{ … }
static void
ahd_construct_wdtr(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
u_int bus_width)
{ … }
static void
ahd_construct_ppr(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
u_int period, u_int offset, u_int bus_width,
u_int ppr_options)
{ … }
static void
ahd_clear_msg_state(struct ahd_softc *ahd)
{ … }
static void
ahd_handle_message_phase(struct ahd_softc *ahd)
{ … }
static int
ahd_sent_msg(struct ahd_softc *ahd, ahd_msgtype type, u_int msgval, int full)
{ … }
static int
ahd_parse_msg(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
{ … }
static int
ahd_handle_msg_reject(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
{ … }
static void
ahd_handle_ign_wide_residue(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
{ … }
static void
ahd_reinitialize_dataptrs(struct ahd_softc *ahd)
{ … }
static void
ahd_handle_devreset(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
u_int lun, cam_status status, char *message,
int verbose_level)
{ … }
#ifdef AHD_TARGET_MODE
static void
ahd_setup_target_msgin(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
struct scb *scb)
{
ahd->msgout_index = 0;
ahd->msgout_len = 0;
if (scb != NULL && (scb->flags & SCB_AUTO_NEGOTIATE) != 0)
ahd_build_transfer_msg(ahd, devinfo);
else
panic("ahd_intr: AWAITING target message with no message");
ahd->msgout_index = 0;
ahd->msg_type = MSG_TYPE_TARGET_MSGIN;
}
#endif
static u_int
ahd_sglist_size(struct ahd_softc *ahd)
{ … }
static u_int
ahd_sglist_allocsize(struct ahd_softc *ahd)
{ … }
struct ahd_softc *
ahd_alloc(void *platform_arg, char *name)
{ … }
int
ahd_softc_init(struct ahd_softc *ahd)
{ … }
void
ahd_set_unit(struct ahd_softc *ahd, int unit)
{ … }
void
ahd_set_name(struct ahd_softc *ahd, char *name)
{ … }
void
ahd_free(struct ahd_softc *ahd)
{ … }
static void
ahd_shutdown(void *arg)
{ … }
int
ahd_reset(struct ahd_softc *ahd, int reinit)
{ … }
static int
ahd_probe_scbs(struct ahd_softc *ahd) { … }
static void
ahd_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
{ … }
static void
ahd_initialize_hscbs(struct ahd_softc *ahd)
{ … }
static int
ahd_init_scbdata(struct ahd_softc *ahd)
{ … }
static struct scb *
ahd_find_scb_by_tag(struct ahd_softc *ahd, u_int tag)
{ … }
static void
ahd_fini_scbdata(struct ahd_softc *ahd)
{ … }
static void
ahd_setup_iocell_workaround(struct ahd_softc *ahd)
{ … }
static void
ahd_iocell_first_selection(struct ahd_softc *ahd)
{ … }
static void
ahd_add_col_list(struct ahd_softc *ahd, struct scb *scb, u_int col_idx)
{ … }
static void
ahd_rem_col_list(struct ahd_softc *ahd, struct scb *scb)
{ … }
struct scb *
ahd_get_scb(struct ahd_softc *ahd, u_int col_idx)
{ … }
void
ahd_free_scb(struct ahd_softc *ahd, struct scb *scb)
{ … }
static void
ahd_alloc_scbs(struct ahd_softc *ahd)
{ … }
void
ahd_controller_info(struct ahd_softc *ahd, char *buf)
{ … }
static const char *channel_strings[] = …;
static const char *termstat_strings[] = …;
static void
ahd_timer_reset(struct timer_list *timer, int usec)
{ … }
int
ahd_init(struct ahd_softc *ahd)
{ … }
static void
ahd_chip_init(struct ahd_softc *ahd)
{ … }
int
ahd_default_config(struct ahd_softc *ahd)
{ … }
int
ahd_parse_cfgdata(struct ahd_softc *ahd, struct seeprom_config *sc)
{ … }
int
ahd_parse_vpddata(struct ahd_softc *ahd, struct vpd_config *vpd)
{ … }
void
ahd_intr_enable(struct ahd_softc *ahd, int enable)
{ … }
static void
ahd_update_coalescing_values(struct ahd_softc *ahd, u_int timer, u_int maxcmds,
u_int mincmds)
{ … }
static void
ahd_enable_coalescing(struct ahd_softc *ahd, int enable)
{ … }
void
ahd_pause_and_flushwork(struct ahd_softc *ahd)
{ … }
int __maybe_unused
ahd_suspend(struct ahd_softc *ahd)
{ … }
void __maybe_unused
ahd_resume(struct ahd_softc *ahd)
{ … }
static inline u_int
ahd_index_busy_tcl(struct ahd_softc *ahd, u_int *saved_scbid, u_int tcl)
{ … }
static u_int
ahd_find_busy_tcl(struct ahd_softc *ahd, u_int tcl)
{ … }
static void
ahd_busy_tcl(struct ahd_softc *ahd, u_int tcl, u_int scbid)
{ … }
static int
ahd_match_scb(struct ahd_softc *ahd, struct scb *scb, int target,
char channel, int lun, u_int tag, role_t role)
{ … }
static void
ahd_freeze_devq(struct ahd_softc *ahd, struct scb *scb)
{ … }
void
ahd_qinfifo_requeue_tail(struct ahd_softc *ahd, struct scb *scb)
{ … }
static void
ahd_qinfifo_requeue(struct ahd_softc *ahd, struct scb *prev_scb,
struct scb *scb)
{ … }
static int
ahd_qinfifo_count(struct ahd_softc *ahd)
{ … }
static void
ahd_reset_cmds_pending(struct ahd_softc *ahd)
{ … }
static void
ahd_done_with_status(struct ahd_softc *ahd, struct scb *scb, uint32_t status)
{ … }
int
ahd_search_qinfifo(struct ahd_softc *ahd, int target, char channel,
int lun, u_int tag, role_t role, uint32_t status,
ahd_search_action action)
{ … }
static int
ahd_search_scb_list(struct ahd_softc *ahd, int target, char channel,
int lun, u_int tag, role_t role, uint32_t status,
ahd_search_action action, u_int *list_head,
u_int *list_tail, u_int tid)
{ … }
static void
ahd_stitch_tid_list(struct ahd_softc *ahd, u_int tid_prev,
u_int tid_cur, u_int tid_next)
{ … }
static u_int
ahd_rem_wscb(struct ahd_softc *ahd, u_int scbid,
u_int prev, u_int next, u_int tid)
{ … }
static void
ahd_add_scb_to_free_list(struct ahd_softc *ahd, u_int scbid)
{ … }
static int
ahd_abort_scbs(struct ahd_softc *ahd, int target, char channel,
int lun, u_int tag, role_t role, uint32_t status)
{ … }
static void
ahd_reset_current_bus(struct ahd_softc *ahd)
{ … }
int
ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset)
{ … }
static void
ahd_stat_timer(struct timer_list *t)
{ … }
static void
ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb)
{ … }
static void
ahd_handle_scb_status(struct ahd_softc *ahd, struct scb *scb)
{ … }
static void
ahd_calc_residual(struct ahd_softc *ahd, struct scb *scb)
{ … }
#ifdef AHD_TARGET_MODE
static void
ahd_queue_lstate_event(struct ahd_softc *ahd, struct ahd_tmode_lstate *lstate,
u_int initiator_id, u_int event_type, u_int event_arg)
{
struct ahd_tmode_event *event;
int pending;
xpt_freeze_devq(lstate->path, 1);
if (lstate->event_w_idx >= lstate->event_r_idx)
pending = lstate->event_w_idx - lstate->event_r_idx;
else
pending = AHD_TMODE_EVENT_BUFFER_SIZE + 1
- (lstate->event_r_idx - lstate->event_w_idx);
if (event_type == EVENT_TYPE_BUS_RESET
|| event_type == TARGET_RESET) {
lstate->event_r_idx = 0;
lstate->event_w_idx = 0;
xpt_release_devq(lstate->path, pending, FALSE);
}
if (pending == AHD_TMODE_EVENT_BUFFER_SIZE) {
xpt_print_path(lstate->path);
printk("immediate event %x:%x lost\n",
lstate->event_buffer[lstate->event_r_idx].event_type,
lstate->event_buffer[lstate->event_r_idx].event_arg);
lstate->event_r_idx++;
if (lstate->event_r_idx == AHD_TMODE_EVENT_BUFFER_SIZE)
lstate->event_r_idx = 0;
xpt_release_devq(lstate->path, 1, FALSE);
}
event = &lstate->event_buffer[lstate->event_w_idx];
event->initiator_id = initiator_id;
event->event_type = event_type;
event->event_arg = event_arg;
lstate->event_w_idx++;
if (lstate->event_w_idx == AHD_TMODE_EVENT_BUFFER_SIZE)
lstate->event_w_idx = 0;
}
void
ahd_send_lstate_events(struct ahd_softc *ahd, struct ahd_tmode_lstate *lstate)
{
struct ccb_hdr *ccbh;
struct ccb_immed_notify *inot;
while (lstate->event_r_idx != lstate->event_w_idx
&& (ccbh = SLIST_FIRST(&lstate->immed_notifies)) != NULL) {
struct ahd_tmode_event *event;
event = &lstate->event_buffer[lstate->event_r_idx];
SLIST_REMOVE_HEAD(&lstate->immed_notifies, sim_links.sle);
inot = (struct ccb_immed_notify *)ccbh;
switch (event->event_type) {
case EVENT_TYPE_BUS_RESET:
ccbh->status = CAM_SCSI_BUS_RESET|CAM_DEV_QFRZN;
break;
default:
ccbh->status = CAM_MESSAGE_RECV|CAM_DEV_QFRZN;
inot->message_args[0] = event->event_type;
inot->message_args[1] = event->event_arg;
break;
}
inot->initiator_id = event->initiator_id;
inot->sense_len = 0;
xpt_done((union ccb *)inot);
lstate->event_r_idx++;
if (lstate->event_r_idx == AHD_TMODE_EVENT_BUFFER_SIZE)
lstate->event_r_idx = 0;
}
}
#endif
#ifdef AHD_DUMP_SEQ
void
ahd_dumpseq(struct ahd_softc* ahd)
{
int i;
int max_prog;
max_prog = 2048;
ahd_outb(ahd, SEQCTL0, PERRORDIS|FAILDIS|FASTMODE|LOADRAM);
ahd_outw(ahd, PRGMCNT, 0);
for (i = 0; i < max_prog; i++) {
uint8_t ins_bytes[4];
ahd_insb(ahd, SEQRAM, ins_bytes, 4);
printk("0x%08x\n", ins_bytes[0] << 24
| ins_bytes[1] << 16
| ins_bytes[2] << 8
| ins_bytes[3]);
}
}
#endif
static void
ahd_loadseq(struct ahd_softc *ahd)
{ … }
static int
ahd_check_patch(struct ahd_softc *ahd, const struct patch **start_patch,
u_int start_instr, u_int *skip_addr)
{ … }
static u_int
ahd_resolve_seqaddr(struct ahd_softc *ahd, u_int address)
{ … }
static void
ahd_download_instr(struct ahd_softc *ahd, u_int instrptr, uint8_t *dconsts)
{ … }
static int
ahd_probe_stack_size(struct ahd_softc *ahd)
{ … }
int
ahd_print_register(const ahd_reg_parse_entry_t *table, u_int num_entries,
const char *name, u_int address, u_int value,
u_int *cur_column, u_int wrap_point)
{ … }
void
ahd_dump_card_state(struct ahd_softc *ahd)
{ … }
#if 0
void
ahd_dump_scbs(struct ahd_softc *ahd)
{
ahd_mode_state saved_modes;
u_int saved_scb_index;
int i;
saved_modes = ahd_save_modes(ahd);
ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
saved_scb_index = ahd_get_scbptr(ahd);
for (i = 0; i < AHD_SCB_MAX; i++) {
ahd_set_scbptr(ahd, i);
printk("%3d", i);
printk("(CTRL 0x%x ID 0x%x N 0x%x N2 0x%x SG 0x%x, RSG 0x%x)\n",
ahd_inb_scbram(ahd, SCB_CONTROL),
ahd_inb_scbram(ahd, SCB_SCSIID),
ahd_inw_scbram(ahd, SCB_NEXT),
ahd_inw_scbram(ahd, SCB_NEXT2),
ahd_inl_scbram(ahd, SCB_SGPTR),
ahd_inl_scbram(ahd, SCB_RESIDUAL_SGPTR));
}
printk("\n");
ahd_set_scbptr(ahd, saved_scb_index);
ahd_restore_modes(ahd, saved_modes);
}
#endif
int
ahd_read_seeprom(struct ahd_softc *ahd, uint16_t *buf,
u_int start_addr, u_int count, int bytestream)
{ … }
int
ahd_write_seeprom(struct ahd_softc *ahd, uint16_t *buf,
u_int start_addr, u_int count)
{ … }
static int
ahd_wait_seeprom(struct ahd_softc *ahd)
{ … }
static int
ahd_verify_vpd_cksum(struct vpd_config *vpd)
{ … }
int
ahd_verify_cksum(struct seeprom_config *sc)
{ … }
int
ahd_acquire_seeprom(struct ahd_softc *ahd)
{ … }
void
ahd_release_seeprom(struct ahd_softc *ahd)
{ … }
static int
ahd_wait_flexport(struct ahd_softc *ahd)
{ … }
int
ahd_write_flexport(struct ahd_softc *ahd, u_int addr, u_int value)
{ … }
int
ahd_read_flexport(struct ahd_softc *ahd, u_int addr, uint8_t *value)
{ … }
#ifdef AHD_TARGET_MODE
cam_status
ahd_find_tmode_devs(struct ahd_softc *ahd, struct cam_sim *sim, union ccb *ccb,
struct ahd_tmode_tstate **tstate,
struct ahd_tmode_lstate **lstate,
int notfound_failure)
{
if ((ahd->features & AHD_TARGETMODE) == 0)
return (CAM_REQ_INVALID);
if (ccb->ccb_h.target_id == CAM_TARGET_WILDCARD
&& ccb->ccb_h.target_lun == CAM_LUN_WILDCARD) {
*tstate = NULL;
*lstate = ahd->black_hole;
} else {
u_int max_id;
max_id = (ahd->features & AHD_WIDE) ? 16 : 8;
if (ccb->ccb_h.target_id >= max_id)
return (CAM_TID_INVALID);
if (ccb->ccb_h.target_lun >= AHD_NUM_LUNS)
return (CAM_LUN_INVALID);
*tstate = ahd->enabled_targets[ccb->ccb_h.target_id];
*lstate = NULL;
if (*tstate != NULL)
*lstate =
(*tstate)->enabled_luns[ccb->ccb_h.target_lun];
}
if (notfound_failure != 0 && *lstate == NULL)
return (CAM_PATH_INVALID);
return (CAM_REQ_CMP);
}
void
ahd_handle_en_lun(struct ahd_softc *ahd, struct cam_sim *sim, union ccb *ccb)
{
#if NOT_YET
struct ahd_tmode_tstate *tstate;
struct ahd_tmode_lstate *lstate;
struct ccb_en_lun *cel;
cam_status status;
u_int target;
u_int lun;
u_int target_mask;
u_long s;
char channel;
status = ahd_find_tmode_devs(ahd, sim, ccb, &tstate, &lstate,
FALSE);
if (status != CAM_REQ_CMP) {
ccb->ccb_h.status = status;
return;
}
if ((ahd->features & AHD_MULTIROLE) != 0) {
u_int our_id;
our_id = ahd->our_id;
if (ccb->ccb_h.target_id != our_id) {
if ((ahd->features & AHD_MULTI_TID) != 0
&& (ahd->flags & AHD_INITIATORROLE) != 0) {
status = CAM_TID_INVALID;
} else if ((ahd->flags & AHD_INITIATORROLE) != 0
|| ahd->enabled_luns > 0) {
status = CAM_TID_INVALID;
}
}
}
if (status != CAM_REQ_CMP) {
ccb->ccb_h.status = status;
return;
}
if ((ahd->flags & AHD_TARGETROLE) == 0
&& ccb->ccb_h.target_id != CAM_TARGET_WILDCARD) {
u_long s;
printk("Configuring Target Mode\n");
ahd_lock(ahd, &s);
if (LIST_FIRST(&ahd->pending_scbs) != NULL) {
ccb->ccb_h.status = CAM_BUSY;
ahd_unlock(ahd, &s);
return;
}
ahd->flags |= AHD_TARGETROLE;
if ((ahd->features & AHD_MULTIROLE) == 0)
ahd->flags &= ~AHD_INITIATORROLE;
ahd_pause(ahd);
ahd_loadseq(ahd);
ahd_restart(ahd);
ahd_unlock(ahd, &s);
}
cel = &ccb->cel;
target = ccb->ccb_h.target_id;
lun = ccb->ccb_h.target_lun;
channel = SIM_CHANNEL(ahd, sim);
target_mask = 0x01 << target;
if (channel == 'B')
target_mask <<= 8;
if (cel->enable != 0) {
u_int scsiseq1;
if (lstate != NULL) {
xpt_print_path(ccb->ccb_h.path);
printk("Lun already enabled\n");
ccb->ccb_h.status = CAM_LUN_ALRDY_ENA;
return;
}
if (cel->grp6_len != 0
|| cel->grp7_len != 0) {
ccb->ccb_h.status = CAM_REQ_INVALID;
printk("Non-zero Group Codes\n");
return;
}
if (target != CAM_TARGET_WILDCARD && tstate == NULL) {
tstate = ahd_alloc_tstate(ahd, target, channel);
if (tstate == NULL) {
xpt_print_path(ccb->ccb_h.path);
printk("Couldn't allocate tstate\n");
ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
return;
}
}
lstate = kzalloc(sizeof(*lstate), GFP_ATOMIC);
if (lstate == NULL) {
xpt_print_path(ccb->ccb_h.path);
printk("Couldn't allocate lstate\n");
ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
return;
}
status = xpt_create_path(&lstate->path, NULL,
xpt_path_path_id(ccb->ccb_h.path),
xpt_path_target_id(ccb->ccb_h.path),
xpt_path_lun_id(ccb->ccb_h.path));
if (status != CAM_REQ_CMP) {
kfree(lstate);
xpt_print_path(ccb->ccb_h.path);
printk("Couldn't allocate path\n");
ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
return;
}
SLIST_INIT(&lstate->accept_tios);
SLIST_INIT(&lstate->immed_notifies);
ahd_lock(ahd, &s);
ahd_pause(ahd);
if (target != CAM_TARGET_WILDCARD) {
tstate->enabled_luns[lun] = lstate;
ahd->enabled_luns++;
if ((ahd->features & AHD_MULTI_TID) != 0) {
u_int targid_mask;
targid_mask = ahd_inw(ahd, TARGID);
targid_mask |= target_mask;
ahd_outw(ahd, TARGID, targid_mask);
ahd_update_scsiid(ahd, targid_mask);
} else {
u_int our_id;
char channel;
channel = SIM_CHANNEL(ahd, sim);
our_id = SIM_SCSI_ID(ahd, sim);
if (target != our_id) {
u_int sblkctl;
char cur_channel;
int swap;
sblkctl = ahd_inb(ahd, SBLKCTL);
cur_channel = (sblkctl & SELBUSB)
? 'B' : 'A';
if ((ahd->features & AHD_TWIN) == 0)
cur_channel = 'A';
swap = cur_channel != channel;
ahd->our_id = target;
if (swap)
ahd_outb(ahd, SBLKCTL,
sblkctl ^ SELBUSB);
ahd_outb(ahd, SCSIID, target);
if (swap)
ahd_outb(ahd, SBLKCTL, sblkctl);
}
}
} else
ahd->black_hole = lstate;
if (ahd->black_hole != NULL && ahd->enabled_luns > 0) {
scsiseq1 = ahd_inb(ahd, SCSISEQ_TEMPLATE);
scsiseq1 |= ENSELI;
ahd_outb(ahd, SCSISEQ_TEMPLATE, scsiseq1);
scsiseq1 = ahd_inb(ahd, SCSISEQ1);
scsiseq1 |= ENSELI;
ahd_outb(ahd, SCSISEQ1, scsiseq1);
}
ahd_unpause(ahd);
ahd_unlock(ahd, &s);
ccb->ccb_h.status = CAM_REQ_CMP;
xpt_print_path(ccb->ccb_h.path);
printk("Lun now enabled for target mode\n");
} else {
struct scb *scb;
int i, empty;
if (lstate == NULL) {
ccb->ccb_h.status = CAM_LUN_INVALID;
return;
}
ahd_lock(ahd, &s);
ccb->ccb_h.status = CAM_REQ_CMP;
LIST_FOREACH(scb, &ahd->pending_scbs, pending_links) {
struct ccb_hdr *ccbh;
ccbh = &scb->io_ctx->ccb_h;
if (ccbh->func_code == XPT_CONT_TARGET_IO
&& !xpt_path_comp(ccbh->path, ccb->ccb_h.path)){
printk("CTIO pending\n");
ccb->ccb_h.status = CAM_REQ_INVALID;
ahd_unlock(ahd, &s);
return;
}
}
if (SLIST_FIRST(&lstate->accept_tios) != NULL) {
printk("ATIOs pending\n");
ccb->ccb_h.status = CAM_REQ_INVALID;
}
if (SLIST_FIRST(&lstate->immed_notifies) != NULL) {
printk("INOTs pending\n");
ccb->ccb_h.status = CAM_REQ_INVALID;
}
if (ccb->ccb_h.status != CAM_REQ_CMP) {
ahd_unlock(ahd, &s);
return;
}
xpt_print_path(ccb->ccb_h.path);
printk("Target mode disabled\n");
xpt_free_path(lstate->path);
kfree(lstate);
ahd_pause(ahd);
if (target != CAM_TARGET_WILDCARD) {
tstate->enabled_luns[lun] = NULL;
ahd->enabled_luns--;
for (empty = 1, i = 0; i < 8; i++)
if (tstate->enabled_luns[i] != NULL) {
empty = 0;
break;
}
if (empty) {
ahd_free_tstate(ahd, target, channel,
FALSE);
if (ahd->features & AHD_MULTI_TID) {
u_int targid_mask;
targid_mask = ahd_inw(ahd, TARGID);
targid_mask &= ~target_mask;
ahd_outw(ahd, TARGID, targid_mask);
ahd_update_scsiid(ahd, targid_mask);
}
}
} else {
ahd->black_hole = NULL;
empty = TRUE;
}
if (ahd->enabled_luns == 0) {
u_int scsiseq1;
scsiseq1 = ahd_inb(ahd, SCSISEQ_TEMPLATE);
scsiseq1 &= ~ENSELI;
ahd_outb(ahd, SCSISEQ_TEMPLATE, scsiseq1);
scsiseq1 = ahd_inb(ahd, SCSISEQ1);
scsiseq1 &= ~ENSELI;
ahd_outb(ahd, SCSISEQ1, scsiseq1);
if ((ahd->features & AHD_MULTIROLE) == 0) {
printk("Configuring Initiator Mode\n");
ahd->flags &= ~AHD_TARGETROLE;
ahd->flags |= AHD_INITIATORROLE;
ahd_pause(ahd);
ahd_loadseq(ahd);
ahd_restart(ahd);
}
}
ahd_unpause(ahd);
ahd_unlock(ahd, &s);
}
#endif
}
static void
ahd_update_scsiid(struct ahd_softc *ahd, u_int targid_mask)
{
#if NOT_YET
u_int scsiid_mask;
u_int scsiid;
if ((ahd->features & AHD_MULTI_TID) == 0)
panic("ahd_update_scsiid called on non-multitid unit\n");
if ((ahd->features & AHD_ULTRA2) != 0)
scsiid = ahd_inb(ahd, SCSIID_ULTRA2);
else
scsiid = ahd_inb(ahd, SCSIID);
scsiid_mask = 0x1 << (scsiid & OID);
if ((targid_mask & scsiid_mask) == 0) {
u_int our_id;
our_id = ffs(targid_mask);
if (our_id == 0)
our_id = ahd->our_id;
else
our_id--;
scsiid &= TID;
scsiid |= our_id;
}
if ((ahd->features & AHD_ULTRA2) != 0)
ahd_outb(ahd, SCSIID_ULTRA2, scsiid);
else
ahd_outb(ahd, SCSIID, scsiid);
#endif
}
static void
ahd_run_tqinfifo(struct ahd_softc *ahd, int paused)
{
struct target_cmd *cmd;
ahd_sync_tqinfifo(ahd, BUS_DMASYNC_POSTREAD);
while ((cmd = &ahd->targetcmds[ahd->tqinfifonext])->cmd_valid != 0) {
if (ahd_handle_target_cmd(ahd, cmd) != 0)
break;
cmd->cmd_valid = 0;
ahd_dmamap_sync(ahd, ahd->shared_data_dmat,
ahd->shared_data_map.dmamap,
ahd_targetcmd_offset(ahd, ahd->tqinfifonext),
sizeof(struct target_cmd),
BUS_DMASYNC_PREREAD);
ahd->tqinfifonext++;
if ((ahd->tqinfifonext & (HOST_TQINPOS - 1)) == 1) {
u_int hs_mailbox;
hs_mailbox = ahd_inb(ahd, HS_MAILBOX);
hs_mailbox &= ~HOST_TQINPOS;
hs_mailbox |= ahd->tqinfifonext & HOST_TQINPOS;
ahd_outb(ahd, HS_MAILBOX, hs_mailbox);
}
}
}
static int
ahd_handle_target_cmd(struct ahd_softc *ahd, struct target_cmd *cmd)
{
struct ahd_tmode_tstate *tstate;
struct ahd_tmode_lstate *lstate;
struct ccb_accept_tio *atio;
uint8_t *byte;
int initiator;
int target;
int lun;
initiator = SCSIID_TARGET(ahd, cmd->scsiid);
target = SCSIID_OUR_ID(cmd->scsiid);
lun = (cmd->identify & MSG_IDENTIFY_LUNMASK);
byte = cmd->bytes;
tstate = ahd->enabled_targets[target];
lstate = NULL;
if (tstate != NULL)
lstate = tstate->enabled_luns[lun];
if (lstate == NULL)
lstate = ahd->black_hole;
atio = (struct ccb_accept_tio*)SLIST_FIRST(&lstate->accept_tios);
if (atio == NULL) {
ahd->flags |= AHD_TQINFIFO_BLOCKED;
return (1);
} else
ahd->flags &= ~AHD_TQINFIFO_BLOCKED;
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_TQIN) != 0)
printk("Incoming command from %d for %d:%d%s\n",
initiator, target, lun,
lstate == ahd->black_hole ? "(Black Holed)" : "");
#endif
SLIST_REMOVE_HEAD(&lstate->accept_tios, sim_links.sle);
if (lstate == ahd->black_hole) {
atio->ccb_h.target_id = target;
atio->ccb_h.target_lun = lun;
}
atio->sense_len = 0;
atio->init_id = initiator;
if (byte[0] != 0xFF) {
atio->tag_action = *byte++;
atio->tag_id = *byte++;
atio->ccb_h.flags = CAM_TAG_ACTION_VALID;
} else {
atio->ccb_h.flags = 0;
}
byte++;
switch (*byte >> CMD_GROUP_CODE_SHIFT) {
case 0:
atio->cdb_len = 6;
break;
case 1:
case 2:
atio->cdb_len = 10;
break;
case 4:
atio->cdb_len = 16;
break;
case 5:
atio->cdb_len = 12;
break;
case 3:
default:
atio->cdb_len = 1;
printk("Reserved or VU command code type encountered\n");
break;
}
memcpy(atio->cdb_io.cdb_bytes, byte, atio->cdb_len);
atio->ccb_h.status |= CAM_CDB_RECVD;
if ((cmd->identify & MSG_IDENTIFY_DISCFLAG) == 0) {
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_TQIN) != 0)
printk("Received Immediate Command %d:%d:%d - %p\n",
initiator, target, lun, ahd->pending_device);
#endif
ahd->pending_device = lstate;
ahd_freeze_ccb((union ccb *)atio);
atio->ccb_h.flags |= CAM_DIS_DISCONNECT;
}
xpt_done((union ccb*)atio);
return (0);
}
#endif