aic79xx_osm.c revision 176355
1139749Simp/*- 2123579Sgibbs * Bus independent FreeBSD shim for the aic79xx based Adaptec SCSI controllers 397883Sgibbs * 4133122Sgibbs * Copyright (c) 1994-2002, 2004 Justin T. Gibbs. 5102684Sgibbs * Copyright (c) 2001-2002 Adaptec Inc. 697883Sgibbs * All rights reserved. 797883Sgibbs * 897883Sgibbs * Redistribution and use in source and binary forms, with or without 997883Sgibbs * modification, are permitted provided that the following conditions 1097883Sgibbs * are met: 1197883Sgibbs * 1. Redistributions of source code must retain the above copyright 1297883Sgibbs * notice, this list of conditions, and the following disclaimer, 1397883Sgibbs * without modification. 1497883Sgibbs * 2. The name of the author may not be used to endorse or promote products 1597883Sgibbs * derived from this software without specific prior written permission. 1697883Sgibbs * 1797883Sgibbs * Alternatively, this software may be distributed under the terms of the 1897883Sgibbs * GNU Public License ("GPL"). 1997883Sgibbs * 2097883Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2197883Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2297883Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2397883Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 2497883Sgibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2597883Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2697883Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2797883Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2897883Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2997883Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3097883Sgibbs * SUCH DAMAGE. 3197883Sgibbs * 32123579Sgibbs * $Id: //depot/aic7xxx/freebsd/dev/aic7xxx/aic79xx_osm.c#35 $ 3397883Sgibbs */ 3497883Sgibbs 35119418Sobrien#include <sys/cdefs.h> 36119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/aic7xxx/aic79xx_osm.c 176355 2008-02-17 06:14:59Z gibbs $"); 37119418Sobrien 3897883Sgibbs#include <dev/aic7xxx/aic79xx_osm.h> 3997883Sgibbs#include <dev/aic7xxx/aic79xx_inline.h> 4097883Sgibbs 41123579Sgibbs#include <sys/kthread.h> 42123579Sgibbs 4397883Sgibbs#include "opt_ddb.h" 4497883Sgibbs#ifdef DDB 4597883Sgibbs#include <ddb/ddb.h> 4697883Sgibbs#endif 4797883Sgibbs 4897883Sgibbs#ifndef AHD_TMODE_ENABLE 4997883Sgibbs#define AHD_TMODE_ENABLE 0 5097883Sgibbs#endif 5197883Sgibbs 52123579Sgibbs#include <dev/aic7xxx/aic_osm_lib.c> 53123579Sgibbs 5497883Sgibbs#define ccb_scb_ptr spriv_ptr0 5597883Sgibbs 56153072Sru#if 0 5797883Sgibbsstatic void ahd_dump_targcmd(struct target_cmd *cmd); 5897883Sgibbs#endif 5997883Sgibbsstatic int ahd_modevent(module_t mod, int type, void *data); 6097883Sgibbsstatic void ahd_action(struct cam_sim *sim, union ccb *ccb); 6197883Sgibbsstatic void ahd_set_tran_settings(struct ahd_softc *ahd, 6297883Sgibbs int our_id, char channel, 6397883Sgibbs struct ccb_trans_settings *cts); 6497883Sgibbsstatic void ahd_get_tran_settings(struct ahd_softc *ahd, 6597883Sgibbs int our_id, char channel, 6697883Sgibbs struct ccb_trans_settings *cts); 6797883Sgibbsstatic void ahd_async(void *callback_arg, uint32_t code, 6897883Sgibbs struct cam_path *path, void *arg); 6997883Sgibbsstatic void ahd_execute_scb(void *arg, bus_dma_segment_t *dm_segs, 7097883Sgibbs int nsegments, int error); 7197883Sgibbsstatic void ahd_poll(struct cam_sim *sim); 7297883Sgibbsstatic void ahd_setup_data(struct ahd_softc *ahd, struct cam_sim *sim, 7397883Sgibbs struct ccb_scsiio *csio, struct scb *scb); 7497883Sgibbsstatic void ahd_abort_ccb(struct ahd_softc *ahd, struct cam_sim *sim, 7597883Sgibbs union ccb *ccb); 7697883Sgibbsstatic int ahd_create_path(struct ahd_softc *ahd, 7797883Sgibbs char channel, u_int target, u_int lun, 7897883Sgibbs struct cam_path **path); 7997883Sgibbs 8097883Sgibbsstatic int 8197883Sgibbsahd_create_path(struct ahd_softc *ahd, char channel, u_int target, 8297883Sgibbs u_int lun, struct cam_path **path) 8397883Sgibbs{ 8497883Sgibbs path_id_t path_id; 8597883Sgibbs 86123579Sgibbs path_id = cam_sim_path(ahd->platform_data->sim); 8797883Sgibbs return (xpt_create_path(path, /*periph*/NULL, 8897883Sgibbs path_id, target, lun)); 8997883Sgibbs} 9097883Sgibbs 9197883Sgibbsint 9297883Sgibbsahd_map_int(struct ahd_softc *ahd) 9397883Sgibbs{ 9497883Sgibbs int error; 9597883Sgibbs 9697883Sgibbs /* Hook up our interrupt handler */ 9797883Sgibbs error = bus_setup_intr(ahd->dev_softc, ahd->platform_data->irq, 98168807Sscottl INTR_TYPE_CAM|INTR_MPSAFE, NULL, 99168807Sscottl ahd_platform_intr, ahd, &ahd->platform_data->ih); 10097883Sgibbs if (error != 0) 10197883Sgibbs device_printf(ahd->dev_softc, "bus_setup_intr() failed: %d\n", 10297883Sgibbs error); 10397883Sgibbs return (error); 10497883Sgibbs} 10597883Sgibbs 10697883Sgibbs/* 10797883Sgibbs * Attach all the sub-devices we can find 10897883Sgibbs */ 10997883Sgibbsint 11097883Sgibbsahd_attach(struct ahd_softc *ahd) 11197883Sgibbs{ 11297883Sgibbs char ahd_info[256]; 11397883Sgibbs struct ccb_setasync csa; 11497883Sgibbs struct cam_devq *devq; 11597883Sgibbs struct cam_sim *sim; 11697883Sgibbs struct cam_path *path; 11797883Sgibbs int count; 11897883Sgibbs 11997883Sgibbs count = 0; 120123579Sgibbs devq = NULL; 12197883Sgibbs sim = NULL; 12297883Sgibbs 123123579Sgibbs /* 124123579Sgibbs * Create a thread to perform all recovery. 125123579Sgibbs */ 126123579Sgibbs if (ahd_spawn_recovery_thread(ahd) != 0) 127123579Sgibbs goto fail; 128123579Sgibbs 12997883Sgibbs ahd_controller_info(ahd, ahd_info); 13097883Sgibbs printf("%s\n", ahd_info); 131168807Sscottl ahd_lock(ahd); 13297883Sgibbs 13397883Sgibbs /* 13497883Sgibbs * Create the device queue for our SIM(s). 13597883Sgibbs */ 13697883Sgibbs devq = cam_simq_alloc(AHD_MAX_QUEUE); 13797883Sgibbs if (devq == NULL) 13897883Sgibbs goto fail; 13997883Sgibbs 14097883Sgibbs /* 14197883Sgibbs * Construct our SIM entry 14297883Sgibbs */ 14397883Sgibbs sim = cam_sim_alloc(ahd_action, ahd_poll, "ahd", ahd, 14497883Sgibbs device_get_unit(ahd->dev_softc), 145168807Sscottl &ahd->platform_data->mtx, 1, /*XXX*/256, devq); 14697883Sgibbs if (sim == NULL) { 14797883Sgibbs cam_simq_free(devq); 14897883Sgibbs goto fail; 14997883Sgibbs } 15097883Sgibbs 151170872Sscottl if (xpt_bus_register(sim, ahd->dev_softc, /*bus_id*/0) != CAM_SUCCESS) { 15297883Sgibbs cam_sim_free(sim, /*free_devq*/TRUE); 15397883Sgibbs sim = NULL; 15497883Sgibbs goto fail; 15597883Sgibbs } 15697883Sgibbs 15797883Sgibbs if (xpt_create_path(&path, /*periph*/NULL, 15897883Sgibbs cam_sim_path(sim), CAM_TARGET_WILDCARD, 15997883Sgibbs CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 16097883Sgibbs xpt_bus_deregister(cam_sim_path(sim)); 16197883Sgibbs cam_sim_free(sim, /*free_devq*/TRUE); 16297883Sgibbs sim = NULL; 16397883Sgibbs goto fail; 16497883Sgibbs } 16597883Sgibbs 16697883Sgibbs xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5); 16797883Sgibbs csa.ccb_h.func_code = XPT_SASYNC_CB; 16897883Sgibbs csa.event_enable = AC_LOST_DEVICE; 16997883Sgibbs csa.callback = ahd_async; 17097883Sgibbs csa.callback_arg = sim; 17197883Sgibbs xpt_action((union ccb *)&csa); 17297883Sgibbs count++; 17397883Sgibbs 17497883Sgibbsfail: 17597883Sgibbs ahd->platform_data->sim = sim; 17697883Sgibbs ahd->platform_data->path = path; 177168807Sscottl ahd_unlock(ahd); 178102684Sgibbs if (count != 0) { 17997883Sgibbs /* We have to wait until after any system dumps... */ 18097883Sgibbs ahd->platform_data->eh = 18197883Sgibbs EVENTHANDLER_REGISTER(shutdown_final, ahd_shutdown, 18297883Sgibbs ahd, SHUTDOWN_PRI_DEFAULT); 183102684Sgibbs ahd_intr_enable(ahd, TRUE); 184102684Sgibbs } 18597883Sgibbs 186102684Sgibbs 18797883Sgibbs return (count); 18897883Sgibbs} 18997883Sgibbs 19097883Sgibbs/* 19197883Sgibbs * Catch an interrupt from the adapter 19297883Sgibbs */ 19397883Sgibbsvoid 19497883Sgibbsahd_platform_intr(void *arg) 19597883Sgibbs{ 19697883Sgibbs struct ahd_softc *ahd; 19797883Sgibbs 19897883Sgibbs ahd = (struct ahd_softc *)arg; 199168807Sscottl ahd_lock(ahd); 20097883Sgibbs ahd_intr(ahd); 201168807Sscottl ahd_unlock(ahd); 20297883Sgibbs} 20397883Sgibbs 20497883Sgibbs/* 20597883Sgibbs * We have an scb which has been processed by the 20697883Sgibbs * adaptor, now we look to see how the operation 20797883Sgibbs * went. 20897883Sgibbs */ 20997883Sgibbsvoid 21097883Sgibbsahd_done(struct ahd_softc *ahd, struct scb *scb) 21197883Sgibbs{ 21297883Sgibbs union ccb *ccb; 21397883Sgibbs 21497883Sgibbs CAM_DEBUG(scb->io_ctx->ccb_h.path, CAM_DEBUG_TRACE, 21597883Sgibbs ("ahd_done - scb %d\n", SCB_GET_TAG(scb))); 21697883Sgibbs 21797883Sgibbs ccb = scb->io_ctx; 21897883Sgibbs LIST_REMOVE(scb, pending_links); 219123579Sgibbs if ((scb->flags & SCB_TIMEDOUT) != 0) 220123579Sgibbs LIST_REMOVE(scb, timedout_links); 22197883Sgibbs 222168807Sscottl callout_stop(&scb->io_timer); 22397883Sgibbs 22497883Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) { 225115343Sscottl bus_dmasync_op_t op; 22697883Sgibbs 22797883Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) 22897883Sgibbs op = BUS_DMASYNC_POSTREAD; 22997883Sgibbs else 23097883Sgibbs op = BUS_DMASYNC_POSTWRITE; 23197883Sgibbs bus_dmamap_sync(ahd->buffer_dmat, scb->dmamap, op); 23297883Sgibbs bus_dmamap_unload(ahd->buffer_dmat, scb->dmamap); 23397883Sgibbs } 23497883Sgibbs 23597883Sgibbs#ifdef AHD_TARGET_MODE 23697883Sgibbs if (ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) { 23797883Sgibbs struct cam_path *ccb_path; 23897883Sgibbs 23997883Sgibbs /* 24097883Sgibbs * If we have finally disconnected, clean up our 24197883Sgibbs * pending device state. 24297883Sgibbs * XXX - There may be error states that cause where 24397883Sgibbs * we will remain connected. 24497883Sgibbs */ 24597883Sgibbs ccb_path = ccb->ccb_h.path; 24697883Sgibbs if (ahd->pending_device != NULL 24797883Sgibbs && xpt_path_comp(ahd->pending_device->path, ccb_path) == 0) { 24897883Sgibbs 24997883Sgibbs if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) { 25097883Sgibbs ahd->pending_device = NULL; 25197883Sgibbs } else { 25297883Sgibbs xpt_print_path(ccb->ccb_h.path); 25397883Sgibbs printf("Still disconnected\n"); 25497883Sgibbs ahd_freeze_ccb(ccb); 25597883Sgibbs } 25697883Sgibbs } 25797883Sgibbs 258123579Sgibbs if (aic_get_transaction_status(scb) == CAM_REQ_INPROG) 25997883Sgibbs ccb->ccb_h.status |= CAM_REQ_CMP; 26097883Sgibbs ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 26197883Sgibbs ahd_free_scb(ahd, scb); 26297883Sgibbs xpt_done(ccb); 26397883Sgibbs return; 26497883Sgibbs } 26597883Sgibbs#endif 26697883Sgibbs 26797883Sgibbs if ((scb->flags & SCB_RECOVERY_SCB) != 0) { 26897883Sgibbs struct scb *list_scb; 26997883Sgibbs 270133911Sgibbs ahd->scb_data.recovery_scbs--; 27197883Sgibbs 272123579Sgibbs if (aic_get_transaction_status(scb) == CAM_BDR_SENT 273123579Sgibbs || aic_get_transaction_status(scb) == CAM_REQ_ABORTED) 274123579Sgibbs aic_set_transaction_status(scb, CAM_CMD_TIMEOUT); 275123579Sgibbs 276133911Sgibbs if (ahd->scb_data.recovery_scbs == 0) { 277133911Sgibbs /* 278133911Sgibbs * All recovery actions have completed successfully, 279133911Sgibbs * so reinstate the timeouts for all other pending 280133911Sgibbs * commands. 281133911Sgibbs */ 282133911Sgibbs LIST_FOREACH(list_scb, 283133911Sgibbs &ahd->pending_scbs, pending_links) { 284133911Sgibbs 285150450Sgibbs aic_scb_timer_reset(list_scb, 286150450Sgibbs aic_get_timeout(scb)); 287133911Sgibbs } 288133911Sgibbs 289133911Sgibbs ahd_print_path(ahd, scb); 290133911Sgibbs printf("no longer in timeout, status = %x\n", 291133911Sgibbs ccb->ccb_h.status); 292133911Sgibbs } 29397883Sgibbs } 29497883Sgibbs 29597883Sgibbs /* Don't clobber any existing error state */ 296123579Sgibbs if (aic_get_transaction_status(scb) == CAM_REQ_INPROG) { 29797883Sgibbs ccb->ccb_h.status |= CAM_REQ_CMP; 29897883Sgibbs } else if ((scb->flags & SCB_SENSE) != 0) { 29997883Sgibbs /* 30097883Sgibbs * We performed autosense retrieval. 30197883Sgibbs * 30297883Sgibbs * Zero any sense not transferred by the 30397883Sgibbs * device. The SCSI spec mandates that any 30497883Sgibbs * untransfered data should be assumed to be 30597883Sgibbs * zero. Complete the 'bounce' of sense information 30697883Sgibbs * through buffers accessible via bus-space by 30797883Sgibbs * copying it into the clients csio. 30897883Sgibbs */ 30997883Sgibbs memset(&ccb->csio.sense_data, 0, sizeof(ccb->csio.sense_data)); 31097883Sgibbs memcpy(&ccb->csio.sense_data, 31197883Sgibbs ahd_get_sense_buf(ahd, scb), 31297883Sgibbs/* XXX What size do we want to use??? */ 31397883Sgibbs sizeof(ccb->csio.sense_data) 31497883Sgibbs - ccb->csio.sense_resid); 31597883Sgibbs scb->io_ctx->ccb_h.status |= CAM_AUTOSNS_VALID; 31697883Sgibbs } else if ((scb->flags & SCB_PKT_SENSE) != 0) { 31797883Sgibbs struct scsi_status_iu_header *siu; 31897883Sgibbs u_int sense_len; 31997883Sgibbs int i; 32097883Sgibbs 32197883Sgibbs /* 32297883Sgibbs * Copy only the sense data into the provided buffer. 32397883Sgibbs */ 32497883Sgibbs siu = (struct scsi_status_iu_header *)scb->sense_data; 32597883Sgibbs sense_len = MIN(scsi_4btoul(siu->sense_length), 32697883Sgibbs sizeof(ccb->csio.sense_data)); 32797883Sgibbs memset(&ccb->csio.sense_data, 0, sizeof(ccb->csio.sense_data)); 32897883Sgibbs memcpy(&ccb->csio.sense_data, 32997883Sgibbs ahd_get_sense_buf(ahd, scb) + SIU_SENSE_OFFSET(siu), 33097883Sgibbs sense_len); 33197883Sgibbs printf("Copied %d bytes of sense data offset %d:", sense_len, 33297883Sgibbs SIU_SENSE_OFFSET(siu)); 33397883Sgibbs for (i = 0; i < sense_len; i++) 33497883Sgibbs printf(" 0x%x", ((uint8_t *)&ccb->csio.sense_data)[i]); 33597883Sgibbs printf("\n"); 33697883Sgibbs scb->io_ctx->ccb_h.status |= CAM_AUTOSNS_VALID; 33797883Sgibbs } 33897883Sgibbs ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 33997883Sgibbs ahd_free_scb(ahd, scb); 34097883Sgibbs xpt_done(ccb); 34197883Sgibbs} 34297883Sgibbs 34397883Sgibbsstatic void 34497883Sgibbsahd_action(struct cam_sim *sim, union ccb *ccb) 34597883Sgibbs{ 34697883Sgibbs struct ahd_softc *ahd; 34797883Sgibbs#ifdef AHD_TARGET_MODE 34897883Sgibbs struct ahd_tmode_lstate *lstate; 34997883Sgibbs#endif 35097883Sgibbs u_int target_id; 35197883Sgibbs u_int our_id; 35297883Sgibbs 35397883Sgibbs CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("ahd_action\n")); 35497883Sgibbs 35597883Sgibbs ahd = (struct ahd_softc *)cam_sim_softc(sim); 35697883Sgibbs 35797883Sgibbs target_id = ccb->ccb_h.target_id; 35897883Sgibbs our_id = SIM_SCSI_ID(ahd, sim); 35997883Sgibbs 36097883Sgibbs switch (ccb->ccb_h.func_code) { 36197883Sgibbs /* Common cases first */ 36297883Sgibbs#ifdef AHD_TARGET_MODE 36397883Sgibbs case XPT_ACCEPT_TARGET_IO: /* Accept Host Target Mode CDB */ 36497883Sgibbs case XPT_CONT_TARGET_IO:/* Continue Host Target I/O Connection*/ 36597883Sgibbs { 36697883Sgibbs struct ahd_tmode_tstate *tstate; 36797883Sgibbs cam_status status; 36897883Sgibbs 36997883Sgibbs status = ahd_find_tmode_devs(ahd, sim, ccb, &tstate, 37097883Sgibbs &lstate, TRUE); 37197883Sgibbs 37297883Sgibbs if (status != CAM_REQ_CMP) { 37397883Sgibbs if (ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) { 37497883Sgibbs /* Response from the black hole device */ 37597883Sgibbs tstate = NULL; 37697883Sgibbs lstate = ahd->black_hole; 37797883Sgibbs } else { 37897883Sgibbs ccb->ccb_h.status = status; 37997883Sgibbs xpt_done(ccb); 38097883Sgibbs break; 38197883Sgibbs } 38297883Sgibbs } 38397883Sgibbs if (ccb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) { 38497883Sgibbs 38597883Sgibbs SLIST_INSERT_HEAD(&lstate->accept_tios, &ccb->ccb_h, 38697883Sgibbs sim_links.sle); 38797883Sgibbs ccb->ccb_h.status = CAM_REQ_INPROG; 38897883Sgibbs if ((ahd->flags & AHD_TQINFIFO_BLOCKED) != 0) 38997883Sgibbs ahd_run_tqinfifo(ahd, /*paused*/FALSE); 39097883Sgibbs break; 39197883Sgibbs } 39297883Sgibbs 39397883Sgibbs /* 39497883Sgibbs * The target_id represents the target we attempt to 39597883Sgibbs * select. In target mode, this is the initiator of 39697883Sgibbs * the original command. 39797883Sgibbs */ 39897883Sgibbs our_id = target_id; 39997883Sgibbs target_id = ccb->csio.init_id; 40097883Sgibbs /* FALLTHROUGH */ 40197883Sgibbs } 40297883Sgibbs#endif 40397883Sgibbs case XPT_SCSI_IO: /* Execute the requested I/O operation */ 40497883Sgibbs case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */ 40597883Sgibbs { 40697883Sgibbs struct scb *scb; 40797883Sgibbs struct hardware_scb *hscb; 408102684Sgibbs struct ahd_initiator_tinfo *tinfo; 409102684Sgibbs struct ahd_tmode_tstate *tstate; 410102684Sgibbs u_int col_idx; 41197883Sgibbs 41297883Sgibbs if ((ahd->flags & AHD_INITIATORROLE) == 0 41397883Sgibbs && (ccb->ccb_h.func_code == XPT_SCSI_IO 41497883Sgibbs || ccb->ccb_h.func_code == XPT_RESET_DEV)) { 41597883Sgibbs ccb->ccb_h.status = CAM_PROVIDE_FAIL; 41697883Sgibbs xpt_done(ccb); 41797883Sgibbs return; 41897883Sgibbs } 41997883Sgibbs 42097883Sgibbs /* 42197883Sgibbs * get an scb to use. 42297883Sgibbs */ 423102684Sgibbs tinfo = ahd_fetch_transinfo(ahd, 'A', our_id, 424102684Sgibbs target_id, &tstate); 425102684Sgibbs if ((ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) == 0 426102684Sgibbs || (tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ) != 0 427102684Sgibbs || ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) { 428102684Sgibbs col_idx = AHD_NEVER_COL_IDX; 429102684Sgibbs } else { 430102684Sgibbs col_idx = AHD_BUILD_COL_IDX(target_id, 431102684Sgibbs ccb->ccb_h.target_lun); 432102684Sgibbs } 433102684Sgibbs if ((scb = ahd_get_scb(ahd, col_idx)) == NULL) { 43497883Sgibbs 43597883Sgibbs xpt_freeze_simq(sim, /*count*/1); 43697883Sgibbs ahd->flags |= AHD_RESOURCE_SHORTAGE; 43797883Sgibbs ccb->ccb_h.status = CAM_REQUEUE_REQ; 43897883Sgibbs xpt_done(ccb); 43997883Sgibbs return; 44097883Sgibbs } 44197883Sgibbs 44297883Sgibbs hscb = scb->hscb; 44397883Sgibbs 44497883Sgibbs CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_SUBTRACE, 44597883Sgibbs ("start scb(%p)\n", scb)); 44697883Sgibbs scb->io_ctx = ccb; 44797883Sgibbs /* 44897883Sgibbs * So we can find the SCB when an abort is requested 44997883Sgibbs */ 45097883Sgibbs ccb->ccb_h.ccb_scb_ptr = scb; 45197883Sgibbs 45297883Sgibbs /* 45397883Sgibbs * Put all the arguments for the xfer in the scb 45497883Sgibbs */ 45597883Sgibbs hscb->control = 0; 45697883Sgibbs hscb->scsiid = BUILD_SCSIID(ahd, sim, target_id, our_id); 45797883Sgibbs hscb->lun = ccb->ccb_h.target_lun; 45897883Sgibbs if (ccb->ccb_h.func_code == XPT_RESET_DEV) { 45997883Sgibbs hscb->cdb_len = 0; 46097883Sgibbs scb->flags |= SCB_DEVICE_RESET; 46197883Sgibbs hscb->control |= MK_MESSAGE; 462109588Sgibbs hscb->task_management = SIU_TASKMGMT_LUN_RESET; 46397883Sgibbs ahd_execute_scb(scb, NULL, 0, 0); 46497883Sgibbs } else { 46597883Sgibbs#ifdef AHD_TARGET_MODE 46697883Sgibbs if (ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) { 46797883Sgibbs struct target_data *tdata; 46897883Sgibbs 46997883Sgibbs tdata = &hscb->shared_data.tdata; 47097883Sgibbs if (ahd->pending_device == lstate) 47197883Sgibbs scb->flags |= SCB_TARGET_IMMEDIATE; 47297883Sgibbs hscb->control |= TARGET_SCB; 47397883Sgibbs tdata->target_phases = 0; 47497883Sgibbs if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) { 47597883Sgibbs tdata->target_phases |= SPHASE_PENDING; 47697883Sgibbs tdata->scsi_status = 47797883Sgibbs ccb->csio.scsi_status; 47897883Sgibbs } 47997883Sgibbs if (ccb->ccb_h.flags & CAM_DIS_DISCONNECT) 48097883Sgibbs tdata->target_phases |= NO_DISCONNECT; 48197883Sgibbs 48297883Sgibbs tdata->initiator_tag = 48397883Sgibbs ahd_htole16(ccb->csio.tag_id); 48497883Sgibbs } 48597883Sgibbs#endif 486109588Sgibbs hscb->task_management = 0; 48797883Sgibbs if (ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) 48897883Sgibbs hscb->control |= ccb->csio.tag_action; 48997883Sgibbs 49097883Sgibbs ahd_setup_data(ahd, sim, &ccb->csio, scb); 49197883Sgibbs } 49297883Sgibbs break; 49397883Sgibbs } 49497883Sgibbs#ifdef AHD_TARGET_MODE 49597883Sgibbs case XPT_NOTIFY_ACK: 49697883Sgibbs case XPT_IMMED_NOTIFY: 49797883Sgibbs { 49897883Sgibbs struct ahd_tmode_tstate *tstate; 49997883Sgibbs struct ahd_tmode_lstate *lstate; 50097883Sgibbs cam_status status; 50197883Sgibbs 50297883Sgibbs status = ahd_find_tmode_devs(ahd, sim, ccb, &tstate, 50397883Sgibbs &lstate, TRUE); 50497883Sgibbs 50597883Sgibbs if (status != CAM_REQ_CMP) { 50697883Sgibbs ccb->ccb_h.status = status; 50797883Sgibbs xpt_done(ccb); 50897883Sgibbs break; 50997883Sgibbs } 51097883Sgibbs SLIST_INSERT_HEAD(&lstate->immed_notifies, &ccb->ccb_h, 51197883Sgibbs sim_links.sle); 51297883Sgibbs ccb->ccb_h.status = CAM_REQ_INPROG; 51397883Sgibbs ahd_send_lstate_events(ahd, lstate); 51497883Sgibbs break; 51597883Sgibbs } 51697883Sgibbs case XPT_EN_LUN: /* Enable LUN as a target */ 51797883Sgibbs ahd_handle_en_lun(ahd, sim, ccb); 51897883Sgibbs xpt_done(ccb); 51997883Sgibbs break; 52097883Sgibbs#endif 52197883Sgibbs case XPT_ABORT: /* Abort the specified CCB */ 52297883Sgibbs { 52397883Sgibbs ahd_abort_ccb(ahd, sim, ccb); 52497883Sgibbs break; 52597883Sgibbs } 52697883Sgibbs case XPT_SET_TRAN_SETTINGS: 52797883Sgibbs { 52897883Sgibbs ahd_set_tran_settings(ahd, SIM_SCSI_ID(ahd, sim), 52997883Sgibbs SIM_CHANNEL(ahd, sim), &ccb->cts); 53097883Sgibbs xpt_done(ccb); 53197883Sgibbs break; 53297883Sgibbs } 53397883Sgibbs case XPT_GET_TRAN_SETTINGS: 53497883Sgibbs /* Get default/user set transfer settings for the target */ 53597883Sgibbs { 53697883Sgibbs ahd_get_tran_settings(ahd, SIM_SCSI_ID(ahd, sim), 53797883Sgibbs SIM_CHANNEL(ahd, sim), &ccb->cts); 53897883Sgibbs xpt_done(ccb); 53997883Sgibbs break; 54097883Sgibbs } 54197883Sgibbs case XPT_CALC_GEOMETRY: 54297883Sgibbs { 543123579Sgibbs aic_calc_geometry(&ccb->ccg, ahd->flags & AHD_EXTENDED_TRANS_A); 54497883Sgibbs xpt_done(ccb); 54597883Sgibbs break; 54697883Sgibbs } 54797883Sgibbs case XPT_RESET_BUS: /* Reset the specified SCSI bus */ 54897883Sgibbs { 54997883Sgibbs int found; 55097883Sgibbs 55197883Sgibbs found = ahd_reset_channel(ahd, SIM_CHANNEL(ahd, sim), 55297883Sgibbs /*initiate reset*/TRUE); 55397883Sgibbs if (bootverbose) { 55497883Sgibbs xpt_print_path(SIM_PATH(ahd, sim)); 55597883Sgibbs printf("SCSI bus reset delivered. " 55697883Sgibbs "%d SCBs aborted.\n", found); 55797883Sgibbs } 55897883Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 55997883Sgibbs xpt_done(ccb); 56097883Sgibbs break; 56197883Sgibbs } 56297883Sgibbs case XPT_TERM_IO: /* Terminate the I/O process */ 56397883Sgibbs /* XXX Implement */ 56497883Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 56597883Sgibbs xpt_done(ccb); 56697883Sgibbs break; 56797883Sgibbs case XPT_PATH_INQ: /* Path routing inquiry */ 56897883Sgibbs { 56997883Sgibbs struct ccb_pathinq *cpi = &ccb->cpi; 57097883Sgibbs 57197883Sgibbs cpi->version_num = 1; /* XXX??? */ 57297883Sgibbs cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE; 57397883Sgibbs if ((ahd->features & AHD_WIDE) != 0) 57497883Sgibbs cpi->hba_inquiry |= PI_WIDE_16; 57597883Sgibbs if ((ahd->features & AHD_TARGETMODE) != 0) { 57697883Sgibbs cpi->target_sprt = PIT_PROCESSOR 57797883Sgibbs | PIT_DISCONNECT 57897883Sgibbs | PIT_TERM_IO; 57997883Sgibbs } else { 58097883Sgibbs cpi->target_sprt = 0; 58197883Sgibbs } 58297883Sgibbs cpi->hba_misc = 0; 58397883Sgibbs cpi->hba_eng_cnt = 0; 58497883Sgibbs cpi->max_target = (ahd->features & AHD_WIDE) ? 15 : 7; 585141978Sgibbs cpi->max_lun = AHD_NUM_LUNS_NONPKT - 1; 58697883Sgibbs cpi->initiator_id = ahd->our_id; 58797883Sgibbs if ((ahd->flags & AHD_RESET_BUS_A) == 0) { 58897883Sgibbs cpi->hba_misc |= PIM_NOBUSRESET; 58997883Sgibbs } 59097883Sgibbs cpi->bus_id = cam_sim_bus(sim); 59197883Sgibbs cpi->base_transfer_speed = 3300; 59297883Sgibbs strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 59397883Sgibbs strncpy(cpi->hba_vid, "Adaptec", HBA_IDLEN); 59497883Sgibbs strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 59597883Sgibbs cpi->unit_number = cam_sim_unit(sim); 59697883Sgibbs cpi->protocol = PROTO_SCSI; 59797883Sgibbs cpi->protocol_version = SCSI_REV_2; 59897883Sgibbs cpi->transport = XPORT_SPI; 59997883Sgibbs cpi->transport_version = 2; 60097883Sgibbs cpi->transport_version = 4; 601176355Sgibbs cpi->xport_specific.spi.ppr_options = SID_SPI_CLOCK_DT_ST 602176355Sgibbs | SID_SPI_IUS 603176355Sgibbs | SID_SPI_QAS; 60497883Sgibbs cpi->ccb_h.status = CAM_REQ_CMP; 60597883Sgibbs xpt_done(ccb); 60697883Sgibbs break; 60797883Sgibbs } 60897883Sgibbs default: 60997883Sgibbs ccb->ccb_h.status = CAM_PROVIDE_FAIL; 61097883Sgibbs xpt_done(ccb); 61197883Sgibbs break; 61297883Sgibbs } 61397883Sgibbs} 61497883Sgibbs 61597883Sgibbs 61697883Sgibbsstatic void 61797883Sgibbsahd_set_tran_settings(struct ahd_softc *ahd, int our_id, char channel, 61897883Sgibbs struct ccb_trans_settings *cts) 61997883Sgibbs{ 62097883Sgibbs struct ahd_devinfo devinfo; 62197883Sgibbs struct ccb_trans_settings_scsi *scsi; 62297883Sgibbs struct ccb_trans_settings_spi *spi; 62397883Sgibbs struct ahd_initiator_tinfo *tinfo; 62497883Sgibbs struct ahd_tmode_tstate *tstate; 62597883Sgibbs uint16_t *discenable; 62697883Sgibbs uint16_t *tagenable; 62797883Sgibbs u_int update_type; 62897883Sgibbs 62997883Sgibbs scsi = &cts->proto_specific.scsi; 63097883Sgibbs spi = &cts->xport_specific.spi; 63197883Sgibbs ahd_compile_devinfo(&devinfo, SIM_SCSI_ID(ahd, sim), 63297883Sgibbs cts->ccb_h.target_id, 63397883Sgibbs cts->ccb_h.target_lun, 63497883Sgibbs SIM_CHANNEL(ahd, sim), 63597883Sgibbs ROLE_UNKNOWN); 63697883Sgibbs tinfo = ahd_fetch_transinfo(ahd, devinfo.channel, 63797883Sgibbs devinfo.our_scsiid, 63897883Sgibbs devinfo.target, &tstate); 63997883Sgibbs update_type = 0; 64097883Sgibbs if (cts->type == CTS_TYPE_CURRENT_SETTINGS) { 64197883Sgibbs update_type |= AHD_TRANS_GOAL; 64297883Sgibbs discenable = &tstate->discenable; 64397883Sgibbs tagenable = &tstate->tagenable; 64497883Sgibbs tinfo->curr.protocol_version = cts->protocol_version; 64597883Sgibbs tinfo->curr.transport_version = cts->transport_version; 64697883Sgibbs tinfo->goal.protocol_version = cts->protocol_version; 64797883Sgibbs tinfo->goal.transport_version = cts->transport_version; 64897883Sgibbs } else if (cts->type == CTS_TYPE_USER_SETTINGS) { 64997883Sgibbs update_type |= AHD_TRANS_USER; 65097883Sgibbs discenable = &ahd->user_discenable; 65197883Sgibbs tagenable = &ahd->user_tagenable; 65297883Sgibbs tinfo->user.protocol_version = cts->protocol_version; 65397883Sgibbs tinfo->user.transport_version = cts->transport_version; 65497883Sgibbs } else { 65597883Sgibbs cts->ccb_h.status = CAM_REQ_INVALID; 65697883Sgibbs return; 65797883Sgibbs } 65897883Sgibbs 65997883Sgibbs if ((spi->valid & CTS_SPI_VALID_DISC) != 0) { 66097883Sgibbs if ((spi->flags & CTS_SPI_FLAGS_DISC_ENB) != 0) 66197883Sgibbs *discenable |= devinfo.target_mask; 66297883Sgibbs else 66397883Sgibbs *discenable &= ~devinfo.target_mask; 66497883Sgibbs } 66597883Sgibbs 66697883Sgibbs if ((scsi->valid & CTS_SCSI_VALID_TQ) != 0) { 66797883Sgibbs if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0) 66897883Sgibbs *tagenable |= devinfo.target_mask; 66997883Sgibbs else 67097883Sgibbs *tagenable &= ~devinfo.target_mask; 67197883Sgibbs } 67297883Sgibbs 67397883Sgibbs if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) { 67497883Sgibbs ahd_validate_width(ahd, /*tinfo limit*/NULL, 67597883Sgibbs &spi->bus_width, ROLE_UNKNOWN); 67697883Sgibbs ahd_set_width(ahd, &devinfo, spi->bus_width, 67797883Sgibbs update_type, /*paused*/FALSE); 67897883Sgibbs } 67997883Sgibbs 68097883Sgibbs if ((spi->valid & CTS_SPI_VALID_PPR_OPTIONS) == 0) { 68197883Sgibbs if (update_type == AHD_TRANS_USER) 68297883Sgibbs spi->ppr_options = tinfo->user.ppr_options; 68397883Sgibbs else 68497883Sgibbs spi->ppr_options = tinfo->goal.ppr_options; 68597883Sgibbs } 68697883Sgibbs 68797883Sgibbs if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) == 0) { 68897883Sgibbs if (update_type == AHD_TRANS_USER) 68997883Sgibbs spi->sync_offset = tinfo->user.offset; 69097883Sgibbs else 69197883Sgibbs spi->sync_offset = tinfo->goal.offset; 69297883Sgibbs } 69397883Sgibbs 69497883Sgibbs if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) == 0) { 69597883Sgibbs if (update_type == AHD_TRANS_USER) 69697883Sgibbs spi->sync_period = tinfo->user.period; 69797883Sgibbs else 69897883Sgibbs spi->sync_period = tinfo->goal.period; 69997883Sgibbs } 70097883Sgibbs 70197883Sgibbs if (((spi->valid & CTS_SPI_VALID_SYNC_RATE) != 0) 70297883Sgibbs || ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0)) { 70397883Sgibbs u_int maxsync; 70497883Sgibbs 70597883Sgibbs maxsync = AHD_SYNCRATE_MAX; 70697883Sgibbs 70797883Sgibbs if (spi->bus_width != MSG_EXT_WDTR_BUS_16_BIT) 70897883Sgibbs spi->ppr_options &= ~MSG_EXT_PPR_DT_REQ; 70997883Sgibbs 71097883Sgibbs if ((*discenable & devinfo.target_mask) == 0) 71197883Sgibbs spi->ppr_options &= ~MSG_EXT_PPR_IU_REQ; 71297883Sgibbs 71397883Sgibbs ahd_find_syncrate(ahd, &spi->sync_period, 71497883Sgibbs &spi->ppr_options, maxsync); 71597883Sgibbs ahd_validate_offset(ahd, /*tinfo limit*/NULL, 71697883Sgibbs spi->sync_period, &spi->sync_offset, 71797883Sgibbs spi->bus_width, ROLE_UNKNOWN); 71897883Sgibbs 71997883Sgibbs /* We use a period of 0 to represent async */ 72097883Sgibbs if (spi->sync_offset == 0) { 72197883Sgibbs spi->sync_period = 0; 72297883Sgibbs spi->ppr_options = 0; 72397883Sgibbs } 72497883Sgibbs 72597883Sgibbs ahd_set_syncrate(ahd, &devinfo, spi->sync_period, 72697883Sgibbs spi->sync_offset, spi->ppr_options, 72797883Sgibbs update_type, /*paused*/FALSE); 72897883Sgibbs } 72997883Sgibbs cts->ccb_h.status = CAM_REQ_CMP; 73097883Sgibbs} 73197883Sgibbs 73297883Sgibbsstatic void 73397883Sgibbsahd_get_tran_settings(struct ahd_softc *ahd, int our_id, char channel, 73497883Sgibbs struct ccb_trans_settings *cts) 73597883Sgibbs{ 73697883Sgibbs struct ahd_devinfo devinfo; 73797883Sgibbs struct ccb_trans_settings_scsi *scsi; 73897883Sgibbs struct ccb_trans_settings_spi *spi; 73997883Sgibbs struct ahd_initiator_tinfo *targ_info; 74097883Sgibbs struct ahd_tmode_tstate *tstate; 74197883Sgibbs struct ahd_transinfo *tinfo; 74297883Sgibbs 74397883Sgibbs scsi = &cts->proto_specific.scsi; 74497883Sgibbs spi = &cts->xport_specific.spi; 74597883Sgibbs ahd_compile_devinfo(&devinfo, our_id, 74697883Sgibbs cts->ccb_h.target_id, 74797883Sgibbs cts->ccb_h.target_lun, 74897883Sgibbs channel, ROLE_UNKNOWN); 74997883Sgibbs targ_info = ahd_fetch_transinfo(ahd, devinfo.channel, 75097883Sgibbs devinfo.our_scsiid, 75197883Sgibbs devinfo.target, &tstate); 75297883Sgibbs 75397883Sgibbs if (cts->type == CTS_TYPE_CURRENT_SETTINGS) 75497883Sgibbs tinfo = &targ_info->curr; 75597883Sgibbs else 75697883Sgibbs tinfo = &targ_info->user; 75797883Sgibbs 75897883Sgibbs scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 75997883Sgibbs spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB; 76097883Sgibbs if (cts->type == CTS_TYPE_USER_SETTINGS) { 76197883Sgibbs if ((ahd->user_discenable & devinfo.target_mask) != 0) 76297883Sgibbs spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 76397883Sgibbs 76497883Sgibbs if ((ahd->user_tagenable & devinfo.target_mask) != 0) 76597883Sgibbs scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; 76697883Sgibbs } else { 76797883Sgibbs if ((tstate->discenable & devinfo.target_mask) != 0) 76897883Sgibbs spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 76997883Sgibbs 77097883Sgibbs if ((tstate->tagenable & devinfo.target_mask) != 0) 77197883Sgibbs scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; 77297883Sgibbs } 77397883Sgibbs cts->protocol_version = tinfo->protocol_version; 77497883Sgibbs cts->transport_version = tinfo->transport_version; 77597883Sgibbs 77697883Sgibbs spi->sync_period = tinfo->period; 77797883Sgibbs spi->sync_offset = tinfo->offset; 77897883Sgibbs spi->bus_width = tinfo->width; 77997883Sgibbs spi->ppr_options = tinfo->ppr_options; 78097883Sgibbs 78197883Sgibbs cts->protocol = PROTO_SCSI; 78297883Sgibbs cts->transport = XPORT_SPI; 78397883Sgibbs spi->valid = CTS_SPI_VALID_SYNC_RATE 78497883Sgibbs | CTS_SPI_VALID_SYNC_OFFSET 78597883Sgibbs | CTS_SPI_VALID_BUS_WIDTH 78697883Sgibbs | CTS_SPI_VALID_PPR_OPTIONS; 78797883Sgibbs 78897883Sgibbs if (cts->ccb_h.target_lun != CAM_LUN_WILDCARD) { 78997883Sgibbs scsi->valid = CTS_SCSI_VALID_TQ; 79097883Sgibbs spi->valid |= CTS_SPI_VALID_DISC; 79197883Sgibbs } else { 79297883Sgibbs scsi->valid = 0; 79397883Sgibbs } 79497883Sgibbs 79597883Sgibbs cts->ccb_h.status = CAM_REQ_CMP; 79697883Sgibbs} 79797883Sgibbs 79897883Sgibbsstatic void 79997883Sgibbsahd_async(void *callback_arg, uint32_t code, struct cam_path *path, void *arg) 80097883Sgibbs{ 80197883Sgibbs struct ahd_softc *ahd; 80297883Sgibbs struct cam_sim *sim; 80397883Sgibbs 80497883Sgibbs sim = (struct cam_sim *)callback_arg; 80597883Sgibbs ahd = (struct ahd_softc *)cam_sim_softc(sim); 80697883Sgibbs switch (code) { 80797883Sgibbs case AC_LOST_DEVICE: 80897883Sgibbs { 80997883Sgibbs struct ahd_devinfo devinfo; 81097883Sgibbs 81197883Sgibbs ahd_compile_devinfo(&devinfo, SIM_SCSI_ID(ahd, sim), 81297883Sgibbs xpt_path_target_id(path), 81397883Sgibbs xpt_path_lun_id(path), 81497883Sgibbs SIM_CHANNEL(ahd, sim), 81597883Sgibbs ROLE_UNKNOWN); 81697883Sgibbs 81797883Sgibbs /* 81897883Sgibbs * Revert to async/narrow transfers 81997883Sgibbs * for the next device. 82097883Sgibbs */ 82197883Sgibbs ahd_set_width(ahd, &devinfo, MSG_EXT_WDTR_BUS_8_BIT, 82297883Sgibbs AHD_TRANS_GOAL|AHD_TRANS_CUR, /*paused*/FALSE); 82397883Sgibbs ahd_set_syncrate(ahd, &devinfo, /*period*/0, /*offset*/0, 82497883Sgibbs /*ppr_options*/0, AHD_TRANS_GOAL|AHD_TRANS_CUR, 82597883Sgibbs /*paused*/FALSE); 82697883Sgibbs break; 82797883Sgibbs } 82897883Sgibbs default: 82997883Sgibbs break; 83097883Sgibbs } 83197883Sgibbs} 83297883Sgibbs 83397883Sgibbsstatic void 83497883Sgibbsahd_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments, 83597883Sgibbs int error) 83697883Sgibbs{ 83797883Sgibbs struct scb *scb; 83897883Sgibbs union ccb *ccb; 83997883Sgibbs struct ahd_softc *ahd; 84097883Sgibbs struct ahd_initiator_tinfo *tinfo; 84197883Sgibbs struct ahd_tmode_tstate *tstate; 84297883Sgibbs u_int mask; 84397883Sgibbs 84497883Sgibbs scb = (struct scb *)arg; 84597883Sgibbs ccb = scb->io_ctx; 84697883Sgibbs ahd = scb->ahd_softc; 84797883Sgibbs 84897883Sgibbs if (error != 0) { 84997883Sgibbs if (error == EFBIG) 850123579Sgibbs aic_set_transaction_status(scb, CAM_REQ_TOO_BIG); 85197883Sgibbs else 852123579Sgibbs aic_set_transaction_status(scb, CAM_REQ_CMP_ERR); 85397883Sgibbs if (nsegments != 0) 85497883Sgibbs bus_dmamap_unload(ahd->buffer_dmat, scb->dmamap); 85597883Sgibbs ahd_free_scb(ahd, scb); 85697883Sgibbs xpt_done(ccb); 85797883Sgibbs return; 85897883Sgibbs } 85997883Sgibbs scb->sg_count = 0; 86097883Sgibbs if (nsegments != 0) { 86197883Sgibbs void *sg; 862115343Sscottl bus_dmasync_op_t op; 86397883Sgibbs u_int i; 86497883Sgibbs 86597883Sgibbs /* Copy the segments into our SG list */ 86697883Sgibbs for (i = nsegments, sg = scb->sg_list; i > 0; i--) { 86797883Sgibbs 86897883Sgibbs sg = ahd_sg_setup(ahd, scb, sg, dm_segs->ds_addr, 86997883Sgibbs dm_segs->ds_len, 87097883Sgibbs /*last*/i == 1); 87197883Sgibbs dm_segs++; 87297883Sgibbs } 87397883Sgibbs 87497883Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) 87597883Sgibbs op = BUS_DMASYNC_PREREAD; 87697883Sgibbs else 87797883Sgibbs op = BUS_DMASYNC_PREWRITE; 87897883Sgibbs 87997883Sgibbs bus_dmamap_sync(ahd->buffer_dmat, scb->dmamap, op); 88097883Sgibbs 88197883Sgibbs if (ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) { 88297883Sgibbs struct target_data *tdata; 88397883Sgibbs 88497883Sgibbs tdata = &scb->hscb->shared_data.tdata; 88597883Sgibbs tdata->target_phases |= DPHASE_PENDING; 88697883Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) 88797883Sgibbs tdata->data_phase = P_DATAOUT; 88897883Sgibbs else 88997883Sgibbs tdata->data_phase = P_DATAIN; 89097883Sgibbs } 89197883Sgibbs } 89297883Sgibbs 89397883Sgibbs /* 89497883Sgibbs * Last time we need to check if this SCB needs to 89597883Sgibbs * be aborted. 89697883Sgibbs */ 897123579Sgibbs if (aic_get_transaction_status(scb) != CAM_REQ_INPROG) { 89897883Sgibbs if (nsegments != 0) 89997883Sgibbs bus_dmamap_unload(ahd->buffer_dmat, 90097883Sgibbs scb->dmamap); 90197883Sgibbs ahd_free_scb(ahd, scb); 90297883Sgibbs xpt_done(ccb); 90397883Sgibbs return; 90497883Sgibbs } 90597883Sgibbs 90697883Sgibbs tinfo = ahd_fetch_transinfo(ahd, SCSIID_CHANNEL(ahd, scb->hscb->scsiid), 90797883Sgibbs SCSIID_OUR_ID(scb->hscb->scsiid), 90897883Sgibbs SCSIID_TARGET(ahd, scb->hscb->scsiid), 90997883Sgibbs &tstate); 91097883Sgibbs 91197883Sgibbs mask = SCB_GET_TARGET_MASK(ahd, scb); 91297883Sgibbs 91397883Sgibbs if ((tstate->discenable & mask) != 0 91497883Sgibbs && (ccb->ccb_h.flags & CAM_DIS_DISCONNECT) == 0) 91597883Sgibbs scb->hscb->control |= DISCENB; 91697883Sgibbs 917109588Sgibbs if ((tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ) != 0) { 91897883Sgibbs scb->flags |= SCB_PACKETIZED; 919109588Sgibbs if (scb->hscb->task_management != 0) 920109588Sgibbs scb->hscb->control &= ~MK_MESSAGE; 921109588Sgibbs } 92297883Sgibbs 92397883Sgibbs if ((ccb->ccb_h.flags & CAM_NEGOTIATE) != 0 92497883Sgibbs && (tinfo->goal.width != 0 92597883Sgibbs || tinfo->goal.period != 0 92697883Sgibbs || tinfo->goal.ppr_options != 0)) { 92797883Sgibbs scb->flags |= SCB_NEGOTIATE; 92897883Sgibbs scb->hscb->control |= MK_MESSAGE; 92997883Sgibbs } else if ((tstate->auto_negotiate & mask) != 0) { 93097883Sgibbs scb->flags |= SCB_AUTO_NEGOTIATE; 93197883Sgibbs scb->hscb->control |= MK_MESSAGE; 93297883Sgibbs } 93397883Sgibbs 93497883Sgibbs LIST_INSERT_HEAD(&ahd->pending_scbs, scb, pending_links); 93597883Sgibbs 93697883Sgibbs ccb->ccb_h.status |= CAM_SIM_QUEUED; 93797883Sgibbs 938133911Sgibbs aic_scb_timer_start(scb); 93997883Sgibbs 94097883Sgibbs if ((scb->flags & SCB_TARGET_IMMEDIATE) != 0) { 94197883Sgibbs /* Define a mapping from our tag to the SCB. */ 94297883Sgibbs ahd->scb_data.scbindex[SCB_GET_TAG(scb)] = scb; 94397883Sgibbs ahd_pause(ahd); 94497883Sgibbs ahd_set_scbptr(ahd, SCB_GET_TAG(scb)); 94597883Sgibbs ahd_outb(ahd, RETURN_1, CONT_MSG_LOOP_TARG); 94697883Sgibbs ahd_unpause(ahd); 94797883Sgibbs } else { 94897883Sgibbs ahd_queue_scb(ahd, scb); 94997883Sgibbs } 95097883Sgibbs 95197883Sgibbs} 95297883Sgibbs 95397883Sgibbsstatic void 95497883Sgibbsahd_poll(struct cam_sim *sim) 95597883Sgibbs{ 95697883Sgibbs ahd_intr(cam_sim_softc(sim)); 95797883Sgibbs} 95897883Sgibbs 95997883Sgibbsstatic void 96097883Sgibbsahd_setup_data(struct ahd_softc *ahd, struct cam_sim *sim, 96197883Sgibbs struct ccb_scsiio *csio, struct scb *scb) 96297883Sgibbs{ 96397883Sgibbs struct hardware_scb *hscb; 96497883Sgibbs struct ccb_hdr *ccb_h; 96597883Sgibbs 96697883Sgibbs hscb = scb->hscb; 96797883Sgibbs ccb_h = &csio->ccb_h; 96897883Sgibbs 96997883Sgibbs csio->resid = 0; 97097883Sgibbs csio->sense_resid = 0; 97197883Sgibbs if (ccb_h->func_code == XPT_SCSI_IO) { 97297883Sgibbs hscb->cdb_len = csio->cdb_len; 97397883Sgibbs if ((ccb_h->flags & CAM_CDB_POINTER) != 0) { 97497883Sgibbs 97597883Sgibbs if (hscb->cdb_len > MAX_CDB_LEN 97697883Sgibbs && (ccb_h->flags & CAM_CDB_PHYS) == 0) { 97797883Sgibbs 978111653Sgibbs /* 979111653Sgibbs * Should CAM start to support CDB sizes 980111653Sgibbs * greater than 16 bytes, we could use 981111653Sgibbs * the sense buffer to store the CDB. 982111653Sgibbs */ 983123579Sgibbs aic_set_transaction_status(scb, 98497883Sgibbs CAM_REQ_INVALID); 98597883Sgibbs ahd_free_scb(ahd, scb); 98697883Sgibbs xpt_done((union ccb *)csio); 98797883Sgibbs return; 98897883Sgibbs } 98997883Sgibbs if ((ccb_h->flags & CAM_CDB_PHYS) != 0) { 990111653Sgibbs hscb->shared_data.idata.cdb_from_host.cdbptr = 991123579Sgibbs aic_htole64((uintptr_t)csio->cdb_io.cdb_ptr); 992111653Sgibbs hscb->shared_data.idata.cdb_from_host.cdblen = 993111653Sgibbs csio->cdb_len; 994111653Sgibbs hscb->cdb_len |= SCB_CDB_LEN_PTR; 99597883Sgibbs } else { 99697883Sgibbs memcpy(hscb->shared_data.idata.cdb, 99797883Sgibbs csio->cdb_io.cdb_ptr, 99897883Sgibbs hscb->cdb_len); 99997883Sgibbs } 100097883Sgibbs } else { 100197883Sgibbs if (hscb->cdb_len > MAX_CDB_LEN) { 100297883Sgibbs 1003123579Sgibbs aic_set_transaction_status(scb, 100497883Sgibbs CAM_REQ_INVALID); 100597883Sgibbs ahd_free_scb(ahd, scb); 100697883Sgibbs xpt_done((union ccb *)csio); 100797883Sgibbs return; 100897883Sgibbs } 100997883Sgibbs memcpy(hscb->shared_data.idata.cdb, 101097883Sgibbs csio->cdb_io.cdb_bytes, hscb->cdb_len); 101197883Sgibbs } 101297883Sgibbs } 101397883Sgibbs 101497883Sgibbs /* Only use S/G if there is a transfer */ 101597883Sgibbs if ((ccb_h->flags & CAM_DIR_MASK) != CAM_DIR_NONE) { 101697883Sgibbs if ((ccb_h->flags & CAM_SCATTER_VALID) == 0) { 101797883Sgibbs /* We've been given a pointer to a single buffer */ 101897883Sgibbs if ((ccb_h->flags & CAM_DATA_PHYS) == 0) { 101997883Sgibbs int s; 102097883Sgibbs int error; 102197883Sgibbs 102297883Sgibbs s = splsoftvm(); 102397883Sgibbs error = bus_dmamap_load(ahd->buffer_dmat, 102497883Sgibbs scb->dmamap, 102597883Sgibbs csio->data_ptr, 102697883Sgibbs csio->dxfer_len, 102797883Sgibbs ahd_execute_scb, 102897883Sgibbs scb, /*flags*/0); 102997883Sgibbs if (error == EINPROGRESS) { 103097883Sgibbs /* 103197883Sgibbs * So as to maintain ordering, 103297883Sgibbs * freeze the controller queue 103397883Sgibbs * until our mapping is 103497883Sgibbs * returned. 103597883Sgibbs */ 103697883Sgibbs xpt_freeze_simq(sim, 103797883Sgibbs /*count*/1); 103897883Sgibbs scb->io_ctx->ccb_h.status |= 103997883Sgibbs CAM_RELEASE_SIMQ; 104097883Sgibbs } 104197883Sgibbs splx(s); 104297883Sgibbs } else { 104397883Sgibbs struct bus_dma_segment seg; 104497883Sgibbs 104597883Sgibbs /* Pointer to physical buffer */ 104697883Sgibbs if (csio->dxfer_len > AHD_MAXTRANSFER_SIZE) 104797883Sgibbs panic("ahd_setup_data - Transfer size " 104897883Sgibbs "larger than can device max"); 104997883Sgibbs 1050113296Sjake seg.ds_addr = 1051113296Sjake (bus_addr_t)(vm_offset_t)csio->data_ptr; 105297883Sgibbs seg.ds_len = csio->dxfer_len; 105397883Sgibbs ahd_execute_scb(scb, &seg, 1, 0); 105497883Sgibbs } 105597883Sgibbs } else { 105697883Sgibbs struct bus_dma_segment *segs; 105797883Sgibbs 105897883Sgibbs if ((ccb_h->flags & CAM_DATA_PHYS) != 0) 105997883Sgibbs panic("ahd_setup_data - Physical segment " 106097883Sgibbs "pointers unsupported"); 106197883Sgibbs 106297883Sgibbs if ((ccb_h->flags & CAM_SG_LIST_PHYS) == 0) 106397883Sgibbs panic("ahd_setup_data - Virtual segment " 106497883Sgibbs "addresses unsupported"); 106597883Sgibbs 106697883Sgibbs /* Just use the segments provided */ 106797883Sgibbs segs = (struct bus_dma_segment *)csio->data_ptr; 106897883Sgibbs ahd_execute_scb(scb, segs, csio->sglist_cnt, 0); 106997883Sgibbs } 107097883Sgibbs } else { 107197883Sgibbs ahd_execute_scb(scb, NULL, 0, 0); 107297883Sgibbs } 107397883Sgibbs} 107497883Sgibbs 107597883Sgibbsstatic void 107697883Sgibbsahd_abort_ccb(struct ahd_softc *ahd, struct cam_sim *sim, union ccb *ccb) 107797883Sgibbs{ 107897883Sgibbs union ccb *abort_ccb; 107997883Sgibbs 108097883Sgibbs abort_ccb = ccb->cab.abort_ccb; 108197883Sgibbs switch (abort_ccb->ccb_h.func_code) { 108297883Sgibbs#ifdef AHD_TARGET_MODE 108397883Sgibbs case XPT_ACCEPT_TARGET_IO: 108497883Sgibbs case XPT_IMMED_NOTIFY: 108597883Sgibbs case XPT_CONT_TARGET_IO: 108697883Sgibbs { 108797883Sgibbs struct ahd_tmode_tstate *tstate; 108897883Sgibbs struct ahd_tmode_lstate *lstate; 108997883Sgibbs struct ccb_hdr_slist *list; 109097883Sgibbs cam_status status; 109197883Sgibbs 109297883Sgibbs status = ahd_find_tmode_devs(ahd, sim, abort_ccb, &tstate, 109397883Sgibbs &lstate, TRUE); 109497883Sgibbs 109597883Sgibbs if (status != CAM_REQ_CMP) { 109697883Sgibbs ccb->ccb_h.status = status; 109797883Sgibbs break; 109897883Sgibbs } 109997883Sgibbs 110097883Sgibbs if (abort_ccb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) 110197883Sgibbs list = &lstate->accept_tios; 110297883Sgibbs else if (abort_ccb->ccb_h.func_code == XPT_IMMED_NOTIFY) 110397883Sgibbs list = &lstate->immed_notifies; 110497883Sgibbs else 110597883Sgibbs list = NULL; 110697883Sgibbs 110797883Sgibbs if (list != NULL) { 110897883Sgibbs struct ccb_hdr *curelm; 110997883Sgibbs int found; 111097883Sgibbs 111197883Sgibbs curelm = SLIST_FIRST(list); 111297883Sgibbs found = 0; 111397883Sgibbs if (curelm == &abort_ccb->ccb_h) { 111497883Sgibbs found = 1; 111597883Sgibbs SLIST_REMOVE_HEAD(list, sim_links.sle); 111697883Sgibbs } else { 111797883Sgibbs while(curelm != NULL) { 111897883Sgibbs struct ccb_hdr *nextelm; 111997883Sgibbs 112097883Sgibbs nextelm = 112197883Sgibbs SLIST_NEXT(curelm, sim_links.sle); 112297883Sgibbs 112397883Sgibbs if (nextelm == &abort_ccb->ccb_h) { 112497883Sgibbs found = 1; 112597883Sgibbs SLIST_NEXT(curelm, 112697883Sgibbs sim_links.sle) = 112797883Sgibbs SLIST_NEXT(nextelm, 112897883Sgibbs sim_links.sle); 112997883Sgibbs break; 113097883Sgibbs } 113197883Sgibbs curelm = nextelm; 113297883Sgibbs } 113397883Sgibbs } 113497883Sgibbs 113597883Sgibbs if (found) { 113697883Sgibbs abort_ccb->ccb_h.status = CAM_REQ_ABORTED; 113797883Sgibbs xpt_done(abort_ccb); 113897883Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 113997883Sgibbs } else { 114097883Sgibbs xpt_print_path(abort_ccb->ccb_h.path); 114197883Sgibbs printf("Not found\n"); 114297883Sgibbs ccb->ccb_h.status = CAM_PATH_INVALID; 114397883Sgibbs } 114497883Sgibbs break; 114597883Sgibbs } 114697883Sgibbs /* FALLTHROUGH */ 114797883Sgibbs } 114897883Sgibbs#endif 114997883Sgibbs case XPT_SCSI_IO: 115097883Sgibbs /* XXX Fully implement the hard ones */ 115197883Sgibbs ccb->ccb_h.status = CAM_UA_ABORT; 115297883Sgibbs break; 115397883Sgibbs default: 115497883Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 115597883Sgibbs break; 115697883Sgibbs } 115797883Sgibbs xpt_done(ccb); 115897883Sgibbs} 115997883Sgibbs 116097883Sgibbsvoid 116197883Sgibbsahd_send_async(struct ahd_softc *ahd, char channel, u_int target, 116297883Sgibbs u_int lun, ac_code code, void *opt_arg) 116397883Sgibbs{ 116497883Sgibbs struct ccb_trans_settings cts; 116597883Sgibbs struct cam_path *path; 116697883Sgibbs void *arg; 116797883Sgibbs int error; 116897883Sgibbs 116997883Sgibbs arg = NULL; 117097883Sgibbs error = ahd_create_path(ahd, channel, target, lun, &path); 117197883Sgibbs 117297883Sgibbs if (error != CAM_REQ_CMP) 117397883Sgibbs return; 117497883Sgibbs 117597883Sgibbs switch (code) { 117697883Sgibbs case AC_TRANSFER_NEG: 117797883Sgibbs { 117897883Sgibbs struct ccb_trans_settings_scsi *scsi; 117997883Sgibbs 118097883Sgibbs cts.type = CTS_TYPE_CURRENT_SETTINGS; 118197883Sgibbs scsi = &cts.proto_specific.scsi; 118297883Sgibbs cts.ccb_h.path = path; 118397883Sgibbs cts.ccb_h.target_id = target; 118497883Sgibbs cts.ccb_h.target_lun = lun; 118597883Sgibbs ahd_get_tran_settings(ahd, ahd->our_id, channel, &cts); 118697883Sgibbs arg = &cts; 118797883Sgibbs scsi->valid &= ~CTS_SCSI_VALID_TQ; 118897883Sgibbs scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 118997883Sgibbs if (opt_arg == NULL) 119097883Sgibbs break; 119197883Sgibbs if (*((ahd_queue_alg *)opt_arg) == AHD_QUEUE_TAGGED) 119297883Sgibbs scsi->flags |= ~CTS_SCSI_FLAGS_TAG_ENB; 119397883Sgibbs scsi->valid |= CTS_SCSI_VALID_TQ; 119497883Sgibbs break; 119597883Sgibbs } 119697883Sgibbs case AC_SENT_BDR: 119797883Sgibbs case AC_BUS_RESET: 119897883Sgibbs break; 119997883Sgibbs default: 120097883Sgibbs panic("ahd_send_async: Unexpected async event"); 120197883Sgibbs } 120297883Sgibbs xpt_async(code, path, arg); 120397883Sgibbs xpt_free_path(path); 120497883Sgibbs} 120597883Sgibbs 120697883Sgibbsvoid 120797883Sgibbsahd_platform_set_tags(struct ahd_softc *ahd, 120897883Sgibbs struct ahd_devinfo *devinfo, int enable) 120997883Sgibbs{ 121097883Sgibbs} 121197883Sgibbs 121297883Sgibbsint 121397883Sgibbsahd_platform_alloc(struct ahd_softc *ahd, void *platform_arg) 121497883Sgibbs{ 121597883Sgibbs ahd->platform_data = malloc(sizeof(struct ahd_platform_data), M_DEVBUF, 121697883Sgibbs M_NOWAIT | M_ZERO); 121797883Sgibbs if (ahd->platform_data == NULL) 121897883Sgibbs return (ENOMEM); 121997883Sgibbs return (0); 122097883Sgibbs} 122197883Sgibbs 122297883Sgibbsvoid 122397883Sgibbsahd_platform_free(struct ahd_softc *ahd) 122497883Sgibbs{ 122597883Sgibbs struct ahd_platform_data *pdata; 122697883Sgibbs 122797883Sgibbs pdata = ahd->platform_data; 122897883Sgibbs if (pdata != NULL) { 122997883Sgibbs if (pdata->regs[0] != NULL) 123097883Sgibbs bus_release_resource(ahd->dev_softc, 123197883Sgibbs pdata->regs_res_type[0], 123297883Sgibbs pdata->regs_res_id[0], 123397883Sgibbs pdata->regs[0]); 123497883Sgibbs 123597883Sgibbs if (pdata->regs[1] != NULL) 123697883Sgibbs bus_release_resource(ahd->dev_softc, 123797883Sgibbs pdata->regs_res_type[1], 123897883Sgibbs pdata->regs_res_id[1], 123997883Sgibbs pdata->regs[1]); 124097883Sgibbs 124197883Sgibbs if (pdata->irq != NULL) 124297883Sgibbs bus_release_resource(ahd->dev_softc, 124397883Sgibbs pdata->irq_res_type, 124497883Sgibbs 0, pdata->irq); 124597883Sgibbs 124697883Sgibbs if (pdata->sim != NULL) { 124797883Sgibbs xpt_async(AC_LOST_DEVICE, pdata->path, NULL); 124897883Sgibbs xpt_free_path(pdata->path); 124997883Sgibbs xpt_bus_deregister(cam_sim_path(pdata->sim)); 125097883Sgibbs cam_sim_free(pdata->sim, /*free_devq*/TRUE); 125197883Sgibbs } 125297883Sgibbs if (pdata->eh != NULL) 125397883Sgibbs EVENTHANDLER_DEREGISTER(shutdown_final, pdata->eh); 125497883Sgibbs free(ahd->platform_data, M_DEVBUF); 125597883Sgibbs } 125697883Sgibbs} 125797883Sgibbs 125897883Sgibbsint 125997883Sgibbsahd_softc_comp(struct ahd_softc *lahd, struct ahd_softc *rahd) 126097883Sgibbs{ 126197883Sgibbs /* We don't sort softcs under FreeBSD so report equal always */ 126297883Sgibbs return (0); 126397883Sgibbs} 126497883Sgibbs 126597883Sgibbsint 126697883Sgibbsahd_detach(device_t dev) 126797883Sgibbs{ 126897883Sgibbs struct ahd_softc *ahd; 126997883Sgibbs 127097883Sgibbs device_printf(dev, "detaching device\n"); 127197883Sgibbs ahd = device_get_softc(dev); 1272168807Sscottl ahd_lock(ahd); 1273123579Sgibbs TAILQ_REMOVE(&ahd_tailq, ahd, links); 127497883Sgibbs ahd_intr_enable(ahd, FALSE); 127597883Sgibbs bus_teardown_intr(dev, ahd->platform_data->irq, ahd->platform_data->ih); 1276168807Sscottl ahd_unlock(ahd); 127797883Sgibbs ahd_free(ahd); 127897883Sgibbs return (0); 127997883Sgibbs} 128097883Sgibbs 1281153072Sru#if 0 128297883Sgibbsstatic void 128397883Sgibbsahd_dump_targcmd(struct target_cmd *cmd) 128497883Sgibbs{ 128597883Sgibbs uint8_t *byte; 128697883Sgibbs uint8_t *last_byte; 128797883Sgibbs int i; 128897883Sgibbs 128997883Sgibbs byte = &cmd->initiator_channel; 129097883Sgibbs /* Debugging info for received commands */ 129197883Sgibbs last_byte = &cmd[1].initiator_channel; 129297883Sgibbs 129397883Sgibbs i = 0; 129497883Sgibbs while (byte < last_byte) { 129597883Sgibbs if (i == 0) 129697883Sgibbs printf("\t"); 129797883Sgibbs printf("%#x", *byte++); 129897883Sgibbs i++; 129997883Sgibbs if (i == 8) { 130097883Sgibbs printf("\n"); 130197883Sgibbs i = 0; 130297883Sgibbs } else { 130397883Sgibbs printf(", "); 130497883Sgibbs } 130597883Sgibbs } 130697883Sgibbs} 130797883Sgibbs#endif 130897883Sgibbs 130997883Sgibbsstatic int 131097883Sgibbsahd_modevent(module_t mod, int type, void *data) 131197883Sgibbs{ 131297883Sgibbs /* XXX Deal with busy status on unload. */ 1313132199Sphk /* XXX Deal with unknown events */ 131497883Sgibbs return 0; 131597883Sgibbs} 131697883Sgibbs 131797883Sgibbsstatic moduledata_t ahd_mod = { 131897883Sgibbs "ahd", 131997883Sgibbs ahd_modevent, 132097883Sgibbs NULL 132197883Sgibbs}; 132297883Sgibbs 132397883Sgibbs/********************************** DDB Hooks *********************************/ 132497883Sgibbs#ifdef DDB 132597883Sgibbsstatic struct ahd_softc *ahd_ddb_softc; 132697883Sgibbsstatic int ahd_ddb_paused; 132797883Sgibbsstatic int ahd_ddb_paused_on_entry; 1328133122SgibbsDB_COMMAND(ahd_sunit, ahd_ddb_sunit) 132997883Sgibbs{ 133097883Sgibbs struct ahd_softc *list_ahd; 133197883Sgibbs 133297883Sgibbs ahd_ddb_softc = NULL; 133397883Sgibbs TAILQ_FOREACH(list_ahd, &ahd_tailq, links) { 133497883Sgibbs if (list_ahd->unit == addr) 133597883Sgibbs ahd_ddb_softc = list_ahd; 133697883Sgibbs } 133797883Sgibbs if (ahd_ddb_softc == NULL) 133897883Sgibbs db_error("No matching softc found!\n"); 133997883Sgibbs} 134097883Sgibbs 134197883SgibbsDB_COMMAND(ahd_pause, ahd_ddb_pause) 134297883Sgibbs{ 134397883Sgibbs if (ahd_ddb_softc == NULL) { 1344133122Sgibbs db_error("Must set unit with ahd_sunit first!\n"); 134597883Sgibbs return; 134697883Sgibbs } 134797883Sgibbs if (ahd_ddb_paused == 0) { 134897883Sgibbs ahd_ddb_paused++; 134997883Sgibbs if (ahd_is_paused(ahd_ddb_softc)) { 135097883Sgibbs ahd_ddb_paused_on_entry++; 135197883Sgibbs return; 135297883Sgibbs } 135397883Sgibbs ahd_pause(ahd_ddb_softc); 135497883Sgibbs } 135597883Sgibbs} 135697883Sgibbs 135797883SgibbsDB_COMMAND(ahd_unpause, ahd_ddb_unpause) 135897883Sgibbs{ 135997883Sgibbs if (ahd_ddb_softc == NULL) { 1360133122Sgibbs db_error("Must set unit with ahd_sunit first!\n"); 136197883Sgibbs return; 136297883Sgibbs } 136397883Sgibbs if (ahd_ddb_paused != 0) { 136497883Sgibbs ahd_ddb_paused = 0; 136597883Sgibbs if (ahd_ddb_paused_on_entry) 136697883Sgibbs return; 136797883Sgibbs ahd_unpause(ahd_ddb_softc); 136897883Sgibbs } else if (ahd_ddb_paused_on_entry != 0) { 136997883Sgibbs /* Two unpauses to clear a paused on entry. */ 137097883Sgibbs ahd_ddb_paused_on_entry = 0; 137197883Sgibbs ahd_unpause(ahd_ddb_softc); 137297883Sgibbs } 137397883Sgibbs} 137497883Sgibbs 137597883SgibbsDB_COMMAND(ahd_in, ahd_ddb_in) 137697883Sgibbs{ 137797883Sgibbs int c; 137897883Sgibbs int size; 137997883Sgibbs 138097883Sgibbs if (ahd_ddb_softc == NULL) { 1381133122Sgibbs db_error("Must set unit with ahd_sunit first!\n"); 138297883Sgibbs return; 138397883Sgibbs } 138497883Sgibbs if (have_addr == 0) 138597883Sgibbs return; 138697883Sgibbs 138797883Sgibbs size = 1; 138897883Sgibbs while ((c = *modif++) != '\0') { 138997883Sgibbs switch (c) { 139097883Sgibbs case 'b': 139197883Sgibbs size = 1; 139297883Sgibbs break; 139397883Sgibbs case 'w': 139497883Sgibbs size = 2; 139597883Sgibbs break; 139697883Sgibbs case 'l': 139797883Sgibbs size = 4; 139897883Sgibbs break; 139997883Sgibbs } 140097883Sgibbs } 140197883Sgibbs 140297883Sgibbs if (count <= 0) 140397883Sgibbs count = 1; 140497883Sgibbs while (--count >= 0) { 1405107368Sscottl db_printf("%04lx (M)%x: \t", (u_long)addr, 140697883Sgibbs ahd_inb(ahd_ddb_softc, MODE_PTR)); 140797883Sgibbs switch (size) { 140897883Sgibbs case 1: 140997883Sgibbs db_printf("%02x\n", ahd_inb(ahd_ddb_softc, addr)); 141097883Sgibbs break; 141197883Sgibbs case 2: 141297883Sgibbs db_printf("%04x\n", ahd_inw(ahd_ddb_softc, addr)); 141397883Sgibbs break; 141497883Sgibbs case 4: 141597883Sgibbs db_printf("%08x\n", ahd_inl(ahd_ddb_softc, addr)); 141697883Sgibbs break; 141797883Sgibbs } 141897883Sgibbs } 141997883Sgibbs} 142097883Sgibbs 1421156412SjhbDB_FUNC(ahd_out, ahd_ddb_out, db_cmd_set, CS_MORE, NULL) 142297883Sgibbs{ 142397883Sgibbs db_expr_t old_value; 142497883Sgibbs db_expr_t new_value; 142597883Sgibbs int size; 142697883Sgibbs 142797883Sgibbs if (ahd_ddb_softc == NULL) { 1428133122Sgibbs db_error("Must set unit with ahd_sunit first!\n"); 142997883Sgibbs return; 143097883Sgibbs } 143197883Sgibbs 143297883Sgibbs switch (modif[0]) { 143397883Sgibbs case '\0': 143497883Sgibbs case 'b': 143597883Sgibbs size = 1; 143697883Sgibbs break; 143797883Sgibbs case 'h': 143897883Sgibbs size = 2; 143997883Sgibbs break; 144097883Sgibbs case 'l': 144197883Sgibbs size = 4; 144297883Sgibbs break; 144397883Sgibbs default: 144497883Sgibbs db_error("Unknown size\n"); 144597883Sgibbs return; 144697883Sgibbs } 144797883Sgibbs 144897883Sgibbs while (db_expression(&new_value)) { 144997883Sgibbs switch (size) { 145097883Sgibbs default: 145197883Sgibbs case 1: 145297883Sgibbs old_value = ahd_inb(ahd_ddb_softc, addr); 145397883Sgibbs ahd_outb(ahd_ddb_softc, addr, new_value); 145497883Sgibbs break; 145597883Sgibbs case 2: 145697883Sgibbs old_value = ahd_inw(ahd_ddb_softc, addr); 145797883Sgibbs ahd_outw(ahd_ddb_softc, addr, new_value); 145897883Sgibbs break; 145997883Sgibbs case 4: 146097883Sgibbs old_value = ahd_inl(ahd_ddb_softc, addr); 146197883Sgibbs ahd_outl(ahd_ddb_softc, addr, new_value); 146297883Sgibbs break; 146397883Sgibbs } 1464107368Sscottl db_printf("%04lx (M)%x: \t0x%lx\t=\t0x%lx", 1465107368Sscottl (u_long)addr, ahd_inb(ahd_ddb_softc, MODE_PTR), 1466107368Sscottl (u_long)old_value, (u_long)new_value); 146797883Sgibbs addr += size; 146897883Sgibbs } 146997883Sgibbs db_skip_to_eol(); 147097883Sgibbs} 147197883Sgibbs 1472133122SgibbsDB_COMMAND(ahd_dump, ahd_ddb_dump) 1473133122Sgibbs{ 1474133122Sgibbs if (ahd_ddb_softc == NULL) { 1475133122Sgibbs db_error("Must set unit with ahd_sunit first!\n"); 1476133122Sgibbs return; 1477133122Sgibbs } 1478133122Sgibbs ahd_dump_card_state(ahd_ddb_softc); 1479133122Sgibbs} 1480133122Sgibbs 148197883Sgibbs#endif 148297883Sgibbs 148397883Sgibbs 148497883SgibbsDECLARE_MODULE(ahd, ahd_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); 148597883SgibbsMODULE_DEPEND(ahd, cam, 1, 1, 1); 148697883SgibbsMODULE_VERSION(ahd, 1); 1487