aic79xx_osm.c revision 239104
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: head/sys/dev/aic7xxx/aic79xx_osm.c 239104 2012-08-06 20:01:32Z dim $"); 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; 70297883Sgibbs strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 70397883Sgibbs strncpy(cpi->hba_vid, "Adaptec", HBA_IDLEN); 70497883Sgibbs strncpy(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; 107497883Sgibbs 107597883Sgibbs hscb = scb->hscb; 107697883Sgibbs ccb_h = &csio->ccb_h; 107797883Sgibbs 107897883Sgibbs csio->resid = 0; 107997883Sgibbs csio->sense_resid = 0; 108097883Sgibbs if (ccb_h->func_code == XPT_SCSI_IO) { 108197883Sgibbs hscb->cdb_len = csio->cdb_len; 108297883Sgibbs if ((ccb_h->flags & CAM_CDB_POINTER) != 0) { 108397883Sgibbs 108497883Sgibbs if (hscb->cdb_len > MAX_CDB_LEN 108597883Sgibbs && (ccb_h->flags & CAM_CDB_PHYS) == 0) { 108697883Sgibbs 1087111653Sgibbs /* 1088111653Sgibbs * Should CAM start to support CDB sizes 1089111653Sgibbs * greater than 16 bytes, we could use 1090111653Sgibbs * the sense buffer to store the CDB. 1091111653Sgibbs */ 1092123579Sgibbs aic_set_transaction_status(scb, 109397883Sgibbs CAM_REQ_INVALID); 109497883Sgibbs ahd_free_scb(ahd, scb); 109597883Sgibbs xpt_done((union ccb *)csio); 109697883Sgibbs return; 109797883Sgibbs } 109897883Sgibbs if ((ccb_h->flags & CAM_CDB_PHYS) != 0) { 1099111653Sgibbs hscb->shared_data.idata.cdb_from_host.cdbptr = 1100123579Sgibbs aic_htole64((uintptr_t)csio->cdb_io.cdb_ptr); 1101111653Sgibbs hscb->shared_data.idata.cdb_from_host.cdblen = 1102111653Sgibbs csio->cdb_len; 1103111653Sgibbs hscb->cdb_len |= SCB_CDB_LEN_PTR; 110497883Sgibbs } else { 110597883Sgibbs memcpy(hscb->shared_data.idata.cdb, 110697883Sgibbs csio->cdb_io.cdb_ptr, 110797883Sgibbs hscb->cdb_len); 110897883Sgibbs } 110997883Sgibbs } else { 111097883Sgibbs if (hscb->cdb_len > MAX_CDB_LEN) { 111197883Sgibbs 1112123579Sgibbs aic_set_transaction_status(scb, 111397883Sgibbs CAM_REQ_INVALID); 111497883Sgibbs ahd_free_scb(ahd, scb); 111597883Sgibbs xpt_done((union ccb *)csio); 111697883Sgibbs return; 111797883Sgibbs } 111897883Sgibbs memcpy(hscb->shared_data.idata.cdb, 111997883Sgibbs csio->cdb_io.cdb_bytes, hscb->cdb_len); 112097883Sgibbs } 112197883Sgibbs } 112297883Sgibbs 112397883Sgibbs /* Only use S/G if there is a transfer */ 112497883Sgibbs if ((ccb_h->flags & CAM_DIR_MASK) != CAM_DIR_NONE) { 112597883Sgibbs if ((ccb_h->flags & CAM_SCATTER_VALID) == 0) { 112697883Sgibbs /* We've been given a pointer to a single buffer */ 112797883Sgibbs if ((ccb_h->flags & CAM_DATA_PHYS) == 0) { 112897883Sgibbs int s; 112997883Sgibbs int error; 113097883Sgibbs 113197883Sgibbs s = splsoftvm(); 113297883Sgibbs error = bus_dmamap_load(ahd->buffer_dmat, 113397883Sgibbs scb->dmamap, 113497883Sgibbs csio->data_ptr, 113597883Sgibbs csio->dxfer_len, 113697883Sgibbs ahd_execute_scb, 113797883Sgibbs scb, /*flags*/0); 113897883Sgibbs if (error == EINPROGRESS) { 113997883Sgibbs /* 114097883Sgibbs * So as to maintain ordering, 114197883Sgibbs * freeze the controller queue 114297883Sgibbs * until our mapping is 114397883Sgibbs * returned. 114497883Sgibbs */ 114597883Sgibbs xpt_freeze_simq(sim, 114697883Sgibbs /*count*/1); 114797883Sgibbs scb->io_ctx->ccb_h.status |= 114897883Sgibbs CAM_RELEASE_SIMQ; 114997883Sgibbs } 115097883Sgibbs splx(s); 115197883Sgibbs } else { 115297883Sgibbs struct bus_dma_segment seg; 115397883Sgibbs 115497883Sgibbs /* Pointer to physical buffer */ 115597883Sgibbs if (csio->dxfer_len > AHD_MAXTRANSFER_SIZE) 115697883Sgibbs panic("ahd_setup_data - Transfer size " 115797883Sgibbs "larger than can device max"); 115897883Sgibbs 1159113296Sjake seg.ds_addr = 1160113296Sjake (bus_addr_t)(vm_offset_t)csio->data_ptr; 116197883Sgibbs seg.ds_len = csio->dxfer_len; 116297883Sgibbs ahd_execute_scb(scb, &seg, 1, 0); 116397883Sgibbs } 116497883Sgibbs } else { 116597883Sgibbs struct bus_dma_segment *segs; 116697883Sgibbs 116797883Sgibbs if ((ccb_h->flags & CAM_DATA_PHYS) != 0) 116897883Sgibbs panic("ahd_setup_data - Physical segment " 116997883Sgibbs "pointers unsupported"); 117097883Sgibbs 117197883Sgibbs if ((ccb_h->flags & CAM_SG_LIST_PHYS) == 0) 117297883Sgibbs panic("ahd_setup_data - Virtual segment " 117397883Sgibbs "addresses unsupported"); 117497883Sgibbs 117597883Sgibbs /* Just use the segments provided */ 117697883Sgibbs segs = (struct bus_dma_segment *)csio->data_ptr; 117797883Sgibbs ahd_execute_scb(scb, segs, csio->sglist_cnt, 0); 117897883Sgibbs } 117997883Sgibbs } else { 118097883Sgibbs ahd_execute_scb(scb, NULL, 0, 0); 118197883Sgibbs } 118297883Sgibbs} 118397883Sgibbs 118497883Sgibbsstatic void 118597883Sgibbsahd_abort_ccb(struct ahd_softc *ahd, struct cam_sim *sim, union ccb *ccb) 118697883Sgibbs{ 118797883Sgibbs union ccb *abort_ccb; 118897883Sgibbs 118997883Sgibbs abort_ccb = ccb->cab.abort_ccb; 119097883Sgibbs switch (abort_ccb->ccb_h.func_code) { 119197883Sgibbs#ifdef AHD_TARGET_MODE 119297883Sgibbs case XPT_ACCEPT_TARGET_IO: 1193237601Sken case XPT_IMMEDIATE_NOTIFY: 119497883Sgibbs case XPT_CONT_TARGET_IO: 119597883Sgibbs { 119697883Sgibbs struct ahd_tmode_tstate *tstate; 119797883Sgibbs struct ahd_tmode_lstate *lstate; 119897883Sgibbs struct ccb_hdr_slist *list; 119997883Sgibbs cam_status status; 120097883Sgibbs 120197883Sgibbs status = ahd_find_tmode_devs(ahd, sim, abort_ccb, &tstate, 120297883Sgibbs &lstate, TRUE); 120397883Sgibbs 120497883Sgibbs if (status != CAM_REQ_CMP) { 120597883Sgibbs ccb->ccb_h.status = status; 120697883Sgibbs break; 120797883Sgibbs } 120897883Sgibbs 120997883Sgibbs if (abort_ccb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) 121097883Sgibbs list = &lstate->accept_tios; 1211237601Sken else if (abort_ccb->ccb_h.func_code == XPT_IMMEDIATE_NOTIFY) 121297883Sgibbs list = &lstate->immed_notifies; 121397883Sgibbs else 121497883Sgibbs list = NULL; 121597883Sgibbs 121697883Sgibbs if (list != NULL) { 121797883Sgibbs struct ccb_hdr *curelm; 121897883Sgibbs int found; 121997883Sgibbs 122097883Sgibbs curelm = SLIST_FIRST(list); 122197883Sgibbs found = 0; 122297883Sgibbs if (curelm == &abort_ccb->ccb_h) { 122397883Sgibbs found = 1; 122497883Sgibbs SLIST_REMOVE_HEAD(list, sim_links.sle); 122597883Sgibbs } else { 122697883Sgibbs while(curelm != NULL) { 122797883Sgibbs struct ccb_hdr *nextelm; 122897883Sgibbs 122997883Sgibbs nextelm = 123097883Sgibbs SLIST_NEXT(curelm, sim_links.sle); 123197883Sgibbs 123297883Sgibbs if (nextelm == &abort_ccb->ccb_h) { 123397883Sgibbs found = 1; 123497883Sgibbs SLIST_NEXT(curelm, 123597883Sgibbs sim_links.sle) = 123697883Sgibbs SLIST_NEXT(nextelm, 123797883Sgibbs sim_links.sle); 123897883Sgibbs break; 123997883Sgibbs } 124097883Sgibbs curelm = nextelm; 124197883Sgibbs } 124297883Sgibbs } 124397883Sgibbs 124497883Sgibbs if (found) { 124597883Sgibbs abort_ccb->ccb_h.status = CAM_REQ_ABORTED; 124697883Sgibbs xpt_done(abort_ccb); 124797883Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 124897883Sgibbs } else { 124997883Sgibbs xpt_print_path(abort_ccb->ccb_h.path); 125097883Sgibbs printf("Not found\n"); 125197883Sgibbs ccb->ccb_h.status = CAM_PATH_INVALID; 125297883Sgibbs } 125397883Sgibbs break; 125497883Sgibbs } 125597883Sgibbs /* FALLTHROUGH */ 125697883Sgibbs } 125797883Sgibbs#endif 125897883Sgibbs case XPT_SCSI_IO: 125997883Sgibbs /* XXX Fully implement the hard ones */ 126097883Sgibbs ccb->ccb_h.status = CAM_UA_ABORT; 126197883Sgibbs break; 126297883Sgibbs default: 126397883Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 126497883Sgibbs break; 126597883Sgibbs } 126697883Sgibbs xpt_done(ccb); 126797883Sgibbs} 126897883Sgibbs 126997883Sgibbsvoid 127097883Sgibbsahd_send_async(struct ahd_softc *ahd, char channel, u_int target, 127197883Sgibbs u_int lun, ac_code code, void *opt_arg) 127297883Sgibbs{ 127397883Sgibbs struct ccb_trans_settings cts; 127497883Sgibbs struct cam_path *path; 127597883Sgibbs void *arg; 127697883Sgibbs int error; 127797883Sgibbs 127897883Sgibbs arg = NULL; 127997883Sgibbs error = ahd_create_path(ahd, channel, target, lun, &path); 128097883Sgibbs 128197883Sgibbs if (error != CAM_REQ_CMP) 128297883Sgibbs return; 128397883Sgibbs 128497883Sgibbs switch (code) { 128597883Sgibbs case AC_TRANSFER_NEG: 128697883Sgibbs { 128797883Sgibbs struct ccb_trans_settings_scsi *scsi; 128897883Sgibbs 128997883Sgibbs cts.type = CTS_TYPE_CURRENT_SETTINGS; 129097883Sgibbs scsi = &cts.proto_specific.scsi; 129197883Sgibbs cts.ccb_h.path = path; 129297883Sgibbs cts.ccb_h.target_id = target; 129397883Sgibbs cts.ccb_h.target_lun = lun; 129497883Sgibbs ahd_get_tran_settings(ahd, ahd->our_id, channel, &cts); 129597883Sgibbs arg = &cts; 129697883Sgibbs scsi->valid &= ~CTS_SCSI_VALID_TQ; 129797883Sgibbs scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 129897883Sgibbs if (opt_arg == NULL) 129997883Sgibbs break; 130097883Sgibbs if (*((ahd_queue_alg *)opt_arg) == AHD_QUEUE_TAGGED) 130197883Sgibbs scsi->flags |= ~CTS_SCSI_FLAGS_TAG_ENB; 130297883Sgibbs scsi->valid |= CTS_SCSI_VALID_TQ; 130397883Sgibbs break; 130497883Sgibbs } 130597883Sgibbs case AC_SENT_BDR: 130697883Sgibbs case AC_BUS_RESET: 130797883Sgibbs break; 130897883Sgibbs default: 130997883Sgibbs panic("ahd_send_async: Unexpected async event"); 131097883Sgibbs } 131197883Sgibbs xpt_async(code, path, arg); 131297883Sgibbs xpt_free_path(path); 131397883Sgibbs} 131497883Sgibbs 131597883Sgibbsvoid 131697883Sgibbsahd_platform_set_tags(struct ahd_softc *ahd, 131797883Sgibbs struct ahd_devinfo *devinfo, int enable) 131897883Sgibbs{ 131997883Sgibbs} 132097883Sgibbs 132197883Sgibbsint 132297883Sgibbsahd_platform_alloc(struct ahd_softc *ahd, void *platform_arg) 132397883Sgibbs{ 132497883Sgibbs ahd->platform_data = malloc(sizeof(struct ahd_platform_data), M_DEVBUF, 132597883Sgibbs M_NOWAIT | M_ZERO); 132697883Sgibbs if (ahd->platform_data == NULL) 132797883Sgibbs return (ENOMEM); 132897883Sgibbs return (0); 132997883Sgibbs} 133097883Sgibbs 133197883Sgibbsvoid 133297883Sgibbsahd_platform_free(struct ahd_softc *ahd) 133397883Sgibbs{ 133497883Sgibbs struct ahd_platform_data *pdata; 133597883Sgibbs 133697883Sgibbs pdata = ahd->platform_data; 133797883Sgibbs if (pdata != NULL) { 133897883Sgibbs if (pdata->regs[0] != NULL) 133997883Sgibbs bus_release_resource(ahd->dev_softc, 134097883Sgibbs pdata->regs_res_type[0], 134197883Sgibbs pdata->regs_res_id[0], 134297883Sgibbs pdata->regs[0]); 134397883Sgibbs 134497883Sgibbs if (pdata->regs[1] != NULL) 134597883Sgibbs bus_release_resource(ahd->dev_softc, 134697883Sgibbs pdata->regs_res_type[1], 134797883Sgibbs pdata->regs_res_id[1], 134897883Sgibbs pdata->regs[1]); 134997883Sgibbs 135097883Sgibbs if (pdata->irq != NULL) 135197883Sgibbs bus_release_resource(ahd->dev_softc, 135297883Sgibbs pdata->irq_res_type, 135397883Sgibbs 0, pdata->irq); 135497883Sgibbs 135597883Sgibbs if (pdata->sim != NULL) { 135697883Sgibbs xpt_async(AC_LOST_DEVICE, pdata->path, NULL); 135797883Sgibbs xpt_free_path(pdata->path); 135897883Sgibbs xpt_bus_deregister(cam_sim_path(pdata->sim)); 135997883Sgibbs cam_sim_free(pdata->sim, /*free_devq*/TRUE); 136097883Sgibbs } 136197883Sgibbs if (pdata->eh != NULL) 136297883Sgibbs EVENTHANDLER_DEREGISTER(shutdown_final, pdata->eh); 136397883Sgibbs free(ahd->platform_data, M_DEVBUF); 136497883Sgibbs } 136597883Sgibbs} 136697883Sgibbs 136797883Sgibbsint 136897883Sgibbsahd_softc_comp(struct ahd_softc *lahd, struct ahd_softc *rahd) 136997883Sgibbs{ 137097883Sgibbs /* We don't sort softcs under FreeBSD so report equal always */ 137197883Sgibbs return (0); 137297883Sgibbs} 137397883Sgibbs 137497883Sgibbsint 137597883Sgibbsahd_detach(device_t dev) 137697883Sgibbs{ 137797883Sgibbs struct ahd_softc *ahd; 137897883Sgibbs 137997883Sgibbs device_printf(dev, "detaching device\n"); 138097883Sgibbs ahd = device_get_softc(dev); 1381168807Sscottl ahd_lock(ahd); 1382123579Sgibbs TAILQ_REMOVE(&ahd_tailq, ahd, links); 138397883Sgibbs ahd_intr_enable(ahd, FALSE); 138497883Sgibbs bus_teardown_intr(dev, ahd->platform_data->irq, ahd->platform_data->ih); 1385168807Sscottl ahd_unlock(ahd); 138697883Sgibbs ahd_free(ahd); 138797883Sgibbs return (0); 138897883Sgibbs} 138997883Sgibbs 1390153072Sru#if 0 139197883Sgibbsstatic void 139297883Sgibbsahd_dump_targcmd(struct target_cmd *cmd) 139397883Sgibbs{ 139497883Sgibbs uint8_t *byte; 139597883Sgibbs uint8_t *last_byte; 139697883Sgibbs int i; 139797883Sgibbs 139897883Sgibbs byte = &cmd->initiator_channel; 139997883Sgibbs /* Debugging info for received commands */ 140097883Sgibbs last_byte = &cmd[1].initiator_channel; 140197883Sgibbs 140297883Sgibbs i = 0; 140397883Sgibbs while (byte < last_byte) { 140497883Sgibbs if (i == 0) 140597883Sgibbs printf("\t"); 140697883Sgibbs printf("%#x", *byte++); 140797883Sgibbs i++; 140897883Sgibbs if (i == 8) { 140997883Sgibbs printf("\n"); 141097883Sgibbs i = 0; 141197883Sgibbs } else { 141297883Sgibbs printf(", "); 141397883Sgibbs } 141497883Sgibbs } 141597883Sgibbs} 141697883Sgibbs#endif 141797883Sgibbs 141897883Sgibbsstatic int 141997883Sgibbsahd_modevent(module_t mod, int type, void *data) 142097883Sgibbs{ 142197883Sgibbs /* XXX Deal with busy status on unload. */ 1422132199Sphk /* XXX Deal with unknown events */ 142397883Sgibbs return 0; 142497883Sgibbs} 142597883Sgibbs 142697883Sgibbsstatic moduledata_t ahd_mod = { 142797883Sgibbs "ahd", 142897883Sgibbs ahd_modevent, 142997883Sgibbs NULL 143097883Sgibbs}; 143197883Sgibbs 143297883Sgibbs/********************************** DDB Hooks *********************************/ 143397883Sgibbs#ifdef DDB 143497883Sgibbsstatic struct ahd_softc *ahd_ddb_softc; 143597883Sgibbsstatic int ahd_ddb_paused; 143697883Sgibbsstatic int ahd_ddb_paused_on_entry; 1437133122SgibbsDB_COMMAND(ahd_sunit, ahd_ddb_sunit) 143897883Sgibbs{ 143997883Sgibbs struct ahd_softc *list_ahd; 144097883Sgibbs 144197883Sgibbs ahd_ddb_softc = NULL; 144297883Sgibbs TAILQ_FOREACH(list_ahd, &ahd_tailq, links) { 144397883Sgibbs if (list_ahd->unit == addr) 144497883Sgibbs ahd_ddb_softc = list_ahd; 144597883Sgibbs } 144697883Sgibbs if (ahd_ddb_softc == NULL) 144797883Sgibbs db_error("No matching softc found!\n"); 144897883Sgibbs} 144997883Sgibbs 145097883SgibbsDB_COMMAND(ahd_pause, ahd_ddb_pause) 145197883Sgibbs{ 145297883Sgibbs if (ahd_ddb_softc == NULL) { 1453133122Sgibbs db_error("Must set unit with ahd_sunit first!\n"); 145497883Sgibbs return; 145597883Sgibbs } 145697883Sgibbs if (ahd_ddb_paused == 0) { 145797883Sgibbs ahd_ddb_paused++; 145897883Sgibbs if (ahd_is_paused(ahd_ddb_softc)) { 145997883Sgibbs ahd_ddb_paused_on_entry++; 146097883Sgibbs return; 146197883Sgibbs } 146297883Sgibbs ahd_pause(ahd_ddb_softc); 146397883Sgibbs } 146497883Sgibbs} 146597883Sgibbs 146697883SgibbsDB_COMMAND(ahd_unpause, ahd_ddb_unpause) 146797883Sgibbs{ 146897883Sgibbs if (ahd_ddb_softc == NULL) { 1469133122Sgibbs db_error("Must set unit with ahd_sunit first!\n"); 147097883Sgibbs return; 147197883Sgibbs } 147297883Sgibbs if (ahd_ddb_paused != 0) { 147397883Sgibbs ahd_ddb_paused = 0; 147497883Sgibbs if (ahd_ddb_paused_on_entry) 147597883Sgibbs return; 147697883Sgibbs ahd_unpause(ahd_ddb_softc); 147797883Sgibbs } else if (ahd_ddb_paused_on_entry != 0) { 147897883Sgibbs /* Two unpauses to clear a paused on entry. */ 147997883Sgibbs ahd_ddb_paused_on_entry = 0; 148097883Sgibbs ahd_unpause(ahd_ddb_softc); 148197883Sgibbs } 148297883Sgibbs} 148397883Sgibbs 148497883SgibbsDB_COMMAND(ahd_in, ahd_ddb_in) 148597883Sgibbs{ 148697883Sgibbs int c; 148797883Sgibbs int size; 148897883Sgibbs 148997883Sgibbs if (ahd_ddb_softc == NULL) { 1490133122Sgibbs db_error("Must set unit with ahd_sunit first!\n"); 149197883Sgibbs return; 149297883Sgibbs } 149397883Sgibbs if (have_addr == 0) 149497883Sgibbs return; 149597883Sgibbs 149697883Sgibbs size = 1; 149797883Sgibbs while ((c = *modif++) != '\0') { 149897883Sgibbs switch (c) { 149997883Sgibbs case 'b': 150097883Sgibbs size = 1; 150197883Sgibbs break; 150297883Sgibbs case 'w': 150397883Sgibbs size = 2; 150497883Sgibbs break; 150597883Sgibbs case 'l': 150697883Sgibbs size = 4; 150797883Sgibbs break; 150897883Sgibbs } 150997883Sgibbs } 151097883Sgibbs 151197883Sgibbs if (count <= 0) 151297883Sgibbs count = 1; 151397883Sgibbs while (--count >= 0) { 1514107368Sscottl db_printf("%04lx (M)%x: \t", (u_long)addr, 151597883Sgibbs ahd_inb(ahd_ddb_softc, MODE_PTR)); 151697883Sgibbs switch (size) { 151797883Sgibbs case 1: 151897883Sgibbs db_printf("%02x\n", ahd_inb(ahd_ddb_softc, addr)); 151997883Sgibbs break; 152097883Sgibbs case 2: 152197883Sgibbs db_printf("%04x\n", ahd_inw(ahd_ddb_softc, addr)); 152297883Sgibbs break; 152397883Sgibbs case 4: 152497883Sgibbs db_printf("%08x\n", ahd_inl(ahd_ddb_softc, addr)); 152597883Sgibbs break; 152697883Sgibbs } 152797883Sgibbs } 152897883Sgibbs} 152997883Sgibbs 1530183054SsamDB_FUNC(ahd_out, ahd_ddb_out, db_cmd_table, CS_MORE, NULL) 153197883Sgibbs{ 153297883Sgibbs db_expr_t old_value; 153397883Sgibbs db_expr_t new_value; 153497883Sgibbs int size; 153597883Sgibbs 153697883Sgibbs if (ahd_ddb_softc == NULL) { 1537133122Sgibbs db_error("Must set unit with ahd_sunit first!\n"); 153897883Sgibbs return; 153997883Sgibbs } 154097883Sgibbs 154197883Sgibbs switch (modif[0]) { 154297883Sgibbs case '\0': 154397883Sgibbs case 'b': 154497883Sgibbs size = 1; 154597883Sgibbs break; 154697883Sgibbs case 'h': 154797883Sgibbs size = 2; 154897883Sgibbs break; 154997883Sgibbs case 'l': 155097883Sgibbs size = 4; 155197883Sgibbs break; 155297883Sgibbs default: 155397883Sgibbs db_error("Unknown size\n"); 155497883Sgibbs return; 155597883Sgibbs } 155697883Sgibbs 155797883Sgibbs while (db_expression(&new_value)) { 155897883Sgibbs switch (size) { 155997883Sgibbs default: 156097883Sgibbs case 1: 156197883Sgibbs old_value = ahd_inb(ahd_ddb_softc, addr); 156297883Sgibbs ahd_outb(ahd_ddb_softc, addr, new_value); 156397883Sgibbs break; 156497883Sgibbs case 2: 156597883Sgibbs old_value = ahd_inw(ahd_ddb_softc, addr); 156697883Sgibbs ahd_outw(ahd_ddb_softc, addr, new_value); 156797883Sgibbs break; 156897883Sgibbs case 4: 156997883Sgibbs old_value = ahd_inl(ahd_ddb_softc, addr); 157097883Sgibbs ahd_outl(ahd_ddb_softc, addr, new_value); 157197883Sgibbs break; 157297883Sgibbs } 1573107368Sscottl db_printf("%04lx (M)%x: \t0x%lx\t=\t0x%lx", 1574107368Sscottl (u_long)addr, ahd_inb(ahd_ddb_softc, MODE_PTR), 1575107368Sscottl (u_long)old_value, (u_long)new_value); 157697883Sgibbs addr += size; 157797883Sgibbs } 157897883Sgibbs db_skip_to_eol(); 157997883Sgibbs} 158097883Sgibbs 1581133122SgibbsDB_COMMAND(ahd_dump, ahd_ddb_dump) 1582133122Sgibbs{ 1583133122Sgibbs if (ahd_ddb_softc == NULL) { 1584133122Sgibbs db_error("Must set unit with ahd_sunit first!\n"); 1585133122Sgibbs return; 1586133122Sgibbs } 1587133122Sgibbs ahd_dump_card_state(ahd_ddb_softc); 1588133122Sgibbs} 1589133122Sgibbs 159097883Sgibbs#endif 159197883Sgibbs 159297883Sgibbs 159397883SgibbsDECLARE_MODULE(ahd, ahd_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); 159497883SgibbsMODULE_DEPEND(ahd, cam, 1, 1, 1); 159597883SgibbsMODULE_VERSION(ahd, 1); 1596