1098ca2bdSWarner Losh /*- 2b3b25f2cSJustin T. Gibbs * Bus independent FreeBSD shim for the aic7xxx based Adaptec SCSI controllers 3717d4247SJustin T. Gibbs * 464a3876fSJustin T. Gibbs * Copyright (c) 1994-2001 Justin T. Gibbs. 5717d4247SJustin T. Gibbs * All rights reserved. 6717d4247SJustin T. Gibbs * 7717d4247SJustin T. Gibbs * Redistribution and use in source and binary forms, with or without 8717d4247SJustin T. Gibbs * modification, are permitted provided that the following conditions 9717d4247SJustin T. Gibbs * are met: 10717d4247SJustin T. Gibbs * 1. Redistributions of source code must retain the above copyright 11717d4247SJustin T. Gibbs * notice, this list of conditions, and the following disclaimer, 12717d4247SJustin T. Gibbs * without modification. 13717d4247SJustin T. Gibbs * 2. The name of the author may not be used to endorse or promote products 14717d4247SJustin T. Gibbs * derived from this software without specific prior written permission. 15717d4247SJustin T. Gibbs * 16717d4247SJustin T. Gibbs * Alternatively, this software may be distributed under the terms of the 17717d4247SJustin T. Gibbs * GNU Public License ("GPL"). 18717d4247SJustin T. Gibbs * 19717d4247SJustin T. Gibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20717d4247SJustin T. Gibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21717d4247SJustin T. Gibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22717d4247SJustin T. Gibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 23717d4247SJustin T. Gibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24717d4247SJustin T. Gibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25717d4247SJustin T. Gibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26717d4247SJustin T. Gibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27717d4247SJustin T. Gibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28717d4247SJustin T. Gibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29717d4247SJustin T. Gibbs * SUCH DAMAGE. 30717d4247SJustin T. Gibbs * 31b3b25f2cSJustin T. Gibbs * $Id: //depot/aic7xxx/freebsd/dev/aic7xxx/aic7xxx_osm.c#20 $ 32717d4247SJustin T. Gibbs */ 33717d4247SJustin T. Gibbs 348f214efcSJustin T. Gibbs #include <dev/aic7xxx/aic7xxx_osm.h> 35717d4247SJustin T. Gibbs #include <dev/aic7xxx/aic7xxx_inline.h> 36717d4247SJustin T. Gibbs 37b3b25f2cSJustin T. Gibbs #include <sys/kthread.h> 38b3b25f2cSJustin T. Gibbs 39717d4247SJustin T. Gibbs #ifndef AHC_TMODE_ENABLE 40717d4247SJustin T. Gibbs #define AHC_TMODE_ENABLE 0 41717d4247SJustin T. Gibbs #endif 42717d4247SJustin T. Gibbs 43b3b25f2cSJustin T. Gibbs #include <dev/aic7xxx/aic_osm_lib.c> 44b3b25f2cSJustin T. Gibbs 45717d4247SJustin T. Gibbs #define ccb_scb_ptr spriv_ptr0 46717d4247SJustin T. Gibbs 47f4e98881SRuslan Ermilov #if 0 48717d4247SJustin T. Gibbs static void ahc_dump_targcmd(struct target_cmd *cmd); 49717d4247SJustin T. Gibbs #endif 5058fb7d8eSJustin T. Gibbs static int ahc_modevent(module_t mod, int type, void *data); 51717d4247SJustin T. Gibbs static void ahc_action(struct cam_sim *sim, union ccb *ccb); 52717d4247SJustin T. Gibbs static void ahc_get_tran_settings(struct ahc_softc *ahc, 53717d4247SJustin T. Gibbs int our_id, char channel, 54717d4247SJustin T. Gibbs struct ccb_trans_settings *cts); 55717d4247SJustin T. Gibbs static void ahc_async(void *callback_arg, uint32_t code, 56717d4247SJustin T. Gibbs struct cam_path *path, void *arg); 57717d4247SJustin T. Gibbs static void ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, 58717d4247SJustin T. Gibbs int nsegments, int error); 59717d4247SJustin T. Gibbs static void ahc_poll(struct cam_sim *sim); 60717d4247SJustin T. Gibbs static void ahc_setup_data(struct ahc_softc *ahc, struct cam_sim *sim, 61717d4247SJustin T. Gibbs struct ccb_scsiio *csio, struct scb *scb); 62717d4247SJustin T. Gibbs static void ahc_abort_ccb(struct ahc_softc *ahc, struct cam_sim *sim, 63717d4247SJustin T. Gibbs union ccb *ccb); 64717d4247SJustin T. Gibbs static int ahc_create_path(struct ahc_softc *ahc, 65c498406dSJustin T. Gibbs char channel, u_int target, u_int lun, 66717d4247SJustin T. Gibbs struct cam_path **path); 67717d4247SJustin T. Gibbs 68717d4247SJustin T. Gibbs static int 69c498406dSJustin T. Gibbs ahc_create_path(struct ahc_softc *ahc, char channel, u_int target, 70c498406dSJustin T. Gibbs u_int lun, struct cam_path **path) 71717d4247SJustin T. Gibbs { 72717d4247SJustin T. Gibbs path_id_t path_id; 73717d4247SJustin T. Gibbs 74c498406dSJustin T. Gibbs if (channel == 'B') 75717d4247SJustin T. Gibbs path_id = cam_sim_path(ahc->platform_data->sim_b); 76717d4247SJustin T. Gibbs else 77717d4247SJustin T. Gibbs path_id = cam_sim_path(ahc->platform_data->sim); 78717d4247SJustin T. Gibbs 79717d4247SJustin T. Gibbs return (xpt_create_path(path, /*periph*/NULL, 80c498406dSJustin T. Gibbs path_id, target, lun)); 81717d4247SJustin T. Gibbs } 82717d4247SJustin T. Gibbs 838f214efcSJustin T. Gibbs int 848f214efcSJustin T. Gibbs ahc_map_int(struct ahc_softc *ahc) 858f214efcSJustin T. Gibbs { 868f214efcSJustin T. Gibbs int error; 877afc0218SJustin T. Gibbs int zero; 887afc0218SJustin T. Gibbs int shareable; 897afc0218SJustin T. Gibbs 907afc0218SJustin T. Gibbs zero = 0; 917afc0218SJustin T. Gibbs shareable = (ahc->flags & AHC_EDGE_INTERRUPT) ? 0: RF_SHAREABLE; 927afc0218SJustin T. Gibbs ahc->platform_data->irq = 937afc0218SJustin T. Gibbs bus_alloc_resource_any(ahc->dev_softc, SYS_RES_IRQ, &zero, 947afc0218SJustin T. Gibbs RF_ACTIVE | shareable); 957afc0218SJustin T. Gibbs if (ahc->platform_data->irq == NULL) { 967afc0218SJustin T. Gibbs device_printf(ahc->dev_softc, 977afc0218SJustin T. Gibbs "bus_alloc_resource() failed to allocate IRQ\n"); 987afc0218SJustin T. Gibbs return (ENOMEM); 997afc0218SJustin T. Gibbs } 1007afc0218SJustin T. Gibbs ahc->platform_data->irq_res_type = SYS_RES_IRQ; 1018f214efcSJustin T. Gibbs 1028f214efcSJustin T. Gibbs /* Hook up our interrupt handler */ 1038f214efcSJustin T. Gibbs error = bus_setup_intr(ahc->dev_softc, ahc->platform_data->irq, 104032b0a17SScott Long INTR_TYPE_CAM|INTR_MPSAFE, NULL, 105032b0a17SScott Long ahc_platform_intr, ahc, &ahc->platform_data->ih); 1068f214efcSJustin T. Gibbs 1078f214efcSJustin T. Gibbs if (error != 0) 1088f214efcSJustin T. Gibbs device_printf(ahc->dev_softc, "bus_setup_intr() failed: %d\n", 1098f214efcSJustin T. Gibbs error); 1108f214efcSJustin T. Gibbs return (error); 1118f214efcSJustin T. Gibbs } 1128f214efcSJustin T. Gibbs 1137afc0218SJustin T. Gibbs int 1147afc0218SJustin T. Gibbs aic7770_map_registers(struct ahc_softc *ahc, u_int unused_ioport_arg) 1157afc0218SJustin T. Gibbs { 1167afc0218SJustin T. Gibbs struct resource *regs; 1177afc0218SJustin T. Gibbs int rid; 1187afc0218SJustin T. Gibbs 1197afc0218SJustin T. Gibbs rid = 0; 1207afc0218SJustin T. Gibbs regs = bus_alloc_resource_any(ahc->dev_softc, SYS_RES_IOPORT, &rid, 1217afc0218SJustin T. Gibbs RF_ACTIVE); 1227afc0218SJustin T. Gibbs if (regs == NULL) { 1237afc0218SJustin T. Gibbs device_printf(ahc->dev_softc, "Unable to map I/O space?!\n"); 1247afc0218SJustin T. Gibbs return ENOMEM; 1257afc0218SJustin T. Gibbs } 1267afc0218SJustin T. Gibbs ahc->platform_data->regs_res_type = SYS_RES_IOPORT; 127f0be707dSPedro F. Giffuni ahc->platform_data->regs_res_id = rid; 1287afc0218SJustin T. Gibbs ahc->platform_data->regs = regs; 1297afc0218SJustin T. Gibbs ahc->tag = rman_get_bustag(regs); 1307afc0218SJustin T. Gibbs ahc->bsh = rman_get_bushandle(regs); 1317afc0218SJustin T. Gibbs return (0); 1327afc0218SJustin T. Gibbs } 1337afc0218SJustin T. Gibbs 134717d4247SJustin T. Gibbs /* 135717d4247SJustin T. Gibbs * Attach all the sub-devices we can find 136717d4247SJustin T. Gibbs */ 137717d4247SJustin T. Gibbs int 138717d4247SJustin T. Gibbs ahc_attach(struct ahc_softc *ahc) 139717d4247SJustin T. Gibbs { 140717d4247SJustin T. Gibbs char ahc_info[256]; 141717d4247SJustin T. Gibbs struct ccb_setasync csa; 142717d4247SJustin T. Gibbs struct cam_devq *devq; 143717d4247SJustin T. Gibbs int bus_id; 144717d4247SJustin T. Gibbs int bus_id2; 145717d4247SJustin T. Gibbs struct cam_sim *sim; 146717d4247SJustin T. Gibbs struct cam_sim *sim2; 147717d4247SJustin T. Gibbs struct cam_path *path; 148717d4247SJustin T. Gibbs struct cam_path *path2; 149717d4247SJustin T. Gibbs int count; 150717d4247SJustin T. Gibbs 151717d4247SJustin T. Gibbs count = 0; 152717d4247SJustin T. Gibbs sim = NULL; 153717d4247SJustin T. Gibbs sim2 = NULL; 1549af877a1SMatt Jacob path = NULL; 1559af877a1SMatt Jacob path2 = NULL; 156717d4247SJustin T. Gibbs 157b3b25f2cSJustin T. Gibbs /* 158b3b25f2cSJustin T. Gibbs * Create a thread to perform all recovery. 159b3b25f2cSJustin T. Gibbs */ 160b3b25f2cSJustin T. Gibbs if (ahc_spawn_recovery_thread(ahc) != 0) 161b3b25f2cSJustin T. Gibbs goto fail; 162b3b25f2cSJustin T. Gibbs 163717d4247SJustin T. Gibbs ahc_controller_info(ahc, ahc_info); 164717d4247SJustin T. Gibbs printf("%s\n", ahc_info); 165032b0a17SScott Long ahc_lock(ahc); 166b3b25f2cSJustin T. Gibbs 167717d4247SJustin T. Gibbs /* 168717d4247SJustin T. Gibbs * Attach secondary channel first if the user has 169717d4247SJustin T. Gibbs * declared it the primary channel. 170717d4247SJustin T. Gibbs */ 171077c1baeSJustin T. Gibbs if ((ahc->features & AHC_TWIN) != 0 1726fb77fefSJustin T. Gibbs && (ahc->flags & AHC_PRIMARY_CHANNEL) != 0) { 173717d4247SJustin T. Gibbs bus_id = 1; 174717d4247SJustin T. Gibbs bus_id2 = 0; 175717d4247SJustin T. Gibbs } else { 176717d4247SJustin T. Gibbs bus_id = 0; 177717d4247SJustin T. Gibbs bus_id2 = 1; 178717d4247SJustin T. Gibbs } 179717d4247SJustin T. Gibbs 180717d4247SJustin T. Gibbs /* 181717d4247SJustin T. Gibbs * Create the device queue for our SIM(s). 182717d4247SJustin T. Gibbs */ 183a5847d5cSJustin T. Gibbs devq = cam_simq_alloc(AHC_MAX_QUEUE); 184717d4247SJustin T. Gibbs if (devq == NULL) 185717d4247SJustin T. Gibbs goto fail; 186717d4247SJustin T. Gibbs 187717d4247SJustin T. Gibbs /* 188717d4247SJustin T. Gibbs * Construct our first channel SIM entry 189717d4247SJustin T. Gibbs */ 190dfd86f14SJustin T. Gibbs sim = cam_sim_alloc(ahc_action, ahc_poll, "ahc", ahc, 191dfd86f14SJustin T. Gibbs device_get_unit(ahc->dev_softc), 192032b0a17SScott Long &ahc->platform_data->mtx, 1, AHC_MAX_QUEUE, devq); 193717d4247SJustin T. Gibbs if (sim == NULL) { 194717d4247SJustin T. Gibbs cam_simq_free(devq); 195717d4247SJustin T. Gibbs goto fail; 196717d4247SJustin T. Gibbs } 197717d4247SJustin T. Gibbs 198b50569b7SScott Long if (xpt_bus_register(sim, ahc->dev_softc, bus_id) != CAM_SUCCESS) { 199717d4247SJustin T. Gibbs cam_sim_free(sim, /*free_devq*/TRUE); 200717d4247SJustin T. Gibbs sim = NULL; 201717d4247SJustin T. Gibbs goto fail; 202717d4247SJustin T. Gibbs } 203717d4247SJustin T. Gibbs 204717d4247SJustin T. Gibbs if (xpt_create_path(&path, /*periph*/NULL, 205717d4247SJustin T. Gibbs cam_sim_path(sim), CAM_TARGET_WILDCARD, 206717d4247SJustin T. Gibbs CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 207717d4247SJustin T. Gibbs xpt_bus_deregister(cam_sim_path(sim)); 208717d4247SJustin T. Gibbs cam_sim_free(sim, /*free_devq*/TRUE); 209717d4247SJustin T. Gibbs sim = NULL; 210717d4247SJustin T. Gibbs goto fail; 211717d4247SJustin T. Gibbs } 212717d4247SJustin T. Gibbs 2138dc96b74SEdward Tomasz Napierala memset(&csa, 0, sizeof(csa)); 214717d4247SJustin T. Gibbs xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5); 215717d4247SJustin T. Gibbs csa.ccb_h.func_code = XPT_SASYNC_CB; 216717d4247SJustin T. Gibbs csa.event_enable = AC_LOST_DEVICE; 217717d4247SJustin T. Gibbs csa.callback = ahc_async; 218717d4247SJustin T. Gibbs csa.callback_arg = sim; 219717d4247SJustin T. Gibbs xpt_action((union ccb *)&csa); 220717d4247SJustin T. Gibbs count++; 221717d4247SJustin T. Gibbs 222717d4247SJustin T. Gibbs if (ahc->features & AHC_TWIN) { 223717d4247SJustin T. Gibbs sim2 = cam_sim_alloc(ahc_action, ahc_poll, "ahc", 2242b83592fSScott Long ahc, device_get_unit(ahc->dev_softc), 225032b0a17SScott Long &ahc->platform_data->mtx, 1, 226a5847d5cSJustin T. Gibbs AHC_MAX_QUEUE, devq); 227717d4247SJustin T. Gibbs 228717d4247SJustin T. Gibbs if (sim2 == NULL) { 229717d4247SJustin T. Gibbs printf("ahc_attach: Unable to attach second " 230717d4247SJustin T. Gibbs "bus due to resource shortage"); 231717d4247SJustin T. Gibbs goto fail; 232717d4247SJustin T. Gibbs } 233717d4247SJustin T. Gibbs 234b50569b7SScott Long if (xpt_bus_register(sim2, ahc->dev_softc, bus_id2) != 235b50569b7SScott Long CAM_SUCCESS) { 236717d4247SJustin T. Gibbs printf("ahc_attach: Unable to attach second " 237717d4247SJustin T. Gibbs "bus due to resource shortage"); 238717d4247SJustin T. Gibbs /* 239717d4247SJustin T. Gibbs * We do not want to destroy the device queue 240717d4247SJustin T. Gibbs * because the first bus is using it. 241717d4247SJustin T. Gibbs */ 242717d4247SJustin T. Gibbs cam_sim_free(sim2, /*free_devq*/FALSE); 243717d4247SJustin T. Gibbs goto fail; 244717d4247SJustin T. Gibbs } 245717d4247SJustin T. Gibbs 246717d4247SJustin T. Gibbs if (xpt_create_path(&path2, /*periph*/NULL, 247717d4247SJustin T. Gibbs cam_sim_path(sim2), 248717d4247SJustin T. Gibbs CAM_TARGET_WILDCARD, 249717d4247SJustin T. Gibbs CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 250717d4247SJustin T. Gibbs xpt_bus_deregister(cam_sim_path(sim2)); 251717d4247SJustin T. Gibbs cam_sim_free(sim2, /*free_devq*/FALSE); 252717d4247SJustin T. Gibbs sim2 = NULL; 253717d4247SJustin T. Gibbs goto fail; 254717d4247SJustin T. Gibbs } 255717d4247SJustin T. Gibbs xpt_setup_ccb(&csa.ccb_h, path2, /*priority*/5); 256717d4247SJustin T. Gibbs csa.ccb_h.func_code = XPT_SASYNC_CB; 257717d4247SJustin T. Gibbs csa.event_enable = AC_LOST_DEVICE; 258717d4247SJustin T. Gibbs csa.callback = ahc_async; 259717d4247SJustin T. Gibbs csa.callback_arg = sim2; 260717d4247SJustin T. Gibbs xpt_action((union ccb *)&csa); 261717d4247SJustin T. Gibbs count++; 262717d4247SJustin T. Gibbs } 263717d4247SJustin T. Gibbs 264717d4247SJustin T. Gibbs fail: 265077c1baeSJustin T. Gibbs if ((ahc->features & AHC_TWIN) != 0 2666fb77fefSJustin T. Gibbs && (ahc->flags & AHC_PRIMARY_CHANNEL) != 0) { 267717d4247SJustin T. Gibbs ahc->platform_data->sim_b = sim; 268717d4247SJustin T. Gibbs ahc->platform_data->path_b = path; 269717d4247SJustin T. Gibbs ahc->platform_data->sim = sim2; 270717d4247SJustin T. Gibbs ahc->platform_data->path = path2; 271717d4247SJustin T. Gibbs } else { 272717d4247SJustin T. Gibbs ahc->platform_data->sim = sim; 273717d4247SJustin T. Gibbs ahc->platform_data->path = path; 274717d4247SJustin T. Gibbs ahc->platform_data->sim_b = sim2; 275717d4247SJustin T. Gibbs ahc->platform_data->path_b = path2; 276717d4247SJustin T. Gibbs } 277032b0a17SScott Long ahc_unlock(ahc); 278717d4247SJustin T. Gibbs 279226aa6eaSJustin T. Gibbs if (count != 0) { 280717d4247SJustin T. Gibbs /* We have to wait until after any system dumps... */ 28156a7c4a8SJustin T. Gibbs ahc->platform_data->eh = 282717d4247SJustin T. Gibbs EVENTHANDLER_REGISTER(shutdown_final, ahc_shutdown, 283717d4247SJustin T. Gibbs ahc, SHUTDOWN_PRI_DEFAULT); 284226aa6eaSJustin T. Gibbs ahc_intr_enable(ahc, TRUE); 285226aa6eaSJustin T. Gibbs } 286717d4247SJustin T. Gibbs 287717d4247SJustin T. Gibbs return (count); 288717d4247SJustin T. Gibbs } 289717d4247SJustin T. Gibbs 290717d4247SJustin T. Gibbs /* 291717d4247SJustin T. Gibbs * Catch an interrupt from the adapter 292717d4247SJustin T. Gibbs */ 293717d4247SJustin T. Gibbs void 29456a7c4a8SJustin T. Gibbs ahc_platform_intr(void *arg) 295717d4247SJustin T. Gibbs { 296717d4247SJustin T. Gibbs struct ahc_softc *ahc; 297717d4247SJustin T. Gibbs 298717d4247SJustin T. Gibbs ahc = (struct ahc_softc *)arg; 299032b0a17SScott Long ahc_lock(ahc); 300717d4247SJustin T. Gibbs ahc_intr(ahc); 301032b0a17SScott Long ahc_unlock(ahc); 302717d4247SJustin T. Gibbs } 303717d4247SJustin T. Gibbs 304*9dcf3957SKyle Evans static void 305*9dcf3957SKyle Evans ahc_sync_ccb(struct ahc_softc *ahc, struct scb *scb, union ccb *ccb, bool post) 306*9dcf3957SKyle Evans { 307*9dcf3957SKyle Evans bus_dmasync_op_t op; 308*9dcf3957SKyle Evans uint32_t rdmask; 309*9dcf3957SKyle Evans 310*9dcf3957SKyle Evans if (ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) 311*9dcf3957SKyle Evans rdmask = CAM_DIR_OUT; 312*9dcf3957SKyle Evans else 313*9dcf3957SKyle Evans rdmask = CAM_DIR_IN; 314*9dcf3957SKyle Evans 315*9dcf3957SKyle Evans if ((ccb->ccb_h.flags & CAM_DIR_MASK) == rdmask) 316*9dcf3957SKyle Evans op = post ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_PREREAD; 317*9dcf3957SKyle Evans else 318*9dcf3957SKyle Evans op = post ? BUS_DMASYNC_POSTWRITE : BUS_DMASYNC_PREWRITE; 319*9dcf3957SKyle Evans 320*9dcf3957SKyle Evans bus_dmamap_sync(ahc->buffer_dmat, scb->dmamap, op); 321*9dcf3957SKyle Evans } 322*9dcf3957SKyle Evans 323717d4247SJustin T. Gibbs /* 324717d4247SJustin T. Gibbs * We have an scb which has been processed by the 325717d4247SJustin T. Gibbs * adaptor, now we look to see how the operation 326717d4247SJustin T. Gibbs * went. 327717d4247SJustin T. Gibbs */ 328717d4247SJustin T. Gibbs void 329717d4247SJustin T. Gibbs ahc_done(struct ahc_softc *ahc, struct scb *scb) 330717d4247SJustin T. Gibbs { 331717d4247SJustin T. Gibbs union ccb *ccb; 332717d4247SJustin T. Gibbs 333717d4247SJustin T. Gibbs CAM_DEBUG(scb->io_ctx->ccb_h.path, CAM_DEBUG_TRACE, 334717d4247SJustin T. Gibbs ("ahc_done - scb %d\n", scb->hscb->tag)); 335717d4247SJustin T. Gibbs 336717d4247SJustin T. Gibbs ccb = scb->io_ctx; 337717d4247SJustin T. Gibbs LIST_REMOVE(scb, pending_links); 338b3b25f2cSJustin T. Gibbs if ((scb->flags & SCB_TIMEDOUT) != 0) 339b3b25f2cSJustin T. Gibbs LIST_REMOVE(scb, timedout_links); 34070351c9aSJustin T. Gibbs if ((scb->flags & SCB_UNTAGGEDQ) != 0) { 341717d4247SJustin T. Gibbs struct scb_tailq *untagged_q; 3421478c711SJustin T. Gibbs int target_offset; 343717d4247SJustin T. Gibbs 3441478c711SJustin T. Gibbs target_offset = SCB_GET_TARGET_OFFSET(ahc, scb); 3451478c711SJustin T. Gibbs untagged_q = &ahc->untagged_queues[target_offset]; 346717d4247SJustin T. Gibbs TAILQ_REMOVE(untagged_q, scb, links.tqe); 34770351c9aSJustin T. Gibbs scb->flags &= ~SCB_UNTAGGEDQ; 348717d4247SJustin T. Gibbs ahc_run_untagged_queue(ahc, untagged_q); 349717d4247SJustin T. Gibbs } 350717d4247SJustin T. Gibbs 351032b0a17SScott Long callout_stop(&scb->io_timer); 352717d4247SJustin T. Gibbs 353717d4247SJustin T. Gibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) { 354*9dcf3957SKyle Evans ahc_sync_ccb(ahc, scb, ccb, true); 355717d4247SJustin T. Gibbs bus_dmamap_unload(ahc->buffer_dmat, scb->dmamap); 356717d4247SJustin T. Gibbs } 357717d4247SJustin T. Gibbs 358717d4247SJustin T. Gibbs if (ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) { 359b95de6daSJustin T. Gibbs struct cam_path *ccb_path; 360b95de6daSJustin T. Gibbs 361b95de6daSJustin T. Gibbs /* 362b95de6daSJustin T. Gibbs * If we have finally disconnected, clean up our 363b95de6daSJustin T. Gibbs * pending device state. 364b95de6daSJustin T. Gibbs * XXX - There may be error states that cause where 365b95de6daSJustin T. Gibbs * we will remain connected. 366b95de6daSJustin T. Gibbs */ 367b95de6daSJustin T. Gibbs ccb_path = ccb->ccb_h.path; 368b95de6daSJustin T. Gibbs if (ahc->pending_device != NULL 369b95de6daSJustin T. Gibbs && xpt_path_comp(ahc->pending_device->path, ccb_path) == 0) { 370b95de6daSJustin T. Gibbs if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) { 371b95de6daSJustin T. Gibbs ahc->pending_device = NULL; 372b95de6daSJustin T. Gibbs } else { 3738f214efcSJustin T. Gibbs if (bootverbose) { 374b95de6daSJustin T. Gibbs xpt_print_path(ccb->ccb_h.path); 3758f214efcSJustin T. Gibbs printf("Still connected\n"); 3768f214efcSJustin T. Gibbs } 377b3b25f2cSJustin T. Gibbs aic_freeze_ccb(ccb); 378b95de6daSJustin T. Gibbs } 379b95de6daSJustin T. Gibbs } 380b95de6daSJustin T. Gibbs 381b3b25f2cSJustin T. Gibbs if (aic_get_transaction_status(scb) == CAM_REQ_INPROG) 382717d4247SJustin T. Gibbs ccb->ccb_h.status |= CAM_REQ_CMP; 383717d4247SJustin T. Gibbs ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 384717d4247SJustin T. Gibbs ahc_free_scb(ahc, scb); 385717d4247SJustin T. Gibbs xpt_done(ccb); 386717d4247SJustin T. Gibbs return; 387717d4247SJustin T. Gibbs } 388717d4247SJustin T. Gibbs 389717d4247SJustin T. Gibbs /* 390717d4247SJustin T. Gibbs * If the recovery SCB completes, we have to be 391717d4247SJustin T. Gibbs * out of our timeout. 392717d4247SJustin T. Gibbs */ 393717d4247SJustin T. Gibbs if ((scb->flags & SCB_RECOVERY_SCB) != 0) { 394717d4247SJustin T. Gibbs struct scb *list_scb; 395717d4247SJustin T. Gibbs 3967afc0218SJustin T. Gibbs ahc->scb_data->recovery_scbs--; 397717d4247SJustin T. Gibbs 398b3b25f2cSJustin T. Gibbs if (aic_get_transaction_status(scb) == CAM_BDR_SENT 399b3b25f2cSJustin T. Gibbs || aic_get_transaction_status(scb) == CAM_REQ_ABORTED) 400b3b25f2cSJustin T. Gibbs aic_set_transaction_status(scb, CAM_CMD_TIMEOUT); 4017afc0218SJustin T. Gibbs 4027afc0218SJustin T. Gibbs if (ahc->scb_data->recovery_scbs == 0) { 4037afc0218SJustin T. Gibbs /* 4047afc0218SJustin T. Gibbs * All recovery actions have completed successfully, 4057afc0218SJustin T. Gibbs * so reinstate the timeouts for all other pending 4067afc0218SJustin T. Gibbs * commands. 4077afc0218SJustin T. Gibbs */ 4087afc0218SJustin T. Gibbs LIST_FOREACH(list_scb, &ahc->pending_scbs, 4097afc0218SJustin T. Gibbs pending_links) { 41016346ae5SJustin T. Gibbs aic_scb_timer_reset(list_scb, 41116346ae5SJustin T. Gibbs aic_get_timeout(scb)); 4127afc0218SJustin T. Gibbs } 4137afc0218SJustin T. Gibbs 414717d4247SJustin T. Gibbs ahc_print_path(ahc, scb); 415717d4247SJustin T. Gibbs printf("no longer in timeout, status = %x\n", 416717d4247SJustin T. Gibbs ccb->ccb_h.status); 417717d4247SJustin T. Gibbs } 4187afc0218SJustin T. Gibbs } 419717d4247SJustin T. Gibbs 420717d4247SJustin T. Gibbs /* Don't clobber any existing error state */ 421b3b25f2cSJustin T. Gibbs if (aic_get_transaction_status(scb) == CAM_REQ_INPROG) { 422717d4247SJustin T. Gibbs ccb->ccb_h.status |= CAM_REQ_CMP; 423717d4247SJustin T. Gibbs } else if ((scb->flags & SCB_SENSE) != 0) { 424717d4247SJustin T. Gibbs /* 425717d4247SJustin T. Gibbs * We performed autosense retrieval. 426717d4247SJustin T. Gibbs * 427717d4247SJustin T. Gibbs * Zero any sense not transferred by the 428717d4247SJustin T. Gibbs * device. The SCSI spec mandates that any 429717d4247SJustin T. Gibbs * untransfered data should be assumed to be 430717d4247SJustin T. Gibbs * zero. Complete the 'bounce' of sense information 431717d4247SJustin T. Gibbs * through buffers accessible via bus-space by 432717d4247SJustin T. Gibbs * copying it into the clients csio. 433717d4247SJustin T. Gibbs */ 434717d4247SJustin T. Gibbs memset(&ccb->csio.sense_data, 0, sizeof(ccb->csio.sense_data)); 435717d4247SJustin T. Gibbs memcpy(&ccb->csio.sense_data, 43676150586SJustin T. Gibbs ahc_get_sense_buf(ahc, scb), 437b3b25f2cSJustin T. Gibbs (aic_le32toh(scb->sg_list->len) & AHC_SG_LEN_MASK) 438717d4247SJustin T. Gibbs - ccb->csio.sense_resid); 439717d4247SJustin T. Gibbs scb->io_ctx->ccb_h.status |= CAM_AUTOSNS_VALID; 440717d4247SJustin T. Gibbs } 441717d4247SJustin T. Gibbs ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 442717d4247SJustin T. Gibbs ahc_free_scb(ahc, scb); 443717d4247SJustin T. Gibbs xpt_done(ccb); 444717d4247SJustin T. Gibbs } 445717d4247SJustin T. Gibbs 446717d4247SJustin T. Gibbs static void 447717d4247SJustin T. Gibbs ahc_action(struct cam_sim *sim, union ccb *ccb) 448717d4247SJustin T. Gibbs { 449717d4247SJustin T. Gibbs struct ahc_softc *ahc; 450b95de6daSJustin T. Gibbs struct ahc_tmode_lstate *lstate; 451717d4247SJustin T. Gibbs u_int target_id; 452717d4247SJustin T. Gibbs u_int our_id; 453717d4247SJustin T. Gibbs 454717d4247SJustin T. Gibbs CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("ahc_action\n")); 455717d4247SJustin T. Gibbs 456717d4247SJustin T. Gibbs ahc = (struct ahc_softc *)cam_sim_softc(sim); 457717d4247SJustin T. Gibbs 458717d4247SJustin T. Gibbs target_id = ccb->ccb_h.target_id; 459717d4247SJustin T. Gibbs our_id = SIM_SCSI_ID(ahc, sim); 460717d4247SJustin T. Gibbs 461717d4247SJustin T. Gibbs switch (ccb->ccb_h.func_code) { 462717d4247SJustin T. Gibbs /* Common cases first */ 463717d4247SJustin T. Gibbs case XPT_ACCEPT_TARGET_IO: /* Accept Host Target Mode CDB */ 464717d4247SJustin T. Gibbs case XPT_CONT_TARGET_IO:/* Continue Host Target I/O Connection*/ 465717d4247SJustin T. Gibbs { 466b95de6daSJustin T. Gibbs struct ahc_tmode_tstate *tstate; 467717d4247SJustin T. Gibbs cam_status status; 468717d4247SJustin T. Gibbs 469717d4247SJustin T. Gibbs status = ahc_find_tmode_devs(ahc, sim, ccb, &tstate, 470717d4247SJustin T. Gibbs &lstate, TRUE); 471717d4247SJustin T. Gibbs 472717d4247SJustin T. Gibbs if (status != CAM_REQ_CMP) { 473717d4247SJustin T. Gibbs if (ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) { 474717d4247SJustin T. Gibbs /* Response from the black hole device */ 475717d4247SJustin T. Gibbs tstate = NULL; 476717d4247SJustin T. Gibbs lstate = ahc->black_hole; 477717d4247SJustin T. Gibbs } else { 478717d4247SJustin T. Gibbs ccb->ccb_h.status = status; 479717d4247SJustin T. Gibbs xpt_done(ccb); 480717d4247SJustin T. Gibbs break; 481717d4247SJustin T. Gibbs } 482717d4247SJustin T. Gibbs } 483717d4247SJustin T. Gibbs if (ccb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) { 484717d4247SJustin T. Gibbs SLIST_INSERT_HEAD(&lstate->accept_tios, &ccb->ccb_h, 485717d4247SJustin T. Gibbs sim_links.sle); 486717d4247SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_INPROG; 487717d4247SJustin T. Gibbs if ((ahc->flags & AHC_TQINFIFO_BLOCKED) != 0) 488717d4247SJustin T. Gibbs ahc_run_tqinfifo(ahc, /*paused*/FALSE); 489717d4247SJustin T. Gibbs break; 490717d4247SJustin T. Gibbs } 491717d4247SJustin T. Gibbs 492717d4247SJustin T. Gibbs /* 493717d4247SJustin T. Gibbs * The target_id represents the target we attempt to 494717d4247SJustin T. Gibbs * select. In target mode, this is the initiator of 495717d4247SJustin T. Gibbs * the original command. 496717d4247SJustin T. Gibbs */ 497717d4247SJustin T. Gibbs our_id = target_id; 498717d4247SJustin T. Gibbs target_id = ccb->csio.init_id; 499717d4247SJustin T. Gibbs /* FALLTHROUGH */ 500717d4247SJustin T. Gibbs } 501717d4247SJustin T. Gibbs case XPT_SCSI_IO: /* Execute the requested I/O operation */ 502717d4247SJustin T. Gibbs case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */ 503717d4247SJustin T. Gibbs { 504717d4247SJustin T. Gibbs struct scb *scb; 505717d4247SJustin T. Gibbs struct hardware_scb *hscb; 506717d4247SJustin T. Gibbs 507dd1290f0SJustin T. Gibbs if ((ahc->flags & AHC_INITIATORROLE) == 0 508dd1290f0SJustin T. Gibbs && (ccb->ccb_h.func_code == XPT_SCSI_IO 509dd1290f0SJustin T. Gibbs || ccb->ccb_h.func_code == XPT_RESET_DEV)) { 510dd1290f0SJustin T. Gibbs ccb->ccb_h.status = CAM_PROVIDE_FAIL; 511dd1290f0SJustin T. Gibbs xpt_done(ccb); 512b95de6daSJustin T. Gibbs return; 513dd1290f0SJustin T. Gibbs } 514dd1290f0SJustin T. Gibbs 515717d4247SJustin T. Gibbs /* 516717d4247SJustin T. Gibbs * get an scb to use. 517717d4247SJustin T. Gibbs */ 518717d4247SJustin T. Gibbs if ((scb = ahc_get_scb(ahc)) == NULL) { 519b00aeda6SJustin T. Gibbs xpt_freeze_simq(sim, /*count*/1); 520717d4247SJustin T. Gibbs ahc->flags |= AHC_RESOURCE_SHORTAGE; 521155c0683SJustin T. Gibbs ccb->ccb_h.status = CAM_REQUEUE_REQ; 522717d4247SJustin T. Gibbs xpt_done(ccb); 523717d4247SJustin T. Gibbs return; 524717d4247SJustin T. Gibbs } 525717d4247SJustin T. Gibbs 526717d4247SJustin T. Gibbs hscb = scb->hscb; 527717d4247SJustin T. Gibbs 528717d4247SJustin T. Gibbs CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_SUBTRACE, 529717d4247SJustin T. Gibbs ("start scb(%p)\n", scb)); 530717d4247SJustin T. Gibbs scb->io_ctx = ccb; 531717d4247SJustin T. Gibbs /* 532717d4247SJustin T. Gibbs * So we can find the SCB when an abort is requested 533717d4247SJustin T. Gibbs */ 534717d4247SJustin T. Gibbs ccb->ccb_h.ccb_scb_ptr = scb; 535717d4247SJustin T. Gibbs 536717d4247SJustin T. Gibbs /* 537717d4247SJustin T. Gibbs * Put all the arguments for the xfer in the scb 538717d4247SJustin T. Gibbs */ 539717d4247SJustin T. Gibbs hscb->control = 0; 540717d4247SJustin T. Gibbs hscb->scsiid = BUILD_SCSIID(ahc, sim, target_id, our_id); 541717d4247SJustin T. Gibbs hscb->lun = ccb->ccb_h.target_lun; 542717d4247SJustin T. Gibbs if (ccb->ccb_h.func_code == XPT_RESET_DEV) { 543717d4247SJustin T. Gibbs hscb->cdb_len = 0; 544717d4247SJustin T. Gibbs scb->flags |= SCB_DEVICE_RESET; 545717d4247SJustin T. Gibbs hscb->control |= MK_MESSAGE; 546717d4247SJustin T. Gibbs ahc_execute_scb(scb, NULL, 0, 0); 547717d4247SJustin T. Gibbs } else { 548717d4247SJustin T. Gibbs if (ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) { 549717d4247SJustin T. Gibbs struct target_data *tdata; 550717d4247SJustin T. Gibbs 551717d4247SJustin T. Gibbs tdata = &hscb->shared_data.tdata; 552b95de6daSJustin T. Gibbs if (ahc->pending_device == lstate) 553717d4247SJustin T. Gibbs scb->flags |= SCB_TARGET_IMMEDIATE; 554717d4247SJustin T. Gibbs hscb->control |= TARGET_SCB; 555a3a33a2bSScott Long scb->flags |= SCB_TARGET_SCB; 556a3a33a2bSScott Long tdata->target_phases = 0; 557717d4247SJustin T. Gibbs if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) { 558717d4247SJustin T. Gibbs tdata->target_phases |= SPHASE_PENDING; 559717d4247SJustin T. Gibbs tdata->scsi_status = 560717d4247SJustin T. Gibbs ccb->csio.scsi_status; 561717d4247SJustin T. Gibbs } 562b95de6daSJustin T. Gibbs if (ccb->ccb_h.flags & CAM_DIS_DISCONNECT) 563b95de6daSJustin T. Gibbs tdata->target_phases |= NO_DISCONNECT; 564b95de6daSJustin T. Gibbs 565717d4247SJustin T. Gibbs tdata->initiator_tag = ccb->csio.tag_id; 566717d4247SJustin T. Gibbs } 567717d4247SJustin T. Gibbs if (ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) 568717d4247SJustin T. Gibbs hscb->control |= ccb->csio.tag_action; 569717d4247SJustin T. Gibbs 570717d4247SJustin T. Gibbs ahc_setup_data(ahc, sim, &ccb->csio, scb); 571717d4247SJustin T. Gibbs } 572717d4247SJustin T. Gibbs break; 573717d4247SJustin T. Gibbs } 574b79dc8a8SKenneth D. Merry case XPT_NOTIFY_ACKNOWLEDGE: 575b79dc8a8SKenneth D. Merry case XPT_IMMEDIATE_NOTIFY: 576717d4247SJustin T. Gibbs { 577b95de6daSJustin T. Gibbs struct ahc_tmode_tstate *tstate; 578b95de6daSJustin T. Gibbs struct ahc_tmode_lstate *lstate; 579717d4247SJustin T. Gibbs cam_status status; 580717d4247SJustin T. Gibbs 581717d4247SJustin T. Gibbs status = ahc_find_tmode_devs(ahc, sim, ccb, &tstate, 582717d4247SJustin T. Gibbs &lstate, TRUE); 583717d4247SJustin T. Gibbs 584717d4247SJustin T. Gibbs if (status != CAM_REQ_CMP) { 585717d4247SJustin T. Gibbs ccb->ccb_h.status = status; 586717d4247SJustin T. Gibbs xpt_done(ccb); 587717d4247SJustin T. Gibbs break; 588717d4247SJustin T. Gibbs } 589717d4247SJustin T. Gibbs SLIST_INSERT_HEAD(&lstate->immed_notifies, &ccb->ccb_h, 590717d4247SJustin T. Gibbs sim_links.sle); 591717d4247SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_INPROG; 592717d4247SJustin T. Gibbs ahc_send_lstate_events(ahc, lstate); 593717d4247SJustin T. Gibbs break; 594717d4247SJustin T. Gibbs } 595717d4247SJustin T. Gibbs case XPT_EN_LUN: /* Enable LUN as a target */ 596717d4247SJustin T. Gibbs ahc_handle_en_lun(ahc, sim, ccb); 597717d4247SJustin T. Gibbs xpt_done(ccb); 598717d4247SJustin T. Gibbs break; 599717d4247SJustin T. Gibbs case XPT_ABORT: /* Abort the specified CCB */ 600717d4247SJustin T. Gibbs { 601717d4247SJustin T. Gibbs ahc_abort_ccb(ahc, sim, ccb); 602717d4247SJustin T. Gibbs break; 603717d4247SJustin T. Gibbs } 604717d4247SJustin T. Gibbs case XPT_SET_TRAN_SETTINGS: 605717d4247SJustin T. Gibbs { 606717d4247SJustin T. Gibbs struct ahc_devinfo devinfo; 607717d4247SJustin T. Gibbs struct ccb_trans_settings *cts; 608717d4247SJustin T. Gibbs struct ccb_trans_settings_scsi *scsi; 609717d4247SJustin T. Gibbs struct ccb_trans_settings_spi *spi; 610717d4247SJustin T. Gibbs struct ahc_initiator_tinfo *tinfo; 611b95de6daSJustin T. Gibbs struct ahc_tmode_tstate *tstate; 612717d4247SJustin T. Gibbs uint16_t *discenable; 613717d4247SJustin T. Gibbs uint16_t *tagenable; 614717d4247SJustin T. Gibbs u_int update_type; 615717d4247SJustin T. Gibbs 616717d4247SJustin T. Gibbs cts = &ccb->cts; 617717d4247SJustin T. Gibbs scsi = &cts->proto_specific.scsi; 618717d4247SJustin T. Gibbs spi = &cts->xport_specific.spi; 619717d4247SJustin T. Gibbs ahc_compile_devinfo(&devinfo, SIM_SCSI_ID(ahc, sim), 620717d4247SJustin T. Gibbs cts->ccb_h.target_id, 621717d4247SJustin T. Gibbs cts->ccb_h.target_lun, 622717d4247SJustin T. Gibbs SIM_CHANNEL(ahc, sim), 623717d4247SJustin T. Gibbs ROLE_UNKNOWN); 624717d4247SJustin T. Gibbs tinfo = ahc_fetch_transinfo(ahc, devinfo.channel, 625717d4247SJustin T. Gibbs devinfo.our_scsiid, 626717d4247SJustin T. Gibbs devinfo.target, &tstate); 627717d4247SJustin T. Gibbs update_type = 0; 628717d4247SJustin T. Gibbs if (cts->type == CTS_TYPE_CURRENT_SETTINGS) { 629717d4247SJustin T. Gibbs update_type |= AHC_TRANS_GOAL; 630717d4247SJustin T. Gibbs discenable = &tstate->discenable; 631717d4247SJustin T. Gibbs tagenable = &tstate->tagenable; 63258fb7d8eSJustin T. Gibbs tinfo->curr.protocol_version = 633717d4247SJustin T. Gibbs cts->protocol_version; 63458fb7d8eSJustin T. Gibbs tinfo->curr.transport_version = 635717d4247SJustin T. Gibbs cts->transport_version; 636717d4247SJustin T. Gibbs tinfo->goal.protocol_version = 637717d4247SJustin T. Gibbs cts->protocol_version; 638717d4247SJustin T. Gibbs tinfo->goal.transport_version = 639717d4247SJustin T. Gibbs cts->transport_version; 640717d4247SJustin T. Gibbs } else if (cts->type == CTS_TYPE_USER_SETTINGS) { 641717d4247SJustin T. Gibbs update_type |= AHC_TRANS_USER; 642717d4247SJustin T. Gibbs discenable = &ahc->user_discenable; 643717d4247SJustin T. Gibbs tagenable = &ahc->user_tagenable; 644717d4247SJustin T. Gibbs tinfo->user.protocol_version = 645717d4247SJustin T. Gibbs cts->protocol_version; 646717d4247SJustin T. Gibbs tinfo->user.transport_version = 647717d4247SJustin T. Gibbs cts->transport_version; 648717d4247SJustin T. Gibbs } else { 649717d4247SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_INVALID; 650717d4247SJustin T. Gibbs xpt_done(ccb); 651717d4247SJustin T. Gibbs break; 652717d4247SJustin T. Gibbs } 653717d4247SJustin T. Gibbs 654717d4247SJustin T. Gibbs if ((spi->valid & CTS_SPI_VALID_DISC) != 0) { 655717d4247SJustin T. Gibbs if ((spi->flags & CTS_SPI_FLAGS_DISC_ENB) != 0) 656717d4247SJustin T. Gibbs *discenable |= devinfo.target_mask; 657717d4247SJustin T. Gibbs else 658717d4247SJustin T. Gibbs *discenable &= ~devinfo.target_mask; 659717d4247SJustin T. Gibbs } 660717d4247SJustin T. Gibbs 661717d4247SJustin T. Gibbs if ((scsi->valid & CTS_SCSI_VALID_TQ) != 0) { 662717d4247SJustin T. Gibbs if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0) 663717d4247SJustin T. Gibbs *tagenable |= devinfo.target_mask; 664717d4247SJustin T. Gibbs else 665717d4247SJustin T. Gibbs *tagenable &= ~devinfo.target_mask; 666717d4247SJustin T. Gibbs } 667717d4247SJustin T. Gibbs 668717d4247SJustin T. Gibbs if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) { 669dd1290f0SJustin T. Gibbs ahc_validate_width(ahc, /*tinfo limit*/NULL, 670dd1290f0SJustin T. Gibbs &spi->bus_width, ROLE_UNKNOWN); 671717d4247SJustin T. Gibbs ahc_set_width(ahc, &devinfo, spi->bus_width, 672717d4247SJustin T. Gibbs update_type, /*paused*/FALSE); 673717d4247SJustin T. Gibbs } 674717d4247SJustin T. Gibbs 675717d4247SJustin T. Gibbs if ((spi->valid & CTS_SPI_VALID_PPR_OPTIONS) == 0) { 676717d4247SJustin T. Gibbs if (update_type == AHC_TRANS_USER) 677717d4247SJustin T. Gibbs spi->ppr_options = tinfo->user.ppr_options; 678717d4247SJustin T. Gibbs else 679717d4247SJustin T. Gibbs spi->ppr_options = tinfo->goal.ppr_options; 680717d4247SJustin T. Gibbs } 681717d4247SJustin T. Gibbs 682717d4247SJustin T. Gibbs if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) == 0) { 683717d4247SJustin T. Gibbs if (update_type == AHC_TRANS_USER) 684717d4247SJustin T. Gibbs spi->sync_offset = tinfo->user.offset; 685717d4247SJustin T. Gibbs else 686717d4247SJustin T. Gibbs spi->sync_offset = tinfo->goal.offset; 687717d4247SJustin T. Gibbs } 688717d4247SJustin T. Gibbs 689717d4247SJustin T. Gibbs if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) == 0) { 690717d4247SJustin T. Gibbs if (update_type == AHC_TRANS_USER) 691717d4247SJustin T. Gibbs spi->sync_period = tinfo->user.period; 692717d4247SJustin T. Gibbs else 693717d4247SJustin T. Gibbs spi->sync_period = tinfo->goal.period; 694717d4247SJustin T. Gibbs } 695717d4247SJustin T. Gibbs 696717d4247SJustin T. Gibbs if (((spi->valid & CTS_SPI_VALID_SYNC_RATE) != 0) 697717d4247SJustin T. Gibbs || ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0)) { 698717d4247SJustin T. Gibbs struct ahc_syncrate *syncrate; 699717d4247SJustin T. Gibbs u_int maxsync; 700717d4247SJustin T. Gibbs 701717d4247SJustin T. Gibbs if ((ahc->features & AHC_ULTRA2) != 0) 702717d4247SJustin T. Gibbs maxsync = AHC_SYNCRATE_DT; 703717d4247SJustin T. Gibbs else if ((ahc->features & AHC_ULTRA) != 0) 704717d4247SJustin T. Gibbs maxsync = AHC_SYNCRATE_ULTRA; 705717d4247SJustin T. Gibbs else 706717d4247SJustin T. Gibbs maxsync = AHC_SYNCRATE_FAST; 707717d4247SJustin T. Gibbs 7088f214efcSJustin T. Gibbs if (spi->bus_width != MSG_EXT_WDTR_BUS_16_BIT) 7098f214efcSJustin T. Gibbs spi->ppr_options &= ~MSG_EXT_PPR_DT_REQ; 7108f214efcSJustin T. Gibbs 711717d4247SJustin T. Gibbs syncrate = ahc_find_syncrate(ahc, &spi->sync_period, 712717d4247SJustin T. Gibbs &spi->ppr_options, 713717d4247SJustin T. Gibbs maxsync); 714dd1290f0SJustin T. Gibbs ahc_validate_offset(ahc, /*tinfo limit*/NULL, 715dd1290f0SJustin T. Gibbs syncrate, &spi->sync_offset, 716dd1290f0SJustin T. Gibbs spi->bus_width, ROLE_UNKNOWN); 717717d4247SJustin T. Gibbs 718717d4247SJustin T. Gibbs /* We use a period of 0 to represent async */ 719717d4247SJustin T. Gibbs if (spi->sync_offset == 0) { 720717d4247SJustin T. Gibbs spi->sync_period = 0; 721717d4247SJustin T. Gibbs spi->ppr_options = 0; 722717d4247SJustin T. Gibbs } 723717d4247SJustin T. Gibbs 724717d4247SJustin T. Gibbs ahc_set_syncrate(ahc, &devinfo, syncrate, 725717d4247SJustin T. Gibbs spi->sync_period, spi->sync_offset, 726717d4247SJustin T. Gibbs spi->ppr_options, update_type, 727717d4247SJustin T. Gibbs /*paused*/FALSE); 728717d4247SJustin T. Gibbs } 729717d4247SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 730717d4247SJustin T. Gibbs xpt_done(ccb); 731717d4247SJustin T. Gibbs break; 732717d4247SJustin T. Gibbs } 733717d4247SJustin T. Gibbs case XPT_GET_TRAN_SETTINGS: 734717d4247SJustin T. Gibbs /* Get default/user set transfer settings for the target */ 735717d4247SJustin T. Gibbs { 736717d4247SJustin T. Gibbs ahc_get_tran_settings(ahc, SIM_SCSI_ID(ahc, sim), 737717d4247SJustin T. Gibbs SIM_CHANNEL(ahc, sim), &ccb->cts); 738717d4247SJustin T. Gibbs xpt_done(ccb); 739717d4247SJustin T. Gibbs break; 740717d4247SJustin T. Gibbs } 741717d4247SJustin T. Gibbs case XPT_CALC_GEOMETRY: 742717d4247SJustin T. Gibbs { 743717d4247SJustin T. Gibbs int extended; 744717d4247SJustin T. Gibbs 745717d4247SJustin T. Gibbs extended = SIM_IS_SCSIBUS_B(ahc, sim) 746717d4247SJustin T. Gibbs ? ahc->flags & AHC_EXTENDED_TRANS_B 747717d4247SJustin T. Gibbs : ahc->flags & AHC_EXTENDED_TRANS_A; 748b3b25f2cSJustin T. Gibbs aic_calc_geometry(&ccb->ccg, extended); 749717d4247SJustin T. Gibbs xpt_done(ccb); 750717d4247SJustin T. Gibbs break; 751717d4247SJustin T. Gibbs } 752717d4247SJustin T. Gibbs case XPT_RESET_BUS: /* Reset the specified SCSI bus */ 753717d4247SJustin T. Gibbs { 754717d4247SJustin T. Gibbs int found; 755717d4247SJustin T. Gibbs 756717d4247SJustin T. Gibbs found = ahc_reset_channel(ahc, SIM_CHANNEL(ahc, sim), 757717d4247SJustin T. Gibbs /*initiate reset*/TRUE); 758717d4247SJustin T. Gibbs if (bootverbose) { 759717d4247SJustin T. Gibbs xpt_print_path(SIM_PATH(ahc, sim)); 760717d4247SJustin T. Gibbs printf("SCSI bus reset delivered. " 761717d4247SJustin T. Gibbs "%d SCBs aborted.\n", found); 762717d4247SJustin T. Gibbs } 763717d4247SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 764717d4247SJustin T. Gibbs xpt_done(ccb); 765717d4247SJustin T. Gibbs break; 766717d4247SJustin T. Gibbs } 767717d4247SJustin T. Gibbs case XPT_TERM_IO: /* Terminate the I/O process */ 768717d4247SJustin T. Gibbs /* XXX Implement */ 769717d4247SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_INVALID; 770717d4247SJustin T. Gibbs xpt_done(ccb); 771717d4247SJustin T. Gibbs break; 772717d4247SJustin T. Gibbs case XPT_PATH_INQ: /* Path routing inquiry */ 773717d4247SJustin T. Gibbs { 774717d4247SJustin T. Gibbs struct ccb_pathinq *cpi = &ccb->cpi; 775717d4247SJustin T. Gibbs 776717d4247SJustin T. Gibbs cpi->version_num = 1; /* XXX??? */ 777717d4247SJustin T. Gibbs cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE; 778717d4247SJustin T. Gibbs if ((ahc->features & AHC_WIDE) != 0) 779717d4247SJustin T. Gibbs cpi->hba_inquiry |= PI_WIDE_16; 780dd1290f0SJustin T. Gibbs if ((ahc->features & AHC_TARGETMODE) != 0) { 781717d4247SJustin T. Gibbs cpi->target_sprt = PIT_PROCESSOR 782717d4247SJustin T. Gibbs | PIT_DISCONNECT 783717d4247SJustin T. Gibbs | PIT_TERM_IO; 784717d4247SJustin T. Gibbs } else { 785717d4247SJustin T. Gibbs cpi->target_sprt = 0; 786717d4247SJustin T. Gibbs } 787dd1290f0SJustin T. Gibbs cpi->hba_misc = 0; 788717d4247SJustin T. Gibbs cpi->hba_eng_cnt = 0; 789717d4247SJustin T. Gibbs cpi->max_target = (ahc->features & AHC_WIDE) ? 15 : 7; 79056a7c4a8SJustin T. Gibbs cpi->max_lun = AHC_NUM_LUNS - 1; 791717d4247SJustin T. Gibbs if (SIM_IS_SCSIBUS_B(ahc, sim)) { 792717d4247SJustin T. Gibbs cpi->initiator_id = ahc->our_id_b; 793717d4247SJustin T. Gibbs if ((ahc->flags & AHC_RESET_BUS_B) == 0) 794717d4247SJustin T. Gibbs cpi->hba_misc |= PIM_NOBUSRESET; 795717d4247SJustin T. Gibbs } else { 796717d4247SJustin T. Gibbs cpi->initiator_id = ahc->our_id; 797717d4247SJustin T. Gibbs if ((ahc->flags & AHC_RESET_BUS_A) == 0) 798717d4247SJustin T. Gibbs cpi->hba_misc |= PIM_NOBUSRESET; 799717d4247SJustin T. Gibbs } 800717d4247SJustin T. Gibbs cpi->bus_id = cam_sim_bus(sim); 801717d4247SJustin T. Gibbs cpi->base_transfer_speed = 3300; 8024195c7deSAlan Somers strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 8034195c7deSAlan Somers strlcpy(cpi->hba_vid, "Adaptec", HBA_IDLEN); 8044195c7deSAlan Somers strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 805717d4247SJustin T. Gibbs cpi->unit_number = cam_sim_unit(sim); 806717d4247SJustin T. Gibbs cpi->protocol = PROTO_SCSI; 807717d4247SJustin T. Gibbs cpi->protocol_version = SCSI_REV_2; 808717d4247SJustin T. Gibbs cpi->transport = XPORT_SPI; 809717d4247SJustin T. Gibbs cpi->transport_version = 2; 810717d4247SJustin T. Gibbs cpi->xport_specific.spi.ppr_options = SID_SPI_CLOCK_ST; 811717d4247SJustin T. Gibbs if ((ahc->features & AHC_DT) != 0) { 812717d4247SJustin T. Gibbs cpi->transport_version = 3; 813717d4247SJustin T. Gibbs cpi->xport_specific.spi.ppr_options = 814717d4247SJustin T. Gibbs SID_SPI_CLOCK_DT_ST; 815717d4247SJustin T. Gibbs } 816717d4247SJustin T. Gibbs cpi->ccb_h.status = CAM_REQ_CMP; 817717d4247SJustin T. Gibbs xpt_done(ccb); 818717d4247SJustin T. Gibbs break; 819717d4247SJustin T. Gibbs } 820717d4247SJustin T. Gibbs default: 821dd1290f0SJustin T. Gibbs ccb->ccb_h.status = CAM_PROVIDE_FAIL; 822717d4247SJustin T. Gibbs xpt_done(ccb); 823717d4247SJustin T. Gibbs break; 824717d4247SJustin T. Gibbs } 825717d4247SJustin T. Gibbs } 826717d4247SJustin T. Gibbs 827717d4247SJustin T. Gibbs static void 828717d4247SJustin T. Gibbs ahc_get_tran_settings(struct ahc_softc *ahc, int our_id, char channel, 829717d4247SJustin T. Gibbs struct ccb_trans_settings *cts) 830717d4247SJustin T. Gibbs { 831717d4247SJustin T. Gibbs struct ahc_devinfo devinfo; 832717d4247SJustin T. Gibbs struct ccb_trans_settings_scsi *scsi; 833717d4247SJustin T. Gibbs struct ccb_trans_settings_spi *spi; 834717d4247SJustin T. Gibbs struct ahc_initiator_tinfo *targ_info; 835b95de6daSJustin T. Gibbs struct ahc_tmode_tstate *tstate; 836717d4247SJustin T. Gibbs struct ahc_transinfo *tinfo; 837717d4247SJustin T. Gibbs 838717d4247SJustin T. Gibbs scsi = &cts->proto_specific.scsi; 839717d4247SJustin T. Gibbs spi = &cts->xport_specific.spi; 840717d4247SJustin T. Gibbs ahc_compile_devinfo(&devinfo, our_id, 841717d4247SJustin T. Gibbs cts->ccb_h.target_id, 842717d4247SJustin T. Gibbs cts->ccb_h.target_lun, 843717d4247SJustin T. Gibbs channel, ROLE_UNKNOWN); 844717d4247SJustin T. Gibbs targ_info = ahc_fetch_transinfo(ahc, devinfo.channel, 845717d4247SJustin T. Gibbs devinfo.our_scsiid, 846717d4247SJustin T. Gibbs devinfo.target, &tstate); 847717d4247SJustin T. Gibbs 848717d4247SJustin T. Gibbs if (cts->type == CTS_TYPE_CURRENT_SETTINGS) 84958fb7d8eSJustin T. Gibbs tinfo = &targ_info->curr; 850717d4247SJustin T. Gibbs else 851717d4247SJustin T. Gibbs tinfo = &targ_info->user; 852717d4247SJustin T. Gibbs 853717d4247SJustin T. Gibbs scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 854717d4247SJustin T. Gibbs spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB; 855717d4247SJustin T. Gibbs if (cts->type == CTS_TYPE_USER_SETTINGS) { 856717d4247SJustin T. Gibbs if ((ahc->user_discenable & devinfo.target_mask) != 0) 857717d4247SJustin T. Gibbs spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 858717d4247SJustin T. Gibbs 859717d4247SJustin T. Gibbs if ((ahc->user_tagenable & devinfo.target_mask) != 0) 860717d4247SJustin T. Gibbs scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; 861717d4247SJustin T. Gibbs } else { 862717d4247SJustin T. Gibbs if ((tstate->discenable & devinfo.target_mask) != 0) 863717d4247SJustin T. Gibbs spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 864717d4247SJustin T. Gibbs 865717d4247SJustin T. Gibbs if ((tstate->tagenable & devinfo.target_mask) != 0) 866717d4247SJustin T. Gibbs scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; 867717d4247SJustin T. Gibbs } 868717d4247SJustin T. Gibbs cts->protocol_version = tinfo->protocol_version; 869717d4247SJustin T. Gibbs cts->transport_version = tinfo->transport_version; 870717d4247SJustin T. Gibbs 871717d4247SJustin T. Gibbs spi->sync_period = tinfo->period; 872717d4247SJustin T. Gibbs spi->sync_offset = tinfo->offset; 873717d4247SJustin T. Gibbs spi->bus_width = tinfo->width; 874717d4247SJustin T. Gibbs spi->ppr_options = tinfo->ppr_options; 875717d4247SJustin T. Gibbs 876717d4247SJustin T. Gibbs cts->protocol = PROTO_SCSI; 877717d4247SJustin T. Gibbs cts->transport = XPORT_SPI; 878717d4247SJustin T. Gibbs spi->valid = CTS_SPI_VALID_SYNC_RATE 879717d4247SJustin T. Gibbs | CTS_SPI_VALID_SYNC_OFFSET 880717d4247SJustin T. Gibbs | CTS_SPI_VALID_BUS_WIDTH 881717d4247SJustin T. Gibbs | CTS_SPI_VALID_PPR_OPTIONS; 882717d4247SJustin T. Gibbs 883ff0c1dafSJustin T. Gibbs if (cts->ccb_h.target_lun != CAM_LUN_WILDCARD) { 884ff0c1dafSJustin T. Gibbs scsi->valid = CTS_SCSI_VALID_TQ; 885ff0c1dafSJustin T. Gibbs spi->valid |= CTS_SPI_VALID_DISC; 886ff0c1dafSJustin T. Gibbs } else { 887ff0c1dafSJustin T. Gibbs scsi->valid = 0; 888ff0c1dafSJustin T. Gibbs } 889ff0c1dafSJustin T. Gibbs 890717d4247SJustin T. Gibbs cts->ccb_h.status = CAM_REQ_CMP; 891717d4247SJustin T. Gibbs } 892717d4247SJustin T. Gibbs 893717d4247SJustin T. Gibbs static void 894717d4247SJustin T. Gibbs ahc_async(void *callback_arg, uint32_t code, struct cam_path *path, void *arg) 895717d4247SJustin T. Gibbs { 896717d4247SJustin T. Gibbs struct ahc_softc *ahc; 897717d4247SJustin T. Gibbs struct cam_sim *sim; 898717d4247SJustin T. Gibbs 899717d4247SJustin T. Gibbs sim = (struct cam_sim *)callback_arg; 900717d4247SJustin T. Gibbs ahc = (struct ahc_softc *)cam_sim_softc(sim); 901717d4247SJustin T. Gibbs switch (code) { 902717d4247SJustin T. Gibbs case AC_LOST_DEVICE: 903717d4247SJustin T. Gibbs { 904717d4247SJustin T. Gibbs struct ahc_devinfo devinfo; 905717d4247SJustin T. Gibbs 906717d4247SJustin T. Gibbs ahc_compile_devinfo(&devinfo, SIM_SCSI_ID(ahc, sim), 907717d4247SJustin T. Gibbs xpt_path_target_id(path), 908717d4247SJustin T. Gibbs xpt_path_lun_id(path), 909717d4247SJustin T. Gibbs SIM_CHANNEL(ahc, sim), 910717d4247SJustin T. Gibbs ROLE_UNKNOWN); 911717d4247SJustin T. Gibbs 912717d4247SJustin T. Gibbs /* 913717d4247SJustin T. Gibbs * Revert to async/narrow transfers 914717d4247SJustin T. Gibbs * for the next device. 915717d4247SJustin T. Gibbs */ 916717d4247SJustin T. Gibbs ahc_set_width(ahc, &devinfo, MSG_EXT_WDTR_BUS_8_BIT, 917717d4247SJustin T. Gibbs AHC_TRANS_GOAL|AHC_TRANS_CUR, /*paused*/FALSE); 918717d4247SJustin T. Gibbs ahc_set_syncrate(ahc, &devinfo, /*syncrate*/NULL, 919717d4247SJustin T. Gibbs /*period*/0, /*offset*/0, /*ppr_options*/0, 920717d4247SJustin T. Gibbs AHC_TRANS_GOAL|AHC_TRANS_CUR, 921717d4247SJustin T. Gibbs /*paused*/FALSE); 922717d4247SJustin T. Gibbs break; 923717d4247SJustin T. Gibbs } 924717d4247SJustin T. Gibbs default: 925717d4247SJustin T. Gibbs break; 926717d4247SJustin T. Gibbs } 927717d4247SJustin T. Gibbs } 928717d4247SJustin T. Gibbs 929717d4247SJustin T. Gibbs static void 930717d4247SJustin T. Gibbs ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments, 931717d4247SJustin T. Gibbs int error) 932717d4247SJustin T. Gibbs { 933717d4247SJustin T. Gibbs struct scb *scb; 934717d4247SJustin T. Gibbs union ccb *ccb; 935717d4247SJustin T. Gibbs struct ahc_softc *ahc; 936ff0c1dafSJustin T. Gibbs struct ahc_initiator_tinfo *tinfo; 937b95de6daSJustin T. Gibbs struct ahc_tmode_tstate *tstate; 938ff0c1dafSJustin T. Gibbs u_int mask; 939717d4247SJustin T. Gibbs 940717d4247SJustin T. Gibbs scb = (struct scb *)arg; 941717d4247SJustin T. Gibbs ccb = scb->io_ctx; 94270351c9aSJustin T. Gibbs ahc = scb->ahc_softc; 943717d4247SJustin T. Gibbs 944717d4247SJustin T. Gibbs if (error != 0) { 945717d4247SJustin T. Gibbs if (error == EFBIG) 946b3b25f2cSJustin T. Gibbs aic_set_transaction_status(scb, CAM_REQ_TOO_BIG); 947717d4247SJustin T. Gibbs else 948b3b25f2cSJustin T. Gibbs aic_set_transaction_status(scb, CAM_REQ_CMP_ERR); 949717d4247SJustin T. Gibbs if (nsegments != 0) 950717d4247SJustin T. Gibbs bus_dmamap_unload(ahc->buffer_dmat, scb->dmamap); 951717d4247SJustin T. Gibbs ahc_free_scb(ahc, scb); 952717d4247SJustin T. Gibbs xpt_done(ccb); 953717d4247SJustin T. Gibbs return; 954717d4247SJustin T. Gibbs } 955717d4247SJustin T. Gibbs if (nsegments != 0) { 956717d4247SJustin T. Gibbs struct ahc_dma_seg *sg; 957717d4247SJustin T. Gibbs bus_dma_segment_t *end_seg; 958717d4247SJustin T. Gibbs 959717d4247SJustin T. Gibbs end_seg = dm_segs + nsegments; 960717d4247SJustin T. Gibbs 961717d4247SJustin T. Gibbs /* Copy the segments into our SG list */ 962717d4247SJustin T. Gibbs sg = scb->sg_list; 963717d4247SJustin T. Gibbs while (dm_segs < end_seg) { 964cd036e89SJustin T. Gibbs uint32_t len; 965cd036e89SJustin T. Gibbs 966b3b25f2cSJustin T. Gibbs sg->addr = aic_htole32(dm_segs->ds_addr); 967cd036e89SJustin T. Gibbs len = dm_segs->ds_len 968cd036e89SJustin T. Gibbs | ((dm_segs->ds_addr >> 8) & 0x7F000000); 969b3b25f2cSJustin T. Gibbs sg->len = aic_htole32(len); 970717d4247SJustin T. Gibbs sg++; 971717d4247SJustin T. Gibbs dm_segs++; 972717d4247SJustin T. Gibbs } 973717d4247SJustin T. Gibbs 974717d4247SJustin T. Gibbs /* 975717d4247SJustin T. Gibbs * Note where to find the SG entries in bus space. 976717d4247SJustin T. Gibbs * We also set the full residual flag which the 977717d4247SJustin T. Gibbs * sequencer will clear as soon as a data transfer 978717d4247SJustin T. Gibbs * occurs. 979717d4247SJustin T. Gibbs */ 980b3b25f2cSJustin T. Gibbs scb->hscb->sgptr = aic_htole32(scb->sg_list_phys|SG_FULL_RESID); 981717d4247SJustin T. Gibbs 982*9dcf3957SKyle Evans ahc_sync_ccb(ahc, scb, ccb, false); 983717d4247SJustin T. Gibbs 984717d4247SJustin T. Gibbs if (ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) { 985717d4247SJustin T. Gibbs struct target_data *tdata; 986717d4247SJustin T. Gibbs 987717d4247SJustin T. Gibbs tdata = &scb->hscb->shared_data.tdata; 988717d4247SJustin T. Gibbs tdata->target_phases |= DPHASE_PENDING; 989b3b25f2cSJustin T. Gibbs /* 990b3b25f2cSJustin T. Gibbs * CAM data direction is relative to the initiator. 991b3b25f2cSJustin T. Gibbs */ 992717d4247SJustin T. Gibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) 993717d4247SJustin T. Gibbs tdata->data_phase = P_DATAOUT; 994717d4247SJustin T. Gibbs else 995717d4247SJustin T. Gibbs tdata->data_phase = P_DATAIN; 996717d4247SJustin T. Gibbs 997717d4247SJustin T. Gibbs /* 998717d4247SJustin T. Gibbs * If the transfer is of an odd length and in the 999717d4247SJustin T. Gibbs * "in" direction (scsi->HostBus), then it may 1000717d4247SJustin T. Gibbs * trigger a bug in the 'WideODD' feature of 1001717d4247SJustin T. Gibbs * non-Ultra2 chips. Force the total data-length 1002717d4247SJustin T. Gibbs * to be even by adding an extra, 1 byte, SG, 1003717d4247SJustin T. Gibbs * element. We do this even if we are not currently 1004717d4247SJustin T. Gibbs * negotiated wide as negotiation could occur before 1005717d4247SJustin T. Gibbs * this command is executed. 1006717d4247SJustin T. Gibbs */ 1007717d4247SJustin T. Gibbs if ((ahc->bugs & AHC_TMODE_WIDEODD_BUG) != 0 1008717d4247SJustin T. Gibbs && (ccb->csio.dxfer_len & 0x1) != 0 1009b3b25f2cSJustin T. Gibbs && (ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) { 1010717d4247SJustin T. Gibbs nsegments++; 1011717d4247SJustin T. Gibbs if (nsegments > AHC_NSEG) { 1012b3b25f2cSJustin T. Gibbs aic_set_transaction_status(scb, 1013717d4247SJustin T. Gibbs CAM_REQ_TOO_BIG); 1014717d4247SJustin T. Gibbs bus_dmamap_unload(ahc->buffer_dmat, 1015717d4247SJustin T. Gibbs scb->dmamap); 1016717d4247SJustin T. Gibbs ahc_free_scb(ahc, scb); 1017717d4247SJustin T. Gibbs xpt_done(ccb); 1018717d4247SJustin T. Gibbs return; 1019717d4247SJustin T. Gibbs } 1020b3b25f2cSJustin T. Gibbs sg->addr = aic_htole32(ahc->dma_bug_buf); 1021b3b25f2cSJustin T. Gibbs sg->len = aic_htole32(1); 1022717d4247SJustin T. Gibbs sg++; 1023717d4247SJustin T. Gibbs } 1024717d4247SJustin T. Gibbs } 1025717d4247SJustin T. Gibbs sg--; 1026b3b25f2cSJustin T. Gibbs sg->len |= aic_htole32(AHC_DMA_LAST_SEG); 1027717d4247SJustin T. Gibbs 1028717d4247SJustin T. Gibbs /* Copy the first SG into the "current" data pointer area */ 1029717d4247SJustin T. Gibbs scb->hscb->dataptr = scb->sg_list->addr; 1030717d4247SJustin T. Gibbs scb->hscb->datacnt = scb->sg_list->len; 1031717d4247SJustin T. Gibbs } else { 1032b3b25f2cSJustin T. Gibbs scb->hscb->sgptr = aic_htole32(SG_LIST_NULL); 1033717d4247SJustin T. Gibbs scb->hscb->dataptr = 0; 1034717d4247SJustin T. Gibbs scb->hscb->datacnt = 0; 1035717d4247SJustin T. Gibbs } 1036717d4247SJustin T. Gibbs 1037717d4247SJustin T. Gibbs scb->sg_count = nsegments; 1038717d4247SJustin T. Gibbs 1039717d4247SJustin T. Gibbs /* 1040717d4247SJustin T. Gibbs * Last time we need to check if this SCB needs to 1041717d4247SJustin T. Gibbs * be aborted. 1042717d4247SJustin T. Gibbs */ 1043b3b25f2cSJustin T. Gibbs if (aic_get_transaction_status(scb) != CAM_REQ_INPROG) { 1044717d4247SJustin T. Gibbs if (nsegments != 0) 10458f214efcSJustin T. Gibbs bus_dmamap_unload(ahc->buffer_dmat, scb->dmamap); 1046717d4247SJustin T. Gibbs ahc_free_scb(ahc, scb); 1047a49630acSJustin T. Gibbs xpt_done(ccb); 1048717d4247SJustin T. Gibbs return; 1049717d4247SJustin T. Gibbs } 1050717d4247SJustin T. Gibbs 1051ff0c1dafSJustin T. Gibbs tinfo = ahc_fetch_transinfo(ahc, SCSIID_CHANNEL(ahc, scb->hscb->scsiid), 1052ff0c1dafSJustin T. Gibbs SCSIID_OUR_ID(scb->hscb->scsiid), 1053dd1290f0SJustin T. Gibbs SCSIID_TARGET(ahc, scb->hscb->scsiid), 1054dd1290f0SJustin T. Gibbs &tstate); 1055ff0c1dafSJustin T. Gibbs 1056ff0c1dafSJustin T. Gibbs mask = SCB_GET_TARGET_MASK(ahc, scb); 1057ff0c1dafSJustin T. Gibbs scb->hscb->scsirate = tinfo->scsirate; 105858fb7d8eSJustin T. Gibbs scb->hscb->scsioffset = tinfo->curr.offset; 1059ff0c1dafSJustin T. Gibbs if ((tstate->ultraenb & mask) != 0) 1060ff0c1dafSJustin T. Gibbs scb->hscb->control |= ULTRAENB; 1061ff0c1dafSJustin T. Gibbs 1062ff0c1dafSJustin T. Gibbs if ((tstate->discenable & mask) != 0 1063ff0c1dafSJustin T. Gibbs && (ccb->ccb_h.flags & CAM_DIS_DISCONNECT) == 0) 1064ff0c1dafSJustin T. Gibbs scb->hscb->control |= DISCENB; 1065ff0c1dafSJustin T. Gibbs 1066ff0c1dafSJustin T. Gibbs if ((ccb->ccb_h.flags & CAM_NEGOTIATE) != 0 106756a7c4a8SJustin T. Gibbs && (tinfo->goal.width != 0 1068226aa6eaSJustin T. Gibbs || tinfo->goal.offset != 0 106956a7c4a8SJustin T. Gibbs || tinfo->goal.ppr_options != 0)) { 1070ff0c1dafSJustin T. Gibbs scb->flags |= SCB_NEGOTIATE; 1071ff0c1dafSJustin T. Gibbs scb->hscb->control |= MK_MESSAGE; 1072b95de6daSJustin T. Gibbs } else if ((tstate->auto_negotiate & mask) != 0) { 1073b95de6daSJustin T. Gibbs scb->flags |= SCB_AUTO_NEGOTIATE; 1074b95de6daSJustin T. Gibbs scb->hscb->control |= MK_MESSAGE; 1075ff0c1dafSJustin T. Gibbs } 1076ff0c1dafSJustin T. Gibbs 1077717d4247SJustin T. Gibbs LIST_INSERT_HEAD(&ahc->pending_scbs, scb, pending_links); 1078717d4247SJustin T. Gibbs 1079717d4247SJustin T. Gibbs ccb->ccb_h.status |= CAM_SIM_QUEUED; 1080717d4247SJustin T. Gibbs 1081717d4247SJustin T. Gibbs /* 1082717d4247SJustin T. Gibbs * We only allow one untagged transaction 1083717d4247SJustin T. Gibbs * per target in the initiator role unless 1084717d4247SJustin T. Gibbs * we are storing a full busy target *lun* 1085717d4247SJustin T. Gibbs * table in SCB space. 1086717d4247SJustin T. Gibbs */ 1087717d4247SJustin T. Gibbs if ((scb->hscb->control & (TARGET_SCB|TAG_ENB)) == 0 1088a5847d5cSJustin T. Gibbs && (ahc->flags & AHC_SCB_BTT) == 0) { 1089717d4247SJustin T. Gibbs struct scb_tailq *untagged_q; 10901478c711SJustin T. Gibbs int target_offset; 1091717d4247SJustin T. Gibbs 10921478c711SJustin T. Gibbs target_offset = SCB_GET_TARGET_OFFSET(ahc, scb); 10931478c711SJustin T. Gibbs untagged_q = &(ahc->untagged_queues[target_offset]); 1094717d4247SJustin T. Gibbs TAILQ_INSERT_TAIL(untagged_q, scb, links.tqe); 109570351c9aSJustin T. Gibbs scb->flags |= SCB_UNTAGGEDQ; 1096717d4247SJustin T. Gibbs if (TAILQ_FIRST(untagged_q) != scb) { 1097717d4247SJustin T. Gibbs return; 1098717d4247SJustin T. Gibbs } 1099717d4247SJustin T. Gibbs } 1100717d4247SJustin T. Gibbs scb->flags |= SCB_ACTIVE; 1101717d4247SJustin T. Gibbs 11027afc0218SJustin T. Gibbs /* 11037afc0218SJustin T. Gibbs * Timers are disabled while recovery is in progress. 11047afc0218SJustin T. Gibbs */ 11057afc0218SJustin T. Gibbs aic_scb_timer_start(scb); 11067afc0218SJustin T. Gibbs 1107717d4247SJustin T. Gibbs if ((scb->flags & SCB_TARGET_IMMEDIATE) != 0) { 1108b95de6daSJustin T. Gibbs /* Define a mapping from our tag to the SCB. */ 1109b95de6daSJustin T. Gibbs ahc->scb_data->scbindex[scb->hscb->tag] = scb; 11106fb77fefSJustin T. Gibbs ahc_pause(ahc); 1111717d4247SJustin T. Gibbs if ((ahc->flags & AHC_PAGESCBS) == 0) 1112717d4247SJustin T. Gibbs ahc_outb(ahc, SCBPTR, scb->hscb->tag); 1113226aa6eaSJustin T. Gibbs ahc_outb(ahc, TARG_IMMEDIATE_SCB, scb->hscb->tag); 11146fb77fefSJustin T. Gibbs ahc_unpause(ahc); 1115717d4247SJustin T. Gibbs } else { 1116717d4247SJustin T. Gibbs ahc_queue_scb(ahc, scb); 1117717d4247SJustin T. Gibbs } 1118717d4247SJustin T. Gibbs } 1119717d4247SJustin T. Gibbs 1120717d4247SJustin T. Gibbs static void 1121717d4247SJustin T. Gibbs ahc_poll(struct cam_sim *sim) 1122717d4247SJustin T. Gibbs { 1123226aa6eaSJustin T. Gibbs struct ahc_softc *ahc; 1124226aa6eaSJustin T. Gibbs 1125226aa6eaSJustin T. Gibbs ahc = (struct ahc_softc *)cam_sim_softc(sim); 1126226aa6eaSJustin T. Gibbs ahc_intr(ahc); 1127717d4247SJustin T. Gibbs } 1128717d4247SJustin T. Gibbs 1129717d4247SJustin T. Gibbs static void 1130717d4247SJustin T. Gibbs ahc_setup_data(struct ahc_softc *ahc, struct cam_sim *sim, 1131717d4247SJustin T. Gibbs struct ccb_scsiio *csio, struct scb *scb) 1132717d4247SJustin T. Gibbs { 1133717d4247SJustin T. Gibbs struct hardware_scb *hscb; 1134717d4247SJustin T. Gibbs struct ccb_hdr *ccb_h; 1135dd0b4fb6SKonstantin Belousov int error; 1136717d4247SJustin T. Gibbs 1137717d4247SJustin T. Gibbs hscb = scb->hscb; 1138717d4247SJustin T. Gibbs ccb_h = &csio->ccb_h; 1139717d4247SJustin T. Gibbs 1140cd036e89SJustin T. Gibbs csio->resid = 0; 1141cd036e89SJustin T. Gibbs csio->sense_resid = 0; 1142717d4247SJustin T. Gibbs if (ccb_h->func_code == XPT_SCSI_IO) { 1143717d4247SJustin T. Gibbs hscb->cdb_len = csio->cdb_len; 1144717d4247SJustin T. Gibbs if ((ccb_h->flags & CAM_CDB_POINTER) != 0) { 1145717d4247SJustin T. Gibbs if (hscb->cdb_len > sizeof(hscb->cdb32) 1146717d4247SJustin T. Gibbs || (ccb_h->flags & CAM_CDB_PHYS) != 0) { 1147b3b25f2cSJustin T. Gibbs aic_set_transaction_status(scb, 1148717d4247SJustin T. Gibbs CAM_REQ_INVALID); 1149717d4247SJustin T. Gibbs ahc_free_scb(ahc, scb); 1150a49630acSJustin T. Gibbs xpt_done((union ccb *)csio); 1151717d4247SJustin T. Gibbs return; 1152717d4247SJustin T. Gibbs } 1153717d4247SJustin T. Gibbs if (hscb->cdb_len > 12) { 1154717d4247SJustin T. Gibbs memcpy(hscb->cdb32, 1155717d4247SJustin T. Gibbs csio->cdb_io.cdb_ptr, 1156717d4247SJustin T. Gibbs hscb->cdb_len); 1157dd1290f0SJustin T. Gibbs scb->flags |= SCB_CDB32_PTR; 1158717d4247SJustin T. Gibbs } else { 1159717d4247SJustin T. Gibbs memcpy(hscb->shared_data.cdb, 1160717d4247SJustin T. Gibbs csio->cdb_io.cdb_ptr, 1161717d4247SJustin T. Gibbs hscb->cdb_len); 1162717d4247SJustin T. Gibbs } 1163717d4247SJustin T. Gibbs } else { 1164717d4247SJustin T. Gibbs if (hscb->cdb_len > 12) { 1165717d4247SJustin T. Gibbs memcpy(hscb->cdb32, csio->cdb_io.cdb_bytes, 1166717d4247SJustin T. Gibbs hscb->cdb_len); 1167dd1290f0SJustin T. Gibbs scb->flags |= SCB_CDB32_PTR; 1168717d4247SJustin T. Gibbs } else { 1169717d4247SJustin T. Gibbs memcpy(hscb->shared_data.cdb, 1170717d4247SJustin T. Gibbs csio->cdb_io.cdb_bytes, 1171717d4247SJustin T. Gibbs hscb->cdb_len); 1172717d4247SJustin T. Gibbs } 1173717d4247SJustin T. Gibbs } 1174717d4247SJustin T. Gibbs } 1175717d4247SJustin T. Gibbs 1176dd0b4fb6SKonstantin Belousov error = bus_dmamap_load_ccb(ahc->buffer_dmat, 1177717d4247SJustin T. Gibbs scb->dmamap, 1178dd0b4fb6SKonstantin Belousov (union ccb *)csio, 1179717d4247SJustin T. Gibbs ahc_execute_scb, 1180dd0b4fb6SKonstantin Belousov scb, 1181dd0b4fb6SKonstantin Belousov 0); 1182717d4247SJustin T. Gibbs if (error == EINPROGRESS) { 1183717d4247SJustin T. Gibbs /* 1184717d4247SJustin T. Gibbs * So as to maintain ordering, 1185717d4247SJustin T. Gibbs * freeze the controller queue 1186717d4247SJustin T. Gibbs * until our mapping is 1187717d4247SJustin T. Gibbs * returned. 1188717d4247SJustin T. Gibbs */ 1189dd0b4fb6SKonstantin Belousov xpt_freeze_simq(sim, /*count*/1); 1190dd0b4fb6SKonstantin Belousov scb->io_ctx->ccb_h.status |= CAM_RELEASE_SIMQ; 1191717d4247SJustin T. Gibbs } 1192717d4247SJustin T. Gibbs } 1193717d4247SJustin T. Gibbs 1194717d4247SJustin T. Gibbs static void 1195717d4247SJustin T. Gibbs ahc_abort_ccb(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb) 1196717d4247SJustin T. Gibbs { 1197717d4247SJustin T. Gibbs union ccb *abort_ccb; 1198717d4247SJustin T. Gibbs 1199717d4247SJustin T. Gibbs abort_ccb = ccb->cab.abort_ccb; 1200717d4247SJustin T. Gibbs switch (abort_ccb->ccb_h.func_code) { 1201717d4247SJustin T. Gibbs case XPT_ACCEPT_TARGET_IO: 1202b79dc8a8SKenneth D. Merry case XPT_IMMEDIATE_NOTIFY: 1203717d4247SJustin T. Gibbs case XPT_CONT_TARGET_IO: 1204717d4247SJustin T. Gibbs { 1205b95de6daSJustin T. Gibbs struct ahc_tmode_tstate *tstate; 1206b95de6daSJustin T. Gibbs struct ahc_tmode_lstate *lstate; 1207717d4247SJustin T. Gibbs struct ccb_hdr_slist *list; 1208717d4247SJustin T. Gibbs cam_status status; 1209717d4247SJustin T. Gibbs 1210717d4247SJustin T. Gibbs status = ahc_find_tmode_devs(ahc, sim, abort_ccb, &tstate, 1211717d4247SJustin T. Gibbs &lstate, TRUE); 1212717d4247SJustin T. Gibbs 1213717d4247SJustin T. Gibbs if (status != CAM_REQ_CMP) { 1214717d4247SJustin T. Gibbs ccb->ccb_h.status = status; 1215717d4247SJustin T. Gibbs break; 1216717d4247SJustin T. Gibbs } 1217717d4247SJustin T. Gibbs 1218717d4247SJustin T. Gibbs if (abort_ccb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) 1219717d4247SJustin T. Gibbs list = &lstate->accept_tios; 1220b79dc8a8SKenneth D. Merry else if (abort_ccb->ccb_h.func_code == XPT_IMMEDIATE_NOTIFY) 1221717d4247SJustin T. Gibbs list = &lstate->immed_notifies; 1222717d4247SJustin T. Gibbs else 1223717d4247SJustin T. Gibbs list = NULL; 1224717d4247SJustin T. Gibbs 1225717d4247SJustin T. Gibbs if (list != NULL) { 1226717d4247SJustin T. Gibbs struct ccb_hdr *curelm; 1227717d4247SJustin T. Gibbs int found; 1228717d4247SJustin T. Gibbs 1229717d4247SJustin T. Gibbs curelm = SLIST_FIRST(list); 1230717d4247SJustin T. Gibbs found = 0; 1231717d4247SJustin T. Gibbs if (curelm == &abort_ccb->ccb_h) { 1232717d4247SJustin T. Gibbs found = 1; 1233717d4247SJustin T. Gibbs SLIST_REMOVE_HEAD(list, sim_links.sle); 1234717d4247SJustin T. Gibbs } else { 1235717d4247SJustin T. Gibbs while(curelm != NULL) { 1236717d4247SJustin T. Gibbs struct ccb_hdr *nextelm; 1237717d4247SJustin T. Gibbs 1238717d4247SJustin T. Gibbs nextelm = 1239717d4247SJustin T. Gibbs SLIST_NEXT(curelm, sim_links.sle); 1240717d4247SJustin T. Gibbs 1241717d4247SJustin T. Gibbs if (nextelm == &abort_ccb->ccb_h) { 1242717d4247SJustin T. Gibbs found = 1; 1243717d4247SJustin T. Gibbs SLIST_NEXT(curelm, 1244717d4247SJustin T. Gibbs sim_links.sle) = 1245717d4247SJustin T. Gibbs SLIST_NEXT(nextelm, 1246717d4247SJustin T. Gibbs sim_links.sle); 1247717d4247SJustin T. Gibbs break; 1248717d4247SJustin T. Gibbs } 1249717d4247SJustin T. Gibbs curelm = nextelm; 1250717d4247SJustin T. Gibbs } 1251717d4247SJustin T. Gibbs } 1252717d4247SJustin T. Gibbs 1253717d4247SJustin T. Gibbs if (found) { 1254717d4247SJustin T. Gibbs abort_ccb->ccb_h.status = CAM_REQ_ABORTED; 1255717d4247SJustin T. Gibbs xpt_done(abort_ccb); 1256717d4247SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 1257717d4247SJustin T. Gibbs } else { 1258dd1290f0SJustin T. Gibbs xpt_print_path(abort_ccb->ccb_h.path); 1259717d4247SJustin T. Gibbs printf("Not found\n"); 1260717d4247SJustin T. Gibbs ccb->ccb_h.status = CAM_PATH_INVALID; 1261717d4247SJustin T. Gibbs } 1262717d4247SJustin T. Gibbs break; 1263717d4247SJustin T. Gibbs } 1264717d4247SJustin T. Gibbs /* FALLTHROUGH */ 1265717d4247SJustin T. Gibbs } 1266717d4247SJustin T. Gibbs case XPT_SCSI_IO: 1267717d4247SJustin T. Gibbs /* XXX Fully implement the hard ones */ 1268717d4247SJustin T. Gibbs ccb->ccb_h.status = CAM_UA_ABORT; 1269717d4247SJustin T. Gibbs break; 1270717d4247SJustin T. Gibbs default: 1271717d4247SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_INVALID; 1272717d4247SJustin T. Gibbs break; 1273717d4247SJustin T. Gibbs } 1274717d4247SJustin T. Gibbs xpt_done(ccb); 1275717d4247SJustin T. Gibbs } 1276717d4247SJustin T. Gibbs 1277717d4247SJustin T. Gibbs void 1278c498406dSJustin T. Gibbs ahc_send_async(struct ahc_softc *ahc, char channel, u_int target, 127958fb7d8eSJustin T. Gibbs u_int lun, ac_code code, void *opt_arg) 1280717d4247SJustin T. Gibbs { 1281717d4247SJustin T. Gibbs struct ccb_trans_settings cts; 1282717d4247SJustin T. Gibbs struct cam_path *path; 1283717d4247SJustin T. Gibbs void *arg; 1284717d4247SJustin T. Gibbs int error; 1285717d4247SJustin T. Gibbs 1286717d4247SJustin T. Gibbs arg = NULL; 1287c498406dSJustin T. Gibbs error = ahc_create_path(ahc, channel, target, lun, &path); 1288717d4247SJustin T. Gibbs 1289717d4247SJustin T. Gibbs if (error != CAM_REQ_CMP) 1290717d4247SJustin T. Gibbs return; 1291717d4247SJustin T. Gibbs 1292717d4247SJustin T. Gibbs switch (code) { 1293717d4247SJustin T. Gibbs case AC_TRANSFER_NEG: 129458fb7d8eSJustin T. Gibbs { 129558fb7d8eSJustin T. Gibbs struct ccb_trans_settings_scsi *scsi; 129658fb7d8eSJustin T. Gibbs 1297717d4247SJustin T. Gibbs cts.type = CTS_TYPE_CURRENT_SETTINGS; 129858fb7d8eSJustin T. Gibbs scsi = &cts.proto_specific.scsi; 1299717d4247SJustin T. Gibbs cts.ccb_h.path = path; 1300c498406dSJustin T. Gibbs cts.ccb_h.target_id = target; 1301c498406dSJustin T. Gibbs cts.ccb_h.target_lun = lun; 1302c498406dSJustin T. Gibbs ahc_get_tran_settings(ahc, channel == 'A' ? ahc->our_id 1303c498406dSJustin T. Gibbs : ahc->our_id_b, 1304c498406dSJustin T. Gibbs channel, &cts); 1305717d4247SJustin T. Gibbs arg = &cts; 130658fb7d8eSJustin T. Gibbs scsi->valid &= ~CTS_SCSI_VALID_TQ; 130758fb7d8eSJustin T. Gibbs scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 130858fb7d8eSJustin T. Gibbs if (opt_arg == NULL) 1309717d4247SJustin T. Gibbs break; 131058fb7d8eSJustin T. Gibbs if (*((ahc_queue_alg *)opt_arg) == AHC_QUEUE_TAGGED) 131158fb7d8eSJustin T. Gibbs scsi->flags |= ~CTS_SCSI_FLAGS_TAG_ENB; 131258fb7d8eSJustin T. Gibbs scsi->valid |= CTS_SCSI_VALID_TQ; 131358fb7d8eSJustin T. Gibbs break; 131458fb7d8eSJustin T. Gibbs } 1315717d4247SJustin T. Gibbs case AC_SENT_BDR: 1316717d4247SJustin T. Gibbs case AC_BUS_RESET: 1317717d4247SJustin T. Gibbs break; 1318717d4247SJustin T. Gibbs default: 1319717d4247SJustin T. Gibbs panic("ahc_send_async: Unexpected async event"); 1320717d4247SJustin T. Gibbs } 1321717d4247SJustin T. Gibbs xpt_async(code, path, arg); 132247c2d60fSJustin T. Gibbs xpt_free_path(path); 1323717d4247SJustin T. Gibbs } 1324717d4247SJustin T. Gibbs 1325717d4247SJustin T. Gibbs void 1326717d4247SJustin T. Gibbs ahc_platform_set_tags(struct ahc_softc *ahc, 1327717d4247SJustin T. Gibbs struct ahc_devinfo *devinfo, int enable) 1328717d4247SJustin T. Gibbs { 1329717d4247SJustin T. Gibbs } 1330717d4247SJustin T. Gibbs 1331717d4247SJustin T. Gibbs int 1332717d4247SJustin T. Gibbs ahc_platform_alloc(struct ahc_softc *ahc, void *platform_arg) 1333717d4247SJustin T. Gibbs { 13345417ec4dSDavid Malone ahc->platform_data = malloc(sizeof(struct ahc_platform_data), M_DEVBUF, 13355417ec4dSDavid Malone M_NOWAIT | M_ZERO); 1336717d4247SJustin T. Gibbs if (ahc->platform_data == NULL) 1337717d4247SJustin T. Gibbs return (ENOMEM); 1338717d4247SJustin T. Gibbs return (0); 1339717d4247SJustin T. Gibbs } 1340717d4247SJustin T. Gibbs 1341717d4247SJustin T. Gibbs void 1342717d4247SJustin T. Gibbs ahc_platform_free(struct ahc_softc *ahc) 1343717d4247SJustin T. Gibbs { 134456a7c4a8SJustin T. Gibbs struct ahc_platform_data *pdata; 1345717d4247SJustin T. Gibbs 134656a7c4a8SJustin T. Gibbs pdata = ahc->platform_data; 134756a7c4a8SJustin T. Gibbs if (pdata != NULL) { 134856a7c4a8SJustin T. Gibbs if (pdata->regs != NULL) 1349717d4247SJustin T. Gibbs bus_release_resource(ahc->dev_softc, 135056a7c4a8SJustin T. Gibbs pdata->regs_res_type, 135156a7c4a8SJustin T. Gibbs pdata->regs_res_id, 135256a7c4a8SJustin T. Gibbs pdata->regs); 1353717d4247SJustin T. Gibbs 135456a7c4a8SJustin T. Gibbs if (pdata->irq != NULL) 135556a7c4a8SJustin T. Gibbs bus_release_resource(ahc->dev_softc, 135656a7c4a8SJustin T. Gibbs pdata->irq_res_type, 135756a7c4a8SJustin T. Gibbs 0, pdata->irq); 135856a7c4a8SJustin T. Gibbs 135956a7c4a8SJustin T. Gibbs if (pdata->sim_b != NULL) { 136056a7c4a8SJustin T. Gibbs xpt_async(AC_LOST_DEVICE, pdata->path_b, NULL); 136156a7c4a8SJustin T. Gibbs xpt_free_path(pdata->path_b); 136256a7c4a8SJustin T. Gibbs xpt_bus_deregister(cam_sim_path(pdata->sim_b)); 136356a7c4a8SJustin T. Gibbs cam_sim_free(pdata->sim_b, /*free_devq*/TRUE); 136456a7c4a8SJustin T. Gibbs } 136556a7c4a8SJustin T. Gibbs if (pdata->sim != NULL) { 136656a7c4a8SJustin T. Gibbs xpt_async(AC_LOST_DEVICE, pdata->path, NULL); 136756a7c4a8SJustin T. Gibbs xpt_free_path(pdata->path); 136856a7c4a8SJustin T. Gibbs xpt_bus_deregister(cam_sim_path(pdata->sim)); 136956a7c4a8SJustin T. Gibbs cam_sim_free(pdata->sim, /*free_devq*/TRUE); 137056a7c4a8SJustin T. Gibbs } 137156a7c4a8SJustin T. Gibbs if (pdata->eh != NULL) 137256a7c4a8SJustin T. Gibbs EVENTHANDLER_DEREGISTER(shutdown_final, pdata->eh); 1373717d4247SJustin T. Gibbs free(ahc->platform_data, M_DEVBUF); 1374717d4247SJustin T. Gibbs } 1375717d4247SJustin T. Gibbs } 1376717d4247SJustin T. Gibbs 1377717d4247SJustin T. Gibbs int 1378717d4247SJustin T. Gibbs ahc_softc_comp(struct ahc_softc *lahc, struct ahc_softc *rahc) 1379717d4247SJustin T. Gibbs { 1380717d4247SJustin T. Gibbs /* We don't sort softcs under FreeBSD so report equal always */ 1381717d4247SJustin T. Gibbs return (0); 1382717d4247SJustin T. Gibbs } 1383717d4247SJustin T. Gibbs 138456a7c4a8SJustin T. Gibbs int 138556a7c4a8SJustin T. Gibbs ahc_detach(device_t dev) 138656a7c4a8SJustin T. Gibbs { 138756a7c4a8SJustin T. Gibbs struct ahc_softc *ahc; 138856a7c4a8SJustin T. Gibbs 138956a7c4a8SJustin T. Gibbs device_printf(dev, "detaching device\n"); 139056a7c4a8SJustin T. Gibbs ahc = device_get_softc(dev); 1391032b0a17SScott Long ahc_lock(ahc); 1392b3b25f2cSJustin T. Gibbs TAILQ_REMOVE(&ahc_tailq, ahc, links); 1393226aa6eaSJustin T. Gibbs ahc_intr_enable(ahc, FALSE); 139456a7c4a8SJustin T. Gibbs bus_teardown_intr(dev, ahc->platform_data->irq, ahc->platform_data->ih); 1395032b0a17SScott Long ahc_unlock(ahc); 139656a7c4a8SJustin T. Gibbs ahc_free(ahc); 139756a7c4a8SJustin T. Gibbs return (0); 139856a7c4a8SJustin T. Gibbs } 139956a7c4a8SJustin T. Gibbs 1400f4e98881SRuslan Ermilov #if 0 1401717d4247SJustin T. Gibbs static void 1402717d4247SJustin T. Gibbs ahc_dump_targcmd(struct target_cmd *cmd) 1403717d4247SJustin T. Gibbs { 1404717d4247SJustin T. Gibbs uint8_t *byte; 1405717d4247SJustin T. Gibbs uint8_t *last_byte; 1406717d4247SJustin T. Gibbs int i; 1407717d4247SJustin T. Gibbs 1408717d4247SJustin T. Gibbs byte = &cmd->initiator_channel; 1409717d4247SJustin T. Gibbs /* Debugging info for received commands */ 1410717d4247SJustin T. Gibbs last_byte = &cmd[1].initiator_channel; 1411717d4247SJustin T. Gibbs 1412717d4247SJustin T. Gibbs i = 0; 1413717d4247SJustin T. Gibbs while (byte < last_byte) { 1414717d4247SJustin T. Gibbs if (i == 0) 1415717d4247SJustin T. Gibbs printf("\t"); 1416717d4247SJustin T. Gibbs printf("%#x", *byte++); 1417717d4247SJustin T. Gibbs i++; 1418717d4247SJustin T. Gibbs if (i == 8) { 1419717d4247SJustin T. Gibbs printf("\n"); 1420717d4247SJustin T. Gibbs i = 0; 1421717d4247SJustin T. Gibbs } else { 1422717d4247SJustin T. Gibbs printf(", "); 1423717d4247SJustin T. Gibbs } 1424717d4247SJustin T. Gibbs } 1425717d4247SJustin T. Gibbs } 1426717d4247SJustin T. Gibbs #endif 142758fb7d8eSJustin T. Gibbs 142858fb7d8eSJustin T. Gibbs static int 142958fb7d8eSJustin T. Gibbs ahc_modevent(module_t mod, int type, void *data) 143058fb7d8eSJustin T. Gibbs { 143158fb7d8eSJustin T. Gibbs /* XXX Deal with busy status on unload. */ 14323e019deaSPoul-Henning Kamp /* XXX Deal with unknown events */ 143358fb7d8eSJustin T. Gibbs return 0; 143458fb7d8eSJustin T. Gibbs } 143558fb7d8eSJustin T. Gibbs 143658fb7d8eSJustin T. Gibbs static moduledata_t ahc_mod = { 143758fb7d8eSJustin T. Gibbs "ahc", 143858fb7d8eSJustin T. Gibbs ahc_modevent, 143958fb7d8eSJustin T. Gibbs NULL 144058fb7d8eSJustin T. Gibbs }; 144158fb7d8eSJustin T. Gibbs 144258fb7d8eSJustin T. Gibbs DECLARE_MODULE(ahc, ahc_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); 144358fb7d8eSJustin T. Gibbs MODULE_DEPEND(ahc, cam, 1, 1, 1); 144458fb7d8eSJustin T. Gibbs MODULE_VERSION(ahc, 1); 1445