aic7xxx_osm.c revision 150450
1139749Simp/*- 2123579Sgibbs * Bus independent FreeBSD shim for the aic7xxx based Adaptec SCSI controllers 365942Sgibbs * 471717Sgibbs * Copyright (c) 1994-2001 Justin T. Gibbs. 565942Sgibbs * All rights reserved. 665942Sgibbs * 765942Sgibbs * Redistribution and use in source and binary forms, with or without 865942Sgibbs * modification, are permitted provided that the following conditions 965942Sgibbs * are met: 1065942Sgibbs * 1. Redistributions of source code must retain the above copyright 1165942Sgibbs * notice, this list of conditions, and the following disclaimer, 1265942Sgibbs * without modification. 1365942Sgibbs * 2. The name of the author may not be used to endorse or promote products 1465942Sgibbs * derived from this software without specific prior written permission. 1565942Sgibbs * 1665942Sgibbs * Alternatively, this software may be distributed under the terms of the 1765942Sgibbs * GNU Public License ("GPL"). 1865942Sgibbs * 1965942Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2065942Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2165942Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2265942Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 2365942Sgibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2465942Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2565942Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2665942Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2765942Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2865942Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2965942Sgibbs * SUCH DAMAGE. 3065942Sgibbs * 31123579Sgibbs * $Id: //depot/aic7xxx/freebsd/dev/aic7xxx/aic7xxx_osm.c#20 $ 3265942Sgibbs */ 3365942Sgibbs 34119418Sobrien#include <sys/cdefs.h> 35119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/aic7xxx/aic7xxx_osm.c 150450 2005-09-22 05:01:37Z gibbs $"); 36119418Sobrien 3795378Sgibbs#include <dev/aic7xxx/aic7xxx_osm.h> 3865942Sgibbs#include <dev/aic7xxx/aic7xxx_inline.h> 3965942Sgibbs 40123579Sgibbs#include <sys/kthread.h> 41123579Sgibbs 4265942Sgibbs#ifndef AHC_TMODE_ENABLE 4365942Sgibbs#define AHC_TMODE_ENABLE 0 4465942Sgibbs#endif 4565942Sgibbs 46123579Sgibbs#include <dev/aic7xxx/aic_osm_lib.c> 47123579Sgibbs 4865942Sgibbs#define ccb_scb_ptr spriv_ptr0 4965942Sgibbs 50103811Sscottldevclass_t ahc_devclass; 51103811Sscottl 5265942Sgibbs#if UNUSED 5365942Sgibbsstatic void ahc_dump_targcmd(struct target_cmd *cmd); 5465942Sgibbs#endif 5576634Sgibbsstatic int ahc_modevent(module_t mod, int type, void *data); 5665942Sgibbsstatic void ahc_action(struct cam_sim *sim, union ccb *ccb); 5765942Sgibbsstatic void ahc_get_tran_settings(struct ahc_softc *ahc, 5865942Sgibbs int our_id, char channel, 5965942Sgibbs struct ccb_trans_settings *cts); 6065942Sgibbsstatic void ahc_async(void *callback_arg, uint32_t code, 6165942Sgibbs struct cam_path *path, void *arg); 6265942Sgibbsstatic void ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, 6365942Sgibbs int nsegments, int error); 6465942Sgibbsstatic void ahc_poll(struct cam_sim *sim); 6565942Sgibbsstatic void ahc_setup_data(struct ahc_softc *ahc, struct cam_sim *sim, 6665942Sgibbs struct ccb_scsiio *csio, struct scb *scb); 6765942Sgibbsstatic void ahc_abort_ccb(struct ahc_softc *ahc, struct cam_sim *sim, 6865942Sgibbs union ccb *ccb); 6965942Sgibbsstatic int ahc_create_path(struct ahc_softc *ahc, 7066269Sgibbs char channel, u_int target, u_int lun, 7165942Sgibbs struct cam_path **path); 7265942Sgibbs 7365942Sgibbs 7465942Sgibbsstatic int 7566269Sgibbsahc_create_path(struct ahc_softc *ahc, char channel, u_int target, 7666269Sgibbs u_int lun, struct cam_path **path) 7765942Sgibbs{ 7865942Sgibbs path_id_t path_id; 7965942Sgibbs 8066269Sgibbs if (channel == 'B') 8165942Sgibbs path_id = cam_sim_path(ahc->platform_data->sim_b); 8265942Sgibbs else 8365942Sgibbs path_id = cam_sim_path(ahc->platform_data->sim); 8465942Sgibbs 8565942Sgibbs return (xpt_create_path(path, /*periph*/NULL, 8666269Sgibbs path_id, target, lun)); 8765942Sgibbs} 8865942Sgibbs 8995378Sgibbsint 9095378Sgibbsahc_map_int(struct ahc_softc *ahc) 9195378Sgibbs{ 9295378Sgibbs int error; 93133911Sgibbs int zero; 94133911Sgibbs int shareable; 9595378Sgibbs 96133911Sgibbs zero = 0; 97133911Sgibbs shareable = (ahc->flags & AHC_EDGE_INTERRUPT) ? 0: RF_SHAREABLE; 98133911Sgibbs ahc->platform_data->irq = 99133911Sgibbs bus_alloc_resource_any(ahc->dev_softc, SYS_RES_IRQ, &zero, 100133911Sgibbs RF_ACTIVE | shareable); 101133911Sgibbs if (ahc->platform_data->irq == NULL) { 102133911Sgibbs device_printf(ahc->dev_softc, 103133911Sgibbs "bus_alloc_resource() failed to allocate IRQ\n"); 104133911Sgibbs return (ENOMEM); 105133911Sgibbs } 106133911Sgibbs ahc->platform_data->irq_res_type = SYS_RES_IRQ; 107133911Sgibbs 10895378Sgibbs /* Hook up our interrupt handler */ 10995378Sgibbs error = bus_setup_intr(ahc->dev_softc, ahc->platform_data->irq, 11095378Sgibbs INTR_TYPE_CAM, ahc_platform_intr, ahc, 11195378Sgibbs &ahc->platform_data->ih); 11295378Sgibbs 11395378Sgibbs if (error != 0) 11495378Sgibbs device_printf(ahc->dev_softc, "bus_setup_intr() failed: %d\n", 11595378Sgibbs error); 11695378Sgibbs return (error); 11795378Sgibbs} 11895378Sgibbs 119133911Sgibbsint 120133911Sgibbsaic7770_map_registers(struct ahc_softc *ahc, u_int unused_ioport_arg) 121133911Sgibbs{ 122133911Sgibbs struct resource *regs; 123133911Sgibbs int rid; 124133911Sgibbs 125133911Sgibbs rid = 0; 126133911Sgibbs regs = bus_alloc_resource_any(ahc->dev_softc, SYS_RES_IOPORT, &rid, 127133911Sgibbs RF_ACTIVE); 128133911Sgibbs if (regs == NULL) { 129133911Sgibbs device_printf(ahc->dev_softc, "Unable to map I/O space?!\n"); 130133911Sgibbs return ENOMEM; 131133911Sgibbs } 132133911Sgibbs ahc->platform_data->regs_res_type = SYS_RES_IOPORT; 133133911Sgibbs ahc->platform_data->regs_res_id = rid, 134133911Sgibbs ahc->platform_data->regs = regs; 135133911Sgibbs ahc->tag = rman_get_bustag(regs); 136133911Sgibbs ahc->bsh = rman_get_bushandle(regs); 137133911Sgibbs return (0); 138133911Sgibbs} 139133911Sgibbs 14065942Sgibbs/* 14165942Sgibbs * Attach all the sub-devices we can find 14265942Sgibbs */ 14365942Sgibbsint 14465942Sgibbsahc_attach(struct ahc_softc *ahc) 14565942Sgibbs{ 14665942Sgibbs char ahc_info[256]; 14765942Sgibbs struct ccb_setasync csa; 14865942Sgibbs struct cam_devq *devq; 14965942Sgibbs int bus_id; 15065942Sgibbs int bus_id2; 15165942Sgibbs struct cam_sim *sim; 15265942Sgibbs struct cam_sim *sim2; 15365942Sgibbs struct cam_path *path; 15465942Sgibbs struct cam_path *path2; 15565942Sgibbs long s; 15665942Sgibbs int count; 15765942Sgibbs 15865942Sgibbs count = 0; 15965942Sgibbs sim = NULL; 16065942Sgibbs sim2 = NULL; 16165942Sgibbs 162123579Sgibbs /* 163123579Sgibbs * Create a thread to perform all recovery. 164123579Sgibbs */ 165123579Sgibbs if (ahc_spawn_recovery_thread(ahc) != 0) 166123579Sgibbs goto fail; 167123579Sgibbs 16865942Sgibbs ahc_controller_info(ahc, ahc_info); 16965942Sgibbs printf("%s\n", ahc_info); 17065942Sgibbs ahc_lock(ahc, &s); 171123579Sgibbs 17265942Sgibbs /* 17365942Sgibbs * Attach secondary channel first if the user has 17465942Sgibbs * declared it the primary channel. 17565942Sgibbs */ 17672552Sgibbs if ((ahc->features & AHC_TWIN) != 0 17774094Sgibbs && (ahc->flags & AHC_PRIMARY_CHANNEL) != 0) { 17865942Sgibbs bus_id = 1; 17965942Sgibbs bus_id2 = 0; 18065942Sgibbs } else { 18165942Sgibbs bus_id = 0; 18265942Sgibbs bus_id2 = 1; 18365942Sgibbs } 18465942Sgibbs 18565942Sgibbs /* 18665942Sgibbs * Create the device queue for our SIM(s). 18765942Sgibbs */ 18871390Sgibbs devq = cam_simq_alloc(AHC_MAX_QUEUE); 18965942Sgibbs if (devq == NULL) 19065942Sgibbs goto fail; 19165942Sgibbs 19265942Sgibbs /* 19365942Sgibbs * Construct our first channel SIM entry 19465942Sgibbs */ 19566104Sgibbs sim = cam_sim_alloc(ahc_action, ahc_poll, "ahc", ahc, 19666104Sgibbs device_get_unit(ahc->dev_softc), 19771390Sgibbs 1, AHC_MAX_QUEUE, devq); 19865942Sgibbs if (sim == NULL) { 19965942Sgibbs cam_simq_free(devq); 20065942Sgibbs goto fail; 20165942Sgibbs } 20265942Sgibbs 20365942Sgibbs if (xpt_bus_register(sim, bus_id) != CAM_SUCCESS) { 20465942Sgibbs cam_sim_free(sim, /*free_devq*/TRUE); 20565942Sgibbs sim = NULL; 20665942Sgibbs goto fail; 20765942Sgibbs } 20865942Sgibbs 20965942Sgibbs if (xpt_create_path(&path, /*periph*/NULL, 21065942Sgibbs cam_sim_path(sim), CAM_TARGET_WILDCARD, 21165942Sgibbs CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 21265942Sgibbs xpt_bus_deregister(cam_sim_path(sim)); 21365942Sgibbs cam_sim_free(sim, /*free_devq*/TRUE); 21465942Sgibbs sim = NULL; 21565942Sgibbs goto fail; 21665942Sgibbs } 21765942Sgibbs 21865942Sgibbs xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5); 21965942Sgibbs csa.ccb_h.func_code = XPT_SASYNC_CB; 22065942Sgibbs csa.event_enable = AC_LOST_DEVICE; 22165942Sgibbs csa.callback = ahc_async; 22265942Sgibbs csa.callback_arg = sim; 22365942Sgibbs xpt_action((union ccb *)&csa); 22465942Sgibbs count++; 22565942Sgibbs 22665942Sgibbs if (ahc->features & AHC_TWIN) { 22765942Sgibbs sim2 = cam_sim_alloc(ahc_action, ahc_poll, "ahc", 22866104Sgibbs ahc, device_get_unit(ahc->dev_softc), 1, 22971390Sgibbs AHC_MAX_QUEUE, devq); 23065942Sgibbs 23165942Sgibbs if (sim2 == NULL) { 23265942Sgibbs printf("ahc_attach: Unable to attach second " 23365942Sgibbs "bus due to resource shortage"); 23465942Sgibbs goto fail; 23565942Sgibbs } 23665942Sgibbs 23765942Sgibbs if (xpt_bus_register(sim2, bus_id2) != CAM_SUCCESS) { 23865942Sgibbs printf("ahc_attach: Unable to attach second " 23965942Sgibbs "bus due to resource shortage"); 24065942Sgibbs /* 24165942Sgibbs * We do not want to destroy the device queue 24265942Sgibbs * because the first bus is using it. 24365942Sgibbs */ 24465942Sgibbs cam_sim_free(sim2, /*free_devq*/FALSE); 24565942Sgibbs goto fail; 24665942Sgibbs } 24765942Sgibbs 24865942Sgibbs if (xpt_create_path(&path2, /*periph*/NULL, 24965942Sgibbs cam_sim_path(sim2), 25065942Sgibbs CAM_TARGET_WILDCARD, 25165942Sgibbs CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 25265942Sgibbs xpt_bus_deregister(cam_sim_path(sim2)); 25365942Sgibbs cam_sim_free(sim2, /*free_devq*/FALSE); 25465942Sgibbs sim2 = NULL; 25565942Sgibbs goto fail; 25665942Sgibbs } 25765942Sgibbs xpt_setup_ccb(&csa.ccb_h, path2, /*priority*/5); 25865942Sgibbs csa.ccb_h.func_code = XPT_SASYNC_CB; 25965942Sgibbs csa.event_enable = AC_LOST_DEVICE; 26065942Sgibbs csa.callback = ahc_async; 26165942Sgibbs csa.callback_arg = sim2; 26265942Sgibbs xpt_action((union ccb *)&csa); 26365942Sgibbs count++; 26465942Sgibbs } 26565942Sgibbs 26665942Sgibbsfail: 26772552Sgibbs if ((ahc->features & AHC_TWIN) != 0 26874094Sgibbs && (ahc->flags & AHC_PRIMARY_CHANNEL) != 0) { 26965942Sgibbs ahc->platform_data->sim_b = sim; 27065942Sgibbs ahc->platform_data->path_b = path; 27165942Sgibbs ahc->platform_data->sim = sim2; 27265942Sgibbs ahc->platform_data->path = path2; 27365942Sgibbs } else { 27465942Sgibbs ahc->platform_data->sim = sim; 27565942Sgibbs ahc->platform_data->path = path; 27665942Sgibbs ahc->platform_data->sim_b = sim2; 27765942Sgibbs ahc->platform_data->path_b = path2; 27865942Sgibbs } 27965942Sgibbs 280102674Sgibbs if (count != 0) { 28165942Sgibbs /* We have to wait until after any system dumps... */ 28270204Sgibbs ahc->platform_data->eh = 28370204Sgibbs EVENTHANDLER_REGISTER(shutdown_final, ahc_shutdown, 28470204Sgibbs ahc, SHUTDOWN_PRI_DEFAULT); 285102674Sgibbs ahc_intr_enable(ahc, TRUE); 286102674Sgibbs } 28765942Sgibbs 288102674Sgibbs ahc_unlock(ahc, &s); 28965942Sgibbs return (count); 29065942Sgibbs} 29165942Sgibbs 29265942Sgibbs/* 29365942Sgibbs * Catch an interrupt from the adapter 29465942Sgibbs */ 29565942Sgibbsvoid 29670204Sgibbsahc_platform_intr(void *arg) 29765942Sgibbs{ 29865942Sgibbs struct ahc_softc *ahc; 29965942Sgibbs 30065942Sgibbs ahc = (struct ahc_softc *)arg; 30165942Sgibbs ahc_intr(ahc); 30265942Sgibbs} 30365942Sgibbs 30465942Sgibbs/* 30565942Sgibbs * We have an scb which has been processed by the 30665942Sgibbs * adaptor, now we look to see how the operation 30765942Sgibbs * went. 30865942Sgibbs */ 30965942Sgibbsvoid 31065942Sgibbsahc_done(struct ahc_softc *ahc, struct scb *scb) 31165942Sgibbs{ 31265942Sgibbs union ccb *ccb; 31365942Sgibbs 31465942Sgibbs CAM_DEBUG(scb->io_ctx->ccb_h.path, CAM_DEBUG_TRACE, 31565942Sgibbs ("ahc_done - scb %d\n", scb->hscb->tag)); 31665942Sgibbs 31765942Sgibbs ccb = scb->io_ctx; 31865942Sgibbs LIST_REMOVE(scb, pending_links); 319123579Sgibbs if ((scb->flags & SCB_TIMEDOUT) != 0) 320123579Sgibbs LIST_REMOVE(scb, timedout_links); 32166986Sgibbs if ((scb->flags & SCB_UNTAGGEDQ) != 0) { 32265942Sgibbs struct scb_tailq *untagged_q; 32372811Sgibbs int target_offset; 32465942Sgibbs 32572811Sgibbs target_offset = SCB_GET_TARGET_OFFSET(ahc, scb); 32672811Sgibbs untagged_q = &ahc->untagged_queues[target_offset]; 32765942Sgibbs TAILQ_REMOVE(untagged_q, scb, links.tqe); 32866986Sgibbs scb->flags &= ~SCB_UNTAGGEDQ; 32965942Sgibbs ahc_run_untagged_queue(ahc, untagged_q); 33065942Sgibbs } 33165942Sgibbs 332123579Sgibbs untimeout(ahc_platform_timeout, (caddr_t)scb, ccb->ccb_h.timeout_ch); 33365942Sgibbs 33465942Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) { 335115343Sscottl bus_dmasync_op_t op; 33665942Sgibbs 33765942Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) 33865942Sgibbs op = BUS_DMASYNC_POSTREAD; 33965942Sgibbs else 34065942Sgibbs op = BUS_DMASYNC_POSTWRITE; 34165942Sgibbs bus_dmamap_sync(ahc->buffer_dmat, scb->dmamap, op); 34265942Sgibbs bus_dmamap_unload(ahc->buffer_dmat, scb->dmamap); 34365942Sgibbs } 34465942Sgibbs 34565942Sgibbs if (ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) { 34674972Sgibbs struct cam_path *ccb_path; 34774972Sgibbs 34874972Sgibbs /* 34974972Sgibbs * If we have finally disconnected, clean up our 35074972Sgibbs * pending device state. 35174972Sgibbs * XXX - There may be error states that cause where 35274972Sgibbs * we will remain connected. 35374972Sgibbs */ 35474972Sgibbs ccb_path = ccb->ccb_h.path; 35574972Sgibbs if (ahc->pending_device != NULL 35674972Sgibbs && xpt_path_comp(ahc->pending_device->path, ccb_path) == 0) { 35774972Sgibbs 35874972Sgibbs if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) { 35974972Sgibbs ahc->pending_device = NULL; 36074972Sgibbs } else { 36195378Sgibbs if (bootverbose) { 36295378Sgibbs xpt_print_path(ccb->ccb_h.path); 36395378Sgibbs printf("Still connected\n"); 36495378Sgibbs } 365123579Sgibbs aic_freeze_ccb(ccb); 36674972Sgibbs } 36774972Sgibbs } 36874972Sgibbs 369123579Sgibbs if (aic_get_transaction_status(scb) == CAM_REQ_INPROG) 37065942Sgibbs ccb->ccb_h.status |= CAM_REQ_CMP; 37165942Sgibbs ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 37265942Sgibbs ahc_free_scb(ahc, scb); 37365942Sgibbs xpt_done(ccb); 37465942Sgibbs return; 37565942Sgibbs } 37665942Sgibbs 37765942Sgibbs /* 37865942Sgibbs * If the recovery SCB completes, we have to be 37965942Sgibbs * out of our timeout. 38065942Sgibbs */ 38165942Sgibbs if ((scb->flags & SCB_RECOVERY_SCB) != 0) { 38265942Sgibbs struct scb *list_scb; 38365942Sgibbs 384133911Sgibbs ahc->scb_data->recovery_scbs--; 38565942Sgibbs 386123579Sgibbs if (aic_get_transaction_status(scb) == CAM_BDR_SENT 387123579Sgibbs || aic_get_transaction_status(scb) == CAM_REQ_ABORTED) 388123579Sgibbs aic_set_transaction_status(scb, CAM_CMD_TIMEOUT); 389133911Sgibbs 390133911Sgibbs if (ahc->scb_data->recovery_scbs == 0) { 391133911Sgibbs /* 392133911Sgibbs * All recovery actions have completed successfully, 393133911Sgibbs * so reinstate the timeouts for all other pending 394133911Sgibbs * commands. 395133911Sgibbs */ 396133911Sgibbs LIST_FOREACH(list_scb, &ahc->pending_scbs, 397133911Sgibbs pending_links) { 398133911Sgibbs 399150450Sgibbs aic_scb_timer_reset(list_scb, 400150450Sgibbs aic_get_timeout(scb)); 401133911Sgibbs } 402133911Sgibbs 403133911Sgibbs ahc_print_path(ahc, scb); 404133911Sgibbs printf("no longer in timeout, status = %x\n", 405133911Sgibbs ccb->ccb_h.status); 406133911Sgibbs } 40765942Sgibbs } 40865942Sgibbs 40965942Sgibbs /* Don't clobber any existing error state */ 410123579Sgibbs if (aic_get_transaction_status(scb) == CAM_REQ_INPROG) { 41165942Sgibbs ccb->ccb_h.status |= CAM_REQ_CMP; 41265942Sgibbs } else if ((scb->flags & SCB_SENSE) != 0) { 41365942Sgibbs /* 41465942Sgibbs * We performed autosense retrieval. 41565942Sgibbs * 41665942Sgibbs * Zero any sense not transferred by the 41765942Sgibbs * device. The SCSI spec mandates that any 41865942Sgibbs * untransfered data should be assumed to be 41965942Sgibbs * zero. Complete the 'bounce' of sense information 42065942Sgibbs * through buffers accessible via bus-space by 42165942Sgibbs * copying it into the clients csio. 42265942Sgibbs */ 42365942Sgibbs memset(&ccb->csio.sense_data, 0, sizeof(ccb->csio.sense_data)); 42465942Sgibbs memcpy(&ccb->csio.sense_data, 42570807Sgibbs ahc_get_sense_buf(ahc, scb), 426123579Sgibbs (aic_le32toh(scb->sg_list->len) & AHC_SG_LEN_MASK) 42765942Sgibbs - ccb->csio.sense_resid); 42865942Sgibbs scb->io_ctx->ccb_h.status |= CAM_AUTOSNS_VALID; 42965942Sgibbs } 43065942Sgibbs ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 43165942Sgibbs ahc_free_scb(ahc, scb); 43265942Sgibbs xpt_done(ccb); 43365942Sgibbs} 43465942Sgibbs 43565942Sgibbsstatic void 43665942Sgibbsahc_action(struct cam_sim *sim, union ccb *ccb) 43765942Sgibbs{ 43865942Sgibbs struct ahc_softc *ahc; 43974972Sgibbs struct ahc_tmode_lstate *lstate; 44065942Sgibbs u_int target_id; 44165942Sgibbs u_int our_id; 44265942Sgibbs long s; 44365942Sgibbs 44465942Sgibbs CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("ahc_action\n")); 44565942Sgibbs 44665942Sgibbs ahc = (struct ahc_softc *)cam_sim_softc(sim); 44765942Sgibbs 44865942Sgibbs target_id = ccb->ccb_h.target_id; 44965942Sgibbs our_id = SIM_SCSI_ID(ahc, sim); 45065942Sgibbs 45165942Sgibbs switch (ccb->ccb_h.func_code) { 45265942Sgibbs /* Common cases first */ 45365942Sgibbs case XPT_ACCEPT_TARGET_IO: /* Accept Host Target Mode CDB */ 45465942Sgibbs case XPT_CONT_TARGET_IO:/* Continue Host Target I/O Connection*/ 45565942Sgibbs { 45674972Sgibbs struct ahc_tmode_tstate *tstate; 45765942Sgibbs cam_status status; 45865942Sgibbs 45965942Sgibbs status = ahc_find_tmode_devs(ahc, sim, ccb, &tstate, 46065942Sgibbs &lstate, TRUE); 46165942Sgibbs 46265942Sgibbs if (status != CAM_REQ_CMP) { 46365942Sgibbs if (ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) { 46465942Sgibbs /* Response from the black hole device */ 46565942Sgibbs tstate = NULL; 46665942Sgibbs lstate = ahc->black_hole; 46765942Sgibbs } else { 46865942Sgibbs ccb->ccb_h.status = status; 46965942Sgibbs xpt_done(ccb); 47065942Sgibbs break; 47165942Sgibbs } 47265942Sgibbs } 47365942Sgibbs if (ccb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) { 47465942Sgibbs 47565942Sgibbs ahc_lock(ahc, &s); 47665942Sgibbs SLIST_INSERT_HEAD(&lstate->accept_tios, &ccb->ccb_h, 47765942Sgibbs sim_links.sle); 47865942Sgibbs ccb->ccb_h.status = CAM_REQ_INPROG; 47965942Sgibbs if ((ahc->flags & AHC_TQINFIFO_BLOCKED) != 0) 48065942Sgibbs ahc_run_tqinfifo(ahc, /*paused*/FALSE); 48165942Sgibbs ahc_unlock(ahc, &s); 48265942Sgibbs break; 48365942Sgibbs } 48465942Sgibbs 48565942Sgibbs /* 48665942Sgibbs * The target_id represents the target we attempt to 48765942Sgibbs * select. In target mode, this is the initiator of 48865942Sgibbs * the original command. 48965942Sgibbs */ 49065942Sgibbs our_id = target_id; 49165942Sgibbs target_id = ccb->csio.init_id; 49265942Sgibbs /* FALLTHROUGH */ 49365942Sgibbs } 49465942Sgibbs case XPT_SCSI_IO: /* Execute the requested I/O operation */ 49565942Sgibbs case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */ 49665942Sgibbs { 49766717Sgibbs struct scb *scb; 49866717Sgibbs struct hardware_scb *hscb; 49965942Sgibbs 50068087Sgibbs if ((ahc->flags & AHC_INITIATORROLE) == 0 50168087Sgibbs && (ccb->ccb_h.func_code == XPT_SCSI_IO 50268087Sgibbs || ccb->ccb_h.func_code == XPT_RESET_DEV)) { 50368087Sgibbs ccb->ccb_h.status = CAM_PROVIDE_FAIL; 50468087Sgibbs xpt_done(ccb); 50574972Sgibbs return; 50668087Sgibbs } 50768087Sgibbs 50865942Sgibbs /* 50965942Sgibbs * get an scb to use. 51065942Sgibbs */ 51166717Sgibbs ahc_lock(ahc, &s); 51265942Sgibbs if ((scb = ahc_get_scb(ahc)) == NULL) { 51365942Sgibbs 51466891Sgibbs xpt_freeze_simq(sim, /*count*/1); 51565942Sgibbs ahc->flags |= AHC_RESOURCE_SHORTAGE; 51665942Sgibbs ahc_unlock(ahc, &s); 51766510Sgibbs ccb->ccb_h.status = CAM_REQUEUE_REQ; 51865942Sgibbs xpt_done(ccb); 51965942Sgibbs return; 52065942Sgibbs } 52166717Sgibbs ahc_unlock(ahc, &s); 52265942Sgibbs 52365942Sgibbs hscb = scb->hscb; 52465942Sgibbs 52565942Sgibbs CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_SUBTRACE, 52665942Sgibbs ("start scb(%p)\n", scb)); 52765942Sgibbs scb->io_ctx = ccb; 52865942Sgibbs /* 52965942Sgibbs * So we can find the SCB when an abort is requested 53065942Sgibbs */ 53165942Sgibbs ccb->ccb_h.ccb_scb_ptr = scb; 53265942Sgibbs 53365942Sgibbs /* 53465942Sgibbs * Put all the arguments for the xfer in the scb 53565942Sgibbs */ 53665942Sgibbs hscb->control = 0; 53765942Sgibbs hscb->scsiid = BUILD_SCSIID(ahc, sim, target_id, our_id); 53865942Sgibbs hscb->lun = ccb->ccb_h.target_lun; 53965942Sgibbs if (ccb->ccb_h.func_code == XPT_RESET_DEV) { 54065942Sgibbs hscb->cdb_len = 0; 54165942Sgibbs scb->flags |= SCB_DEVICE_RESET; 54265942Sgibbs hscb->control |= MK_MESSAGE; 54365942Sgibbs ahc_execute_scb(scb, NULL, 0, 0); 54465942Sgibbs } else { 54565942Sgibbs if (ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) { 54665942Sgibbs struct target_data *tdata; 54765942Sgibbs 54865942Sgibbs tdata = &hscb->shared_data.tdata; 54974972Sgibbs if (ahc->pending_device == lstate) 55065942Sgibbs scb->flags |= SCB_TARGET_IMMEDIATE; 55165942Sgibbs hscb->control |= TARGET_SCB; 552107417Sscottl scb->flags |= SCB_TARGET_SCB; 553107417Sscottl tdata->target_phases = 0; 55465942Sgibbs if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) { 55565942Sgibbs tdata->target_phases |= SPHASE_PENDING; 55665942Sgibbs tdata->scsi_status = 55765942Sgibbs ccb->csio.scsi_status; 55865942Sgibbs } 55974972Sgibbs if (ccb->ccb_h.flags & CAM_DIS_DISCONNECT) 56074972Sgibbs tdata->target_phases |= NO_DISCONNECT; 56174972Sgibbs 56265942Sgibbs tdata->initiator_tag = ccb->csio.tag_id; 56365942Sgibbs } 56465942Sgibbs if (ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) 56565942Sgibbs hscb->control |= ccb->csio.tag_action; 56665942Sgibbs 56765942Sgibbs ahc_setup_data(ahc, sim, &ccb->csio, scb); 56865942Sgibbs } 56965942Sgibbs break; 57065942Sgibbs } 57165942Sgibbs case XPT_NOTIFY_ACK: 57265942Sgibbs case XPT_IMMED_NOTIFY: 57365942Sgibbs { 57474972Sgibbs struct ahc_tmode_tstate *tstate; 57574972Sgibbs struct ahc_tmode_lstate *lstate; 57665942Sgibbs cam_status status; 57765942Sgibbs 57865942Sgibbs status = ahc_find_tmode_devs(ahc, sim, ccb, &tstate, 57965942Sgibbs &lstate, TRUE); 58065942Sgibbs 58165942Sgibbs if (status != CAM_REQ_CMP) { 58265942Sgibbs ccb->ccb_h.status = status; 58365942Sgibbs xpt_done(ccb); 58465942Sgibbs break; 58565942Sgibbs } 58665942Sgibbs SLIST_INSERT_HEAD(&lstate->immed_notifies, &ccb->ccb_h, 58765942Sgibbs sim_links.sle); 58865942Sgibbs ccb->ccb_h.status = CAM_REQ_INPROG; 58965942Sgibbs ahc_send_lstate_events(ahc, lstate); 59065942Sgibbs break; 59165942Sgibbs } 59265942Sgibbs case XPT_EN_LUN: /* Enable LUN as a target */ 59365942Sgibbs ahc_handle_en_lun(ahc, sim, ccb); 59465942Sgibbs xpt_done(ccb); 59565942Sgibbs break; 59665942Sgibbs case XPT_ABORT: /* Abort the specified CCB */ 59765942Sgibbs { 59865942Sgibbs ahc_abort_ccb(ahc, sim, ccb); 59965942Sgibbs break; 60065942Sgibbs } 60165942Sgibbs case XPT_SET_TRAN_SETTINGS: 60265942Sgibbs { 60365942Sgibbs#ifdef AHC_NEW_TRAN_SETTINGS 60465942Sgibbs struct ahc_devinfo devinfo; 60565942Sgibbs struct ccb_trans_settings *cts; 60665942Sgibbs struct ccb_trans_settings_scsi *scsi; 60765942Sgibbs struct ccb_trans_settings_spi *spi; 60865942Sgibbs struct ahc_initiator_tinfo *tinfo; 60974972Sgibbs struct ahc_tmode_tstate *tstate; 61065942Sgibbs uint16_t *discenable; 61165942Sgibbs uint16_t *tagenable; 61265942Sgibbs u_int update_type; 61365942Sgibbs 61465942Sgibbs cts = &ccb->cts; 61565942Sgibbs scsi = &cts->proto_specific.scsi; 61665942Sgibbs spi = &cts->xport_specific.spi; 61765942Sgibbs ahc_compile_devinfo(&devinfo, SIM_SCSI_ID(ahc, sim), 61865942Sgibbs cts->ccb_h.target_id, 61965942Sgibbs cts->ccb_h.target_lun, 62065942Sgibbs SIM_CHANNEL(ahc, sim), 62165942Sgibbs ROLE_UNKNOWN); 62265942Sgibbs tinfo = ahc_fetch_transinfo(ahc, devinfo.channel, 62365942Sgibbs devinfo.our_scsiid, 62465942Sgibbs devinfo.target, &tstate); 62565942Sgibbs update_type = 0; 62665942Sgibbs if (cts->type == CTS_TYPE_CURRENT_SETTINGS) { 62765942Sgibbs update_type |= AHC_TRANS_GOAL; 62865942Sgibbs discenable = &tstate->discenable; 62965942Sgibbs tagenable = &tstate->tagenable; 63076634Sgibbs tinfo->curr.protocol_version = 63165942Sgibbs cts->protocol_version; 63276634Sgibbs tinfo->curr.transport_version = 63365942Sgibbs cts->transport_version; 63465942Sgibbs tinfo->goal.protocol_version = 63565942Sgibbs cts->protocol_version; 63665942Sgibbs tinfo->goal.transport_version = 63765942Sgibbs cts->transport_version; 63865942Sgibbs } else if (cts->type == CTS_TYPE_USER_SETTINGS) { 63965942Sgibbs update_type |= AHC_TRANS_USER; 64065942Sgibbs discenable = &ahc->user_discenable; 64165942Sgibbs tagenable = &ahc->user_tagenable; 64265942Sgibbs tinfo->user.protocol_version = 64365942Sgibbs cts->protocol_version; 64465942Sgibbs tinfo->user.transport_version = 64565942Sgibbs cts->transport_version; 64665942Sgibbs } else { 64765942Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 64865942Sgibbs xpt_done(ccb); 64965942Sgibbs break; 65065942Sgibbs } 65165942Sgibbs 65265942Sgibbs ahc_lock(ahc, &s); 65365942Sgibbs 65465942Sgibbs if ((spi->valid & CTS_SPI_VALID_DISC) != 0) { 65565942Sgibbs if ((spi->flags & CTS_SPI_FLAGS_DISC_ENB) != 0) 65665942Sgibbs *discenable |= devinfo.target_mask; 65765942Sgibbs else 65865942Sgibbs *discenable &= ~devinfo.target_mask; 65965942Sgibbs } 66065942Sgibbs 66165942Sgibbs if ((scsi->valid & CTS_SCSI_VALID_TQ) != 0) { 66265942Sgibbs if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0) 66365942Sgibbs *tagenable |= devinfo.target_mask; 66465942Sgibbs else 66565942Sgibbs *tagenable &= ~devinfo.target_mask; 66665942Sgibbs } 66765942Sgibbs 66865942Sgibbs if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) { 66968087Sgibbs ahc_validate_width(ahc, /*tinfo limit*/NULL, 67068087Sgibbs &spi->bus_width, ROLE_UNKNOWN); 67165942Sgibbs ahc_set_width(ahc, &devinfo, spi->bus_width, 67265942Sgibbs update_type, /*paused*/FALSE); 67365942Sgibbs } 67465942Sgibbs 67565942Sgibbs if ((spi->valid & CTS_SPI_VALID_PPR_OPTIONS) == 0) { 67665942Sgibbs if (update_type == AHC_TRANS_USER) 67765942Sgibbs spi->ppr_options = tinfo->user.ppr_options; 67865942Sgibbs else 67965942Sgibbs spi->ppr_options = tinfo->goal.ppr_options; 68065942Sgibbs } 68165942Sgibbs 68265942Sgibbs if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) == 0) { 68365942Sgibbs if (update_type == AHC_TRANS_USER) 68465942Sgibbs spi->sync_offset = tinfo->user.offset; 68565942Sgibbs else 68665942Sgibbs spi->sync_offset = tinfo->goal.offset; 68765942Sgibbs } 68865942Sgibbs 68965942Sgibbs if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) == 0) { 69065942Sgibbs if (update_type == AHC_TRANS_USER) 69165942Sgibbs spi->sync_period = tinfo->user.period; 69265942Sgibbs else 69365942Sgibbs spi->sync_period = tinfo->goal.period; 69465942Sgibbs } 69565942Sgibbs 69665942Sgibbs if (((spi->valid & CTS_SPI_VALID_SYNC_RATE) != 0) 69765942Sgibbs || ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0)) { 69865942Sgibbs struct ahc_syncrate *syncrate; 69965942Sgibbs u_int maxsync; 70065942Sgibbs 70165942Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) 70265942Sgibbs maxsync = AHC_SYNCRATE_DT; 70365942Sgibbs else if ((ahc->features & AHC_ULTRA) != 0) 70465942Sgibbs maxsync = AHC_SYNCRATE_ULTRA; 70565942Sgibbs else 70665942Sgibbs maxsync = AHC_SYNCRATE_FAST; 70765942Sgibbs 70895378Sgibbs if (spi->bus_width != MSG_EXT_WDTR_BUS_16_BIT) 70995378Sgibbs spi->ppr_options &= ~MSG_EXT_PPR_DT_REQ; 71095378Sgibbs 71165942Sgibbs syncrate = ahc_find_syncrate(ahc, &spi->sync_period, 71265942Sgibbs &spi->ppr_options, 71365942Sgibbs maxsync); 71468087Sgibbs ahc_validate_offset(ahc, /*tinfo limit*/NULL, 71568087Sgibbs syncrate, &spi->sync_offset, 71668087Sgibbs spi->bus_width, ROLE_UNKNOWN); 71765942Sgibbs 71865942Sgibbs /* We use a period of 0 to represent async */ 71965942Sgibbs if (spi->sync_offset == 0) { 72065942Sgibbs spi->sync_period = 0; 72165942Sgibbs spi->ppr_options = 0; 72265942Sgibbs } 72365942Sgibbs 72465942Sgibbs ahc_set_syncrate(ahc, &devinfo, syncrate, 72565942Sgibbs spi->sync_period, spi->sync_offset, 72665942Sgibbs spi->ppr_options, update_type, 72765942Sgibbs /*paused*/FALSE); 72865942Sgibbs } 72965942Sgibbs ahc_unlock(ahc, &s); 73065942Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 73165942Sgibbs xpt_done(ccb); 73265942Sgibbs#else 73365942Sgibbs struct ahc_devinfo devinfo; 73465942Sgibbs struct ccb_trans_settings *cts; 73565942Sgibbs struct ahc_initiator_tinfo *tinfo; 73674972Sgibbs struct ahc_tmode_tstate *tstate; 73765942Sgibbs uint16_t *discenable; 73865942Sgibbs uint16_t *tagenable; 73965942Sgibbs u_int update_type; 74065942Sgibbs long s; 74165942Sgibbs 74265942Sgibbs cts = &ccb->cts; 74365942Sgibbs ahc_compile_devinfo(&devinfo, SIM_SCSI_ID(ahc, sim), 74465942Sgibbs cts->ccb_h.target_id, 74565942Sgibbs cts->ccb_h.target_lun, 74665942Sgibbs SIM_CHANNEL(ahc, sim), 74765942Sgibbs ROLE_UNKNOWN); 74865942Sgibbs tinfo = ahc_fetch_transinfo(ahc, devinfo.channel, 74965942Sgibbs devinfo.our_scsiid, 75065942Sgibbs devinfo.target, &tstate); 75165942Sgibbs update_type = 0; 75265942Sgibbs if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0) { 75365942Sgibbs update_type |= AHC_TRANS_GOAL; 75465942Sgibbs discenable = &tstate->discenable; 75565942Sgibbs tagenable = &tstate->tagenable; 75665942Sgibbs } else if ((cts->flags & CCB_TRANS_USER_SETTINGS) != 0) { 75765942Sgibbs update_type |= AHC_TRANS_USER; 75865942Sgibbs discenable = &ahc->user_discenable; 75965942Sgibbs tagenable = &ahc->user_tagenable; 76065942Sgibbs } else { 76165942Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 76265942Sgibbs xpt_done(ccb); 76365942Sgibbs break; 76465942Sgibbs } 76565942Sgibbs 76665942Sgibbs ahc_lock(ahc, &s); 76765942Sgibbs 76865942Sgibbs if ((cts->valid & CCB_TRANS_DISC_VALID) != 0) { 76965942Sgibbs if ((cts->flags & CCB_TRANS_DISC_ENB) != 0) 77065942Sgibbs *discenable |= devinfo.target_mask; 77165942Sgibbs else 77265942Sgibbs *discenable &= ~devinfo.target_mask; 77365942Sgibbs } 77465942Sgibbs 77565942Sgibbs if ((cts->valid & CCB_TRANS_TQ_VALID) != 0) { 77665942Sgibbs if ((cts->flags & CCB_TRANS_TAG_ENB) != 0) 77765942Sgibbs *tagenable |= devinfo.target_mask; 77865942Sgibbs else 77965942Sgibbs *tagenable &= ~devinfo.target_mask; 78065942Sgibbs } 78165942Sgibbs 78265942Sgibbs if ((cts->valid & CCB_TRANS_BUS_WIDTH_VALID) != 0) { 78368087Sgibbs ahc_validate_width(ahc, /*tinfo limit*/NULL, 78468087Sgibbs &cts->bus_width, ROLE_UNKNOWN); 78565942Sgibbs ahc_set_width(ahc, &devinfo, cts->bus_width, 78665942Sgibbs update_type, /*paused*/FALSE); 78765942Sgibbs } 78865942Sgibbs 78965942Sgibbs if ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) == 0) { 79065942Sgibbs if (update_type == AHC_TRANS_USER) 79165942Sgibbs cts->sync_offset = tinfo->user.offset; 79265942Sgibbs else 79365942Sgibbs cts->sync_offset = tinfo->goal.offset; 79465942Sgibbs } 79565942Sgibbs 79665942Sgibbs if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) == 0) { 79765942Sgibbs if (update_type == AHC_TRANS_USER) 79865942Sgibbs cts->sync_period = tinfo->user.period; 79965942Sgibbs else 80065942Sgibbs cts->sync_period = tinfo->goal.period; 80165942Sgibbs } 80265942Sgibbs 80365942Sgibbs if (((cts->valid & CCB_TRANS_SYNC_RATE_VALID) != 0) 80465942Sgibbs || ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0)) { 80565942Sgibbs struct ahc_syncrate *syncrate; 80665942Sgibbs u_int ppr_options; 80765942Sgibbs u_int maxsync; 80865942Sgibbs 80965942Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) 81065942Sgibbs maxsync = AHC_SYNCRATE_DT; 81165942Sgibbs else if ((ahc->features & AHC_ULTRA) != 0) 81265942Sgibbs maxsync = AHC_SYNCRATE_ULTRA; 81365942Sgibbs else 81465942Sgibbs maxsync = AHC_SYNCRATE_FAST; 81565942Sgibbs 81665942Sgibbs ppr_options = 0; 81795378Sgibbs if (cts->sync_period <= 9 81895378Sgibbs && cts->bus_width == MSG_EXT_WDTR_BUS_16_BIT) 81965942Sgibbs ppr_options = MSG_EXT_PPR_DT_REQ; 82065942Sgibbs 82165942Sgibbs syncrate = ahc_find_syncrate(ahc, &cts->sync_period, 82265942Sgibbs &ppr_options, 82365942Sgibbs maxsync); 82468087Sgibbs ahc_validate_offset(ahc, /*tinfo limit*/NULL, 82568087Sgibbs syncrate, &cts->sync_offset, 82668087Sgibbs MSG_EXT_WDTR_BUS_8_BIT, 82768087Sgibbs ROLE_UNKNOWN); 82865942Sgibbs 82965942Sgibbs /* We use a period of 0 to represent async */ 83065942Sgibbs if (cts->sync_offset == 0) { 83165942Sgibbs cts->sync_period = 0; 83265942Sgibbs ppr_options = 0; 83365942Sgibbs } 83465942Sgibbs 83565942Sgibbs if (ppr_options == MSG_EXT_PPR_DT_REQ 83665942Sgibbs && tinfo->user.transport_version >= 3) { 83765942Sgibbs tinfo->goal.transport_version = 83865942Sgibbs tinfo->user.transport_version; 83976634Sgibbs tinfo->curr.transport_version = 84065942Sgibbs tinfo->user.transport_version; 84165942Sgibbs } 84265942Sgibbs 84365942Sgibbs ahc_set_syncrate(ahc, &devinfo, syncrate, 84465942Sgibbs cts->sync_period, cts->sync_offset, 84565942Sgibbs ppr_options, update_type, 84665942Sgibbs /*paused*/FALSE); 84765942Sgibbs } 84865942Sgibbs ahc_unlock(ahc, &s); 84965942Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 85065942Sgibbs xpt_done(ccb); 85165942Sgibbs#endif 85265942Sgibbs break; 85365942Sgibbs } 85465942Sgibbs case XPT_GET_TRAN_SETTINGS: 85565942Sgibbs /* Get default/user set transfer settings for the target */ 85665942Sgibbs { 85765942Sgibbs 85865942Sgibbs ahc_lock(ahc, &s); 85965942Sgibbs ahc_get_tran_settings(ahc, SIM_SCSI_ID(ahc, sim), 86065942Sgibbs SIM_CHANNEL(ahc, sim), &ccb->cts); 86165942Sgibbs ahc_unlock(ahc, &s); 86265942Sgibbs xpt_done(ccb); 86365942Sgibbs break; 86465942Sgibbs } 86565942Sgibbs case XPT_CALC_GEOMETRY: 86665942Sgibbs { 867123579Sgibbs int extended; 86865942Sgibbs 86965942Sgibbs extended = SIM_IS_SCSIBUS_B(ahc, sim) 870123579Sgibbs ? ahc->flags & AHC_EXTENDED_TRANS_B 871123579Sgibbs : ahc->flags & AHC_EXTENDED_TRANS_A; 872123579Sgibbs aic_calc_geometry(&ccb->ccg, extended); 87365942Sgibbs xpt_done(ccb); 87465942Sgibbs break; 87565942Sgibbs } 87665942Sgibbs case XPT_RESET_BUS: /* Reset the specified SCSI bus */ 87765942Sgibbs { 87865942Sgibbs int found; 87965942Sgibbs 88065942Sgibbs ahc_lock(ahc, &s); 88165942Sgibbs found = ahc_reset_channel(ahc, SIM_CHANNEL(ahc, sim), 88265942Sgibbs /*initiate reset*/TRUE); 88365942Sgibbs ahc_unlock(ahc, &s); 88465942Sgibbs if (bootverbose) { 88565942Sgibbs xpt_print_path(SIM_PATH(ahc, sim)); 88665942Sgibbs printf("SCSI bus reset delivered. " 88765942Sgibbs "%d SCBs aborted.\n", found); 88865942Sgibbs } 88965942Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 89065942Sgibbs xpt_done(ccb); 89165942Sgibbs break; 89265942Sgibbs } 89365942Sgibbs case XPT_TERM_IO: /* Terminate the I/O process */ 89465942Sgibbs /* XXX Implement */ 89565942Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 89665942Sgibbs xpt_done(ccb); 89765942Sgibbs break; 89865942Sgibbs case XPT_PATH_INQ: /* Path routing inquiry */ 89965942Sgibbs { 90065942Sgibbs struct ccb_pathinq *cpi = &ccb->cpi; 90165942Sgibbs 90265942Sgibbs cpi->version_num = 1; /* XXX??? */ 90365942Sgibbs cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE; 90465942Sgibbs if ((ahc->features & AHC_WIDE) != 0) 90565942Sgibbs cpi->hba_inquiry |= PI_WIDE_16; 90668087Sgibbs if ((ahc->features & AHC_TARGETMODE) != 0) { 90765942Sgibbs cpi->target_sprt = PIT_PROCESSOR 90865942Sgibbs | PIT_DISCONNECT 90965942Sgibbs | PIT_TERM_IO; 91065942Sgibbs } else { 91165942Sgibbs cpi->target_sprt = 0; 91265942Sgibbs } 91368087Sgibbs cpi->hba_misc = 0; 91465942Sgibbs cpi->hba_eng_cnt = 0; 91565942Sgibbs cpi->max_target = (ahc->features & AHC_WIDE) ? 15 : 7; 91670204Sgibbs cpi->max_lun = AHC_NUM_LUNS - 1; 91765942Sgibbs if (SIM_IS_SCSIBUS_B(ahc, sim)) { 91865942Sgibbs cpi->initiator_id = ahc->our_id_b; 91965942Sgibbs if ((ahc->flags & AHC_RESET_BUS_B) == 0) 92065942Sgibbs cpi->hba_misc |= PIM_NOBUSRESET; 92165942Sgibbs } else { 92265942Sgibbs cpi->initiator_id = ahc->our_id; 92365942Sgibbs if ((ahc->flags & AHC_RESET_BUS_A) == 0) 92465942Sgibbs cpi->hba_misc |= PIM_NOBUSRESET; 92565942Sgibbs } 92665942Sgibbs cpi->bus_id = cam_sim_bus(sim); 92765942Sgibbs cpi->base_transfer_speed = 3300; 92865942Sgibbs strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 92965942Sgibbs strncpy(cpi->hba_vid, "Adaptec", HBA_IDLEN); 93065942Sgibbs strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 93165942Sgibbs cpi->unit_number = cam_sim_unit(sim); 93265942Sgibbs#ifdef AHC_NEW_TRAN_SETTINGS 93365942Sgibbs cpi->protocol = PROTO_SCSI; 93465942Sgibbs cpi->protocol_version = SCSI_REV_2; 93565942Sgibbs cpi->transport = XPORT_SPI; 93665942Sgibbs cpi->transport_version = 2; 93765942Sgibbs cpi->xport_specific.spi.ppr_options = SID_SPI_CLOCK_ST; 93865942Sgibbs if ((ahc->features & AHC_DT) != 0) { 93965942Sgibbs cpi->transport_version = 3; 94065942Sgibbs cpi->xport_specific.spi.ppr_options = 94165942Sgibbs SID_SPI_CLOCK_DT_ST; 94265942Sgibbs } 94365942Sgibbs#endif 94465942Sgibbs cpi->ccb_h.status = CAM_REQ_CMP; 94565942Sgibbs xpt_done(ccb); 94665942Sgibbs break; 94765942Sgibbs } 94865942Sgibbs default: 94968087Sgibbs ccb->ccb_h.status = CAM_PROVIDE_FAIL; 95065942Sgibbs xpt_done(ccb); 95165942Sgibbs break; 95265942Sgibbs } 95365942Sgibbs} 95465942Sgibbs 95565942Sgibbsstatic void 95665942Sgibbsahc_get_tran_settings(struct ahc_softc *ahc, int our_id, char channel, 95765942Sgibbs struct ccb_trans_settings *cts) 95865942Sgibbs{ 95965942Sgibbs#ifdef AHC_NEW_TRAN_SETTINGS 96065942Sgibbs struct ahc_devinfo devinfo; 96165942Sgibbs struct ccb_trans_settings_scsi *scsi; 96265942Sgibbs struct ccb_trans_settings_spi *spi; 96365942Sgibbs struct ahc_initiator_tinfo *targ_info; 96474972Sgibbs struct ahc_tmode_tstate *tstate; 96565942Sgibbs struct ahc_transinfo *tinfo; 96665942Sgibbs 96765942Sgibbs scsi = &cts->proto_specific.scsi; 96865942Sgibbs spi = &cts->xport_specific.spi; 96965942Sgibbs ahc_compile_devinfo(&devinfo, our_id, 97065942Sgibbs cts->ccb_h.target_id, 97165942Sgibbs cts->ccb_h.target_lun, 97265942Sgibbs channel, ROLE_UNKNOWN); 97365942Sgibbs targ_info = ahc_fetch_transinfo(ahc, devinfo.channel, 97465942Sgibbs devinfo.our_scsiid, 97565942Sgibbs devinfo.target, &tstate); 97665942Sgibbs 97765942Sgibbs if (cts->type == CTS_TYPE_CURRENT_SETTINGS) 97876634Sgibbs tinfo = &targ_info->curr; 97965942Sgibbs else 98065942Sgibbs tinfo = &targ_info->user; 98165942Sgibbs 98265942Sgibbs scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 98365942Sgibbs spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB; 98465942Sgibbs if (cts->type == CTS_TYPE_USER_SETTINGS) { 98565942Sgibbs if ((ahc->user_discenable & devinfo.target_mask) != 0) 98665942Sgibbs spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 98765942Sgibbs 98865942Sgibbs if ((ahc->user_tagenable & devinfo.target_mask) != 0) 98965942Sgibbs scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; 99065942Sgibbs } else { 99165942Sgibbs if ((tstate->discenable & devinfo.target_mask) != 0) 99265942Sgibbs spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 99365942Sgibbs 99465942Sgibbs if ((tstate->tagenable & devinfo.target_mask) != 0) 99565942Sgibbs scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; 99665942Sgibbs } 99765942Sgibbs cts->protocol_version = tinfo->protocol_version; 99865942Sgibbs cts->transport_version = tinfo->transport_version; 99965942Sgibbs 100065942Sgibbs spi->sync_period = tinfo->period; 100165942Sgibbs spi->sync_offset = tinfo->offset; 100265942Sgibbs spi->bus_width = tinfo->width; 100365942Sgibbs spi->ppr_options = tinfo->ppr_options; 100465942Sgibbs 100565942Sgibbs cts->protocol = PROTO_SCSI; 100665942Sgibbs cts->transport = XPORT_SPI; 100765942Sgibbs spi->valid = CTS_SPI_VALID_SYNC_RATE 100865942Sgibbs | CTS_SPI_VALID_SYNC_OFFSET 100965942Sgibbs | CTS_SPI_VALID_BUS_WIDTH 101065942Sgibbs | CTS_SPI_VALID_PPR_OPTIONS; 101165942Sgibbs 101266717Sgibbs if (cts->ccb_h.target_lun != CAM_LUN_WILDCARD) { 101366717Sgibbs scsi->valid = CTS_SCSI_VALID_TQ; 101466717Sgibbs spi->valid |= CTS_SPI_VALID_DISC; 101566717Sgibbs } else { 101666717Sgibbs scsi->valid = 0; 101766717Sgibbs } 101866717Sgibbs 101965942Sgibbs cts->ccb_h.status = CAM_REQ_CMP; 102065942Sgibbs#else 102165942Sgibbs struct ahc_devinfo devinfo; 102265942Sgibbs struct ahc_initiator_tinfo *targ_info; 102374972Sgibbs struct ahc_tmode_tstate *tstate; 102465942Sgibbs struct ahc_transinfo *tinfo; 102565942Sgibbs 102665942Sgibbs ahc_compile_devinfo(&devinfo, our_id, 102765942Sgibbs cts->ccb_h.target_id, 102865942Sgibbs cts->ccb_h.target_lun, 102965942Sgibbs channel, ROLE_UNKNOWN); 103065942Sgibbs targ_info = ahc_fetch_transinfo(ahc, devinfo.channel, 103165942Sgibbs devinfo.our_scsiid, 103265942Sgibbs devinfo.target, &tstate); 103365942Sgibbs 103465942Sgibbs if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0) 103576634Sgibbs tinfo = &targ_info->curr; 103665942Sgibbs else 103765942Sgibbs tinfo = &targ_info->user; 103865942Sgibbs 103965942Sgibbs cts->flags &= ~(CCB_TRANS_DISC_ENB|CCB_TRANS_TAG_ENB); 104066760Sgibbs if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) == 0) { 104165942Sgibbs if ((ahc->user_discenable & devinfo.target_mask) != 0) 104265942Sgibbs cts->flags |= CCB_TRANS_DISC_ENB; 104365942Sgibbs 104465942Sgibbs if ((ahc->user_tagenable & devinfo.target_mask) != 0) 104565942Sgibbs cts->flags |= CCB_TRANS_TAG_ENB; 104665942Sgibbs } else { 104765942Sgibbs if ((tstate->discenable & devinfo.target_mask) != 0) 104865942Sgibbs cts->flags |= CCB_TRANS_DISC_ENB; 104965942Sgibbs 105065942Sgibbs if ((tstate->tagenable & devinfo.target_mask) != 0) 105165942Sgibbs cts->flags |= CCB_TRANS_TAG_ENB; 105265942Sgibbs } 105365942Sgibbs cts->sync_period = tinfo->period; 105465942Sgibbs cts->sync_offset = tinfo->offset; 105565942Sgibbs cts->bus_width = tinfo->width; 105665942Sgibbs 105765942Sgibbs cts->valid = CCB_TRANS_SYNC_RATE_VALID 105865942Sgibbs | CCB_TRANS_SYNC_OFFSET_VALID 105966717Sgibbs | CCB_TRANS_BUS_WIDTH_VALID; 106065942Sgibbs 106166717Sgibbs if (cts->ccb_h.target_lun != CAM_LUN_WILDCARD) 106266717Sgibbs cts->valid |= CCB_TRANS_DISC_VALID|CCB_TRANS_TQ_VALID; 106366717Sgibbs 106465942Sgibbs cts->ccb_h.status = CAM_REQ_CMP; 106565942Sgibbs#endif 106665942Sgibbs} 106765942Sgibbs 106865942Sgibbsstatic void 106965942Sgibbsahc_async(void *callback_arg, uint32_t code, struct cam_path *path, void *arg) 107065942Sgibbs{ 107165942Sgibbs struct ahc_softc *ahc; 107265942Sgibbs struct cam_sim *sim; 107365942Sgibbs 107465942Sgibbs sim = (struct cam_sim *)callback_arg; 107565942Sgibbs ahc = (struct ahc_softc *)cam_sim_softc(sim); 107665942Sgibbs switch (code) { 107765942Sgibbs case AC_LOST_DEVICE: 107865942Sgibbs { 107965942Sgibbs struct ahc_devinfo devinfo; 108065942Sgibbs long s; 108165942Sgibbs 108265942Sgibbs ahc_compile_devinfo(&devinfo, SIM_SCSI_ID(ahc, sim), 108365942Sgibbs xpt_path_target_id(path), 108465942Sgibbs xpt_path_lun_id(path), 108565942Sgibbs SIM_CHANNEL(ahc, sim), 108665942Sgibbs ROLE_UNKNOWN); 108765942Sgibbs 108865942Sgibbs /* 108965942Sgibbs * Revert to async/narrow transfers 109065942Sgibbs * for the next device. 109165942Sgibbs */ 109265942Sgibbs ahc_lock(ahc, &s); 109365942Sgibbs ahc_set_width(ahc, &devinfo, MSG_EXT_WDTR_BUS_8_BIT, 109465942Sgibbs AHC_TRANS_GOAL|AHC_TRANS_CUR, /*paused*/FALSE); 109565942Sgibbs ahc_set_syncrate(ahc, &devinfo, /*syncrate*/NULL, 109665942Sgibbs /*period*/0, /*offset*/0, /*ppr_options*/0, 109765942Sgibbs AHC_TRANS_GOAL|AHC_TRANS_CUR, 109865942Sgibbs /*paused*/FALSE); 109965942Sgibbs ahc_unlock(ahc, &s); 110065942Sgibbs break; 110165942Sgibbs } 110265942Sgibbs default: 110365942Sgibbs break; 110465942Sgibbs } 110565942Sgibbs} 110665942Sgibbs 110765942Sgibbsstatic void 110865942Sgibbsahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments, 110965942Sgibbs int error) 111065942Sgibbs{ 111166717Sgibbs struct scb *scb; 111266717Sgibbs union ccb *ccb; 111366717Sgibbs struct ahc_softc *ahc; 111466717Sgibbs struct ahc_initiator_tinfo *tinfo; 111574972Sgibbs struct ahc_tmode_tstate *tstate; 111666717Sgibbs u_int mask; 111766717Sgibbs long s; 111865942Sgibbs 111965942Sgibbs scb = (struct scb *)arg; 112065942Sgibbs ccb = scb->io_ctx; 112166986Sgibbs ahc = scb->ahc_softc; 112265942Sgibbs 112365942Sgibbs if (error != 0) { 112465942Sgibbs if (error == EFBIG) 1125123579Sgibbs aic_set_transaction_status(scb, CAM_REQ_TOO_BIG); 112665942Sgibbs else 1127123579Sgibbs aic_set_transaction_status(scb, CAM_REQ_CMP_ERR); 112865942Sgibbs if (nsegments != 0) 112965942Sgibbs bus_dmamap_unload(ahc->buffer_dmat, scb->dmamap); 113066647Sgibbs ahc_lock(ahc, &s); 113165942Sgibbs ahc_free_scb(ahc, scb); 113266647Sgibbs ahc_unlock(ahc, &s); 113365942Sgibbs xpt_done(ccb); 113465942Sgibbs return; 113565942Sgibbs } 113665942Sgibbs if (nsegments != 0) { 113765942Sgibbs struct ahc_dma_seg *sg; 113865942Sgibbs bus_dma_segment_t *end_seg; 1139115343Sscottl bus_dmasync_op_t op; 114065942Sgibbs 114165942Sgibbs end_seg = dm_segs + nsegments; 114265942Sgibbs 114365942Sgibbs /* Copy the segments into our SG list */ 114465942Sgibbs sg = scb->sg_list; 114565942Sgibbs while (dm_segs < end_seg) { 114679874Sgibbs uint32_t len; 114779874Sgibbs 1148123579Sgibbs sg->addr = aic_htole32(dm_segs->ds_addr); 114979874Sgibbs len = dm_segs->ds_len 115079874Sgibbs | ((dm_segs->ds_addr >> 8) & 0x7F000000); 1151123579Sgibbs sg->len = aic_htole32(len); 115265942Sgibbs sg++; 115365942Sgibbs dm_segs++; 115465942Sgibbs } 115565942Sgibbs 115665942Sgibbs /* 115765942Sgibbs * Note where to find the SG entries in bus space. 115865942Sgibbs * We also set the full residual flag which the 115965942Sgibbs * sequencer will clear as soon as a data transfer 116065942Sgibbs * occurs. 116165942Sgibbs */ 1162123579Sgibbs scb->hscb->sgptr = aic_htole32(scb->sg_list_phys|SG_FULL_RESID); 116365942Sgibbs 116465942Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) 116565942Sgibbs op = BUS_DMASYNC_PREREAD; 116665942Sgibbs else 116765942Sgibbs op = BUS_DMASYNC_PREWRITE; 116865942Sgibbs 116965942Sgibbs bus_dmamap_sync(ahc->buffer_dmat, scb->dmamap, op); 117065942Sgibbs 117165942Sgibbs if (ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) { 117265942Sgibbs struct target_data *tdata; 117365942Sgibbs 117465942Sgibbs tdata = &scb->hscb->shared_data.tdata; 117565942Sgibbs tdata->target_phases |= DPHASE_PENDING; 1176123579Sgibbs /* 1177123579Sgibbs * CAM data direction is relative to the initiator. 1178123579Sgibbs */ 117965942Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) 118065942Sgibbs tdata->data_phase = P_DATAOUT; 118165942Sgibbs else 118265942Sgibbs tdata->data_phase = P_DATAIN; 118365942Sgibbs 118465942Sgibbs /* 118565942Sgibbs * If the transfer is of an odd length and in the 118665942Sgibbs * "in" direction (scsi->HostBus), then it may 118765942Sgibbs * trigger a bug in the 'WideODD' feature of 118865942Sgibbs * non-Ultra2 chips. Force the total data-length 118965942Sgibbs * to be even by adding an extra, 1 byte, SG, 119065942Sgibbs * element. We do this even if we are not currently 119165942Sgibbs * negotiated wide as negotiation could occur before 119265942Sgibbs * this command is executed. 119365942Sgibbs */ 119465942Sgibbs if ((ahc->bugs & AHC_TMODE_WIDEODD_BUG) != 0 119565942Sgibbs && (ccb->csio.dxfer_len & 0x1) != 0 1196123579Sgibbs && (ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) { 119765942Sgibbs 119865942Sgibbs nsegments++; 119965942Sgibbs if (nsegments > AHC_NSEG) { 120065942Sgibbs 1201123579Sgibbs aic_set_transaction_status(scb, 120265942Sgibbs CAM_REQ_TOO_BIG); 120365942Sgibbs bus_dmamap_unload(ahc->buffer_dmat, 120465942Sgibbs scb->dmamap); 120566647Sgibbs ahc_lock(ahc, &s); 120665942Sgibbs ahc_free_scb(ahc, scb); 120766647Sgibbs ahc_unlock(ahc, &s); 120865942Sgibbs xpt_done(ccb); 120965942Sgibbs return; 121065942Sgibbs } 1211123579Sgibbs sg->addr = aic_htole32(ahc->dma_bug_buf); 1212123579Sgibbs sg->len = aic_htole32(1); 121365942Sgibbs sg++; 121465942Sgibbs } 121565942Sgibbs } 121665942Sgibbs sg--; 1217123579Sgibbs sg->len |= aic_htole32(AHC_DMA_LAST_SEG); 121865942Sgibbs 121965942Sgibbs /* Copy the first SG into the "current" data pointer area */ 122065942Sgibbs scb->hscb->dataptr = scb->sg_list->addr; 122165942Sgibbs scb->hscb->datacnt = scb->sg_list->len; 122265942Sgibbs } else { 1223123579Sgibbs scb->hscb->sgptr = aic_htole32(SG_LIST_NULL); 122465942Sgibbs scb->hscb->dataptr = 0; 122565942Sgibbs scb->hscb->datacnt = 0; 122665942Sgibbs } 122765942Sgibbs 122865942Sgibbs scb->sg_count = nsegments; 122965942Sgibbs 123065942Sgibbs ahc_lock(ahc, &s); 123165942Sgibbs 123265942Sgibbs /* 123365942Sgibbs * Last time we need to check if this SCB needs to 123465942Sgibbs * be aborted. 123565942Sgibbs */ 1236123579Sgibbs if (aic_get_transaction_status(scb) != CAM_REQ_INPROG) { 123765942Sgibbs if (nsegments != 0) 123895378Sgibbs bus_dmamap_unload(ahc->buffer_dmat, scb->dmamap); 123965942Sgibbs ahc_free_scb(ahc, scb); 124066647Sgibbs ahc_unlock(ahc, &s); 124165942Sgibbs xpt_done(ccb); 124265942Sgibbs return; 124365942Sgibbs } 124465942Sgibbs 124566717Sgibbs tinfo = ahc_fetch_transinfo(ahc, SCSIID_CHANNEL(ahc, scb->hscb->scsiid), 124666717Sgibbs SCSIID_OUR_ID(scb->hscb->scsiid), 124768087Sgibbs SCSIID_TARGET(ahc, scb->hscb->scsiid), 124868087Sgibbs &tstate); 124966717Sgibbs 125066717Sgibbs mask = SCB_GET_TARGET_MASK(ahc, scb); 125166717Sgibbs scb->hscb->scsirate = tinfo->scsirate; 125276634Sgibbs scb->hscb->scsioffset = tinfo->curr.offset; 125366717Sgibbs if ((tstate->ultraenb & mask) != 0) 125466717Sgibbs scb->hscb->control |= ULTRAENB; 125574972Sgibbs 125666717Sgibbs if ((tstate->discenable & mask) != 0 125766717Sgibbs && (ccb->ccb_h.flags & CAM_DIS_DISCONNECT) == 0) 125866717Sgibbs scb->hscb->control |= DISCENB; 125966717Sgibbs 126066717Sgibbs if ((ccb->ccb_h.flags & CAM_NEGOTIATE) != 0 126170204Sgibbs && (tinfo->goal.width != 0 1262102674Sgibbs || tinfo->goal.offset != 0 126370204Sgibbs || tinfo->goal.ppr_options != 0)) { 126466717Sgibbs scb->flags |= SCB_NEGOTIATE; 126566717Sgibbs scb->hscb->control |= MK_MESSAGE; 126674972Sgibbs } else if ((tstate->auto_negotiate & mask) != 0) { 126774972Sgibbs scb->flags |= SCB_AUTO_NEGOTIATE; 126874972Sgibbs scb->hscb->control |= MK_MESSAGE; 126966717Sgibbs } 127066717Sgibbs 127165942Sgibbs LIST_INSERT_HEAD(&ahc->pending_scbs, scb, pending_links); 127265942Sgibbs 127365942Sgibbs ccb->ccb_h.status |= CAM_SIM_QUEUED; 127465942Sgibbs 127565942Sgibbs /* 127665942Sgibbs * We only allow one untagged transaction 127765942Sgibbs * per target in the initiator role unless 127865942Sgibbs * we are storing a full busy target *lun* 127965942Sgibbs * table in SCB space. 128065942Sgibbs */ 128165942Sgibbs if ((scb->hscb->control & (TARGET_SCB|TAG_ENB)) == 0 128271390Sgibbs && (ahc->flags & AHC_SCB_BTT) == 0) { 128365942Sgibbs struct scb_tailq *untagged_q; 128472811Sgibbs int target_offset; 128565942Sgibbs 128672811Sgibbs target_offset = SCB_GET_TARGET_OFFSET(ahc, scb); 128772811Sgibbs untagged_q = &(ahc->untagged_queues[target_offset]); 128865942Sgibbs TAILQ_INSERT_TAIL(untagged_q, scb, links.tqe); 128966986Sgibbs scb->flags |= SCB_UNTAGGEDQ; 129065942Sgibbs if (TAILQ_FIRST(untagged_q) != scb) { 129165942Sgibbs ahc_unlock(ahc, &s); 129265942Sgibbs return; 129365942Sgibbs } 129465942Sgibbs } 129565942Sgibbs scb->flags |= SCB_ACTIVE; 129665942Sgibbs 1297133911Sgibbs /* 1298133911Sgibbs * Timers are disabled while recovery is in progress. 1299133911Sgibbs */ 1300133911Sgibbs aic_scb_timer_start(scb); 1301133911Sgibbs 130265942Sgibbs if ((scb->flags & SCB_TARGET_IMMEDIATE) != 0) { 130374972Sgibbs /* Define a mapping from our tag to the SCB. */ 130474972Sgibbs ahc->scb_data->scbindex[scb->hscb->tag] = scb; 130574094Sgibbs ahc_pause(ahc); 130665942Sgibbs if ((ahc->flags & AHC_PAGESCBS) == 0) 130765942Sgibbs ahc_outb(ahc, SCBPTR, scb->hscb->tag); 1308102674Sgibbs ahc_outb(ahc, TARG_IMMEDIATE_SCB, scb->hscb->tag); 130974094Sgibbs ahc_unpause(ahc); 131065942Sgibbs } else { 131165942Sgibbs ahc_queue_scb(ahc, scb); 131265942Sgibbs } 131365942Sgibbs 131465942Sgibbs ahc_unlock(ahc, &s); 131565942Sgibbs} 131665942Sgibbs 131765942Sgibbsstatic void 131865942Sgibbsahc_poll(struct cam_sim *sim) 131965942Sgibbs{ 1320102674Sgibbs struct ahc_softc *ahc; 1321102674Sgibbs 1322102674Sgibbs ahc = (struct ahc_softc *)cam_sim_softc(sim); 1323102674Sgibbs ahc_intr(ahc); 132465942Sgibbs} 132565942Sgibbs 132665942Sgibbsstatic void 132765942Sgibbsahc_setup_data(struct ahc_softc *ahc, struct cam_sim *sim, 132865942Sgibbs struct ccb_scsiio *csio, struct scb *scb) 132965942Sgibbs{ 133065942Sgibbs struct hardware_scb *hscb; 133165942Sgibbs struct ccb_hdr *ccb_h; 133265942Sgibbs 133365942Sgibbs hscb = scb->hscb; 133465942Sgibbs ccb_h = &csio->ccb_h; 133565942Sgibbs 133679874Sgibbs csio->resid = 0; 133779874Sgibbs csio->sense_resid = 0; 133865942Sgibbs if (ccb_h->func_code == XPT_SCSI_IO) { 133965942Sgibbs hscb->cdb_len = csio->cdb_len; 134065942Sgibbs if ((ccb_h->flags & CAM_CDB_POINTER) != 0) { 134165942Sgibbs 134265942Sgibbs if (hscb->cdb_len > sizeof(hscb->cdb32) 134365942Sgibbs || (ccb_h->flags & CAM_CDB_PHYS) != 0) { 134466647Sgibbs u_long s; 134566647Sgibbs 1346123579Sgibbs aic_set_transaction_status(scb, 134765942Sgibbs CAM_REQ_INVALID); 134866647Sgibbs ahc_lock(ahc, &s); 134965942Sgibbs ahc_free_scb(ahc, scb); 135066647Sgibbs ahc_unlock(ahc, &s); 135166647Sgibbs xpt_done((union ccb *)csio); 135265942Sgibbs return; 135365942Sgibbs } 135465942Sgibbs if (hscb->cdb_len > 12) { 135565942Sgibbs memcpy(hscb->cdb32, 135665942Sgibbs csio->cdb_io.cdb_ptr, 135765942Sgibbs hscb->cdb_len); 135868087Sgibbs scb->flags |= SCB_CDB32_PTR; 135965942Sgibbs } else { 136065942Sgibbs memcpy(hscb->shared_data.cdb, 136165942Sgibbs csio->cdb_io.cdb_ptr, 136265942Sgibbs hscb->cdb_len); 136365942Sgibbs } 136465942Sgibbs } else { 136565942Sgibbs if (hscb->cdb_len > 12) { 136665942Sgibbs memcpy(hscb->cdb32, csio->cdb_io.cdb_bytes, 136765942Sgibbs hscb->cdb_len); 136868087Sgibbs scb->flags |= SCB_CDB32_PTR; 136965942Sgibbs } else { 137065942Sgibbs memcpy(hscb->shared_data.cdb, 137165942Sgibbs csio->cdb_io.cdb_bytes, 137265942Sgibbs hscb->cdb_len); 137365942Sgibbs } 137465942Sgibbs } 137565942Sgibbs } 137665942Sgibbs 137765942Sgibbs /* Only use S/G if there is a transfer */ 137865942Sgibbs if ((ccb_h->flags & CAM_DIR_MASK) != CAM_DIR_NONE) { 137965942Sgibbs if ((ccb_h->flags & CAM_SCATTER_VALID) == 0) { 138065942Sgibbs /* We've been given a pointer to a single buffer */ 138165942Sgibbs if ((ccb_h->flags & CAM_DATA_PHYS) == 0) { 138265942Sgibbs int s; 138365942Sgibbs int error; 138465942Sgibbs 138565942Sgibbs s = splsoftvm(); 138665942Sgibbs error = bus_dmamap_load(ahc->buffer_dmat, 138765942Sgibbs scb->dmamap, 138865942Sgibbs csio->data_ptr, 138965942Sgibbs csio->dxfer_len, 139065942Sgibbs ahc_execute_scb, 139165942Sgibbs scb, /*flags*/0); 139265942Sgibbs if (error == EINPROGRESS) { 139365942Sgibbs /* 139465942Sgibbs * So as to maintain ordering, 139565942Sgibbs * freeze the controller queue 139665942Sgibbs * until our mapping is 139765942Sgibbs * returned. 139865942Sgibbs */ 139965942Sgibbs xpt_freeze_simq(sim, 140065942Sgibbs /*count*/1); 140165942Sgibbs scb->io_ctx->ccb_h.status |= 140265942Sgibbs CAM_RELEASE_SIMQ; 140365942Sgibbs } 140465942Sgibbs splx(s); 140565942Sgibbs } else { 140665942Sgibbs struct bus_dma_segment seg; 140765942Sgibbs 140865942Sgibbs /* Pointer to physical buffer */ 140965942Sgibbs if (csio->dxfer_len > AHC_MAXTRANSFER_SIZE) 141065942Sgibbs panic("ahc_setup_data - Transfer size " 141165942Sgibbs "larger than can device max"); 141265942Sgibbs 1413112842Sjake seg.ds_addr = 1414112842Sjake (bus_addr_t)(vm_offset_t)csio->data_ptr; 141565942Sgibbs seg.ds_len = csio->dxfer_len; 141665942Sgibbs ahc_execute_scb(scb, &seg, 1, 0); 141765942Sgibbs } 141865942Sgibbs } else { 141965942Sgibbs struct bus_dma_segment *segs; 142065942Sgibbs 142165942Sgibbs if ((ccb_h->flags & CAM_DATA_PHYS) != 0) 142265942Sgibbs panic("ahc_setup_data - Physical segment " 142365942Sgibbs "pointers unsupported"); 142465942Sgibbs 142565942Sgibbs if ((ccb_h->flags & CAM_SG_LIST_PHYS) == 0) 142665942Sgibbs panic("ahc_setup_data - Virtual segment " 142765942Sgibbs "addresses unsupported"); 142865942Sgibbs 142965942Sgibbs /* Just use the segments provided */ 143065942Sgibbs segs = (struct bus_dma_segment *)csio->data_ptr; 143165942Sgibbs ahc_execute_scb(scb, segs, csio->sglist_cnt, 0); 143265942Sgibbs } 143365942Sgibbs } else { 143465942Sgibbs ahc_execute_scb(scb, NULL, 0, 0); 143565942Sgibbs } 143665942Sgibbs} 143765942Sgibbs 143865942Sgibbsstatic void 143965942Sgibbsahc_abort_ccb(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb) 144065942Sgibbs{ 144165942Sgibbs union ccb *abort_ccb; 144265942Sgibbs 144365942Sgibbs abort_ccb = ccb->cab.abort_ccb; 144465942Sgibbs switch (abort_ccb->ccb_h.func_code) { 144565942Sgibbs case XPT_ACCEPT_TARGET_IO: 144665942Sgibbs case XPT_IMMED_NOTIFY: 144765942Sgibbs case XPT_CONT_TARGET_IO: 144865942Sgibbs { 144974972Sgibbs struct ahc_tmode_tstate *tstate; 145074972Sgibbs struct ahc_tmode_lstate *lstate; 145165942Sgibbs struct ccb_hdr_slist *list; 145265942Sgibbs cam_status status; 145365942Sgibbs 145465942Sgibbs status = ahc_find_tmode_devs(ahc, sim, abort_ccb, &tstate, 145565942Sgibbs &lstate, TRUE); 145665942Sgibbs 145765942Sgibbs if (status != CAM_REQ_CMP) { 145865942Sgibbs ccb->ccb_h.status = status; 145965942Sgibbs break; 146065942Sgibbs } 146165942Sgibbs 146265942Sgibbs if (abort_ccb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) 146365942Sgibbs list = &lstate->accept_tios; 146465942Sgibbs else if (abort_ccb->ccb_h.func_code == XPT_IMMED_NOTIFY) 146565942Sgibbs list = &lstate->immed_notifies; 146665942Sgibbs else 146765942Sgibbs list = NULL; 146865942Sgibbs 146965942Sgibbs if (list != NULL) { 147065942Sgibbs struct ccb_hdr *curelm; 147165942Sgibbs int found; 147265942Sgibbs 147365942Sgibbs curelm = SLIST_FIRST(list); 147465942Sgibbs found = 0; 147565942Sgibbs if (curelm == &abort_ccb->ccb_h) { 147665942Sgibbs found = 1; 147765942Sgibbs SLIST_REMOVE_HEAD(list, sim_links.sle); 147865942Sgibbs } else { 147965942Sgibbs while(curelm != NULL) { 148065942Sgibbs struct ccb_hdr *nextelm; 148165942Sgibbs 148265942Sgibbs nextelm = 148365942Sgibbs SLIST_NEXT(curelm, sim_links.sle); 148465942Sgibbs 148565942Sgibbs if (nextelm == &abort_ccb->ccb_h) { 148665942Sgibbs found = 1; 148765942Sgibbs SLIST_NEXT(curelm, 148865942Sgibbs sim_links.sle) = 148965942Sgibbs SLIST_NEXT(nextelm, 149065942Sgibbs sim_links.sle); 149165942Sgibbs break; 149265942Sgibbs } 149365942Sgibbs curelm = nextelm; 149465942Sgibbs } 149565942Sgibbs } 149665942Sgibbs 149765942Sgibbs if (found) { 149865942Sgibbs abort_ccb->ccb_h.status = CAM_REQ_ABORTED; 149965942Sgibbs xpt_done(abort_ccb); 150065942Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 150165942Sgibbs } else { 150268087Sgibbs xpt_print_path(abort_ccb->ccb_h.path); 150365942Sgibbs printf("Not found\n"); 150465942Sgibbs ccb->ccb_h.status = CAM_PATH_INVALID; 150565942Sgibbs } 150665942Sgibbs break; 150765942Sgibbs } 150865942Sgibbs /* FALLTHROUGH */ 150965942Sgibbs } 151065942Sgibbs case XPT_SCSI_IO: 151165942Sgibbs /* XXX Fully implement the hard ones */ 151265942Sgibbs ccb->ccb_h.status = CAM_UA_ABORT; 151365942Sgibbs break; 151465942Sgibbs default: 151565942Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 151665942Sgibbs break; 151765942Sgibbs } 151865942Sgibbs xpt_done(ccb); 151965942Sgibbs} 152065942Sgibbs 152165942Sgibbsvoid 152266269Sgibbsahc_send_async(struct ahc_softc *ahc, char channel, u_int target, 152376634Sgibbs u_int lun, ac_code code, void *opt_arg) 152465942Sgibbs{ 152565942Sgibbs struct ccb_trans_settings cts; 152665942Sgibbs struct cam_path *path; 152765942Sgibbs void *arg; 152865942Sgibbs int error; 152965942Sgibbs 153065942Sgibbs arg = NULL; 153166269Sgibbs error = ahc_create_path(ahc, channel, target, lun, &path); 153265942Sgibbs 153365942Sgibbs if (error != CAM_REQ_CMP) 153465942Sgibbs return; 153565942Sgibbs 153665942Sgibbs switch (code) { 153765942Sgibbs case AC_TRANSFER_NEG: 153876634Sgibbs { 153965942Sgibbs#ifdef AHC_NEW_TRAN_SETTINGS 154076634Sgibbs struct ccb_trans_settings_scsi *scsi; 154176634Sgibbs 154265942Sgibbs cts.type = CTS_TYPE_CURRENT_SETTINGS; 154376634Sgibbs scsi = &cts.proto_specific.scsi; 154465942Sgibbs#else 154565942Sgibbs cts.flags = CCB_TRANS_CURRENT_SETTINGS; 154665942Sgibbs#endif 154765942Sgibbs cts.ccb_h.path = path; 154866269Sgibbs cts.ccb_h.target_id = target; 154966269Sgibbs cts.ccb_h.target_lun = lun; 155066269Sgibbs ahc_get_tran_settings(ahc, channel == 'A' ? ahc->our_id 155166269Sgibbs : ahc->our_id_b, 155266269Sgibbs channel, &cts); 155365942Sgibbs arg = &cts; 155476634Sgibbs#ifdef AHC_NEW_TRAN_SETTINGS 155576634Sgibbs scsi->valid &= ~CTS_SCSI_VALID_TQ; 155676634Sgibbs scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 155776634Sgibbs#else 155876634Sgibbs cts.valid &= ~CCB_TRANS_TQ_VALID; 155976634Sgibbs cts.flags &= ~CCB_TRANS_TAG_ENB; 156076634Sgibbs#endif 156176634Sgibbs if (opt_arg == NULL) 156276634Sgibbs break; 156376634Sgibbs if (*((ahc_queue_alg *)opt_arg) == AHC_QUEUE_TAGGED) 156476634Sgibbs#ifdef AHC_NEW_TRAN_SETTINGS 156576634Sgibbs scsi->flags |= ~CTS_SCSI_FLAGS_TAG_ENB; 156676634Sgibbs scsi->valid |= CTS_SCSI_VALID_TQ; 156776634Sgibbs#else 156876634Sgibbs cts.flags |= CCB_TRANS_TAG_ENB; 156976634Sgibbs cts.valid |= CCB_TRANS_TQ_VALID; 157076634Sgibbs#endif 157165942Sgibbs break; 157276634Sgibbs } 157365942Sgibbs case AC_SENT_BDR: 157465942Sgibbs case AC_BUS_RESET: 157565942Sgibbs break; 157665942Sgibbs default: 157765942Sgibbs panic("ahc_send_async: Unexpected async event"); 157865942Sgibbs } 157965942Sgibbs xpt_async(code, path, arg); 158068402Sgibbs xpt_free_path(path); 158165942Sgibbs} 158265942Sgibbs 158365942Sgibbsvoid 158465942Sgibbsahc_platform_set_tags(struct ahc_softc *ahc, 158565942Sgibbs struct ahc_devinfo *devinfo, int enable) 158665942Sgibbs{ 158765942Sgibbs} 158865942Sgibbs 158965942Sgibbsint 159065942Sgibbsahc_platform_alloc(struct ahc_softc *ahc, void *platform_arg) 159165942Sgibbs{ 159267888Sdwmalone ahc->platform_data = malloc(sizeof(struct ahc_platform_data), M_DEVBUF, 159367888Sdwmalone M_NOWAIT | M_ZERO); 159465942Sgibbs if (ahc->platform_data == NULL) 159565942Sgibbs return (ENOMEM); 159665942Sgibbs return (0); 159765942Sgibbs} 159865942Sgibbs 159965942Sgibbsvoid 160065942Sgibbsahc_platform_free(struct ahc_softc *ahc) 160165942Sgibbs{ 160270204Sgibbs struct ahc_platform_data *pdata; 160370204Sgibbs 160470204Sgibbs pdata = ahc->platform_data; 160570204Sgibbs if (pdata != NULL) { 160670204Sgibbs if (pdata->regs != NULL) 160765942Sgibbs bus_release_resource(ahc->dev_softc, 160870204Sgibbs pdata->regs_res_type, 160970204Sgibbs pdata->regs_res_id, 161070204Sgibbs pdata->regs); 161165942Sgibbs 161270204Sgibbs if (pdata->irq != NULL) 161365942Sgibbs bus_release_resource(ahc->dev_softc, 161470204Sgibbs pdata->irq_res_type, 161570204Sgibbs 0, pdata->irq); 161665942Sgibbs 161770204Sgibbs if (pdata->sim_b != NULL) { 161870204Sgibbs xpt_async(AC_LOST_DEVICE, pdata->path_b, NULL); 161970204Sgibbs xpt_free_path(pdata->path_b); 162070204Sgibbs xpt_bus_deregister(cam_sim_path(pdata->sim_b)); 162170204Sgibbs cam_sim_free(pdata->sim_b, /*free_devq*/TRUE); 162270204Sgibbs } 162370204Sgibbs if (pdata->sim != NULL) { 162470204Sgibbs xpt_async(AC_LOST_DEVICE, pdata->path, NULL); 162570204Sgibbs xpt_free_path(pdata->path); 162670204Sgibbs xpt_bus_deregister(cam_sim_path(pdata->sim)); 162770204Sgibbs cam_sim_free(pdata->sim, /*free_devq*/TRUE); 162870204Sgibbs } 162970204Sgibbs if (pdata->eh != NULL) 163070204Sgibbs EVENTHANDLER_DEREGISTER(shutdown_final, pdata->eh); 163165942Sgibbs free(ahc->platform_data, M_DEVBUF); 163265942Sgibbs } 163365942Sgibbs} 163465942Sgibbs 163565942Sgibbsint 163665942Sgibbsahc_softc_comp(struct ahc_softc *lahc, struct ahc_softc *rahc) 163765942Sgibbs{ 163865942Sgibbs /* We don't sort softcs under FreeBSD so report equal always */ 163965942Sgibbs return (0); 164065942Sgibbs} 164165942Sgibbs 164270204Sgibbsint 164370204Sgibbsahc_detach(device_t dev) 164470204Sgibbs{ 164570204Sgibbs struct ahc_softc *ahc; 1646102674Sgibbs u_long l; 164770204Sgibbs u_long s; 164870204Sgibbs 1649102674Sgibbs ahc_list_lock(&l); 165070204Sgibbs device_printf(dev, "detaching device\n"); 165170204Sgibbs ahc = device_get_softc(dev); 1652102674Sgibbs ahc = ahc_find_softc(ahc); 1653102674Sgibbs if (ahc == NULL) { 1654102674Sgibbs device_printf(dev, "aic7xxx already detached\n"); 1655102674Sgibbs ahc_list_unlock(&l); 1656102674Sgibbs return (ENOENT); 1657102674Sgibbs } 1658123579Sgibbs TAILQ_REMOVE(&ahc_tailq, ahc, links); 1659123579Sgibbs ahc_list_unlock(&l); 166070204Sgibbs ahc_lock(ahc, &s); 1661102674Sgibbs ahc_intr_enable(ahc, FALSE); 166270204Sgibbs bus_teardown_intr(dev, ahc->platform_data->irq, ahc->platform_data->ih); 166370204Sgibbs ahc_unlock(ahc, &s); 166470204Sgibbs ahc_free(ahc); 166570204Sgibbs return (0); 166670204Sgibbs} 166770204Sgibbs 166865942Sgibbs#if UNUSED 166965942Sgibbsstatic void 167065942Sgibbsahc_dump_targcmd(struct target_cmd *cmd) 167165942Sgibbs{ 167265942Sgibbs uint8_t *byte; 167365942Sgibbs uint8_t *last_byte; 167465942Sgibbs int i; 167565942Sgibbs 167665942Sgibbs byte = &cmd->initiator_channel; 167765942Sgibbs /* Debugging info for received commands */ 167865942Sgibbs last_byte = &cmd[1].initiator_channel; 167965942Sgibbs 168065942Sgibbs i = 0; 168165942Sgibbs while (byte < last_byte) { 168265942Sgibbs if (i == 0) 168365942Sgibbs printf("\t"); 168465942Sgibbs printf("%#x", *byte++); 168565942Sgibbs i++; 168665942Sgibbs if (i == 8) { 168765942Sgibbs printf("\n"); 168865942Sgibbs i = 0; 168965942Sgibbs } else { 169065942Sgibbs printf(", "); 169165942Sgibbs } 169265942Sgibbs } 169365942Sgibbs} 169465942Sgibbs#endif 169576634Sgibbs 169676634Sgibbsstatic int 169776634Sgibbsahc_modevent(module_t mod, int type, void *data) 169876634Sgibbs{ 169976634Sgibbs /* XXX Deal with busy status on unload. */ 1700132199Sphk /* XXX Deal with unknown events */ 170176634Sgibbs return 0; 170276634Sgibbs} 170376634Sgibbs 170476634Sgibbsstatic moduledata_t ahc_mod = { 170576634Sgibbs "ahc", 170676634Sgibbs ahc_modevent, 170776634Sgibbs NULL 170876634Sgibbs}; 170976634Sgibbs 171076634SgibbsDECLARE_MODULE(ahc, ahc_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); 171176634SgibbsMODULE_DEPEND(ahc, cam, 1, 1, 1); 171276634SgibbsMODULE_VERSION(ahc, 1); 1713