aic79xx_osm.c revision 111653
197883Sgibbs/* 297883Sgibbs * Bus independent FreeBSD shim for the aic7xxx based adaptec SCSI controllers 397883Sgibbs * 4102684Sgibbs * Copyright (c) 1994-2002 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 * 32111653Sgibbs * $Id: //depot/aic7xxx/freebsd/dev/aic7xxx/aic79xx_osm.c#26 $ 3397883Sgibbs * 3497883Sgibbs * $FreeBSD: head/sys/dev/aic7xxx/aic79xx_osm.c 111653 2003-02-27 23:23:16Z gibbs $ 3597883Sgibbs */ 3697883Sgibbs 3797883Sgibbs#include <dev/aic7xxx/aic79xx_osm.h> 3897883Sgibbs#include <dev/aic7xxx/aic79xx_inline.h> 3997883Sgibbs 4097883Sgibbs#include "opt_ddb.h" 4197883Sgibbs#ifdef DDB 4297883Sgibbs#include <ddb/ddb.h> 4397883Sgibbs#endif 4497883Sgibbs 4597883Sgibbs#ifndef AHD_TMODE_ENABLE 4697883Sgibbs#define AHD_TMODE_ENABLE 0 4797883Sgibbs#endif 4897883Sgibbs 4997883Sgibbs#define ccb_scb_ptr spriv_ptr0 5097883Sgibbs 5197883Sgibbs#if UNUSED 5297883Sgibbsstatic void ahd_dump_targcmd(struct target_cmd *cmd); 5397883Sgibbs#endif 5497883Sgibbsstatic int ahd_modevent(module_t mod, int type, void *data); 5597883Sgibbsstatic void ahd_action(struct cam_sim *sim, union ccb *ccb); 5697883Sgibbsstatic void ahd_set_tran_settings(struct ahd_softc *ahd, 5797883Sgibbs int our_id, char channel, 5897883Sgibbs struct ccb_trans_settings *cts); 5997883Sgibbsstatic void ahd_get_tran_settings(struct ahd_softc *ahd, 6097883Sgibbs int our_id, char channel, 6197883Sgibbs struct ccb_trans_settings *cts); 6297883Sgibbsstatic void ahd_async(void *callback_arg, uint32_t code, 6397883Sgibbs struct cam_path *path, void *arg); 6497883Sgibbsstatic void ahd_execute_scb(void *arg, bus_dma_segment_t *dm_segs, 6597883Sgibbs int nsegments, int error); 6697883Sgibbsstatic void ahd_poll(struct cam_sim *sim); 6797883Sgibbsstatic void ahd_setup_data(struct ahd_softc *ahd, struct cam_sim *sim, 6897883Sgibbs struct ccb_scsiio *csio, struct scb *scb); 6997883Sgibbsstatic void ahd_abort_ccb(struct ahd_softc *ahd, struct cam_sim *sim, 7097883Sgibbs union ccb *ccb); 7197883Sgibbsstatic int ahd_create_path(struct ahd_softc *ahd, 7297883Sgibbs char channel, u_int target, u_int lun, 7397883Sgibbs struct cam_path **path); 7497883Sgibbs 7597883Sgibbs#if NOT_YET 7697883Sgibbsstatic void ahd_set_recoveryscb(struct ahd_softc *ahd, struct scb *scb); 7797883Sgibbs#endif 7897883Sgibbs 7997883Sgibbsstatic int 8097883Sgibbsahd_create_path(struct ahd_softc *ahd, char channel, u_int target, 8197883Sgibbs u_int lun, struct cam_path **path) 8297883Sgibbs{ 8397883Sgibbs path_id_t path_id; 8497883Sgibbs 8597883Sgibbs if (channel == 'B') 8697883Sgibbs path_id = cam_sim_path(ahd->platform_data->sim_b); 8797883Sgibbs else 8897883Sgibbs path_id = cam_sim_path(ahd->platform_data->sim); 8997883Sgibbs 9097883Sgibbs return (xpt_create_path(path, /*periph*/NULL, 9197883Sgibbs path_id, target, lun)); 9297883Sgibbs} 9397883Sgibbs 9497883Sgibbsint 9597883Sgibbsahd_map_int(struct ahd_softc *ahd) 9697883Sgibbs{ 9797883Sgibbs int error; 9897883Sgibbs 9997883Sgibbs /* Hook up our interrupt handler */ 10097883Sgibbs error = bus_setup_intr(ahd->dev_softc, ahd->platform_data->irq, 10197883Sgibbs INTR_TYPE_CAM, ahd_platform_intr, ahd, 10297883Sgibbs &ahd->platform_data->ih); 10397883Sgibbs if (error != 0) 10497883Sgibbs device_printf(ahd->dev_softc, "bus_setup_intr() failed: %d\n", 10597883Sgibbs error); 10697883Sgibbs return (error); 10797883Sgibbs} 10897883Sgibbs 10997883Sgibbs/* 11097883Sgibbs * Attach all the sub-devices we can find 11197883Sgibbs */ 11297883Sgibbsint 11397883Sgibbsahd_attach(struct ahd_softc *ahd) 11497883Sgibbs{ 11597883Sgibbs char ahd_info[256]; 11697883Sgibbs struct ccb_setasync csa; 11797883Sgibbs struct cam_devq *devq; 11897883Sgibbs struct cam_sim *sim; 11997883Sgibbs struct cam_path *path; 12097883Sgibbs long s; 12197883Sgibbs int count; 12297883Sgibbs 12397883Sgibbs count = 0; 12497883Sgibbs sim = NULL; 12597883Sgibbs 12697883Sgibbs ahd_controller_info(ahd, ahd_info); 12797883Sgibbs printf("%s\n", ahd_info); 12897883Sgibbs ahd_lock(ahd, &s); 12997883Sgibbs 13097883Sgibbs /* 13197883Sgibbs * Create the device queue for our SIM(s). 13297883Sgibbs */ 13397883Sgibbs devq = cam_simq_alloc(AHD_MAX_QUEUE); 13497883Sgibbs if (devq == NULL) 13597883Sgibbs goto fail; 13697883Sgibbs 13797883Sgibbs /* 13897883Sgibbs * Construct our SIM entry 13997883Sgibbs */ 14097883Sgibbs sim = cam_sim_alloc(ahd_action, ahd_poll, "ahd", ahd, 14197883Sgibbs device_get_unit(ahd->dev_softc), 14297883Sgibbs 1, /*XXX*/256, devq); 14397883Sgibbs if (sim == NULL) { 14497883Sgibbs cam_simq_free(devq); 14597883Sgibbs goto fail; 14697883Sgibbs } 14797883Sgibbs 14897883Sgibbs if (xpt_bus_register(sim, /*bus_id*/0) != CAM_SUCCESS) { 14997883Sgibbs cam_sim_free(sim, /*free_devq*/TRUE); 15097883Sgibbs sim = NULL; 15197883Sgibbs goto fail; 15297883Sgibbs } 15397883Sgibbs 15497883Sgibbs if (xpt_create_path(&path, /*periph*/NULL, 15597883Sgibbs cam_sim_path(sim), CAM_TARGET_WILDCARD, 15697883Sgibbs CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 15797883Sgibbs xpt_bus_deregister(cam_sim_path(sim)); 15897883Sgibbs cam_sim_free(sim, /*free_devq*/TRUE); 15997883Sgibbs sim = NULL; 16097883Sgibbs goto fail; 16197883Sgibbs } 16297883Sgibbs 16397883Sgibbs xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5); 16497883Sgibbs csa.ccb_h.func_code = XPT_SASYNC_CB; 16597883Sgibbs csa.event_enable = AC_LOST_DEVICE; 16697883Sgibbs csa.callback = ahd_async; 16797883Sgibbs csa.callback_arg = sim; 16897883Sgibbs xpt_action((union ccb *)&csa); 16997883Sgibbs count++; 17097883Sgibbs 17197883Sgibbsfail: 17297883Sgibbs ahd->platform_data->sim = sim; 17397883Sgibbs ahd->platform_data->path = path; 174102684Sgibbs if (count != 0) { 17597883Sgibbs /* We have to wait until after any system dumps... */ 17697883Sgibbs ahd->platform_data->eh = 17797883Sgibbs EVENTHANDLER_REGISTER(shutdown_final, ahd_shutdown, 17897883Sgibbs ahd, SHUTDOWN_PRI_DEFAULT); 179102684Sgibbs ahd_intr_enable(ahd, TRUE); 180102684Sgibbs } 18197883Sgibbs 182102684Sgibbs ahd_unlock(ahd, &s); 183102684Sgibbs 18497883Sgibbs return (count); 18597883Sgibbs} 18697883Sgibbs 18797883Sgibbs/* 18897883Sgibbs * Catch an interrupt from the adapter 18997883Sgibbs */ 19097883Sgibbsvoid 19197883Sgibbsahd_platform_intr(void *arg) 19297883Sgibbs{ 19397883Sgibbs struct ahd_softc *ahd; 19497883Sgibbs 19597883Sgibbs ahd = (struct ahd_softc *)arg; 19697883Sgibbs ahd_intr(ahd); 19797883Sgibbs} 19897883Sgibbs 19997883Sgibbs/* 20097883Sgibbs * We have an scb which has been processed by the 20197883Sgibbs * adaptor, now we look to see how the operation 20297883Sgibbs * went. 20397883Sgibbs */ 20497883Sgibbsvoid 20597883Sgibbsahd_done(struct ahd_softc *ahd, struct scb *scb) 20697883Sgibbs{ 20797883Sgibbs union ccb *ccb; 20897883Sgibbs 20997883Sgibbs CAM_DEBUG(scb->io_ctx->ccb_h.path, CAM_DEBUG_TRACE, 21097883Sgibbs ("ahd_done - scb %d\n", SCB_GET_TAG(scb))); 21197883Sgibbs 21297883Sgibbs ccb = scb->io_ctx; 21397883Sgibbs LIST_REMOVE(scb, pending_links); 21497883Sgibbs 21597883Sgibbs untimeout(ahd_timeout, (caddr_t)scb, ccb->ccb_h.timeout_ch); 21697883Sgibbs 21797883Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) { 21897883Sgibbs bus_dmasync_op_t op; 21997883Sgibbs 22097883Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) 22197883Sgibbs op = BUS_DMASYNC_POSTREAD; 22297883Sgibbs else 22397883Sgibbs op = BUS_DMASYNC_POSTWRITE; 22497883Sgibbs bus_dmamap_sync(ahd->buffer_dmat, scb->dmamap, op); 22597883Sgibbs bus_dmamap_unload(ahd->buffer_dmat, scb->dmamap); 22697883Sgibbs } 22797883Sgibbs 22897883Sgibbs#ifdef AHD_TARGET_MODE 22997883Sgibbs if (ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) { 23097883Sgibbs struct cam_path *ccb_path; 23197883Sgibbs 23297883Sgibbs /* 23397883Sgibbs * If we have finally disconnected, clean up our 23497883Sgibbs * pending device state. 23597883Sgibbs * XXX - There may be error states that cause where 23697883Sgibbs * we will remain connected. 23797883Sgibbs */ 23897883Sgibbs ccb_path = ccb->ccb_h.path; 23997883Sgibbs if (ahd->pending_device != NULL 24097883Sgibbs && xpt_path_comp(ahd->pending_device->path, ccb_path) == 0) { 24197883Sgibbs 24297883Sgibbs if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) { 24397883Sgibbs ahd->pending_device = NULL; 24497883Sgibbs } else { 24597883Sgibbs xpt_print_path(ccb->ccb_h.path); 24697883Sgibbs printf("Still disconnected\n"); 24797883Sgibbs ahd_freeze_ccb(ccb); 24897883Sgibbs } 24997883Sgibbs } 25097883Sgibbs 25197883Sgibbs if (ahd_get_transaction_status(scb) == CAM_REQ_INPROG) 25297883Sgibbs ccb->ccb_h.status |= CAM_REQ_CMP; 25397883Sgibbs ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 25497883Sgibbs ahd_free_scb(ahd, scb); 25597883Sgibbs xpt_done(ccb); 25697883Sgibbs return; 25797883Sgibbs } 25897883Sgibbs#endif 25997883Sgibbs 26097883Sgibbs /* 26197883Sgibbs * If the recovery SCB completes, we have to be 26297883Sgibbs * out of our timeout. 26397883Sgibbs */ 26497883Sgibbs if ((scb->flags & SCB_RECOVERY_SCB) != 0) { 26597883Sgibbs struct scb *list_scb; 26697883Sgibbs 26797883Sgibbs /* 26897883Sgibbs * We were able to complete the command successfully, 26997883Sgibbs * so reinstate the timeouts for all other pending 27097883Sgibbs * commands. 27197883Sgibbs */ 27297883Sgibbs LIST_FOREACH(list_scb, &ahd->pending_scbs, pending_links) { 27397883Sgibbs union ccb *ccb; 27497883Sgibbs uint64_t time; 27597883Sgibbs 27697883Sgibbs ccb = list_scb->io_ctx; 27797883Sgibbs if (ccb->ccb_h.timeout == CAM_TIME_INFINITY) 27897883Sgibbs continue; 27997883Sgibbs 28097883Sgibbs time = ccb->ccb_h.timeout; 28197883Sgibbs time *= hz; 28297883Sgibbs time /= 1000; 28397883Sgibbs ccb->ccb_h.timeout_ch = 28497883Sgibbs timeout(ahd_timeout, list_scb, time); 28597883Sgibbs } 28697883Sgibbs 28797883Sgibbs if (ahd_get_transaction_status(scb) == CAM_BDR_SENT 28897883Sgibbs || ahd_get_transaction_status(scb) == CAM_REQ_ABORTED) 28997883Sgibbs ahd_set_transaction_status(scb, CAM_CMD_TIMEOUT); 29097883Sgibbs ahd_print_path(ahd, scb); 29197883Sgibbs printf("no longer in timeout, status = %x\n", 29297883Sgibbs ccb->ccb_h.status); 29397883Sgibbs } 29497883Sgibbs 29597883Sgibbs /* Don't clobber any existing error state */ 29697883Sgibbs if (ahd_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 long s; 35397883Sgibbs 35497883Sgibbs CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("ahd_action\n")); 35597883Sgibbs 35697883Sgibbs ahd = (struct ahd_softc *)cam_sim_softc(sim); 35797883Sgibbs 35897883Sgibbs target_id = ccb->ccb_h.target_id; 35997883Sgibbs our_id = SIM_SCSI_ID(ahd, sim); 36097883Sgibbs 36197883Sgibbs switch (ccb->ccb_h.func_code) { 36297883Sgibbs /* Common cases first */ 36397883Sgibbs#ifdef AHD_TARGET_MODE 36497883Sgibbs case XPT_ACCEPT_TARGET_IO: /* Accept Host Target Mode CDB */ 36597883Sgibbs case XPT_CONT_TARGET_IO:/* Continue Host Target I/O Connection*/ 36697883Sgibbs { 36797883Sgibbs struct ahd_tmode_tstate *tstate; 36897883Sgibbs cam_status status; 36997883Sgibbs 37097883Sgibbs status = ahd_find_tmode_devs(ahd, sim, ccb, &tstate, 37197883Sgibbs &lstate, TRUE); 37297883Sgibbs 37397883Sgibbs if (status != CAM_REQ_CMP) { 37497883Sgibbs if (ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) { 37597883Sgibbs /* Response from the black hole device */ 37697883Sgibbs tstate = NULL; 37797883Sgibbs lstate = ahd->black_hole; 37897883Sgibbs } else { 37997883Sgibbs ccb->ccb_h.status = status; 38097883Sgibbs xpt_done(ccb); 38197883Sgibbs break; 38297883Sgibbs } 38397883Sgibbs } 38497883Sgibbs if (ccb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) { 38597883Sgibbs 38697883Sgibbs ahd_lock(ahd, &s); 38797883Sgibbs SLIST_INSERT_HEAD(&lstate->accept_tios, &ccb->ccb_h, 38897883Sgibbs sim_links.sle); 38997883Sgibbs ccb->ccb_h.status = CAM_REQ_INPROG; 39097883Sgibbs if ((ahd->flags & AHD_TQINFIFO_BLOCKED) != 0) 39197883Sgibbs ahd_run_tqinfifo(ahd, /*paused*/FALSE); 39297883Sgibbs ahd_unlock(ahd, &s); 39397883Sgibbs break; 39497883Sgibbs } 39597883Sgibbs 39697883Sgibbs /* 39797883Sgibbs * The target_id represents the target we attempt to 39897883Sgibbs * select. In target mode, this is the initiator of 39997883Sgibbs * the original command. 40097883Sgibbs */ 40197883Sgibbs our_id = target_id; 40297883Sgibbs target_id = ccb->csio.init_id; 40397883Sgibbs /* FALLTHROUGH */ 40497883Sgibbs } 40597883Sgibbs#endif 40697883Sgibbs case XPT_SCSI_IO: /* Execute the requested I/O operation */ 40797883Sgibbs case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */ 40897883Sgibbs { 40997883Sgibbs struct scb *scb; 41097883Sgibbs struct hardware_scb *hscb; 411102684Sgibbs struct ahd_initiator_tinfo *tinfo; 412102684Sgibbs struct ahd_tmode_tstate *tstate; 413102684Sgibbs u_int col_idx; 41497883Sgibbs 41597883Sgibbs if ((ahd->flags & AHD_INITIATORROLE) == 0 41697883Sgibbs && (ccb->ccb_h.func_code == XPT_SCSI_IO 41797883Sgibbs || ccb->ccb_h.func_code == XPT_RESET_DEV)) { 41897883Sgibbs ccb->ccb_h.status = CAM_PROVIDE_FAIL; 41997883Sgibbs xpt_done(ccb); 42097883Sgibbs return; 42197883Sgibbs } 42297883Sgibbs 42397883Sgibbs /* 42497883Sgibbs * get an scb to use. 42597883Sgibbs */ 42697883Sgibbs ahd_lock(ahd, &s); 427102684Sgibbs tinfo = ahd_fetch_transinfo(ahd, 'A', our_id, 428102684Sgibbs target_id, &tstate); 429102684Sgibbs if ((ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) == 0 430102684Sgibbs || (tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ) != 0 431102684Sgibbs || ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) { 432102684Sgibbs col_idx = AHD_NEVER_COL_IDX; 433102684Sgibbs } else { 434102684Sgibbs col_idx = AHD_BUILD_COL_IDX(target_id, 435102684Sgibbs ccb->ccb_h.target_lun); 436102684Sgibbs } 437102684Sgibbs if ((scb = ahd_get_scb(ahd, col_idx)) == NULL) { 43897883Sgibbs 43997883Sgibbs xpt_freeze_simq(sim, /*count*/1); 44097883Sgibbs ahd->flags |= AHD_RESOURCE_SHORTAGE; 44197883Sgibbs ahd_unlock(ahd, &s); 44297883Sgibbs ccb->ccb_h.status = CAM_REQUEUE_REQ; 44397883Sgibbs xpt_done(ccb); 44497883Sgibbs return; 44597883Sgibbs } 44697883Sgibbs ahd_unlock(ahd, &s); 44797883Sgibbs 44897883Sgibbs hscb = scb->hscb; 44997883Sgibbs 45097883Sgibbs CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_SUBTRACE, 45197883Sgibbs ("start scb(%p)\n", scb)); 45297883Sgibbs scb->io_ctx = ccb; 45397883Sgibbs /* 45497883Sgibbs * So we can find the SCB when an abort is requested 45597883Sgibbs */ 45697883Sgibbs ccb->ccb_h.ccb_scb_ptr = scb; 45797883Sgibbs 45897883Sgibbs /* 45997883Sgibbs * Put all the arguments for the xfer in the scb 46097883Sgibbs */ 46197883Sgibbs hscb->control = 0; 46297883Sgibbs hscb->scsiid = BUILD_SCSIID(ahd, sim, target_id, our_id); 46397883Sgibbs hscb->lun = ccb->ccb_h.target_lun; 46497883Sgibbs if (ccb->ccb_h.func_code == XPT_RESET_DEV) { 46597883Sgibbs hscb->cdb_len = 0; 46697883Sgibbs scb->flags |= SCB_DEVICE_RESET; 46797883Sgibbs hscb->control |= MK_MESSAGE; 468109588Sgibbs hscb->task_management = SIU_TASKMGMT_LUN_RESET; 46997883Sgibbs ahd_execute_scb(scb, NULL, 0, 0); 47097883Sgibbs } else { 47197883Sgibbs#ifdef AHD_TARGET_MODE 47297883Sgibbs if (ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) { 47397883Sgibbs struct target_data *tdata; 47497883Sgibbs 47597883Sgibbs tdata = &hscb->shared_data.tdata; 47697883Sgibbs if (ahd->pending_device == lstate) 47797883Sgibbs scb->flags |= SCB_TARGET_IMMEDIATE; 47897883Sgibbs hscb->control |= TARGET_SCB; 47997883Sgibbs tdata->target_phases = 0; 48097883Sgibbs if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) { 48197883Sgibbs tdata->target_phases |= SPHASE_PENDING; 48297883Sgibbs tdata->scsi_status = 48397883Sgibbs ccb->csio.scsi_status; 48497883Sgibbs } 48597883Sgibbs if (ccb->ccb_h.flags & CAM_DIS_DISCONNECT) 48697883Sgibbs tdata->target_phases |= NO_DISCONNECT; 48797883Sgibbs 48897883Sgibbs tdata->initiator_tag = 48997883Sgibbs ahd_htole16(ccb->csio.tag_id); 49097883Sgibbs } 49197883Sgibbs#endif 492109588Sgibbs hscb->task_management = 0; 49397883Sgibbs if (ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) 49497883Sgibbs hscb->control |= ccb->csio.tag_action; 49597883Sgibbs 49697883Sgibbs ahd_setup_data(ahd, sim, &ccb->csio, scb); 49797883Sgibbs } 49897883Sgibbs break; 49997883Sgibbs } 50097883Sgibbs#ifdef AHD_TARGET_MODE 50197883Sgibbs case XPT_NOTIFY_ACK: 50297883Sgibbs case XPT_IMMED_NOTIFY: 50397883Sgibbs { 50497883Sgibbs struct ahd_tmode_tstate *tstate; 50597883Sgibbs struct ahd_tmode_lstate *lstate; 50697883Sgibbs cam_status status; 50797883Sgibbs 50897883Sgibbs status = ahd_find_tmode_devs(ahd, sim, ccb, &tstate, 50997883Sgibbs &lstate, TRUE); 51097883Sgibbs 51197883Sgibbs if (status != CAM_REQ_CMP) { 51297883Sgibbs ccb->ccb_h.status = status; 51397883Sgibbs xpt_done(ccb); 51497883Sgibbs break; 51597883Sgibbs } 51697883Sgibbs SLIST_INSERT_HEAD(&lstate->immed_notifies, &ccb->ccb_h, 51797883Sgibbs sim_links.sle); 51897883Sgibbs ccb->ccb_h.status = CAM_REQ_INPROG; 51997883Sgibbs ahd_send_lstate_events(ahd, lstate); 52097883Sgibbs break; 52197883Sgibbs } 52297883Sgibbs case XPT_EN_LUN: /* Enable LUN as a target */ 52397883Sgibbs ahd_handle_en_lun(ahd, sim, ccb); 52497883Sgibbs xpt_done(ccb); 52597883Sgibbs break; 52697883Sgibbs#endif 52797883Sgibbs case XPT_ABORT: /* Abort the specified CCB */ 52897883Sgibbs { 52997883Sgibbs ahd_abort_ccb(ahd, sim, ccb); 53097883Sgibbs break; 53197883Sgibbs } 53297883Sgibbs case XPT_SET_TRAN_SETTINGS: 53397883Sgibbs { 53497883Sgibbs ahd_lock(ahd, &s); 53597883Sgibbs ahd_set_tran_settings(ahd, SIM_SCSI_ID(ahd, sim), 53697883Sgibbs SIM_CHANNEL(ahd, sim), &ccb->cts); 53797883Sgibbs ahd_unlock(ahd, &s); 53897883Sgibbs xpt_done(ccb); 53997883Sgibbs break; 54097883Sgibbs } 54197883Sgibbs case XPT_GET_TRAN_SETTINGS: 54297883Sgibbs /* Get default/user set transfer settings for the target */ 54397883Sgibbs { 54497883Sgibbs ahd_lock(ahd, &s); 54597883Sgibbs ahd_get_tran_settings(ahd, SIM_SCSI_ID(ahd, sim), 54697883Sgibbs SIM_CHANNEL(ahd, sim), &ccb->cts); 54797883Sgibbs ahd_unlock(ahd, &s); 54897883Sgibbs xpt_done(ccb); 54997883Sgibbs break; 55097883Sgibbs } 55197883Sgibbs case XPT_CALC_GEOMETRY: 55297883Sgibbs { 55397883Sgibbs struct ccb_calc_geometry *ccg; 55497883Sgibbs uint32_t size_mb; 55597883Sgibbs uint32_t secs_per_cylinder; 55697883Sgibbs int extended; 55797883Sgibbs 55897883Sgibbs ccg = &ccb->ccg; 55997883Sgibbs size_mb = ccg->volume_size 56097883Sgibbs / ((1024L * 1024L) / ccg->block_size); 56197883Sgibbs extended = ahd->flags & AHD_EXTENDED_TRANS_A; 56297883Sgibbs 56397883Sgibbs if (size_mb > 1024 && extended) { 56497883Sgibbs ccg->heads = 255; 56597883Sgibbs ccg->secs_per_track = 63; 56697883Sgibbs } else { 56797883Sgibbs ccg->heads = 64; 56897883Sgibbs ccg->secs_per_track = 32; 56997883Sgibbs } 57097883Sgibbs secs_per_cylinder = ccg->heads * ccg->secs_per_track; 57197883Sgibbs ccg->cylinders = ccg->volume_size / secs_per_cylinder; 57297883Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 57397883Sgibbs xpt_done(ccb); 57497883Sgibbs break; 57597883Sgibbs } 57697883Sgibbs case XPT_RESET_BUS: /* Reset the specified SCSI bus */ 57797883Sgibbs { 57897883Sgibbs int found; 57997883Sgibbs 58097883Sgibbs ahd_lock(ahd, &s); 58197883Sgibbs found = ahd_reset_channel(ahd, SIM_CHANNEL(ahd, sim), 58297883Sgibbs /*initiate reset*/TRUE); 58397883Sgibbs ahd_unlock(ahd, &s); 58497883Sgibbs if (bootverbose) { 58597883Sgibbs xpt_print_path(SIM_PATH(ahd, sim)); 58697883Sgibbs printf("SCSI bus reset delivered. " 58797883Sgibbs "%d SCBs aborted.\n", found); 58897883Sgibbs } 58997883Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 59097883Sgibbs xpt_done(ccb); 59197883Sgibbs break; 59297883Sgibbs } 59397883Sgibbs case XPT_TERM_IO: /* Terminate the I/O process */ 59497883Sgibbs /* XXX Implement */ 59597883Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 59697883Sgibbs xpt_done(ccb); 59797883Sgibbs break; 59897883Sgibbs case XPT_PATH_INQ: /* Path routing inquiry */ 59997883Sgibbs { 60097883Sgibbs struct ccb_pathinq *cpi = &ccb->cpi; 60197883Sgibbs 60297883Sgibbs cpi->version_num = 1; /* XXX??? */ 60397883Sgibbs cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE; 60497883Sgibbs if ((ahd->features & AHD_WIDE) != 0) 60597883Sgibbs cpi->hba_inquiry |= PI_WIDE_16; 60697883Sgibbs if ((ahd->features & AHD_TARGETMODE) != 0) { 60797883Sgibbs cpi->target_sprt = PIT_PROCESSOR 60897883Sgibbs | PIT_DISCONNECT 60997883Sgibbs | PIT_TERM_IO; 61097883Sgibbs } else { 61197883Sgibbs cpi->target_sprt = 0; 61297883Sgibbs } 61397883Sgibbs cpi->hba_misc = 0; 61497883Sgibbs cpi->hba_eng_cnt = 0; 61597883Sgibbs cpi->max_target = (ahd->features & AHD_WIDE) ? 15 : 7; 61697883Sgibbs cpi->max_lun = AHD_NUM_LUNS - 1; 61797883Sgibbs cpi->initiator_id = ahd->our_id; 61897883Sgibbs if ((ahd->flags & AHD_RESET_BUS_A) == 0) { 61997883Sgibbs cpi->hba_misc |= PIM_NOBUSRESET; 62097883Sgibbs } 62197883Sgibbs cpi->bus_id = cam_sim_bus(sim); 62297883Sgibbs cpi->base_transfer_speed = 3300; 62397883Sgibbs strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 62497883Sgibbs strncpy(cpi->hba_vid, "Adaptec", HBA_IDLEN); 62597883Sgibbs strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 62697883Sgibbs cpi->unit_number = cam_sim_unit(sim); 62797883Sgibbs#ifdef AHD_NEW_TRAN_SETTINGS 62897883Sgibbs cpi->protocol = PROTO_SCSI; 62997883Sgibbs cpi->protocol_version = SCSI_REV_2; 63097883Sgibbs cpi->transport = XPORT_SPI; 63197883Sgibbs cpi->transport_version = 2; 63297883Sgibbs cpi->xport_specific.spi.ppr_options = SID_SPI_CLOCK_ST; 63397883Sgibbs cpi->transport_version = 4; 63497883Sgibbs cpi->xport_specific.spi.ppr_options = SID_SPI_CLOCK_DT_ST; 63597883Sgibbs#endif 63697883Sgibbs cpi->ccb_h.status = CAM_REQ_CMP; 63797883Sgibbs xpt_done(ccb); 63897883Sgibbs break; 63997883Sgibbs } 64097883Sgibbs default: 64197883Sgibbs ccb->ccb_h.status = CAM_PROVIDE_FAIL; 64297883Sgibbs xpt_done(ccb); 64397883Sgibbs break; 64497883Sgibbs } 64597883Sgibbs} 64697883Sgibbs 64797883Sgibbs 64897883Sgibbsstatic void 64997883Sgibbsahd_set_tran_settings(struct ahd_softc *ahd, int our_id, char channel, 65097883Sgibbs struct ccb_trans_settings *cts) 65197883Sgibbs{ 65297883Sgibbs#ifdef AHD_NEW_TRAN_SETTINGS 65397883Sgibbs struct ahd_devinfo devinfo; 65497883Sgibbs struct ccb_trans_settings_scsi *scsi; 65597883Sgibbs struct ccb_trans_settings_spi *spi; 65697883Sgibbs struct ahd_initiator_tinfo *tinfo; 65797883Sgibbs struct ahd_tmode_tstate *tstate; 65897883Sgibbs uint16_t *discenable; 65997883Sgibbs uint16_t *tagenable; 66097883Sgibbs u_int update_type; 66197883Sgibbs 66297883Sgibbs scsi = &cts->proto_specific.scsi; 66397883Sgibbs spi = &cts->xport_specific.spi; 66497883Sgibbs ahd_compile_devinfo(&devinfo, SIM_SCSI_ID(ahd, sim), 66597883Sgibbs cts->ccb_h.target_id, 66697883Sgibbs cts->ccb_h.target_lun, 66797883Sgibbs SIM_CHANNEL(ahd, sim), 66897883Sgibbs ROLE_UNKNOWN); 66997883Sgibbs tinfo = ahd_fetch_transinfo(ahd, devinfo.channel, 67097883Sgibbs devinfo.our_scsiid, 67197883Sgibbs devinfo.target, &tstate); 67297883Sgibbs update_type = 0; 67397883Sgibbs if (cts->type == CTS_TYPE_CURRENT_SETTINGS) { 67497883Sgibbs update_type |= AHD_TRANS_GOAL; 67597883Sgibbs discenable = &tstate->discenable; 67697883Sgibbs tagenable = &tstate->tagenable; 67797883Sgibbs tinfo->curr.protocol_version = cts->protocol_version; 67897883Sgibbs tinfo->curr.transport_version = cts->transport_version; 67997883Sgibbs tinfo->goal.protocol_version = cts->protocol_version; 68097883Sgibbs tinfo->goal.transport_version = cts->transport_version; 68197883Sgibbs } else if (cts->type == CTS_TYPE_USER_SETTINGS) { 68297883Sgibbs update_type |= AHD_TRANS_USER; 68397883Sgibbs discenable = &ahd->user_discenable; 68497883Sgibbs tagenable = &ahd->user_tagenable; 68597883Sgibbs tinfo->user.protocol_version = cts->protocol_version; 68697883Sgibbs tinfo->user.transport_version = cts->transport_version; 68797883Sgibbs } else { 68897883Sgibbs cts->ccb_h.status = CAM_REQ_INVALID; 68997883Sgibbs return; 69097883Sgibbs } 69197883Sgibbs 69297883Sgibbs if ((spi->valid & CTS_SPI_VALID_DISC) != 0) { 69397883Sgibbs if ((spi->flags & CTS_SPI_FLAGS_DISC_ENB) != 0) 69497883Sgibbs *discenable |= devinfo.target_mask; 69597883Sgibbs else 69697883Sgibbs *discenable &= ~devinfo.target_mask; 69797883Sgibbs } 69897883Sgibbs 69997883Sgibbs if ((scsi->valid & CTS_SCSI_VALID_TQ) != 0) { 70097883Sgibbs if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0) 70197883Sgibbs *tagenable |= devinfo.target_mask; 70297883Sgibbs else 70397883Sgibbs *tagenable &= ~devinfo.target_mask; 70497883Sgibbs } 70597883Sgibbs 70697883Sgibbs if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) { 70797883Sgibbs ahd_validate_width(ahd, /*tinfo limit*/NULL, 70897883Sgibbs &spi->bus_width, ROLE_UNKNOWN); 70997883Sgibbs ahd_set_width(ahd, &devinfo, spi->bus_width, 71097883Sgibbs update_type, /*paused*/FALSE); 71197883Sgibbs } 71297883Sgibbs 71397883Sgibbs if ((spi->valid & CTS_SPI_VALID_PPR_OPTIONS) == 0) { 71497883Sgibbs if (update_type == AHD_TRANS_USER) 71597883Sgibbs spi->ppr_options = tinfo->user.ppr_options; 71697883Sgibbs else 71797883Sgibbs spi->ppr_options = tinfo->goal.ppr_options; 71897883Sgibbs } 71997883Sgibbs 72097883Sgibbs if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) == 0) { 72197883Sgibbs if (update_type == AHD_TRANS_USER) 72297883Sgibbs spi->sync_offset = tinfo->user.offset; 72397883Sgibbs else 72497883Sgibbs spi->sync_offset = tinfo->goal.offset; 72597883Sgibbs } 72697883Sgibbs 72797883Sgibbs if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) == 0) { 72897883Sgibbs if (update_type == AHD_TRANS_USER) 72997883Sgibbs spi->sync_period = tinfo->user.period; 73097883Sgibbs else 73197883Sgibbs spi->sync_period = tinfo->goal.period; 73297883Sgibbs } 73397883Sgibbs 73497883Sgibbs if (((spi->valid & CTS_SPI_VALID_SYNC_RATE) != 0) 73597883Sgibbs || ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0)) { 73697883Sgibbs u_int maxsync; 73797883Sgibbs 73897883Sgibbs maxsync = AHD_SYNCRATE_MAX; 73997883Sgibbs 74097883Sgibbs if (spi->bus_width != MSG_EXT_WDTR_BUS_16_BIT) 74197883Sgibbs spi->ppr_options &= ~MSG_EXT_PPR_DT_REQ; 74297883Sgibbs 74397883Sgibbs if ((*discenable & devinfo.target_mask) == 0) 74497883Sgibbs spi->ppr_options &= ~MSG_EXT_PPR_IU_REQ; 74597883Sgibbs 74697883Sgibbs ahd_find_syncrate(ahd, &spi->sync_period, 74797883Sgibbs &spi->ppr_options, maxsync); 74897883Sgibbs ahd_validate_offset(ahd, /*tinfo limit*/NULL, 74997883Sgibbs spi->sync_period, &spi->sync_offset, 75097883Sgibbs spi->bus_width, ROLE_UNKNOWN); 75197883Sgibbs 75297883Sgibbs /* We use a period of 0 to represent async */ 75397883Sgibbs if (spi->sync_offset == 0) { 75497883Sgibbs spi->sync_period = 0; 75597883Sgibbs spi->ppr_options = 0; 75697883Sgibbs } 75797883Sgibbs 75897883Sgibbs ahd_set_syncrate(ahd, &devinfo, spi->sync_period, 75997883Sgibbs spi->sync_offset, spi->ppr_options, 76097883Sgibbs update_type, /*paused*/FALSE); 76197883Sgibbs } 76297883Sgibbs cts->ccb_h.status = CAM_REQ_CMP; 76397883Sgibbs#else 76497883Sgibbs struct ahd_devinfo devinfo; 76597883Sgibbs struct ahd_initiator_tinfo *tinfo; 76697883Sgibbs struct ahd_tmode_tstate *tstate; 76797883Sgibbs uint16_t *discenable; 76897883Sgibbs uint16_t *tagenable; 76997883Sgibbs u_int update_type; 77097883Sgibbs 77197883Sgibbs ahd_compile_devinfo(&devinfo, SIM_SCSI_ID(ahd, sim), 77297883Sgibbs cts->ccb_h.target_id, 77397883Sgibbs cts->ccb_h.target_lun, 77497883Sgibbs SIM_CHANNEL(ahd, sim), 77597883Sgibbs ROLE_UNKNOWN); 77697883Sgibbs tinfo = ahd_fetch_transinfo(ahd, devinfo.channel, 77797883Sgibbs devinfo.our_scsiid, 77897883Sgibbs devinfo.target, &tstate); 77997883Sgibbs update_type = 0; 78097883Sgibbs if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0) { 78197883Sgibbs update_type |= AHD_TRANS_GOAL; 78297883Sgibbs discenable = &tstate->discenable; 78397883Sgibbs tagenable = &tstate->tagenable; 78497883Sgibbs } else if ((cts->flags & CCB_TRANS_USER_SETTINGS) != 0) { 78597883Sgibbs update_type |= AHD_TRANS_USER; 78697883Sgibbs discenable = &ahd->user_discenable; 78797883Sgibbs tagenable = &ahd->user_tagenable; 78897883Sgibbs } else { 78997883Sgibbs cts->ccb_h.status = CAM_REQ_INVALID; 79097883Sgibbs return; 79197883Sgibbs } 79297883Sgibbs 79397883Sgibbs if ((cts->valid & CCB_TRANS_DISC_VALID) != 0) { 79497883Sgibbs if ((cts->flags & CCB_TRANS_DISC_ENB) != 0) 79597883Sgibbs *discenable |= devinfo.target_mask; 79697883Sgibbs else 79797883Sgibbs *discenable &= ~devinfo.target_mask; 79897883Sgibbs } 79997883Sgibbs 80097883Sgibbs if ((cts->valid & CCB_TRANS_TQ_VALID) != 0) { 80197883Sgibbs if ((cts->flags & CCB_TRANS_TAG_ENB) != 0) 80297883Sgibbs *tagenable |= devinfo.target_mask; 80397883Sgibbs else 80497883Sgibbs *tagenable &= ~devinfo.target_mask; 80597883Sgibbs } 80697883Sgibbs 80797883Sgibbs if ((cts->valid & CCB_TRANS_BUS_WIDTH_VALID) != 0) { 80897883Sgibbs ahd_validate_width(ahd, /*tinfo limit*/NULL, 80997883Sgibbs &cts->bus_width, ROLE_UNKNOWN); 81097883Sgibbs ahd_set_width(ahd, &devinfo, cts->bus_width, 81197883Sgibbs update_type, /*paused*/FALSE); 81297883Sgibbs } 81397883Sgibbs 81497883Sgibbs if ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) == 0) { 81597883Sgibbs if (update_type == AHD_TRANS_USER) 81697883Sgibbs cts->sync_offset = tinfo->user.offset; 81797883Sgibbs else 81897883Sgibbs cts->sync_offset = tinfo->goal.offset; 81997883Sgibbs } 82097883Sgibbs 82197883Sgibbs if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) == 0) { 82297883Sgibbs if (update_type == AHD_TRANS_USER) 82397883Sgibbs cts->sync_period = tinfo->user.period; 82497883Sgibbs else 82597883Sgibbs cts->sync_period = tinfo->goal.period; 82697883Sgibbs } 82797883Sgibbs 82897883Sgibbs if (((cts->valid & CCB_TRANS_SYNC_RATE_VALID) != 0) 829102684Sgibbs || ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0) 830102684Sgibbs || ((cts->valid & CCB_TRANS_TQ_VALID) != 0) 831102684Sgibbs || ((cts->valid & CCB_TRANS_DISC_VALID) != 0)) { 83297883Sgibbs u_int ppr_options; 83397883Sgibbs u_int maxsync; 83497883Sgibbs 83597883Sgibbs maxsync = AHD_SYNCRATE_MAX; 83697883Sgibbs ppr_options = 0; 83797883Sgibbs if (cts->sync_period <= AHD_SYNCRATE_DT 83897883Sgibbs && cts->bus_width == MSG_EXT_WDTR_BUS_16_BIT) { 83997883Sgibbs ppr_options = tinfo->user.ppr_options 84097883Sgibbs | MSG_EXT_PPR_DT_REQ; 84197883Sgibbs } 84297883Sgibbs 843102684Sgibbs if ((*tagenable & devinfo.target_mask) == 0 844102684Sgibbs || (*discenable & devinfo.target_mask) == 0) 845102684Sgibbs ppr_options &= ~MSG_EXT_PPR_IU_REQ; 846102684Sgibbs 84797883Sgibbs ahd_find_syncrate(ahd, &cts->sync_period, 84897883Sgibbs &ppr_options, maxsync); 84997883Sgibbs ahd_validate_offset(ahd, /*tinfo limit*/NULL, 85097883Sgibbs cts->sync_period, &cts->sync_offset, 85197883Sgibbs MSG_EXT_WDTR_BUS_8_BIT, 85297883Sgibbs ROLE_UNKNOWN); 85397883Sgibbs 85497883Sgibbs /* We use a period of 0 to represent async */ 85597883Sgibbs if (cts->sync_offset == 0) { 85697883Sgibbs cts->sync_period = 0; 85797883Sgibbs ppr_options = 0; 85897883Sgibbs } 85997883Sgibbs 86097883Sgibbs if (ppr_options != 0 86197883Sgibbs && tinfo->user.transport_version >= 3) { 86297883Sgibbs tinfo->goal.transport_version = 86397883Sgibbs tinfo->user.transport_version; 86497883Sgibbs tinfo->curr.transport_version = 86597883Sgibbs tinfo->user.transport_version; 86697883Sgibbs } 86797883Sgibbs 86897883Sgibbs ahd_set_syncrate(ahd, &devinfo, cts->sync_period, 86997883Sgibbs cts->sync_offset, ppr_options, 87097883Sgibbs update_type, /*paused*/FALSE); 87197883Sgibbs } 87297883Sgibbs cts->ccb_h.status = CAM_REQ_CMP; 87397883Sgibbs#endif 87497883Sgibbs} 87597883Sgibbs 87697883Sgibbsstatic void 87797883Sgibbsahd_get_tran_settings(struct ahd_softc *ahd, int our_id, char channel, 87897883Sgibbs struct ccb_trans_settings *cts) 87997883Sgibbs{ 88097883Sgibbs#ifdef AHD_NEW_TRAN_SETTINGS 88197883Sgibbs struct ahd_devinfo devinfo; 88297883Sgibbs struct ccb_trans_settings_scsi *scsi; 88397883Sgibbs struct ccb_trans_settings_spi *spi; 88497883Sgibbs struct ahd_initiator_tinfo *targ_info; 88597883Sgibbs struct ahd_tmode_tstate *tstate; 88697883Sgibbs struct ahd_transinfo *tinfo; 88797883Sgibbs 88897883Sgibbs scsi = &cts->proto_specific.scsi; 88997883Sgibbs spi = &cts->xport_specific.spi; 89097883Sgibbs ahd_compile_devinfo(&devinfo, our_id, 89197883Sgibbs cts->ccb_h.target_id, 89297883Sgibbs cts->ccb_h.target_lun, 89397883Sgibbs channel, ROLE_UNKNOWN); 89497883Sgibbs targ_info = ahd_fetch_transinfo(ahd, devinfo.channel, 89597883Sgibbs devinfo.our_scsiid, 89697883Sgibbs devinfo.target, &tstate); 89797883Sgibbs 89897883Sgibbs if (cts->type == CTS_TYPE_CURRENT_SETTINGS) 89997883Sgibbs tinfo = &targ_info->curr; 90097883Sgibbs else 90197883Sgibbs tinfo = &targ_info->user; 90297883Sgibbs 90397883Sgibbs scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 90497883Sgibbs spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB; 90597883Sgibbs if (cts->type == CTS_TYPE_USER_SETTINGS) { 90697883Sgibbs if ((ahd->user_discenable & devinfo.target_mask) != 0) 90797883Sgibbs spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 90897883Sgibbs 90997883Sgibbs if ((ahd->user_tagenable & devinfo.target_mask) != 0) 91097883Sgibbs scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; 91197883Sgibbs } else { 91297883Sgibbs if ((tstate->discenable & devinfo.target_mask) != 0) 91397883Sgibbs spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 91497883Sgibbs 91597883Sgibbs if ((tstate->tagenable & devinfo.target_mask) != 0) 91697883Sgibbs scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; 91797883Sgibbs } 91897883Sgibbs cts->protocol_version = tinfo->protocol_version; 91997883Sgibbs cts->transport_version = tinfo->transport_version; 92097883Sgibbs 92197883Sgibbs spi->sync_period = tinfo->period; 92297883Sgibbs spi->sync_offset = tinfo->offset; 92397883Sgibbs spi->bus_width = tinfo->width; 92497883Sgibbs spi->ppr_options = tinfo->ppr_options; 92597883Sgibbs 92697883Sgibbs cts->protocol = PROTO_SCSI; 92797883Sgibbs cts->transport = XPORT_SPI; 92897883Sgibbs spi->valid = CTS_SPI_VALID_SYNC_RATE 92997883Sgibbs | CTS_SPI_VALID_SYNC_OFFSET 93097883Sgibbs | CTS_SPI_VALID_BUS_WIDTH 93197883Sgibbs | CTS_SPI_VALID_PPR_OPTIONS; 93297883Sgibbs 93397883Sgibbs if (cts->ccb_h.target_lun != CAM_LUN_WILDCARD) { 93497883Sgibbs scsi->valid = CTS_SCSI_VALID_TQ; 93597883Sgibbs spi->valid |= CTS_SPI_VALID_DISC; 93697883Sgibbs } else { 93797883Sgibbs scsi->valid = 0; 93897883Sgibbs } 93997883Sgibbs 94097883Sgibbs cts->ccb_h.status = CAM_REQ_CMP; 94197883Sgibbs#else 94297883Sgibbs struct ahd_devinfo devinfo; 94397883Sgibbs struct ahd_initiator_tinfo *targ_info; 94497883Sgibbs struct ahd_tmode_tstate *tstate; 94597883Sgibbs struct ahd_transinfo *tinfo; 94697883Sgibbs 94797883Sgibbs ahd_compile_devinfo(&devinfo, our_id, 94897883Sgibbs cts->ccb_h.target_id, 94997883Sgibbs cts->ccb_h.target_lun, 95097883Sgibbs channel, ROLE_UNKNOWN); 95197883Sgibbs targ_info = ahd_fetch_transinfo(ahd, devinfo.channel, 95297883Sgibbs devinfo.our_scsiid, 95397883Sgibbs devinfo.target, &tstate); 95497883Sgibbs 95597883Sgibbs if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0) 95697883Sgibbs tinfo = &targ_info->curr; 95797883Sgibbs else 95897883Sgibbs tinfo = &targ_info->user; 95997883Sgibbs 96097883Sgibbs cts->flags &= ~(CCB_TRANS_DISC_ENB|CCB_TRANS_TAG_ENB); 96197883Sgibbs if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) == 0) { 96297883Sgibbs if ((ahd->user_discenable & devinfo.target_mask) != 0) 96397883Sgibbs cts->flags |= CCB_TRANS_DISC_ENB; 96497883Sgibbs 96597883Sgibbs if ((ahd->user_tagenable & devinfo.target_mask) != 0) 96697883Sgibbs cts->flags |= CCB_TRANS_TAG_ENB; 96797883Sgibbs } else { 96897883Sgibbs if ((tstate->discenable & devinfo.target_mask) != 0) 96997883Sgibbs cts->flags |= CCB_TRANS_DISC_ENB; 97097883Sgibbs 97197883Sgibbs if ((tstate->tagenable & devinfo.target_mask) != 0) 97297883Sgibbs cts->flags |= CCB_TRANS_TAG_ENB; 97397883Sgibbs } 97497883Sgibbs cts->sync_period = tinfo->period; 97597883Sgibbs cts->sync_offset = tinfo->offset; 97697883Sgibbs cts->bus_width = tinfo->width; 97797883Sgibbs 97897883Sgibbs cts->valid = CCB_TRANS_SYNC_RATE_VALID 97997883Sgibbs | CCB_TRANS_SYNC_OFFSET_VALID 98097883Sgibbs | CCB_TRANS_BUS_WIDTH_VALID; 98197883Sgibbs 98297883Sgibbs if (cts->ccb_h.target_lun != CAM_LUN_WILDCARD) 98397883Sgibbs cts->valid |= CCB_TRANS_DISC_VALID|CCB_TRANS_TQ_VALID; 98497883Sgibbs 98597883Sgibbs cts->ccb_h.status = CAM_REQ_CMP; 98697883Sgibbs#endif 98797883Sgibbs} 98897883Sgibbs 98997883Sgibbsstatic void 99097883Sgibbsahd_async(void *callback_arg, uint32_t code, struct cam_path *path, void *arg) 99197883Sgibbs{ 99297883Sgibbs struct ahd_softc *ahd; 99397883Sgibbs struct cam_sim *sim; 99497883Sgibbs 99597883Sgibbs sim = (struct cam_sim *)callback_arg; 99697883Sgibbs ahd = (struct ahd_softc *)cam_sim_softc(sim); 99797883Sgibbs switch (code) { 99897883Sgibbs case AC_LOST_DEVICE: 99997883Sgibbs { 100097883Sgibbs struct ahd_devinfo devinfo; 100197883Sgibbs long s; 100297883Sgibbs 100397883Sgibbs ahd_compile_devinfo(&devinfo, SIM_SCSI_ID(ahd, sim), 100497883Sgibbs xpt_path_target_id(path), 100597883Sgibbs xpt_path_lun_id(path), 100697883Sgibbs SIM_CHANNEL(ahd, sim), 100797883Sgibbs ROLE_UNKNOWN); 100897883Sgibbs 100997883Sgibbs /* 101097883Sgibbs * Revert to async/narrow transfers 101197883Sgibbs * for the next device. 101297883Sgibbs */ 101397883Sgibbs ahd_lock(ahd, &s); 101497883Sgibbs ahd_set_width(ahd, &devinfo, MSG_EXT_WDTR_BUS_8_BIT, 101597883Sgibbs AHD_TRANS_GOAL|AHD_TRANS_CUR, /*paused*/FALSE); 101697883Sgibbs ahd_set_syncrate(ahd, &devinfo, /*period*/0, /*offset*/0, 101797883Sgibbs /*ppr_options*/0, AHD_TRANS_GOAL|AHD_TRANS_CUR, 101897883Sgibbs /*paused*/FALSE); 101997883Sgibbs ahd_unlock(ahd, &s); 102097883Sgibbs break; 102197883Sgibbs } 102297883Sgibbs default: 102397883Sgibbs break; 102497883Sgibbs } 102597883Sgibbs} 102697883Sgibbs 102797883Sgibbsstatic void 102897883Sgibbsahd_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments, 102997883Sgibbs int error) 103097883Sgibbs{ 103197883Sgibbs struct scb *scb; 103297883Sgibbs union ccb *ccb; 103397883Sgibbs struct ahd_softc *ahd; 103497883Sgibbs struct ahd_initiator_tinfo *tinfo; 103597883Sgibbs struct ahd_tmode_tstate *tstate; 103697883Sgibbs u_int mask; 103797883Sgibbs u_long s; 103897883Sgibbs 103997883Sgibbs scb = (struct scb *)arg; 104097883Sgibbs ccb = scb->io_ctx; 104197883Sgibbs ahd = scb->ahd_softc; 104297883Sgibbs 104397883Sgibbs if (error != 0) { 104497883Sgibbs if (error == EFBIG) 104597883Sgibbs ahd_set_transaction_status(scb, CAM_REQ_TOO_BIG); 104697883Sgibbs else 104797883Sgibbs ahd_set_transaction_status(scb, CAM_REQ_CMP_ERR); 104897883Sgibbs if (nsegments != 0) 104997883Sgibbs bus_dmamap_unload(ahd->buffer_dmat, scb->dmamap); 105097883Sgibbs ahd_lock(ahd, &s); 105197883Sgibbs ahd_free_scb(ahd, scb); 105297883Sgibbs ahd_unlock(ahd, &s); 105397883Sgibbs xpt_done(ccb); 105497883Sgibbs return; 105597883Sgibbs } 105697883Sgibbs scb->sg_count = 0; 105797883Sgibbs if (nsegments != 0) { 105897883Sgibbs void *sg; 105997883Sgibbs bus_dmasync_op_t op; 106097883Sgibbs u_int i; 106197883Sgibbs 106297883Sgibbs /* Copy the segments into our SG list */ 106397883Sgibbs for (i = nsegments, sg = scb->sg_list; i > 0; i--) { 106497883Sgibbs 106597883Sgibbs sg = ahd_sg_setup(ahd, scb, sg, dm_segs->ds_addr, 106697883Sgibbs dm_segs->ds_len, 106797883Sgibbs /*last*/i == 1); 106897883Sgibbs dm_segs++; 106997883Sgibbs } 107097883Sgibbs 107197883Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) 107297883Sgibbs op = BUS_DMASYNC_PREREAD; 107397883Sgibbs else 107497883Sgibbs op = BUS_DMASYNC_PREWRITE; 107597883Sgibbs 107697883Sgibbs bus_dmamap_sync(ahd->buffer_dmat, scb->dmamap, op); 107797883Sgibbs 107897883Sgibbs if (ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) { 107997883Sgibbs struct target_data *tdata; 108097883Sgibbs 108197883Sgibbs tdata = &scb->hscb->shared_data.tdata; 108297883Sgibbs tdata->target_phases |= DPHASE_PENDING; 108397883Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) 108497883Sgibbs tdata->data_phase = P_DATAOUT; 108597883Sgibbs else 108697883Sgibbs tdata->data_phase = P_DATAIN; 108797883Sgibbs } 108897883Sgibbs } 108997883Sgibbs 109097883Sgibbs ahd_lock(ahd, &s); 109197883Sgibbs 109297883Sgibbs /* 109397883Sgibbs * Last time we need to check if this SCB needs to 109497883Sgibbs * be aborted. 109597883Sgibbs */ 109697883Sgibbs if (ahd_get_transaction_status(scb) != CAM_REQ_INPROG) { 109797883Sgibbs if (nsegments != 0) 109897883Sgibbs bus_dmamap_unload(ahd->buffer_dmat, 109997883Sgibbs scb->dmamap); 110097883Sgibbs ahd_free_scb(ahd, scb); 110197883Sgibbs ahd_unlock(ahd, &s); 110297883Sgibbs xpt_done(ccb); 110397883Sgibbs return; 110497883Sgibbs } 110597883Sgibbs 110697883Sgibbs tinfo = ahd_fetch_transinfo(ahd, SCSIID_CHANNEL(ahd, scb->hscb->scsiid), 110797883Sgibbs SCSIID_OUR_ID(scb->hscb->scsiid), 110897883Sgibbs SCSIID_TARGET(ahd, scb->hscb->scsiid), 110997883Sgibbs &tstate); 111097883Sgibbs 111197883Sgibbs mask = SCB_GET_TARGET_MASK(ahd, scb); 111297883Sgibbs 111397883Sgibbs if ((tstate->discenable & mask) != 0 111497883Sgibbs && (ccb->ccb_h.flags & CAM_DIS_DISCONNECT) == 0) 111597883Sgibbs scb->hscb->control |= DISCENB; 111697883Sgibbs 1117109588Sgibbs if ((tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ) != 0) { 111897883Sgibbs scb->flags |= SCB_PACKETIZED; 1119109588Sgibbs if (scb->hscb->task_management != 0) 1120109588Sgibbs scb->hscb->control &= ~MK_MESSAGE; 1121109588Sgibbs } 112297883Sgibbs 112397883Sgibbs if ((ccb->ccb_h.flags & CAM_NEGOTIATE) != 0 112497883Sgibbs && (tinfo->goal.width != 0 112597883Sgibbs || tinfo->goal.period != 0 112697883Sgibbs || tinfo->goal.ppr_options != 0)) { 112797883Sgibbs scb->flags |= SCB_NEGOTIATE; 112897883Sgibbs scb->hscb->control |= MK_MESSAGE; 112997883Sgibbs } else if ((tstate->auto_negotiate & mask) != 0) { 113097883Sgibbs scb->flags |= SCB_AUTO_NEGOTIATE; 113197883Sgibbs scb->hscb->control |= MK_MESSAGE; 113297883Sgibbs } 113397883Sgibbs 113497883Sgibbs LIST_INSERT_HEAD(&ahd->pending_scbs, scb, pending_links); 113597883Sgibbs 113697883Sgibbs ccb->ccb_h.status |= CAM_SIM_QUEUED; 113797883Sgibbs 113897883Sgibbs if (ccb->ccb_h.timeout != CAM_TIME_INFINITY) { 113997883Sgibbs uint64_t time; 114097883Sgibbs 114197883Sgibbs if (ccb->ccb_h.timeout == CAM_TIME_DEFAULT) 114297883Sgibbs ccb->ccb_h.timeout = 5 * 1000; 114397883Sgibbs 114497883Sgibbs time = ccb->ccb_h.timeout; 114597883Sgibbs time *= hz; 114697883Sgibbs time /= 1000; 114797883Sgibbs ccb->ccb_h.timeout_ch = 114897883Sgibbs timeout(ahd_timeout, (caddr_t)scb, time); 114997883Sgibbs } 115097883Sgibbs 115197883Sgibbs if ((scb->flags & SCB_TARGET_IMMEDIATE) != 0) { 115297883Sgibbs /* Define a mapping from our tag to the SCB. */ 115397883Sgibbs ahd->scb_data.scbindex[SCB_GET_TAG(scb)] = scb; 115497883Sgibbs ahd_pause(ahd); 115597883Sgibbs ahd_set_scbptr(ahd, SCB_GET_TAG(scb)); 115697883Sgibbs ahd_outb(ahd, RETURN_1, CONT_MSG_LOOP_TARG); 115797883Sgibbs ahd_unpause(ahd); 115897883Sgibbs } else { 115997883Sgibbs ahd_queue_scb(ahd, scb); 116097883Sgibbs } 116197883Sgibbs 116297883Sgibbs ahd_unlock(ahd, &s); 116397883Sgibbs} 116497883Sgibbs 116597883Sgibbsstatic void 116697883Sgibbsahd_poll(struct cam_sim *sim) 116797883Sgibbs{ 116897883Sgibbs ahd_intr(cam_sim_softc(sim)); 116997883Sgibbs} 117097883Sgibbs 117197883Sgibbsstatic void 117297883Sgibbsahd_setup_data(struct ahd_softc *ahd, struct cam_sim *sim, 117397883Sgibbs struct ccb_scsiio *csio, struct scb *scb) 117497883Sgibbs{ 117597883Sgibbs struct hardware_scb *hscb; 117697883Sgibbs struct ccb_hdr *ccb_h; 117797883Sgibbs 117897883Sgibbs hscb = scb->hscb; 117997883Sgibbs ccb_h = &csio->ccb_h; 118097883Sgibbs 118197883Sgibbs csio->resid = 0; 118297883Sgibbs csio->sense_resid = 0; 118397883Sgibbs if (ccb_h->func_code == XPT_SCSI_IO) { 118497883Sgibbs hscb->cdb_len = csio->cdb_len; 118597883Sgibbs if ((ccb_h->flags & CAM_CDB_POINTER) != 0) { 118697883Sgibbs 118797883Sgibbs if (hscb->cdb_len > MAX_CDB_LEN 118897883Sgibbs && (ccb_h->flags & CAM_CDB_PHYS) == 0) { 118997883Sgibbs u_long s; 119097883Sgibbs 1191111653Sgibbs /* 1192111653Sgibbs * Should CAM start to support CDB sizes 1193111653Sgibbs * greater than 16 bytes, we could use 1194111653Sgibbs * the sense buffer to store the CDB. 1195111653Sgibbs */ 119697883Sgibbs ahd_set_transaction_status(scb, 119797883Sgibbs CAM_REQ_INVALID); 119897883Sgibbs ahd_lock(ahd, &s); 119997883Sgibbs ahd_free_scb(ahd, scb); 120097883Sgibbs ahd_unlock(ahd, &s); 120197883Sgibbs xpt_done((union ccb *)csio); 120297883Sgibbs return; 120397883Sgibbs } 120497883Sgibbs if ((ccb_h->flags & CAM_CDB_PHYS) != 0) { 1205111653Sgibbs hscb->shared_data.idata.cdb_from_host.cdbptr = 120697883Sgibbs ahd_htole64((uintptr_t)csio->cdb_io.cdb_ptr); 1207111653Sgibbs hscb->shared_data.idata.cdb_from_host.cdblen = 1208111653Sgibbs csio->cdb_len; 1209111653Sgibbs hscb->cdb_len |= SCB_CDB_LEN_PTR; 121097883Sgibbs } else { 121197883Sgibbs memcpy(hscb->shared_data.idata.cdb, 121297883Sgibbs csio->cdb_io.cdb_ptr, 121397883Sgibbs hscb->cdb_len); 121497883Sgibbs } 121597883Sgibbs } else { 121697883Sgibbs if (hscb->cdb_len > MAX_CDB_LEN) { 121797883Sgibbs u_long s; 121897883Sgibbs 121997883Sgibbs ahd_set_transaction_status(scb, 122097883Sgibbs CAM_REQ_INVALID); 122197883Sgibbs ahd_lock(ahd, &s); 122297883Sgibbs ahd_free_scb(ahd, scb); 122397883Sgibbs ahd_unlock(ahd, &s); 122497883Sgibbs xpt_done((union ccb *)csio); 122597883Sgibbs return; 122697883Sgibbs } 122797883Sgibbs memcpy(hscb->shared_data.idata.cdb, 122897883Sgibbs csio->cdb_io.cdb_bytes, hscb->cdb_len); 122997883Sgibbs } 123097883Sgibbs } 123197883Sgibbs 123297883Sgibbs /* Only use S/G if there is a transfer */ 123397883Sgibbs if ((ccb_h->flags & CAM_DIR_MASK) != CAM_DIR_NONE) { 123497883Sgibbs if ((ccb_h->flags & CAM_SCATTER_VALID) == 0) { 123597883Sgibbs /* We've been given a pointer to a single buffer */ 123697883Sgibbs if ((ccb_h->flags & CAM_DATA_PHYS) == 0) { 123797883Sgibbs int s; 123897883Sgibbs int error; 123997883Sgibbs 124097883Sgibbs s = splsoftvm(); 124197883Sgibbs error = bus_dmamap_load(ahd->buffer_dmat, 124297883Sgibbs scb->dmamap, 124397883Sgibbs csio->data_ptr, 124497883Sgibbs csio->dxfer_len, 124597883Sgibbs ahd_execute_scb, 124697883Sgibbs scb, /*flags*/0); 124797883Sgibbs if (error == EINPROGRESS) { 124897883Sgibbs /* 124997883Sgibbs * So as to maintain ordering, 125097883Sgibbs * freeze the controller queue 125197883Sgibbs * until our mapping is 125297883Sgibbs * returned. 125397883Sgibbs */ 125497883Sgibbs xpt_freeze_simq(sim, 125597883Sgibbs /*count*/1); 125697883Sgibbs scb->io_ctx->ccb_h.status |= 125797883Sgibbs CAM_RELEASE_SIMQ; 125897883Sgibbs } 125997883Sgibbs splx(s); 126097883Sgibbs } else { 126197883Sgibbs struct bus_dma_segment seg; 126297883Sgibbs 126397883Sgibbs /* Pointer to physical buffer */ 126497883Sgibbs if (csio->dxfer_len > AHD_MAXTRANSFER_SIZE) 126597883Sgibbs panic("ahd_setup_data - Transfer size " 126697883Sgibbs "larger than can device max"); 126797883Sgibbs 126897883Sgibbs seg.ds_addr = (bus_addr_t)csio->data_ptr; 126997883Sgibbs seg.ds_len = csio->dxfer_len; 127097883Sgibbs ahd_execute_scb(scb, &seg, 1, 0); 127197883Sgibbs } 127297883Sgibbs } else { 127397883Sgibbs struct bus_dma_segment *segs; 127497883Sgibbs 127597883Sgibbs if ((ccb_h->flags & CAM_DATA_PHYS) != 0) 127697883Sgibbs panic("ahd_setup_data - Physical segment " 127797883Sgibbs "pointers unsupported"); 127897883Sgibbs 127997883Sgibbs if ((ccb_h->flags & CAM_SG_LIST_PHYS) == 0) 128097883Sgibbs panic("ahd_setup_data - Virtual segment " 128197883Sgibbs "addresses unsupported"); 128297883Sgibbs 128397883Sgibbs /* Just use the segments provided */ 128497883Sgibbs segs = (struct bus_dma_segment *)csio->data_ptr; 128597883Sgibbs ahd_execute_scb(scb, segs, csio->sglist_cnt, 0); 128697883Sgibbs } 128797883Sgibbs } else { 128897883Sgibbs ahd_execute_scb(scb, NULL, 0, 0); 128997883Sgibbs } 129097883Sgibbs} 129197883Sgibbs 129297883Sgibbs#if NOT_YET 129397883Sgibbsstatic void 129497883Sgibbsahd_set_recoveryscb(struct ahd_softc *ahd, struct scb *scb) { 129597883Sgibbs 129697883Sgibbs if ((scb->flags & SCB_RECOVERY_SCB) == 0) { 129797883Sgibbs struct scb *list_scb; 129897883Sgibbs 129997883Sgibbs scb->flags |= SCB_RECOVERY_SCB; 130097883Sgibbs 130197883Sgibbs /* 130297883Sgibbs * Take all queued, but not sent SCBs out of the equation. 130397883Sgibbs * Also ensure that no new CCBs are queued to us while we 130497883Sgibbs * try to fix this problem. 130597883Sgibbs */ 130697883Sgibbs if ((scb->io_ctx->ccb_h.status & CAM_RELEASE_SIMQ) == 0) { 130797883Sgibbs xpt_freeze_simq(SCB_GET_SIM(ahd, scb), /*count*/1); 130897883Sgibbs scb->io_ctx->ccb_h.status |= CAM_RELEASE_SIMQ; 130997883Sgibbs } 131097883Sgibbs 131197883Sgibbs /* 131297883Sgibbs * Go through all of our pending SCBs and remove 131397883Sgibbs * any scheduled timeouts for them. We will reschedule 131497883Sgibbs * them after we've successfully fixed this problem. 131597883Sgibbs */ 131697883Sgibbs LIST_FOREACH(list_scb, &ahd->pending_scbs, pending_links) { 131797883Sgibbs union ccb *ccb; 131897883Sgibbs 131997883Sgibbs ccb = list_scb->io_ctx; 132097883Sgibbs untimeout(ahd_timeout, list_scb, ccb->ccb_h.timeout_ch); 132197883Sgibbs } 132297883Sgibbs } 132397883Sgibbs} 132497883Sgibbs#endif 132597883Sgibbs 132697883Sgibbsvoid 132797883Sgibbsahd_timeout(void *arg) 132897883Sgibbs{ 132997883Sgibbs struct scb *scb; 133097883Sgibbs struct ahd_softc *ahd; 133197883Sgibbs ahd_mode_state saved_modes; 133297883Sgibbs long s; 133397883Sgibbs int target; 133497883Sgibbs int lun; 133597883Sgibbs char channel; 133697883Sgibbs 133797883Sgibbs#if NOT_YET 133897883Sgibbs int i; 133997883Sgibbs int found; 134097883Sgibbs u_int last_phase; 134197883Sgibbs#endif 134297883Sgibbs 134397883Sgibbs scb = (struct scb *)arg; 134497883Sgibbs ahd = (struct ahd_softc *)scb->ahd_softc; 134597883Sgibbs 134697883Sgibbs ahd_lock(ahd, &s); 134797883Sgibbs 134897883Sgibbs ahd_pause_and_flushwork(ahd); 134997883Sgibbs 135097883Sgibbs saved_modes = ahd_save_modes(ahd); 135197883Sgibbs#if 0 135297883Sgibbs ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 135397883Sgibbs ahd_outb(ahd, SCSISIGO, ACKO); 135497883Sgibbs printf("set ACK\n"); 135597883Sgibbs ahd_outb(ahd, SCSISIGO, 0); 135697883Sgibbs printf("clearing Ack\n"); 135797883Sgibbs ahd_restore_modes(ahd, saved_modes); 135897883Sgibbs#endif 135997883Sgibbs if ((scb->flags & SCB_ACTIVE) == 0) { 136097883Sgibbs /* Previous timeout took care of me already */ 136197883Sgibbs printf("%s: Timedout SCB already complete. " 136297883Sgibbs "Interrupts may not be functioning.\n", ahd_name(ahd)); 136397883Sgibbs ahd_unpause(ahd); 136497883Sgibbs ahd_unlock(ahd, &s); 136597883Sgibbs return; 136697883Sgibbs } 136797883Sgibbs 136897883Sgibbs target = SCB_GET_TARGET(ahd, scb); 136997883Sgibbs channel = SCB_GET_CHANNEL(ahd, scb); 137097883Sgibbs lun = SCB_GET_LUN(scb); 137197883Sgibbs 137297883Sgibbs ahd_print_path(ahd, scb); 137397883Sgibbs printf("SCB 0x%x - timed out\n", SCB_GET_TAG(scb)); 137497883Sgibbs ahd_dump_card_state(ahd); 137597883Sgibbs ahd_reset_channel(ahd, SIM_CHANNEL(ahd, sim), 137697883Sgibbs /*initiate reset*/TRUE); 137797883Sgibbs ahd_unlock(ahd, &s); 137897883Sgibbs return; 137997883Sgibbs#if NOT_YET 138097883Sgibbs last_phase = ahd_inb(ahd, LASTPHASE); 138197883Sgibbs if (scb->sg_count > 0) { 138297883Sgibbs for (i = 0; i < scb->sg_count; i++) { 138397883Sgibbs printf("sg[%d] - Addr 0x%x : Length %d\n", 138497883Sgibbs i, 138597883Sgibbs ((struct ahd_dma_seg *)scb->sg_list)[i].addr, 138697883Sgibbs ((struct ahd_dma_seg *)scb->sg_list)[i].len 138797883Sgibbs & AHD_SG_LEN_MASK); 138897883Sgibbs } 138997883Sgibbs } 139097883Sgibbs if (scb->flags & (SCB_DEVICE_RESET|SCB_ABORT)) { 139197883Sgibbs /* 139297883Sgibbs * Been down this road before. 139397883Sgibbs * Do a full bus reset. 139497883Sgibbs */ 139597883Sgibbsbus_reset: 139697883Sgibbs ahd_set_transaction_status(scb, CAM_CMD_TIMEOUT); 139797883Sgibbs found = ahd_reset_channel(ahd, channel, /*Initiate Reset*/TRUE); 139897883Sgibbs printf("%s: Issued Channel %c Bus Reset. " 139997883Sgibbs "%d SCBs aborted\n", ahd_name(ahd), channel, found); 140097883Sgibbs } else { 140197883Sgibbs /* 140297883Sgibbs * If we are a target, transition to bus free and report 140397883Sgibbs * the timeout. 140497883Sgibbs * 140597883Sgibbs * The target/initiator that is holding up the bus may not 140697883Sgibbs * be the same as the one that triggered this timeout 140797883Sgibbs * (different commands have different timeout lengths). 140897883Sgibbs * If the bus is idle and we are actiing as the initiator 140997883Sgibbs * for this request, queue a BDR message to the timed out 141097883Sgibbs * target. Otherwise, if the timed out transaction is 141197883Sgibbs * active: 141297883Sgibbs * Initiator transaction: 141397883Sgibbs * Stuff the message buffer with a BDR message and assert 141497883Sgibbs * ATN in the hopes that the target will let go of the bus 141597883Sgibbs * and go to the mesgout phase. If this fails, we'll 141697883Sgibbs * get another timeout 2 seconds later which will attempt 141797883Sgibbs * a bus reset. 141897883Sgibbs * 141997883Sgibbs * Target transaction: 142097883Sgibbs * Transition to BUS FREE and report the error. 142197883Sgibbs * It's good to be the target! 142297883Sgibbs */ 142397883Sgibbs u_int active_scb_index; 142497883Sgibbs u_int saved_scbptr; 142597883Sgibbs 142697883Sgibbs saved_scbptr = ahd_get_scbptr(ahd); 142797883Sgibbs active_scb_index = saved_scbptr; 142897883Sgibbs 142997883Sgibbs if (last_phase != P_BUSFREE 143097883Sgibbs && (ahd_inb(ahd, SEQ_FLAGS) & NOT_IDENTIFIED) == 0 143197883Sgibbs && (active_scb_index < ahd->scb_data.numscbs)) { 143297883Sgibbs struct scb *active_scb; 143397883Sgibbs 143497883Sgibbs /* 143597883Sgibbs * If the active SCB is not us, assume that 143697883Sgibbs * the active SCB has a longer timeout than 143797883Sgibbs * the timedout SCB, and wait for the active 143897883Sgibbs * SCB to timeout. 143997883Sgibbs */ 144097883Sgibbs active_scb = ahd_lookup_scb(ahd, active_scb_index); 144197883Sgibbs if (active_scb != scb) { 144297883Sgibbs struct ccb_hdr *ccbh; 144397883Sgibbs uint64_t newtimeout; 144497883Sgibbs 144597883Sgibbs ahd_print_path(ahd, scb); 144697883Sgibbs printf("Other SCB Timeout%s", 144797883Sgibbs (scb->flags & SCB_OTHERTCL_TIMEOUT) != 0 144897883Sgibbs ? " again\n" : "\n"); 144997883Sgibbs scb->flags |= SCB_OTHERTCL_TIMEOUT; 145097883Sgibbs newtimeout = 145197883Sgibbs MAX(active_scb->io_ctx->ccb_h.timeout, 145297883Sgibbs scb->io_ctx->ccb_h.timeout); 145397883Sgibbs newtimeout *= hz; 145497883Sgibbs newtimeout /= 1000; 145597883Sgibbs ccbh = &scb->io_ctx->ccb_h; 145697883Sgibbs scb->io_ctx->ccb_h.timeout_ch = 145797883Sgibbs timeout(ahd_timeout, scb, newtimeout); 145897883Sgibbs ahd_unpause(ahd); 145997883Sgibbs ahd_unlock(ahd, &s); 146097883Sgibbs return; 146197883Sgibbs } 146297883Sgibbs 146397883Sgibbs /* It's us */ 146497883Sgibbs if ((scb->hscb->control & TARGET_SCB) != 0) { 146597883Sgibbs 146697883Sgibbs /* 146797883Sgibbs * Send back any queued up transactions 146897883Sgibbs * and properly record the error condition. 146997883Sgibbs */ 147097883Sgibbs ahd_abort_scbs(ahd, SCB_GET_TARGET(ahd, scb), 147197883Sgibbs SCB_GET_CHANNEL(ahd, scb), 147297883Sgibbs SCB_GET_LUN(scb), 147397883Sgibbs SCB_GET_TAG(scb), 147497883Sgibbs ROLE_TARGET, 147597883Sgibbs CAM_CMD_TIMEOUT); 147697883Sgibbs 147797883Sgibbs /* Will clear us from the bus */ 147897883Sgibbs ahd_restart(ahd); 147997883Sgibbs ahd_unlock(ahd, &s); 148097883Sgibbs return; 148197883Sgibbs } 148297883Sgibbs 148397883Sgibbs ahd_set_recoveryscb(ahd, active_scb); 148497883Sgibbs ahd_outb(ahd, MSG_OUT, HOST_MSG); 148597883Sgibbs ahd_outb(ahd, SCSISIGO, last_phase|ATNO); 148697883Sgibbs ahd_print_path(ahd, active_scb); 148797883Sgibbs printf("BDR message in message buffer\n"); 148897883Sgibbs active_scb->flags |= SCB_DEVICE_RESET; 148997883Sgibbs active_scb->io_ctx->ccb_h.timeout_ch = 149097883Sgibbs timeout(ahd_timeout, (caddr_t)active_scb, 2 * hz); 149197883Sgibbs ahd_unpause(ahd); 149297883Sgibbs } else { 149397883Sgibbs int disconnected; 149497883Sgibbs 149597883Sgibbs /* XXX Shouldn't panic. Just punt instead? */ 149697883Sgibbs if ((scb->hscb->control & TARGET_SCB) != 0) 149797883Sgibbs panic("Timed-out target SCB but bus idle"); 149897883Sgibbs 149997883Sgibbs if (last_phase != P_BUSFREE 150097883Sgibbs && (ahd_inb(ahd, SSTAT0) & TARGET) != 0) { 150197883Sgibbs /* XXX What happened to the SCB? */ 150297883Sgibbs /* Hung target selection. Goto busfree */ 150397883Sgibbs printf("%s: Hung target selection\n", 150497883Sgibbs ahd_name(ahd)); 150597883Sgibbs ahd_restart(ahd); 150697883Sgibbs ahd_unlock(ahd, &s); 150797883Sgibbs return; 150897883Sgibbs } 150997883Sgibbs 151097883Sgibbs if (ahd_search_qinfifo(ahd, target, channel, lun, 151197883Sgibbs SCB_GET_TAG(scb), ROLE_INITIATOR, 151297883Sgibbs /*status*/0, SEARCH_COUNT) > 0) { 151397883Sgibbs disconnected = FALSE; 151497883Sgibbs } else { 151597883Sgibbs disconnected = TRUE; 151697883Sgibbs } 151797883Sgibbs 151897883Sgibbs if (disconnected) { 151997883Sgibbs 152097883Sgibbs ahd_set_recoveryscb(ahd, scb); 152197883Sgibbs /* 152297883Sgibbs * Actually re-queue this SCB in an attempt 152397883Sgibbs * to select the device before it reconnects. 152497883Sgibbs * In either case (selection or reselection), 152597883Sgibbs * we will now issue a target reset to the 152697883Sgibbs * timed-out device. 152797883Sgibbs * 152897883Sgibbs * Set the MK_MESSAGE control bit indicating 152997883Sgibbs * that we desire to send a message. We 153097883Sgibbs * also set the disconnected flag since 153197883Sgibbs * in the paging case there is no guarantee 153297883Sgibbs * that our SCB control byte matches the 153397883Sgibbs * version on the card. We don't want the 153497883Sgibbs * sequencer to abort the command thinking 153597883Sgibbs * an unsolicited reselection occurred. 153697883Sgibbs */ 153797883Sgibbs scb->hscb->control |= MK_MESSAGE|DISCONNECTED; 153897883Sgibbs scb->flags |= SCB_DEVICE_RESET; 153997883Sgibbs 154097883Sgibbs /* 154197883Sgibbs * The sequencer will never re-reference the 154297883Sgibbs * in-core SCB. To make sure we are notified 154397883Sgibbs * during reslection, set the MK_MESSAGE flag 154497883Sgibbs * in the card's copy of the SCB. 154597883Sgibbs */ 154697883Sgibbs ahd_set_scbptr(ahd, SCB_GET_TAG(scb)); 154797883Sgibbs ahd_outb(ahd, SCB_CONTROL, 154897883Sgibbs ahd_inb(ahd, SCB_CONTROL)|MK_MESSAGE); 154997883Sgibbs 155097883Sgibbs /* 155197883Sgibbs * Clear out any entries in the QINFIFO first 155297883Sgibbs * so we are the next SCB for this target 155397883Sgibbs * to run. 155497883Sgibbs */ 155597883Sgibbs ahd_search_qinfifo(ahd, 155697883Sgibbs SCB_GET_TARGET(ahd, scb), 155797883Sgibbs channel, SCB_GET_LUN(scb), 155897883Sgibbs SCB_LIST_NULL, 155997883Sgibbs ROLE_INITIATOR, 156097883Sgibbs CAM_REQUEUE_REQ, 156197883Sgibbs SEARCH_COMPLETE); 156297883Sgibbs ahd_print_path(ahd, scb); 156397883Sgibbs printf("Queuing a BDR SCB\n"); 156497883Sgibbs ahd_qinfifo_requeue_tail(ahd, scb); 156597883Sgibbs ahd_set_scbptr(ahd, saved_scbptr); 156697883Sgibbs scb->io_ctx->ccb_h.timeout_ch = 156797883Sgibbs timeout(ahd_timeout, (caddr_t)scb, 2 * hz); 156897883Sgibbs ahd_unpause(ahd); 156997883Sgibbs } else { 157097883Sgibbs /* Go "immediatly" to the bus reset */ 157197883Sgibbs /* This shouldn't happen */ 157297883Sgibbs ahd_set_recoveryscb(ahd, scb); 157397883Sgibbs ahd_print_path(ahd, scb); 157497883Sgibbs printf("SCB %d: Immediate reset. " 157597883Sgibbs "Flags = 0x%x\n", SCB_GET_TAG(scb), 157697883Sgibbs scb->flags); 157797883Sgibbs goto bus_reset; 157897883Sgibbs } 157997883Sgibbs } 158097883Sgibbs } 158197883Sgibbs ahd_unlock(ahd, &s); 158297883Sgibbs#endif 158397883Sgibbs} 158497883Sgibbs 158597883Sgibbsstatic void 158697883Sgibbsahd_abort_ccb(struct ahd_softc *ahd, struct cam_sim *sim, union ccb *ccb) 158797883Sgibbs{ 158897883Sgibbs union ccb *abort_ccb; 158997883Sgibbs 159097883Sgibbs abort_ccb = ccb->cab.abort_ccb; 159197883Sgibbs switch (abort_ccb->ccb_h.func_code) { 159297883Sgibbs#ifdef AHD_TARGET_MODE 159397883Sgibbs case XPT_ACCEPT_TARGET_IO: 159497883Sgibbs case XPT_IMMED_NOTIFY: 159597883Sgibbs case XPT_CONT_TARGET_IO: 159697883Sgibbs { 159797883Sgibbs struct ahd_tmode_tstate *tstate; 159897883Sgibbs struct ahd_tmode_lstate *lstate; 159997883Sgibbs struct ccb_hdr_slist *list; 160097883Sgibbs cam_status status; 160197883Sgibbs 160297883Sgibbs status = ahd_find_tmode_devs(ahd, sim, abort_ccb, &tstate, 160397883Sgibbs &lstate, TRUE); 160497883Sgibbs 160597883Sgibbs if (status != CAM_REQ_CMP) { 160697883Sgibbs ccb->ccb_h.status = status; 160797883Sgibbs break; 160897883Sgibbs } 160997883Sgibbs 161097883Sgibbs if (abort_ccb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) 161197883Sgibbs list = &lstate->accept_tios; 161297883Sgibbs else if (abort_ccb->ccb_h.func_code == XPT_IMMED_NOTIFY) 161397883Sgibbs list = &lstate->immed_notifies; 161497883Sgibbs else 161597883Sgibbs list = NULL; 161697883Sgibbs 161797883Sgibbs if (list != NULL) { 161897883Sgibbs struct ccb_hdr *curelm; 161997883Sgibbs int found; 162097883Sgibbs 162197883Sgibbs curelm = SLIST_FIRST(list); 162297883Sgibbs found = 0; 162397883Sgibbs if (curelm == &abort_ccb->ccb_h) { 162497883Sgibbs found = 1; 162597883Sgibbs SLIST_REMOVE_HEAD(list, sim_links.sle); 162697883Sgibbs } else { 162797883Sgibbs while(curelm != NULL) { 162897883Sgibbs struct ccb_hdr *nextelm; 162997883Sgibbs 163097883Sgibbs nextelm = 163197883Sgibbs SLIST_NEXT(curelm, sim_links.sle); 163297883Sgibbs 163397883Sgibbs if (nextelm == &abort_ccb->ccb_h) { 163497883Sgibbs found = 1; 163597883Sgibbs SLIST_NEXT(curelm, 163697883Sgibbs sim_links.sle) = 163797883Sgibbs SLIST_NEXT(nextelm, 163897883Sgibbs sim_links.sle); 163997883Sgibbs break; 164097883Sgibbs } 164197883Sgibbs curelm = nextelm; 164297883Sgibbs } 164397883Sgibbs } 164497883Sgibbs 164597883Sgibbs if (found) { 164697883Sgibbs abort_ccb->ccb_h.status = CAM_REQ_ABORTED; 164797883Sgibbs xpt_done(abort_ccb); 164897883Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 164997883Sgibbs } else { 165097883Sgibbs xpt_print_path(abort_ccb->ccb_h.path); 165197883Sgibbs printf("Not found\n"); 165297883Sgibbs ccb->ccb_h.status = CAM_PATH_INVALID; 165397883Sgibbs } 165497883Sgibbs break; 165597883Sgibbs } 165697883Sgibbs /* FALLTHROUGH */ 165797883Sgibbs } 165897883Sgibbs#endif 165997883Sgibbs case XPT_SCSI_IO: 166097883Sgibbs /* XXX Fully implement the hard ones */ 166197883Sgibbs ccb->ccb_h.status = CAM_UA_ABORT; 166297883Sgibbs break; 166397883Sgibbs default: 166497883Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 166597883Sgibbs break; 166697883Sgibbs } 166797883Sgibbs xpt_done(ccb); 166897883Sgibbs} 166997883Sgibbs 167097883Sgibbsvoid 167197883Sgibbsahd_send_async(struct ahd_softc *ahd, char channel, u_int target, 167297883Sgibbs u_int lun, ac_code code, void *opt_arg) 167397883Sgibbs{ 167497883Sgibbs struct ccb_trans_settings cts; 167597883Sgibbs struct cam_path *path; 167697883Sgibbs void *arg; 167797883Sgibbs int error; 167897883Sgibbs 167997883Sgibbs arg = NULL; 168097883Sgibbs error = ahd_create_path(ahd, channel, target, lun, &path); 168197883Sgibbs 168297883Sgibbs if (error != CAM_REQ_CMP) 168397883Sgibbs return; 168497883Sgibbs 168597883Sgibbs switch (code) { 168697883Sgibbs case AC_TRANSFER_NEG: 168797883Sgibbs { 168897883Sgibbs#ifdef AHD_NEW_TRAN_SETTINGS 168997883Sgibbs struct ccb_trans_settings_scsi *scsi; 169097883Sgibbs 169197883Sgibbs cts.type = CTS_TYPE_CURRENT_SETTINGS; 169297883Sgibbs scsi = &cts.proto_specific.scsi; 169397883Sgibbs#else 169497883Sgibbs cts.flags = CCB_TRANS_CURRENT_SETTINGS; 169597883Sgibbs#endif 169697883Sgibbs cts.ccb_h.path = path; 169797883Sgibbs cts.ccb_h.target_id = target; 169897883Sgibbs cts.ccb_h.target_lun = lun; 169997883Sgibbs ahd_get_tran_settings(ahd, ahd->our_id, channel, &cts); 170097883Sgibbs arg = &cts; 170197883Sgibbs#ifdef AHD_NEW_TRAN_SETTINGS 170297883Sgibbs scsi->valid &= ~CTS_SCSI_VALID_TQ; 170397883Sgibbs scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 170497883Sgibbs#else 170597883Sgibbs cts.valid &= ~CCB_TRANS_TQ_VALID; 170697883Sgibbs cts.flags &= ~CCB_TRANS_TAG_ENB; 170797883Sgibbs#endif 170897883Sgibbs if (opt_arg == NULL) 170997883Sgibbs break; 171097883Sgibbs if (*((ahd_queue_alg *)opt_arg) == AHD_QUEUE_TAGGED) 171197883Sgibbs#ifdef AHD_NEW_TRAN_SETTINGS 171297883Sgibbs scsi->flags |= ~CTS_SCSI_FLAGS_TAG_ENB; 171397883Sgibbs scsi->valid |= CTS_SCSI_VALID_TQ; 171497883Sgibbs#else 171597883Sgibbs cts.flags |= CCB_TRANS_TAG_ENB; 171697883Sgibbs cts.valid |= CCB_TRANS_TQ_VALID; 171797883Sgibbs#endif 171897883Sgibbs break; 171997883Sgibbs } 172097883Sgibbs case AC_SENT_BDR: 172197883Sgibbs case AC_BUS_RESET: 172297883Sgibbs break; 172397883Sgibbs default: 172497883Sgibbs panic("ahd_send_async: Unexpected async event"); 172597883Sgibbs } 172697883Sgibbs xpt_async(code, path, arg); 172797883Sgibbs xpt_free_path(path); 172897883Sgibbs} 172997883Sgibbs 173097883Sgibbsvoid 173197883Sgibbsahd_platform_set_tags(struct ahd_softc *ahd, 173297883Sgibbs struct ahd_devinfo *devinfo, int enable) 173397883Sgibbs{ 173497883Sgibbs} 173597883Sgibbs 173697883Sgibbsint 173797883Sgibbsahd_platform_alloc(struct ahd_softc *ahd, void *platform_arg) 173897883Sgibbs{ 173997883Sgibbs ahd->platform_data = malloc(sizeof(struct ahd_platform_data), M_DEVBUF, 174097883Sgibbs M_NOWAIT | M_ZERO); 174197883Sgibbs if (ahd->platform_data == NULL) 174297883Sgibbs return (ENOMEM); 174397883Sgibbs return (0); 174497883Sgibbs} 174597883Sgibbs 174697883Sgibbsvoid 174797883Sgibbsahd_platform_free(struct ahd_softc *ahd) 174897883Sgibbs{ 174997883Sgibbs struct ahd_platform_data *pdata; 175097883Sgibbs 175197883Sgibbs pdata = ahd->platform_data; 175297883Sgibbs if (pdata != NULL) { 175397883Sgibbs if (pdata->regs[0] != NULL) 175497883Sgibbs bus_release_resource(ahd->dev_softc, 175597883Sgibbs pdata->regs_res_type[0], 175697883Sgibbs pdata->regs_res_id[0], 175797883Sgibbs pdata->regs[0]); 175897883Sgibbs 175997883Sgibbs if (pdata->regs[1] != NULL) 176097883Sgibbs bus_release_resource(ahd->dev_softc, 176197883Sgibbs pdata->regs_res_type[1], 176297883Sgibbs pdata->regs_res_id[1], 176397883Sgibbs pdata->regs[1]); 176497883Sgibbs 176597883Sgibbs if (pdata->irq != NULL) 176697883Sgibbs bus_release_resource(ahd->dev_softc, 176797883Sgibbs pdata->irq_res_type, 176897883Sgibbs 0, pdata->irq); 176997883Sgibbs 177097883Sgibbs if (pdata->sim_b != NULL) { 177197883Sgibbs xpt_async(AC_LOST_DEVICE, pdata->path_b, NULL); 177297883Sgibbs xpt_free_path(pdata->path_b); 177397883Sgibbs xpt_bus_deregister(cam_sim_path(pdata->sim_b)); 177497883Sgibbs cam_sim_free(pdata->sim_b, /*free_devq*/TRUE); 177597883Sgibbs } 177697883Sgibbs if (pdata->sim != NULL) { 177797883Sgibbs xpt_async(AC_LOST_DEVICE, pdata->path, NULL); 177897883Sgibbs xpt_free_path(pdata->path); 177997883Sgibbs xpt_bus_deregister(cam_sim_path(pdata->sim)); 178097883Sgibbs cam_sim_free(pdata->sim, /*free_devq*/TRUE); 178197883Sgibbs } 178297883Sgibbs if (pdata->eh != NULL) 178397883Sgibbs EVENTHANDLER_DEREGISTER(shutdown_final, pdata->eh); 178497883Sgibbs free(ahd->platform_data, M_DEVBUF); 178597883Sgibbs } 178697883Sgibbs} 178797883Sgibbs 178897883Sgibbsint 178997883Sgibbsahd_softc_comp(struct ahd_softc *lahd, struct ahd_softc *rahd) 179097883Sgibbs{ 179197883Sgibbs /* We don't sort softcs under FreeBSD so report equal always */ 179297883Sgibbs return (0); 179397883Sgibbs} 179497883Sgibbs 179597883Sgibbsint 179697883Sgibbsahd_detach(device_t dev) 179797883Sgibbs{ 179897883Sgibbs struct ahd_softc *ahd; 179997883Sgibbs u_long l; 180097883Sgibbs u_long s; 180197883Sgibbs 180297883Sgibbs ahd_list_lock(&l); 180397883Sgibbs device_printf(dev, "detaching device\n"); 180497883Sgibbs ahd = device_get_softc(dev); 180597883Sgibbs ahd = ahd_find_softc(ahd); 180697883Sgibbs if (ahd == NULL) { 180797883Sgibbs device_printf(dev, "aic7xxx already detached\n"); 180897883Sgibbs ahd_list_unlock(&l); 180997883Sgibbs return (ENOENT); 181097883Sgibbs } 181197883Sgibbs ahd_lock(ahd, &s); 181297883Sgibbs ahd_intr_enable(ahd, FALSE); 181397883Sgibbs bus_teardown_intr(dev, ahd->platform_data->irq, ahd->platform_data->ih); 181497883Sgibbs ahd_unlock(ahd, &s); 181597883Sgibbs ahd_free(ahd); 181697883Sgibbs ahd_list_unlock(&l); 181797883Sgibbs return (0); 181897883Sgibbs} 181997883Sgibbs 182097883Sgibbs#if UNUSED 182197883Sgibbsstatic void 182297883Sgibbsahd_dump_targcmd(struct target_cmd *cmd) 182397883Sgibbs{ 182497883Sgibbs uint8_t *byte; 182597883Sgibbs uint8_t *last_byte; 182697883Sgibbs int i; 182797883Sgibbs 182897883Sgibbs byte = &cmd->initiator_channel; 182997883Sgibbs /* Debugging info for received commands */ 183097883Sgibbs last_byte = &cmd[1].initiator_channel; 183197883Sgibbs 183297883Sgibbs i = 0; 183397883Sgibbs while (byte < last_byte) { 183497883Sgibbs if (i == 0) 183597883Sgibbs printf("\t"); 183697883Sgibbs printf("%#x", *byte++); 183797883Sgibbs i++; 183897883Sgibbs if (i == 8) { 183997883Sgibbs printf("\n"); 184097883Sgibbs i = 0; 184197883Sgibbs } else { 184297883Sgibbs printf(", "); 184397883Sgibbs } 184497883Sgibbs } 184597883Sgibbs} 184697883Sgibbs#endif 184797883Sgibbs 184897883Sgibbsstatic int 184997883Sgibbsahd_modevent(module_t mod, int type, void *data) 185097883Sgibbs{ 185197883Sgibbs /* XXX Deal with busy status on unload. */ 185297883Sgibbs return 0; 185397883Sgibbs} 185497883Sgibbs 185597883Sgibbsstatic moduledata_t ahd_mod = { 185697883Sgibbs "ahd", 185797883Sgibbs ahd_modevent, 185897883Sgibbs NULL 185997883Sgibbs}; 186097883Sgibbs 186197883Sgibbs/********************************** DDB Hooks *********************************/ 186297883Sgibbs#ifdef DDB 186397883Sgibbsstatic struct ahd_softc *ahd_ddb_softc; 186497883Sgibbsstatic int ahd_ddb_paused; 186597883Sgibbsstatic int ahd_ddb_paused_on_entry; 186697883SgibbsDB_COMMAND(ahd_set_unit, ahd_ddb_set_unit) 186797883Sgibbs{ 186897883Sgibbs struct ahd_softc *list_ahd; 186997883Sgibbs 187097883Sgibbs ahd_ddb_softc = NULL; 187197883Sgibbs TAILQ_FOREACH(list_ahd, &ahd_tailq, links) { 187297883Sgibbs if (list_ahd->unit == addr) 187397883Sgibbs ahd_ddb_softc = list_ahd; 187497883Sgibbs } 187597883Sgibbs if (ahd_ddb_softc == NULL) 187697883Sgibbs db_error("No matching softc found!\n"); 187797883Sgibbs} 187897883Sgibbs 187997883SgibbsDB_COMMAND(ahd_pause, ahd_ddb_pause) 188097883Sgibbs{ 188197883Sgibbs if (ahd_ddb_softc == NULL) { 188297883Sgibbs db_error("Must set unit with ahd_set_unit first!\n"); 188397883Sgibbs return; 188497883Sgibbs } 188597883Sgibbs if (ahd_ddb_paused == 0) { 188697883Sgibbs ahd_ddb_paused++; 188797883Sgibbs if (ahd_is_paused(ahd_ddb_softc)) { 188897883Sgibbs ahd_ddb_paused_on_entry++; 188997883Sgibbs return; 189097883Sgibbs } 189197883Sgibbs ahd_pause(ahd_ddb_softc); 189297883Sgibbs } 189397883Sgibbs} 189497883Sgibbs 189597883SgibbsDB_COMMAND(ahd_unpause, ahd_ddb_unpause) 189697883Sgibbs{ 189797883Sgibbs if (ahd_ddb_softc == NULL) { 189897883Sgibbs db_error("Must set unit with ahd_set_unit first!\n"); 189997883Sgibbs return; 190097883Sgibbs } 190197883Sgibbs if (ahd_ddb_paused != 0) { 190297883Sgibbs ahd_ddb_paused = 0; 190397883Sgibbs if (ahd_ddb_paused_on_entry) 190497883Sgibbs return; 190597883Sgibbs ahd_unpause(ahd_ddb_softc); 190697883Sgibbs } else if (ahd_ddb_paused_on_entry != 0) { 190797883Sgibbs /* Two unpauses to clear a paused on entry. */ 190897883Sgibbs ahd_ddb_paused_on_entry = 0; 190997883Sgibbs ahd_unpause(ahd_ddb_softc); 191097883Sgibbs } 191197883Sgibbs} 191297883Sgibbs 191397883SgibbsDB_COMMAND(ahd_in, ahd_ddb_in) 191497883Sgibbs{ 191597883Sgibbs int c; 191697883Sgibbs int size; 191797883Sgibbs 191897883Sgibbs if (ahd_ddb_softc == NULL) { 191997883Sgibbs db_error("Must set unit with ahd_set_unit first!\n"); 192097883Sgibbs return; 192197883Sgibbs } 192297883Sgibbs if (have_addr == 0) 192397883Sgibbs return; 192497883Sgibbs 192597883Sgibbs size = 1; 192697883Sgibbs while ((c = *modif++) != '\0') { 192797883Sgibbs switch (c) { 192897883Sgibbs case 'b': 192997883Sgibbs size = 1; 193097883Sgibbs break; 193197883Sgibbs case 'w': 193297883Sgibbs size = 2; 193397883Sgibbs break; 193497883Sgibbs case 'l': 193597883Sgibbs size = 4; 193697883Sgibbs break; 193797883Sgibbs } 193897883Sgibbs } 193997883Sgibbs 194097883Sgibbs if (count <= 0) 194197883Sgibbs count = 1; 194297883Sgibbs while (--count >= 0) { 1943107368Sscottl db_printf("%04lx (M)%x: \t", (u_long)addr, 194497883Sgibbs ahd_inb(ahd_ddb_softc, MODE_PTR)); 194597883Sgibbs switch (size) { 194697883Sgibbs case 1: 194797883Sgibbs db_printf("%02x\n", ahd_inb(ahd_ddb_softc, addr)); 194897883Sgibbs break; 194997883Sgibbs case 2: 195097883Sgibbs db_printf("%04x\n", ahd_inw(ahd_ddb_softc, addr)); 195197883Sgibbs break; 195297883Sgibbs case 4: 195397883Sgibbs db_printf("%08x\n", ahd_inl(ahd_ddb_softc, addr)); 195497883Sgibbs break; 195597883Sgibbs } 195697883Sgibbs } 195797883Sgibbs} 195897883Sgibbs 195997883SgibbsDB_SET(ahd_out, ahd_ddb_out, db_cmd_set, CS_MORE, NULL) 196097883Sgibbs{ 196197883Sgibbs db_expr_t old_value; 196297883Sgibbs db_expr_t new_value; 196397883Sgibbs int size; 196497883Sgibbs 196597883Sgibbs if (ahd_ddb_softc == NULL) { 196697883Sgibbs db_error("Must set unit with ahd_set_unit first!\n"); 196797883Sgibbs return; 196897883Sgibbs } 196997883Sgibbs 197097883Sgibbs switch (modif[0]) { 197197883Sgibbs case '\0': 197297883Sgibbs case 'b': 197397883Sgibbs size = 1; 197497883Sgibbs break; 197597883Sgibbs case 'h': 197697883Sgibbs size = 2; 197797883Sgibbs break; 197897883Sgibbs case 'l': 197997883Sgibbs size = 4; 198097883Sgibbs break; 198197883Sgibbs default: 198297883Sgibbs db_error("Unknown size\n"); 198397883Sgibbs return; 198497883Sgibbs } 198597883Sgibbs 198697883Sgibbs while (db_expression(&new_value)) { 198797883Sgibbs switch (size) { 198897883Sgibbs default: 198997883Sgibbs case 1: 199097883Sgibbs old_value = ahd_inb(ahd_ddb_softc, addr); 199197883Sgibbs ahd_outb(ahd_ddb_softc, addr, new_value); 199297883Sgibbs break; 199397883Sgibbs case 2: 199497883Sgibbs old_value = ahd_inw(ahd_ddb_softc, addr); 199597883Sgibbs ahd_outw(ahd_ddb_softc, addr, new_value); 199697883Sgibbs break; 199797883Sgibbs case 4: 199897883Sgibbs old_value = ahd_inl(ahd_ddb_softc, addr); 199997883Sgibbs ahd_outl(ahd_ddb_softc, addr, new_value); 200097883Sgibbs break; 200197883Sgibbs } 2002107368Sscottl db_printf("%04lx (M)%x: \t0x%lx\t=\t0x%lx", 2003107368Sscottl (u_long)addr, ahd_inb(ahd_ddb_softc, MODE_PTR), 2004107368Sscottl (u_long)old_value, (u_long)new_value); 200597883Sgibbs addr += size; 200697883Sgibbs } 200797883Sgibbs db_skip_to_eol(); 200897883Sgibbs} 200997883Sgibbs 201097883Sgibbs#endif 201197883Sgibbs 201297883Sgibbs 201397883SgibbsDECLARE_MODULE(ahd, ahd_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); 201497883SgibbsMODULE_DEPEND(ahd, cam, 1, 1, 1); 201597883SgibbsMODULE_VERSION(ahd, 1); 2016