aic79xx_osm.c revision 150450
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 150450 2005-09-22 05:01:37Z 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 5697883Sgibbs#if UNUSED 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, 9897883Sgibbs INTR_TYPE_CAM, ahd_platform_intr, ahd, 9997883Sgibbs &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 long s; 11897883Sgibbs int count; 11997883Sgibbs 12097883Sgibbs count = 0; 121123579Sgibbs devq = NULL; 12297883Sgibbs sim = NULL; 12397883Sgibbs 124123579Sgibbs /* 125123579Sgibbs * Create a thread to perform all recovery. 126123579Sgibbs */ 127123579Sgibbs if (ahd_spawn_recovery_thread(ahd) != 0) 128123579Sgibbs goto fail; 129123579Sgibbs 13097883Sgibbs ahd_controller_info(ahd, ahd_info); 13197883Sgibbs printf("%s\n", ahd_info); 13297883Sgibbs ahd_lock(ahd, &s); 13397883Sgibbs 13497883Sgibbs /* 13597883Sgibbs * Create the device queue for our SIM(s). 13697883Sgibbs */ 13797883Sgibbs devq = cam_simq_alloc(AHD_MAX_QUEUE); 13897883Sgibbs if (devq == NULL) 13997883Sgibbs goto fail; 14097883Sgibbs 14197883Sgibbs /* 14297883Sgibbs * Construct our SIM entry 14397883Sgibbs */ 14497883Sgibbs sim = cam_sim_alloc(ahd_action, ahd_poll, "ahd", ahd, 14597883Sgibbs device_get_unit(ahd->dev_softc), 14697883Sgibbs 1, /*XXX*/256, devq); 14797883Sgibbs if (sim == NULL) { 14897883Sgibbs cam_simq_free(devq); 14997883Sgibbs goto fail; 15097883Sgibbs } 15197883Sgibbs 15297883Sgibbs if (xpt_bus_register(sim, /*bus_id*/0) != CAM_SUCCESS) { 15397883Sgibbs cam_sim_free(sim, /*free_devq*/TRUE); 15497883Sgibbs sim = NULL; 15597883Sgibbs goto fail; 15697883Sgibbs } 15797883Sgibbs 15897883Sgibbs if (xpt_create_path(&path, /*periph*/NULL, 15997883Sgibbs cam_sim_path(sim), CAM_TARGET_WILDCARD, 16097883Sgibbs CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 16197883Sgibbs xpt_bus_deregister(cam_sim_path(sim)); 16297883Sgibbs cam_sim_free(sim, /*free_devq*/TRUE); 16397883Sgibbs sim = NULL; 16497883Sgibbs goto fail; 16597883Sgibbs } 16697883Sgibbs 16797883Sgibbs xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5); 16897883Sgibbs csa.ccb_h.func_code = XPT_SASYNC_CB; 16997883Sgibbs csa.event_enable = AC_LOST_DEVICE; 17097883Sgibbs csa.callback = ahd_async; 17197883Sgibbs csa.callback_arg = sim; 17297883Sgibbs xpt_action((union ccb *)&csa); 17397883Sgibbs count++; 17497883Sgibbs 17597883Sgibbsfail: 17697883Sgibbs ahd->platform_data->sim = sim; 17797883Sgibbs ahd->platform_data->path = path; 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 ahd_unlock(ahd, &s); 187102684Sgibbs 18897883Sgibbs return (count); 18997883Sgibbs} 19097883Sgibbs 19197883Sgibbs/* 19297883Sgibbs * Catch an interrupt from the adapter 19397883Sgibbs */ 19497883Sgibbsvoid 19597883Sgibbsahd_platform_intr(void *arg) 19697883Sgibbs{ 19797883Sgibbs struct ahd_softc *ahd; 19897883Sgibbs 19997883Sgibbs ahd = (struct ahd_softc *)arg; 20097883Sgibbs ahd_intr(ahd); 20197883Sgibbs} 20297883Sgibbs 20397883Sgibbs/* 20497883Sgibbs * We have an scb which has been processed by the 20597883Sgibbs * adaptor, now we look to see how the operation 20697883Sgibbs * went. 20797883Sgibbs */ 20897883Sgibbsvoid 20997883Sgibbsahd_done(struct ahd_softc *ahd, struct scb *scb) 21097883Sgibbs{ 21197883Sgibbs union ccb *ccb; 21297883Sgibbs 21397883Sgibbs CAM_DEBUG(scb->io_ctx->ccb_h.path, CAM_DEBUG_TRACE, 21497883Sgibbs ("ahd_done - scb %d\n", SCB_GET_TAG(scb))); 21597883Sgibbs 21697883Sgibbs ccb = scb->io_ctx; 21797883Sgibbs LIST_REMOVE(scb, pending_links); 218123579Sgibbs if ((scb->flags & SCB_TIMEDOUT) != 0) 219123579Sgibbs LIST_REMOVE(scb, timedout_links); 22097883Sgibbs 221123579Sgibbs untimeout(ahd_platform_timeout, (caddr_t)scb, ccb->ccb_h.timeout_ch); 22297883Sgibbs 22397883Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) { 224115343Sscottl bus_dmasync_op_t op; 22597883Sgibbs 22697883Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) 22797883Sgibbs op = BUS_DMASYNC_POSTREAD; 22897883Sgibbs else 22997883Sgibbs op = BUS_DMASYNC_POSTWRITE; 23097883Sgibbs bus_dmamap_sync(ahd->buffer_dmat, scb->dmamap, op); 23197883Sgibbs bus_dmamap_unload(ahd->buffer_dmat, scb->dmamap); 23297883Sgibbs } 23397883Sgibbs 23497883Sgibbs#ifdef AHD_TARGET_MODE 23597883Sgibbs if (ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) { 23697883Sgibbs struct cam_path *ccb_path; 23797883Sgibbs 23897883Sgibbs /* 23997883Sgibbs * If we have finally disconnected, clean up our 24097883Sgibbs * pending device state. 24197883Sgibbs * XXX - There may be error states that cause where 24297883Sgibbs * we will remain connected. 24397883Sgibbs */ 24497883Sgibbs ccb_path = ccb->ccb_h.path; 24597883Sgibbs if (ahd->pending_device != NULL 24697883Sgibbs && xpt_path_comp(ahd->pending_device->path, ccb_path) == 0) { 24797883Sgibbs 24897883Sgibbs if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) { 24997883Sgibbs ahd->pending_device = NULL; 25097883Sgibbs } else { 25197883Sgibbs xpt_print_path(ccb->ccb_h.path); 25297883Sgibbs printf("Still disconnected\n"); 25397883Sgibbs ahd_freeze_ccb(ccb); 25497883Sgibbs } 25597883Sgibbs } 25697883Sgibbs 257123579Sgibbs if (aic_get_transaction_status(scb) == CAM_REQ_INPROG) 25897883Sgibbs ccb->ccb_h.status |= CAM_REQ_CMP; 25997883Sgibbs ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 26097883Sgibbs ahd_free_scb(ahd, scb); 26197883Sgibbs xpt_done(ccb); 26297883Sgibbs return; 26397883Sgibbs } 26497883Sgibbs#endif 26597883Sgibbs 26697883Sgibbs if ((scb->flags & SCB_RECOVERY_SCB) != 0) { 26797883Sgibbs struct scb *list_scb; 26897883Sgibbs 269133911Sgibbs ahd->scb_data.recovery_scbs--; 27097883Sgibbs 271123579Sgibbs if (aic_get_transaction_status(scb) == CAM_BDR_SENT 272123579Sgibbs || aic_get_transaction_status(scb) == CAM_REQ_ABORTED) 273123579Sgibbs aic_set_transaction_status(scb, CAM_CMD_TIMEOUT); 274123579Sgibbs 275133911Sgibbs if (ahd->scb_data.recovery_scbs == 0) { 276133911Sgibbs /* 277133911Sgibbs * All recovery actions have completed successfully, 278133911Sgibbs * so reinstate the timeouts for all other pending 279133911Sgibbs * commands. 280133911Sgibbs */ 281133911Sgibbs LIST_FOREACH(list_scb, 282133911Sgibbs &ahd->pending_scbs, pending_links) { 283133911Sgibbs 284150450Sgibbs aic_scb_timer_reset(list_scb, 285150450Sgibbs aic_get_timeout(scb)); 286133911Sgibbs } 287133911Sgibbs 288133911Sgibbs ahd_print_path(ahd, scb); 289133911Sgibbs printf("no longer in timeout, status = %x\n", 290133911Sgibbs ccb->ccb_h.status); 291133911Sgibbs } 29297883Sgibbs } 29397883Sgibbs 29497883Sgibbs /* Don't clobber any existing error state */ 295123579Sgibbs if (aic_get_transaction_status(scb) == CAM_REQ_INPROG) { 29697883Sgibbs ccb->ccb_h.status |= CAM_REQ_CMP; 29797883Sgibbs } else if ((scb->flags & SCB_SENSE) != 0) { 29897883Sgibbs /* 29997883Sgibbs * We performed autosense retrieval. 30097883Sgibbs * 30197883Sgibbs * Zero any sense not transferred by the 30297883Sgibbs * device. The SCSI spec mandates that any 30397883Sgibbs * untransfered data should be assumed to be 30497883Sgibbs * zero. Complete the 'bounce' of sense information 30597883Sgibbs * through buffers accessible via bus-space by 30697883Sgibbs * copying it into the clients csio. 30797883Sgibbs */ 30897883Sgibbs memset(&ccb->csio.sense_data, 0, sizeof(ccb->csio.sense_data)); 30997883Sgibbs memcpy(&ccb->csio.sense_data, 31097883Sgibbs ahd_get_sense_buf(ahd, scb), 31197883Sgibbs/* XXX What size do we want to use??? */ 31297883Sgibbs sizeof(ccb->csio.sense_data) 31397883Sgibbs - ccb->csio.sense_resid); 31497883Sgibbs scb->io_ctx->ccb_h.status |= CAM_AUTOSNS_VALID; 31597883Sgibbs } else if ((scb->flags & SCB_PKT_SENSE) != 0) { 31697883Sgibbs struct scsi_status_iu_header *siu; 31797883Sgibbs u_int sense_len; 31897883Sgibbs int i; 31997883Sgibbs 32097883Sgibbs /* 32197883Sgibbs * Copy only the sense data into the provided buffer. 32297883Sgibbs */ 32397883Sgibbs siu = (struct scsi_status_iu_header *)scb->sense_data; 32497883Sgibbs sense_len = MIN(scsi_4btoul(siu->sense_length), 32597883Sgibbs sizeof(ccb->csio.sense_data)); 32697883Sgibbs memset(&ccb->csio.sense_data, 0, sizeof(ccb->csio.sense_data)); 32797883Sgibbs memcpy(&ccb->csio.sense_data, 32897883Sgibbs ahd_get_sense_buf(ahd, scb) + SIU_SENSE_OFFSET(siu), 32997883Sgibbs sense_len); 33097883Sgibbs printf("Copied %d bytes of sense data offset %d:", sense_len, 33197883Sgibbs SIU_SENSE_OFFSET(siu)); 33297883Sgibbs for (i = 0; i < sense_len; i++) 33397883Sgibbs printf(" 0x%x", ((uint8_t *)&ccb->csio.sense_data)[i]); 33497883Sgibbs printf("\n"); 33597883Sgibbs scb->io_ctx->ccb_h.status |= CAM_AUTOSNS_VALID; 33697883Sgibbs } 33797883Sgibbs ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 33897883Sgibbs ahd_free_scb(ahd, scb); 33997883Sgibbs xpt_done(ccb); 34097883Sgibbs} 34197883Sgibbs 34297883Sgibbsstatic void 34397883Sgibbsahd_action(struct cam_sim *sim, union ccb *ccb) 34497883Sgibbs{ 34597883Sgibbs struct ahd_softc *ahd; 34697883Sgibbs#ifdef AHD_TARGET_MODE 34797883Sgibbs struct ahd_tmode_lstate *lstate; 34897883Sgibbs#endif 34997883Sgibbs u_int target_id; 35097883Sgibbs u_int our_id; 35197883Sgibbs long s; 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 ahd_lock(ahd, &s); 38697883Sgibbs SLIST_INSERT_HEAD(&lstate->accept_tios, &ccb->ccb_h, 38797883Sgibbs sim_links.sle); 38897883Sgibbs ccb->ccb_h.status = CAM_REQ_INPROG; 38997883Sgibbs if ((ahd->flags & AHD_TQINFIFO_BLOCKED) != 0) 39097883Sgibbs ahd_run_tqinfifo(ahd, /*paused*/FALSE); 39197883Sgibbs ahd_unlock(ahd, &s); 39297883Sgibbs break; 39397883Sgibbs } 39497883Sgibbs 39597883Sgibbs /* 39697883Sgibbs * The target_id represents the target we attempt to 39797883Sgibbs * select. In target mode, this is the initiator of 39897883Sgibbs * the original command. 39997883Sgibbs */ 40097883Sgibbs our_id = target_id; 40197883Sgibbs target_id = ccb->csio.init_id; 40297883Sgibbs /* FALLTHROUGH */ 40397883Sgibbs } 40497883Sgibbs#endif 40597883Sgibbs case XPT_SCSI_IO: /* Execute the requested I/O operation */ 40697883Sgibbs case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */ 40797883Sgibbs { 40897883Sgibbs struct scb *scb; 40997883Sgibbs struct hardware_scb *hscb; 410102684Sgibbs struct ahd_initiator_tinfo *tinfo; 411102684Sgibbs struct ahd_tmode_tstate *tstate; 412102684Sgibbs u_int col_idx; 41397883Sgibbs 41497883Sgibbs if ((ahd->flags & AHD_INITIATORROLE) == 0 41597883Sgibbs && (ccb->ccb_h.func_code == XPT_SCSI_IO 41697883Sgibbs || ccb->ccb_h.func_code == XPT_RESET_DEV)) { 41797883Sgibbs ccb->ccb_h.status = CAM_PROVIDE_FAIL; 41897883Sgibbs xpt_done(ccb); 41997883Sgibbs return; 42097883Sgibbs } 42197883Sgibbs 42297883Sgibbs /* 42397883Sgibbs * get an scb to use. 42497883Sgibbs */ 42597883Sgibbs ahd_lock(ahd, &s); 426102684Sgibbs tinfo = ahd_fetch_transinfo(ahd, 'A', our_id, 427102684Sgibbs target_id, &tstate); 428102684Sgibbs if ((ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) == 0 429102684Sgibbs || (tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ) != 0 430102684Sgibbs || ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) { 431102684Sgibbs col_idx = AHD_NEVER_COL_IDX; 432102684Sgibbs } else { 433102684Sgibbs col_idx = AHD_BUILD_COL_IDX(target_id, 434102684Sgibbs ccb->ccb_h.target_lun); 435102684Sgibbs } 436102684Sgibbs if ((scb = ahd_get_scb(ahd, col_idx)) == NULL) { 43797883Sgibbs 43897883Sgibbs xpt_freeze_simq(sim, /*count*/1); 43997883Sgibbs ahd->flags |= AHD_RESOURCE_SHORTAGE; 44097883Sgibbs ahd_unlock(ahd, &s); 44197883Sgibbs ccb->ccb_h.status = CAM_REQUEUE_REQ; 44297883Sgibbs xpt_done(ccb); 44397883Sgibbs return; 44497883Sgibbs } 44597883Sgibbs ahd_unlock(ahd, &s); 44697883Sgibbs 44797883Sgibbs hscb = scb->hscb; 44897883Sgibbs 44997883Sgibbs CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_SUBTRACE, 45097883Sgibbs ("start scb(%p)\n", scb)); 45197883Sgibbs scb->io_ctx = ccb; 45297883Sgibbs /* 45397883Sgibbs * So we can find the SCB when an abort is requested 45497883Sgibbs */ 45597883Sgibbs ccb->ccb_h.ccb_scb_ptr = scb; 45697883Sgibbs 45797883Sgibbs /* 45897883Sgibbs * Put all the arguments for the xfer in the scb 45997883Sgibbs */ 46097883Sgibbs hscb->control = 0; 46197883Sgibbs hscb->scsiid = BUILD_SCSIID(ahd, sim, target_id, our_id); 46297883Sgibbs hscb->lun = ccb->ccb_h.target_lun; 46397883Sgibbs if (ccb->ccb_h.func_code == XPT_RESET_DEV) { 46497883Sgibbs hscb->cdb_len = 0; 46597883Sgibbs scb->flags |= SCB_DEVICE_RESET; 46697883Sgibbs hscb->control |= MK_MESSAGE; 467109588Sgibbs hscb->task_management = SIU_TASKMGMT_LUN_RESET; 46897883Sgibbs ahd_execute_scb(scb, NULL, 0, 0); 46997883Sgibbs } else { 47097883Sgibbs#ifdef AHD_TARGET_MODE 47197883Sgibbs if (ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) { 47297883Sgibbs struct target_data *tdata; 47397883Sgibbs 47497883Sgibbs tdata = &hscb->shared_data.tdata; 47597883Sgibbs if (ahd->pending_device == lstate) 47697883Sgibbs scb->flags |= SCB_TARGET_IMMEDIATE; 47797883Sgibbs hscb->control |= TARGET_SCB; 47897883Sgibbs tdata->target_phases = 0; 47997883Sgibbs if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) { 48097883Sgibbs tdata->target_phases |= SPHASE_PENDING; 48197883Sgibbs tdata->scsi_status = 48297883Sgibbs ccb->csio.scsi_status; 48397883Sgibbs } 48497883Sgibbs if (ccb->ccb_h.flags & CAM_DIS_DISCONNECT) 48597883Sgibbs tdata->target_phases |= NO_DISCONNECT; 48697883Sgibbs 48797883Sgibbs tdata->initiator_tag = 48897883Sgibbs ahd_htole16(ccb->csio.tag_id); 48997883Sgibbs } 49097883Sgibbs#endif 491109588Sgibbs hscb->task_management = 0; 49297883Sgibbs if (ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) 49397883Sgibbs hscb->control |= ccb->csio.tag_action; 49497883Sgibbs 49597883Sgibbs ahd_setup_data(ahd, sim, &ccb->csio, scb); 49697883Sgibbs } 49797883Sgibbs break; 49897883Sgibbs } 49997883Sgibbs#ifdef AHD_TARGET_MODE 50097883Sgibbs case XPT_NOTIFY_ACK: 50197883Sgibbs case XPT_IMMED_NOTIFY: 50297883Sgibbs { 50397883Sgibbs struct ahd_tmode_tstate *tstate; 50497883Sgibbs struct ahd_tmode_lstate *lstate; 50597883Sgibbs cam_status status; 50697883Sgibbs 50797883Sgibbs status = ahd_find_tmode_devs(ahd, sim, ccb, &tstate, 50897883Sgibbs &lstate, TRUE); 50997883Sgibbs 51097883Sgibbs if (status != CAM_REQ_CMP) { 51197883Sgibbs ccb->ccb_h.status = status; 51297883Sgibbs xpt_done(ccb); 51397883Sgibbs break; 51497883Sgibbs } 51597883Sgibbs SLIST_INSERT_HEAD(&lstate->immed_notifies, &ccb->ccb_h, 51697883Sgibbs sim_links.sle); 51797883Sgibbs ccb->ccb_h.status = CAM_REQ_INPROG; 51897883Sgibbs ahd_send_lstate_events(ahd, lstate); 51997883Sgibbs break; 52097883Sgibbs } 52197883Sgibbs case XPT_EN_LUN: /* Enable LUN as a target */ 52297883Sgibbs ahd_handle_en_lun(ahd, sim, ccb); 52397883Sgibbs xpt_done(ccb); 52497883Sgibbs break; 52597883Sgibbs#endif 52697883Sgibbs case XPT_ABORT: /* Abort the specified CCB */ 52797883Sgibbs { 52897883Sgibbs ahd_abort_ccb(ahd, sim, ccb); 52997883Sgibbs break; 53097883Sgibbs } 53197883Sgibbs case XPT_SET_TRAN_SETTINGS: 53297883Sgibbs { 53397883Sgibbs ahd_lock(ahd, &s); 53497883Sgibbs ahd_set_tran_settings(ahd, SIM_SCSI_ID(ahd, sim), 53597883Sgibbs SIM_CHANNEL(ahd, sim), &ccb->cts); 53697883Sgibbs ahd_unlock(ahd, &s); 53797883Sgibbs xpt_done(ccb); 53897883Sgibbs break; 53997883Sgibbs } 54097883Sgibbs case XPT_GET_TRAN_SETTINGS: 54197883Sgibbs /* Get default/user set transfer settings for the target */ 54297883Sgibbs { 54397883Sgibbs ahd_lock(ahd, &s); 54497883Sgibbs ahd_get_tran_settings(ahd, SIM_SCSI_ID(ahd, sim), 54597883Sgibbs SIM_CHANNEL(ahd, sim), &ccb->cts); 54697883Sgibbs ahd_unlock(ahd, &s); 54797883Sgibbs xpt_done(ccb); 54897883Sgibbs break; 54997883Sgibbs } 55097883Sgibbs case XPT_CALC_GEOMETRY: 55197883Sgibbs { 552123579Sgibbs aic_calc_geometry(&ccb->ccg, ahd->flags & AHD_EXTENDED_TRANS_A); 55397883Sgibbs xpt_done(ccb); 55497883Sgibbs break; 55597883Sgibbs } 55697883Sgibbs case XPT_RESET_BUS: /* Reset the specified SCSI bus */ 55797883Sgibbs { 55897883Sgibbs int found; 55997883Sgibbs 56097883Sgibbs ahd_lock(ahd, &s); 56197883Sgibbs found = ahd_reset_channel(ahd, SIM_CHANNEL(ahd, sim), 56297883Sgibbs /*initiate reset*/TRUE); 56397883Sgibbs ahd_unlock(ahd, &s); 56497883Sgibbs if (bootverbose) { 56597883Sgibbs xpt_print_path(SIM_PATH(ahd, sim)); 56697883Sgibbs printf("SCSI bus reset delivered. " 56797883Sgibbs "%d SCBs aborted.\n", found); 56897883Sgibbs } 56997883Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 57097883Sgibbs xpt_done(ccb); 57197883Sgibbs break; 57297883Sgibbs } 57397883Sgibbs case XPT_TERM_IO: /* Terminate the I/O process */ 57497883Sgibbs /* XXX Implement */ 57597883Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 57697883Sgibbs xpt_done(ccb); 57797883Sgibbs break; 57897883Sgibbs case XPT_PATH_INQ: /* Path routing inquiry */ 57997883Sgibbs { 58097883Sgibbs struct ccb_pathinq *cpi = &ccb->cpi; 58197883Sgibbs 58297883Sgibbs cpi->version_num = 1; /* XXX??? */ 58397883Sgibbs cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE; 58497883Sgibbs if ((ahd->features & AHD_WIDE) != 0) 58597883Sgibbs cpi->hba_inquiry |= PI_WIDE_16; 58697883Sgibbs if ((ahd->features & AHD_TARGETMODE) != 0) { 58797883Sgibbs cpi->target_sprt = PIT_PROCESSOR 58897883Sgibbs | PIT_DISCONNECT 58997883Sgibbs | PIT_TERM_IO; 59097883Sgibbs } else { 59197883Sgibbs cpi->target_sprt = 0; 59297883Sgibbs } 59397883Sgibbs cpi->hba_misc = 0; 59497883Sgibbs cpi->hba_eng_cnt = 0; 59597883Sgibbs cpi->max_target = (ahd->features & AHD_WIDE) ? 15 : 7; 596141978Sgibbs cpi->max_lun = AHD_NUM_LUNS_NONPKT - 1; 59797883Sgibbs cpi->initiator_id = ahd->our_id; 59897883Sgibbs if ((ahd->flags & AHD_RESET_BUS_A) == 0) { 59997883Sgibbs cpi->hba_misc |= PIM_NOBUSRESET; 60097883Sgibbs } 60197883Sgibbs cpi->bus_id = cam_sim_bus(sim); 60297883Sgibbs cpi->base_transfer_speed = 3300; 60397883Sgibbs strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 60497883Sgibbs strncpy(cpi->hba_vid, "Adaptec", HBA_IDLEN); 60597883Sgibbs strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 60697883Sgibbs cpi->unit_number = cam_sim_unit(sim); 60797883Sgibbs#ifdef AHD_NEW_TRAN_SETTINGS 60897883Sgibbs cpi->protocol = PROTO_SCSI; 60997883Sgibbs cpi->protocol_version = SCSI_REV_2; 61097883Sgibbs cpi->transport = XPORT_SPI; 61197883Sgibbs cpi->transport_version = 2; 61297883Sgibbs cpi->xport_specific.spi.ppr_options = SID_SPI_CLOCK_ST; 61397883Sgibbs cpi->transport_version = 4; 61497883Sgibbs cpi->xport_specific.spi.ppr_options = SID_SPI_CLOCK_DT_ST; 61597883Sgibbs#endif 61697883Sgibbs cpi->ccb_h.status = CAM_REQ_CMP; 61797883Sgibbs xpt_done(ccb); 61897883Sgibbs break; 61997883Sgibbs } 62097883Sgibbs default: 62197883Sgibbs ccb->ccb_h.status = CAM_PROVIDE_FAIL; 62297883Sgibbs xpt_done(ccb); 62397883Sgibbs break; 62497883Sgibbs } 62597883Sgibbs} 62697883Sgibbs 62797883Sgibbs 62897883Sgibbsstatic void 62997883Sgibbsahd_set_tran_settings(struct ahd_softc *ahd, int our_id, char channel, 63097883Sgibbs struct ccb_trans_settings *cts) 63197883Sgibbs{ 63297883Sgibbs#ifdef AHD_NEW_TRAN_SETTINGS 63397883Sgibbs struct ahd_devinfo devinfo; 63497883Sgibbs struct ccb_trans_settings_scsi *scsi; 63597883Sgibbs struct ccb_trans_settings_spi *spi; 63697883Sgibbs struct ahd_initiator_tinfo *tinfo; 63797883Sgibbs struct ahd_tmode_tstate *tstate; 63897883Sgibbs uint16_t *discenable; 63997883Sgibbs uint16_t *tagenable; 64097883Sgibbs u_int update_type; 64197883Sgibbs 64297883Sgibbs scsi = &cts->proto_specific.scsi; 64397883Sgibbs spi = &cts->xport_specific.spi; 64497883Sgibbs ahd_compile_devinfo(&devinfo, SIM_SCSI_ID(ahd, sim), 64597883Sgibbs cts->ccb_h.target_id, 64697883Sgibbs cts->ccb_h.target_lun, 64797883Sgibbs SIM_CHANNEL(ahd, sim), 64897883Sgibbs ROLE_UNKNOWN); 64997883Sgibbs tinfo = ahd_fetch_transinfo(ahd, devinfo.channel, 65097883Sgibbs devinfo.our_scsiid, 65197883Sgibbs devinfo.target, &tstate); 65297883Sgibbs update_type = 0; 65397883Sgibbs if (cts->type == CTS_TYPE_CURRENT_SETTINGS) { 65497883Sgibbs update_type |= AHD_TRANS_GOAL; 65597883Sgibbs discenable = &tstate->discenable; 65697883Sgibbs tagenable = &tstate->tagenable; 65797883Sgibbs tinfo->curr.protocol_version = cts->protocol_version; 65897883Sgibbs tinfo->curr.transport_version = cts->transport_version; 65997883Sgibbs tinfo->goal.protocol_version = cts->protocol_version; 66097883Sgibbs tinfo->goal.transport_version = cts->transport_version; 66197883Sgibbs } else if (cts->type == CTS_TYPE_USER_SETTINGS) { 66297883Sgibbs update_type |= AHD_TRANS_USER; 66397883Sgibbs discenable = &ahd->user_discenable; 66497883Sgibbs tagenable = &ahd->user_tagenable; 66597883Sgibbs tinfo->user.protocol_version = cts->protocol_version; 66697883Sgibbs tinfo->user.transport_version = cts->transport_version; 66797883Sgibbs } else { 66897883Sgibbs cts->ccb_h.status = CAM_REQ_INVALID; 66997883Sgibbs return; 67097883Sgibbs } 67197883Sgibbs 67297883Sgibbs if ((spi->valid & CTS_SPI_VALID_DISC) != 0) { 67397883Sgibbs if ((spi->flags & CTS_SPI_FLAGS_DISC_ENB) != 0) 67497883Sgibbs *discenable |= devinfo.target_mask; 67597883Sgibbs else 67697883Sgibbs *discenable &= ~devinfo.target_mask; 67797883Sgibbs } 67897883Sgibbs 67997883Sgibbs if ((scsi->valid & CTS_SCSI_VALID_TQ) != 0) { 68097883Sgibbs if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0) 68197883Sgibbs *tagenable |= devinfo.target_mask; 68297883Sgibbs else 68397883Sgibbs *tagenable &= ~devinfo.target_mask; 68497883Sgibbs } 68597883Sgibbs 68697883Sgibbs if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) { 68797883Sgibbs ahd_validate_width(ahd, /*tinfo limit*/NULL, 68897883Sgibbs &spi->bus_width, ROLE_UNKNOWN); 68997883Sgibbs ahd_set_width(ahd, &devinfo, spi->bus_width, 69097883Sgibbs update_type, /*paused*/FALSE); 69197883Sgibbs } 69297883Sgibbs 69397883Sgibbs if ((spi->valid & CTS_SPI_VALID_PPR_OPTIONS) == 0) { 69497883Sgibbs if (update_type == AHD_TRANS_USER) 69597883Sgibbs spi->ppr_options = tinfo->user.ppr_options; 69697883Sgibbs else 69797883Sgibbs spi->ppr_options = tinfo->goal.ppr_options; 69897883Sgibbs } 69997883Sgibbs 70097883Sgibbs if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) == 0) { 70197883Sgibbs if (update_type == AHD_TRANS_USER) 70297883Sgibbs spi->sync_offset = tinfo->user.offset; 70397883Sgibbs else 70497883Sgibbs spi->sync_offset = tinfo->goal.offset; 70597883Sgibbs } 70697883Sgibbs 70797883Sgibbs if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) == 0) { 70897883Sgibbs if (update_type == AHD_TRANS_USER) 70997883Sgibbs spi->sync_period = tinfo->user.period; 71097883Sgibbs else 71197883Sgibbs spi->sync_period = tinfo->goal.period; 71297883Sgibbs } 71397883Sgibbs 71497883Sgibbs if (((spi->valid & CTS_SPI_VALID_SYNC_RATE) != 0) 71597883Sgibbs || ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0)) { 71697883Sgibbs u_int maxsync; 71797883Sgibbs 71897883Sgibbs maxsync = AHD_SYNCRATE_MAX; 71997883Sgibbs 72097883Sgibbs if (spi->bus_width != MSG_EXT_WDTR_BUS_16_BIT) 72197883Sgibbs spi->ppr_options &= ~MSG_EXT_PPR_DT_REQ; 72297883Sgibbs 72397883Sgibbs if ((*discenable & devinfo.target_mask) == 0) 72497883Sgibbs spi->ppr_options &= ~MSG_EXT_PPR_IU_REQ; 72597883Sgibbs 72697883Sgibbs ahd_find_syncrate(ahd, &spi->sync_period, 72797883Sgibbs &spi->ppr_options, maxsync); 72897883Sgibbs ahd_validate_offset(ahd, /*tinfo limit*/NULL, 72997883Sgibbs spi->sync_period, &spi->sync_offset, 73097883Sgibbs spi->bus_width, ROLE_UNKNOWN); 73197883Sgibbs 73297883Sgibbs /* We use a period of 0 to represent async */ 73397883Sgibbs if (spi->sync_offset == 0) { 73497883Sgibbs spi->sync_period = 0; 73597883Sgibbs spi->ppr_options = 0; 73697883Sgibbs } 73797883Sgibbs 73897883Sgibbs ahd_set_syncrate(ahd, &devinfo, spi->sync_period, 73997883Sgibbs spi->sync_offset, spi->ppr_options, 74097883Sgibbs update_type, /*paused*/FALSE); 74197883Sgibbs } 74297883Sgibbs cts->ccb_h.status = CAM_REQ_CMP; 74397883Sgibbs#else 74497883Sgibbs struct ahd_devinfo devinfo; 74597883Sgibbs struct ahd_initiator_tinfo *tinfo; 74697883Sgibbs struct ahd_tmode_tstate *tstate; 74797883Sgibbs uint16_t *discenable; 74897883Sgibbs uint16_t *tagenable; 74997883Sgibbs u_int update_type; 75097883Sgibbs 75197883Sgibbs ahd_compile_devinfo(&devinfo, SIM_SCSI_ID(ahd, sim), 75297883Sgibbs cts->ccb_h.target_id, 75397883Sgibbs cts->ccb_h.target_lun, 75497883Sgibbs SIM_CHANNEL(ahd, sim), 75597883Sgibbs ROLE_UNKNOWN); 75697883Sgibbs tinfo = ahd_fetch_transinfo(ahd, devinfo.channel, 75797883Sgibbs devinfo.our_scsiid, 75897883Sgibbs devinfo.target, &tstate); 75997883Sgibbs update_type = 0; 76097883Sgibbs if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0) { 76197883Sgibbs update_type |= AHD_TRANS_GOAL; 76297883Sgibbs discenable = &tstate->discenable; 76397883Sgibbs tagenable = &tstate->tagenable; 76497883Sgibbs } else if ((cts->flags & CCB_TRANS_USER_SETTINGS) != 0) { 76597883Sgibbs update_type |= AHD_TRANS_USER; 76697883Sgibbs discenable = &ahd->user_discenable; 76797883Sgibbs tagenable = &ahd->user_tagenable; 76897883Sgibbs } else { 76997883Sgibbs cts->ccb_h.status = CAM_REQ_INVALID; 77097883Sgibbs return; 77197883Sgibbs } 77297883Sgibbs 77397883Sgibbs if ((cts->valid & CCB_TRANS_DISC_VALID) != 0) { 77497883Sgibbs if ((cts->flags & CCB_TRANS_DISC_ENB) != 0) 77597883Sgibbs *discenable |= devinfo.target_mask; 77697883Sgibbs else 77797883Sgibbs *discenable &= ~devinfo.target_mask; 77897883Sgibbs } 77997883Sgibbs 78097883Sgibbs if ((cts->valid & CCB_TRANS_TQ_VALID) != 0) { 78197883Sgibbs if ((cts->flags & CCB_TRANS_TAG_ENB) != 0) 78297883Sgibbs *tagenable |= devinfo.target_mask; 78397883Sgibbs else 78497883Sgibbs *tagenable &= ~devinfo.target_mask; 78597883Sgibbs } 78697883Sgibbs 78797883Sgibbs if ((cts->valid & CCB_TRANS_BUS_WIDTH_VALID) != 0) { 78897883Sgibbs ahd_validate_width(ahd, /*tinfo limit*/NULL, 78997883Sgibbs &cts->bus_width, ROLE_UNKNOWN); 79097883Sgibbs ahd_set_width(ahd, &devinfo, cts->bus_width, 79197883Sgibbs update_type, /*paused*/FALSE); 79297883Sgibbs } 79397883Sgibbs 79497883Sgibbs if ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) == 0) { 79597883Sgibbs if (update_type == AHD_TRANS_USER) 79697883Sgibbs cts->sync_offset = tinfo->user.offset; 79797883Sgibbs else 79897883Sgibbs cts->sync_offset = tinfo->goal.offset; 79997883Sgibbs } 80097883Sgibbs 80197883Sgibbs if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) == 0) { 80297883Sgibbs if (update_type == AHD_TRANS_USER) 80397883Sgibbs cts->sync_period = tinfo->user.period; 80497883Sgibbs else 80597883Sgibbs cts->sync_period = tinfo->goal.period; 80697883Sgibbs } 80797883Sgibbs 80897883Sgibbs if (((cts->valid & CCB_TRANS_SYNC_RATE_VALID) != 0) 809102684Sgibbs || ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0) 810102684Sgibbs || ((cts->valid & CCB_TRANS_TQ_VALID) != 0) 811102684Sgibbs || ((cts->valid & CCB_TRANS_DISC_VALID) != 0)) { 81297883Sgibbs u_int ppr_options; 81397883Sgibbs u_int maxsync; 81497883Sgibbs 81597883Sgibbs maxsync = AHD_SYNCRATE_MAX; 81697883Sgibbs ppr_options = 0; 81797883Sgibbs if (cts->sync_period <= AHD_SYNCRATE_DT 81897883Sgibbs && cts->bus_width == MSG_EXT_WDTR_BUS_16_BIT) { 81997883Sgibbs ppr_options = tinfo->user.ppr_options 82097883Sgibbs | MSG_EXT_PPR_DT_REQ; 82197883Sgibbs } 82297883Sgibbs 823102684Sgibbs if ((*tagenable & devinfo.target_mask) == 0 824102684Sgibbs || (*discenable & devinfo.target_mask) == 0) 825102684Sgibbs ppr_options &= ~MSG_EXT_PPR_IU_REQ; 826102684Sgibbs 82797883Sgibbs ahd_find_syncrate(ahd, &cts->sync_period, 82897883Sgibbs &ppr_options, maxsync); 82997883Sgibbs ahd_validate_offset(ahd, /*tinfo limit*/NULL, 83097883Sgibbs cts->sync_period, &cts->sync_offset, 83197883Sgibbs MSG_EXT_WDTR_BUS_8_BIT, 83297883Sgibbs ROLE_UNKNOWN); 83397883Sgibbs 83497883Sgibbs /* We use a period of 0 to represent async */ 83597883Sgibbs if (cts->sync_offset == 0) { 83697883Sgibbs cts->sync_period = 0; 83797883Sgibbs ppr_options = 0; 83897883Sgibbs } 83997883Sgibbs 84097883Sgibbs if (ppr_options != 0 84197883Sgibbs && tinfo->user.transport_version >= 3) { 84297883Sgibbs tinfo->goal.transport_version = 84397883Sgibbs tinfo->user.transport_version; 84497883Sgibbs tinfo->curr.transport_version = 84597883Sgibbs tinfo->user.transport_version; 84697883Sgibbs } 84797883Sgibbs 84897883Sgibbs ahd_set_syncrate(ahd, &devinfo, cts->sync_period, 84997883Sgibbs cts->sync_offset, ppr_options, 85097883Sgibbs update_type, /*paused*/FALSE); 85197883Sgibbs } 85297883Sgibbs cts->ccb_h.status = CAM_REQ_CMP; 85397883Sgibbs#endif 85497883Sgibbs} 85597883Sgibbs 85697883Sgibbsstatic void 85797883Sgibbsahd_get_tran_settings(struct ahd_softc *ahd, int our_id, char channel, 85897883Sgibbs struct ccb_trans_settings *cts) 85997883Sgibbs{ 86097883Sgibbs#ifdef AHD_NEW_TRAN_SETTINGS 86197883Sgibbs struct ahd_devinfo devinfo; 86297883Sgibbs struct ccb_trans_settings_scsi *scsi; 86397883Sgibbs struct ccb_trans_settings_spi *spi; 86497883Sgibbs struct ahd_initiator_tinfo *targ_info; 86597883Sgibbs struct ahd_tmode_tstate *tstate; 86697883Sgibbs struct ahd_transinfo *tinfo; 86797883Sgibbs 86897883Sgibbs scsi = &cts->proto_specific.scsi; 86997883Sgibbs spi = &cts->xport_specific.spi; 87097883Sgibbs ahd_compile_devinfo(&devinfo, our_id, 87197883Sgibbs cts->ccb_h.target_id, 87297883Sgibbs cts->ccb_h.target_lun, 87397883Sgibbs channel, ROLE_UNKNOWN); 87497883Sgibbs targ_info = ahd_fetch_transinfo(ahd, devinfo.channel, 87597883Sgibbs devinfo.our_scsiid, 87697883Sgibbs devinfo.target, &tstate); 87797883Sgibbs 87897883Sgibbs if (cts->type == CTS_TYPE_CURRENT_SETTINGS) 87997883Sgibbs tinfo = &targ_info->curr; 88097883Sgibbs else 88197883Sgibbs tinfo = &targ_info->user; 88297883Sgibbs 88397883Sgibbs scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 88497883Sgibbs spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB; 88597883Sgibbs if (cts->type == CTS_TYPE_USER_SETTINGS) { 88697883Sgibbs if ((ahd->user_discenable & devinfo.target_mask) != 0) 88797883Sgibbs spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 88897883Sgibbs 88997883Sgibbs if ((ahd->user_tagenable & devinfo.target_mask) != 0) 89097883Sgibbs scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; 89197883Sgibbs } else { 89297883Sgibbs if ((tstate->discenable & devinfo.target_mask) != 0) 89397883Sgibbs spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 89497883Sgibbs 89597883Sgibbs if ((tstate->tagenable & devinfo.target_mask) != 0) 89697883Sgibbs scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; 89797883Sgibbs } 89897883Sgibbs cts->protocol_version = tinfo->protocol_version; 89997883Sgibbs cts->transport_version = tinfo->transport_version; 90097883Sgibbs 90197883Sgibbs spi->sync_period = tinfo->period; 90297883Sgibbs spi->sync_offset = tinfo->offset; 90397883Sgibbs spi->bus_width = tinfo->width; 90497883Sgibbs spi->ppr_options = tinfo->ppr_options; 90597883Sgibbs 90697883Sgibbs cts->protocol = PROTO_SCSI; 90797883Sgibbs cts->transport = XPORT_SPI; 90897883Sgibbs spi->valid = CTS_SPI_VALID_SYNC_RATE 90997883Sgibbs | CTS_SPI_VALID_SYNC_OFFSET 91097883Sgibbs | CTS_SPI_VALID_BUS_WIDTH 91197883Sgibbs | CTS_SPI_VALID_PPR_OPTIONS; 91297883Sgibbs 91397883Sgibbs if (cts->ccb_h.target_lun != CAM_LUN_WILDCARD) { 91497883Sgibbs scsi->valid = CTS_SCSI_VALID_TQ; 91597883Sgibbs spi->valid |= CTS_SPI_VALID_DISC; 91697883Sgibbs } else { 91797883Sgibbs scsi->valid = 0; 91897883Sgibbs } 91997883Sgibbs 92097883Sgibbs cts->ccb_h.status = CAM_REQ_CMP; 92197883Sgibbs#else 92297883Sgibbs struct ahd_devinfo devinfo; 92397883Sgibbs struct ahd_initiator_tinfo *targ_info; 92497883Sgibbs struct ahd_tmode_tstate *tstate; 92597883Sgibbs struct ahd_transinfo *tinfo; 92697883Sgibbs 92797883Sgibbs ahd_compile_devinfo(&devinfo, our_id, 92897883Sgibbs cts->ccb_h.target_id, 92997883Sgibbs cts->ccb_h.target_lun, 93097883Sgibbs channel, ROLE_UNKNOWN); 93197883Sgibbs targ_info = ahd_fetch_transinfo(ahd, devinfo.channel, 93297883Sgibbs devinfo.our_scsiid, 93397883Sgibbs devinfo.target, &tstate); 93497883Sgibbs 93597883Sgibbs if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0) 93697883Sgibbs tinfo = &targ_info->curr; 93797883Sgibbs else 93897883Sgibbs tinfo = &targ_info->user; 93997883Sgibbs 94097883Sgibbs cts->flags &= ~(CCB_TRANS_DISC_ENB|CCB_TRANS_TAG_ENB); 94197883Sgibbs if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) == 0) { 94297883Sgibbs if ((ahd->user_discenable & devinfo.target_mask) != 0) 94397883Sgibbs cts->flags |= CCB_TRANS_DISC_ENB; 94497883Sgibbs 94597883Sgibbs if ((ahd->user_tagenable & devinfo.target_mask) != 0) 94697883Sgibbs cts->flags |= CCB_TRANS_TAG_ENB; 94797883Sgibbs } else { 94897883Sgibbs if ((tstate->discenable & devinfo.target_mask) != 0) 94997883Sgibbs cts->flags |= CCB_TRANS_DISC_ENB; 95097883Sgibbs 95197883Sgibbs if ((tstate->tagenable & devinfo.target_mask) != 0) 95297883Sgibbs cts->flags |= CCB_TRANS_TAG_ENB; 95397883Sgibbs } 95497883Sgibbs cts->sync_period = tinfo->period; 95597883Sgibbs cts->sync_offset = tinfo->offset; 95697883Sgibbs cts->bus_width = tinfo->width; 95797883Sgibbs 95897883Sgibbs cts->valid = CCB_TRANS_SYNC_RATE_VALID 95997883Sgibbs | CCB_TRANS_SYNC_OFFSET_VALID 96097883Sgibbs | CCB_TRANS_BUS_WIDTH_VALID; 96197883Sgibbs 96297883Sgibbs if (cts->ccb_h.target_lun != CAM_LUN_WILDCARD) 96397883Sgibbs cts->valid |= CCB_TRANS_DISC_VALID|CCB_TRANS_TQ_VALID; 96497883Sgibbs 96597883Sgibbs cts->ccb_h.status = CAM_REQ_CMP; 96697883Sgibbs#endif 96797883Sgibbs} 96897883Sgibbs 96997883Sgibbsstatic void 97097883Sgibbsahd_async(void *callback_arg, uint32_t code, struct cam_path *path, void *arg) 97197883Sgibbs{ 97297883Sgibbs struct ahd_softc *ahd; 97397883Sgibbs struct cam_sim *sim; 97497883Sgibbs 97597883Sgibbs sim = (struct cam_sim *)callback_arg; 97697883Sgibbs ahd = (struct ahd_softc *)cam_sim_softc(sim); 97797883Sgibbs switch (code) { 97897883Sgibbs case AC_LOST_DEVICE: 97997883Sgibbs { 98097883Sgibbs struct ahd_devinfo devinfo; 98197883Sgibbs long s; 98297883Sgibbs 98397883Sgibbs ahd_compile_devinfo(&devinfo, SIM_SCSI_ID(ahd, sim), 98497883Sgibbs xpt_path_target_id(path), 98597883Sgibbs xpt_path_lun_id(path), 98697883Sgibbs SIM_CHANNEL(ahd, sim), 98797883Sgibbs ROLE_UNKNOWN); 98897883Sgibbs 98997883Sgibbs /* 99097883Sgibbs * Revert to async/narrow transfers 99197883Sgibbs * for the next device. 99297883Sgibbs */ 99397883Sgibbs ahd_lock(ahd, &s); 99497883Sgibbs ahd_set_width(ahd, &devinfo, MSG_EXT_WDTR_BUS_8_BIT, 99597883Sgibbs AHD_TRANS_GOAL|AHD_TRANS_CUR, /*paused*/FALSE); 99697883Sgibbs ahd_set_syncrate(ahd, &devinfo, /*period*/0, /*offset*/0, 99797883Sgibbs /*ppr_options*/0, AHD_TRANS_GOAL|AHD_TRANS_CUR, 99897883Sgibbs /*paused*/FALSE); 99997883Sgibbs ahd_unlock(ahd, &s); 100097883Sgibbs break; 100197883Sgibbs } 100297883Sgibbs default: 100397883Sgibbs break; 100497883Sgibbs } 100597883Sgibbs} 100697883Sgibbs 100797883Sgibbsstatic void 100897883Sgibbsahd_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments, 100997883Sgibbs int error) 101097883Sgibbs{ 101197883Sgibbs struct scb *scb; 101297883Sgibbs union ccb *ccb; 101397883Sgibbs struct ahd_softc *ahd; 101497883Sgibbs struct ahd_initiator_tinfo *tinfo; 101597883Sgibbs struct ahd_tmode_tstate *tstate; 101697883Sgibbs u_int mask; 101797883Sgibbs u_long s; 101897883Sgibbs 101997883Sgibbs scb = (struct scb *)arg; 102097883Sgibbs ccb = scb->io_ctx; 102197883Sgibbs ahd = scb->ahd_softc; 102297883Sgibbs 102397883Sgibbs if (error != 0) { 102497883Sgibbs if (error == EFBIG) 1025123579Sgibbs aic_set_transaction_status(scb, CAM_REQ_TOO_BIG); 102697883Sgibbs else 1027123579Sgibbs aic_set_transaction_status(scb, CAM_REQ_CMP_ERR); 102897883Sgibbs if (nsegments != 0) 102997883Sgibbs bus_dmamap_unload(ahd->buffer_dmat, scb->dmamap); 103097883Sgibbs ahd_lock(ahd, &s); 103197883Sgibbs ahd_free_scb(ahd, scb); 103297883Sgibbs ahd_unlock(ahd, &s); 103397883Sgibbs xpt_done(ccb); 103497883Sgibbs return; 103597883Sgibbs } 103697883Sgibbs scb->sg_count = 0; 103797883Sgibbs if (nsegments != 0) { 103897883Sgibbs void *sg; 1039115343Sscottl bus_dmasync_op_t op; 104097883Sgibbs u_int i; 104197883Sgibbs 104297883Sgibbs /* Copy the segments into our SG list */ 104397883Sgibbs for (i = nsegments, sg = scb->sg_list; i > 0; i--) { 104497883Sgibbs 104597883Sgibbs sg = ahd_sg_setup(ahd, scb, sg, dm_segs->ds_addr, 104697883Sgibbs dm_segs->ds_len, 104797883Sgibbs /*last*/i == 1); 104897883Sgibbs dm_segs++; 104997883Sgibbs } 105097883Sgibbs 105197883Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) 105297883Sgibbs op = BUS_DMASYNC_PREREAD; 105397883Sgibbs else 105497883Sgibbs op = BUS_DMASYNC_PREWRITE; 105597883Sgibbs 105697883Sgibbs bus_dmamap_sync(ahd->buffer_dmat, scb->dmamap, op); 105797883Sgibbs 105897883Sgibbs if (ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) { 105997883Sgibbs struct target_data *tdata; 106097883Sgibbs 106197883Sgibbs tdata = &scb->hscb->shared_data.tdata; 106297883Sgibbs tdata->target_phases |= DPHASE_PENDING; 106397883Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) 106497883Sgibbs tdata->data_phase = P_DATAOUT; 106597883Sgibbs else 106697883Sgibbs tdata->data_phase = P_DATAIN; 106797883Sgibbs } 106897883Sgibbs } 106997883Sgibbs 107097883Sgibbs ahd_lock(ahd, &s); 107197883Sgibbs 107297883Sgibbs /* 107397883Sgibbs * Last time we need to check if this SCB needs to 107497883Sgibbs * be aborted. 107597883Sgibbs */ 1076123579Sgibbs if (aic_get_transaction_status(scb) != CAM_REQ_INPROG) { 107797883Sgibbs if (nsegments != 0) 107897883Sgibbs bus_dmamap_unload(ahd->buffer_dmat, 107997883Sgibbs scb->dmamap); 108097883Sgibbs ahd_free_scb(ahd, scb); 108197883Sgibbs ahd_unlock(ahd, &s); 108297883Sgibbs xpt_done(ccb); 108397883Sgibbs return; 108497883Sgibbs } 108597883Sgibbs 108697883Sgibbs tinfo = ahd_fetch_transinfo(ahd, SCSIID_CHANNEL(ahd, scb->hscb->scsiid), 108797883Sgibbs SCSIID_OUR_ID(scb->hscb->scsiid), 108897883Sgibbs SCSIID_TARGET(ahd, scb->hscb->scsiid), 108997883Sgibbs &tstate); 109097883Sgibbs 109197883Sgibbs mask = SCB_GET_TARGET_MASK(ahd, scb); 109297883Sgibbs 109397883Sgibbs if ((tstate->discenable & mask) != 0 109497883Sgibbs && (ccb->ccb_h.flags & CAM_DIS_DISCONNECT) == 0) 109597883Sgibbs scb->hscb->control |= DISCENB; 109697883Sgibbs 1097109588Sgibbs if ((tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ) != 0) { 109897883Sgibbs scb->flags |= SCB_PACKETIZED; 1099109588Sgibbs if (scb->hscb->task_management != 0) 1100109588Sgibbs scb->hscb->control &= ~MK_MESSAGE; 1101109588Sgibbs } 110297883Sgibbs 110397883Sgibbs if ((ccb->ccb_h.flags & CAM_NEGOTIATE) != 0 110497883Sgibbs && (tinfo->goal.width != 0 110597883Sgibbs || tinfo->goal.period != 0 110697883Sgibbs || tinfo->goal.ppr_options != 0)) { 110797883Sgibbs scb->flags |= SCB_NEGOTIATE; 110897883Sgibbs scb->hscb->control |= MK_MESSAGE; 110997883Sgibbs } else if ((tstate->auto_negotiate & mask) != 0) { 111097883Sgibbs scb->flags |= SCB_AUTO_NEGOTIATE; 111197883Sgibbs scb->hscb->control |= MK_MESSAGE; 111297883Sgibbs } 111397883Sgibbs 111497883Sgibbs LIST_INSERT_HEAD(&ahd->pending_scbs, scb, pending_links); 111597883Sgibbs 111697883Sgibbs ccb->ccb_h.status |= CAM_SIM_QUEUED; 111797883Sgibbs 1118133911Sgibbs aic_scb_timer_start(scb); 111997883Sgibbs 112097883Sgibbs if ((scb->flags & SCB_TARGET_IMMEDIATE) != 0) { 112197883Sgibbs /* Define a mapping from our tag to the SCB. */ 112297883Sgibbs ahd->scb_data.scbindex[SCB_GET_TAG(scb)] = scb; 112397883Sgibbs ahd_pause(ahd); 112497883Sgibbs ahd_set_scbptr(ahd, SCB_GET_TAG(scb)); 112597883Sgibbs ahd_outb(ahd, RETURN_1, CONT_MSG_LOOP_TARG); 112697883Sgibbs ahd_unpause(ahd); 112797883Sgibbs } else { 112897883Sgibbs ahd_queue_scb(ahd, scb); 112997883Sgibbs } 113097883Sgibbs 113197883Sgibbs ahd_unlock(ahd, &s); 113297883Sgibbs} 113397883Sgibbs 113497883Sgibbsstatic void 113597883Sgibbsahd_poll(struct cam_sim *sim) 113697883Sgibbs{ 113797883Sgibbs ahd_intr(cam_sim_softc(sim)); 113897883Sgibbs} 113997883Sgibbs 114097883Sgibbsstatic void 114197883Sgibbsahd_setup_data(struct ahd_softc *ahd, struct cam_sim *sim, 114297883Sgibbs struct ccb_scsiio *csio, struct scb *scb) 114397883Sgibbs{ 114497883Sgibbs struct hardware_scb *hscb; 114597883Sgibbs struct ccb_hdr *ccb_h; 114697883Sgibbs 114797883Sgibbs hscb = scb->hscb; 114897883Sgibbs ccb_h = &csio->ccb_h; 114997883Sgibbs 115097883Sgibbs csio->resid = 0; 115197883Sgibbs csio->sense_resid = 0; 115297883Sgibbs if (ccb_h->func_code == XPT_SCSI_IO) { 115397883Sgibbs hscb->cdb_len = csio->cdb_len; 115497883Sgibbs if ((ccb_h->flags & CAM_CDB_POINTER) != 0) { 115597883Sgibbs 115697883Sgibbs if (hscb->cdb_len > MAX_CDB_LEN 115797883Sgibbs && (ccb_h->flags & CAM_CDB_PHYS) == 0) { 115897883Sgibbs u_long s; 115997883Sgibbs 1160111653Sgibbs /* 1161111653Sgibbs * Should CAM start to support CDB sizes 1162111653Sgibbs * greater than 16 bytes, we could use 1163111653Sgibbs * the sense buffer to store the CDB. 1164111653Sgibbs */ 1165123579Sgibbs aic_set_transaction_status(scb, 116697883Sgibbs CAM_REQ_INVALID); 116797883Sgibbs ahd_lock(ahd, &s); 116897883Sgibbs ahd_free_scb(ahd, scb); 116997883Sgibbs ahd_unlock(ahd, &s); 117097883Sgibbs xpt_done((union ccb *)csio); 117197883Sgibbs return; 117297883Sgibbs } 117397883Sgibbs if ((ccb_h->flags & CAM_CDB_PHYS) != 0) { 1174111653Sgibbs hscb->shared_data.idata.cdb_from_host.cdbptr = 1175123579Sgibbs aic_htole64((uintptr_t)csio->cdb_io.cdb_ptr); 1176111653Sgibbs hscb->shared_data.idata.cdb_from_host.cdblen = 1177111653Sgibbs csio->cdb_len; 1178111653Sgibbs hscb->cdb_len |= SCB_CDB_LEN_PTR; 117997883Sgibbs } else { 118097883Sgibbs memcpy(hscb->shared_data.idata.cdb, 118197883Sgibbs csio->cdb_io.cdb_ptr, 118297883Sgibbs hscb->cdb_len); 118397883Sgibbs } 118497883Sgibbs } else { 118597883Sgibbs if (hscb->cdb_len > MAX_CDB_LEN) { 118697883Sgibbs u_long s; 118797883Sgibbs 1188123579Sgibbs aic_set_transaction_status(scb, 118997883Sgibbs CAM_REQ_INVALID); 119097883Sgibbs ahd_lock(ahd, &s); 119197883Sgibbs ahd_free_scb(ahd, scb); 119297883Sgibbs ahd_unlock(ahd, &s); 119397883Sgibbs xpt_done((union ccb *)csio); 119497883Sgibbs return; 119597883Sgibbs } 119697883Sgibbs memcpy(hscb->shared_data.idata.cdb, 119797883Sgibbs csio->cdb_io.cdb_bytes, hscb->cdb_len); 119897883Sgibbs } 119997883Sgibbs } 120097883Sgibbs 120197883Sgibbs /* Only use S/G if there is a transfer */ 120297883Sgibbs if ((ccb_h->flags & CAM_DIR_MASK) != CAM_DIR_NONE) { 120397883Sgibbs if ((ccb_h->flags & CAM_SCATTER_VALID) == 0) { 120497883Sgibbs /* We've been given a pointer to a single buffer */ 120597883Sgibbs if ((ccb_h->flags & CAM_DATA_PHYS) == 0) { 120697883Sgibbs int s; 120797883Sgibbs int error; 120897883Sgibbs 120997883Sgibbs s = splsoftvm(); 121097883Sgibbs error = bus_dmamap_load(ahd->buffer_dmat, 121197883Sgibbs scb->dmamap, 121297883Sgibbs csio->data_ptr, 121397883Sgibbs csio->dxfer_len, 121497883Sgibbs ahd_execute_scb, 121597883Sgibbs scb, /*flags*/0); 121697883Sgibbs if (error == EINPROGRESS) { 121797883Sgibbs /* 121897883Sgibbs * So as to maintain ordering, 121997883Sgibbs * freeze the controller queue 122097883Sgibbs * until our mapping is 122197883Sgibbs * returned. 122297883Sgibbs */ 122397883Sgibbs xpt_freeze_simq(sim, 122497883Sgibbs /*count*/1); 122597883Sgibbs scb->io_ctx->ccb_h.status |= 122697883Sgibbs CAM_RELEASE_SIMQ; 122797883Sgibbs } 122897883Sgibbs splx(s); 122997883Sgibbs } else { 123097883Sgibbs struct bus_dma_segment seg; 123197883Sgibbs 123297883Sgibbs /* Pointer to physical buffer */ 123397883Sgibbs if (csio->dxfer_len > AHD_MAXTRANSFER_SIZE) 123497883Sgibbs panic("ahd_setup_data - Transfer size " 123597883Sgibbs "larger than can device max"); 123697883Sgibbs 1237113296Sjake seg.ds_addr = 1238113296Sjake (bus_addr_t)(vm_offset_t)csio->data_ptr; 123997883Sgibbs seg.ds_len = csio->dxfer_len; 124097883Sgibbs ahd_execute_scb(scb, &seg, 1, 0); 124197883Sgibbs } 124297883Sgibbs } else { 124397883Sgibbs struct bus_dma_segment *segs; 124497883Sgibbs 124597883Sgibbs if ((ccb_h->flags & CAM_DATA_PHYS) != 0) 124697883Sgibbs panic("ahd_setup_data - Physical segment " 124797883Sgibbs "pointers unsupported"); 124897883Sgibbs 124997883Sgibbs if ((ccb_h->flags & CAM_SG_LIST_PHYS) == 0) 125097883Sgibbs panic("ahd_setup_data - Virtual segment " 125197883Sgibbs "addresses unsupported"); 125297883Sgibbs 125397883Sgibbs /* Just use the segments provided */ 125497883Sgibbs segs = (struct bus_dma_segment *)csio->data_ptr; 125597883Sgibbs ahd_execute_scb(scb, segs, csio->sglist_cnt, 0); 125697883Sgibbs } 125797883Sgibbs } else { 125897883Sgibbs ahd_execute_scb(scb, NULL, 0, 0); 125997883Sgibbs } 126097883Sgibbs} 126197883Sgibbs 126297883Sgibbsstatic void 126397883Sgibbsahd_abort_ccb(struct ahd_softc *ahd, struct cam_sim *sim, union ccb *ccb) 126497883Sgibbs{ 126597883Sgibbs union ccb *abort_ccb; 126697883Sgibbs 126797883Sgibbs abort_ccb = ccb->cab.abort_ccb; 126897883Sgibbs switch (abort_ccb->ccb_h.func_code) { 126997883Sgibbs#ifdef AHD_TARGET_MODE 127097883Sgibbs case XPT_ACCEPT_TARGET_IO: 127197883Sgibbs case XPT_IMMED_NOTIFY: 127297883Sgibbs case XPT_CONT_TARGET_IO: 127397883Sgibbs { 127497883Sgibbs struct ahd_tmode_tstate *tstate; 127597883Sgibbs struct ahd_tmode_lstate *lstate; 127697883Sgibbs struct ccb_hdr_slist *list; 127797883Sgibbs cam_status status; 127897883Sgibbs 127997883Sgibbs status = ahd_find_tmode_devs(ahd, sim, abort_ccb, &tstate, 128097883Sgibbs &lstate, TRUE); 128197883Sgibbs 128297883Sgibbs if (status != CAM_REQ_CMP) { 128397883Sgibbs ccb->ccb_h.status = status; 128497883Sgibbs break; 128597883Sgibbs } 128697883Sgibbs 128797883Sgibbs if (abort_ccb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) 128897883Sgibbs list = &lstate->accept_tios; 128997883Sgibbs else if (abort_ccb->ccb_h.func_code == XPT_IMMED_NOTIFY) 129097883Sgibbs list = &lstate->immed_notifies; 129197883Sgibbs else 129297883Sgibbs list = NULL; 129397883Sgibbs 129497883Sgibbs if (list != NULL) { 129597883Sgibbs struct ccb_hdr *curelm; 129697883Sgibbs int found; 129797883Sgibbs 129897883Sgibbs curelm = SLIST_FIRST(list); 129997883Sgibbs found = 0; 130097883Sgibbs if (curelm == &abort_ccb->ccb_h) { 130197883Sgibbs found = 1; 130297883Sgibbs SLIST_REMOVE_HEAD(list, sim_links.sle); 130397883Sgibbs } else { 130497883Sgibbs while(curelm != NULL) { 130597883Sgibbs struct ccb_hdr *nextelm; 130697883Sgibbs 130797883Sgibbs nextelm = 130897883Sgibbs SLIST_NEXT(curelm, sim_links.sle); 130997883Sgibbs 131097883Sgibbs if (nextelm == &abort_ccb->ccb_h) { 131197883Sgibbs found = 1; 131297883Sgibbs SLIST_NEXT(curelm, 131397883Sgibbs sim_links.sle) = 131497883Sgibbs SLIST_NEXT(nextelm, 131597883Sgibbs sim_links.sle); 131697883Sgibbs break; 131797883Sgibbs } 131897883Sgibbs curelm = nextelm; 131997883Sgibbs } 132097883Sgibbs } 132197883Sgibbs 132297883Sgibbs if (found) { 132397883Sgibbs abort_ccb->ccb_h.status = CAM_REQ_ABORTED; 132497883Sgibbs xpt_done(abort_ccb); 132597883Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 132697883Sgibbs } else { 132797883Sgibbs xpt_print_path(abort_ccb->ccb_h.path); 132897883Sgibbs printf("Not found\n"); 132997883Sgibbs ccb->ccb_h.status = CAM_PATH_INVALID; 133097883Sgibbs } 133197883Sgibbs break; 133297883Sgibbs } 133397883Sgibbs /* FALLTHROUGH */ 133497883Sgibbs } 133597883Sgibbs#endif 133697883Sgibbs case XPT_SCSI_IO: 133797883Sgibbs /* XXX Fully implement the hard ones */ 133897883Sgibbs ccb->ccb_h.status = CAM_UA_ABORT; 133997883Sgibbs break; 134097883Sgibbs default: 134197883Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 134297883Sgibbs break; 134397883Sgibbs } 134497883Sgibbs xpt_done(ccb); 134597883Sgibbs} 134697883Sgibbs 134797883Sgibbsvoid 134897883Sgibbsahd_send_async(struct ahd_softc *ahd, char channel, u_int target, 134997883Sgibbs u_int lun, ac_code code, void *opt_arg) 135097883Sgibbs{ 135197883Sgibbs struct ccb_trans_settings cts; 135297883Sgibbs struct cam_path *path; 135397883Sgibbs void *arg; 135497883Sgibbs int error; 135597883Sgibbs 135697883Sgibbs arg = NULL; 135797883Sgibbs error = ahd_create_path(ahd, channel, target, lun, &path); 135897883Sgibbs 135997883Sgibbs if (error != CAM_REQ_CMP) 136097883Sgibbs return; 136197883Sgibbs 136297883Sgibbs switch (code) { 136397883Sgibbs case AC_TRANSFER_NEG: 136497883Sgibbs { 136597883Sgibbs#ifdef AHD_NEW_TRAN_SETTINGS 136697883Sgibbs struct ccb_trans_settings_scsi *scsi; 136797883Sgibbs 136897883Sgibbs cts.type = CTS_TYPE_CURRENT_SETTINGS; 136997883Sgibbs scsi = &cts.proto_specific.scsi; 137097883Sgibbs#else 137197883Sgibbs cts.flags = CCB_TRANS_CURRENT_SETTINGS; 137297883Sgibbs#endif 137397883Sgibbs cts.ccb_h.path = path; 137497883Sgibbs cts.ccb_h.target_id = target; 137597883Sgibbs cts.ccb_h.target_lun = lun; 137697883Sgibbs ahd_get_tran_settings(ahd, ahd->our_id, channel, &cts); 137797883Sgibbs arg = &cts; 137897883Sgibbs#ifdef AHD_NEW_TRAN_SETTINGS 137997883Sgibbs scsi->valid &= ~CTS_SCSI_VALID_TQ; 138097883Sgibbs scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 138197883Sgibbs#else 138297883Sgibbs cts.valid &= ~CCB_TRANS_TQ_VALID; 138397883Sgibbs cts.flags &= ~CCB_TRANS_TAG_ENB; 138497883Sgibbs#endif 138597883Sgibbs if (opt_arg == NULL) 138697883Sgibbs break; 138797883Sgibbs if (*((ahd_queue_alg *)opt_arg) == AHD_QUEUE_TAGGED) 138897883Sgibbs#ifdef AHD_NEW_TRAN_SETTINGS 138997883Sgibbs scsi->flags |= ~CTS_SCSI_FLAGS_TAG_ENB; 139097883Sgibbs scsi->valid |= CTS_SCSI_VALID_TQ; 139197883Sgibbs#else 139297883Sgibbs cts.flags |= CCB_TRANS_TAG_ENB; 139397883Sgibbs cts.valid |= CCB_TRANS_TQ_VALID; 139497883Sgibbs#endif 139597883Sgibbs break; 139697883Sgibbs } 139797883Sgibbs case AC_SENT_BDR: 139897883Sgibbs case AC_BUS_RESET: 139997883Sgibbs break; 140097883Sgibbs default: 140197883Sgibbs panic("ahd_send_async: Unexpected async event"); 140297883Sgibbs } 140397883Sgibbs xpt_async(code, path, arg); 140497883Sgibbs xpt_free_path(path); 140597883Sgibbs} 140697883Sgibbs 140797883Sgibbsvoid 140897883Sgibbsahd_platform_set_tags(struct ahd_softc *ahd, 140997883Sgibbs struct ahd_devinfo *devinfo, int enable) 141097883Sgibbs{ 141197883Sgibbs} 141297883Sgibbs 141397883Sgibbsint 141497883Sgibbsahd_platform_alloc(struct ahd_softc *ahd, void *platform_arg) 141597883Sgibbs{ 141697883Sgibbs ahd->platform_data = malloc(sizeof(struct ahd_platform_data), M_DEVBUF, 141797883Sgibbs M_NOWAIT | M_ZERO); 141897883Sgibbs if (ahd->platform_data == NULL) 141997883Sgibbs return (ENOMEM); 142097883Sgibbs return (0); 142197883Sgibbs} 142297883Sgibbs 142397883Sgibbsvoid 142497883Sgibbsahd_platform_free(struct ahd_softc *ahd) 142597883Sgibbs{ 142697883Sgibbs struct ahd_platform_data *pdata; 142797883Sgibbs 142897883Sgibbs pdata = ahd->platform_data; 142997883Sgibbs if (pdata != NULL) { 143097883Sgibbs if (pdata->regs[0] != NULL) 143197883Sgibbs bus_release_resource(ahd->dev_softc, 143297883Sgibbs pdata->regs_res_type[0], 143397883Sgibbs pdata->regs_res_id[0], 143497883Sgibbs pdata->regs[0]); 143597883Sgibbs 143697883Sgibbs if (pdata->regs[1] != NULL) 143797883Sgibbs bus_release_resource(ahd->dev_softc, 143897883Sgibbs pdata->regs_res_type[1], 143997883Sgibbs pdata->regs_res_id[1], 144097883Sgibbs pdata->regs[1]); 144197883Sgibbs 144297883Sgibbs if (pdata->irq != NULL) 144397883Sgibbs bus_release_resource(ahd->dev_softc, 144497883Sgibbs pdata->irq_res_type, 144597883Sgibbs 0, pdata->irq); 144697883Sgibbs 144797883Sgibbs if (pdata->sim != NULL) { 144897883Sgibbs xpt_async(AC_LOST_DEVICE, pdata->path, NULL); 144997883Sgibbs xpt_free_path(pdata->path); 145097883Sgibbs xpt_bus_deregister(cam_sim_path(pdata->sim)); 145197883Sgibbs cam_sim_free(pdata->sim, /*free_devq*/TRUE); 145297883Sgibbs } 145397883Sgibbs if (pdata->eh != NULL) 145497883Sgibbs EVENTHANDLER_DEREGISTER(shutdown_final, pdata->eh); 145597883Sgibbs free(ahd->platform_data, M_DEVBUF); 145697883Sgibbs } 145797883Sgibbs} 145897883Sgibbs 145997883Sgibbsint 146097883Sgibbsahd_softc_comp(struct ahd_softc *lahd, struct ahd_softc *rahd) 146197883Sgibbs{ 146297883Sgibbs /* We don't sort softcs under FreeBSD so report equal always */ 146397883Sgibbs return (0); 146497883Sgibbs} 146597883Sgibbs 146697883Sgibbsint 146797883Sgibbsahd_detach(device_t dev) 146897883Sgibbs{ 146997883Sgibbs struct ahd_softc *ahd; 147097883Sgibbs u_long l; 147197883Sgibbs u_long s; 147297883Sgibbs 147397883Sgibbs ahd_list_lock(&l); 147497883Sgibbs device_printf(dev, "detaching device\n"); 147597883Sgibbs ahd = device_get_softc(dev); 147697883Sgibbs ahd = ahd_find_softc(ahd); 147797883Sgibbs if (ahd == NULL) { 147897883Sgibbs device_printf(dev, "aic7xxx already detached\n"); 147997883Sgibbs ahd_list_unlock(&l); 148097883Sgibbs return (ENOENT); 148197883Sgibbs } 1482123579Sgibbs TAILQ_REMOVE(&ahd_tailq, ahd, links); 1483123579Sgibbs ahd_list_unlock(&l); 148497883Sgibbs ahd_lock(ahd, &s); 148597883Sgibbs ahd_intr_enable(ahd, FALSE); 148697883Sgibbs bus_teardown_intr(dev, ahd->platform_data->irq, ahd->platform_data->ih); 148797883Sgibbs ahd_unlock(ahd, &s); 148897883Sgibbs ahd_free(ahd); 148997883Sgibbs return (0); 149097883Sgibbs} 149197883Sgibbs 149297883Sgibbs#if UNUSED 149397883Sgibbsstatic void 149497883Sgibbsahd_dump_targcmd(struct target_cmd *cmd) 149597883Sgibbs{ 149697883Sgibbs uint8_t *byte; 149797883Sgibbs uint8_t *last_byte; 149897883Sgibbs int i; 149997883Sgibbs 150097883Sgibbs byte = &cmd->initiator_channel; 150197883Sgibbs /* Debugging info for received commands */ 150297883Sgibbs last_byte = &cmd[1].initiator_channel; 150397883Sgibbs 150497883Sgibbs i = 0; 150597883Sgibbs while (byte < last_byte) { 150697883Sgibbs if (i == 0) 150797883Sgibbs printf("\t"); 150897883Sgibbs printf("%#x", *byte++); 150997883Sgibbs i++; 151097883Sgibbs if (i == 8) { 151197883Sgibbs printf("\n"); 151297883Sgibbs i = 0; 151397883Sgibbs } else { 151497883Sgibbs printf(", "); 151597883Sgibbs } 151697883Sgibbs } 151797883Sgibbs} 151897883Sgibbs#endif 151997883Sgibbs 152097883Sgibbsstatic int 152197883Sgibbsahd_modevent(module_t mod, int type, void *data) 152297883Sgibbs{ 152397883Sgibbs /* XXX Deal with busy status on unload. */ 1524132199Sphk /* XXX Deal with unknown events */ 152597883Sgibbs return 0; 152697883Sgibbs} 152797883Sgibbs 152897883Sgibbsstatic moduledata_t ahd_mod = { 152997883Sgibbs "ahd", 153097883Sgibbs ahd_modevent, 153197883Sgibbs NULL 153297883Sgibbs}; 153397883Sgibbs 153497883Sgibbs/********************************** DDB Hooks *********************************/ 153597883Sgibbs#ifdef DDB 153697883Sgibbsstatic struct ahd_softc *ahd_ddb_softc; 153797883Sgibbsstatic int ahd_ddb_paused; 153897883Sgibbsstatic int ahd_ddb_paused_on_entry; 1539133122SgibbsDB_COMMAND(ahd_sunit, ahd_ddb_sunit) 154097883Sgibbs{ 154197883Sgibbs struct ahd_softc *list_ahd; 154297883Sgibbs 154397883Sgibbs ahd_ddb_softc = NULL; 154497883Sgibbs TAILQ_FOREACH(list_ahd, &ahd_tailq, links) { 154597883Sgibbs if (list_ahd->unit == addr) 154697883Sgibbs ahd_ddb_softc = list_ahd; 154797883Sgibbs } 154897883Sgibbs if (ahd_ddb_softc == NULL) 154997883Sgibbs db_error("No matching softc found!\n"); 155097883Sgibbs} 155197883Sgibbs 155297883SgibbsDB_COMMAND(ahd_pause, ahd_ddb_pause) 155397883Sgibbs{ 155497883Sgibbs if (ahd_ddb_softc == NULL) { 1555133122Sgibbs db_error("Must set unit with ahd_sunit first!\n"); 155697883Sgibbs return; 155797883Sgibbs } 155897883Sgibbs if (ahd_ddb_paused == 0) { 155997883Sgibbs ahd_ddb_paused++; 156097883Sgibbs if (ahd_is_paused(ahd_ddb_softc)) { 156197883Sgibbs ahd_ddb_paused_on_entry++; 156297883Sgibbs return; 156397883Sgibbs } 156497883Sgibbs ahd_pause(ahd_ddb_softc); 156597883Sgibbs } 156697883Sgibbs} 156797883Sgibbs 156897883SgibbsDB_COMMAND(ahd_unpause, ahd_ddb_unpause) 156997883Sgibbs{ 157097883Sgibbs if (ahd_ddb_softc == NULL) { 1571133122Sgibbs db_error("Must set unit with ahd_sunit first!\n"); 157297883Sgibbs return; 157397883Sgibbs } 157497883Sgibbs if (ahd_ddb_paused != 0) { 157597883Sgibbs ahd_ddb_paused = 0; 157697883Sgibbs if (ahd_ddb_paused_on_entry) 157797883Sgibbs return; 157897883Sgibbs ahd_unpause(ahd_ddb_softc); 157997883Sgibbs } else if (ahd_ddb_paused_on_entry != 0) { 158097883Sgibbs /* Two unpauses to clear a paused on entry. */ 158197883Sgibbs ahd_ddb_paused_on_entry = 0; 158297883Sgibbs ahd_unpause(ahd_ddb_softc); 158397883Sgibbs } 158497883Sgibbs} 158597883Sgibbs 158697883SgibbsDB_COMMAND(ahd_in, ahd_ddb_in) 158797883Sgibbs{ 158897883Sgibbs int c; 158997883Sgibbs int size; 159097883Sgibbs 159197883Sgibbs if (ahd_ddb_softc == NULL) { 1592133122Sgibbs db_error("Must set unit with ahd_sunit first!\n"); 159397883Sgibbs return; 159497883Sgibbs } 159597883Sgibbs if (have_addr == 0) 159697883Sgibbs return; 159797883Sgibbs 159897883Sgibbs size = 1; 159997883Sgibbs while ((c = *modif++) != '\0') { 160097883Sgibbs switch (c) { 160197883Sgibbs case 'b': 160297883Sgibbs size = 1; 160397883Sgibbs break; 160497883Sgibbs case 'w': 160597883Sgibbs size = 2; 160697883Sgibbs break; 160797883Sgibbs case 'l': 160897883Sgibbs size = 4; 160997883Sgibbs break; 161097883Sgibbs } 161197883Sgibbs } 161297883Sgibbs 161397883Sgibbs if (count <= 0) 161497883Sgibbs count = 1; 161597883Sgibbs while (--count >= 0) { 1616107368Sscottl db_printf("%04lx (M)%x: \t", (u_long)addr, 161797883Sgibbs ahd_inb(ahd_ddb_softc, MODE_PTR)); 161897883Sgibbs switch (size) { 161997883Sgibbs case 1: 162097883Sgibbs db_printf("%02x\n", ahd_inb(ahd_ddb_softc, addr)); 162197883Sgibbs break; 162297883Sgibbs case 2: 162397883Sgibbs db_printf("%04x\n", ahd_inw(ahd_ddb_softc, addr)); 162497883Sgibbs break; 162597883Sgibbs case 4: 162697883Sgibbs db_printf("%08x\n", ahd_inl(ahd_ddb_softc, addr)); 162797883Sgibbs break; 162897883Sgibbs } 162997883Sgibbs } 163097883Sgibbs} 163197883Sgibbs 163297883SgibbsDB_SET(ahd_out, ahd_ddb_out, db_cmd_set, CS_MORE, NULL) 163397883Sgibbs{ 163497883Sgibbs db_expr_t old_value; 163597883Sgibbs db_expr_t new_value; 163697883Sgibbs int size; 163797883Sgibbs 163897883Sgibbs if (ahd_ddb_softc == NULL) { 1639133122Sgibbs db_error("Must set unit with ahd_sunit first!\n"); 164097883Sgibbs return; 164197883Sgibbs } 164297883Sgibbs 164397883Sgibbs switch (modif[0]) { 164497883Sgibbs case '\0': 164597883Sgibbs case 'b': 164697883Sgibbs size = 1; 164797883Sgibbs break; 164897883Sgibbs case 'h': 164997883Sgibbs size = 2; 165097883Sgibbs break; 165197883Sgibbs case 'l': 165297883Sgibbs size = 4; 165397883Sgibbs break; 165497883Sgibbs default: 165597883Sgibbs db_error("Unknown size\n"); 165697883Sgibbs return; 165797883Sgibbs } 165897883Sgibbs 165997883Sgibbs while (db_expression(&new_value)) { 166097883Sgibbs switch (size) { 166197883Sgibbs default: 166297883Sgibbs case 1: 166397883Sgibbs old_value = ahd_inb(ahd_ddb_softc, addr); 166497883Sgibbs ahd_outb(ahd_ddb_softc, addr, new_value); 166597883Sgibbs break; 166697883Sgibbs case 2: 166797883Sgibbs old_value = ahd_inw(ahd_ddb_softc, addr); 166897883Sgibbs ahd_outw(ahd_ddb_softc, addr, new_value); 166997883Sgibbs break; 167097883Sgibbs case 4: 167197883Sgibbs old_value = ahd_inl(ahd_ddb_softc, addr); 167297883Sgibbs ahd_outl(ahd_ddb_softc, addr, new_value); 167397883Sgibbs break; 167497883Sgibbs } 1675107368Sscottl db_printf("%04lx (M)%x: \t0x%lx\t=\t0x%lx", 1676107368Sscottl (u_long)addr, ahd_inb(ahd_ddb_softc, MODE_PTR), 1677107368Sscottl (u_long)old_value, (u_long)new_value); 167897883Sgibbs addr += size; 167997883Sgibbs } 168097883Sgibbs db_skip_to_eol(); 168197883Sgibbs} 168297883Sgibbs 1683133122SgibbsDB_COMMAND(ahd_dump, ahd_ddb_dump) 1684133122Sgibbs{ 1685133122Sgibbs if (ahd_ddb_softc == NULL) { 1686133122Sgibbs db_error("Must set unit with ahd_sunit first!\n"); 1687133122Sgibbs return; 1688133122Sgibbs } 1689133122Sgibbs ahd_dump_card_state(ahd_ddb_softc); 1690133122Sgibbs} 1691133122Sgibbs 169297883Sgibbs#endif 169397883Sgibbs 169497883Sgibbs 169597883SgibbsDECLARE_MODULE(ahd, ahd_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); 169697883SgibbsMODULE_DEPEND(ahd, cam, 1, 1, 1); 169797883SgibbsMODULE_VERSION(ahd, 1); 1698