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