aic79xx_osm.c revision 107368
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 * 32102684Sgibbs * $Id: //depot/aic7xxx/freebsd/dev/aic7xxx/aic79xx_osm.c#22 $ 3397883Sgibbs * 3497883Sgibbs * $FreeBSD: head/sys/dev/aic7xxx/aic79xx_osm.c 107368 2002-11-28 04:09:29Z scottl $ 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; 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 49197883Sgibbs if (ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) 49297883Sgibbs hscb->control |= ccb->csio.tag_action; 49397883Sgibbs 49497883Sgibbs ahd_setup_data(ahd, sim, &ccb->csio, scb); 49597883Sgibbs } 49697883Sgibbs break; 49797883Sgibbs } 49897883Sgibbs#ifdef AHD_TARGET_MODE 49997883Sgibbs case XPT_NOTIFY_ACK: 50097883Sgibbs case XPT_IMMED_NOTIFY: 50197883Sgibbs { 50297883Sgibbs struct ahd_tmode_tstate *tstate; 50397883Sgibbs struct ahd_tmode_lstate *lstate; 50497883Sgibbs cam_status status; 50597883Sgibbs 50697883Sgibbs status = ahd_find_tmode_devs(ahd, sim, ccb, &tstate, 50797883Sgibbs &lstate, TRUE); 50897883Sgibbs 50997883Sgibbs if (status != CAM_REQ_CMP) { 51097883Sgibbs ccb->ccb_h.status = status; 51197883Sgibbs xpt_done(ccb); 51297883Sgibbs break; 51397883Sgibbs } 51497883Sgibbs SLIST_INSERT_HEAD(&lstate->immed_notifies, &ccb->ccb_h, 51597883Sgibbs sim_links.sle); 51697883Sgibbs ccb->ccb_h.status = CAM_REQ_INPROG; 51797883Sgibbs ahd_send_lstate_events(ahd, lstate); 51897883Sgibbs break; 51997883Sgibbs } 52097883Sgibbs case XPT_EN_LUN: /* Enable LUN as a target */ 52197883Sgibbs ahd_handle_en_lun(ahd, sim, ccb); 52297883Sgibbs xpt_done(ccb); 52397883Sgibbs break; 52497883Sgibbs#endif 52597883Sgibbs case XPT_ABORT: /* Abort the specified CCB */ 52697883Sgibbs { 52797883Sgibbs ahd_abort_ccb(ahd, sim, ccb); 52897883Sgibbs break; 52997883Sgibbs } 53097883Sgibbs case XPT_SET_TRAN_SETTINGS: 53197883Sgibbs { 53297883Sgibbs ahd_lock(ahd, &s); 53397883Sgibbs ahd_set_tran_settings(ahd, SIM_SCSI_ID(ahd, sim), 53497883Sgibbs SIM_CHANNEL(ahd, sim), &ccb->cts); 53597883Sgibbs ahd_unlock(ahd, &s); 53697883Sgibbs xpt_done(ccb); 53797883Sgibbs break; 53897883Sgibbs } 53997883Sgibbs case XPT_GET_TRAN_SETTINGS: 54097883Sgibbs /* Get default/user set transfer settings for the target */ 54197883Sgibbs { 54297883Sgibbs ahd_lock(ahd, &s); 54397883Sgibbs ahd_get_tran_settings(ahd, SIM_SCSI_ID(ahd, sim), 54497883Sgibbs SIM_CHANNEL(ahd, sim), &ccb->cts); 54597883Sgibbs ahd_unlock(ahd, &s); 54697883Sgibbs xpt_done(ccb); 54797883Sgibbs break; 54897883Sgibbs } 54997883Sgibbs case XPT_CALC_GEOMETRY: 55097883Sgibbs { 55197883Sgibbs struct ccb_calc_geometry *ccg; 55297883Sgibbs uint32_t size_mb; 55397883Sgibbs uint32_t secs_per_cylinder; 55497883Sgibbs int extended; 55597883Sgibbs 55697883Sgibbs ccg = &ccb->ccg; 55797883Sgibbs size_mb = ccg->volume_size 55897883Sgibbs / ((1024L * 1024L) / ccg->block_size); 55997883Sgibbs extended = ahd->flags & AHD_EXTENDED_TRANS_A; 56097883Sgibbs 56197883Sgibbs if (size_mb > 1024 && extended) { 56297883Sgibbs ccg->heads = 255; 56397883Sgibbs ccg->secs_per_track = 63; 56497883Sgibbs } else { 56597883Sgibbs ccg->heads = 64; 56697883Sgibbs ccg->secs_per_track = 32; 56797883Sgibbs } 56897883Sgibbs secs_per_cylinder = ccg->heads * ccg->secs_per_track; 56997883Sgibbs ccg->cylinders = ccg->volume_size / secs_per_cylinder; 57097883Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 57197883Sgibbs xpt_done(ccb); 57297883Sgibbs break; 57397883Sgibbs } 57497883Sgibbs case XPT_RESET_BUS: /* Reset the specified SCSI bus */ 57597883Sgibbs { 57697883Sgibbs int found; 57797883Sgibbs 57897883Sgibbs ahd_lock(ahd, &s); 57997883Sgibbs found = ahd_reset_channel(ahd, SIM_CHANNEL(ahd, sim), 58097883Sgibbs /*initiate reset*/TRUE); 58197883Sgibbs ahd_unlock(ahd, &s); 58297883Sgibbs if (bootverbose) { 58397883Sgibbs xpt_print_path(SIM_PATH(ahd, sim)); 58497883Sgibbs printf("SCSI bus reset delivered. " 58597883Sgibbs "%d SCBs aborted.\n", found); 58697883Sgibbs } 58797883Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 58897883Sgibbs xpt_done(ccb); 58997883Sgibbs break; 59097883Sgibbs } 59197883Sgibbs case XPT_TERM_IO: /* Terminate the I/O process */ 59297883Sgibbs /* XXX Implement */ 59397883Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 59497883Sgibbs xpt_done(ccb); 59597883Sgibbs break; 59697883Sgibbs case XPT_PATH_INQ: /* Path routing inquiry */ 59797883Sgibbs { 59897883Sgibbs struct ccb_pathinq *cpi = &ccb->cpi; 59997883Sgibbs 60097883Sgibbs cpi->version_num = 1; /* XXX??? */ 60197883Sgibbs cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE; 60297883Sgibbs if ((ahd->features & AHD_WIDE) != 0) 60397883Sgibbs cpi->hba_inquiry |= PI_WIDE_16; 60497883Sgibbs if ((ahd->features & AHD_TARGETMODE) != 0) { 60597883Sgibbs cpi->target_sprt = PIT_PROCESSOR 60697883Sgibbs | PIT_DISCONNECT 60797883Sgibbs | PIT_TERM_IO; 60897883Sgibbs } else { 60997883Sgibbs cpi->target_sprt = 0; 61097883Sgibbs } 61197883Sgibbs cpi->hba_misc = 0; 61297883Sgibbs cpi->hba_eng_cnt = 0; 61397883Sgibbs cpi->max_target = (ahd->features & AHD_WIDE) ? 15 : 7; 61497883Sgibbs cpi->max_lun = AHD_NUM_LUNS - 1; 61597883Sgibbs cpi->initiator_id = ahd->our_id; 61697883Sgibbs if ((ahd->flags & AHD_RESET_BUS_A) == 0) { 61797883Sgibbs cpi->hba_misc |= PIM_NOBUSRESET; 61897883Sgibbs } 61997883Sgibbs cpi->bus_id = cam_sim_bus(sim); 62097883Sgibbs cpi->base_transfer_speed = 3300; 62197883Sgibbs strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 62297883Sgibbs strncpy(cpi->hba_vid, "Adaptec", HBA_IDLEN); 62397883Sgibbs strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 62497883Sgibbs cpi->unit_number = cam_sim_unit(sim); 62597883Sgibbs#ifdef AHD_NEW_TRAN_SETTINGS 62697883Sgibbs cpi->protocol = PROTO_SCSI; 62797883Sgibbs cpi->protocol_version = SCSI_REV_2; 62897883Sgibbs cpi->transport = XPORT_SPI; 62997883Sgibbs cpi->transport_version = 2; 63097883Sgibbs cpi->xport_specific.spi.ppr_options = SID_SPI_CLOCK_ST; 63197883Sgibbs cpi->transport_version = 4; 63297883Sgibbs cpi->xport_specific.spi.ppr_options = SID_SPI_CLOCK_DT_ST; 63397883Sgibbs#endif 63497883Sgibbs cpi->ccb_h.status = CAM_REQ_CMP; 63597883Sgibbs xpt_done(ccb); 63697883Sgibbs break; 63797883Sgibbs } 63897883Sgibbs default: 63997883Sgibbs ccb->ccb_h.status = CAM_PROVIDE_FAIL; 64097883Sgibbs xpt_done(ccb); 64197883Sgibbs break; 64297883Sgibbs } 64397883Sgibbs} 64497883Sgibbs 64597883Sgibbs 64697883Sgibbsstatic void 64797883Sgibbsahd_set_tran_settings(struct ahd_softc *ahd, int our_id, char channel, 64897883Sgibbs struct ccb_trans_settings *cts) 64997883Sgibbs{ 65097883Sgibbs#ifdef AHD_NEW_TRAN_SETTINGS 65197883Sgibbs struct ahd_devinfo devinfo; 65297883Sgibbs struct ccb_trans_settings_scsi *scsi; 65397883Sgibbs struct ccb_trans_settings_spi *spi; 65497883Sgibbs struct ahd_initiator_tinfo *tinfo; 65597883Sgibbs struct ahd_tmode_tstate *tstate; 65697883Sgibbs uint16_t *discenable; 65797883Sgibbs uint16_t *tagenable; 65897883Sgibbs u_int update_type; 65997883Sgibbs 66097883Sgibbs scsi = &cts->proto_specific.scsi; 66197883Sgibbs spi = &cts->xport_specific.spi; 66297883Sgibbs ahd_compile_devinfo(&devinfo, SIM_SCSI_ID(ahd, sim), 66397883Sgibbs cts->ccb_h.target_id, 66497883Sgibbs cts->ccb_h.target_lun, 66597883Sgibbs SIM_CHANNEL(ahd, sim), 66697883Sgibbs ROLE_UNKNOWN); 66797883Sgibbs tinfo = ahd_fetch_transinfo(ahd, devinfo.channel, 66897883Sgibbs devinfo.our_scsiid, 66997883Sgibbs devinfo.target, &tstate); 67097883Sgibbs update_type = 0; 67197883Sgibbs if (cts->type == CTS_TYPE_CURRENT_SETTINGS) { 67297883Sgibbs update_type |= AHD_TRANS_GOAL; 67397883Sgibbs discenable = &tstate->discenable; 67497883Sgibbs tagenable = &tstate->tagenable; 67597883Sgibbs tinfo->curr.protocol_version = cts->protocol_version; 67697883Sgibbs tinfo->curr.transport_version = cts->transport_version; 67797883Sgibbs tinfo->goal.protocol_version = cts->protocol_version; 67897883Sgibbs tinfo->goal.transport_version = cts->transport_version; 67997883Sgibbs } else if (cts->type == CTS_TYPE_USER_SETTINGS) { 68097883Sgibbs update_type |= AHD_TRANS_USER; 68197883Sgibbs discenable = &ahd->user_discenable; 68297883Sgibbs tagenable = &ahd->user_tagenable; 68397883Sgibbs tinfo->user.protocol_version = cts->protocol_version; 68497883Sgibbs tinfo->user.transport_version = cts->transport_version; 68597883Sgibbs } else { 68697883Sgibbs cts->ccb_h.status = CAM_REQ_INVALID; 68797883Sgibbs return; 68897883Sgibbs } 68997883Sgibbs 69097883Sgibbs if ((spi->valid & CTS_SPI_VALID_DISC) != 0) { 69197883Sgibbs if ((spi->flags & CTS_SPI_FLAGS_DISC_ENB) != 0) 69297883Sgibbs *discenable |= devinfo.target_mask; 69397883Sgibbs else 69497883Sgibbs *discenable &= ~devinfo.target_mask; 69597883Sgibbs } 69697883Sgibbs 69797883Sgibbs if ((scsi->valid & CTS_SCSI_VALID_TQ) != 0) { 69897883Sgibbs if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0) 69997883Sgibbs *tagenable |= devinfo.target_mask; 70097883Sgibbs else 70197883Sgibbs *tagenable &= ~devinfo.target_mask; 70297883Sgibbs } 70397883Sgibbs 70497883Sgibbs if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) { 70597883Sgibbs ahd_validate_width(ahd, /*tinfo limit*/NULL, 70697883Sgibbs &spi->bus_width, ROLE_UNKNOWN); 70797883Sgibbs ahd_set_width(ahd, &devinfo, spi->bus_width, 70897883Sgibbs update_type, /*paused*/FALSE); 70997883Sgibbs } 71097883Sgibbs 71197883Sgibbs if ((spi->valid & CTS_SPI_VALID_PPR_OPTIONS) == 0) { 71297883Sgibbs if (update_type == AHD_TRANS_USER) 71397883Sgibbs spi->ppr_options = tinfo->user.ppr_options; 71497883Sgibbs else 71597883Sgibbs spi->ppr_options = tinfo->goal.ppr_options; 71697883Sgibbs } 71797883Sgibbs 71897883Sgibbs if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) == 0) { 71997883Sgibbs if (update_type == AHD_TRANS_USER) 72097883Sgibbs spi->sync_offset = tinfo->user.offset; 72197883Sgibbs else 72297883Sgibbs spi->sync_offset = tinfo->goal.offset; 72397883Sgibbs } 72497883Sgibbs 72597883Sgibbs if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) == 0) { 72697883Sgibbs if (update_type == AHD_TRANS_USER) 72797883Sgibbs spi->sync_period = tinfo->user.period; 72897883Sgibbs else 72997883Sgibbs spi->sync_period = tinfo->goal.period; 73097883Sgibbs } 73197883Sgibbs 73297883Sgibbs if (((spi->valid & CTS_SPI_VALID_SYNC_RATE) != 0) 73397883Sgibbs || ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0)) { 73497883Sgibbs u_int maxsync; 73597883Sgibbs 73697883Sgibbs maxsync = AHD_SYNCRATE_MAX; 73797883Sgibbs 73897883Sgibbs if (spi->bus_width != MSG_EXT_WDTR_BUS_16_BIT) 73997883Sgibbs spi->ppr_options &= ~MSG_EXT_PPR_DT_REQ; 74097883Sgibbs 74197883Sgibbs if ((*discenable & devinfo.target_mask) == 0) 74297883Sgibbs spi->ppr_options &= ~MSG_EXT_PPR_IU_REQ; 74397883Sgibbs 74497883Sgibbs ahd_find_syncrate(ahd, &spi->sync_period, 74597883Sgibbs &spi->ppr_options, maxsync); 74697883Sgibbs ahd_validate_offset(ahd, /*tinfo limit*/NULL, 74797883Sgibbs spi->sync_period, &spi->sync_offset, 74897883Sgibbs spi->bus_width, ROLE_UNKNOWN); 74997883Sgibbs 75097883Sgibbs /* We use a period of 0 to represent async */ 75197883Sgibbs if (spi->sync_offset == 0) { 75297883Sgibbs spi->sync_period = 0; 75397883Sgibbs spi->ppr_options = 0; 75497883Sgibbs } 75597883Sgibbs 75697883Sgibbs ahd_set_syncrate(ahd, &devinfo, spi->sync_period, 75797883Sgibbs spi->sync_offset, spi->ppr_options, 75897883Sgibbs update_type, /*paused*/FALSE); 75997883Sgibbs } 76097883Sgibbs cts->ccb_h.status = CAM_REQ_CMP; 76197883Sgibbs#else 76297883Sgibbs struct ahd_devinfo devinfo; 76397883Sgibbs struct ahd_initiator_tinfo *tinfo; 76497883Sgibbs struct ahd_tmode_tstate *tstate; 76597883Sgibbs uint16_t *discenable; 76697883Sgibbs uint16_t *tagenable; 76797883Sgibbs u_int update_type; 76897883Sgibbs 76997883Sgibbs ahd_compile_devinfo(&devinfo, SIM_SCSI_ID(ahd, sim), 77097883Sgibbs cts->ccb_h.target_id, 77197883Sgibbs cts->ccb_h.target_lun, 77297883Sgibbs SIM_CHANNEL(ahd, sim), 77397883Sgibbs ROLE_UNKNOWN); 77497883Sgibbs tinfo = ahd_fetch_transinfo(ahd, devinfo.channel, 77597883Sgibbs devinfo.our_scsiid, 77697883Sgibbs devinfo.target, &tstate); 77797883Sgibbs update_type = 0; 77897883Sgibbs if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0) { 77997883Sgibbs update_type |= AHD_TRANS_GOAL; 78097883Sgibbs discenable = &tstate->discenable; 78197883Sgibbs tagenable = &tstate->tagenable; 78297883Sgibbs } else if ((cts->flags & CCB_TRANS_USER_SETTINGS) != 0) { 78397883Sgibbs update_type |= AHD_TRANS_USER; 78497883Sgibbs discenable = &ahd->user_discenable; 78597883Sgibbs tagenable = &ahd->user_tagenable; 78697883Sgibbs } else { 78797883Sgibbs cts->ccb_h.status = CAM_REQ_INVALID; 78897883Sgibbs return; 78997883Sgibbs } 79097883Sgibbs 79197883Sgibbs if ((cts->valid & CCB_TRANS_DISC_VALID) != 0) { 79297883Sgibbs if ((cts->flags & CCB_TRANS_DISC_ENB) != 0) 79397883Sgibbs *discenable |= devinfo.target_mask; 79497883Sgibbs else 79597883Sgibbs *discenable &= ~devinfo.target_mask; 79697883Sgibbs } 79797883Sgibbs 79897883Sgibbs if ((cts->valid & CCB_TRANS_TQ_VALID) != 0) { 79997883Sgibbs if ((cts->flags & CCB_TRANS_TAG_ENB) != 0) 80097883Sgibbs *tagenable |= devinfo.target_mask; 80197883Sgibbs else 80297883Sgibbs *tagenable &= ~devinfo.target_mask; 80397883Sgibbs } 80497883Sgibbs 80597883Sgibbs if ((cts->valid & CCB_TRANS_BUS_WIDTH_VALID) != 0) { 80697883Sgibbs ahd_validate_width(ahd, /*tinfo limit*/NULL, 80797883Sgibbs &cts->bus_width, ROLE_UNKNOWN); 80897883Sgibbs ahd_set_width(ahd, &devinfo, cts->bus_width, 80997883Sgibbs update_type, /*paused*/FALSE); 81097883Sgibbs } 81197883Sgibbs 81297883Sgibbs if ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) == 0) { 81397883Sgibbs if (update_type == AHD_TRANS_USER) 81497883Sgibbs cts->sync_offset = tinfo->user.offset; 81597883Sgibbs else 81697883Sgibbs cts->sync_offset = tinfo->goal.offset; 81797883Sgibbs } 81897883Sgibbs 81997883Sgibbs if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) == 0) { 82097883Sgibbs if (update_type == AHD_TRANS_USER) 82197883Sgibbs cts->sync_period = tinfo->user.period; 82297883Sgibbs else 82397883Sgibbs cts->sync_period = tinfo->goal.period; 82497883Sgibbs } 82597883Sgibbs 82697883Sgibbs if (((cts->valid & CCB_TRANS_SYNC_RATE_VALID) != 0) 827102684Sgibbs || ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0) 828102684Sgibbs || ((cts->valid & CCB_TRANS_TQ_VALID) != 0) 829102684Sgibbs || ((cts->valid & CCB_TRANS_DISC_VALID) != 0)) { 83097883Sgibbs u_int ppr_options; 83197883Sgibbs u_int maxsync; 83297883Sgibbs 83397883Sgibbs maxsync = AHD_SYNCRATE_MAX; 83497883Sgibbs ppr_options = 0; 83597883Sgibbs if (cts->sync_period <= AHD_SYNCRATE_DT 83697883Sgibbs && cts->bus_width == MSG_EXT_WDTR_BUS_16_BIT) { 83797883Sgibbs ppr_options = tinfo->user.ppr_options 83897883Sgibbs | MSG_EXT_PPR_DT_REQ; 83997883Sgibbs } 84097883Sgibbs 841102684Sgibbs if ((*tagenable & devinfo.target_mask) == 0 842102684Sgibbs || (*discenable & devinfo.target_mask) == 0) 843102684Sgibbs ppr_options &= ~MSG_EXT_PPR_IU_REQ; 844102684Sgibbs 84597883Sgibbs ahd_find_syncrate(ahd, &cts->sync_period, 84697883Sgibbs &ppr_options, maxsync); 84797883Sgibbs ahd_validate_offset(ahd, /*tinfo limit*/NULL, 84897883Sgibbs cts->sync_period, &cts->sync_offset, 84997883Sgibbs MSG_EXT_WDTR_BUS_8_BIT, 85097883Sgibbs ROLE_UNKNOWN); 85197883Sgibbs 85297883Sgibbs /* We use a period of 0 to represent async */ 85397883Sgibbs if (cts->sync_offset == 0) { 85497883Sgibbs cts->sync_period = 0; 85597883Sgibbs ppr_options = 0; 85697883Sgibbs } 85797883Sgibbs 85897883Sgibbs if (ppr_options != 0 85997883Sgibbs && tinfo->user.transport_version >= 3) { 86097883Sgibbs tinfo->goal.transport_version = 86197883Sgibbs tinfo->user.transport_version; 86297883Sgibbs tinfo->curr.transport_version = 86397883Sgibbs tinfo->user.transport_version; 86497883Sgibbs } 86597883Sgibbs 86697883Sgibbs ahd_set_syncrate(ahd, &devinfo, cts->sync_period, 86797883Sgibbs cts->sync_offset, ppr_options, 86897883Sgibbs update_type, /*paused*/FALSE); 86997883Sgibbs } 87097883Sgibbs cts->ccb_h.status = CAM_REQ_CMP; 87197883Sgibbs#endif 87297883Sgibbs} 87397883Sgibbs 87497883Sgibbsstatic void 87597883Sgibbsahd_get_tran_settings(struct ahd_softc *ahd, int our_id, char channel, 87697883Sgibbs struct ccb_trans_settings *cts) 87797883Sgibbs{ 87897883Sgibbs#ifdef AHD_NEW_TRAN_SETTINGS 87997883Sgibbs struct ahd_devinfo devinfo; 88097883Sgibbs struct ccb_trans_settings_scsi *scsi; 88197883Sgibbs struct ccb_trans_settings_spi *spi; 88297883Sgibbs struct ahd_initiator_tinfo *targ_info; 88397883Sgibbs struct ahd_tmode_tstate *tstate; 88497883Sgibbs struct ahd_transinfo *tinfo; 88597883Sgibbs 88697883Sgibbs scsi = &cts->proto_specific.scsi; 88797883Sgibbs spi = &cts->xport_specific.spi; 88897883Sgibbs ahd_compile_devinfo(&devinfo, our_id, 88997883Sgibbs cts->ccb_h.target_id, 89097883Sgibbs cts->ccb_h.target_lun, 89197883Sgibbs channel, ROLE_UNKNOWN); 89297883Sgibbs targ_info = ahd_fetch_transinfo(ahd, devinfo.channel, 89397883Sgibbs devinfo.our_scsiid, 89497883Sgibbs devinfo.target, &tstate); 89597883Sgibbs 89697883Sgibbs if (cts->type == CTS_TYPE_CURRENT_SETTINGS) 89797883Sgibbs tinfo = &targ_info->curr; 89897883Sgibbs else 89997883Sgibbs tinfo = &targ_info->user; 90097883Sgibbs 90197883Sgibbs scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 90297883Sgibbs spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB; 90397883Sgibbs if (cts->type == CTS_TYPE_USER_SETTINGS) { 90497883Sgibbs if ((ahd->user_discenable & devinfo.target_mask) != 0) 90597883Sgibbs spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 90697883Sgibbs 90797883Sgibbs if ((ahd->user_tagenable & devinfo.target_mask) != 0) 90897883Sgibbs scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; 90997883Sgibbs } else { 91097883Sgibbs if ((tstate->discenable & devinfo.target_mask) != 0) 91197883Sgibbs spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 91297883Sgibbs 91397883Sgibbs if ((tstate->tagenable & devinfo.target_mask) != 0) 91497883Sgibbs scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; 91597883Sgibbs } 91697883Sgibbs cts->protocol_version = tinfo->protocol_version; 91797883Sgibbs cts->transport_version = tinfo->transport_version; 91897883Sgibbs 91997883Sgibbs spi->sync_period = tinfo->period; 92097883Sgibbs spi->sync_offset = tinfo->offset; 92197883Sgibbs spi->bus_width = tinfo->width; 92297883Sgibbs spi->ppr_options = tinfo->ppr_options; 92397883Sgibbs 92497883Sgibbs cts->protocol = PROTO_SCSI; 92597883Sgibbs cts->transport = XPORT_SPI; 92697883Sgibbs spi->valid = CTS_SPI_VALID_SYNC_RATE 92797883Sgibbs | CTS_SPI_VALID_SYNC_OFFSET 92897883Sgibbs | CTS_SPI_VALID_BUS_WIDTH 92997883Sgibbs | CTS_SPI_VALID_PPR_OPTIONS; 93097883Sgibbs 93197883Sgibbs if (cts->ccb_h.target_lun != CAM_LUN_WILDCARD) { 93297883Sgibbs scsi->valid = CTS_SCSI_VALID_TQ; 93397883Sgibbs spi->valid |= CTS_SPI_VALID_DISC; 93497883Sgibbs } else { 93597883Sgibbs scsi->valid = 0; 93697883Sgibbs } 93797883Sgibbs 93897883Sgibbs cts->ccb_h.status = CAM_REQ_CMP; 93997883Sgibbs#else 94097883Sgibbs struct ahd_devinfo devinfo; 94197883Sgibbs struct ahd_initiator_tinfo *targ_info; 94297883Sgibbs struct ahd_tmode_tstate *tstate; 94397883Sgibbs struct ahd_transinfo *tinfo; 94497883Sgibbs 94597883Sgibbs ahd_compile_devinfo(&devinfo, our_id, 94697883Sgibbs cts->ccb_h.target_id, 94797883Sgibbs cts->ccb_h.target_lun, 94897883Sgibbs channel, ROLE_UNKNOWN); 94997883Sgibbs targ_info = ahd_fetch_transinfo(ahd, devinfo.channel, 95097883Sgibbs devinfo.our_scsiid, 95197883Sgibbs devinfo.target, &tstate); 95297883Sgibbs 95397883Sgibbs if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0) 95497883Sgibbs tinfo = &targ_info->curr; 95597883Sgibbs else 95697883Sgibbs tinfo = &targ_info->user; 95797883Sgibbs 95897883Sgibbs cts->flags &= ~(CCB_TRANS_DISC_ENB|CCB_TRANS_TAG_ENB); 95997883Sgibbs if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) == 0) { 96097883Sgibbs if ((ahd->user_discenable & devinfo.target_mask) != 0) 96197883Sgibbs cts->flags |= CCB_TRANS_DISC_ENB; 96297883Sgibbs 96397883Sgibbs if ((ahd->user_tagenable & devinfo.target_mask) != 0) 96497883Sgibbs cts->flags |= CCB_TRANS_TAG_ENB; 96597883Sgibbs } else { 96697883Sgibbs if ((tstate->discenable & devinfo.target_mask) != 0) 96797883Sgibbs cts->flags |= CCB_TRANS_DISC_ENB; 96897883Sgibbs 96997883Sgibbs if ((tstate->tagenable & devinfo.target_mask) != 0) 97097883Sgibbs cts->flags |= CCB_TRANS_TAG_ENB; 97197883Sgibbs } 97297883Sgibbs cts->sync_period = tinfo->period; 97397883Sgibbs cts->sync_offset = tinfo->offset; 97497883Sgibbs cts->bus_width = tinfo->width; 97597883Sgibbs 97697883Sgibbs cts->valid = CCB_TRANS_SYNC_RATE_VALID 97797883Sgibbs | CCB_TRANS_SYNC_OFFSET_VALID 97897883Sgibbs | CCB_TRANS_BUS_WIDTH_VALID; 97997883Sgibbs 98097883Sgibbs if (cts->ccb_h.target_lun != CAM_LUN_WILDCARD) 98197883Sgibbs cts->valid |= CCB_TRANS_DISC_VALID|CCB_TRANS_TQ_VALID; 98297883Sgibbs 98397883Sgibbs cts->ccb_h.status = CAM_REQ_CMP; 98497883Sgibbs#endif 98597883Sgibbs} 98697883Sgibbs 98797883Sgibbsstatic void 98897883Sgibbsahd_async(void *callback_arg, uint32_t code, struct cam_path *path, void *arg) 98997883Sgibbs{ 99097883Sgibbs struct ahd_softc *ahd; 99197883Sgibbs struct cam_sim *sim; 99297883Sgibbs 99397883Sgibbs sim = (struct cam_sim *)callback_arg; 99497883Sgibbs ahd = (struct ahd_softc *)cam_sim_softc(sim); 99597883Sgibbs switch (code) { 99697883Sgibbs case AC_LOST_DEVICE: 99797883Sgibbs { 99897883Sgibbs struct ahd_devinfo devinfo; 99997883Sgibbs long s; 100097883Sgibbs 100197883Sgibbs ahd_compile_devinfo(&devinfo, SIM_SCSI_ID(ahd, sim), 100297883Sgibbs xpt_path_target_id(path), 100397883Sgibbs xpt_path_lun_id(path), 100497883Sgibbs SIM_CHANNEL(ahd, sim), 100597883Sgibbs ROLE_UNKNOWN); 100697883Sgibbs 100797883Sgibbs /* 100897883Sgibbs * Revert to async/narrow transfers 100997883Sgibbs * for the next device. 101097883Sgibbs */ 101197883Sgibbs ahd_lock(ahd, &s); 101297883Sgibbs ahd_set_width(ahd, &devinfo, MSG_EXT_WDTR_BUS_8_BIT, 101397883Sgibbs AHD_TRANS_GOAL|AHD_TRANS_CUR, /*paused*/FALSE); 101497883Sgibbs ahd_set_syncrate(ahd, &devinfo, /*period*/0, /*offset*/0, 101597883Sgibbs /*ppr_options*/0, AHD_TRANS_GOAL|AHD_TRANS_CUR, 101697883Sgibbs /*paused*/FALSE); 101797883Sgibbs ahd_unlock(ahd, &s); 101897883Sgibbs break; 101997883Sgibbs } 102097883Sgibbs default: 102197883Sgibbs break; 102297883Sgibbs } 102397883Sgibbs} 102497883Sgibbs 102597883Sgibbsstatic void 102697883Sgibbsahd_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments, 102797883Sgibbs int error) 102897883Sgibbs{ 102997883Sgibbs struct scb *scb; 103097883Sgibbs union ccb *ccb; 103197883Sgibbs struct ahd_softc *ahd; 103297883Sgibbs struct ahd_initiator_tinfo *tinfo; 103397883Sgibbs struct ahd_tmode_tstate *tstate; 103497883Sgibbs u_int mask; 103597883Sgibbs u_long s; 103697883Sgibbs 103797883Sgibbs scb = (struct scb *)arg; 103897883Sgibbs ccb = scb->io_ctx; 103997883Sgibbs ahd = scb->ahd_softc; 104097883Sgibbs 104197883Sgibbs if (error != 0) { 104297883Sgibbs if (error == EFBIG) 104397883Sgibbs ahd_set_transaction_status(scb, CAM_REQ_TOO_BIG); 104497883Sgibbs else 104597883Sgibbs ahd_set_transaction_status(scb, CAM_REQ_CMP_ERR); 104697883Sgibbs if (nsegments != 0) 104797883Sgibbs bus_dmamap_unload(ahd->buffer_dmat, scb->dmamap); 104897883Sgibbs ahd_lock(ahd, &s); 104997883Sgibbs ahd_free_scb(ahd, scb); 105097883Sgibbs ahd_unlock(ahd, &s); 105197883Sgibbs xpt_done(ccb); 105297883Sgibbs return; 105397883Sgibbs } 105497883Sgibbs scb->sg_count = 0; 105597883Sgibbs if (nsegments != 0) { 105697883Sgibbs void *sg; 105797883Sgibbs bus_dmasync_op_t op; 105897883Sgibbs u_int i; 105997883Sgibbs 106097883Sgibbs /* Copy the segments into our SG list */ 106197883Sgibbs for (i = nsegments, sg = scb->sg_list; i > 0; i--) { 106297883Sgibbs 106397883Sgibbs sg = ahd_sg_setup(ahd, scb, sg, dm_segs->ds_addr, 106497883Sgibbs dm_segs->ds_len, 106597883Sgibbs /*last*/i == 1); 106697883Sgibbs dm_segs++; 106797883Sgibbs } 106897883Sgibbs 106997883Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) 107097883Sgibbs op = BUS_DMASYNC_PREREAD; 107197883Sgibbs else 107297883Sgibbs op = BUS_DMASYNC_PREWRITE; 107397883Sgibbs 107497883Sgibbs bus_dmamap_sync(ahd->buffer_dmat, scb->dmamap, op); 107597883Sgibbs 107697883Sgibbs if (ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) { 107797883Sgibbs struct target_data *tdata; 107897883Sgibbs 107997883Sgibbs tdata = &scb->hscb->shared_data.tdata; 108097883Sgibbs tdata->target_phases |= DPHASE_PENDING; 108197883Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) 108297883Sgibbs tdata->data_phase = P_DATAOUT; 108397883Sgibbs else 108497883Sgibbs tdata->data_phase = P_DATAIN; 108597883Sgibbs } 108697883Sgibbs } 108797883Sgibbs 108897883Sgibbs ahd_lock(ahd, &s); 108997883Sgibbs 109097883Sgibbs /* 109197883Sgibbs * Last time we need to check if this SCB needs to 109297883Sgibbs * be aborted. 109397883Sgibbs */ 109497883Sgibbs if (ahd_get_transaction_status(scb) != CAM_REQ_INPROG) { 109597883Sgibbs if (nsegments != 0) 109697883Sgibbs bus_dmamap_unload(ahd->buffer_dmat, 109797883Sgibbs scb->dmamap); 109897883Sgibbs ahd_free_scb(ahd, scb); 109997883Sgibbs ahd_unlock(ahd, &s); 110097883Sgibbs xpt_done(ccb); 110197883Sgibbs return; 110297883Sgibbs } 110397883Sgibbs 110497883Sgibbs tinfo = ahd_fetch_transinfo(ahd, SCSIID_CHANNEL(ahd, scb->hscb->scsiid), 110597883Sgibbs SCSIID_OUR_ID(scb->hscb->scsiid), 110697883Sgibbs SCSIID_TARGET(ahd, scb->hscb->scsiid), 110797883Sgibbs &tstate); 110897883Sgibbs 110997883Sgibbs mask = SCB_GET_TARGET_MASK(ahd, scb); 111097883Sgibbs 111197883Sgibbs if ((tstate->discenable & mask) != 0 111297883Sgibbs && (ccb->ccb_h.flags & CAM_DIS_DISCONNECT) == 0) 111397883Sgibbs scb->hscb->control |= DISCENB; 111497883Sgibbs 111597883Sgibbs if ((tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ) != 0) 111697883Sgibbs scb->flags |= SCB_PACKETIZED; 111797883Sgibbs 111897883Sgibbs if ((ccb->ccb_h.flags & CAM_NEGOTIATE) != 0 111997883Sgibbs && (tinfo->goal.width != 0 112097883Sgibbs || tinfo->goal.period != 0 112197883Sgibbs || tinfo->goal.ppr_options != 0)) { 112297883Sgibbs scb->flags |= SCB_NEGOTIATE; 112397883Sgibbs scb->hscb->control |= MK_MESSAGE; 112497883Sgibbs } else if ((tstate->auto_negotiate & mask) != 0) { 112597883Sgibbs scb->flags |= SCB_AUTO_NEGOTIATE; 112697883Sgibbs scb->hscb->control |= MK_MESSAGE; 112797883Sgibbs } 112897883Sgibbs 112997883Sgibbs LIST_INSERT_HEAD(&ahd->pending_scbs, scb, pending_links); 113097883Sgibbs 113197883Sgibbs ccb->ccb_h.status |= CAM_SIM_QUEUED; 113297883Sgibbs 113397883Sgibbs if (ccb->ccb_h.timeout != CAM_TIME_INFINITY) { 113497883Sgibbs uint64_t time; 113597883Sgibbs 113697883Sgibbs if (ccb->ccb_h.timeout == CAM_TIME_DEFAULT) 113797883Sgibbs ccb->ccb_h.timeout = 5 * 1000; 113897883Sgibbs 113997883Sgibbs time = ccb->ccb_h.timeout; 114097883Sgibbs time *= hz; 114197883Sgibbs time /= 1000; 114297883Sgibbs ccb->ccb_h.timeout_ch = 114397883Sgibbs timeout(ahd_timeout, (caddr_t)scb, time); 114497883Sgibbs } 114597883Sgibbs 114697883Sgibbs if ((scb->flags & SCB_TARGET_IMMEDIATE) != 0) { 114797883Sgibbs /* Define a mapping from our tag to the SCB. */ 114897883Sgibbs ahd->scb_data.scbindex[SCB_GET_TAG(scb)] = scb; 114997883Sgibbs ahd_pause(ahd); 115097883Sgibbs ahd_set_scbptr(ahd, SCB_GET_TAG(scb)); 115197883Sgibbs ahd_outb(ahd, RETURN_1, CONT_MSG_LOOP_TARG); 115297883Sgibbs ahd_unpause(ahd); 115397883Sgibbs } else { 115497883Sgibbs ahd_queue_scb(ahd, scb); 115597883Sgibbs } 115697883Sgibbs 115797883Sgibbs ahd_unlock(ahd, &s); 115897883Sgibbs} 115997883Sgibbs 116097883Sgibbsstatic void 116197883Sgibbsahd_poll(struct cam_sim *sim) 116297883Sgibbs{ 116397883Sgibbs ahd_intr(cam_sim_softc(sim)); 116497883Sgibbs} 116597883Sgibbs 116697883Sgibbsstatic void 116797883Sgibbsahd_setup_data(struct ahd_softc *ahd, struct cam_sim *sim, 116897883Sgibbs struct ccb_scsiio *csio, struct scb *scb) 116997883Sgibbs{ 117097883Sgibbs struct hardware_scb *hscb; 117197883Sgibbs struct ccb_hdr *ccb_h; 117297883Sgibbs 117397883Sgibbs hscb = scb->hscb; 117497883Sgibbs ccb_h = &csio->ccb_h; 117597883Sgibbs 117697883Sgibbs csio->resid = 0; 117797883Sgibbs csio->sense_resid = 0; 117897883Sgibbs if (ccb_h->func_code == XPT_SCSI_IO) { 117997883Sgibbs hscb->cdb_len = csio->cdb_len; 118097883Sgibbs if ((ccb_h->flags & CAM_CDB_POINTER) != 0) { 118197883Sgibbs 118297883Sgibbs if (hscb->cdb_len > MAX_CDB_LEN 118397883Sgibbs && (ccb_h->flags & CAM_CDB_PHYS) == 0) { 118497883Sgibbs u_long s; 118597883Sgibbs 118697883Sgibbs ahd_set_transaction_status(scb, 118797883Sgibbs CAM_REQ_INVALID); 118897883Sgibbs ahd_lock(ahd, &s); 118997883Sgibbs ahd_free_scb(ahd, scb); 119097883Sgibbs ahd_unlock(ahd, &s); 119197883Sgibbs xpt_done((union ccb *)csio); 119297883Sgibbs return; 119397883Sgibbs } 119497883Sgibbs if ((ccb_h->flags & CAM_CDB_PHYS) != 0) { 119597883Sgibbs hscb->shared_data.idata.cdbptr = 119697883Sgibbs ahd_htole64((uintptr_t)csio->cdb_io.cdb_ptr); 119797883Sgibbs } else { 119897883Sgibbs memcpy(hscb->shared_data.idata.cdb, 119997883Sgibbs csio->cdb_io.cdb_ptr, 120097883Sgibbs hscb->cdb_len); 120197883Sgibbs } 120297883Sgibbs } else { 120397883Sgibbs if (hscb->cdb_len > MAX_CDB_LEN) { 120497883Sgibbs u_long s; 120597883Sgibbs 120697883Sgibbs ahd_set_transaction_status(scb, 120797883Sgibbs CAM_REQ_INVALID); 120897883Sgibbs ahd_lock(ahd, &s); 120997883Sgibbs ahd_free_scb(ahd, scb); 121097883Sgibbs ahd_unlock(ahd, &s); 121197883Sgibbs xpt_done((union ccb *)csio); 121297883Sgibbs return; 121397883Sgibbs } 121497883Sgibbs memcpy(hscb->shared_data.idata.cdb, 121597883Sgibbs csio->cdb_io.cdb_bytes, hscb->cdb_len); 121697883Sgibbs } 121797883Sgibbs } 121897883Sgibbs 121997883Sgibbs /* Only use S/G if there is a transfer */ 122097883Sgibbs if ((ccb_h->flags & CAM_DIR_MASK) != CAM_DIR_NONE) { 122197883Sgibbs if ((ccb_h->flags & CAM_SCATTER_VALID) == 0) { 122297883Sgibbs /* We've been given a pointer to a single buffer */ 122397883Sgibbs if ((ccb_h->flags & CAM_DATA_PHYS) == 0) { 122497883Sgibbs int s; 122597883Sgibbs int error; 122697883Sgibbs 122797883Sgibbs s = splsoftvm(); 122897883Sgibbs error = bus_dmamap_load(ahd->buffer_dmat, 122997883Sgibbs scb->dmamap, 123097883Sgibbs csio->data_ptr, 123197883Sgibbs csio->dxfer_len, 123297883Sgibbs ahd_execute_scb, 123397883Sgibbs scb, /*flags*/0); 123497883Sgibbs if (error == EINPROGRESS) { 123597883Sgibbs /* 123697883Sgibbs * So as to maintain ordering, 123797883Sgibbs * freeze the controller queue 123897883Sgibbs * until our mapping is 123997883Sgibbs * returned. 124097883Sgibbs */ 124197883Sgibbs xpt_freeze_simq(sim, 124297883Sgibbs /*count*/1); 124397883Sgibbs scb->io_ctx->ccb_h.status |= 124497883Sgibbs CAM_RELEASE_SIMQ; 124597883Sgibbs } 124697883Sgibbs splx(s); 124797883Sgibbs } else { 124897883Sgibbs struct bus_dma_segment seg; 124997883Sgibbs 125097883Sgibbs /* Pointer to physical buffer */ 125197883Sgibbs if (csio->dxfer_len > AHD_MAXTRANSFER_SIZE) 125297883Sgibbs panic("ahd_setup_data - Transfer size " 125397883Sgibbs "larger than can device max"); 125497883Sgibbs 125597883Sgibbs seg.ds_addr = (bus_addr_t)csio->data_ptr; 125697883Sgibbs seg.ds_len = csio->dxfer_len; 125797883Sgibbs ahd_execute_scb(scb, &seg, 1, 0); 125897883Sgibbs } 125997883Sgibbs } else { 126097883Sgibbs struct bus_dma_segment *segs; 126197883Sgibbs 126297883Sgibbs if ((ccb_h->flags & CAM_DATA_PHYS) != 0) 126397883Sgibbs panic("ahd_setup_data - Physical segment " 126497883Sgibbs "pointers unsupported"); 126597883Sgibbs 126697883Sgibbs if ((ccb_h->flags & CAM_SG_LIST_PHYS) == 0) 126797883Sgibbs panic("ahd_setup_data - Virtual segment " 126897883Sgibbs "addresses unsupported"); 126997883Sgibbs 127097883Sgibbs /* Just use the segments provided */ 127197883Sgibbs segs = (struct bus_dma_segment *)csio->data_ptr; 127297883Sgibbs ahd_execute_scb(scb, segs, csio->sglist_cnt, 0); 127397883Sgibbs } 127497883Sgibbs } else { 127597883Sgibbs ahd_execute_scb(scb, NULL, 0, 0); 127697883Sgibbs } 127797883Sgibbs} 127897883Sgibbs 127997883Sgibbs#if NOT_YET 128097883Sgibbsstatic void 128197883Sgibbsahd_set_recoveryscb(struct ahd_softc *ahd, struct scb *scb) { 128297883Sgibbs 128397883Sgibbs if ((scb->flags & SCB_RECOVERY_SCB) == 0) { 128497883Sgibbs struct scb *list_scb; 128597883Sgibbs 128697883Sgibbs scb->flags |= SCB_RECOVERY_SCB; 128797883Sgibbs 128897883Sgibbs /* 128997883Sgibbs * Take all queued, but not sent SCBs out of the equation. 129097883Sgibbs * Also ensure that no new CCBs are queued to us while we 129197883Sgibbs * try to fix this problem. 129297883Sgibbs */ 129397883Sgibbs if ((scb->io_ctx->ccb_h.status & CAM_RELEASE_SIMQ) == 0) { 129497883Sgibbs xpt_freeze_simq(SCB_GET_SIM(ahd, scb), /*count*/1); 129597883Sgibbs scb->io_ctx->ccb_h.status |= CAM_RELEASE_SIMQ; 129697883Sgibbs } 129797883Sgibbs 129897883Sgibbs /* 129997883Sgibbs * Go through all of our pending SCBs and remove 130097883Sgibbs * any scheduled timeouts for them. We will reschedule 130197883Sgibbs * them after we've successfully fixed this problem. 130297883Sgibbs */ 130397883Sgibbs LIST_FOREACH(list_scb, &ahd->pending_scbs, pending_links) { 130497883Sgibbs union ccb *ccb; 130597883Sgibbs 130697883Sgibbs ccb = list_scb->io_ctx; 130797883Sgibbs untimeout(ahd_timeout, list_scb, ccb->ccb_h.timeout_ch); 130897883Sgibbs } 130997883Sgibbs } 131097883Sgibbs} 131197883Sgibbs#endif 131297883Sgibbs 131397883Sgibbsvoid 131497883Sgibbsahd_timeout(void *arg) 131597883Sgibbs{ 131697883Sgibbs struct scb *scb; 131797883Sgibbs struct ahd_softc *ahd; 131897883Sgibbs ahd_mode_state saved_modes; 131997883Sgibbs long s; 132097883Sgibbs int target; 132197883Sgibbs int lun; 132297883Sgibbs char channel; 132397883Sgibbs 132497883Sgibbs#if NOT_YET 132597883Sgibbs int i; 132697883Sgibbs int found; 132797883Sgibbs u_int last_phase; 132897883Sgibbs#endif 132997883Sgibbs 133097883Sgibbs scb = (struct scb *)arg; 133197883Sgibbs ahd = (struct ahd_softc *)scb->ahd_softc; 133297883Sgibbs 133397883Sgibbs ahd_lock(ahd, &s); 133497883Sgibbs 133597883Sgibbs ahd_pause_and_flushwork(ahd); 133697883Sgibbs 133797883Sgibbs saved_modes = ahd_save_modes(ahd); 133897883Sgibbs#if 0 133997883Sgibbs ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 134097883Sgibbs ahd_outb(ahd, SCSISIGO, ACKO); 134197883Sgibbs printf("set ACK\n"); 134297883Sgibbs ahd_outb(ahd, SCSISIGO, 0); 134397883Sgibbs printf("clearing Ack\n"); 134497883Sgibbs ahd_restore_modes(ahd, saved_modes); 134597883Sgibbs#endif 134697883Sgibbs if ((scb->flags & SCB_ACTIVE) == 0) { 134797883Sgibbs /* Previous timeout took care of me already */ 134897883Sgibbs printf("%s: Timedout SCB already complete. " 134997883Sgibbs "Interrupts may not be functioning.\n", ahd_name(ahd)); 135097883Sgibbs ahd_unpause(ahd); 135197883Sgibbs ahd_unlock(ahd, &s); 135297883Sgibbs return; 135397883Sgibbs } 135497883Sgibbs 135597883Sgibbs target = SCB_GET_TARGET(ahd, scb); 135697883Sgibbs channel = SCB_GET_CHANNEL(ahd, scb); 135797883Sgibbs lun = SCB_GET_LUN(scb); 135897883Sgibbs 135997883Sgibbs ahd_print_path(ahd, scb); 136097883Sgibbs printf("SCB 0x%x - timed out\n", SCB_GET_TAG(scb)); 136197883Sgibbs ahd_dump_card_state(ahd); 136297883Sgibbs ahd_reset_channel(ahd, SIM_CHANNEL(ahd, sim), 136397883Sgibbs /*initiate reset*/TRUE); 136497883Sgibbs ahd_unlock(ahd, &s); 136597883Sgibbs return; 136697883Sgibbs#if NOT_YET 136797883Sgibbs last_phase = ahd_inb(ahd, LASTPHASE); 136897883Sgibbs if (scb->sg_count > 0) { 136997883Sgibbs for (i = 0; i < scb->sg_count; i++) { 137097883Sgibbs printf("sg[%d] - Addr 0x%x : Length %d\n", 137197883Sgibbs i, 137297883Sgibbs ((struct ahd_dma_seg *)scb->sg_list)[i].addr, 137397883Sgibbs ((struct ahd_dma_seg *)scb->sg_list)[i].len 137497883Sgibbs & AHD_SG_LEN_MASK); 137597883Sgibbs } 137697883Sgibbs } 137797883Sgibbs if (scb->flags & (SCB_DEVICE_RESET|SCB_ABORT)) { 137897883Sgibbs /* 137997883Sgibbs * Been down this road before. 138097883Sgibbs * Do a full bus reset. 138197883Sgibbs */ 138297883Sgibbsbus_reset: 138397883Sgibbs ahd_set_transaction_status(scb, CAM_CMD_TIMEOUT); 138497883Sgibbs found = ahd_reset_channel(ahd, channel, /*Initiate Reset*/TRUE); 138597883Sgibbs printf("%s: Issued Channel %c Bus Reset. " 138697883Sgibbs "%d SCBs aborted\n", ahd_name(ahd), channel, found); 138797883Sgibbs } else { 138897883Sgibbs /* 138997883Sgibbs * If we are a target, transition to bus free and report 139097883Sgibbs * the timeout. 139197883Sgibbs * 139297883Sgibbs * The target/initiator that is holding up the bus may not 139397883Sgibbs * be the same as the one that triggered this timeout 139497883Sgibbs * (different commands have different timeout lengths). 139597883Sgibbs * If the bus is idle and we are actiing as the initiator 139697883Sgibbs * for this request, queue a BDR message to the timed out 139797883Sgibbs * target. Otherwise, if the timed out transaction is 139897883Sgibbs * active: 139997883Sgibbs * Initiator transaction: 140097883Sgibbs * Stuff the message buffer with a BDR message and assert 140197883Sgibbs * ATN in the hopes that the target will let go of the bus 140297883Sgibbs * and go to the mesgout phase. If this fails, we'll 140397883Sgibbs * get another timeout 2 seconds later which will attempt 140497883Sgibbs * a bus reset. 140597883Sgibbs * 140697883Sgibbs * Target transaction: 140797883Sgibbs * Transition to BUS FREE and report the error. 140897883Sgibbs * It's good to be the target! 140997883Sgibbs */ 141097883Sgibbs u_int active_scb_index; 141197883Sgibbs u_int saved_scbptr; 141297883Sgibbs 141397883Sgibbs saved_scbptr = ahd_get_scbptr(ahd); 141497883Sgibbs active_scb_index = saved_scbptr; 141597883Sgibbs 141697883Sgibbs if (last_phase != P_BUSFREE 141797883Sgibbs && (ahd_inb(ahd, SEQ_FLAGS) & NOT_IDENTIFIED) == 0 141897883Sgibbs && (active_scb_index < ahd->scb_data.numscbs)) { 141997883Sgibbs struct scb *active_scb; 142097883Sgibbs 142197883Sgibbs /* 142297883Sgibbs * If the active SCB is not us, assume that 142397883Sgibbs * the active SCB has a longer timeout than 142497883Sgibbs * the timedout SCB, and wait for the active 142597883Sgibbs * SCB to timeout. 142697883Sgibbs */ 142797883Sgibbs active_scb = ahd_lookup_scb(ahd, active_scb_index); 142897883Sgibbs if (active_scb != scb) { 142997883Sgibbs struct ccb_hdr *ccbh; 143097883Sgibbs uint64_t newtimeout; 143197883Sgibbs 143297883Sgibbs ahd_print_path(ahd, scb); 143397883Sgibbs printf("Other SCB Timeout%s", 143497883Sgibbs (scb->flags & SCB_OTHERTCL_TIMEOUT) != 0 143597883Sgibbs ? " again\n" : "\n"); 143697883Sgibbs scb->flags |= SCB_OTHERTCL_TIMEOUT; 143797883Sgibbs newtimeout = 143897883Sgibbs MAX(active_scb->io_ctx->ccb_h.timeout, 143997883Sgibbs scb->io_ctx->ccb_h.timeout); 144097883Sgibbs newtimeout *= hz; 144197883Sgibbs newtimeout /= 1000; 144297883Sgibbs ccbh = &scb->io_ctx->ccb_h; 144397883Sgibbs scb->io_ctx->ccb_h.timeout_ch = 144497883Sgibbs timeout(ahd_timeout, scb, newtimeout); 144597883Sgibbs ahd_unpause(ahd); 144697883Sgibbs ahd_unlock(ahd, &s); 144797883Sgibbs return; 144897883Sgibbs } 144997883Sgibbs 145097883Sgibbs /* It's us */ 145197883Sgibbs if ((scb->hscb->control & TARGET_SCB) != 0) { 145297883Sgibbs 145397883Sgibbs /* 145497883Sgibbs * Send back any queued up transactions 145597883Sgibbs * and properly record the error condition. 145697883Sgibbs */ 145797883Sgibbs ahd_abort_scbs(ahd, SCB_GET_TARGET(ahd, scb), 145897883Sgibbs SCB_GET_CHANNEL(ahd, scb), 145997883Sgibbs SCB_GET_LUN(scb), 146097883Sgibbs SCB_GET_TAG(scb), 146197883Sgibbs ROLE_TARGET, 146297883Sgibbs CAM_CMD_TIMEOUT); 146397883Sgibbs 146497883Sgibbs /* Will clear us from the bus */ 146597883Sgibbs ahd_restart(ahd); 146697883Sgibbs ahd_unlock(ahd, &s); 146797883Sgibbs return; 146897883Sgibbs } 146997883Sgibbs 147097883Sgibbs ahd_set_recoveryscb(ahd, active_scb); 147197883Sgibbs ahd_outb(ahd, MSG_OUT, HOST_MSG); 147297883Sgibbs ahd_outb(ahd, SCSISIGO, last_phase|ATNO); 147397883Sgibbs ahd_print_path(ahd, active_scb); 147497883Sgibbs printf("BDR message in message buffer\n"); 147597883Sgibbs active_scb->flags |= SCB_DEVICE_RESET; 147697883Sgibbs active_scb->io_ctx->ccb_h.timeout_ch = 147797883Sgibbs timeout(ahd_timeout, (caddr_t)active_scb, 2 * hz); 147897883Sgibbs ahd_unpause(ahd); 147997883Sgibbs } else { 148097883Sgibbs int disconnected; 148197883Sgibbs 148297883Sgibbs /* XXX Shouldn't panic. Just punt instead? */ 148397883Sgibbs if ((scb->hscb->control & TARGET_SCB) != 0) 148497883Sgibbs panic("Timed-out target SCB but bus idle"); 148597883Sgibbs 148697883Sgibbs if (last_phase != P_BUSFREE 148797883Sgibbs && (ahd_inb(ahd, SSTAT0) & TARGET) != 0) { 148897883Sgibbs /* XXX What happened to the SCB? */ 148997883Sgibbs /* Hung target selection. Goto busfree */ 149097883Sgibbs printf("%s: Hung target selection\n", 149197883Sgibbs ahd_name(ahd)); 149297883Sgibbs ahd_restart(ahd); 149397883Sgibbs ahd_unlock(ahd, &s); 149497883Sgibbs return; 149597883Sgibbs } 149697883Sgibbs 149797883Sgibbs if (ahd_search_qinfifo(ahd, target, channel, lun, 149897883Sgibbs SCB_GET_TAG(scb), ROLE_INITIATOR, 149997883Sgibbs /*status*/0, SEARCH_COUNT) > 0) { 150097883Sgibbs disconnected = FALSE; 150197883Sgibbs } else { 150297883Sgibbs disconnected = TRUE; 150397883Sgibbs } 150497883Sgibbs 150597883Sgibbs if (disconnected) { 150697883Sgibbs 150797883Sgibbs ahd_set_recoveryscb(ahd, scb); 150897883Sgibbs /* 150997883Sgibbs * Actually re-queue this SCB in an attempt 151097883Sgibbs * to select the device before it reconnects. 151197883Sgibbs * In either case (selection or reselection), 151297883Sgibbs * we will now issue a target reset to the 151397883Sgibbs * timed-out device. 151497883Sgibbs * 151597883Sgibbs * Set the MK_MESSAGE control bit indicating 151697883Sgibbs * that we desire to send a message. We 151797883Sgibbs * also set the disconnected flag since 151897883Sgibbs * in the paging case there is no guarantee 151997883Sgibbs * that our SCB control byte matches the 152097883Sgibbs * version on the card. We don't want the 152197883Sgibbs * sequencer to abort the command thinking 152297883Sgibbs * an unsolicited reselection occurred. 152397883Sgibbs */ 152497883Sgibbs scb->hscb->control |= MK_MESSAGE|DISCONNECTED; 152597883Sgibbs scb->flags |= SCB_DEVICE_RESET; 152697883Sgibbs 152797883Sgibbs /* 152897883Sgibbs * The sequencer will never re-reference the 152997883Sgibbs * in-core SCB. To make sure we are notified 153097883Sgibbs * during reslection, set the MK_MESSAGE flag 153197883Sgibbs * in the card's copy of the SCB. 153297883Sgibbs */ 153397883Sgibbs ahd_set_scbptr(ahd, SCB_GET_TAG(scb)); 153497883Sgibbs ahd_outb(ahd, SCB_CONTROL, 153597883Sgibbs ahd_inb(ahd, SCB_CONTROL)|MK_MESSAGE); 153697883Sgibbs 153797883Sgibbs /* 153897883Sgibbs * Clear out any entries in the QINFIFO first 153997883Sgibbs * so we are the next SCB for this target 154097883Sgibbs * to run. 154197883Sgibbs */ 154297883Sgibbs ahd_search_qinfifo(ahd, 154397883Sgibbs SCB_GET_TARGET(ahd, scb), 154497883Sgibbs channel, SCB_GET_LUN(scb), 154597883Sgibbs SCB_LIST_NULL, 154697883Sgibbs ROLE_INITIATOR, 154797883Sgibbs CAM_REQUEUE_REQ, 154897883Sgibbs SEARCH_COMPLETE); 154997883Sgibbs ahd_print_path(ahd, scb); 155097883Sgibbs printf("Queuing a BDR SCB\n"); 155197883Sgibbs ahd_qinfifo_requeue_tail(ahd, scb); 155297883Sgibbs ahd_set_scbptr(ahd, saved_scbptr); 155397883Sgibbs scb->io_ctx->ccb_h.timeout_ch = 155497883Sgibbs timeout(ahd_timeout, (caddr_t)scb, 2 * hz); 155597883Sgibbs ahd_unpause(ahd); 155697883Sgibbs } else { 155797883Sgibbs /* Go "immediatly" to the bus reset */ 155897883Sgibbs /* This shouldn't happen */ 155997883Sgibbs ahd_set_recoveryscb(ahd, scb); 156097883Sgibbs ahd_print_path(ahd, scb); 156197883Sgibbs printf("SCB %d: Immediate reset. " 156297883Sgibbs "Flags = 0x%x\n", SCB_GET_TAG(scb), 156397883Sgibbs scb->flags); 156497883Sgibbs goto bus_reset; 156597883Sgibbs } 156697883Sgibbs } 156797883Sgibbs } 156897883Sgibbs ahd_unlock(ahd, &s); 156997883Sgibbs#endif 157097883Sgibbs} 157197883Sgibbs 157297883Sgibbsstatic void 157397883Sgibbsahd_abort_ccb(struct ahd_softc *ahd, struct cam_sim *sim, union ccb *ccb) 157497883Sgibbs{ 157597883Sgibbs union ccb *abort_ccb; 157697883Sgibbs 157797883Sgibbs abort_ccb = ccb->cab.abort_ccb; 157897883Sgibbs switch (abort_ccb->ccb_h.func_code) { 157997883Sgibbs#ifdef AHD_TARGET_MODE 158097883Sgibbs case XPT_ACCEPT_TARGET_IO: 158197883Sgibbs case XPT_IMMED_NOTIFY: 158297883Sgibbs case XPT_CONT_TARGET_IO: 158397883Sgibbs { 158497883Sgibbs struct ahd_tmode_tstate *tstate; 158597883Sgibbs struct ahd_tmode_lstate *lstate; 158697883Sgibbs struct ccb_hdr_slist *list; 158797883Sgibbs cam_status status; 158897883Sgibbs 158997883Sgibbs status = ahd_find_tmode_devs(ahd, sim, abort_ccb, &tstate, 159097883Sgibbs &lstate, TRUE); 159197883Sgibbs 159297883Sgibbs if (status != CAM_REQ_CMP) { 159397883Sgibbs ccb->ccb_h.status = status; 159497883Sgibbs break; 159597883Sgibbs } 159697883Sgibbs 159797883Sgibbs if (abort_ccb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) 159897883Sgibbs list = &lstate->accept_tios; 159997883Sgibbs else if (abort_ccb->ccb_h.func_code == XPT_IMMED_NOTIFY) 160097883Sgibbs list = &lstate->immed_notifies; 160197883Sgibbs else 160297883Sgibbs list = NULL; 160397883Sgibbs 160497883Sgibbs if (list != NULL) { 160597883Sgibbs struct ccb_hdr *curelm; 160697883Sgibbs int found; 160797883Sgibbs 160897883Sgibbs curelm = SLIST_FIRST(list); 160997883Sgibbs found = 0; 161097883Sgibbs if (curelm == &abort_ccb->ccb_h) { 161197883Sgibbs found = 1; 161297883Sgibbs SLIST_REMOVE_HEAD(list, sim_links.sle); 161397883Sgibbs } else { 161497883Sgibbs while(curelm != NULL) { 161597883Sgibbs struct ccb_hdr *nextelm; 161697883Sgibbs 161797883Sgibbs nextelm = 161897883Sgibbs SLIST_NEXT(curelm, sim_links.sle); 161997883Sgibbs 162097883Sgibbs if (nextelm == &abort_ccb->ccb_h) { 162197883Sgibbs found = 1; 162297883Sgibbs SLIST_NEXT(curelm, 162397883Sgibbs sim_links.sle) = 162497883Sgibbs SLIST_NEXT(nextelm, 162597883Sgibbs sim_links.sle); 162697883Sgibbs break; 162797883Sgibbs } 162897883Sgibbs curelm = nextelm; 162997883Sgibbs } 163097883Sgibbs } 163197883Sgibbs 163297883Sgibbs if (found) { 163397883Sgibbs abort_ccb->ccb_h.status = CAM_REQ_ABORTED; 163497883Sgibbs xpt_done(abort_ccb); 163597883Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 163697883Sgibbs } else { 163797883Sgibbs xpt_print_path(abort_ccb->ccb_h.path); 163897883Sgibbs printf("Not found\n"); 163997883Sgibbs ccb->ccb_h.status = CAM_PATH_INVALID; 164097883Sgibbs } 164197883Sgibbs break; 164297883Sgibbs } 164397883Sgibbs /* FALLTHROUGH */ 164497883Sgibbs } 164597883Sgibbs#endif 164697883Sgibbs case XPT_SCSI_IO: 164797883Sgibbs /* XXX Fully implement the hard ones */ 164897883Sgibbs ccb->ccb_h.status = CAM_UA_ABORT; 164997883Sgibbs break; 165097883Sgibbs default: 165197883Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 165297883Sgibbs break; 165397883Sgibbs } 165497883Sgibbs xpt_done(ccb); 165597883Sgibbs} 165697883Sgibbs 165797883Sgibbsvoid 165897883Sgibbsahd_send_async(struct ahd_softc *ahd, char channel, u_int target, 165997883Sgibbs u_int lun, ac_code code, void *opt_arg) 166097883Sgibbs{ 166197883Sgibbs struct ccb_trans_settings cts; 166297883Sgibbs struct cam_path *path; 166397883Sgibbs void *arg; 166497883Sgibbs int error; 166597883Sgibbs 166697883Sgibbs arg = NULL; 166797883Sgibbs error = ahd_create_path(ahd, channel, target, lun, &path); 166897883Sgibbs 166997883Sgibbs if (error != CAM_REQ_CMP) 167097883Sgibbs return; 167197883Sgibbs 167297883Sgibbs switch (code) { 167397883Sgibbs case AC_TRANSFER_NEG: 167497883Sgibbs { 167597883Sgibbs#ifdef AHD_NEW_TRAN_SETTINGS 167697883Sgibbs struct ccb_trans_settings_scsi *scsi; 167797883Sgibbs 167897883Sgibbs cts.type = CTS_TYPE_CURRENT_SETTINGS; 167997883Sgibbs scsi = &cts.proto_specific.scsi; 168097883Sgibbs#else 168197883Sgibbs cts.flags = CCB_TRANS_CURRENT_SETTINGS; 168297883Sgibbs#endif 168397883Sgibbs cts.ccb_h.path = path; 168497883Sgibbs cts.ccb_h.target_id = target; 168597883Sgibbs cts.ccb_h.target_lun = lun; 168697883Sgibbs ahd_get_tran_settings(ahd, ahd->our_id, channel, &cts); 168797883Sgibbs arg = &cts; 168897883Sgibbs#ifdef AHD_NEW_TRAN_SETTINGS 168997883Sgibbs scsi->valid &= ~CTS_SCSI_VALID_TQ; 169097883Sgibbs scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 169197883Sgibbs#else 169297883Sgibbs cts.valid &= ~CCB_TRANS_TQ_VALID; 169397883Sgibbs cts.flags &= ~CCB_TRANS_TAG_ENB; 169497883Sgibbs#endif 169597883Sgibbs if (opt_arg == NULL) 169697883Sgibbs break; 169797883Sgibbs if (*((ahd_queue_alg *)opt_arg) == AHD_QUEUE_TAGGED) 169897883Sgibbs#ifdef AHD_NEW_TRAN_SETTINGS 169997883Sgibbs scsi->flags |= ~CTS_SCSI_FLAGS_TAG_ENB; 170097883Sgibbs scsi->valid |= CTS_SCSI_VALID_TQ; 170197883Sgibbs#else 170297883Sgibbs cts.flags |= CCB_TRANS_TAG_ENB; 170397883Sgibbs cts.valid |= CCB_TRANS_TQ_VALID; 170497883Sgibbs#endif 170597883Sgibbs break; 170697883Sgibbs } 170797883Sgibbs case AC_SENT_BDR: 170897883Sgibbs case AC_BUS_RESET: 170997883Sgibbs break; 171097883Sgibbs default: 171197883Sgibbs panic("ahd_send_async: Unexpected async event"); 171297883Sgibbs } 171397883Sgibbs xpt_async(code, path, arg); 171497883Sgibbs xpt_free_path(path); 171597883Sgibbs} 171697883Sgibbs 171797883Sgibbsvoid 171897883Sgibbsahd_platform_set_tags(struct ahd_softc *ahd, 171997883Sgibbs struct ahd_devinfo *devinfo, int enable) 172097883Sgibbs{ 172197883Sgibbs} 172297883Sgibbs 172397883Sgibbsint 172497883Sgibbsahd_platform_alloc(struct ahd_softc *ahd, void *platform_arg) 172597883Sgibbs{ 172697883Sgibbs ahd->platform_data = malloc(sizeof(struct ahd_platform_data), M_DEVBUF, 172797883Sgibbs M_NOWAIT | M_ZERO); 172897883Sgibbs if (ahd->platform_data == NULL) 172997883Sgibbs return (ENOMEM); 173097883Sgibbs return (0); 173197883Sgibbs} 173297883Sgibbs 173397883Sgibbsvoid 173497883Sgibbsahd_platform_free(struct ahd_softc *ahd) 173597883Sgibbs{ 173697883Sgibbs struct ahd_platform_data *pdata; 173797883Sgibbs 173897883Sgibbs pdata = ahd->platform_data; 173997883Sgibbs if (pdata != NULL) { 174097883Sgibbs if (pdata->regs[0] != NULL) 174197883Sgibbs bus_release_resource(ahd->dev_softc, 174297883Sgibbs pdata->regs_res_type[0], 174397883Sgibbs pdata->regs_res_id[0], 174497883Sgibbs pdata->regs[0]); 174597883Sgibbs 174697883Sgibbs if (pdata->regs[1] != NULL) 174797883Sgibbs bus_release_resource(ahd->dev_softc, 174897883Sgibbs pdata->regs_res_type[1], 174997883Sgibbs pdata->regs_res_id[1], 175097883Sgibbs pdata->regs[1]); 175197883Sgibbs 175297883Sgibbs if (pdata->irq != NULL) 175397883Sgibbs bus_release_resource(ahd->dev_softc, 175497883Sgibbs pdata->irq_res_type, 175597883Sgibbs 0, pdata->irq); 175697883Sgibbs 175797883Sgibbs if (pdata->sim_b != NULL) { 175897883Sgibbs xpt_async(AC_LOST_DEVICE, pdata->path_b, NULL); 175997883Sgibbs xpt_free_path(pdata->path_b); 176097883Sgibbs xpt_bus_deregister(cam_sim_path(pdata->sim_b)); 176197883Sgibbs cam_sim_free(pdata->sim_b, /*free_devq*/TRUE); 176297883Sgibbs } 176397883Sgibbs if (pdata->sim != NULL) { 176497883Sgibbs xpt_async(AC_LOST_DEVICE, pdata->path, NULL); 176597883Sgibbs xpt_free_path(pdata->path); 176697883Sgibbs xpt_bus_deregister(cam_sim_path(pdata->sim)); 176797883Sgibbs cam_sim_free(pdata->sim, /*free_devq*/TRUE); 176897883Sgibbs } 176997883Sgibbs if (pdata->eh != NULL) 177097883Sgibbs EVENTHANDLER_DEREGISTER(shutdown_final, pdata->eh); 177197883Sgibbs free(ahd->platform_data, M_DEVBUF); 177297883Sgibbs } 177397883Sgibbs} 177497883Sgibbs 177597883Sgibbsint 177697883Sgibbsahd_softc_comp(struct ahd_softc *lahd, struct ahd_softc *rahd) 177797883Sgibbs{ 177897883Sgibbs /* We don't sort softcs under FreeBSD so report equal always */ 177997883Sgibbs return (0); 178097883Sgibbs} 178197883Sgibbs 178297883Sgibbsint 178397883Sgibbsahd_detach(device_t dev) 178497883Sgibbs{ 178597883Sgibbs struct ahd_softc *ahd; 178697883Sgibbs u_long l; 178797883Sgibbs u_long s; 178897883Sgibbs 178997883Sgibbs ahd_list_lock(&l); 179097883Sgibbs device_printf(dev, "detaching device\n"); 179197883Sgibbs ahd = device_get_softc(dev); 179297883Sgibbs ahd = ahd_find_softc(ahd); 179397883Sgibbs if (ahd == NULL) { 179497883Sgibbs device_printf(dev, "aic7xxx already detached\n"); 179597883Sgibbs ahd_list_unlock(&l); 179697883Sgibbs return (ENOENT); 179797883Sgibbs } 179897883Sgibbs ahd_lock(ahd, &s); 179997883Sgibbs ahd_intr_enable(ahd, FALSE); 180097883Sgibbs bus_teardown_intr(dev, ahd->platform_data->irq, ahd->platform_data->ih); 180197883Sgibbs ahd_unlock(ahd, &s); 180297883Sgibbs ahd_free(ahd); 180397883Sgibbs ahd_list_unlock(&l); 180497883Sgibbs return (0); 180597883Sgibbs} 180697883Sgibbs 180797883Sgibbs#if UNUSED 180897883Sgibbsstatic void 180997883Sgibbsahd_dump_targcmd(struct target_cmd *cmd) 181097883Sgibbs{ 181197883Sgibbs uint8_t *byte; 181297883Sgibbs uint8_t *last_byte; 181397883Sgibbs int i; 181497883Sgibbs 181597883Sgibbs byte = &cmd->initiator_channel; 181697883Sgibbs /* Debugging info for received commands */ 181797883Sgibbs last_byte = &cmd[1].initiator_channel; 181897883Sgibbs 181997883Sgibbs i = 0; 182097883Sgibbs while (byte < last_byte) { 182197883Sgibbs if (i == 0) 182297883Sgibbs printf("\t"); 182397883Sgibbs printf("%#x", *byte++); 182497883Sgibbs i++; 182597883Sgibbs if (i == 8) { 182697883Sgibbs printf("\n"); 182797883Sgibbs i = 0; 182897883Sgibbs } else { 182997883Sgibbs printf(", "); 183097883Sgibbs } 183197883Sgibbs } 183297883Sgibbs} 183397883Sgibbs#endif 183497883Sgibbs 183597883Sgibbsstatic int 183697883Sgibbsahd_modevent(module_t mod, int type, void *data) 183797883Sgibbs{ 183897883Sgibbs /* XXX Deal with busy status on unload. */ 183997883Sgibbs return 0; 184097883Sgibbs} 184197883Sgibbs 184297883Sgibbsstatic moduledata_t ahd_mod = { 184397883Sgibbs "ahd", 184497883Sgibbs ahd_modevent, 184597883Sgibbs NULL 184697883Sgibbs}; 184797883Sgibbs 184897883Sgibbs/********************************** DDB Hooks *********************************/ 184997883Sgibbs#ifdef DDB 185097883Sgibbsstatic struct ahd_softc *ahd_ddb_softc; 185197883Sgibbsstatic int ahd_ddb_paused; 185297883Sgibbsstatic int ahd_ddb_paused_on_entry; 185397883SgibbsDB_COMMAND(ahd_set_unit, ahd_ddb_set_unit) 185497883Sgibbs{ 185597883Sgibbs struct ahd_softc *list_ahd; 185697883Sgibbs 185797883Sgibbs ahd_ddb_softc = NULL; 185897883Sgibbs TAILQ_FOREACH(list_ahd, &ahd_tailq, links) { 185997883Sgibbs if (list_ahd->unit == addr) 186097883Sgibbs ahd_ddb_softc = list_ahd; 186197883Sgibbs } 186297883Sgibbs if (ahd_ddb_softc == NULL) 186397883Sgibbs db_error("No matching softc found!\n"); 186497883Sgibbs} 186597883Sgibbs 186697883SgibbsDB_COMMAND(ahd_pause, ahd_ddb_pause) 186797883Sgibbs{ 186897883Sgibbs if (ahd_ddb_softc == NULL) { 186997883Sgibbs db_error("Must set unit with ahd_set_unit first!\n"); 187097883Sgibbs return; 187197883Sgibbs } 187297883Sgibbs if (ahd_ddb_paused == 0) { 187397883Sgibbs ahd_ddb_paused++; 187497883Sgibbs if (ahd_is_paused(ahd_ddb_softc)) { 187597883Sgibbs ahd_ddb_paused_on_entry++; 187697883Sgibbs return; 187797883Sgibbs } 187897883Sgibbs ahd_pause(ahd_ddb_softc); 187997883Sgibbs } 188097883Sgibbs} 188197883Sgibbs 188297883SgibbsDB_COMMAND(ahd_unpause, ahd_ddb_unpause) 188397883Sgibbs{ 188497883Sgibbs if (ahd_ddb_softc == NULL) { 188597883Sgibbs db_error("Must set unit with ahd_set_unit first!\n"); 188697883Sgibbs return; 188797883Sgibbs } 188897883Sgibbs if (ahd_ddb_paused != 0) { 188997883Sgibbs ahd_ddb_paused = 0; 189097883Sgibbs if (ahd_ddb_paused_on_entry) 189197883Sgibbs return; 189297883Sgibbs ahd_unpause(ahd_ddb_softc); 189397883Sgibbs } else if (ahd_ddb_paused_on_entry != 0) { 189497883Sgibbs /* Two unpauses to clear a paused on entry. */ 189597883Sgibbs ahd_ddb_paused_on_entry = 0; 189697883Sgibbs ahd_unpause(ahd_ddb_softc); 189797883Sgibbs } 189897883Sgibbs} 189997883Sgibbs 190097883SgibbsDB_COMMAND(ahd_in, ahd_ddb_in) 190197883Sgibbs{ 190297883Sgibbs int c; 190397883Sgibbs int size; 190497883Sgibbs 190597883Sgibbs if (ahd_ddb_softc == NULL) { 190697883Sgibbs db_error("Must set unit with ahd_set_unit first!\n"); 190797883Sgibbs return; 190897883Sgibbs } 190997883Sgibbs if (have_addr == 0) 191097883Sgibbs return; 191197883Sgibbs 191297883Sgibbs size = 1; 191397883Sgibbs while ((c = *modif++) != '\0') { 191497883Sgibbs switch (c) { 191597883Sgibbs case 'b': 191697883Sgibbs size = 1; 191797883Sgibbs break; 191897883Sgibbs case 'w': 191997883Sgibbs size = 2; 192097883Sgibbs break; 192197883Sgibbs case 'l': 192297883Sgibbs size = 4; 192397883Sgibbs break; 192497883Sgibbs } 192597883Sgibbs } 192697883Sgibbs 192797883Sgibbs if (count <= 0) 192897883Sgibbs count = 1; 192997883Sgibbs while (--count >= 0) { 1930107368Sscottl db_printf("%04lx (M)%x: \t", (u_long)addr, 193197883Sgibbs ahd_inb(ahd_ddb_softc, MODE_PTR)); 193297883Sgibbs switch (size) { 193397883Sgibbs case 1: 193497883Sgibbs db_printf("%02x\n", ahd_inb(ahd_ddb_softc, addr)); 193597883Sgibbs break; 193697883Sgibbs case 2: 193797883Sgibbs db_printf("%04x\n", ahd_inw(ahd_ddb_softc, addr)); 193897883Sgibbs break; 193997883Sgibbs case 4: 194097883Sgibbs db_printf("%08x\n", ahd_inl(ahd_ddb_softc, addr)); 194197883Sgibbs break; 194297883Sgibbs } 194397883Sgibbs } 194497883Sgibbs} 194597883Sgibbs 194697883SgibbsDB_SET(ahd_out, ahd_ddb_out, db_cmd_set, CS_MORE, NULL) 194797883Sgibbs{ 194897883Sgibbs db_expr_t old_value; 194997883Sgibbs db_expr_t new_value; 195097883Sgibbs int size; 195197883Sgibbs 195297883Sgibbs if (ahd_ddb_softc == NULL) { 195397883Sgibbs db_error("Must set unit with ahd_set_unit first!\n"); 195497883Sgibbs return; 195597883Sgibbs } 195697883Sgibbs 195797883Sgibbs switch (modif[0]) { 195897883Sgibbs case '\0': 195997883Sgibbs case 'b': 196097883Sgibbs size = 1; 196197883Sgibbs break; 196297883Sgibbs case 'h': 196397883Sgibbs size = 2; 196497883Sgibbs break; 196597883Sgibbs case 'l': 196697883Sgibbs size = 4; 196797883Sgibbs break; 196897883Sgibbs default: 196997883Sgibbs db_error("Unknown size\n"); 197097883Sgibbs return; 197197883Sgibbs } 197297883Sgibbs 197397883Sgibbs while (db_expression(&new_value)) { 197497883Sgibbs switch (size) { 197597883Sgibbs default: 197697883Sgibbs case 1: 197797883Sgibbs old_value = ahd_inb(ahd_ddb_softc, addr); 197897883Sgibbs ahd_outb(ahd_ddb_softc, addr, new_value); 197997883Sgibbs break; 198097883Sgibbs case 2: 198197883Sgibbs old_value = ahd_inw(ahd_ddb_softc, addr); 198297883Sgibbs ahd_outw(ahd_ddb_softc, addr, new_value); 198397883Sgibbs break; 198497883Sgibbs case 4: 198597883Sgibbs old_value = ahd_inl(ahd_ddb_softc, addr); 198697883Sgibbs ahd_outl(ahd_ddb_softc, addr, new_value); 198797883Sgibbs break; 198897883Sgibbs } 1989107368Sscottl db_printf("%04lx (M)%x: \t0x%lx\t=\t0x%lx", 1990107368Sscottl (u_long)addr, ahd_inb(ahd_ddb_softc, MODE_PTR), 1991107368Sscottl (u_long)old_value, (u_long)new_value); 199297883Sgibbs addr += size; 199397883Sgibbs } 199497883Sgibbs db_skip_to_eol(); 199597883Sgibbs} 199697883Sgibbs 199797883Sgibbs#endif 199897883Sgibbs 199997883Sgibbs 200097883SgibbsDECLARE_MODULE(ahd, ahd_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); 200197883SgibbsMODULE_DEPEND(ahd, cam, 1, 1, 1); 200297883SgibbsMODULE_VERSION(ahd, 1); 2003