1139749Simp/*- 2123579Sgibbs * Bus independent FreeBSD shim for the aic79xx based Adaptec SCSI controllers 397883Sgibbs * 4133122Sgibbs * Copyright (c) 1994-2002, 2004 Justin T. Gibbs. 5102684Sgibbs * Copyright (c) 2001-2002 Adaptec Inc. 697883Sgibbs * All rights reserved. 797883Sgibbs * 897883Sgibbs * Redistribution and use in source and binary forms, with or without 997883Sgibbs * modification, are permitted provided that the following conditions 1097883Sgibbs * are met: 1197883Sgibbs * 1. Redistributions of source code must retain the above copyright 1297883Sgibbs * notice, this list of conditions, and the following disclaimer, 1397883Sgibbs * without modification. 1497883Sgibbs * 2. The name of the author may not be used to endorse or promote products 1597883Sgibbs * derived from this software without specific prior written permission. 1697883Sgibbs * 1797883Sgibbs * Alternatively, this software may be distributed under the terms of the 1897883Sgibbs * GNU Public License ("GPL"). 1997883Sgibbs * 2097883Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2197883Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2297883Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2397883Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 2497883Sgibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2597883Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2697883Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2797883Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2897883Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2997883Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3097883Sgibbs * SUCH DAMAGE. 3197883Sgibbs * 32123579Sgibbs * $Id: //depot/aic7xxx/freebsd/dev/aic7xxx/aic79xx_osm.c#35 $ 3397883Sgibbs */ 3497883Sgibbs 35119418Sobrien#include <sys/cdefs.h> 36119418Sobrien__FBSDID("$FreeBSD: stable/11/sys/dev/aic7xxx/aic79xx_osm.c 315812 2017-03-23 06:40:20Z mav $"); 37119418Sobrien 3897883Sgibbs#include <dev/aic7xxx/aic79xx_osm.h> 3997883Sgibbs#include <dev/aic7xxx/aic79xx_inline.h> 4097883Sgibbs 41123579Sgibbs#include <sys/kthread.h> 42123579Sgibbs 4397883Sgibbs#include "opt_ddb.h" 4497883Sgibbs#ifdef DDB 4597883Sgibbs#include <ddb/ddb.h> 4697883Sgibbs#endif 4797883Sgibbs 4897883Sgibbs#ifndef AHD_TMODE_ENABLE 4997883Sgibbs#define AHD_TMODE_ENABLE 0 5097883Sgibbs#endif 5197883Sgibbs 52123579Sgibbs#include <dev/aic7xxx/aic_osm_lib.c> 53123579Sgibbs 5497883Sgibbs#define ccb_scb_ptr spriv_ptr0 5597883Sgibbs 56153072Sru#if 0 5797883Sgibbsstatic void ahd_dump_targcmd(struct target_cmd *cmd); 5897883Sgibbs#endif 5997883Sgibbsstatic int ahd_modevent(module_t mod, int type, void *data); 6097883Sgibbsstatic void ahd_action(struct cam_sim *sim, union ccb *ccb); 6197883Sgibbsstatic void ahd_set_tran_settings(struct ahd_softc *ahd, 6297883Sgibbs int our_id, char channel, 6397883Sgibbs struct ccb_trans_settings *cts); 6497883Sgibbsstatic void ahd_get_tran_settings(struct ahd_softc *ahd, 6597883Sgibbs int our_id, char channel, 6697883Sgibbs struct ccb_trans_settings *cts); 6797883Sgibbsstatic void ahd_async(void *callback_arg, uint32_t code, 6897883Sgibbs struct cam_path *path, void *arg); 6997883Sgibbsstatic void ahd_execute_scb(void *arg, bus_dma_segment_t *dm_segs, 7097883Sgibbs int nsegments, int error); 7197883Sgibbsstatic void ahd_poll(struct cam_sim *sim); 7297883Sgibbsstatic void ahd_setup_data(struct ahd_softc *ahd, struct cam_sim *sim, 7397883Sgibbs struct ccb_scsiio *csio, struct scb *scb); 7497883Sgibbsstatic void ahd_abort_ccb(struct ahd_softc *ahd, struct cam_sim *sim, 7597883Sgibbs union ccb *ccb); 7697883Sgibbsstatic int ahd_create_path(struct ahd_softc *ahd, 7797883Sgibbs char channel, u_int target, u_int lun, 7897883Sgibbs struct cam_path **path); 7997883Sgibbs 80199260Sattiliostatic const char *ahd_sysctl_node_elements[] = { 81199260Sattilio "root", 82199260Sattilio "summary", 83199260Sattilio "debug" 84199260Sattilio}; 85199260Sattilio 86203685Sbrucec#ifndef NO_SYSCTL_DESCR 87199260Sattiliostatic const char *ahd_sysctl_node_descriptions[] = { 88199260Sattilio "root error collection for aic79xx controllers", 89199260Sattilio "summary collection for aic79xx controllers", 90199260Sattilio "debug collection for aic79xx controllers" 91199260Sattilio}; 92203685Sbrucec#endif 93199260Sattilio 94199260Sattiliostatic const char *ahd_sysctl_errors_elements[] = { 95199260Sattilio "Cerrors", 96199260Sattilio "Uerrors", 97199260Sattilio "Ferrors" 98199260Sattilio}; 99199260Sattilio 100203685Sbrucec#ifndef NO_SYSCTL_DESCR 101199260Sattiliostatic const char *ahd_sysctl_errors_descriptions[] = { 102199260Sattilio "Correctable errors", 103199260Sattilio "Uncorrectable errors", 104199260Sattilio "Fatal errors" 105199260Sattilio}; 106203685Sbrucec#endif 107199260Sattilio 10897883Sgibbsstatic int 109199260Sattilioahd_set_debugcounters(SYSCTL_HANDLER_ARGS) 110199260Sattilio{ 111199260Sattilio struct ahd_softc *sc; 112199260Sattilio int error, tmpv; 113199260Sattilio 114199260Sattilio tmpv = 0; 115199260Sattilio sc = arg1; 116199260Sattilio error = sysctl_handle_int(oidp, &tmpv, 0, req); 117199260Sattilio if (error != 0 || req->newptr == NULL) 118199260Sattilio return (error); 119199260Sattilio if (tmpv < 0 || tmpv >= AHD_ERRORS_NUMBER) 120199260Sattilio return (EINVAL); 121199260Sattilio sc->summerr[arg2] = tmpv; 122199260Sattilio return (0); 123199260Sattilio} 124199260Sattilio 125199260Sattiliostatic int 126199260Sattilioahd_clear_allcounters(SYSCTL_HANDLER_ARGS) 127199260Sattilio{ 128199260Sattilio struct ahd_softc *sc; 129199260Sattilio int error, tmpv; 130199260Sattilio 131199260Sattilio tmpv = 0; 132199260Sattilio sc = arg1; 133199260Sattilio error = sysctl_handle_int(oidp, &tmpv, 0, req); 134199260Sattilio if (error != 0 || req->newptr == NULL) 135199260Sattilio return (error); 136199260Sattilio if (tmpv != 0) 137199260Sattilio bzero(sc->summerr, sizeof(sc->summerr)); 138199260Sattilio return (0); 139199260Sattilio} 140199260Sattilio 141199260Sattiliostatic int 14297883Sgibbsahd_create_path(struct ahd_softc *ahd, char channel, u_int target, 14397883Sgibbs u_int lun, struct cam_path **path) 14497883Sgibbs{ 14597883Sgibbs path_id_t path_id; 14697883Sgibbs 147123579Sgibbs path_id = cam_sim_path(ahd->platform_data->sim); 14897883Sgibbs return (xpt_create_path(path, /*periph*/NULL, 14997883Sgibbs path_id, target, lun)); 15097883Sgibbs} 15197883Sgibbs 152199260Sattiliovoid 153199260Sattilioahd_sysctl(struct ahd_softc *ahd) 154199260Sattilio{ 155199260Sattilio u_int i; 156199260Sattilio 157199260Sattilio for (i = 0; i < AHD_SYSCTL_NUMBER; i++) 158199260Sattilio sysctl_ctx_init(&ahd->sysctl_ctx[i]); 159199260Sattilio 160199260Sattilio ahd->sysctl_tree[AHD_SYSCTL_ROOT] = 161199260Sattilio SYSCTL_ADD_NODE(&ahd->sysctl_ctx[AHD_SYSCTL_ROOT], 162199260Sattilio SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, 163199260Sattilio device_get_nameunit(ahd->dev_softc), CTLFLAG_RD, 0, 164199260Sattilio ahd_sysctl_node_descriptions[AHD_SYSCTL_ROOT]); 165199260Sattilio SYSCTL_ADD_PROC(&ahd->sysctl_ctx[AHD_SYSCTL_ROOT], 166199260Sattilio SYSCTL_CHILDREN(ahd->sysctl_tree[AHD_SYSCTL_ROOT]), 167199260Sattilio OID_AUTO, "clear", CTLTYPE_UINT | CTLFLAG_RW, ahd, 168199260Sattilio 0, ahd_clear_allcounters, "IU", 169199260Sattilio "Clear all counters"); 170199260Sattilio 171199260Sattilio for (i = AHD_SYSCTL_SUMMARY; i < AHD_SYSCTL_NUMBER; i++) 172199260Sattilio ahd->sysctl_tree[i] = 173199260Sattilio SYSCTL_ADD_NODE(&ahd->sysctl_ctx[i], 174199260Sattilio SYSCTL_CHILDREN(ahd->sysctl_tree[AHD_SYSCTL_ROOT]), 175199260Sattilio OID_AUTO, ahd_sysctl_node_elements[i], 176199260Sattilio CTLFLAG_RD, 0, 177199260Sattilio ahd_sysctl_node_descriptions[i]); 178199260Sattilio 179199260Sattilio for (i = AHD_ERRORS_CORRECTABLE; i < AHD_ERRORS_NUMBER; i++) { 180199260Sattilio SYSCTL_ADD_UINT(&ahd->sysctl_ctx[AHD_SYSCTL_SUMMARY], 181199260Sattilio SYSCTL_CHILDREN(ahd->sysctl_tree[AHD_SYSCTL_SUMMARY]), 182199260Sattilio OID_AUTO, ahd_sysctl_errors_elements[i], 183199260Sattilio CTLFLAG_RD, &ahd->summerr[i], i, 184199260Sattilio ahd_sysctl_errors_descriptions[i]); 185199260Sattilio SYSCTL_ADD_PROC(&ahd->sysctl_ctx[AHD_SYSCTL_DEBUG], 186199260Sattilio SYSCTL_CHILDREN(ahd->sysctl_tree[AHD_SYSCTL_DEBUG]), 187199260Sattilio OID_AUTO, ahd_sysctl_errors_elements[i], 188199260Sattilio CTLFLAG_RW | CTLTYPE_UINT, ahd, i, 189199260Sattilio ahd_set_debugcounters, "IU", 190199260Sattilio ahd_sysctl_errors_descriptions[i]); 191199260Sattilio } 192199260Sattilio} 193199260Sattilio 19497883Sgibbsint 19597883Sgibbsahd_map_int(struct ahd_softc *ahd) 19697883Sgibbs{ 19797883Sgibbs int error; 19897883Sgibbs 19997883Sgibbs /* Hook up our interrupt handler */ 20097883Sgibbs error = bus_setup_intr(ahd->dev_softc, ahd->platform_data->irq, 201168807Sscottl INTR_TYPE_CAM|INTR_MPSAFE, NULL, 202168807Sscottl ahd_platform_intr, ahd, &ahd->platform_data->ih); 20397883Sgibbs if (error != 0) 20497883Sgibbs device_printf(ahd->dev_softc, "bus_setup_intr() failed: %d\n", 20597883Sgibbs error); 20697883Sgibbs return (error); 20797883Sgibbs} 20897883Sgibbs 20997883Sgibbs/* 21097883Sgibbs * Attach all the sub-devices we can find 21197883Sgibbs */ 21297883Sgibbsint 21397883Sgibbsahd_attach(struct ahd_softc *ahd) 21497883Sgibbs{ 21597883Sgibbs char ahd_info[256]; 21697883Sgibbs struct ccb_setasync csa; 21797883Sgibbs struct cam_devq *devq; 21897883Sgibbs struct cam_sim *sim; 21997883Sgibbs struct cam_path *path; 22097883Sgibbs int count; 22197883Sgibbs 22297883Sgibbs count = 0; 223123579Sgibbs devq = NULL; 22497883Sgibbs sim = NULL; 225239104Sdim path = NULL; 22697883Sgibbs 227123579Sgibbs /* 228123579Sgibbs * Create a thread to perform all recovery. 229123579Sgibbs */ 230123579Sgibbs if (ahd_spawn_recovery_thread(ahd) != 0) 231123579Sgibbs goto fail; 232123579Sgibbs 23397883Sgibbs ahd_controller_info(ahd, ahd_info); 23497883Sgibbs printf("%s\n", ahd_info); 235168807Sscottl ahd_lock(ahd); 23697883Sgibbs 23797883Sgibbs /* 23897883Sgibbs * Create the device queue for our SIM(s). 23997883Sgibbs */ 24097883Sgibbs devq = cam_simq_alloc(AHD_MAX_QUEUE); 24197883Sgibbs if (devq == NULL) 24297883Sgibbs goto fail; 24397883Sgibbs 24497883Sgibbs /* 24597883Sgibbs * Construct our SIM entry 24697883Sgibbs */ 24797883Sgibbs sim = cam_sim_alloc(ahd_action, ahd_poll, "ahd", ahd, 24897883Sgibbs device_get_unit(ahd->dev_softc), 249168807Sscottl &ahd->platform_data->mtx, 1, /*XXX*/256, devq); 25097883Sgibbs if (sim == NULL) { 25197883Sgibbs cam_simq_free(devq); 25297883Sgibbs goto fail; 25397883Sgibbs } 25497883Sgibbs 255170872Sscottl if (xpt_bus_register(sim, ahd->dev_softc, /*bus_id*/0) != CAM_SUCCESS) { 25697883Sgibbs cam_sim_free(sim, /*free_devq*/TRUE); 25797883Sgibbs sim = NULL; 25897883Sgibbs goto fail; 25997883Sgibbs } 26097883Sgibbs 26197883Sgibbs if (xpt_create_path(&path, /*periph*/NULL, 26297883Sgibbs cam_sim_path(sim), CAM_TARGET_WILDCARD, 26397883Sgibbs CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 26497883Sgibbs xpt_bus_deregister(cam_sim_path(sim)); 26597883Sgibbs cam_sim_free(sim, /*free_devq*/TRUE); 26697883Sgibbs sim = NULL; 26797883Sgibbs goto fail; 26897883Sgibbs } 26997883Sgibbs 27097883Sgibbs xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5); 27197883Sgibbs csa.ccb_h.func_code = XPT_SASYNC_CB; 27297883Sgibbs csa.event_enable = AC_LOST_DEVICE; 27397883Sgibbs csa.callback = ahd_async; 27497883Sgibbs csa.callback_arg = sim; 27597883Sgibbs xpt_action((union ccb *)&csa); 27697883Sgibbs count++; 27797883Sgibbs 27897883Sgibbsfail: 27997883Sgibbs ahd->platform_data->sim = sim; 28097883Sgibbs ahd->platform_data->path = path; 281168807Sscottl ahd_unlock(ahd); 282102684Sgibbs if (count != 0) { 28397883Sgibbs /* We have to wait until after any system dumps... */ 28497883Sgibbs ahd->platform_data->eh = 28597883Sgibbs EVENTHANDLER_REGISTER(shutdown_final, ahd_shutdown, 28697883Sgibbs ahd, SHUTDOWN_PRI_DEFAULT); 287102684Sgibbs ahd_intr_enable(ahd, TRUE); 288102684Sgibbs } 28997883Sgibbs 290102684Sgibbs 29197883Sgibbs return (count); 29297883Sgibbs} 29397883Sgibbs 29497883Sgibbs/* 29597883Sgibbs * Catch an interrupt from the adapter 29697883Sgibbs */ 29797883Sgibbsvoid 29897883Sgibbsahd_platform_intr(void *arg) 29997883Sgibbs{ 30097883Sgibbs struct ahd_softc *ahd; 30197883Sgibbs 30297883Sgibbs ahd = (struct ahd_softc *)arg; 303168807Sscottl ahd_lock(ahd); 30497883Sgibbs ahd_intr(ahd); 305168807Sscottl ahd_unlock(ahd); 30697883Sgibbs} 30797883Sgibbs 30897883Sgibbs/* 30997883Sgibbs * We have an scb which has been processed by the 31097883Sgibbs * adaptor, now we look to see how the operation 31197883Sgibbs * went. 31297883Sgibbs */ 31397883Sgibbsvoid 31497883Sgibbsahd_done(struct ahd_softc *ahd, struct scb *scb) 31597883Sgibbs{ 31697883Sgibbs union ccb *ccb; 31797883Sgibbs 31897883Sgibbs CAM_DEBUG(scb->io_ctx->ccb_h.path, CAM_DEBUG_TRACE, 31997883Sgibbs ("ahd_done - scb %d\n", SCB_GET_TAG(scb))); 32097883Sgibbs 32197883Sgibbs ccb = scb->io_ctx; 32297883Sgibbs LIST_REMOVE(scb, pending_links); 323123579Sgibbs if ((scb->flags & SCB_TIMEDOUT) != 0) 324123579Sgibbs LIST_REMOVE(scb, timedout_links); 32597883Sgibbs 326168807Sscottl callout_stop(&scb->io_timer); 32797883Sgibbs 32897883Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) { 329115343Sscottl bus_dmasync_op_t op; 33097883Sgibbs 33197883Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) 33297883Sgibbs op = BUS_DMASYNC_POSTREAD; 33397883Sgibbs else 33497883Sgibbs op = BUS_DMASYNC_POSTWRITE; 33597883Sgibbs bus_dmamap_sync(ahd->buffer_dmat, scb->dmamap, op); 33697883Sgibbs bus_dmamap_unload(ahd->buffer_dmat, scb->dmamap); 33797883Sgibbs } 33897883Sgibbs 33997883Sgibbs#ifdef AHD_TARGET_MODE 34097883Sgibbs if (ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) { 34197883Sgibbs struct cam_path *ccb_path; 34297883Sgibbs 34397883Sgibbs /* 34497883Sgibbs * If we have finally disconnected, clean up our 34597883Sgibbs * pending device state. 34697883Sgibbs * XXX - There may be error states that cause where 34797883Sgibbs * we will remain connected. 34897883Sgibbs */ 34997883Sgibbs ccb_path = ccb->ccb_h.path; 35097883Sgibbs if (ahd->pending_device != NULL 35197883Sgibbs && xpt_path_comp(ahd->pending_device->path, ccb_path) == 0) { 35297883Sgibbs 35397883Sgibbs if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) { 35497883Sgibbs ahd->pending_device = NULL; 35597883Sgibbs } else { 35697883Sgibbs xpt_print_path(ccb->ccb_h.path); 35797883Sgibbs printf("Still disconnected\n"); 35897883Sgibbs ahd_freeze_ccb(ccb); 35997883Sgibbs } 36097883Sgibbs } 36197883Sgibbs 362123579Sgibbs if (aic_get_transaction_status(scb) == CAM_REQ_INPROG) 36397883Sgibbs ccb->ccb_h.status |= CAM_REQ_CMP; 36497883Sgibbs ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 36597883Sgibbs ahd_free_scb(ahd, scb); 36697883Sgibbs xpt_done(ccb); 36797883Sgibbs return; 36897883Sgibbs } 36997883Sgibbs#endif 37097883Sgibbs 37197883Sgibbs if ((scb->flags & SCB_RECOVERY_SCB) != 0) { 37297883Sgibbs struct scb *list_scb; 37397883Sgibbs 374133911Sgibbs ahd->scb_data.recovery_scbs--; 37597883Sgibbs 376123579Sgibbs if (aic_get_transaction_status(scb) == CAM_BDR_SENT 377123579Sgibbs || aic_get_transaction_status(scb) == CAM_REQ_ABORTED) 378123579Sgibbs aic_set_transaction_status(scb, CAM_CMD_TIMEOUT); 379123579Sgibbs 380133911Sgibbs if (ahd->scb_data.recovery_scbs == 0) { 381133911Sgibbs /* 382133911Sgibbs * All recovery actions have completed successfully, 383133911Sgibbs * so reinstate the timeouts for all other pending 384133911Sgibbs * commands. 385133911Sgibbs */ 386133911Sgibbs LIST_FOREACH(list_scb, 387133911Sgibbs &ahd->pending_scbs, pending_links) { 388133911Sgibbs 389150450Sgibbs aic_scb_timer_reset(list_scb, 390150450Sgibbs aic_get_timeout(scb)); 391133911Sgibbs } 392133911Sgibbs 393133911Sgibbs ahd_print_path(ahd, scb); 394133911Sgibbs printf("no longer in timeout, status = %x\n", 395133911Sgibbs ccb->ccb_h.status); 396133911Sgibbs } 39797883Sgibbs } 39897883Sgibbs 39997883Sgibbs /* Don't clobber any existing error state */ 400123579Sgibbs if (aic_get_transaction_status(scb) == CAM_REQ_INPROG) { 40197883Sgibbs ccb->ccb_h.status |= CAM_REQ_CMP; 40297883Sgibbs } else if ((scb->flags & SCB_SENSE) != 0) { 40397883Sgibbs /* 40497883Sgibbs * We performed autosense retrieval. 40597883Sgibbs * 40697883Sgibbs * Zero any sense not transferred by the 40797883Sgibbs * device. The SCSI spec mandates that any 40897883Sgibbs * untransfered data should be assumed to be 40997883Sgibbs * zero. Complete the 'bounce' of sense information 41097883Sgibbs * through buffers accessible via bus-space by 41197883Sgibbs * copying it into the clients csio. 41297883Sgibbs */ 41397883Sgibbs memset(&ccb->csio.sense_data, 0, sizeof(ccb->csio.sense_data)); 41497883Sgibbs memcpy(&ccb->csio.sense_data, 41597883Sgibbs ahd_get_sense_buf(ahd, scb), 41697883Sgibbs/* XXX What size do we want to use??? */ 41797883Sgibbs sizeof(ccb->csio.sense_data) 41897883Sgibbs - ccb->csio.sense_resid); 41997883Sgibbs scb->io_ctx->ccb_h.status |= CAM_AUTOSNS_VALID; 42097883Sgibbs } else if ((scb->flags & SCB_PKT_SENSE) != 0) { 42197883Sgibbs struct scsi_status_iu_header *siu; 42297883Sgibbs u_int sense_len; 42397883Sgibbs 42497883Sgibbs /* 42597883Sgibbs * Copy only the sense data into the provided buffer. 42697883Sgibbs */ 42797883Sgibbs siu = (struct scsi_status_iu_header *)scb->sense_data; 42897883Sgibbs sense_len = MIN(scsi_4btoul(siu->sense_length), 42997883Sgibbs sizeof(ccb->csio.sense_data)); 43097883Sgibbs memset(&ccb->csio.sense_data, 0, sizeof(ccb->csio.sense_data)); 43197883Sgibbs memcpy(&ccb->csio.sense_data, 43297883Sgibbs ahd_get_sense_buf(ahd, scb) + SIU_SENSE_OFFSET(siu), 43397883Sgibbs sense_len); 434176366Sgibbs#ifdef AHD_DEBUG 435176366Sgibbs if ((ahd_debug & AHD_SHOW_SENSE) != 0) { 436176366Sgibbs uint8_t *sense_data = (uint8_t *)&ccb->csio.sense_data; 437176366Sgibbs u_int i; 438176366Sgibbs 439176366Sgibbs printf("Copied %d bytes of sense data offset %d:", 440176366Sgibbs sense_len, SIU_SENSE_OFFSET(siu)); 441176366Sgibbs for (i = 0; i < sense_len; i++) 442176366Sgibbs printf(" 0x%x", *sense_data++); 443176366Sgibbs printf("\n"); 444176366Sgibbs } 445176366Sgibbs#endif 44697883Sgibbs scb->io_ctx->ccb_h.status |= CAM_AUTOSNS_VALID; 44797883Sgibbs } 44897883Sgibbs ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 44997883Sgibbs ahd_free_scb(ahd, scb); 45097883Sgibbs xpt_done(ccb); 45197883Sgibbs} 45297883Sgibbs 45397883Sgibbsstatic void 45497883Sgibbsahd_action(struct cam_sim *sim, union ccb *ccb) 45597883Sgibbs{ 45697883Sgibbs struct ahd_softc *ahd; 45797883Sgibbs#ifdef AHD_TARGET_MODE 45897883Sgibbs struct ahd_tmode_lstate *lstate; 45997883Sgibbs#endif 46097883Sgibbs u_int target_id; 46197883Sgibbs u_int our_id; 46297883Sgibbs 46397883Sgibbs CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("ahd_action\n")); 46497883Sgibbs 46597883Sgibbs ahd = (struct ahd_softc *)cam_sim_softc(sim); 46697883Sgibbs 46797883Sgibbs target_id = ccb->ccb_h.target_id; 46897883Sgibbs our_id = SIM_SCSI_ID(ahd, sim); 46997883Sgibbs 47097883Sgibbs switch (ccb->ccb_h.func_code) { 47197883Sgibbs /* Common cases first */ 47297883Sgibbs#ifdef AHD_TARGET_MODE 47397883Sgibbs case XPT_ACCEPT_TARGET_IO: /* Accept Host Target Mode CDB */ 47497883Sgibbs case XPT_CONT_TARGET_IO:/* Continue Host Target I/O Connection*/ 47597883Sgibbs { 47697883Sgibbs struct ahd_tmode_tstate *tstate; 47797883Sgibbs cam_status status; 47897883Sgibbs 47997883Sgibbs status = ahd_find_tmode_devs(ahd, sim, ccb, &tstate, 48097883Sgibbs &lstate, TRUE); 48197883Sgibbs 48297883Sgibbs if (status != CAM_REQ_CMP) { 48397883Sgibbs if (ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) { 48497883Sgibbs /* Response from the black hole device */ 48597883Sgibbs tstate = NULL; 48697883Sgibbs lstate = ahd->black_hole; 48797883Sgibbs } else { 48897883Sgibbs ccb->ccb_h.status = status; 48997883Sgibbs xpt_done(ccb); 49097883Sgibbs break; 49197883Sgibbs } 49297883Sgibbs } 49397883Sgibbs if (ccb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) { 49497883Sgibbs 49597883Sgibbs SLIST_INSERT_HEAD(&lstate->accept_tios, &ccb->ccb_h, 49697883Sgibbs sim_links.sle); 49797883Sgibbs ccb->ccb_h.status = CAM_REQ_INPROG; 49897883Sgibbs if ((ahd->flags & AHD_TQINFIFO_BLOCKED) != 0) 49997883Sgibbs ahd_run_tqinfifo(ahd, /*paused*/FALSE); 50097883Sgibbs break; 50197883Sgibbs } 50297883Sgibbs 50397883Sgibbs /* 50497883Sgibbs * The target_id represents the target we attempt to 50597883Sgibbs * select. In target mode, this is the initiator of 50697883Sgibbs * the original command. 50797883Sgibbs */ 50897883Sgibbs our_id = target_id; 50997883Sgibbs target_id = ccb->csio.init_id; 51097883Sgibbs /* FALLTHROUGH */ 51197883Sgibbs } 51297883Sgibbs#endif 51397883Sgibbs case XPT_SCSI_IO: /* Execute the requested I/O operation */ 51497883Sgibbs case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */ 51597883Sgibbs { 51697883Sgibbs struct scb *scb; 51797883Sgibbs struct hardware_scb *hscb; 518102684Sgibbs struct ahd_initiator_tinfo *tinfo; 519102684Sgibbs struct ahd_tmode_tstate *tstate; 520102684Sgibbs u_int col_idx; 52197883Sgibbs 52297883Sgibbs if ((ahd->flags & AHD_INITIATORROLE) == 0 52397883Sgibbs && (ccb->ccb_h.func_code == XPT_SCSI_IO 52497883Sgibbs || ccb->ccb_h.func_code == XPT_RESET_DEV)) { 52597883Sgibbs ccb->ccb_h.status = CAM_PROVIDE_FAIL; 52697883Sgibbs xpt_done(ccb); 52797883Sgibbs return; 52897883Sgibbs } 52997883Sgibbs 53097883Sgibbs /* 53197883Sgibbs * get an scb to use. 53297883Sgibbs */ 533102684Sgibbs tinfo = ahd_fetch_transinfo(ahd, 'A', our_id, 534102684Sgibbs target_id, &tstate); 535102684Sgibbs if ((ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) == 0 536102684Sgibbs || (tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ) != 0 537102684Sgibbs || ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) { 538102684Sgibbs col_idx = AHD_NEVER_COL_IDX; 539102684Sgibbs } else { 540102684Sgibbs col_idx = AHD_BUILD_COL_IDX(target_id, 541102684Sgibbs ccb->ccb_h.target_lun); 542102684Sgibbs } 543102684Sgibbs if ((scb = ahd_get_scb(ahd, col_idx)) == NULL) { 54497883Sgibbs 54597883Sgibbs xpt_freeze_simq(sim, /*count*/1); 54697883Sgibbs ahd->flags |= AHD_RESOURCE_SHORTAGE; 54797883Sgibbs ccb->ccb_h.status = CAM_REQUEUE_REQ; 54897883Sgibbs xpt_done(ccb); 54997883Sgibbs return; 55097883Sgibbs } 55197883Sgibbs 55297883Sgibbs hscb = scb->hscb; 55397883Sgibbs 55497883Sgibbs CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_SUBTRACE, 55597883Sgibbs ("start scb(%p)\n", scb)); 55697883Sgibbs scb->io_ctx = ccb; 55797883Sgibbs /* 55897883Sgibbs * So we can find the SCB when an abort is requested 55997883Sgibbs */ 56097883Sgibbs ccb->ccb_h.ccb_scb_ptr = scb; 56197883Sgibbs 56297883Sgibbs /* 56397883Sgibbs * Put all the arguments for the xfer in the scb 56497883Sgibbs */ 56597883Sgibbs hscb->control = 0; 56697883Sgibbs hscb->scsiid = BUILD_SCSIID(ahd, sim, target_id, our_id); 56797883Sgibbs hscb->lun = ccb->ccb_h.target_lun; 56897883Sgibbs if (ccb->ccb_h.func_code == XPT_RESET_DEV) { 56997883Sgibbs hscb->cdb_len = 0; 57097883Sgibbs scb->flags |= SCB_DEVICE_RESET; 57197883Sgibbs hscb->control |= MK_MESSAGE; 572109588Sgibbs hscb->task_management = SIU_TASKMGMT_LUN_RESET; 57397883Sgibbs ahd_execute_scb(scb, NULL, 0, 0); 57497883Sgibbs } else { 57597883Sgibbs#ifdef AHD_TARGET_MODE 57697883Sgibbs if (ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) { 57797883Sgibbs struct target_data *tdata; 57897883Sgibbs 57997883Sgibbs tdata = &hscb->shared_data.tdata; 58097883Sgibbs if (ahd->pending_device == lstate) 58197883Sgibbs scb->flags |= SCB_TARGET_IMMEDIATE; 58297883Sgibbs hscb->control |= TARGET_SCB; 58397883Sgibbs tdata->target_phases = 0; 58497883Sgibbs if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) { 58597883Sgibbs tdata->target_phases |= SPHASE_PENDING; 58697883Sgibbs tdata->scsi_status = 58797883Sgibbs ccb->csio.scsi_status; 58897883Sgibbs } 58997883Sgibbs if (ccb->ccb_h.flags & CAM_DIS_DISCONNECT) 59097883Sgibbs tdata->target_phases |= NO_DISCONNECT; 59197883Sgibbs 59297883Sgibbs tdata->initiator_tag = 59397883Sgibbs ahd_htole16(ccb->csio.tag_id); 59497883Sgibbs } 59597883Sgibbs#endif 596109588Sgibbs hscb->task_management = 0; 59797883Sgibbs if (ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) 59897883Sgibbs hscb->control |= ccb->csio.tag_action; 59997883Sgibbs 60097883Sgibbs ahd_setup_data(ahd, sim, &ccb->csio, scb); 60197883Sgibbs } 60297883Sgibbs break; 60397883Sgibbs } 60497883Sgibbs#ifdef AHD_TARGET_MODE 605237601Sken case XPT_NOTIFY_ACKNOWLEDGE: 606237601Sken case XPT_IMMEDIATE_NOTIFY: 60797883Sgibbs { 60897883Sgibbs struct ahd_tmode_tstate *tstate; 60997883Sgibbs struct ahd_tmode_lstate *lstate; 61097883Sgibbs cam_status status; 61197883Sgibbs 61297883Sgibbs status = ahd_find_tmode_devs(ahd, sim, ccb, &tstate, 61397883Sgibbs &lstate, TRUE); 61497883Sgibbs 61597883Sgibbs if (status != CAM_REQ_CMP) { 61697883Sgibbs ccb->ccb_h.status = status; 61797883Sgibbs xpt_done(ccb); 61897883Sgibbs break; 61997883Sgibbs } 62097883Sgibbs SLIST_INSERT_HEAD(&lstate->immed_notifies, &ccb->ccb_h, 62197883Sgibbs sim_links.sle); 62297883Sgibbs ccb->ccb_h.status = CAM_REQ_INPROG; 62397883Sgibbs ahd_send_lstate_events(ahd, lstate); 62497883Sgibbs break; 62597883Sgibbs } 62697883Sgibbs case XPT_EN_LUN: /* Enable LUN as a target */ 62797883Sgibbs ahd_handle_en_lun(ahd, sim, ccb); 62897883Sgibbs xpt_done(ccb); 62997883Sgibbs break; 63097883Sgibbs#endif 63197883Sgibbs case XPT_ABORT: /* Abort the specified CCB */ 63297883Sgibbs { 63397883Sgibbs ahd_abort_ccb(ahd, sim, ccb); 63497883Sgibbs break; 63597883Sgibbs } 63697883Sgibbs case XPT_SET_TRAN_SETTINGS: 63797883Sgibbs { 63897883Sgibbs ahd_set_tran_settings(ahd, SIM_SCSI_ID(ahd, sim), 63997883Sgibbs SIM_CHANNEL(ahd, sim), &ccb->cts); 64097883Sgibbs xpt_done(ccb); 64197883Sgibbs break; 64297883Sgibbs } 64397883Sgibbs case XPT_GET_TRAN_SETTINGS: 64497883Sgibbs /* Get default/user set transfer settings for the target */ 64597883Sgibbs { 64697883Sgibbs ahd_get_tran_settings(ahd, SIM_SCSI_ID(ahd, sim), 64797883Sgibbs SIM_CHANNEL(ahd, sim), &ccb->cts); 64897883Sgibbs xpt_done(ccb); 64997883Sgibbs break; 65097883Sgibbs } 65197883Sgibbs case XPT_CALC_GEOMETRY: 65297883Sgibbs { 653123579Sgibbs aic_calc_geometry(&ccb->ccg, ahd->flags & AHD_EXTENDED_TRANS_A); 65497883Sgibbs xpt_done(ccb); 65597883Sgibbs break; 65697883Sgibbs } 65797883Sgibbs case XPT_RESET_BUS: /* Reset the specified SCSI bus */ 65897883Sgibbs { 65997883Sgibbs int found; 66097883Sgibbs 66197883Sgibbs found = ahd_reset_channel(ahd, SIM_CHANNEL(ahd, sim), 66297883Sgibbs /*initiate reset*/TRUE); 66397883Sgibbs if (bootverbose) { 66497883Sgibbs xpt_print_path(SIM_PATH(ahd, sim)); 66597883Sgibbs printf("SCSI bus reset delivered. " 66697883Sgibbs "%d SCBs aborted.\n", found); 66797883Sgibbs } 66897883Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 66997883Sgibbs xpt_done(ccb); 67097883Sgibbs break; 67197883Sgibbs } 67297883Sgibbs case XPT_TERM_IO: /* Terminate the I/O process */ 67397883Sgibbs /* XXX Implement */ 67497883Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 67597883Sgibbs xpt_done(ccb); 67697883Sgibbs break; 67797883Sgibbs case XPT_PATH_INQ: /* Path routing inquiry */ 67897883Sgibbs { 67997883Sgibbs struct ccb_pathinq *cpi = &ccb->cpi; 68097883Sgibbs 68197883Sgibbs cpi->version_num = 1; /* XXX??? */ 68297883Sgibbs cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE; 68397883Sgibbs if ((ahd->features & AHD_WIDE) != 0) 68497883Sgibbs cpi->hba_inquiry |= PI_WIDE_16; 68597883Sgibbs if ((ahd->features & AHD_TARGETMODE) != 0) { 68697883Sgibbs cpi->target_sprt = PIT_PROCESSOR 68797883Sgibbs | PIT_DISCONNECT 68897883Sgibbs | PIT_TERM_IO; 68997883Sgibbs } else { 69097883Sgibbs cpi->target_sprt = 0; 69197883Sgibbs } 69297883Sgibbs cpi->hba_misc = 0; 69397883Sgibbs cpi->hba_eng_cnt = 0; 69497883Sgibbs cpi->max_target = (ahd->features & AHD_WIDE) ? 15 : 7; 695141978Sgibbs cpi->max_lun = AHD_NUM_LUNS_NONPKT - 1; 69697883Sgibbs cpi->initiator_id = ahd->our_id; 69797883Sgibbs if ((ahd->flags & AHD_RESET_BUS_A) == 0) { 69897883Sgibbs cpi->hba_misc |= PIM_NOBUSRESET; 69997883Sgibbs } 70097883Sgibbs cpi->bus_id = cam_sim_bus(sim); 70197883Sgibbs cpi->base_transfer_speed = 3300; 702315812Smav strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 703315812Smav strlcpy(cpi->hba_vid, "Adaptec", HBA_IDLEN); 704315812Smav strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 70597883Sgibbs cpi->unit_number = cam_sim_unit(sim); 70697883Sgibbs cpi->protocol = PROTO_SCSI; 70797883Sgibbs cpi->protocol_version = SCSI_REV_2; 70897883Sgibbs cpi->transport = XPORT_SPI; 70997883Sgibbs cpi->transport_version = 4; 710176355Sgibbs cpi->xport_specific.spi.ppr_options = SID_SPI_CLOCK_DT_ST 711176355Sgibbs | SID_SPI_IUS 712176355Sgibbs | SID_SPI_QAS; 71397883Sgibbs cpi->ccb_h.status = CAM_REQ_CMP; 71497883Sgibbs xpt_done(ccb); 71597883Sgibbs break; 71697883Sgibbs } 71797883Sgibbs default: 71897883Sgibbs ccb->ccb_h.status = CAM_PROVIDE_FAIL; 71997883Sgibbs xpt_done(ccb); 72097883Sgibbs break; 72197883Sgibbs } 72297883Sgibbs} 72397883Sgibbs 72497883Sgibbs 72597883Sgibbsstatic void 72697883Sgibbsahd_set_tran_settings(struct ahd_softc *ahd, int our_id, char channel, 72797883Sgibbs struct ccb_trans_settings *cts) 72897883Sgibbs{ 72997883Sgibbs struct ahd_devinfo devinfo; 73097883Sgibbs struct ccb_trans_settings_scsi *scsi; 73197883Sgibbs struct ccb_trans_settings_spi *spi; 73297883Sgibbs struct ahd_initiator_tinfo *tinfo; 73397883Sgibbs struct ahd_tmode_tstate *tstate; 73497883Sgibbs uint16_t *discenable; 73597883Sgibbs uint16_t *tagenable; 73697883Sgibbs u_int update_type; 73797883Sgibbs 73897883Sgibbs scsi = &cts->proto_specific.scsi; 73997883Sgibbs spi = &cts->xport_specific.spi; 74097883Sgibbs ahd_compile_devinfo(&devinfo, SIM_SCSI_ID(ahd, sim), 74197883Sgibbs cts->ccb_h.target_id, 74297883Sgibbs cts->ccb_h.target_lun, 74397883Sgibbs SIM_CHANNEL(ahd, sim), 74497883Sgibbs ROLE_UNKNOWN); 74597883Sgibbs tinfo = ahd_fetch_transinfo(ahd, devinfo.channel, 74697883Sgibbs devinfo.our_scsiid, 74797883Sgibbs devinfo.target, &tstate); 74897883Sgibbs update_type = 0; 74997883Sgibbs if (cts->type == CTS_TYPE_CURRENT_SETTINGS) { 75097883Sgibbs update_type |= AHD_TRANS_GOAL; 75197883Sgibbs discenable = &tstate->discenable; 75297883Sgibbs tagenable = &tstate->tagenable; 75397883Sgibbs tinfo->curr.protocol_version = cts->protocol_version; 75497883Sgibbs tinfo->curr.transport_version = cts->transport_version; 75597883Sgibbs tinfo->goal.protocol_version = cts->protocol_version; 75697883Sgibbs tinfo->goal.transport_version = cts->transport_version; 75797883Sgibbs } else if (cts->type == CTS_TYPE_USER_SETTINGS) { 75897883Sgibbs update_type |= AHD_TRANS_USER; 75997883Sgibbs discenable = &ahd->user_discenable; 76097883Sgibbs tagenable = &ahd->user_tagenable; 76197883Sgibbs tinfo->user.protocol_version = cts->protocol_version; 76297883Sgibbs tinfo->user.transport_version = cts->transport_version; 76397883Sgibbs } else { 76497883Sgibbs cts->ccb_h.status = CAM_REQ_INVALID; 76597883Sgibbs return; 76697883Sgibbs } 76797883Sgibbs 76897883Sgibbs if ((spi->valid & CTS_SPI_VALID_DISC) != 0) { 76997883Sgibbs if ((spi->flags & CTS_SPI_FLAGS_DISC_ENB) != 0) 77097883Sgibbs *discenable |= devinfo.target_mask; 77197883Sgibbs else 77297883Sgibbs *discenable &= ~devinfo.target_mask; 77397883Sgibbs } 77497883Sgibbs 77597883Sgibbs if ((scsi->valid & CTS_SCSI_VALID_TQ) != 0) { 77697883Sgibbs if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0) 77797883Sgibbs *tagenable |= devinfo.target_mask; 77897883Sgibbs else 77997883Sgibbs *tagenable &= ~devinfo.target_mask; 78097883Sgibbs } 78197883Sgibbs 78297883Sgibbs if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) { 78397883Sgibbs ahd_validate_width(ahd, /*tinfo limit*/NULL, 78497883Sgibbs &spi->bus_width, ROLE_UNKNOWN); 78597883Sgibbs ahd_set_width(ahd, &devinfo, spi->bus_width, 78697883Sgibbs update_type, /*paused*/FALSE); 78797883Sgibbs } 78897883Sgibbs 78997883Sgibbs if ((spi->valid & CTS_SPI_VALID_PPR_OPTIONS) == 0) { 79097883Sgibbs if (update_type == AHD_TRANS_USER) 79197883Sgibbs spi->ppr_options = tinfo->user.ppr_options; 79297883Sgibbs else 79397883Sgibbs spi->ppr_options = tinfo->goal.ppr_options; 79497883Sgibbs } 79597883Sgibbs 79697883Sgibbs if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) == 0) { 79797883Sgibbs if (update_type == AHD_TRANS_USER) 79897883Sgibbs spi->sync_offset = tinfo->user.offset; 79997883Sgibbs else 80097883Sgibbs spi->sync_offset = tinfo->goal.offset; 80197883Sgibbs } 80297883Sgibbs 80397883Sgibbs if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) == 0) { 80497883Sgibbs if (update_type == AHD_TRANS_USER) 80597883Sgibbs spi->sync_period = tinfo->user.period; 80697883Sgibbs else 80797883Sgibbs spi->sync_period = tinfo->goal.period; 80897883Sgibbs } 80997883Sgibbs 81097883Sgibbs if (((spi->valid & CTS_SPI_VALID_SYNC_RATE) != 0) 81197883Sgibbs || ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0)) { 81297883Sgibbs u_int maxsync; 81397883Sgibbs 81497883Sgibbs maxsync = AHD_SYNCRATE_MAX; 81597883Sgibbs 81697883Sgibbs if (spi->bus_width != MSG_EXT_WDTR_BUS_16_BIT) 81797883Sgibbs spi->ppr_options &= ~MSG_EXT_PPR_DT_REQ; 81897883Sgibbs 81997883Sgibbs if ((*discenable & devinfo.target_mask) == 0) 82097883Sgibbs spi->ppr_options &= ~MSG_EXT_PPR_IU_REQ; 82197883Sgibbs 82297883Sgibbs ahd_find_syncrate(ahd, &spi->sync_period, 82397883Sgibbs &spi->ppr_options, maxsync); 82497883Sgibbs ahd_validate_offset(ahd, /*tinfo limit*/NULL, 82597883Sgibbs spi->sync_period, &spi->sync_offset, 82697883Sgibbs spi->bus_width, ROLE_UNKNOWN); 82797883Sgibbs 82897883Sgibbs /* We use a period of 0 to represent async */ 82997883Sgibbs if (spi->sync_offset == 0) { 83097883Sgibbs spi->sync_period = 0; 83197883Sgibbs spi->ppr_options = 0; 83297883Sgibbs } 83397883Sgibbs 83497883Sgibbs ahd_set_syncrate(ahd, &devinfo, spi->sync_period, 83597883Sgibbs spi->sync_offset, spi->ppr_options, 83697883Sgibbs update_type, /*paused*/FALSE); 83797883Sgibbs } 83897883Sgibbs cts->ccb_h.status = CAM_REQ_CMP; 83997883Sgibbs} 84097883Sgibbs 84197883Sgibbsstatic void 84297883Sgibbsahd_get_tran_settings(struct ahd_softc *ahd, int our_id, char channel, 84397883Sgibbs struct ccb_trans_settings *cts) 84497883Sgibbs{ 84597883Sgibbs struct ahd_devinfo devinfo; 84697883Sgibbs struct ccb_trans_settings_scsi *scsi; 84797883Sgibbs struct ccb_trans_settings_spi *spi; 84897883Sgibbs struct ahd_initiator_tinfo *targ_info; 84997883Sgibbs struct ahd_tmode_tstate *tstate; 85097883Sgibbs struct ahd_transinfo *tinfo; 85197883Sgibbs 85297883Sgibbs scsi = &cts->proto_specific.scsi; 85397883Sgibbs spi = &cts->xport_specific.spi; 85497883Sgibbs ahd_compile_devinfo(&devinfo, our_id, 85597883Sgibbs cts->ccb_h.target_id, 85697883Sgibbs cts->ccb_h.target_lun, 85797883Sgibbs channel, ROLE_UNKNOWN); 85897883Sgibbs targ_info = ahd_fetch_transinfo(ahd, devinfo.channel, 85997883Sgibbs devinfo.our_scsiid, 86097883Sgibbs devinfo.target, &tstate); 86197883Sgibbs 86297883Sgibbs if (cts->type == CTS_TYPE_CURRENT_SETTINGS) 86397883Sgibbs tinfo = &targ_info->curr; 86497883Sgibbs else 86597883Sgibbs tinfo = &targ_info->user; 86697883Sgibbs 86797883Sgibbs scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 86897883Sgibbs spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB; 86997883Sgibbs if (cts->type == CTS_TYPE_USER_SETTINGS) { 87097883Sgibbs if ((ahd->user_discenable & devinfo.target_mask) != 0) 87197883Sgibbs spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 87297883Sgibbs 87397883Sgibbs if ((ahd->user_tagenable & devinfo.target_mask) != 0) 87497883Sgibbs scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; 87597883Sgibbs } else { 87697883Sgibbs if ((tstate->discenable & devinfo.target_mask) != 0) 87797883Sgibbs spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 87897883Sgibbs 87997883Sgibbs if ((tstate->tagenable & devinfo.target_mask) != 0) 88097883Sgibbs scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; 88197883Sgibbs } 88297883Sgibbs cts->protocol_version = tinfo->protocol_version; 88397883Sgibbs cts->transport_version = tinfo->transport_version; 88497883Sgibbs 88597883Sgibbs spi->sync_period = tinfo->period; 88697883Sgibbs spi->sync_offset = tinfo->offset; 88797883Sgibbs spi->bus_width = tinfo->width; 88897883Sgibbs spi->ppr_options = tinfo->ppr_options; 88997883Sgibbs 89097883Sgibbs cts->protocol = PROTO_SCSI; 89197883Sgibbs cts->transport = XPORT_SPI; 89297883Sgibbs spi->valid = CTS_SPI_VALID_SYNC_RATE 89397883Sgibbs | CTS_SPI_VALID_SYNC_OFFSET 89497883Sgibbs | CTS_SPI_VALID_BUS_WIDTH 89597883Sgibbs | CTS_SPI_VALID_PPR_OPTIONS; 89697883Sgibbs 89797883Sgibbs if (cts->ccb_h.target_lun != CAM_LUN_WILDCARD) { 89897883Sgibbs scsi->valid = CTS_SCSI_VALID_TQ; 89997883Sgibbs spi->valid |= CTS_SPI_VALID_DISC; 90097883Sgibbs } else { 90197883Sgibbs scsi->valid = 0; 90297883Sgibbs } 90397883Sgibbs 90497883Sgibbs cts->ccb_h.status = CAM_REQ_CMP; 90597883Sgibbs} 90697883Sgibbs 90797883Sgibbsstatic void 90897883Sgibbsahd_async(void *callback_arg, uint32_t code, struct cam_path *path, void *arg) 90997883Sgibbs{ 91097883Sgibbs struct ahd_softc *ahd; 91197883Sgibbs struct cam_sim *sim; 91297883Sgibbs 91397883Sgibbs sim = (struct cam_sim *)callback_arg; 91497883Sgibbs ahd = (struct ahd_softc *)cam_sim_softc(sim); 91597883Sgibbs switch (code) { 91697883Sgibbs case AC_LOST_DEVICE: 91797883Sgibbs { 91897883Sgibbs struct ahd_devinfo devinfo; 91997883Sgibbs 92097883Sgibbs ahd_compile_devinfo(&devinfo, SIM_SCSI_ID(ahd, sim), 92197883Sgibbs xpt_path_target_id(path), 92297883Sgibbs xpt_path_lun_id(path), 92397883Sgibbs SIM_CHANNEL(ahd, sim), 92497883Sgibbs ROLE_UNKNOWN); 92597883Sgibbs 92697883Sgibbs /* 92797883Sgibbs * Revert to async/narrow transfers 92897883Sgibbs * for the next device. 92997883Sgibbs */ 93097883Sgibbs ahd_set_width(ahd, &devinfo, MSG_EXT_WDTR_BUS_8_BIT, 93197883Sgibbs AHD_TRANS_GOAL|AHD_TRANS_CUR, /*paused*/FALSE); 93297883Sgibbs ahd_set_syncrate(ahd, &devinfo, /*period*/0, /*offset*/0, 93397883Sgibbs /*ppr_options*/0, AHD_TRANS_GOAL|AHD_TRANS_CUR, 93497883Sgibbs /*paused*/FALSE); 93597883Sgibbs break; 93697883Sgibbs } 93797883Sgibbs default: 93897883Sgibbs break; 93997883Sgibbs } 94097883Sgibbs} 94197883Sgibbs 94297883Sgibbsstatic void 94397883Sgibbsahd_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments, 94497883Sgibbs int error) 94597883Sgibbs{ 94697883Sgibbs struct scb *scb; 94797883Sgibbs union ccb *ccb; 94897883Sgibbs struct ahd_softc *ahd; 94997883Sgibbs struct ahd_initiator_tinfo *tinfo; 95097883Sgibbs struct ahd_tmode_tstate *tstate; 95197883Sgibbs u_int mask; 95297883Sgibbs 95397883Sgibbs scb = (struct scb *)arg; 95497883Sgibbs ccb = scb->io_ctx; 95597883Sgibbs ahd = scb->ahd_softc; 95697883Sgibbs 95797883Sgibbs if (error != 0) { 95897883Sgibbs if (error == EFBIG) 959123579Sgibbs aic_set_transaction_status(scb, CAM_REQ_TOO_BIG); 96097883Sgibbs else 961123579Sgibbs aic_set_transaction_status(scb, CAM_REQ_CMP_ERR); 96297883Sgibbs if (nsegments != 0) 96397883Sgibbs bus_dmamap_unload(ahd->buffer_dmat, scb->dmamap); 96497883Sgibbs ahd_free_scb(ahd, scb); 96597883Sgibbs xpt_done(ccb); 96697883Sgibbs return; 96797883Sgibbs } 96897883Sgibbs scb->sg_count = 0; 96997883Sgibbs if (nsegments != 0) { 97097883Sgibbs void *sg; 971115343Sscottl bus_dmasync_op_t op; 97297883Sgibbs u_int i; 97397883Sgibbs 97497883Sgibbs /* Copy the segments into our SG list */ 97597883Sgibbs for (i = nsegments, sg = scb->sg_list; i > 0; i--) { 97697883Sgibbs 97797883Sgibbs sg = ahd_sg_setup(ahd, scb, sg, dm_segs->ds_addr, 97897883Sgibbs dm_segs->ds_len, 97997883Sgibbs /*last*/i == 1); 98097883Sgibbs dm_segs++; 98197883Sgibbs } 98297883Sgibbs 98397883Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) 98497883Sgibbs op = BUS_DMASYNC_PREREAD; 98597883Sgibbs else 98697883Sgibbs op = BUS_DMASYNC_PREWRITE; 98797883Sgibbs 98897883Sgibbs bus_dmamap_sync(ahd->buffer_dmat, scb->dmamap, op); 98997883Sgibbs 99097883Sgibbs if (ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) { 99197883Sgibbs struct target_data *tdata; 99297883Sgibbs 99397883Sgibbs tdata = &scb->hscb->shared_data.tdata; 99497883Sgibbs tdata->target_phases |= DPHASE_PENDING; 99597883Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) 99697883Sgibbs tdata->data_phase = P_DATAOUT; 99797883Sgibbs else 99897883Sgibbs tdata->data_phase = P_DATAIN; 99997883Sgibbs } 100097883Sgibbs } 100197883Sgibbs 100297883Sgibbs /* 100397883Sgibbs * Last time we need to check if this SCB needs to 100497883Sgibbs * be aborted. 100597883Sgibbs */ 1006123579Sgibbs if (aic_get_transaction_status(scb) != CAM_REQ_INPROG) { 100797883Sgibbs if (nsegments != 0) 100897883Sgibbs bus_dmamap_unload(ahd->buffer_dmat, 100997883Sgibbs scb->dmamap); 101097883Sgibbs ahd_free_scb(ahd, scb); 101197883Sgibbs xpt_done(ccb); 101297883Sgibbs return; 101397883Sgibbs } 101497883Sgibbs 101597883Sgibbs tinfo = ahd_fetch_transinfo(ahd, SCSIID_CHANNEL(ahd, scb->hscb->scsiid), 101697883Sgibbs SCSIID_OUR_ID(scb->hscb->scsiid), 101797883Sgibbs SCSIID_TARGET(ahd, scb->hscb->scsiid), 101897883Sgibbs &tstate); 101997883Sgibbs 102097883Sgibbs mask = SCB_GET_TARGET_MASK(ahd, scb); 102197883Sgibbs 102297883Sgibbs if ((tstate->discenable & mask) != 0 102397883Sgibbs && (ccb->ccb_h.flags & CAM_DIS_DISCONNECT) == 0) 102497883Sgibbs scb->hscb->control |= DISCENB; 102597883Sgibbs 1026109588Sgibbs if ((tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ) != 0) { 102797883Sgibbs scb->flags |= SCB_PACKETIZED; 1028109588Sgibbs if (scb->hscb->task_management != 0) 1029109588Sgibbs scb->hscb->control &= ~MK_MESSAGE; 1030109588Sgibbs } 103197883Sgibbs 103297883Sgibbs if ((ccb->ccb_h.flags & CAM_NEGOTIATE) != 0 103397883Sgibbs && (tinfo->goal.width != 0 103497883Sgibbs || tinfo->goal.period != 0 103597883Sgibbs || tinfo->goal.ppr_options != 0)) { 103697883Sgibbs scb->flags |= SCB_NEGOTIATE; 103797883Sgibbs scb->hscb->control |= MK_MESSAGE; 103897883Sgibbs } else if ((tstate->auto_negotiate & mask) != 0) { 103997883Sgibbs scb->flags |= SCB_AUTO_NEGOTIATE; 104097883Sgibbs scb->hscb->control |= MK_MESSAGE; 104197883Sgibbs } 104297883Sgibbs 104397883Sgibbs LIST_INSERT_HEAD(&ahd->pending_scbs, scb, pending_links); 104497883Sgibbs 104597883Sgibbs ccb->ccb_h.status |= CAM_SIM_QUEUED; 104697883Sgibbs 1047133911Sgibbs aic_scb_timer_start(scb); 104897883Sgibbs 104997883Sgibbs if ((scb->flags & SCB_TARGET_IMMEDIATE) != 0) { 105097883Sgibbs /* Define a mapping from our tag to the SCB. */ 105197883Sgibbs ahd->scb_data.scbindex[SCB_GET_TAG(scb)] = scb; 105297883Sgibbs ahd_pause(ahd); 105397883Sgibbs ahd_set_scbptr(ahd, SCB_GET_TAG(scb)); 105497883Sgibbs ahd_outb(ahd, RETURN_1, CONT_MSG_LOOP_TARG); 105597883Sgibbs ahd_unpause(ahd); 105697883Sgibbs } else { 105797883Sgibbs ahd_queue_scb(ahd, scb); 105897883Sgibbs } 105997883Sgibbs 106097883Sgibbs} 106197883Sgibbs 106297883Sgibbsstatic void 106397883Sgibbsahd_poll(struct cam_sim *sim) 106497883Sgibbs{ 106597883Sgibbs ahd_intr(cam_sim_softc(sim)); 106697883Sgibbs} 106797883Sgibbs 106897883Sgibbsstatic void 106997883Sgibbsahd_setup_data(struct ahd_softc *ahd, struct cam_sim *sim, 107097883Sgibbs struct ccb_scsiio *csio, struct scb *scb) 107197883Sgibbs{ 107297883Sgibbs struct hardware_scb *hscb; 107397883Sgibbs struct ccb_hdr *ccb_h; 1074246713Skib int error; 107597883Sgibbs 107697883Sgibbs hscb = scb->hscb; 107797883Sgibbs ccb_h = &csio->ccb_h; 107897883Sgibbs 107997883Sgibbs csio->resid = 0; 108097883Sgibbs csio->sense_resid = 0; 108197883Sgibbs if (ccb_h->func_code == XPT_SCSI_IO) { 108297883Sgibbs hscb->cdb_len = csio->cdb_len; 108397883Sgibbs if ((ccb_h->flags & CAM_CDB_POINTER) != 0) { 108497883Sgibbs 108597883Sgibbs if (hscb->cdb_len > MAX_CDB_LEN 108697883Sgibbs && (ccb_h->flags & CAM_CDB_PHYS) == 0) { 108797883Sgibbs 1088111653Sgibbs /* 1089111653Sgibbs * Should CAM start to support CDB sizes 1090111653Sgibbs * greater than 16 bytes, we could use 1091111653Sgibbs * the sense buffer to store the CDB. 1092111653Sgibbs */ 1093123579Sgibbs aic_set_transaction_status(scb, 109497883Sgibbs CAM_REQ_INVALID); 109597883Sgibbs ahd_free_scb(ahd, scb); 109697883Sgibbs xpt_done((union ccb *)csio); 109797883Sgibbs return; 109897883Sgibbs } 109997883Sgibbs if ((ccb_h->flags & CAM_CDB_PHYS) != 0) { 1100111653Sgibbs hscb->shared_data.idata.cdb_from_host.cdbptr = 1101123579Sgibbs aic_htole64((uintptr_t)csio->cdb_io.cdb_ptr); 1102111653Sgibbs hscb->shared_data.idata.cdb_from_host.cdblen = 1103111653Sgibbs csio->cdb_len; 1104111653Sgibbs hscb->cdb_len |= SCB_CDB_LEN_PTR; 110597883Sgibbs } else { 110697883Sgibbs memcpy(hscb->shared_data.idata.cdb, 110797883Sgibbs csio->cdb_io.cdb_ptr, 110897883Sgibbs hscb->cdb_len); 110997883Sgibbs } 111097883Sgibbs } else { 111197883Sgibbs if (hscb->cdb_len > MAX_CDB_LEN) { 111297883Sgibbs 1113123579Sgibbs aic_set_transaction_status(scb, 111497883Sgibbs CAM_REQ_INVALID); 111597883Sgibbs ahd_free_scb(ahd, scb); 111697883Sgibbs xpt_done((union ccb *)csio); 111797883Sgibbs return; 111897883Sgibbs } 111997883Sgibbs memcpy(hscb->shared_data.idata.cdb, 112097883Sgibbs csio->cdb_io.cdb_bytes, hscb->cdb_len); 112197883Sgibbs } 112297883Sgibbs } 112397883Sgibbs 1124246713Skib error = bus_dmamap_load_ccb(ahd->buffer_dmat, 1125246713Skib scb->dmamap, 1126246713Skib (union ccb *)csio, 1127246713Skib ahd_execute_scb, 1128246713Skib scb, /*flags*/0); 1129246713Skib if (error == EINPROGRESS) { 1130246713Skib /* 1131246713Skib * So as to maintain ordering, freeze the controller queue 1132246713Skib * until our mapping is returned. 1133246713Skib */ 1134246713Skib xpt_freeze_simq(sim, /*count*/1); 1135246713Skib scb->io_ctx->ccb_h.status |= CAM_RELEASE_SIMQ; 113697883Sgibbs } 113797883Sgibbs} 113897883Sgibbs 113997883Sgibbsstatic void 114097883Sgibbsahd_abort_ccb(struct ahd_softc *ahd, struct cam_sim *sim, union ccb *ccb) 114197883Sgibbs{ 114297883Sgibbs union ccb *abort_ccb; 114397883Sgibbs 114497883Sgibbs abort_ccb = ccb->cab.abort_ccb; 114597883Sgibbs switch (abort_ccb->ccb_h.func_code) { 114697883Sgibbs#ifdef AHD_TARGET_MODE 114797883Sgibbs case XPT_ACCEPT_TARGET_IO: 1148237601Sken case XPT_IMMEDIATE_NOTIFY: 114997883Sgibbs case XPT_CONT_TARGET_IO: 115097883Sgibbs { 115197883Sgibbs struct ahd_tmode_tstate *tstate; 115297883Sgibbs struct ahd_tmode_lstate *lstate; 115397883Sgibbs struct ccb_hdr_slist *list; 115497883Sgibbs cam_status status; 115597883Sgibbs 115697883Sgibbs status = ahd_find_tmode_devs(ahd, sim, abort_ccb, &tstate, 115797883Sgibbs &lstate, TRUE); 115897883Sgibbs 115997883Sgibbs if (status != CAM_REQ_CMP) { 116097883Sgibbs ccb->ccb_h.status = status; 116197883Sgibbs break; 116297883Sgibbs } 116397883Sgibbs 116497883Sgibbs if (abort_ccb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) 116597883Sgibbs list = &lstate->accept_tios; 1166237601Sken else if (abort_ccb->ccb_h.func_code == XPT_IMMEDIATE_NOTIFY) 116797883Sgibbs list = &lstate->immed_notifies; 116897883Sgibbs else 116997883Sgibbs list = NULL; 117097883Sgibbs 117197883Sgibbs if (list != NULL) { 117297883Sgibbs struct ccb_hdr *curelm; 117397883Sgibbs int found; 117497883Sgibbs 117597883Sgibbs curelm = SLIST_FIRST(list); 117697883Sgibbs found = 0; 117797883Sgibbs if (curelm == &abort_ccb->ccb_h) { 117897883Sgibbs found = 1; 117997883Sgibbs SLIST_REMOVE_HEAD(list, sim_links.sle); 118097883Sgibbs } else { 118197883Sgibbs while(curelm != NULL) { 118297883Sgibbs struct ccb_hdr *nextelm; 118397883Sgibbs 118497883Sgibbs nextelm = 118597883Sgibbs SLIST_NEXT(curelm, sim_links.sle); 118697883Sgibbs 118797883Sgibbs if (nextelm == &abort_ccb->ccb_h) { 118897883Sgibbs found = 1; 118997883Sgibbs SLIST_NEXT(curelm, 119097883Sgibbs sim_links.sle) = 119197883Sgibbs SLIST_NEXT(nextelm, 119297883Sgibbs sim_links.sle); 119397883Sgibbs break; 119497883Sgibbs } 119597883Sgibbs curelm = nextelm; 119697883Sgibbs } 119797883Sgibbs } 119897883Sgibbs 119997883Sgibbs if (found) { 120097883Sgibbs abort_ccb->ccb_h.status = CAM_REQ_ABORTED; 120197883Sgibbs xpt_done(abort_ccb); 120297883Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 120397883Sgibbs } else { 120497883Sgibbs xpt_print_path(abort_ccb->ccb_h.path); 120597883Sgibbs printf("Not found\n"); 120697883Sgibbs ccb->ccb_h.status = CAM_PATH_INVALID; 120797883Sgibbs } 120897883Sgibbs break; 120997883Sgibbs } 121097883Sgibbs /* FALLTHROUGH */ 121197883Sgibbs } 121297883Sgibbs#endif 121397883Sgibbs case XPT_SCSI_IO: 121497883Sgibbs /* XXX Fully implement the hard ones */ 121597883Sgibbs ccb->ccb_h.status = CAM_UA_ABORT; 121697883Sgibbs break; 121797883Sgibbs default: 121897883Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 121997883Sgibbs break; 122097883Sgibbs } 122197883Sgibbs xpt_done(ccb); 122297883Sgibbs} 122397883Sgibbs 122497883Sgibbsvoid 122597883Sgibbsahd_send_async(struct ahd_softc *ahd, char channel, u_int target, 122697883Sgibbs u_int lun, ac_code code, void *opt_arg) 122797883Sgibbs{ 122897883Sgibbs struct ccb_trans_settings cts; 122997883Sgibbs struct cam_path *path; 123097883Sgibbs void *arg; 123197883Sgibbs int error; 123297883Sgibbs 123397883Sgibbs arg = NULL; 123497883Sgibbs error = ahd_create_path(ahd, channel, target, lun, &path); 123597883Sgibbs 123697883Sgibbs if (error != CAM_REQ_CMP) 123797883Sgibbs return; 123897883Sgibbs 123997883Sgibbs switch (code) { 124097883Sgibbs case AC_TRANSFER_NEG: 124197883Sgibbs { 124297883Sgibbs struct ccb_trans_settings_scsi *scsi; 124397883Sgibbs 124497883Sgibbs cts.type = CTS_TYPE_CURRENT_SETTINGS; 124597883Sgibbs scsi = &cts.proto_specific.scsi; 124697883Sgibbs cts.ccb_h.path = path; 124797883Sgibbs cts.ccb_h.target_id = target; 124897883Sgibbs cts.ccb_h.target_lun = lun; 124997883Sgibbs ahd_get_tran_settings(ahd, ahd->our_id, channel, &cts); 125097883Sgibbs arg = &cts; 125197883Sgibbs scsi->valid &= ~CTS_SCSI_VALID_TQ; 125297883Sgibbs scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 125397883Sgibbs if (opt_arg == NULL) 125497883Sgibbs break; 125597883Sgibbs if (*((ahd_queue_alg *)opt_arg) == AHD_QUEUE_TAGGED) 125697883Sgibbs scsi->flags |= ~CTS_SCSI_FLAGS_TAG_ENB; 125797883Sgibbs scsi->valid |= CTS_SCSI_VALID_TQ; 125897883Sgibbs break; 125997883Sgibbs } 126097883Sgibbs case AC_SENT_BDR: 126197883Sgibbs case AC_BUS_RESET: 126297883Sgibbs break; 126397883Sgibbs default: 126497883Sgibbs panic("ahd_send_async: Unexpected async event"); 126597883Sgibbs } 126697883Sgibbs xpt_async(code, path, arg); 126797883Sgibbs xpt_free_path(path); 126897883Sgibbs} 126997883Sgibbs 127097883Sgibbsvoid 127197883Sgibbsahd_platform_set_tags(struct ahd_softc *ahd, 127297883Sgibbs struct ahd_devinfo *devinfo, int enable) 127397883Sgibbs{ 127497883Sgibbs} 127597883Sgibbs 127697883Sgibbsint 127797883Sgibbsahd_platform_alloc(struct ahd_softc *ahd, void *platform_arg) 127897883Sgibbs{ 127997883Sgibbs ahd->platform_data = malloc(sizeof(struct ahd_platform_data), M_DEVBUF, 128097883Sgibbs M_NOWAIT | M_ZERO); 128197883Sgibbs if (ahd->platform_data == NULL) 128297883Sgibbs return (ENOMEM); 128397883Sgibbs return (0); 128497883Sgibbs} 128597883Sgibbs 128697883Sgibbsvoid 128797883Sgibbsahd_platform_free(struct ahd_softc *ahd) 128897883Sgibbs{ 128997883Sgibbs struct ahd_platform_data *pdata; 129097883Sgibbs 129197883Sgibbs pdata = ahd->platform_data; 129297883Sgibbs if (pdata != NULL) { 129397883Sgibbs if (pdata->regs[0] != NULL) 129497883Sgibbs bus_release_resource(ahd->dev_softc, 129597883Sgibbs pdata->regs_res_type[0], 129697883Sgibbs pdata->regs_res_id[0], 129797883Sgibbs pdata->regs[0]); 129897883Sgibbs 129997883Sgibbs if (pdata->regs[1] != NULL) 130097883Sgibbs bus_release_resource(ahd->dev_softc, 130197883Sgibbs pdata->regs_res_type[1], 130297883Sgibbs pdata->regs_res_id[1], 130397883Sgibbs pdata->regs[1]); 130497883Sgibbs 130597883Sgibbs if (pdata->irq != NULL) 130697883Sgibbs bus_release_resource(ahd->dev_softc, 130797883Sgibbs pdata->irq_res_type, 130897883Sgibbs 0, pdata->irq); 130997883Sgibbs 131097883Sgibbs if (pdata->sim != NULL) { 131197883Sgibbs xpt_async(AC_LOST_DEVICE, pdata->path, NULL); 131297883Sgibbs xpt_free_path(pdata->path); 131397883Sgibbs xpt_bus_deregister(cam_sim_path(pdata->sim)); 131497883Sgibbs cam_sim_free(pdata->sim, /*free_devq*/TRUE); 131597883Sgibbs } 131697883Sgibbs if (pdata->eh != NULL) 131797883Sgibbs EVENTHANDLER_DEREGISTER(shutdown_final, pdata->eh); 131897883Sgibbs free(ahd->platform_data, M_DEVBUF); 131997883Sgibbs } 132097883Sgibbs} 132197883Sgibbs 132297883Sgibbsint 132397883Sgibbsahd_softc_comp(struct ahd_softc *lahd, struct ahd_softc *rahd) 132497883Sgibbs{ 132597883Sgibbs /* We don't sort softcs under FreeBSD so report equal always */ 132697883Sgibbs return (0); 132797883Sgibbs} 132897883Sgibbs 132997883Sgibbsint 133097883Sgibbsahd_detach(device_t dev) 133197883Sgibbs{ 133297883Sgibbs struct ahd_softc *ahd; 133397883Sgibbs 133497883Sgibbs device_printf(dev, "detaching device\n"); 133597883Sgibbs ahd = device_get_softc(dev); 1336168807Sscottl ahd_lock(ahd); 1337123579Sgibbs TAILQ_REMOVE(&ahd_tailq, ahd, links); 133897883Sgibbs ahd_intr_enable(ahd, FALSE); 133997883Sgibbs bus_teardown_intr(dev, ahd->platform_data->irq, ahd->platform_data->ih); 1340168807Sscottl ahd_unlock(ahd); 134197883Sgibbs ahd_free(ahd); 134297883Sgibbs return (0); 134397883Sgibbs} 134497883Sgibbs 1345153072Sru#if 0 134697883Sgibbsstatic void 134797883Sgibbsahd_dump_targcmd(struct target_cmd *cmd) 134897883Sgibbs{ 134997883Sgibbs uint8_t *byte; 135097883Sgibbs uint8_t *last_byte; 135197883Sgibbs int i; 135297883Sgibbs 135397883Sgibbs byte = &cmd->initiator_channel; 135497883Sgibbs /* Debugging info for received commands */ 135597883Sgibbs last_byte = &cmd[1].initiator_channel; 135697883Sgibbs 135797883Sgibbs i = 0; 135897883Sgibbs while (byte < last_byte) { 135997883Sgibbs if (i == 0) 136097883Sgibbs printf("\t"); 136197883Sgibbs printf("%#x", *byte++); 136297883Sgibbs i++; 136397883Sgibbs if (i == 8) { 136497883Sgibbs printf("\n"); 136597883Sgibbs i = 0; 136697883Sgibbs } else { 136797883Sgibbs printf(", "); 136897883Sgibbs } 136997883Sgibbs } 137097883Sgibbs} 137197883Sgibbs#endif 137297883Sgibbs 137397883Sgibbsstatic int 137497883Sgibbsahd_modevent(module_t mod, int type, void *data) 137597883Sgibbs{ 137697883Sgibbs /* XXX Deal with busy status on unload. */ 1377132199Sphk /* XXX Deal with unknown events */ 137897883Sgibbs return 0; 137997883Sgibbs} 138097883Sgibbs 138197883Sgibbsstatic moduledata_t ahd_mod = { 138297883Sgibbs "ahd", 138397883Sgibbs ahd_modevent, 138497883Sgibbs NULL 138597883Sgibbs}; 138697883Sgibbs 138797883Sgibbs/********************************** DDB Hooks *********************************/ 138897883Sgibbs#ifdef DDB 138997883Sgibbsstatic struct ahd_softc *ahd_ddb_softc; 139097883Sgibbsstatic int ahd_ddb_paused; 139197883Sgibbsstatic int ahd_ddb_paused_on_entry; 1392133122SgibbsDB_COMMAND(ahd_sunit, ahd_ddb_sunit) 139397883Sgibbs{ 139497883Sgibbs struct ahd_softc *list_ahd; 139597883Sgibbs 139697883Sgibbs ahd_ddb_softc = NULL; 139797883Sgibbs TAILQ_FOREACH(list_ahd, &ahd_tailq, links) { 139897883Sgibbs if (list_ahd->unit == addr) 139997883Sgibbs ahd_ddb_softc = list_ahd; 140097883Sgibbs } 140197883Sgibbs if (ahd_ddb_softc == NULL) 140297883Sgibbs db_error("No matching softc found!\n"); 140397883Sgibbs} 140497883Sgibbs 140597883SgibbsDB_COMMAND(ahd_pause, ahd_ddb_pause) 140697883Sgibbs{ 140797883Sgibbs if (ahd_ddb_softc == NULL) { 1408133122Sgibbs db_error("Must set unit with ahd_sunit first!\n"); 140997883Sgibbs return; 141097883Sgibbs } 141197883Sgibbs if (ahd_ddb_paused == 0) { 141297883Sgibbs ahd_ddb_paused++; 141397883Sgibbs if (ahd_is_paused(ahd_ddb_softc)) { 141497883Sgibbs ahd_ddb_paused_on_entry++; 141597883Sgibbs return; 141697883Sgibbs } 141797883Sgibbs ahd_pause(ahd_ddb_softc); 141897883Sgibbs } 141997883Sgibbs} 142097883Sgibbs 142197883SgibbsDB_COMMAND(ahd_unpause, ahd_ddb_unpause) 142297883Sgibbs{ 142397883Sgibbs if (ahd_ddb_softc == NULL) { 1424133122Sgibbs db_error("Must set unit with ahd_sunit first!\n"); 142597883Sgibbs return; 142697883Sgibbs } 142797883Sgibbs if (ahd_ddb_paused != 0) { 142897883Sgibbs ahd_ddb_paused = 0; 142997883Sgibbs if (ahd_ddb_paused_on_entry) 143097883Sgibbs return; 143197883Sgibbs ahd_unpause(ahd_ddb_softc); 143297883Sgibbs } else if (ahd_ddb_paused_on_entry != 0) { 143397883Sgibbs /* Two unpauses to clear a paused on entry. */ 143497883Sgibbs ahd_ddb_paused_on_entry = 0; 143597883Sgibbs ahd_unpause(ahd_ddb_softc); 143697883Sgibbs } 143797883Sgibbs} 143897883Sgibbs 143997883SgibbsDB_COMMAND(ahd_in, ahd_ddb_in) 144097883Sgibbs{ 144197883Sgibbs int c; 144297883Sgibbs int size; 144397883Sgibbs 144497883Sgibbs if (ahd_ddb_softc == NULL) { 1445133122Sgibbs db_error("Must set unit with ahd_sunit first!\n"); 144697883Sgibbs return; 144797883Sgibbs } 144897883Sgibbs if (have_addr == 0) 144997883Sgibbs return; 145097883Sgibbs 145197883Sgibbs size = 1; 145297883Sgibbs while ((c = *modif++) != '\0') { 145397883Sgibbs switch (c) { 145497883Sgibbs case 'b': 145597883Sgibbs size = 1; 145697883Sgibbs break; 145797883Sgibbs case 'w': 145897883Sgibbs size = 2; 145997883Sgibbs break; 146097883Sgibbs case 'l': 146197883Sgibbs size = 4; 146297883Sgibbs break; 146397883Sgibbs } 146497883Sgibbs } 146597883Sgibbs 146697883Sgibbs if (count <= 0) 146797883Sgibbs count = 1; 146897883Sgibbs while (--count >= 0) { 1469107368Sscottl db_printf("%04lx (M)%x: \t", (u_long)addr, 147097883Sgibbs ahd_inb(ahd_ddb_softc, MODE_PTR)); 147197883Sgibbs switch (size) { 147297883Sgibbs case 1: 147397883Sgibbs db_printf("%02x\n", ahd_inb(ahd_ddb_softc, addr)); 147497883Sgibbs break; 147597883Sgibbs case 2: 147697883Sgibbs db_printf("%04x\n", ahd_inw(ahd_ddb_softc, addr)); 147797883Sgibbs break; 147897883Sgibbs case 4: 147997883Sgibbs db_printf("%08x\n", ahd_inl(ahd_ddb_softc, addr)); 148097883Sgibbs break; 148197883Sgibbs } 148297883Sgibbs } 148397883Sgibbs} 148497883Sgibbs 1485183054SsamDB_FUNC(ahd_out, ahd_ddb_out, db_cmd_table, CS_MORE, NULL) 148697883Sgibbs{ 148797883Sgibbs db_expr_t old_value; 148897883Sgibbs db_expr_t new_value; 148997883Sgibbs int size; 149097883Sgibbs 149197883Sgibbs if (ahd_ddb_softc == NULL) { 1492133122Sgibbs db_error("Must set unit with ahd_sunit first!\n"); 149397883Sgibbs return; 149497883Sgibbs } 149597883Sgibbs 149697883Sgibbs switch (modif[0]) { 149797883Sgibbs case '\0': 149897883Sgibbs case 'b': 149997883Sgibbs size = 1; 150097883Sgibbs break; 150197883Sgibbs case 'h': 150297883Sgibbs size = 2; 150397883Sgibbs break; 150497883Sgibbs case 'l': 150597883Sgibbs size = 4; 150697883Sgibbs break; 150797883Sgibbs default: 150897883Sgibbs db_error("Unknown size\n"); 150997883Sgibbs return; 151097883Sgibbs } 151197883Sgibbs 151297883Sgibbs while (db_expression(&new_value)) { 151397883Sgibbs switch (size) { 151497883Sgibbs default: 151597883Sgibbs case 1: 151697883Sgibbs old_value = ahd_inb(ahd_ddb_softc, addr); 151797883Sgibbs ahd_outb(ahd_ddb_softc, addr, new_value); 151897883Sgibbs break; 151997883Sgibbs case 2: 152097883Sgibbs old_value = ahd_inw(ahd_ddb_softc, addr); 152197883Sgibbs ahd_outw(ahd_ddb_softc, addr, new_value); 152297883Sgibbs break; 152397883Sgibbs case 4: 152497883Sgibbs old_value = ahd_inl(ahd_ddb_softc, addr); 152597883Sgibbs ahd_outl(ahd_ddb_softc, addr, new_value); 152697883Sgibbs break; 152797883Sgibbs } 1528107368Sscottl db_printf("%04lx (M)%x: \t0x%lx\t=\t0x%lx", 1529107368Sscottl (u_long)addr, ahd_inb(ahd_ddb_softc, MODE_PTR), 1530107368Sscottl (u_long)old_value, (u_long)new_value); 153197883Sgibbs addr += size; 153297883Sgibbs } 153397883Sgibbs db_skip_to_eol(); 153497883Sgibbs} 153597883Sgibbs 1536133122SgibbsDB_COMMAND(ahd_dump, ahd_ddb_dump) 1537133122Sgibbs{ 1538133122Sgibbs if (ahd_ddb_softc == NULL) { 1539133122Sgibbs db_error("Must set unit with ahd_sunit first!\n"); 1540133122Sgibbs return; 1541133122Sgibbs } 1542133122Sgibbs ahd_dump_card_state(ahd_ddb_softc); 1543133122Sgibbs} 1544133122Sgibbs 154597883Sgibbs#endif 154697883Sgibbs 154797883Sgibbs 154897883SgibbsDECLARE_MODULE(ahd, ahd_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); 154997883SgibbsMODULE_DEPEND(ahd, cam, 1, 1, 1); 155097883SgibbsMODULE_VERSION(ahd, 1); 1551