1139749Simp/*- 232801Sjulian * Copyright (c) 1997 by Simon Shapiro 332801Sjulian * All Rights Reserved 432801Sjulian * 532801Sjulian * Redistribution and use in source and binary forms, with or without 632801Sjulian * modification, are permitted provided that the following conditions 732801Sjulian * are met: 832801Sjulian * 1. Redistributions of source code must retain the above copyright 932801Sjulian * notice, this list of conditions, and the following disclaimer, 1032801Sjulian * without modification, immediately at the beginning of the file. 1132801Sjulian * 2. Redistributions in binary form must reproduce the above copyright 1232801Sjulian * notice, this list of conditions and the following disclaimer in the 1332801Sjulian * documentation and/or other materials provided with the distribution. 1432801Sjulian * 3. The name of the author may not be used to endorse or promote products 1532801Sjulian * derived from this software without specific prior written permission. 1632801Sjulian * 1732801Sjulian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1832801Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1932801Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2032801Sjulian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 2132801Sjulian * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2232801Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2332801Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2432801Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2532801Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2632801Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2732801Sjulian * SUCH DAMAGE. 2832801Sjulian */ 2932801Sjulian 30119418Sobrien#include <sys/cdefs.h> 31119418Sobrien__FBSDID("$FreeBSD: releng/10.3/sys/dev/dpt/dpt_scsi.c 281826 2015-04-21 11:27:50Z mav $"); 32119418Sobrien 3339234Sgibbs/* 3432801Sjulian * dpt_scsi.c: SCSI dependant code for the DPT driver 3532801Sjulian * 3632801Sjulian * credits: Assisted by Mike Neuffer in the early low level DPT code 3732801Sjulian * Thanx to Mark Salyzyn of DPT for his assistance. 3832801Sjulian * Special thanx to Justin Gibbs for invaluable help in 3932801Sjulian * making this driver look and work like a FreeBSD component. 4032801Sjulian * Last but not least, many thanx to UCB and the FreeBSD 4132801Sjulian * team for creating and maintaining such a wonderful O/S. 4232801Sjulian * 4339234Sgibbs * TODO: * Add ISA probe code. 4439234Sgibbs * * Add driver-level RAID-0. This will allow interoperability with 4538115Seivind * NiceTry, M$-Doze, Win-Dog, Slowlaris, etc., in recognizing RAID 4632801Sjulian * arrays that span controllers (Wow!). 4732801Sjulian */ 4832801Sjulian 4932801Sjulian#define _DPT_C_ 5032801Sjulian 5132801Sjulian#include "opt_dpt.h" 52166091Smarius#include "opt_eisa.h" 53166091Smarius 5432801Sjulian#include <sys/param.h> 5532801Sjulian#include <sys/systm.h> 56241593Sjhb#include <sys/conf.h> 5750135Smsmith#include <sys/eventhandler.h> 5832801Sjulian#include <sys/malloc.h> 5932801Sjulian#include <sys/kernel.h> 6032801Sjulian 6159078Smdodd#include <sys/bus.h> 6259078Smdodd 6339234Sgibbs#include <machine/bus.h> 6459078Smdodd 65112780Smdodd#include <machine/resource.h> 66112780Smdodd#include <sys/rman.h> 6732801Sjulian 68112780Smdodd 6939234Sgibbs#include <cam/cam.h> 7039234Sgibbs#include <cam/cam_ccb.h> 7139234Sgibbs#include <cam/cam_sim.h> 7239234Sgibbs#include <cam/cam_xpt_sim.h> 7339234Sgibbs#include <cam/cam_debug.h> 7439234Sgibbs#include <cam/scsi/scsi_all.h> 7539234Sgibbs#include <cam/scsi/scsi_message.h> 7639234Sgibbs 7732801Sjulian#include <vm/vm.h> 7832801Sjulian#include <vm/pmap.h> 7932801Sjulian 8039234Sgibbs#include <dev/dpt/dpt.h> 8138115Seivind 8239234Sgibbs/* dpt_isa.c, dpt_eisa.c, and dpt_pci.c need this in a central place */ 83112780Smdodddevclass_t dpt_devclass; 8432801Sjulian 8539234Sgibbs#define microtime_now dpt_time_now() 8634480Sjulian 8739234Sgibbs#define dpt_inl(dpt, port) \ 88241593Sjhb bus_read_4((dpt)->io_res, (dpt)->io_offset + port) 8939234Sgibbs#define dpt_inb(dpt, port) \ 90241593Sjhb bus_read_1((dpt)->io_res, (dpt)->io_offset + port) 9139234Sgibbs#define dpt_outl(dpt, port, value) \ 92241593Sjhb bus_write_4((dpt)->io_res, (dpt)->io_offset + port, value) 9339234Sgibbs#define dpt_outb(dpt, port, value) \ 94241593Sjhb bus_write_1((dpt)->io_res, (dpt)->io_offset + port, value) 9534480Sjulian 9639234Sgibbs/* 9739234Sgibbs * These will have to be setup by parameters passed at boot/load time. For 9839234Sgibbs * perfromance reasons, we make them constants for the time being. 9939234Sgibbs */ 10039234Sgibbs#define dpt_min_segs DPT_MAX_SEGS 10139234Sgibbs#define dpt_max_segs DPT_MAX_SEGS 10232801Sjulian 10339234Sgibbs/* Definitions for our use of the SIM private CCB area */ 10439234Sgibbs#define ccb_dccb_ptr spriv_ptr0 10539234Sgibbs#define ccb_dpt_ptr spriv_ptr1 10638115Seivind 10739234Sgibbs/* ================= Private Inline Function declarations ===================*/ 10839234Sgibbsstatic __inline int dpt_just_reset(dpt_softc_t * dpt); 10939234Sgibbsstatic __inline int dpt_raid_busy(dpt_softc_t * dpt); 110166091Smarius#ifdef DEV_EISA 11152042Smdoddstatic __inline int dpt_pio_wait (u_int32_t, u_int, u_int, u_int); 112166091Smarius#endif 11339234Sgibbsstatic __inline int dpt_wait(dpt_softc_t *dpt, u_int bits, 11439234Sgibbs u_int state); 11539234Sgibbsstatic __inline struct dpt_ccb* dptgetccb(struct dpt_softc *dpt); 11639234Sgibbsstatic __inline void dptfreeccb(struct dpt_softc *dpt, 11739234Sgibbs struct dpt_ccb *dccb); 118106527Sjhbstatic __inline bus_addr_t dptccbvtop(struct dpt_softc *dpt, 11939234Sgibbs struct dpt_ccb *dccb); 12032801Sjulian 12139234Sgibbsstatic __inline int dpt_send_immediate(dpt_softc_t *dpt, 12239234Sgibbs eata_ccb_t *cmd_block, 12339234Sgibbs u_int32_t cmd_busaddr, 12439234Sgibbs u_int retries, 12539234Sgibbs u_int ifc, u_int code, 12639234Sgibbs u_int code2); 12732801Sjulian 12839234Sgibbs/* ==================== Private Function declarations =======================*/ 12939234Sgibbsstatic void dptmapmem(void *arg, bus_dma_segment_t *segs, 13039234Sgibbs int nseg, int error); 13132801Sjulian 13239234Sgibbsstatic struct sg_map_node* 13339234Sgibbs dptallocsgmap(struct dpt_softc *dpt); 13432801Sjulian 13539234Sgibbsstatic int dptallocccbs(dpt_softc_t *dpt); 13632801Sjulian 13739234Sgibbsstatic int dpt_get_conf(dpt_softc_t *dpt, dpt_ccb_t *dccb, 13839234Sgibbs u_int32_t dccb_busaddr, u_int size, 13939234Sgibbs u_int page, u_int target, int extent); 14039234Sgibbsstatic void dpt_detect_cache(dpt_softc_t *dpt, dpt_ccb_t *dccb, 14139234Sgibbs u_int32_t dccb_busaddr, 14239234Sgibbs u_int8_t *buff); 14332801Sjulian 14439234Sgibbsstatic void dpt_poll(struct cam_sim *sim); 145241593Sjhbstatic void dpt_intr_locked(dpt_softc_t *dpt); 14632801Sjulian 14739234Sgibbsstatic void dptexecuteccb(void *arg, bus_dma_segment_t *dm_segs, 14839234Sgibbs int nseg, int error); 14932801Sjulian 15039234Sgibbsstatic void dpt_action(struct cam_sim *sim, union ccb *ccb); 15132801Sjulian 15239234Sgibbsstatic int dpt_send_eata_command(dpt_softc_t *dpt, eata_ccb_t *cmd, 15339234Sgibbs u_int32_t cmd_busaddr, 15439234Sgibbs u_int command, u_int retries, 15539234Sgibbs u_int ifc, u_int code, 15639234Sgibbs u_int code2); 15739234Sgibbsstatic void dptprocesserror(dpt_softc_t *dpt, dpt_ccb_t *dccb, 15839234Sgibbs union ccb *ccb, u_int hba_stat, 15939234Sgibbs u_int scsi_stat, u_int32_t resid); 16032801Sjulian 16139234Sgibbsstatic void dpttimeout(void *arg); 16250107Smsmithstatic void dptshutdown(void *arg, int howto); 16334480Sjulian 16439234Sgibbs/* ================= Private Inline Function definitions ====================*/ 16539234Sgibbsstatic __inline int 16639234Sgibbsdpt_just_reset(dpt_softc_t * dpt) 16739234Sgibbs{ 16839234Sgibbs if ((dpt_inb(dpt, 2) == 'D') 16939234Sgibbs && (dpt_inb(dpt, 3) == 'P') 17039234Sgibbs && (dpt_inb(dpt, 4) == 'T') 17139234Sgibbs && (dpt_inb(dpt, 5) == 'H')) 17239234Sgibbs return (1); 17339234Sgibbs else 17439234Sgibbs return (0); 17539234Sgibbs} 17632801Sjulian 17739234Sgibbsstatic __inline int 17839234Sgibbsdpt_raid_busy(dpt_softc_t * dpt) 17939234Sgibbs{ 18039234Sgibbs if ((dpt_inb(dpt, 0) == 'D') 18139234Sgibbs && (dpt_inb(dpt, 1) == 'P') 18239234Sgibbs && (dpt_inb(dpt, 2) == 'T')) 18339234Sgibbs return (1); 18439234Sgibbs else 18539234Sgibbs return (0); 18639234Sgibbs} 18732801Sjulian 188166091Smarius#ifdef DEV_EISA 18939234Sgibbsstatic __inline int 19052042Smdodddpt_pio_wait (u_int32_t base, u_int reg, u_int bits, u_int state) 19152042Smdodd{ 19252042Smdodd int i; 19352042Smdodd u_int c; 19452042Smdodd 19552042Smdodd for (i = 0; i < 20000; i++) { /* wait 20ms for not busy */ 19652042Smdodd c = inb(base + reg) & bits; 19752042Smdodd if (!(c == state)) 19852042Smdodd return (0); 19952042Smdodd else 20052042Smdodd DELAY(50); 20152042Smdodd } 20252042Smdodd return (-1); 20352042Smdodd} 204166091Smarius#endif 20552042Smdodd 20652042Smdoddstatic __inline int 20739234Sgibbsdpt_wait(dpt_softc_t *dpt, u_int bits, u_int state) 20839234Sgibbs{ 20939234Sgibbs int i; 21039234Sgibbs u_int c; 21132801Sjulian 21239234Sgibbs for (i = 0; i < 20000; i++) { /* wait 20ms for not busy */ 21339234Sgibbs c = dpt_inb(dpt, HA_RSTATUS) & bits; 21439234Sgibbs if (c == state) 21539234Sgibbs return (0); 21639234Sgibbs else 21739234Sgibbs DELAY(50); 21839234Sgibbs } 21939234Sgibbs return (-1); 22039234Sgibbs} 22132801Sjulian 22239234Sgibbsstatic __inline struct dpt_ccb* 22339234Sgibbsdptgetccb(struct dpt_softc *dpt) 22439234Sgibbs{ 22539234Sgibbs struct dpt_ccb* dccb; 22632801Sjulian 227241593Sjhb if (!dumping) 228241593Sjhb mtx_assert(&dpt->lock, MA_OWNED); 22939234Sgibbs if ((dccb = SLIST_FIRST(&dpt->free_dccb_list)) != NULL) { 23039234Sgibbs SLIST_REMOVE_HEAD(&dpt->free_dccb_list, links); 23139234Sgibbs dpt->free_dccbs--; 23239234Sgibbs } else if (dpt->total_dccbs < dpt->max_dccbs) { 23339234Sgibbs dptallocccbs(dpt); 23439234Sgibbs dccb = SLIST_FIRST(&dpt->free_dccb_list); 23539234Sgibbs if (dccb == NULL) 236241593Sjhb device_printf(dpt->dev, "Can't malloc DCCB\n"); 23739234Sgibbs else { 23839234Sgibbs SLIST_REMOVE_HEAD(&dpt->free_dccb_list, links); 23939234Sgibbs dpt->free_dccbs--; 24039234Sgibbs } 24139234Sgibbs } 24239234Sgibbs 24339234Sgibbs return (dccb); 24439234Sgibbs} 24539234Sgibbs 24639234Sgibbsstatic __inline void 24739234Sgibbsdptfreeccb(struct dpt_softc *dpt, struct dpt_ccb *dccb) 24832801Sjulian{ 24932801Sjulian 250241593Sjhb if (!dumping) 251241593Sjhb mtx_assert(&dpt->lock, MA_OWNED); 25239234Sgibbs if ((dccb->state & DCCB_ACTIVE) != 0) 25339234Sgibbs LIST_REMOVE(&dccb->ccb->ccb_h, sim_links.le); 25439234Sgibbs if ((dccb->state & DCCB_RELEASE_SIMQ) != 0) 25539234Sgibbs dccb->ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 25639234Sgibbs else if (dpt->resource_shortage != 0 25739234Sgibbs && (dccb->ccb->ccb_h.status & CAM_RELEASE_SIMQ) == 0) { 25839234Sgibbs dccb->ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 25939234Sgibbs dpt->resource_shortage = FALSE; 26039234Sgibbs } 26139234Sgibbs dccb->state = DCCB_FREE; 26239234Sgibbs SLIST_INSERT_HEAD(&dpt->free_dccb_list, dccb, links); 26339234Sgibbs ++dpt->free_dccbs; 26439234Sgibbs} 26539234Sgibbs 266106527Sjhbstatic __inline bus_addr_t 26739234Sgibbsdptccbvtop(struct dpt_softc *dpt, struct dpt_ccb *dccb) 26832801Sjulian{ 26939234Sgibbs return (dpt->dpt_ccb_busbase 27039234Sgibbs + (u_int32_t)((caddr_t)dccb - (caddr_t)dpt->dpt_dccbs)); 27139234Sgibbs} 27232801Sjulian 27339234Sgibbsstatic __inline struct dpt_ccb * 274106527Sjhbdptccbptov(struct dpt_softc *dpt, bus_addr_t busaddr) 27539234Sgibbs{ 27639234Sgibbs return (dpt->dpt_dccbs 27739234Sgibbs + ((struct dpt_ccb *)busaddr 27839234Sgibbs - (struct dpt_ccb *)dpt->dpt_ccb_busbase)); 27939234Sgibbs} 28032801Sjulian 28139234Sgibbs/* 28239234Sgibbs * Send a command for immediate execution by the DPT 28339234Sgibbs * See above function for IMPORTANT notes. 28439234Sgibbs */ 28539234Sgibbsstatic __inline int 28639234Sgibbsdpt_send_immediate(dpt_softc_t *dpt, eata_ccb_t *cmd_block, 28739234Sgibbs u_int32_t cmd_busaddr, u_int retries, 28839234Sgibbs u_int ifc, u_int code, u_int code2) 28939234Sgibbs{ 29039234Sgibbs return (dpt_send_eata_command(dpt, cmd_block, cmd_busaddr, 29139234Sgibbs EATA_CMD_IMMEDIATE, retries, ifc, 29239234Sgibbs code, code2)); 29339234Sgibbs} 29439234Sgibbs 29539234Sgibbs 29639234Sgibbs/* ===================== Private Function definitions =======================*/ 29732801Sjulianstatic void 29839234Sgibbsdptmapmem(void *arg, bus_dma_segment_t *segs, int nseg, int error) 29932801Sjulian{ 30039234Sgibbs bus_addr_t *busaddrp; 30139234Sgibbs 30239234Sgibbs busaddrp = (bus_addr_t *)arg; 30339234Sgibbs *busaddrp = segs->ds_addr; 30432801Sjulian} 30532801Sjulian 30639234Sgibbsstatic struct sg_map_node * 30739234Sgibbsdptallocsgmap(struct dpt_softc *dpt) 30839234Sgibbs{ 30939234Sgibbs struct sg_map_node *sg_map; 31032801Sjulian 31139234Sgibbs sg_map = malloc(sizeof(*sg_map), M_DEVBUF, M_NOWAIT); 31239234Sgibbs 31339234Sgibbs if (sg_map == NULL) 31439234Sgibbs return (NULL); 31539234Sgibbs 31639234Sgibbs /* Allocate S/G space for the next batch of CCBS */ 31739234Sgibbs if (bus_dmamem_alloc(dpt->sg_dmat, (void **)&sg_map->sg_vaddr, 31839234Sgibbs BUS_DMA_NOWAIT, &sg_map->sg_dmamap) != 0) { 31939234Sgibbs free(sg_map, M_DEVBUF); 32039234Sgibbs return (NULL); 32139234Sgibbs } 32239234Sgibbs 32342018Seivind (void)bus_dmamap_load(dpt->sg_dmat, sg_map->sg_dmamap, sg_map->sg_vaddr, 32442018Seivind PAGE_SIZE, dptmapmem, &sg_map->sg_physaddr, 32542018Seivind /*flags*/0); 32641996Seivind 32739234Sgibbs SLIST_INSERT_HEAD(&dpt->sg_maps, sg_map, links); 32839234Sgibbs 32939234Sgibbs return (sg_map); 33039234Sgibbs} 33139234Sgibbs 33239234Sgibbs/* 33339234Sgibbs * Allocate another chunk of CCB's. Return count of entries added. 33439234Sgibbs */ 33539234Sgibbsstatic int 33639234Sgibbsdptallocccbs(dpt_softc_t *dpt) 33732801Sjulian{ 33839234Sgibbs struct dpt_ccb *next_ccb; 33939234Sgibbs struct sg_map_node *sg_map; 34039234Sgibbs bus_addr_t physaddr; 34139234Sgibbs dpt_sg_t *segs; 34239234Sgibbs int newcount; 34339234Sgibbs int i; 34432801Sjulian 345241593Sjhb if (!dumping) 346241593Sjhb mtx_assert(&dpt->lock, MA_OWNED); 34739234Sgibbs next_ccb = &dpt->dpt_dccbs[dpt->total_dccbs]; 34839234Sgibbs 34939234Sgibbs if (next_ccb == dpt->dpt_dccbs) { 35039234Sgibbs /* 35139234Sgibbs * First time through. Re-use the S/G 35239234Sgibbs * space we allocated for initialization 35339234Sgibbs * CCBS. 35439234Sgibbs */ 35539234Sgibbs sg_map = SLIST_FIRST(&dpt->sg_maps); 35632801Sjulian } else { 35739234Sgibbs sg_map = dptallocsgmap(dpt); 35832801Sjulian } 35939234Sgibbs 36039234Sgibbs if (sg_map == NULL) 36139234Sgibbs return (0); 36239234Sgibbs 36339234Sgibbs segs = sg_map->sg_vaddr; 36439234Sgibbs physaddr = sg_map->sg_physaddr; 36539234Sgibbs 36639234Sgibbs newcount = (PAGE_SIZE / (dpt->sgsize * sizeof(dpt_sg_t))); 36739234Sgibbs for (i = 0; dpt->total_dccbs < dpt->max_dccbs && i < newcount; i++) { 36839234Sgibbs int error; 36939234Sgibbs 37039234Sgibbs error = bus_dmamap_create(dpt->buffer_dmat, /*flags*/0, 37139234Sgibbs &next_ccb->dmamap); 37239234Sgibbs if (error != 0) 37339234Sgibbs break; 374241593Sjhb callout_init_mtx(&next_ccb->timer, &dpt->lock, 0); 37539234Sgibbs next_ccb->sg_list = segs; 37639234Sgibbs next_ccb->sg_busaddr = htonl(physaddr); 37739234Sgibbs next_ccb->eata_ccb.cp_dataDMA = htonl(physaddr); 37839234Sgibbs next_ccb->eata_ccb.cp_statDMA = htonl(dpt->sp_physaddr); 37939234Sgibbs next_ccb->eata_ccb.cp_reqDMA = 38039234Sgibbs htonl(dptccbvtop(dpt, next_ccb) 38139234Sgibbs + offsetof(struct dpt_ccb, sense_data)); 38239234Sgibbs next_ccb->eata_ccb.cp_busaddr = dpt->dpt_ccb_busend; 38339234Sgibbs next_ccb->state = DCCB_FREE; 38439515Sgibbs next_ccb->tag = dpt->total_dccbs; 38539234Sgibbs SLIST_INSERT_HEAD(&dpt->free_dccb_list, next_ccb, links); 38639553Sgibbs segs += dpt->sgsize; 38739234Sgibbs physaddr += (dpt->sgsize * sizeof(dpt_sg_t)); 38839234Sgibbs dpt->dpt_ccb_busend += sizeof(*next_ccb); 38939234Sgibbs next_ccb++; 39039234Sgibbs dpt->total_dccbs++; 39139234Sgibbs } 39239234Sgibbs return (i); 39332801Sjulian} 39432801Sjulian 395166091Smarius#ifdef DEV_EISA 39652042Smdodddpt_conf_t * 39752042Smdodddpt_pio_get_conf (u_int32_t base) 39852042Smdodd{ 39952042Smdodd static dpt_conf_t * conf; 40052042Smdodd u_int16_t * p; 40152042Smdodd int i; 40252042Smdodd 40352042Smdodd /* 40452042Smdodd * Allocate a dpt_conf_t 40552042Smdodd */ 40652042Smdodd if (!conf) { 40752042Smdodd conf = (dpt_conf_t *)malloc(sizeof(dpt_conf_t), 408241593Sjhb M_DEVBUF, M_NOWAIT | M_ZERO); 40952042Smdodd } 41052042Smdodd 41152042Smdodd /* 41252042Smdodd * If we didn't get one then we probably won't ever get one. 41352042Smdodd */ 41452042Smdodd if (!conf) { 41552042Smdodd printf("dpt: unable to allocate dpt_conf_t\n"); 41652042Smdodd return (NULL); 41752042Smdodd } 41852042Smdodd 41952042Smdodd /* 42052042Smdodd * Reset the controller. 42152042Smdodd */ 42252042Smdodd outb((base + HA_WCOMMAND), EATA_CMD_RESET); 42352042Smdodd 42452042Smdodd /* 42552042Smdodd * Wait for the controller to become ready. 42659078Smdodd * For some reason there can be -no- delays after calling reset 42759078Smdodd * before we wait on ready status. 42852042Smdodd */ 42952042Smdodd if (dpt_pio_wait(base, HA_RSTATUS, HA_SBUSY, 0)) { 43052042Smdodd printf("dpt: timeout waiting for controller to become ready\n"); 43152042Smdodd return (NULL); 43252042Smdodd } 43352042Smdodd 43452042Smdodd if (dpt_pio_wait(base, HA_RAUXSTAT, HA_ABUSY, 0)) { 43552042Smdodd printf("dpt: timetout waiting for adapter ready.\n"); 43652042Smdodd return (NULL); 43752042Smdodd } 43852042Smdodd 43952042Smdodd /* 44052042Smdodd * Send the PIO_READ_CONFIG command. 44152042Smdodd */ 44252042Smdodd outb((base + HA_WCOMMAND), EATA_CMD_PIO_READ_CONFIG); 44352042Smdodd 44452042Smdodd /* 44552042Smdodd * Read the data into the struct. 44652042Smdodd */ 44752042Smdodd p = (u_int16_t *)conf; 44852042Smdodd for (i = 0; i < (sizeof(dpt_conf_t) / 2); i++) { 44952042Smdodd 45052042Smdodd if (dpt_pio_wait(base, HA_RSTATUS, HA_SDRQ, 0)) { 451112780Smdodd if (bootverbose) 452112780Smdodd printf("dpt: timeout in data read.\n"); 45352042Smdodd return (NULL); 45452042Smdodd } 45552042Smdodd 45659078Smdodd (*p) = inw(base + HA_RDATA); 45752042Smdodd p++; 45852042Smdodd } 45952042Smdodd 46052042Smdodd if (inb(base + HA_RSTATUS) & HA_SERROR) { 461112780Smdodd if (bootverbose) 462112780Smdodd printf("dpt: error reading configuration data.\n"); 46352042Smdodd return (NULL); 46452042Smdodd } 46552042Smdodd 46652042Smdodd#define BE_EATA_SIGNATURE 0x45415441 46752042Smdodd#define LE_EATA_SIGNATURE 0x41544145 46852042Smdodd 46952042Smdodd /* 47052042Smdodd * Test to see if we have a valid card. 47152042Smdodd */ 47252042Smdodd if ((conf->signature == BE_EATA_SIGNATURE) || 47352042Smdodd (conf->signature == LE_EATA_SIGNATURE)) { 47452042Smdodd 47552042Smdodd while (inb(base + HA_RSTATUS) & HA_SDRQ) { 47652042Smdodd inw(base + HA_RDATA); 47752042Smdodd } 47852042Smdodd 47952042Smdodd return (conf); 48052042Smdodd } 48152042Smdodd return (NULL); 48252042Smdodd} 483166091Smarius#endif 48452042Smdodd 48539234Sgibbs/* 48639234Sgibbs * Read a configuration page into the supplied dpt_cont_t buffer. 48739234Sgibbs */ 48839234Sgibbsstatic int 48939234Sgibbsdpt_get_conf(dpt_softc_t *dpt, dpt_ccb_t *dccb, u_int32_t dccb_busaddr, 49039234Sgibbs u_int size, u_int page, u_int target, int extent) 49132801Sjulian{ 49239234Sgibbs eata_ccb_t *cp; 49332801Sjulian 49440419Sgibbs u_int8_t status; 49539234Sgibbs 49639234Sgibbs int ndx; 49739234Sgibbs int result; 49839234Sgibbs 499241593Sjhb mtx_assert(&dpt->lock, MA_OWNED); 50039234Sgibbs cp = &dccb->eata_ccb; 50164355Speter bzero((void *)(uintptr_t)(volatile void *)dpt->sp, sizeof(*dpt->sp)); 50239234Sgibbs 50339234Sgibbs cp->Interpret = 1; 50439234Sgibbs cp->DataIn = 1; 50539234Sgibbs cp->Auto_Req_Sen = 1; 50639234Sgibbs cp->reqlen = sizeof(struct scsi_sense_data); 50739234Sgibbs 50839234Sgibbs cp->cp_id = target; 50939234Sgibbs cp->cp_LUN = 0; /* In the EATA packet */ 51039234Sgibbs cp->cp_lun = 0; /* In the SCSI command */ 51139234Sgibbs 51239234Sgibbs cp->cp_scsi_cmd = INQUIRY; 51339234Sgibbs cp->cp_len = size; 51439234Sgibbs 51539234Sgibbs cp->cp_extent = extent; 51639234Sgibbs 51739234Sgibbs cp->cp_page = page; 51839234Sgibbs cp->cp_channel = 0; /* DNC, Interpret mode is set */ 51939234Sgibbs cp->cp_identify = 1; 52039234Sgibbs cp->cp_datalen = htonl(size); 52139234Sgibbs 52239234Sgibbs /* 52339234Sgibbs * This could be a simple for loop, but we suspected the compiler To 52439234Sgibbs * have optimized it a bit too much. Wait for the controller to 52539234Sgibbs * become ready 52639234Sgibbs */ 52739234Sgibbs while (((status = dpt_inb(dpt, HA_RSTATUS)) != (HA_SREADY | HA_SSC) 52839234Sgibbs && (status != (HA_SREADY | HA_SSC | HA_SERROR)) 52939234Sgibbs && (status != (HA_SDRDY | HA_SERROR | HA_SDRQ))) 53039234Sgibbs || (dpt_wait(dpt, HA_SBUSY, 0))) { 53139234Sgibbs 53239234Sgibbs /* 53339234Sgibbs * RAID Drives still Spinning up? (This should only occur if 53439234Sgibbs * the DPT controller is in a NON PC (PCI?) platform). 53539234Sgibbs */ 53639234Sgibbs if (dpt_raid_busy(dpt)) { 537241593Sjhb device_printf(dpt->dev, 538241593Sjhb "WARNING: Get_conf() RSUS failed.\n"); 53939234Sgibbs return (0); 54039234Sgibbs } 54132801Sjulian } 54239234Sgibbs 54339234Sgibbs DptStat_Reset_BUSY(dpt->sp); 54439234Sgibbs 54539234Sgibbs /* 54639234Sgibbs * XXXX We might want to do something more clever than aborting at 54739234Sgibbs * this point, like resetting (rebooting) the controller and trying 54839234Sgibbs * again. 54939234Sgibbs */ 55039234Sgibbs if ((result = dpt_send_eata_command(dpt, cp, dccb_busaddr, 55139234Sgibbs EATA_CMD_DMA_SEND_CP, 55239234Sgibbs 10000, 0, 0, 0)) != 0) { 553241593Sjhb device_printf(dpt->dev, 554241593Sjhb "WARNING: Get_conf() failed (%d) to send " 55539234Sgibbs "EATA_CMD_DMA_READ_CONFIG\n", 556241593Sjhb result); 55739234Sgibbs return (0); 55839234Sgibbs } 55939234Sgibbs /* Wait for two seconds for a response. This can be slow */ 56039234Sgibbs for (ndx = 0; 56139234Sgibbs (ndx < 20000) 56239234Sgibbs && !((status = dpt_inb(dpt, HA_RAUXSTAT)) & HA_AIRQ); 56339234Sgibbs ndx++) { 56439234Sgibbs DELAY(50); 56539234Sgibbs } 56639234Sgibbs 56739234Sgibbs /* Grab the status and clear interrupts */ 56839234Sgibbs status = dpt_inb(dpt, HA_RSTATUS); 56939234Sgibbs 57039234Sgibbs /* 57139234Sgibbs * Check the status carefully. Return only if the 57239234Sgibbs * command was successful. 57339234Sgibbs */ 57439234Sgibbs if (((status & HA_SERROR) == 0) 57539234Sgibbs && (dpt->sp->hba_stat == 0) 57639234Sgibbs && (dpt->sp->scsi_stat == 0) 57739234Sgibbs && (dpt->sp->residue_len == 0)) 57839234Sgibbs return (0); 57959078Smdodd 58059078Smdodd if (dpt->sp->scsi_stat == SCSI_STATUS_CHECK_COND) 58159078Smdodd return (0); 58259078Smdodd 58339234Sgibbs return (1); 58432801Sjulian} 58532801Sjulian 58639234Sgibbs/* Detect Cache parameters and size */ 58739234Sgibbsstatic void 58839234Sgibbsdpt_detect_cache(dpt_softc_t *dpt, dpt_ccb_t *dccb, u_int32_t dccb_busaddr, 58939234Sgibbs u_int8_t *buff) 59032801Sjulian{ 59139234Sgibbs eata_ccb_t *cp; 59239234Sgibbs u_int8_t *param; 59339234Sgibbs int bytes; 59439234Sgibbs int result; 59539234Sgibbs int ndx; 59639234Sgibbs u_int8_t status; 59739234Sgibbs 598241593Sjhb mtx_assert(&dpt->lock, MA_OWNED); 599241593Sjhb 60039234Sgibbs /* 60139234Sgibbs * Default setting, for best perfromance.. 60239234Sgibbs * This is what virtually all cards default to.. 60339234Sgibbs */ 60439234Sgibbs dpt->cache_type = DPT_CACHE_WRITEBACK; 60539234Sgibbs dpt->cache_size = 0; 60639234Sgibbs 60739234Sgibbs cp = &dccb->eata_ccb; 60864355Speter bzero((void *)(uintptr_t)(volatile void *)dpt->sp, sizeof(dpt->sp)); 60939234Sgibbs bzero(buff, 512); 61039234Sgibbs 61139234Sgibbs /* Setup the command structure */ 61239234Sgibbs cp->Interpret = 1; 61339234Sgibbs cp->DataIn = 1; 61439234Sgibbs cp->Auto_Req_Sen = 1; 61539234Sgibbs cp->reqlen = sizeof(struct scsi_sense_data); 61639234Sgibbs 61739234Sgibbs cp->cp_id = 0; /* who cares? The HBA will interpret.. */ 61839234Sgibbs cp->cp_LUN = 0; /* In the EATA packet */ 61939234Sgibbs cp->cp_lun = 0; /* In the SCSI command */ 62039234Sgibbs cp->cp_channel = 0; 62139234Sgibbs 62239234Sgibbs cp->cp_scsi_cmd = EATA_CMD_DMA_SEND_CP; 62339234Sgibbs cp->cp_len = 56; 62439234Sgibbs 62539234Sgibbs cp->cp_extent = 0; 62639234Sgibbs cp->cp_page = 0; 62739234Sgibbs cp->cp_identify = 1; 62839234Sgibbs cp->cp_dispri = 1; 62939234Sgibbs 63039234Sgibbs /* 63139234Sgibbs * Build the EATA Command Packet structure 63239234Sgibbs * for a Log Sense Command. 63339234Sgibbs */ 63439234Sgibbs cp->cp_cdb[0] = 0x4d; 63539234Sgibbs cp->cp_cdb[1] = 0x0; 63639234Sgibbs cp->cp_cdb[2] = 0x40 | 0x33; 63739234Sgibbs cp->cp_cdb[7] = 1; 63839234Sgibbs 63939234Sgibbs cp->cp_datalen = htonl(512); 64039234Sgibbs 64139234Sgibbs result = dpt_send_eata_command(dpt, cp, dccb_busaddr, 64239234Sgibbs EATA_CMD_DMA_SEND_CP, 64339234Sgibbs 10000, 0, 0, 0); 64439234Sgibbs if (result != 0) { 645241593Sjhb device_printf(dpt->dev, 646241593Sjhb "WARNING: detect_cache() failed (%d) to send " 647241593Sjhb "EATA_CMD_DMA_SEND_CP\n", result); 64839234Sgibbs return; 64932801Sjulian } 65039234Sgibbs /* Wait for two seconds for a response. This can be slow... */ 65139234Sgibbs for (ndx = 0; 65239234Sgibbs (ndx < 20000) && 65339234Sgibbs !((status = dpt_inb(dpt, HA_RAUXSTAT)) & HA_AIRQ); 65439234Sgibbs ndx++) { 65539234Sgibbs DELAY(50); 65639234Sgibbs } 65739234Sgibbs 65839234Sgibbs /* Grab the status and clear interrupts */ 65939234Sgibbs status = dpt_inb(dpt, HA_RSTATUS); 66039234Sgibbs 66139234Sgibbs /* 66239234Sgibbs * Sanity check 66339234Sgibbs */ 66439234Sgibbs if (buff[0] != 0x33) { 66539234Sgibbs return; 66639234Sgibbs } 66739234Sgibbs bytes = DPT_HCP_LENGTH(buff); 66839234Sgibbs param = DPT_HCP_FIRST(buff); 66939234Sgibbs 67039234Sgibbs if (DPT_HCP_CODE(param) != 1) { 67139234Sgibbs /* 67239234Sgibbs * DPT Log Page layout error 67339234Sgibbs */ 674241593Sjhb device_printf(dpt->dev, "NOTICE: Log Page (1) layout error\n"); 67539234Sgibbs return; 67639234Sgibbs } 67739234Sgibbs if (!(param[4] & 0x4)) { 67839234Sgibbs dpt->cache_type = DPT_NO_CACHE; 67939234Sgibbs return; 68039234Sgibbs } 68139234Sgibbs while (DPT_HCP_CODE(param) != 6) { 68239234Sgibbs param = DPT_HCP_NEXT(param); 68339234Sgibbs if ((param < buff) 68439234Sgibbs || (param >= &buff[bytes])) { 68539234Sgibbs return; 68639234Sgibbs } 68739234Sgibbs } 68839234Sgibbs 68939234Sgibbs if (param[4] & 0x2) { 69039234Sgibbs /* 69139234Sgibbs * Cache disabled 69239234Sgibbs */ 69339234Sgibbs dpt->cache_type = DPT_NO_CACHE; 69439234Sgibbs return; 69539234Sgibbs } 69639234Sgibbs 69739234Sgibbs if (param[4] & 0x4) { 69839234Sgibbs dpt->cache_type = DPT_CACHE_WRITETHROUGH; 69939234Sgibbs } 70039234Sgibbs 70139234Sgibbs /* XXX This isn't correct. This log parameter only has two bytes.... */ 70239234Sgibbs#if 0 70339234Sgibbs dpt->cache_size = param[5] 70439234Sgibbs | (param[6] << 8) 70539234Sgibbs | (param[7] << 16) 70639234Sgibbs | (param[8] << 24); 70739234Sgibbs#endif 70832801Sjulian} 70932801Sjulian 71039234Sgibbsstatic void 71139234Sgibbsdpt_poll(struct cam_sim *sim) 71232801Sjulian{ 713241593Sjhb dpt_intr_locked(cam_sim_softc(sim)); 71439234Sgibbs} 71539234Sgibbs 71639234Sgibbsstatic void 71739234Sgibbsdptexecuteccb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) 71839234Sgibbs{ 71939234Sgibbs struct dpt_ccb *dccb; 72039234Sgibbs union ccb *ccb; 72139234Sgibbs struct dpt_softc *dpt; 72239234Sgibbs 72339234Sgibbs dccb = (struct dpt_ccb *)arg; 72439234Sgibbs ccb = dccb->ccb; 72539234Sgibbs dpt = (struct dpt_softc *)ccb->ccb_h.ccb_dpt_ptr; 726241605Spluknet if (!dumping) 727241605Spluknet mtx_assert(&dpt->lock, MA_OWNED); 72839234Sgibbs 72939234Sgibbs if (error != 0) { 73039234Sgibbs if (error != EFBIG) 731241593Sjhb device_printf(dpt->dev, 732241593Sjhb "Unexepected error 0x%x returned from " 733241593Sjhb "bus_dmamap_load\n", error); 73439234Sgibbs if (ccb->ccb_h.status == CAM_REQ_INPROG) { 73539234Sgibbs xpt_freeze_devq(ccb->ccb_h.path, /*count*/1); 73639234Sgibbs ccb->ccb_h.status = CAM_REQ_TOO_BIG|CAM_DEV_QFRZN; 73739234Sgibbs } 73839234Sgibbs dptfreeccb(dpt, dccb); 73939234Sgibbs xpt_done(ccb); 74039234Sgibbs return; 74139234Sgibbs } 74239234Sgibbs 74339234Sgibbs if (nseg != 0) { 74439234Sgibbs dpt_sg_t *sg; 74539234Sgibbs bus_dma_segment_t *end_seg; 746115343Sscottl bus_dmasync_op_t op; 74739234Sgibbs 74839234Sgibbs end_seg = dm_segs + nseg; 74939234Sgibbs 75039234Sgibbs /* Copy the segments into our SG list */ 75139234Sgibbs sg = dccb->sg_list; 75239234Sgibbs while (dm_segs < end_seg) { 75339234Sgibbs sg->seg_len = htonl(dm_segs->ds_len); 75439234Sgibbs sg->seg_addr = htonl(dm_segs->ds_addr); 75539234Sgibbs sg++; 75639234Sgibbs dm_segs++; 75739234Sgibbs } 75839234Sgibbs 75939234Sgibbs if (nseg > 1) { 76039234Sgibbs dccb->eata_ccb.scatter = 1; 76139234Sgibbs dccb->eata_ccb.cp_dataDMA = dccb->sg_busaddr; 76239234Sgibbs dccb->eata_ccb.cp_datalen = 76339234Sgibbs htonl(nseg * sizeof(dpt_sg_t)); 76439234Sgibbs } else { 76539234Sgibbs dccb->eata_ccb.cp_dataDMA = dccb->sg_list[0].seg_addr; 76639234Sgibbs dccb->eata_ccb.cp_datalen = dccb->sg_list[0].seg_len; 76739234Sgibbs } 76839234Sgibbs 76939234Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) 77039234Sgibbs op = BUS_DMASYNC_PREREAD; 77139234Sgibbs else 77239234Sgibbs op = BUS_DMASYNC_PREWRITE; 77339234Sgibbs 77439234Sgibbs bus_dmamap_sync(dpt->buffer_dmat, dccb->dmamap, op); 77539234Sgibbs 77632801Sjulian } else { 77739234Sgibbs dccb->eata_ccb.cp_dataDMA = 0; 77839234Sgibbs dccb->eata_ccb.cp_datalen = 0; 77932801Sjulian } 78039234Sgibbs 78139234Sgibbs /* 78239234Sgibbs * Last time we need to check if this CCB needs to 78339234Sgibbs * be aborted. 78439234Sgibbs */ 78539234Sgibbs if (ccb->ccb_h.status != CAM_REQ_INPROG) { 78639234Sgibbs if (nseg != 0) 78739234Sgibbs bus_dmamap_unload(dpt->buffer_dmat, dccb->dmamap); 78839234Sgibbs dptfreeccb(dpt, dccb); 78939234Sgibbs xpt_done(ccb); 79039234Sgibbs return; 79139234Sgibbs } 79239234Sgibbs 79339234Sgibbs dccb->state |= DCCB_ACTIVE; 79439234Sgibbs ccb->ccb_h.status |= CAM_SIM_QUEUED; 79539234Sgibbs LIST_INSERT_HEAD(&dpt->pending_ccb_list, &ccb->ccb_h, sim_links.le); 796275982Ssmh callout_reset_sbt(&dccb->timer, SBT_1MS * ccb->ccb_h.timeout, 0, 797275982Ssmh dpttimeout, dccb, 0); 79839234Sgibbs if (dpt_send_eata_command(dpt, &dccb->eata_ccb, 79939234Sgibbs dccb->eata_ccb.cp_busaddr, 80039234Sgibbs EATA_CMD_DMA_SEND_CP, 0, 0, 0, 0) != 0) { 80139234Sgibbs ccb->ccb_h.status = CAM_NO_HBA; /* HBA dead or just busy?? */ 80239234Sgibbs if (nseg != 0) 80339234Sgibbs bus_dmamap_unload(dpt->buffer_dmat, dccb->dmamap); 80439234Sgibbs dptfreeccb(dpt, dccb); 80539234Sgibbs xpt_done(ccb); 80639234Sgibbs } 80732801Sjulian} 80832801Sjulian 80939234Sgibbsstatic void 81039234Sgibbsdpt_action(struct cam_sim *sim, union ccb *ccb) 81132801Sjulian{ 81239234Sgibbs struct dpt_softc *dpt; 81339234Sgibbs 81439234Sgibbs CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("dpt_action\n")); 81539234Sgibbs 81639234Sgibbs dpt = (struct dpt_softc *)cam_sim_softc(sim); 817241593Sjhb mtx_assert(&dpt->lock, MA_OWNED); 81839234Sgibbs 81939234Sgibbs if ((dpt->state & DPT_HA_SHUTDOWN_ACTIVE) != 0) { 82039234Sgibbs xpt_print_path(ccb->ccb_h.path); 82139234Sgibbs printf("controller is shutdown. Aborting CCB.\n"); 82239234Sgibbs ccb->ccb_h.status = CAM_NO_HBA; 82339234Sgibbs xpt_done(ccb); 82432801Sjulian return; 82532801Sjulian } 82639234Sgibbs 82739234Sgibbs switch (ccb->ccb_h.func_code) { 82839234Sgibbs /* Common cases first */ 82939234Sgibbs case XPT_SCSI_IO: /* Execute the requested I/O operation */ 83039234Sgibbs { 83139234Sgibbs struct ccb_scsiio *csio; 83239234Sgibbs struct ccb_hdr *ccbh; 83339234Sgibbs struct dpt_ccb *dccb; 83439234Sgibbs struct eata_ccb *eccb; 83539234Sgibbs 83639234Sgibbs csio = &ccb->csio; 83739234Sgibbs ccbh = &ccb->ccb_h; 83839234Sgibbs /* Max CDB length is 12 bytes */ 83939234Sgibbs if (csio->cdb_len > 12) { 84039234Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 84139234Sgibbs xpt_done(ccb); 84239234Sgibbs return; 84339234Sgibbs } 84439234Sgibbs if ((dccb = dptgetccb(dpt)) == NULL) { 84539234Sgibbs dpt->resource_shortage = 1; 84639234Sgibbs xpt_freeze_simq(sim, /*count*/1); 84739234Sgibbs ccb->ccb_h.status = CAM_REQUEUE_REQ; 84839234Sgibbs xpt_done(ccb); 84939234Sgibbs return; 85039234Sgibbs } 85139234Sgibbs eccb = &dccb->eata_ccb; 85239234Sgibbs 85339234Sgibbs /* Link dccb and ccb so we can find one from the other */ 85439234Sgibbs dccb->ccb = ccb; 85539234Sgibbs ccb->ccb_h.ccb_dccb_ptr = dccb; 85639234Sgibbs ccb->ccb_h.ccb_dpt_ptr = dpt; 85739234Sgibbs 85839234Sgibbs /* 85939234Sgibbs * Explicitly set all flags so that the compiler can 86039553Sgibbs * be smart about setting them. 86139234Sgibbs */ 86239234Sgibbs eccb->SCSI_Reset = 0; 86339234Sgibbs eccb->HBA_Init = 0; 86439234Sgibbs eccb->Auto_Req_Sen = (ccb->ccb_h.flags & CAM_DIS_AUTOSENSE) 86539234Sgibbs ? 0 : 1; 86639234Sgibbs eccb->scatter = 0; 86739234Sgibbs eccb->Quick = 0; 86839234Sgibbs eccb->Interpret = 86939234Sgibbs ccb->ccb_h.target_id == dpt->hostid[cam_sim_bus(sim)] 87039234Sgibbs ? 1 : 0; 87139234Sgibbs eccb->DataOut = (ccb->ccb_h.flags & CAM_DIR_OUT) ? 1 : 0; 87239234Sgibbs eccb->DataIn = (ccb->ccb_h.flags & CAM_DIR_IN) ? 1 : 0; 87339234Sgibbs eccb->reqlen = csio->sense_len; 87439234Sgibbs eccb->cp_id = ccb->ccb_h.target_id; 87539234Sgibbs eccb->cp_channel = cam_sim_bus(sim); 87639234Sgibbs eccb->cp_LUN = ccb->ccb_h.target_lun; 87739234Sgibbs eccb->cp_luntar = 0; 87839234Sgibbs eccb->cp_dispri = (ccb->ccb_h.flags & CAM_DIS_DISCONNECT) 87939234Sgibbs ? 0 : 1; 88039234Sgibbs eccb->cp_identify = 1; 88139515Sgibbs 88240418Sgibbs if ((ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) != 0 88340418Sgibbs && csio->tag_action != CAM_TAG_ACTION_NONE) { 88439515Sgibbs eccb->cp_msg[0] = csio->tag_action; 88539515Sgibbs eccb->cp_msg[1] = dccb->tag; 88639515Sgibbs } else { 88739515Sgibbs eccb->cp_msg[0] = 0; 88839515Sgibbs eccb->cp_msg[1] = 0; 88939515Sgibbs } 89039234Sgibbs eccb->cp_msg[2] = 0; 89139234Sgibbs 89239234Sgibbs if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) { 89339234Sgibbs if ((ccb->ccb_h.flags & CAM_CDB_PHYS) == 0) { 89439234Sgibbs bcopy(csio->cdb_io.cdb_ptr, 89539234Sgibbs eccb->cp_cdb, csio->cdb_len); 89639234Sgibbs } else { 89739234Sgibbs /* I guess I could map it in... */ 89839234Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 89939234Sgibbs dptfreeccb(dpt, dccb); 90039234Sgibbs xpt_done(ccb); 90139234Sgibbs return; 90239234Sgibbs } 90339234Sgibbs } else { 90439234Sgibbs bcopy(csio->cdb_io.cdb_bytes, 90539234Sgibbs eccb->cp_cdb, csio->cdb_len); 90639234Sgibbs } 90739234Sgibbs /* 90839234Sgibbs * If we have any data to send with this command, 90939234Sgibbs * map it into bus space. 91039234Sgibbs */ 91139234Sgibbs /* Only use S/G if there is a transfer */ 91239234Sgibbs if ((ccbh->flags & CAM_DIR_MASK) != CAM_DIR_NONE) { 913246713Skib int error; 914246713Skib 915246713Skib error = bus_dmamap_load_ccb(dpt->buffer_dmat, 916246713Skib dccb->dmamap, 917246713Skib ccb, 918246713Skib dptexecuteccb, 919246713Skib dccb, /*flags*/0); 920246713Skib if (error == EINPROGRESS) { 92139234Sgibbs /* 922246713Skib * So as to maintain ordering, 923246713Skib * freeze the controller queue 924246713Skib * until our mapping is 925246713Skib * returned. 92639234Sgibbs */ 927246713Skib xpt_freeze_simq(sim, 1); 928246713Skib dccb->state |= CAM_RELEASE_SIMQ; 92939234Sgibbs } 93039234Sgibbs } else { 93139234Sgibbs /* 93239234Sgibbs * XXX JGibbs. 93339234Sgibbs * Does it want them both on or both off? 93439234Sgibbs * CAM_DIR_NONE is both on, so this code can 93539234Sgibbs * be removed if this is also what the DPT 93639234Sgibbs * exptects. 93739234Sgibbs */ 93839234Sgibbs eccb->DataOut = 0; 93939234Sgibbs eccb->DataIn = 0; 94039234Sgibbs dptexecuteccb(dccb, NULL, 0, 0); 94139234Sgibbs } 94239234Sgibbs break; 94339234Sgibbs } 94439234Sgibbs case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */ 94539234Sgibbs case XPT_ABORT: /* Abort the specified CCB */ 94639234Sgibbs /* XXX Implement */ 94739234Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 94839234Sgibbs xpt_done(ccb); 94939234Sgibbs break; 95039234Sgibbs case XPT_SET_TRAN_SETTINGS: 95139234Sgibbs { 95239234Sgibbs ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 95339234Sgibbs xpt_done(ccb); 95439234Sgibbs break; 95539234Sgibbs } 95639234Sgibbs case XPT_GET_TRAN_SETTINGS: 95739234Sgibbs /* Get default/user set transfer settings for the target */ 95839234Sgibbs { 959163816Smjacob struct ccb_trans_settings *cts = &ccb->cts; 960163816Smjacob struct ccb_trans_settings_scsi *scsi = 961163816Smjacob &cts->proto_specific.scsi; 962163816Smjacob struct ccb_trans_settings_spi *spi = 963163816Smjacob &cts->xport_specific.spi; 964163816Smjacob 965163816Smjacob cts->protocol = PROTO_SCSI; 966163816Smjacob cts->protocol_version = SCSI_REV_2; 967163816Smjacob cts->transport = XPORT_SPI; 968163816Smjacob cts->transport_version = 2; 96939234Sgibbs 970163816Smjacob if (cts->type == CTS_TYPE_USER_SETTINGS) { 971163816Smjacob spi->flags = CTS_SPI_FLAGS_DISC_ENB; 972163816Smjacob spi->bus_width = (dpt->max_id > 7) 973163816Smjacob ? MSG_EXT_WDTR_BUS_8_BIT 974163816Smjacob : MSG_EXT_WDTR_BUS_16_BIT; 975163816Smjacob spi->sync_period = 25; /* 10MHz */ 976163816Smjacob if (spi->sync_period != 0) 977163816Smjacob spi->sync_offset = 15; 978163816Smjacob scsi->flags = CTS_SCSI_FLAGS_TAG_ENB; 979163816Smjacob 980163816Smjacob spi->valid = CTS_SPI_VALID_SYNC_RATE 981163816Smjacob | CTS_SPI_VALID_SYNC_OFFSET 982163816Smjacob | CTS_SPI_VALID_BUS_WIDTH 983163816Smjacob | CTS_SPI_VALID_DISC; 984163816Smjacob scsi->valid = CTS_SCSI_VALID_TQ; 985163816Smjacob ccb->ccb_h.status = CAM_REQ_CMP; 986163816Smjacob } else { 987163816Smjacob ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 988163816Smjacob } 98939234Sgibbs xpt_done(ccb); 99039234Sgibbs break; 99139234Sgibbs } 99239234Sgibbs case XPT_CALC_GEOMETRY: 99339234Sgibbs { 99439234Sgibbs /* 99539234Sgibbs * XXX Use Adaptec translation until I find out how to 99639234Sgibbs * get this information from the card. 99739234Sgibbs */ 998116351Snjl cam_calc_geometry(&ccb->ccg, /*extended*/1); 99939234Sgibbs xpt_done(ccb); 100039234Sgibbs break; 100139234Sgibbs } 100239234Sgibbs case XPT_RESET_BUS: /* Reset the specified SCSI bus */ 100339234Sgibbs { 100439234Sgibbs /* XXX Implement */ 100539234Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 100639234Sgibbs xpt_done(ccb); 100739234Sgibbs break; 100839234Sgibbs } 100939234Sgibbs case XPT_TERM_IO: /* Terminate the I/O process */ 101039234Sgibbs /* XXX Implement */ 101139234Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 101239234Sgibbs xpt_done(ccb); 101339234Sgibbs break; 101439234Sgibbs case XPT_PATH_INQ: /* Path routing inquiry */ 101539234Sgibbs { 101639234Sgibbs struct ccb_pathinq *cpi = &ccb->cpi; 101739234Sgibbs 101839234Sgibbs cpi->version_num = 1; 101939234Sgibbs cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE; 102039234Sgibbs if (dpt->max_id > 7) 102139234Sgibbs cpi->hba_inquiry |= PI_WIDE_16; 102239234Sgibbs cpi->target_sprt = 0; 102339234Sgibbs cpi->hba_misc = 0; 102439234Sgibbs cpi->hba_eng_cnt = 0; 102539234Sgibbs cpi->max_target = dpt->max_id; 102639234Sgibbs cpi->max_lun = dpt->max_lun; 102739234Sgibbs cpi->initiator_id = dpt->hostid[cam_sim_bus(sim)]; 102839234Sgibbs cpi->bus_id = cam_sim_bus(sim); 102946581Sken cpi->base_transfer_speed = 3300; 103039234Sgibbs strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 103139234Sgibbs strncpy(cpi->hba_vid, "DPT", HBA_IDLEN); 103239234Sgibbs strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 103339234Sgibbs cpi->unit_number = cam_sim_unit(sim); 1034163816Smjacob cpi->transport = XPORT_SPI; 1035163816Smjacob cpi->transport_version = 2; 1036163816Smjacob cpi->protocol = PROTO_SCSI; 1037163816Smjacob cpi->protocol_version = SCSI_REV_2; 103839234Sgibbs cpi->ccb_h.status = CAM_REQ_CMP; 103939234Sgibbs xpt_done(ccb); 104039234Sgibbs break; 104139234Sgibbs } 104239234Sgibbs default: 104339234Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 104439234Sgibbs xpt_done(ccb); 104539234Sgibbs break; 104639234Sgibbs } 104732801Sjulian} 104832801Sjulian 104939234Sgibbs/* 105039234Sgibbs * This routine will try to send an EATA command to the DPT HBA. 105139234Sgibbs * It will, by default, try 20,000 times, waiting 50us between tries. 105239234Sgibbs * It returns 0 on success and 1 on failure. 105339234Sgibbs */ 105439234Sgibbsstatic int 105539234Sgibbsdpt_send_eata_command(dpt_softc_t *dpt, eata_ccb_t *cmd_block, 105639234Sgibbs u_int32_t cmd_busaddr, u_int command, u_int retries, 105739234Sgibbs u_int ifc, u_int code, u_int code2) 105832801Sjulian{ 105939234Sgibbs u_int loop; 106039234Sgibbs 106139234Sgibbs if (!retries) 106239234Sgibbs retries = 20000; 106332801Sjulian 106439234Sgibbs /* 106539234Sgibbs * I hate this polling nonsense. Wish there was a way to tell the DPT 106639234Sgibbs * to go get commands at its own pace, or to interrupt when ready. 106739234Sgibbs * In the mean time we will measure how many itterations it really 106839234Sgibbs * takes. 106939234Sgibbs */ 107039234Sgibbs for (loop = 0; loop < retries; loop++) { 107139234Sgibbs if ((dpt_inb(dpt, HA_RAUXSTAT) & HA_ABUSY) == 0) 107239234Sgibbs break; 107332801Sjulian else 107432801Sjulian DELAY(50); 107532801Sjulian } 107639234Sgibbs 107739234Sgibbs if (loop < retries) { 107839234Sgibbs#ifdef DPT_MEASURE_PERFORMANCE 107939234Sgibbs if (loop > dpt->performance.max_eata_tries) 108039234Sgibbs dpt->performance.max_eata_tries = loop; 108139234Sgibbs 108239234Sgibbs if (loop < dpt->performance.min_eata_tries) 108339234Sgibbs dpt->performance.min_eata_tries = loop; 108439234Sgibbs#endif 108539234Sgibbs } else { 108639234Sgibbs#ifdef DPT_MEASURE_PERFORMANCE 108739234Sgibbs ++dpt->performance.command_too_busy; 108839234Sgibbs#endif 108939234Sgibbs return (1); 109039234Sgibbs } 109139234Sgibbs 109239234Sgibbs /* The controller is alive, advance the wedge timer */ 109339234Sgibbs#ifdef DPT_RESET_HBA 109439234Sgibbs dpt->last_contact = microtime_now; 109539234Sgibbs#endif 109639234Sgibbs 109739234Sgibbs if (cmd_block == NULL) 109839234Sgibbs cmd_busaddr = 0; 109939234Sgibbs#if (BYTE_ORDER == BIG_ENDIAN) 110039234Sgibbs else { 110139234Sgibbs cmd_busaddr = ((cmd_busaddr >> 24) & 0xFF) 110239234Sgibbs | ((cmd_busaddr >> 16) & 0xFF) 110339234Sgibbs | ((cmd_busaddr >> 8) & 0xFF) 110439234Sgibbs | (cmd_busaddr & 0xFF); 110539234Sgibbs } 110639234Sgibbs#endif 110739234Sgibbs /* And now the address */ 110839234Sgibbs dpt_outl(dpt, HA_WDMAADDR, cmd_busaddr); 110939234Sgibbs 111039234Sgibbs if (command == EATA_CMD_IMMEDIATE) { 111139234Sgibbs if (cmd_block == NULL) { 111239234Sgibbs dpt_outb(dpt, HA_WCODE2, code2); 111339234Sgibbs dpt_outb(dpt, HA_WCODE, code); 111439234Sgibbs } 111539234Sgibbs dpt_outb(dpt, HA_WIFC, ifc); 111639234Sgibbs } 111739234Sgibbs dpt_outb(dpt, HA_WCOMMAND, command); 111839234Sgibbs 111939234Sgibbs return (0); 112032801Sjulian} 112132801Sjulian 112239234Sgibbs 112339234Sgibbs/* ==================== Exported Function definitions =======================*/ 1124112780Smdoddvoid 1125112780Smdodddpt_alloc(device_t dev) 112632801Sjulian{ 112759078Smdodd dpt_softc_t *dpt = device_get_softc(dev); 112839234Sgibbs int i; 112939234Sgibbs 1130241593Sjhb mtx_init(&dpt->lock, "dpt", NULL, MTX_DEF); 113139234Sgibbs SLIST_INIT(&dpt->free_dccb_list); 113239234Sgibbs LIST_INIT(&dpt->pending_ccb_list); 113339234Sgibbs for (i = 0; i < MAX_CHANNELS; i++) 113439234Sgibbs dpt->resetlevel[i] = DPT_HA_OK; 113539234Sgibbs 113639234Sgibbs#ifdef DPT_MEASURE_PERFORMANCE 113739234Sgibbs dpt_reset_performance(dpt); 113839234Sgibbs#endif /* DPT_MEASURE_PERFORMANCE */ 1139112780Smdodd return; 114039234Sgibbs} 114139234Sgibbs 114239234Sgibbsvoid 114339234Sgibbsdpt_free(struct dpt_softc *dpt) 114439234Sgibbs{ 114539234Sgibbs switch (dpt->init_level) { 114639234Sgibbs default: 114739234Sgibbs case 5: 114839234Sgibbs bus_dmamap_unload(dpt->dccb_dmat, dpt->dccb_dmamap); 114939234Sgibbs case 4: 115039234Sgibbs bus_dmamem_free(dpt->dccb_dmat, dpt->dpt_dccbs, 115139234Sgibbs dpt->dccb_dmamap); 115239234Sgibbs bus_dmamap_destroy(dpt->dccb_dmat, dpt->dccb_dmamap); 115339234Sgibbs case 3: 115439234Sgibbs bus_dma_tag_destroy(dpt->dccb_dmat); 115539234Sgibbs case 2: 115639234Sgibbs bus_dma_tag_destroy(dpt->buffer_dmat); 115739234Sgibbs case 1: 115839234Sgibbs { 115939234Sgibbs struct sg_map_node *sg_map; 116039234Sgibbs 116139234Sgibbs while ((sg_map = SLIST_FIRST(&dpt->sg_maps)) != NULL) { 116239234Sgibbs SLIST_REMOVE_HEAD(&dpt->sg_maps, links); 116339234Sgibbs bus_dmamap_unload(dpt->sg_dmat, 116439234Sgibbs sg_map->sg_dmamap); 116539234Sgibbs bus_dmamem_free(dpt->sg_dmat, sg_map->sg_vaddr, 116639234Sgibbs sg_map->sg_dmamap); 116739234Sgibbs free(sg_map, M_DEVBUF); 116839234Sgibbs } 116939234Sgibbs bus_dma_tag_destroy(dpt->sg_dmat); 117039234Sgibbs } 117139234Sgibbs case 0: 117239234Sgibbs break; 117339234Sgibbs } 1174241593Sjhb mtx_destroy(&dpt->lock); 117539234Sgibbs} 117639234Sgibbs 1177112780Smdoddint 1178112780Smdodddpt_alloc_resources (device_t dev) 1179112780Smdodd{ 1180112780Smdodd dpt_softc_t * dpt; 1181112780Smdodd int error; 1182112780Smdodd 1183112780Smdodd dpt = device_get_softc(dev); 1184112780Smdodd 1185127135Snjl dpt->io_res = bus_alloc_resource_any(dev, dpt->io_type, &dpt->io_rid, 1186127135Snjl RF_ACTIVE); 1187112780Smdodd if (dpt->io_res == NULL) { 1188112780Smdodd device_printf(dev, "No I/O space?!\n"); 1189112780Smdodd error = ENOMEM; 1190112780Smdodd goto bad; 1191112780Smdodd } 1192112780Smdodd 1193127135Snjl dpt->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &dpt->irq_rid, 1194127135Snjl RF_ACTIVE); 1195112780Smdodd if (dpt->irq_res == NULL) { 1196112780Smdodd device_printf(dev, "No IRQ!\n"); 1197112780Smdodd error = ENOMEM; 1198112780Smdodd goto bad; 1199112780Smdodd } 1200112780Smdodd 1201112780Smdodd return (0); 1202112780Smdoddbad: 1203112780Smdodd return(error); 1204112780Smdodd} 1205112780Smdodd 1206112780Smdodd 1207112780Smdoddvoid 1208112780Smdodddpt_release_resources (device_t dev) 1209112780Smdodd{ 1210112780Smdodd struct dpt_softc * dpt; 1211112780Smdodd 1212112780Smdodd dpt = device_get_softc(dev); 1213112780Smdodd 1214112780Smdodd if (dpt->ih) 1215112780Smdodd bus_teardown_intr(dev, dpt->irq_res, dpt->ih); 1216112780Smdodd if (dpt->io_res) 1217112780Smdodd bus_release_resource(dev, dpt->io_type, dpt->io_rid, dpt->io_res); 1218112780Smdodd if (dpt->irq_res) 1219112780Smdodd bus_release_resource(dev, SYS_RES_IRQ, dpt->irq_rid, dpt->irq_res); 1220112780Smdodd if (dpt->drq_res) 1221112780Smdodd bus_release_resource(dev, SYS_RES_DRQ, dpt->drq_rid, dpt->drq_res); 1222112780Smdodd 1223112780Smdodd return; 1224112780Smdodd} 1225112780Smdodd 122641996Seivindstatic u_int8_t string_sizes[] = 122739234Sgibbs{ 122839234Sgibbs sizeof(((dpt_inq_t*)NULL)->vendor), 122939234Sgibbs sizeof(((dpt_inq_t*)NULL)->modelNum), 123039234Sgibbs sizeof(((dpt_inq_t*)NULL)->firmware), 123139234Sgibbs sizeof(((dpt_inq_t*)NULL)->protocol), 123239234Sgibbs}; 123339234Sgibbs 123439234Sgibbsint 123539234Sgibbsdpt_init(struct dpt_softc *dpt) 123639234Sgibbs{ 123739234Sgibbs dpt_conf_t conf; 123839234Sgibbs struct sg_map_node *sg_map; 123939234Sgibbs dpt_ccb_t *dccb; 124039234Sgibbs u_int8_t *strp; 124139234Sgibbs int index; 124239234Sgibbs int i; 124339234Sgibbs int retval; 124439234Sgibbs 124541996Seivind dpt->init_level = 0; 124641996Seivind SLIST_INIT(&dpt->sg_maps); 1247241593Sjhb mtx_lock(&dpt->lock); 124841996Seivind 124939234Sgibbs#ifdef DPT_RESET_BOARD 1250241593Sjhb device_printf(dpt->dev, "resetting HBA\n"); 125139234Sgibbs dpt_outb(dpt, HA_WCOMMAND, EATA_CMD_RESET); 125239234Sgibbs DELAY(750000); 125339234Sgibbs /* XXX Shouldn't we poll a status register or something??? */ 125439234Sgibbs#endif 125539234Sgibbs /* DMA tag for our S/G structures. We allocate in page sized chunks */ 1256112782Smdodd if (bus_dma_tag_create( /* parent */ dpt->parent_dmat, 1257112782Smdodd /* alignment */ 1, 1258112782Smdodd /* boundary */ 0, 1259112782Smdodd /* lowaddr */ BUS_SPACE_MAXADDR, 1260112782Smdodd /* highaddr */ BUS_SPACE_MAXADDR, 1261112782Smdodd /* filter */ NULL, 1262112782Smdodd /* filterarg */ NULL, 1263112782Smdodd /* maxsize */ PAGE_SIZE, 1264112782Smdodd /* nsegments */ 1, 1265112782Smdodd /* maxsegsz */ BUS_SPACE_MAXSIZE_32BIT, 1266112782Smdodd /* flags */ 0, 1267241593Sjhb /* lockfunc */ NULL, 1268241593Sjhb /* lockarg */ NULL, 1269112782Smdodd &dpt->sg_dmat) != 0) { 127039234Sgibbs goto error_exit; 127139234Sgibbs } 127239234Sgibbs 127339234Sgibbs dpt->init_level++; 127439234Sgibbs 127539234Sgibbs /* 127639234Sgibbs * We allocate our DPT ccbs as a contiguous array of bus dma'able 127739234Sgibbs * memory. To get the allocation size, we need to know how many 127839234Sgibbs * ccbs the card supports. This requires a ccb. We solve this 127939234Sgibbs * chicken and egg problem by allocating some re-usable S/G space 128039234Sgibbs * up front, and treating it as our status packet, CCB, and target 128139234Sgibbs * memory space for these commands. 128239234Sgibbs */ 128339234Sgibbs sg_map = dptallocsgmap(dpt); 128439234Sgibbs if (sg_map == NULL) 128539234Sgibbs goto error_exit; 128639234Sgibbs 128739234Sgibbs dpt->sp = (volatile dpt_sp_t *)sg_map->sg_vaddr; 128864355Speter dccb = (struct dpt_ccb *)(uintptr_t)(volatile void *)&dpt->sp[1]; 128939234Sgibbs bzero(dccb, sizeof(*dccb)); 129039234Sgibbs dpt->sp_physaddr = sg_map->sg_physaddr; 129139234Sgibbs dccb->eata_ccb.cp_dataDMA = 129239234Sgibbs htonl(sg_map->sg_physaddr + sizeof(dpt_sp_t) + sizeof(*dccb)); 129339234Sgibbs dccb->eata_ccb.cp_busaddr = ~0; 129439234Sgibbs dccb->eata_ccb.cp_statDMA = htonl(dpt->sp_physaddr); 129539234Sgibbs dccb->eata_ccb.cp_reqDMA = htonl(dpt->sp_physaddr + sizeof(*dccb) 129639234Sgibbs + offsetof(struct dpt_ccb, sense_data)); 129739234Sgibbs 129839234Sgibbs /* Okay. Fetch our config */ 129939234Sgibbs bzero(&dccb[1], sizeof(conf)); /* data area */ 130039234Sgibbs retval = dpt_get_conf(dpt, dccb, sg_map->sg_physaddr + sizeof(dpt_sp_t), 130139234Sgibbs sizeof(conf), 0xc1, 7, 1); 130239234Sgibbs 130339234Sgibbs if (retval != 0) { 1304241593Sjhb device_printf(dpt->dev, "Failed to get board configuration\n"); 1305241593Sjhb goto error_exit; 130639234Sgibbs } 130739234Sgibbs bcopy(&dccb[1], &conf, sizeof(conf)); 130839234Sgibbs 130939234Sgibbs bzero(&dccb[1], sizeof(dpt->board_data)); 131039234Sgibbs retval = dpt_get_conf(dpt, dccb, sg_map->sg_physaddr + sizeof(dpt_sp_t), 131139234Sgibbs sizeof(dpt->board_data), 0, conf.scsi_id0, 0); 131239234Sgibbs if (retval != 0) { 1313241593Sjhb device_printf(dpt->dev, "Failed to get inquiry information\n"); 1314241593Sjhb goto error_exit; 131539234Sgibbs } 131639234Sgibbs bcopy(&dccb[1], &dpt->board_data, sizeof(dpt->board_data)); 131739234Sgibbs 131839234Sgibbs dpt_detect_cache(dpt, dccb, sg_map->sg_physaddr + sizeof(dpt_sp_t), 131939234Sgibbs (u_int8_t *)&dccb[1]); 132039234Sgibbs 132139234Sgibbs switch (ntohl(conf.splen)) { 132239234Sgibbs case DPT_EATA_REVA: 132339234Sgibbs dpt->EATA_revision = 'a'; 132439234Sgibbs break; 132539234Sgibbs case DPT_EATA_REVB: 132639234Sgibbs dpt->EATA_revision = 'b'; 132739234Sgibbs break; 132839234Sgibbs case DPT_EATA_REVC: 132939234Sgibbs dpt->EATA_revision = 'c'; 133039234Sgibbs break; 133139234Sgibbs case DPT_EATA_REVZ: 133239234Sgibbs dpt->EATA_revision = 'z'; 133339234Sgibbs break; 133439234Sgibbs default: 133539234Sgibbs dpt->EATA_revision = '?'; 133639234Sgibbs } 133739234Sgibbs 133839234Sgibbs dpt->max_id = conf.MAX_ID; 133939234Sgibbs dpt->max_lun = conf.MAX_LUN; 134039234Sgibbs dpt->irq = conf.IRQ; 134139234Sgibbs dpt->dma_channel = (8 - conf.DMA_channel) & 7; 134239234Sgibbs dpt->channels = conf.MAX_CHAN + 1; 134339234Sgibbs dpt->state |= DPT_HA_OK; 134439234Sgibbs if (conf.SECOND) 134539234Sgibbs dpt->primary = FALSE; 134632801Sjulian else 134739234Sgibbs dpt->primary = TRUE; 134839234Sgibbs 134939234Sgibbs dpt->more_support = conf.MORE_support; 135039234Sgibbs 135139234Sgibbs if (strncmp(dpt->board_data.firmware, "07G0", 4) >= 0) 135239234Sgibbs dpt->immediate_support = 1; 135339234Sgibbs else 135439234Sgibbs dpt->immediate_support = 0; 135539234Sgibbs 135639234Sgibbs dpt->broken_INQUIRY = FALSE; 135739234Sgibbs 135839234Sgibbs dpt->cplen = ntohl(conf.cplen); 135939234Sgibbs dpt->cppadlen = ntohs(conf.cppadlen); 136039234Sgibbs dpt->max_dccbs = ntohs(conf.queuesiz); 136139234Sgibbs 136239515Sgibbs if (dpt->max_dccbs > 256) { 1363241593Sjhb device_printf(dpt->dev, "Max CCBs reduced from %d to " 1364241593Sjhb "256 due to tag algorithm\n", dpt->max_dccbs); 136539515Sgibbs dpt->max_dccbs = 256; 136639515Sgibbs } 136739515Sgibbs 136839234Sgibbs dpt->hostid[0] = conf.scsi_id0; 136939234Sgibbs dpt->hostid[1] = conf.scsi_id1; 137039234Sgibbs dpt->hostid[2] = conf.scsi_id2; 137139234Sgibbs 137239553Sgibbs if (conf.SG_64K) 137339553Sgibbs dpt->sgsize = 8192; 137439553Sgibbs else 137539234Sgibbs dpt->sgsize = ntohs(conf.SGsiz); 137639234Sgibbs 137739553Sgibbs /* We can only get 64k buffers, so don't bother to waste space. */ 137839553Sgibbs if (dpt->sgsize < 17 || dpt->sgsize > 32) 137939553Sgibbs dpt->sgsize = 32; 138039553Sgibbs 138139234Sgibbs if (dpt->sgsize > dpt_max_segs) 138239234Sgibbs dpt->sgsize = dpt_max_segs; 138339234Sgibbs 138439234Sgibbs /* DMA tag for mapping buffers into device visible space. */ 1385112782Smdodd if (bus_dma_tag_create( /* parent */ dpt->parent_dmat, 1386112782Smdodd /* alignment */ 1, 1387112782Smdodd /* boundary */ 0, 1388112782Smdodd /* lowaddr */ BUS_SPACE_MAXADDR, 1389112782Smdodd /* highaddr */ BUS_SPACE_MAXADDR, 1390112782Smdodd /* filter */ NULL, 1391112782Smdodd /* filterarg */ NULL, 1392281826Smav /* maxsize */ DFLTPHYS, 1393112782Smdodd /* nsegments */ dpt->sgsize, 1394112782Smdodd /* maxsegsz */ BUS_SPACE_MAXSIZE_32BIT, 1395112782Smdodd /* flags */ BUS_DMA_ALLOCNOW, 1396117126Sscottl /* lockfunc */ busdma_lock_mutex, 1397241593Sjhb /* lockarg */ &dpt->lock, 1398112782Smdodd &dpt->buffer_dmat) != 0) { 1399241593Sjhb device_printf(dpt->dev, 1400241593Sjhb "bus_dma_tag_create(...,dpt->buffer_dmat) failed\n"); 140139234Sgibbs goto error_exit; 140239234Sgibbs } 140339234Sgibbs 140439234Sgibbs dpt->init_level++; 140539234Sgibbs 140639234Sgibbs /* DMA tag for our ccb structures and interrupt status packet */ 1407112782Smdodd if (bus_dma_tag_create( /* parent */ dpt->parent_dmat, 1408112782Smdodd /* alignment */ 1, 1409112782Smdodd /* boundary */ 0, 1410112782Smdodd /* lowaddr */ BUS_SPACE_MAXADDR, 1411112782Smdodd /* highaddr */ BUS_SPACE_MAXADDR, 1412112782Smdodd /* filter */ NULL, 1413112782Smdodd /* filterarg */ NULL, 1414112782Smdodd /* maxsize */ (dpt->max_dccbs * 1415112782Smdodd sizeof(struct dpt_ccb)) + 1416112782Smdodd sizeof(dpt_sp_t), 1417112782Smdodd /* nsegments */ 1, 1418112782Smdodd /* maxsegsz */ BUS_SPACE_MAXSIZE_32BIT, 1419112782Smdodd /* flags */ 0, 1420241593Sjhb /* lockfunc */ NULL, 1421241593Sjhb /* lockarg */ NULL, 1422112782Smdodd &dpt->dccb_dmat) != 0) { 1423241593Sjhb device_printf(dpt->dev, 1424241593Sjhb "bus_dma_tag_create(...,dpt->dccb_dmat) failed\n"); 142539234Sgibbs goto error_exit; 142639234Sgibbs } 142739234Sgibbs 142839234Sgibbs dpt->init_level++; 142939234Sgibbs 143039234Sgibbs /* Allocation for our ccbs and interrupt status packet */ 143139234Sgibbs if (bus_dmamem_alloc(dpt->dccb_dmat, (void **)&dpt->dpt_dccbs, 143239234Sgibbs BUS_DMA_NOWAIT, &dpt->dccb_dmamap) != 0) { 1433241593Sjhb device_printf(dpt->dev, 1434241593Sjhb "bus_dmamem_alloc(dpt->dccb_dmat,...) failed\n"); 143539234Sgibbs goto error_exit; 143639234Sgibbs } 143739234Sgibbs 143839234Sgibbs dpt->init_level++; 143939234Sgibbs 144039234Sgibbs /* And permanently map them */ 144139234Sgibbs bus_dmamap_load(dpt->dccb_dmat, dpt->dccb_dmamap, 144239234Sgibbs dpt->dpt_dccbs, 144339234Sgibbs (dpt->max_dccbs * sizeof(struct dpt_ccb)) 144439234Sgibbs + sizeof(dpt_sp_t), 144539234Sgibbs dptmapmem, &dpt->dpt_ccb_busbase, /*flags*/0); 144639234Sgibbs 144739553Sgibbs /* Clear them out. */ 144839553Sgibbs bzero(dpt->dpt_dccbs, 144939553Sgibbs (dpt->max_dccbs * sizeof(struct dpt_ccb)) + sizeof(dpt_sp_t)); 145039553Sgibbs 145139234Sgibbs dpt->dpt_ccb_busend = dpt->dpt_ccb_busbase; 145239234Sgibbs 145339234Sgibbs dpt->sp = (dpt_sp_t*)&dpt->dpt_dccbs[dpt->max_dccbs]; 145439234Sgibbs dpt->sp_physaddr = dpt->dpt_ccb_busbase 145539234Sgibbs + (dpt->max_dccbs * sizeof(dpt_ccb_t)); 145639234Sgibbs dpt->init_level++; 145739234Sgibbs 145839234Sgibbs /* Allocate our first batch of ccbs */ 145959078Smdodd if (dptallocccbs(dpt) == 0) { 1460241593Sjhb device_printf(dpt->dev, "dptallocccbs(dpt) == 0\n"); 1461241593Sjhb mtx_unlock(&dpt->lock); 146239234Sgibbs return (2); 146359078Smdodd } 146439234Sgibbs 146539234Sgibbs /* Prepare for Target Mode */ 146639234Sgibbs dpt->target_mode_enabled = 1; 146739234Sgibbs 146839234Sgibbs /* Nuke excess spaces from inquiry information */ 146939234Sgibbs strp = dpt->board_data.vendor; 147039234Sgibbs for (i = 0; i < sizeof(string_sizes); i++) { 147139234Sgibbs index = string_sizes[i] - 1; 147239234Sgibbs while (index && (strp[index] == ' ')) 147339234Sgibbs strp[index--] = '\0'; 147439234Sgibbs strp += string_sizes[i]; 147539234Sgibbs } 147639234Sgibbs 1477241593Sjhb device_printf(dpt->dev, "%.8s %.16s FW Rev. %.4s, ", 1478241593Sjhb dpt->board_data.vendor, 147939234Sgibbs dpt->board_data.modelNum, dpt->board_data.firmware); 148039234Sgibbs 148139234Sgibbs printf("%d channel%s, ", dpt->channels, dpt->channels > 1 ? "s" : ""); 148239234Sgibbs 148339234Sgibbs if (dpt->cache_type != DPT_NO_CACHE 148439234Sgibbs && dpt->cache_size != 0) { 148539234Sgibbs printf("%s Cache, ", 148639234Sgibbs dpt->cache_type == DPT_CACHE_WRITETHROUGH 148739234Sgibbs ? "Write-Through" : "Write-Back"); 148839234Sgibbs } 148939234Sgibbs 149039234Sgibbs printf("%d CCBs\n", dpt->max_dccbs); 1491241593Sjhb mtx_unlock(&dpt->lock); 149239234Sgibbs return (0); 149339234Sgibbs 149439234Sgibbserror_exit: 1495241593Sjhb mtx_unlock(&dpt->lock); 149639234Sgibbs return (1); 149732801Sjulian} 149832801Sjulian 149939234Sgibbsint 150039234Sgibbsdpt_attach(dpt_softc_t *dpt) 150132801Sjulian{ 150239234Sgibbs struct cam_devq *devq; 150339234Sgibbs int i; 150439234Sgibbs 150539234Sgibbs /* 150639234Sgibbs * Create the device queue for our SIM. 150739234Sgibbs */ 150839234Sgibbs devq = cam_simq_alloc(dpt->max_dccbs); 150939234Sgibbs if (devq == NULL) 151032801Sjulian return (0); 151139234Sgibbs 1512241593Sjhb mtx_lock(&dpt->lock); 151339234Sgibbs for (i = 0; i < dpt->channels; i++) { 151439234Sgibbs /* 151539234Sgibbs * Construct our SIM entry 151639234Sgibbs */ 151739234Sgibbs dpt->sims[i] = cam_sim_alloc(dpt_action, dpt_poll, "dpt", 1518241593Sjhb dpt, device_get_unit(dpt->dev), &dpt->lock, 1519168752Sscottl /*untagged*/2, 152039234Sgibbs /*tagged*/dpt->max_dccbs, devq); 1521124612Smdodd if (dpt->sims[i] == NULL) { 1522124612Smdodd if (i == 0) 1523124612Smdodd cam_simq_free(devq); 1524124612Smdodd else 1525124612Smdodd printf( "%s(): Unable to attach bus %d " 1526124612Smdodd "due to resource shortage\n", 1527124612Smdodd __func__, i); 1528124612Smdodd break; 1529124612Smdodd } 1530124612Smdodd 1531170872Sscottl if (xpt_bus_register(dpt->sims[i], dpt->dev, i) != CAM_SUCCESS){ 153239234Sgibbs cam_sim_free(dpt->sims[i], /*free_devq*/i == 0); 1533124612Smdodd dpt->sims[i] = NULL; 153439234Sgibbs break; 153539234Sgibbs } 153639234Sgibbs 153739234Sgibbs if (xpt_create_path(&dpt->paths[i], /*periph*/NULL, 153839234Sgibbs cam_sim_path(dpt->sims[i]), 153939234Sgibbs CAM_TARGET_WILDCARD, 154039234Sgibbs CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 154139234Sgibbs xpt_bus_deregister(cam_sim_path(dpt->sims[i])); 154239234Sgibbs cam_sim_free(dpt->sims[i], /*free_devq*/i == 0); 1543124612Smdodd dpt->sims[i] = NULL; 154439234Sgibbs break; 154539234Sgibbs } 154639234Sgibbs 154739234Sgibbs } 1548241593Sjhb mtx_unlock(&dpt->lock); 154939234Sgibbs if (i > 0) 155050107Smsmith EVENTHANDLER_REGISTER(shutdown_final, dptshutdown, 155150107Smsmith dpt, SHUTDOWN_PRI_DEFAULT); 155239234Sgibbs return (i); 155332801Sjulian} 155432801Sjulian 1555112780Smdoddint 1556112780Smdodddpt_detach (device_t dev) 1557112780Smdodd{ 1558112780Smdodd struct dpt_softc * dpt; 1559112780Smdodd int i; 156039234Sgibbs 1561112780Smdodd dpt = device_get_softc(dev); 1562112780Smdodd 1563241593Sjhb mtx_lock(&dpt->lock); 1564112780Smdodd for (i = 0; i < dpt->channels; i++) { 1565112780Smdodd#if 0 1566112780Smdodd xpt_async(AC_LOST_DEVICE, dpt->paths[i], NULL); 1567112780Smdodd#endif 1568112780Smdodd xpt_free_path(dpt->paths[i]); 1569112780Smdodd xpt_bus_deregister(cam_sim_path(dpt->sims[i])); 1570112780Smdodd cam_sim_free(dpt->sims[i], /*free_devq*/TRUE); 1571112780Smdodd } 1572241593Sjhb mtx_unlock(&dpt->lock); 1573112780Smdodd 1574112780Smdodd dptshutdown((void *)dpt, SHUTDOWN_PRI_DEFAULT); 1575112780Smdodd 1576112780Smdodd dpt_release_resources(dev); 1577112780Smdodd 1578112780Smdodd dpt_free(dpt); 1579112780Smdodd 1580112780Smdodd return (0); 1581112780Smdodd} 1582112780Smdodd 158339234Sgibbs/* 158439234Sgibbs * This is the interrupt handler for the DPT driver. 158539234Sgibbs */ 158639234Sgibbsvoid 158739234Sgibbsdpt_intr(void *arg) 158839234Sgibbs{ 158939234Sgibbs dpt_softc_t *dpt; 1590241593Sjhb 1591241593Sjhb dpt = arg; 1592241593Sjhb mtx_lock(&dpt->lock); 1593241593Sjhb dpt_intr_locked(dpt); 1594241593Sjhb mtx_unlock(&dpt->lock); 1595241593Sjhb} 1596241593Sjhb 1597241593Sjhbvoid 1598241593Sjhbdpt_intr_locked(dpt_softc_t *dpt) 1599241593Sjhb{ 160039234Sgibbs dpt_ccb_t *dccb; 160139234Sgibbs union ccb *ccb; 160239234Sgibbs u_int status; 160339234Sgibbs u_int aux_status; 160439234Sgibbs u_int hba_stat; 160539234Sgibbs u_int scsi_stat; 160639234Sgibbs u_int32_t residue_len; /* Number of bytes not transferred */ 160739234Sgibbs 160839234Sgibbs /* First order of business is to check if this interrupt is for us */ 160939234Sgibbs while (((aux_status = dpt_inb(dpt, HA_RAUXSTAT)) & HA_AIRQ) != 0) { 161039234Sgibbs 161139234Sgibbs /* 161239234Sgibbs * What we want to do now, is to capture the status, all of it, 161339234Sgibbs * move it where it belongs, wake up whoever sleeps waiting to 161439234Sgibbs * process this result, and get out of here. 161539234Sgibbs */ 161639234Sgibbs if (dpt->sp->ccb_busaddr < dpt->dpt_ccb_busbase 161739234Sgibbs || dpt->sp->ccb_busaddr >= dpt->dpt_ccb_busend) { 1618241593Sjhb device_printf(dpt->dev, 1619241593Sjhb "Encountered bogus status packet\n"); 162039234Sgibbs status = dpt_inb(dpt, HA_RSTATUS); 162139234Sgibbs return; 162239234Sgibbs } 162339234Sgibbs 162439234Sgibbs dccb = dptccbptov(dpt, dpt->sp->ccb_busaddr); 162539234Sgibbs 162639234Sgibbs dpt->sp->ccb_busaddr = ~0; 162739234Sgibbs 162839234Sgibbs /* Ignore status packets with EOC not set */ 162939234Sgibbs if (dpt->sp->EOC == 0) { 1630241593Sjhb device_printf(dpt->dev, 1631241593Sjhb "ERROR: Request %d received with " 163239234Sgibbs "clear EOC.\n Marking as LOST.\n", 1633241593Sjhb dccb->transaction_id); 163439234Sgibbs 163539234Sgibbs /* This CLEARS the interrupt! */ 163639234Sgibbs status = dpt_inb(dpt, HA_RSTATUS); 163739234Sgibbs continue; 163839234Sgibbs } 163939234Sgibbs dpt->sp->EOC = 0; 164039234Sgibbs 164139234Sgibbs /* 164239234Sgibbs * Double buffer the status information so the hardware can 164339234Sgibbs * work on updating the status packet while we decifer the 164439234Sgibbs * one we were just interrupted for. 164539234Sgibbs * According to Mark Salyzyn, we only need few pieces of it. 164639234Sgibbs */ 164739234Sgibbs hba_stat = dpt->sp->hba_stat; 164839234Sgibbs scsi_stat = dpt->sp->scsi_stat; 164939234Sgibbs residue_len = dpt->sp->residue_len; 165039234Sgibbs 165139234Sgibbs /* Clear interrupts, check for error */ 165239234Sgibbs if ((status = dpt_inb(dpt, HA_RSTATUS)) & HA_SERROR) { 165339234Sgibbs /* 165439234Sgibbs * Error Condition. Check for magic cookie. Exit 165539234Sgibbs * this test on earliest sign of non-reset condition 165639234Sgibbs */ 165739234Sgibbs 165839234Sgibbs /* Check that this is not a board reset interrupt */ 165939234Sgibbs if (dpt_just_reset(dpt)) { 1660241593Sjhb device_printf(dpt->dev, "HBA rebooted.\n" 166139234Sgibbs " All transactions should be " 1662241593Sjhb "resubmitted\n"); 166339234Sgibbs 1664241593Sjhb device_printf(dpt->dev, 1665241593Sjhb ">>---->> This is incomplete, " 1666241593Sjhb "fix me.... <<----<<"); 166739234Sgibbs panic("DPT Rebooted"); 166839234Sgibbs 166939234Sgibbs } 167039234Sgibbs } 167139234Sgibbs /* Process CCB */ 167239234Sgibbs ccb = dccb->ccb; 1673241593Sjhb callout_stop(&dccb->timer); 167439234Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) { 1675115343Sscottl bus_dmasync_op_t op; 167639234Sgibbs 167739234Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) 167839234Sgibbs op = BUS_DMASYNC_POSTREAD; 167939234Sgibbs else 168039234Sgibbs op = BUS_DMASYNC_POSTWRITE; 168139234Sgibbs bus_dmamap_sync(dpt->buffer_dmat, dccb->dmamap, op); 168239234Sgibbs bus_dmamap_unload(dpt->buffer_dmat, dccb->dmamap); 168339234Sgibbs } 168439234Sgibbs 168539234Sgibbs /* Common Case inline... */ 168639234Sgibbs if (hba_stat == HA_NO_ERROR) { 168739234Sgibbs ccb->csio.scsi_status = scsi_stat; 168839234Sgibbs ccb->ccb_h.status = 0; 168939234Sgibbs switch (scsi_stat) { 169039234Sgibbs case SCSI_STATUS_OK: 169139234Sgibbs ccb->ccb_h.status |= CAM_REQ_CMP; 169239234Sgibbs break; 169339234Sgibbs case SCSI_STATUS_CHECK_COND: 169439234Sgibbs case SCSI_STATUS_CMD_TERMINATED: 169539234Sgibbs bcopy(&dccb->sense_data, &ccb->csio.sense_data, 169639234Sgibbs ccb->csio.sense_len); 169739234Sgibbs ccb->ccb_h.status |= CAM_AUTOSNS_VALID; 169839234Sgibbs /* FALLTHROUGH */ 169939234Sgibbs default: 170039234Sgibbs ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR; 170139234Sgibbs /* XXX Freeze DevQ */ 170239234Sgibbs break; 170339234Sgibbs } 170439234Sgibbs ccb->csio.resid = residue_len; 170539234Sgibbs dptfreeccb(dpt, dccb); 170639234Sgibbs xpt_done(ccb); 170739234Sgibbs } else { 170839234Sgibbs dptprocesserror(dpt, dccb, ccb, hba_stat, scsi_stat, 170939234Sgibbs residue_len); 171039234Sgibbs } 171139234Sgibbs } 171239234Sgibbs} 171339234Sgibbs 171439234Sgibbsstatic void 171539234Sgibbsdptprocesserror(dpt_softc_t *dpt, dpt_ccb_t *dccb, union ccb *ccb, 171639234Sgibbs u_int hba_stat, u_int scsi_stat, u_int32_t resid) 171739234Sgibbs{ 171839234Sgibbs ccb->csio.resid = resid; 171939234Sgibbs switch (hba_stat) { 172039234Sgibbs case HA_ERR_SEL_TO: 172139234Sgibbs ccb->ccb_h.status = CAM_SEL_TIMEOUT; 172239234Sgibbs break; 172339234Sgibbs case HA_ERR_CMD_TO: 172439234Sgibbs ccb->ccb_h.status = CAM_CMD_TIMEOUT; 172539234Sgibbs break; 172639234Sgibbs case HA_SCSIBUS_RESET: 172739234Sgibbs case HA_HBA_POWER_UP: /* Similar effect to a bus reset??? */ 172839234Sgibbs ccb->ccb_h.status = CAM_SCSI_BUS_RESET; 172939234Sgibbs break; 173039234Sgibbs case HA_CP_ABORTED: 173139234Sgibbs case HA_CP_RESET: /* XXX ??? */ 173239234Sgibbs case HA_CP_ABORT_NA: /* XXX ??? */ 173339234Sgibbs case HA_CP_RESET_NA: /* XXX ??? */ 173439515Sgibbs if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG) 173539515Sgibbs ccb->ccb_h.status = CAM_REQ_ABORTED; 173639234Sgibbs break; 173739234Sgibbs case HA_PCI_PARITY: 173839234Sgibbs case HA_PCI_MABORT: 173939234Sgibbs case HA_PCI_TABORT: 174039234Sgibbs case HA_PCI_STABORT: 174139234Sgibbs case HA_BUS_PARITY: 174239234Sgibbs case HA_PARITY_ERR: 174339234Sgibbs case HA_ECC_ERR: 174439234Sgibbs ccb->ccb_h.status = CAM_UNCOR_PARITY; 174539234Sgibbs break; 174639234Sgibbs case HA_UNX_MSGRJCT: 174739234Sgibbs ccb->ccb_h.status = CAM_MSG_REJECT_REC; 174839234Sgibbs break; 174939234Sgibbs case HA_UNX_BUSPHASE: 175039234Sgibbs ccb->ccb_h.status = CAM_SEQUENCE_FAIL; 175139234Sgibbs break; 175239234Sgibbs case HA_UNX_BUS_FREE: 175339234Sgibbs ccb->ccb_h.status = CAM_UNEXP_BUSFREE; 175439234Sgibbs break; 175539234Sgibbs case HA_SCSI_HUNG: 175639234Sgibbs case HA_RESET_STUCK: 175739234Sgibbs /* 175839234Sgibbs * Dead??? Can the controller get unstuck 175939234Sgibbs * from these conditions 176039234Sgibbs */ 176139234Sgibbs ccb->ccb_h.status = CAM_NO_HBA; 176239234Sgibbs break; 176339234Sgibbs case HA_RSENSE_FAIL: 176439234Sgibbs ccb->ccb_h.status = CAM_AUTOSENSE_FAIL; 176539234Sgibbs break; 176639234Sgibbs default: 1767241593Sjhb device_printf(dpt->dev, "Undocumented Error %x\n", hba_stat); 176840134Sgibbs printf("Please mail this message to shimon@simon-shapiro.org\n"); 176939234Sgibbs ccb->ccb_h.status = CAM_REQ_CMP_ERR; 177039234Sgibbs break; 177139234Sgibbs } 177239234Sgibbs dptfreeccb(dpt, dccb); 177339234Sgibbs xpt_done(ccb); 177439234Sgibbs} 177539234Sgibbs 177639234Sgibbsstatic void 177739234Sgibbsdpttimeout(void *arg) 177839234Sgibbs{ 177939234Sgibbs struct dpt_ccb *dccb; 178039234Sgibbs union ccb *ccb; 178139234Sgibbs struct dpt_softc *dpt; 178239234Sgibbs 178339234Sgibbs dccb = (struct dpt_ccb *)arg; 178439234Sgibbs ccb = dccb->ccb; 178539234Sgibbs dpt = (struct dpt_softc *)ccb->ccb_h.ccb_dpt_ptr; 1786241593Sjhb mtx_assert(&dpt->lock, MA_OWNED); 178739234Sgibbs xpt_print_path(ccb->ccb_h.path); 178839515Sgibbs printf("CCB %p - timed out\n", (void *)dccb); 178939234Sgibbs 179040134Sgibbs /* 1791160964Syar * Try to clear any pending jobs. FreeBSD will lose interrupts, 179240134Sgibbs * leaving the controller suspended, and commands timed-out. 179340134Sgibbs * By calling the interrupt handler, any command thus stuck will be 179440134Sgibbs * completed. 179540134Sgibbs */ 1796241593Sjhb dpt_intr_locked(dpt); 179740134Sgibbs 179839234Sgibbs if ((dccb->state & DCCB_ACTIVE) == 0) { 179939234Sgibbs xpt_print_path(ccb->ccb_h.path); 180039515Sgibbs printf("CCB %p - timed out CCB already completed\n", 180139515Sgibbs (void *)dccb); 180239234Sgibbs return; 180339234Sgibbs } 180439234Sgibbs 180540134Sgibbs /* Abort this particular command. Leave all others running */ 180639234Sgibbs dpt_send_immediate(dpt, &dccb->eata_ccb, dccb->eata_ccb.cp_busaddr, 180739234Sgibbs /*retries*/20000, EATA_SPECIFIC_ABORT, 0, 0); 180839234Sgibbs ccb->ccb_h.status = CAM_CMD_TIMEOUT; 180939234Sgibbs} 181039234Sgibbs 181139234Sgibbs/* 181239234Sgibbs * Shutdown the controller and ensure that the cache is completely flushed. 181350107Smsmith * Called from the shutdown_final event after all disk access has completed. 181439234Sgibbs */ 181539234Sgibbsstatic void 181650107Smsmithdptshutdown(void *arg, int howto) 181739234Sgibbs{ 181839234Sgibbs dpt_softc_t *dpt; 181939234Sgibbs 182039234Sgibbs dpt = (dpt_softc_t *)arg; 182139234Sgibbs 1822241593Sjhb device_printf(dpt->dev, 1823241593Sjhb "Shutting down (mode %x) HBA. Please wait...\n", howto); 182439234Sgibbs 182539234Sgibbs /* 182639234Sgibbs * What we do for a shutdown, is give the DPT early power loss warning 182739234Sgibbs */ 1828241593Sjhb mtx_lock(&dpt->lock); 182939234Sgibbs dpt_send_immediate(dpt, NULL, 0, EATA_POWER_OFF_WARN, 0, 0, 0); 1830241593Sjhb mtx_unlock(&dpt->lock); 183139234Sgibbs DELAY(1000 * 1000 * 5); 1832241593Sjhb device_printf(dpt->dev, "Controller was warned of shutdown and is now " 1833241593Sjhb "disabled\n"); 183439234Sgibbs} 183539234Sgibbs 183639234Sgibbs/*============================================================================*/ 183739234Sgibbs 183839234Sgibbs#if 0 183938115Seivind#ifdef DPT_RESET_HBA 184038115Seivind 184138115Seivind/* 184238115Seivind** Function name : dpt_reset_hba 184338115Seivind** 184438115Seivind** Description : Reset the HBA and properly discard all pending work 184539234Sgibbs** Input : Softc 184638115Seivind** Output : Nothing 184738115Seivind*/ 184838115Seivindstatic void 184938147Seivinddpt_reset_hba(dpt_softc_t *dpt) 185038115Seivind{ 185139234Sgibbs eata_ccb_t *ccb; 185239234Sgibbs dpt_ccb_t dccb, *dccbp; 185339234Sgibbs int result; 185439234Sgibbs struct scsi_xfer *xs; 1855241593Sjhb 1856241593Sjhb mtx_assert(&dpt->lock, MA_OWNED); 1857241593Sjhb 185839234Sgibbs /* Prepare a control block. The SCSI command part is immaterial */ 185939234Sgibbs dccb.xs = NULL; 186039234Sgibbs dccb.flags = 0; 186139234Sgibbs dccb.state = DPT_CCB_STATE_NEW; 186239234Sgibbs dccb.std_callback = NULL; 186339234Sgibbs dccb.wrbuff_callback = NULL; 186438115Seivind 186539234Sgibbs ccb = &dccb.eata_ccb; 186639234Sgibbs ccb->CP_OpCode = EATA_CMD_RESET; 186739234Sgibbs ccb->SCSI_Reset = 0; 186839234Sgibbs ccb->HBA_Init = 1; 186939234Sgibbs ccb->Auto_Req_Sen = 1; 187039234Sgibbs ccb->cp_id = 0; /* Should be ignored */ 187139234Sgibbs ccb->DataIn = 1; 187239234Sgibbs ccb->DataOut = 0; 187339234Sgibbs ccb->Interpret = 1; 187439234Sgibbs ccb->reqlen = htonl(sizeof(struct scsi_sense_data)); 187539234Sgibbs ccb->cp_statDMA = htonl(vtophys(&ccb->cp_statDMA)); 187639234Sgibbs ccb->cp_reqDMA = htonl(vtophys(&ccb->cp_reqDMA)); 187739234Sgibbs ccb->cp_viraddr = (u_int32_t) & ccb; 187838115Seivind 187939234Sgibbs ccb->cp_msg[0] = HA_IDENTIFY_MSG | HA_DISCO_RECO; 188039234Sgibbs ccb->cp_scsi_cmd = 0; /* Should be ignored */ 188138115Seivind 188239234Sgibbs /* Lock up the submitted queue. We are very persistant here */ 188339234Sgibbs while (dpt->queue_status & DPT_SUBMITTED_QUEUE_ACTIVE) { 188439234Sgibbs DELAY(100); 188539234Sgibbs } 188638115Seivind 188739234Sgibbs dpt->queue_status |= DPT_SUBMITTED_QUEUE_ACTIVE; 188838115Seivind 188939234Sgibbs /* Send the RESET message */ 189039234Sgibbs if ((result = dpt_send_eata_command(dpt, &dccb.eata_ccb, 189139234Sgibbs EATA_CMD_RESET, 0, 0, 0, 0)) != 0) { 1892241593Sjhb device_printf(dpt->dev, "Failed to send the RESET message.\n" 1893241593Sjhb " Trying cold boot (ouch!)\n"); 189438115Seivind 189538115Seivind 189639234Sgibbs if ((result = dpt_send_eata_command(dpt, &dccb.eata_ccb, 189739234Sgibbs EATA_COLD_BOOT, 0, 0, 189839234Sgibbs 0, 0)) != 0) { 1899241593Sjhb panic("%s: Faild to cold boot the HBA\n", 1900241593Sjhb device_get_nameunit(dpt->dev)); 190139234Sgibbs } 190238115Seivind#ifdef DPT_MEASURE_PERFORMANCE 190339234Sgibbs dpt->performance.cold_boots++; 190438115Seivind#endif /* DPT_MEASURE_PERFORMANCE */ 190539234Sgibbs } 190638115Seivind 190738115Seivind#ifdef DPT_MEASURE_PERFORMANCE 190838115Seivind dpt->performance.warm_starts++; 190938115Seivind#endif /* DPT_MEASURE_PERFORMANCE */ 191038115Seivind 1911241593Sjhb device_printf(dpt->dev, 1912241593Sjhb "Aborting pending requests. O/S should re-submit\n"); 191338115Seivind 191439234Sgibbs while ((dccbp = TAILQ_FIRST(&dpt->completed_ccbs)) != NULL) { 191539234Sgibbs struct scsi_xfer *xs = dccbp->xs; 191638115Seivind 191739234Sgibbs /* Not all transactions have xs structs */ 191839234Sgibbs if (xs != NULL) { 191939234Sgibbs /* Tell the kernel proper this did not complete well */ 192039234Sgibbs xs->error |= XS_SELTIMEOUT; 192139234Sgibbs xs->flags |= SCSI_ITSDONE; 192239234Sgibbs scsi_done(xs); 192339234Sgibbs } 192438115Seivind 192539234Sgibbs dpt_Qremove_submitted(dpt, dccbp); 192638115Seivind 192739234Sgibbs /* Remember, Callbacks are NOT in the standard queue */ 192839234Sgibbs if (dccbp->std_callback != NULL) { 192939234Sgibbs (dccbp->std_callback)(dpt, dccbp->eata_ccb.cp_channel, 193039234Sgibbs dccbp); 193139234Sgibbs } else { 193239234Sgibbs dpt_Qpush_free(dpt, dccbp); 193339234Sgibbs } 193438115Seivind } 193539234Sgibbs 1936241593Sjhb device_printf(dpt->dev, "reset done aborting all pending commands\n"); 193739234Sgibbs dpt->queue_status &= ~DPT_SUBMITTED_QUEUE_ACTIVE; 193838115Seivind} 193938115Seivind 194038115Seivind#endif /* DPT_RESET_HBA */ 194138115Seivind 194239234Sgibbs/* 194332801Sjulian * Build a Command Block for target mode READ/WRITE BUFFER, 194432801Sjulian * with the ``sync'' bit ON. 194532801Sjulian * 194632801Sjulian * Although the length and offset are 24 bit fields in the command, they cannot 194732801Sjulian * exceed 8192 bytes, so we take them as short integers andcheck their range. 194839234Sgibbs * If they are sensless, we round them to zero offset, maximum length and 194939234Sgibbs * complain. 195032801Sjulian */ 195132801Sjulian 195232801Sjulianstatic void 195332801Sjuliandpt_target_ccb(dpt_softc_t * dpt, int bus, u_int8_t target, u_int8_t lun, 195432801Sjulian dpt_ccb_t * ccb, int mode, u_int8_t command, 195532801Sjulian u_int16_t length, u_int16_t offset) 195632801Sjulian{ 195732801Sjulian eata_ccb_t *cp; 195832801Sjulian 1959241593Sjhb mtx_assert(&dpt->lock, MA_OWNED); 196032801Sjulian if ((length + offset) > DPT_MAX_TARGET_MODE_BUFFER_SIZE) { 1961241593Sjhb device_printf(dpt->dev, 1962241593Sjhb "Length of %d, and offset of %d are wrong\n", 1963241593Sjhb length, offset); 196432801Sjulian length = DPT_MAX_TARGET_MODE_BUFFER_SIZE; 196532801Sjulian offset = 0; 196632801Sjulian } 196732801Sjulian ccb->xs = NULL; 196832801Sjulian ccb->flags = 0; 196932801Sjulian ccb->state = DPT_CCB_STATE_NEW; 197032801Sjulian ccb->std_callback = (ccb_callback) dpt_target_done; 197132801Sjulian ccb->wrbuff_callback = NULL; 197232801Sjulian 197332801Sjulian cp = &ccb->eata_ccb; 197432801Sjulian cp->CP_OpCode = EATA_CMD_DMA_SEND_CP; 197532801Sjulian cp->SCSI_Reset = 0; 197632801Sjulian cp->HBA_Init = 0; 197732801Sjulian cp->Auto_Req_Sen = 1; 197832801Sjulian cp->cp_id = target; 197932801Sjulian cp->DataIn = 1; 198032801Sjulian cp->DataOut = 0; 198132801Sjulian cp->Interpret = 0; 198232801Sjulian cp->reqlen = htonl(sizeof(struct scsi_sense_data)); 198332801Sjulian cp->cp_statDMA = htonl(vtophys(&cp->cp_statDMA)); 198432801Sjulian cp->cp_reqDMA = htonl(vtophys(&cp->cp_reqDMA)); 198532801Sjulian cp->cp_viraddr = (u_int32_t) & ccb; 198632801Sjulian 198732801Sjulian cp->cp_msg[0] = HA_IDENTIFY_MSG | HA_DISCO_RECO; 198832801Sjulian 198932801Sjulian cp->cp_scsi_cmd = command; 199032801Sjulian cp->cp_cdb[1] = (u_int8_t) (mode & SCSI_TM_MODE_MASK); 199132801Sjulian cp->cp_lun = lun; /* Order is important here! */ 199232801Sjulian cp->cp_cdb[2] = 0x00; /* Buffer Id, only 1 :-( */ 199332801Sjulian cp->cp_cdb[3] = (length >> 16) & 0xFF; /* Buffer offset MSB */ 199432801Sjulian cp->cp_cdb[4] = (length >> 8) & 0xFF; 199532801Sjulian cp->cp_cdb[5] = length & 0xFF; 199632801Sjulian cp->cp_cdb[6] = (length >> 16) & 0xFF; /* Length MSB */ 199732801Sjulian cp->cp_cdb[7] = (length >> 8) & 0xFF; 199832801Sjulian cp->cp_cdb[8] = length & 0xFF; /* Length LSB */ 199932801Sjulian cp->cp_cdb[9] = 0; /* No sync, no match bits */ 200032801Sjulian 200139234Sgibbs /* 200232801Sjulian * This could be optimized to live in dpt_register_buffer. 200339234Sgibbs * We keep it here, just in case the kernel decides to reallocate pages 200432801Sjulian */ 200532801Sjulian if (dpt_scatter_gather(dpt, ccb, DPT_RW_BUFFER_SIZE, 200632801Sjulian dpt->rw_buffer[bus][target][lun])) { 2007241593Sjhb device_printf(dpt->dev, "Failed to setup Scatter/Gather for " 2008241593Sjhb "Target-Mode buffer\n"); 200932801Sjulian } 201032801Sjulian} 201132801Sjulian 201232801Sjulian/* Setup a target mode READ command */ 201332801Sjulian 201432801Sjulianstatic void 201532801Sjuliandpt_set_target(int redo, dpt_softc_t * dpt, 201632801Sjulian u_int8_t bus, u_int8_t target, u_int8_t lun, int mode, 201732801Sjulian u_int16_t length, u_int16_t offset, dpt_ccb_t * ccb) 201832801Sjulian{ 201932801Sjulian 2020241593Sjhb mtx_assert(&dpt->lock, MA_OWNED); 202132801Sjulian if (dpt->target_mode_enabled) { 202232801Sjulian if (!redo) 202332801Sjulian dpt_target_ccb(dpt, bus, target, lun, ccb, mode, 202432801Sjulian SCSI_TM_READ_BUFFER, length, offset); 202532801Sjulian 202632801Sjulian ccb->transaction_id = ++dpt->commands_processed; 202732801Sjulian 202832801Sjulian#ifdef DPT_MEASURE_PERFORMANCE 202938115Seivind dpt->performance.command_count[ccb->eata_ccb.cp_scsi_cmd]++; 203038115Seivind ccb->command_started = microtime_now; 203132801Sjulian#endif 203232801Sjulian dpt_Qadd_waiting(dpt, ccb); 203332801Sjulian dpt_sched_queue(dpt); 203432801Sjulian } else { 2035241593Sjhb device_printf(dpt->dev, 2036241593Sjhb "Target Mode Request, but Target Mode is OFF\n"); 203732801Sjulian } 203832801Sjulian} 203932801Sjulian 204039234Sgibbs/* 204132801Sjulian * Schedule a buffer to be sent to another target. 204238115Seivind * The work will be scheduled and the callback provided will be called when 204338115Seivind * the work is actually done. 204432801Sjulian * 204538115Seivind * Please NOTE: ``Anyone'' can send a buffer, but only registered clients 204638115Seivind * get notified of receipt of buffers. 204732801Sjulian */ 204832801Sjulian 204934480Sjulianint 205039234Sgibbsdpt_send_buffer(int unit, u_int8_t channel, u_int8_t target, u_int8_t lun, 205139234Sgibbs u_int8_t mode, u_int16_t length, u_int16_t offset, void *data, 205232801Sjulian buff_wr_done callback) 205332801Sjulian{ 205432801Sjulian dpt_softc_t *dpt; 205532801Sjulian dpt_ccb_t *ccb = NULL; 205632801Sjulian 205732801Sjulian /* This is an external call. Be a bit paranoid */ 2058241593Sjhb dpt = devclass_get_device(dpt_devclass, unit); 2059241593Sjhb if (dpt == NULL) 2060241593Sjhb return (INVALID_UNIT); 206132801Sjulian 2062241593Sjhb mtx_lock(&dpt->lock); 206332801Sjulian if (dpt->target_mode_enabled) { 206432801Sjulian if ((channel >= dpt->channels) || (target > dpt->max_id) || 206532801Sjulian (lun > dpt->max_lun)) { 2066241593Sjhb mtx_unlock(&dpt->lock); 206732801Sjulian return (INVALID_SENDER); 206832801Sjulian } 206932801Sjulian if ((dpt->rw_buffer[channel][target][lun] == NULL) || 2070241593Sjhb (dpt->buffer_receiver[channel][target][lun] == NULL)) { 2071241593Sjhb mtx_unlock(&dpt->lock); 207232801Sjulian return (NOT_REGISTERED); 2073241593Sjhb } 207432801Sjulian 207532801Sjulian /* Process the free list */ 207632801Sjulian if ((TAILQ_EMPTY(&dpt->free_ccbs)) && dpt_alloc_freelist(dpt)) { 2077241593Sjhb device_printf(dpt->dev, 2078241593Sjhb "ERROR: Cannot allocate any more free CCB's.\n" 2079241593Sjhb " Please try later\n"); 2080241593Sjhb mtx_unlock(&dpt->lock); 208132801Sjulian return (NO_RESOURCES); 208232801Sjulian } 208332801Sjulian /* Now grab the newest CCB */ 208432801Sjulian if ((ccb = dpt_Qpop_free(dpt)) == NULL) { 2085241593Sjhb mtx_unlock(&dpt->lock); 2086241593Sjhb panic("%s: Got a NULL CCB from pop_free()\n", 2087241593Sjhb device_get_nameunit(dpt->dev)); 208832801Sjulian } 208932801Sjulian 209032801Sjulian bcopy(dpt->rw_buffer[channel][target][lun] + offset, data, length); 209138115Seivind dpt_target_ccb(dpt, channel, target, lun, ccb, mode, 209238115Seivind SCSI_TM_WRITE_BUFFER, 209338115Seivind length, offset); 209438115Seivind ccb->std_callback = (ccb_callback) callback; /* Potential trouble */ 209532801Sjulian 209632801Sjulian ccb->transaction_id = ++dpt->commands_processed; 209732801Sjulian 209832801Sjulian#ifdef DPT_MEASURE_PERFORMANCE 209938115Seivind dpt->performance.command_count[ccb->eata_ccb.cp_scsi_cmd]++; 210038115Seivind ccb->command_started = microtime_now; 210132801Sjulian#endif 210232801Sjulian dpt_Qadd_waiting(dpt, ccb); 210332801Sjulian dpt_sched_queue(dpt); 210432801Sjulian 2105241593Sjhb mtx_unlock(&dpt->lock); 210632801Sjulian return (0); 210732801Sjulian } 2108241593Sjhb mtx_unlock(&dpt->lock); 210932801Sjulian return (DRIVER_DOWN); 211032801Sjulian} 211132801Sjulian 211232801Sjulianstatic void 211332801Sjuliandpt_target_done(dpt_softc_t * dpt, int bus, dpt_ccb_t * ccb) 211432801Sjulian{ 211532801Sjulian eata_ccb_t *cp; 211632801Sjulian 211732801Sjulian cp = &ccb->eata_ccb; 211832801Sjulian 211938561Sgibbs /* 212032801Sjulian * Remove the CCB from the waiting queue. 212132801Sjulian * We do NOT put it back on the free, etc., queues as it is a special 212232801Sjulian * ccb, owned by the dpt_softc of this unit. 212332801Sjulian */ 212432801Sjulian dpt_Qremove_completed(dpt, ccb); 212532801Sjulian 212632801Sjulian#define br_channel (ccb->eata_ccb.cp_channel) 212732801Sjulian#define br_target (ccb->eata_ccb.cp_id) 212832801Sjulian#define br_lun (ccb->eata_ccb.cp_LUN) 212932801Sjulian#define br_index [br_channel][br_target][br_lun] 213032801Sjulian#define read_buffer_callback (dpt->buffer_receiver br_index ) 213132801Sjulian#define read_buffer (dpt->rw_buffer[br_channel][br_target][br_lun]) 213232801Sjulian#define cb(offset) (ccb->eata_ccb.cp_cdb[offset]) 213332801Sjulian#define br_offset ((cb(3) << 16) | (cb(4) << 8) | cb(5)) 213432801Sjulian#define br_length ((cb(6) << 16) | (cb(7) << 8) | cb(8)) 213532801Sjulian 213632801Sjulian /* Different reasons for being here, you know... */ 213732801Sjulian switch (ccb->eata_ccb.cp_scsi_cmd) { 213832801Sjulian case SCSI_TM_READ_BUFFER: 213932801Sjulian if (read_buffer_callback != NULL) { 214032801Sjulian /* This is a buffer generated by a kernel process */ 2141241593Sjhb read_buffer_callback(device_get_unit(dpt->dev), 2142241593Sjhb br_channel, br_target, br_lun, 214332801Sjulian read_buffer, 214432801Sjulian br_offset, br_length); 214532801Sjulian } else { 214632801Sjulian /* 214732801Sjulian * This is a buffer waited for by a user (sleeping) 214832801Sjulian * command 214932801Sjulian */ 215032801Sjulian wakeup(ccb); 215132801Sjulian } 215232801Sjulian 215332801Sjulian /* We ALWAYS re-issue the same command; args are don't-care */ 215432801Sjulian dpt_set_target(1, 0, 0, 0, 0, 0, 0, 0, 0); 215532801Sjulian break; 215632801Sjulian 215732801Sjulian case SCSI_TM_WRITE_BUFFER: 2158241593Sjhb (ccb->wrbuff_callback) (device_get_unit(dpt->dev), br_channel, 2159241593Sjhb br_target, br_offset, br_length, 216032801Sjulian br_lun, ccb->status_packet.hba_stat); 216132801Sjulian break; 216232801Sjulian default: 2163241593Sjhb device_printf(dpt->dev, 2164241593Sjhb "%s is an unsupported command for target mode\n", 2165241593Sjhb scsi_cmd_name(ccb->eata_ccb.cp_scsi_cmd)); 216632801Sjulian } 216732801Sjulian dpt->target_ccb[br_channel][br_target][br_lun] = NULL; 216832801Sjulian dpt_Qpush_free(dpt, ccb); 216932801Sjulian} 217032801Sjulian 217132801Sjulian 217239234Sgibbs/* 217332801Sjulian * Use this function to register a client for a buffer read target operation. 217432801Sjulian * The function you register will be called every time a buffer is received 217532801Sjulian * by the target mode code. 217632801Sjulian */ 217734480Sjuliandpt_rb_t 217839234Sgibbsdpt_register_buffer(int unit, u_int8_t channel, u_int8_t target, u_int8_t lun, 217939234Sgibbs u_int8_t mode, u_int16_t length, u_int16_t offset, 218039234Sgibbs dpt_rec_buff callback, dpt_rb_op_t op) 218132801Sjulian{ 218232801Sjulian dpt_softc_t *dpt; 218332801Sjulian dpt_ccb_t *ccb = NULL; 218432801Sjulian int ospl; 218532801Sjulian 2186241593Sjhb dpt = devclass_get_device(dpt_devclass, unit); 2187241593Sjhb if (dpt == NULL) 2188241593Sjhb return (INVALID_UNIT); 2189241593Sjhb mtx_lock(&dpt->lock); 219032801Sjulian 2191241593Sjhb if (dpt->state & DPT_HA_SHUTDOWN_ACTIVE) { 2192241593Sjhb mtx_unlock(&dpt->lock); 219332801Sjulian return (DRIVER_DOWN); 2194241593Sjhb } 219532801Sjulian 219632801Sjulian if ((channel > (dpt->channels - 1)) || (target > (dpt->max_id - 1)) || 2197241593Sjhb (lun > (dpt->max_lun - 1))) { 2198241593Sjhb mtx_unlock(&dpt->lock); 219932801Sjulian return (INVALID_SENDER); 2200241593Sjhb } 220132801Sjulian 220232801Sjulian if (dpt->buffer_receiver[channel][target][lun] == NULL) { 220332801Sjulian if (op == REGISTER_BUFFER) { 220432801Sjulian /* Assign the requested callback */ 220532801Sjulian dpt->buffer_receiver[channel][target][lun] = callback; 220632801Sjulian /* Get a CCB */ 220732801Sjulian 220832801Sjulian /* Process the free list */ 220932801Sjulian if ((TAILQ_EMPTY(&dpt->free_ccbs)) && dpt_alloc_freelist(dpt)) { 2210241593Sjhb device_printf(dpt->dev, 2211241593Sjhb "ERROR: Cannot allocate any more free CCB's.\n" 2212241593Sjhb " Please try later\n"); 2213241593Sjhb mtx_unlock(&dpt->lock); 221432801Sjulian return (NO_RESOURCES); 221532801Sjulian } 221632801Sjulian /* Now grab the newest CCB */ 221732801Sjulian if ((ccb = dpt_Qpop_free(dpt)) == NULL) { 2218241593Sjhb mtx_unlock(&dpt->lock); 2219241593Sjhb panic("%s: Got a NULL CCB from pop_free()\n", 2220241593Sjhb device_get_nameunit(dpt->dev)); 222132801Sjulian } 222232801Sjulian 222332801Sjulian /* Clean up the leftover of the previous tenant */ 222432801Sjulian ccb->status = DPT_CCB_STATE_NEW; 222532801Sjulian dpt->target_ccb[channel][target][lun] = ccb; 222632801Sjulian 222739234Sgibbs dpt->rw_buffer[channel][target][lun] = 222839234Sgibbs malloc(DPT_RW_BUFFER_SIZE, M_DEVBUF, M_NOWAIT); 222932801Sjulian if (dpt->rw_buffer[channel][target][lun] == NULL) { 2230241593Sjhb device_printf(dpt->dev, "Failed to allocate " 2231241593Sjhb "Target-Mode buffer\n"); 223232801Sjulian dpt_Qpush_free(dpt, ccb); 2233241593Sjhb mtx_unlock(&dpt->lock); 223432801Sjulian return (NO_RESOURCES); 223532801Sjulian } 223639234Sgibbs dpt_set_target(0, dpt, channel, target, lun, mode, 223739234Sgibbs length, offset, ccb); 2238241593Sjhb mtx_unlock(&dpt->lock); 223932801Sjulian return (SUCCESSFULLY_REGISTERED); 2240241593Sjhb } else { 2241241593Sjhb mtx_unlock(&dpt->lock); 224232801Sjulian return (NOT_REGISTERED); 2243241593Sjhb } 224432801Sjulian } else { 224532801Sjulian if (op == REGISTER_BUFFER) { 2246241593Sjhb if (dpt->buffer_receiver[channel][target][lun] == callback) { 2247241593Sjhb mtx_unlock(&dpt->lock); 224832801Sjulian return (ALREADY_REGISTERED); 2249241593Sjhb } else { 2250241593Sjhb mtx_unlock(&dpt->lock); 225132801Sjulian return (REGISTERED_TO_ANOTHER); 2252241593Sjhb } 225332801Sjulian } else { 225432801Sjulian if (dpt->buffer_receiver[channel][target][lun] == callback) { 225532801Sjulian dpt->buffer_receiver[channel][target][lun] = NULL; 225632801Sjulian dpt_Qpush_free(dpt, ccb); 225732801Sjulian free(dpt->rw_buffer[channel][target][lun], M_DEVBUF); 2258241593Sjhb mtx_unlock(&dpt->lock); 225932801Sjulian return (SUCCESSFULLY_REGISTERED); 2260241593Sjhb } else { 2261241593Sjhb mtx_unlock(&dpt->lock); 226232801Sjulian return (INVALID_CALLBACK); 2263241593Sjhb } 226432801Sjulian } 226532801Sjulian 226632801Sjulian } 2267241593Sjhb mtx_unlock(&dpt->lock); 226832801Sjulian} 226932801Sjulian 227032801Sjulian/* Return the state of the blinking DPT LED's */ 227132801Sjulianu_int8_t 227232801Sjuliandpt_blinking_led(dpt_softc_t * dpt) 227332801Sjulian{ 227432801Sjulian int ndx; 227532801Sjulian u_int32_t state; 227632801Sjulian u_int32_t previous; 227732801Sjulian u_int8_t result; 227832801Sjulian 2279241593Sjhb mtx_assert(&dpt->lock, MA_OWNED); 228032801Sjulian result = 0; 228132801Sjulian 228232801Sjulian for (ndx = 0, state = 0, previous = 0; 228332801Sjulian (ndx < 10) && (state != previous); 228432801Sjulian ndx++) { 228532801Sjulian previous = state; 228632801Sjulian state = dpt_inl(dpt, 1); 228732801Sjulian } 228832801Sjulian 228932801Sjulian if ((state == previous) && (state == DPT_BLINK_INDICATOR)) 229032801Sjulian result = dpt_inb(dpt, 5); 229132801Sjulian 229232801Sjulian return (result); 229332801Sjulian} 229432801Sjulian 229539234Sgibbs/* 229632801Sjulian * Execute a command which did not come from the kernel's SCSI layer. 229732801Sjulian * The only way to map user commands to bus and target is to comply with the 229832801Sjulian * standard DPT wire-down scheme: 229932801Sjulian */ 230032801Sjulianint 230132801Sjuliandpt_user_cmd(dpt_softc_t * dpt, eata_pt_t * user_cmd, 230232801Sjulian caddr_t cmdarg, int minor_no) 230332801Sjulian{ 230439234Sgibbs dpt_ccb_t *ccb; 230539234Sgibbs void *data; 230639234Sgibbs int channel, target, lun; 230739234Sgibbs int huh; 230839234Sgibbs int result; 230939234Sgibbs int submitted; 231032801Sjulian 2311241593Sjhb mtx_assert(&dpt->lock, MA_OWNED); 231232801Sjulian data = NULL; 231332801Sjulian channel = minor2hba(minor_no); 231432801Sjulian target = minor2target(minor_no); 231532801Sjulian lun = minor2lun(minor_no); 231632801Sjulian 231732801Sjulian if ((channel > (dpt->channels - 1)) 231839234Sgibbs || (target > dpt->max_id) 231939234Sgibbs || (lun > dpt->max_lun)) 232032801Sjulian return (ENXIO); 232132801Sjulian 232232801Sjulian if (target == dpt->sc_scsi_link[channel].adapter_targ) { 232332801Sjulian /* This one is for the controller itself */ 232432801Sjulian if ((user_cmd->eataID[0] != 'E') 232539234Sgibbs || (user_cmd->eataID[1] != 'A') 232639234Sgibbs || (user_cmd->eataID[2] != 'T') 232739234Sgibbs || (user_cmd->eataID[3] != 'A')) { 232832801Sjulian return (ENXIO); 232932801Sjulian } 233032801Sjulian } 233132801Sjulian /* Get a DPT CCB, so we can prepare a command */ 233232801Sjulian 233332801Sjulian /* Process the free list */ 233432801Sjulian if ((TAILQ_EMPTY(&dpt->free_ccbs)) && dpt_alloc_freelist(dpt)) { 2335241593Sjhb device_printf(dpt->dev, 2336241593Sjhb "ERROR: Cannot allocate any more free CCB's.\n" 2337241593Sjhb " Please try later\n"); 233832801Sjulian return (EFAULT); 233932801Sjulian } 234032801Sjulian /* Now grab the newest CCB */ 234132801Sjulian if ((ccb = dpt_Qpop_free(dpt)) == NULL) { 2342241593Sjhb panic("%s: Got a NULL CCB from pop_free()\n", 2343241593Sjhb device_get_nameunit(dpt->dev)); 234432801Sjulian } else { 234532801Sjulian /* Clean up the leftover of the previous tenant */ 234632801Sjulian ccb->status = DPT_CCB_STATE_NEW; 234732801Sjulian } 234832801Sjulian 234932801Sjulian bcopy((caddr_t) & user_cmd->command_packet, (caddr_t) & ccb->eata_ccb, 235032801Sjulian sizeof(eata_ccb_t)); 235132801Sjulian 235232801Sjulian /* We do not want to do user specified scatter/gather. Why?? */ 235332801Sjulian if (ccb->eata_ccb.scatter == 1) 235432801Sjulian return (EINVAL); 235532801Sjulian 235632801Sjulian ccb->eata_ccb.Auto_Req_Sen = 1; 235732801Sjulian ccb->eata_ccb.reqlen = htonl(sizeof(struct scsi_sense_data)); 235832801Sjulian ccb->eata_ccb.cp_datalen = htonl(sizeof(ccb->eata_ccb.cp_datalen)); 235932801Sjulian ccb->eata_ccb.cp_dataDMA = htonl(vtophys(ccb->eata_ccb.cp_dataDMA)); 236032801Sjulian ccb->eata_ccb.cp_statDMA = htonl(vtophys(&ccb->eata_ccb.cp_statDMA)); 236132801Sjulian ccb->eata_ccb.cp_reqDMA = htonl(vtophys(&ccb->eata_ccb.cp_reqDMA)); 236232801Sjulian ccb->eata_ccb.cp_viraddr = (u_int32_t) & ccb; 236332801Sjulian 236432801Sjulian if (ccb->eata_ccb.DataIn || ccb->eata_ccb.DataOut) { 236532801Sjulian /* Data I/O is involved in this command. Alocate buffer */ 236632801Sjulian if (ccb->eata_ccb.cp_datalen > PAGE_SIZE) { 236732801Sjulian data = contigmalloc(ccb->eata_ccb.cp_datalen, 2368111119Simp M_TEMP, M_WAITOK, 0, ~0, 236932801Sjulian ccb->eata_ccb.cp_datalen, 237032801Sjulian 0x10000); 237132801Sjulian } else { 237232801Sjulian data = malloc(ccb->eata_ccb.cp_datalen, M_TEMP, 2373111119Simp M_WAITOK); 237432801Sjulian } 237532801Sjulian 237632801Sjulian if (data == NULL) { 2377241593Sjhb device_printf(dpt->dev, "Cannot allocate %d bytes " 2378241593Sjhb "for EATA command\n", 237932801Sjulian ccb->eata_ccb.cp_datalen); 238032801Sjulian return (EFAULT); 238132801Sjulian } 238232801Sjulian#define usr_cmd_DMA (caddr_t)user_cmd->command_packet.cp_dataDMA 238332801Sjulian if (ccb->eata_ccb.DataIn == 1) { 238432801Sjulian if (copyin(usr_cmd_DMA, 238532801Sjulian data, ccb->eata_ccb.cp_datalen) == -1) 238632801Sjulian return (EFAULT); 238732801Sjulian } 238832801Sjulian } else { 238932801Sjulian /* No data I/O involved here. Make sure the DPT knows that */ 239032801Sjulian ccb->eata_ccb.cp_datalen = 0; 239132801Sjulian data = NULL; 239232801Sjulian } 239332801Sjulian 239432801Sjulian if (ccb->eata_ccb.FWNEST == 1) 239532801Sjulian ccb->eata_ccb.FWNEST = 0; 239632801Sjulian 239732801Sjulian if (ccb->eata_ccb.cp_datalen != 0) { 239832801Sjulian if (dpt_scatter_gather(dpt, ccb, ccb->eata_ccb.cp_datalen, 239932801Sjulian data) != 0) { 240032801Sjulian if (data != NULL) 240132801Sjulian free(data, M_TEMP); 240232801Sjulian return (EFAULT); 240332801Sjulian } 240432801Sjulian } 240532801Sjulian /** 240632801Sjulian * We are required to quiet a SCSI bus. 240732801Sjulian * since we do not queue comands on a bus basis, 240832801Sjulian * we wait for ALL commands on a controller to complete. 240932801Sjulian * In the mean time, sched_queue() will not schedule new commands. 241032801Sjulian */ 241132801Sjulian if ((ccb->eata_ccb.cp_cdb[0] == MULTIFUNCTION_CMD) 241232801Sjulian && (ccb->eata_ccb.cp_cdb[2] == BUS_QUIET)) { 241332801Sjulian /* We wait for ALL traffic for this HBa to subside */ 241432801Sjulian dpt->state |= DPT_HA_QUIET; 241532801Sjulian 241632801Sjulian while ((submitted = dpt->submitted_ccbs_count) != 0) { 2417241593Sjhb huh = mtx_sleep((void *) dpt, &dpt->lock, 2418241593Sjhb PCATCH | PRIBIO, "dptqt", 100 * hz); 241932801Sjulian switch (huh) { 242032801Sjulian case 0: 242132801Sjulian /* Wakeup call received */ 242232801Sjulian break; 242332801Sjulian case EWOULDBLOCK: 242432801Sjulian /* Timer Expired */ 242532801Sjulian break; 242632801Sjulian default: 242732801Sjulian /* anything else */ 242832801Sjulian break; 242932801Sjulian } 243032801Sjulian } 243132801Sjulian } 243232801Sjulian /* Resume normal operation */ 243332801Sjulian if ((ccb->eata_ccb.cp_cdb[0] == MULTIFUNCTION_CMD) 243432801Sjulian && (ccb->eata_ccb.cp_cdb[2] == BUS_UNQUIET)) { 243532801Sjulian dpt->state &= ~DPT_HA_QUIET; 243632801Sjulian } 243732801Sjulian /** 243832801Sjulian * Schedule the command and submit it. 243932801Sjulian * We bypass dpt_sched_queue, as it will block on DPT_HA_QUIET 244032801Sjulian */ 244132801Sjulian ccb->xs = NULL; 244232801Sjulian ccb->flags = 0; 244332801Sjulian ccb->eata_ccb.Auto_Req_Sen = 1; /* We always want this feature */ 244432801Sjulian 244532801Sjulian ccb->transaction_id = ++dpt->commands_processed; 244632801Sjulian ccb->std_callback = (ccb_callback) dpt_user_cmd_done; 244732801Sjulian ccb->result = (u_int32_t) & cmdarg; 244832801Sjulian ccb->data = data; 244932801Sjulian 245032801Sjulian#ifdef DPT_MEASURE_PERFORMANCE 245138115Seivind ++dpt->performance.command_count[ccb->eata_ccb.cp_scsi_cmd]; 245238115Seivind ccb->command_started = microtime_now; 245332801Sjulian#endif 245432801Sjulian dpt_Qadd_waiting(dpt, ccb); 245532801Sjulian 245632801Sjulian dpt_sched_queue(dpt); 245732801Sjulian 245832801Sjulian /* Wait for the command to complete */ 2459241593Sjhb (void) mtx_sleep((void *) ccb, &dpt->lock, PCATCH | PRIBIO, "dptucw", 2460241593Sjhb 100 * hz); 246132801Sjulian 246232801Sjulian /* Free allocated memory */ 246332801Sjulian if (data != NULL) 246432801Sjulian free(data, M_TEMP); 246532801Sjulian 246632801Sjulian return (0); 246732801Sjulian} 246832801Sjulian 246932801Sjulianstatic void 247032801Sjuliandpt_user_cmd_done(dpt_softc_t * dpt, int bus, dpt_ccb_t * ccb) 247132801Sjulian{ 247232801Sjulian u_int32_t result; 247332801Sjulian caddr_t cmd_arg; 247432801Sjulian 2475241593Sjhb mtx_unlock(&dpt->lock); 2476241593Sjhb 247732801Sjulian /** 247832801Sjulian * If Auto Request Sense is on, copyout the sense struct 247932801Sjulian */ 248038231Sbde#define usr_pckt_DMA (caddr_t)(intptr_t)ntohl(ccb->eata_ccb.cp_reqDMA) 248132801Sjulian#define usr_pckt_len ntohl(ccb->eata_ccb.cp_datalen) 248232801Sjulian if (ccb->eata_ccb.Auto_Req_Sen == 1) { 248332801Sjulian if (copyout((caddr_t) & ccb->sense_data, usr_pckt_DMA, 248432801Sjulian sizeof(struct scsi_sense_data))) { 2485241593Sjhb mtx_lock(&dpt->lock); 248632801Sjulian ccb->result = EFAULT; 248732801Sjulian dpt_Qpush_free(dpt, ccb); 248832801Sjulian wakeup(ccb); 248932801Sjulian return; 249032801Sjulian } 249132801Sjulian } 249232801Sjulian /* If DataIn is on, copyout the data */ 249332801Sjulian if ((ccb->eata_ccb.DataIn == 1) 249432801Sjulian && (ccb->status_packet.hba_stat == HA_NO_ERROR)) { 249532801Sjulian if (copyout(ccb->data, usr_pckt_DMA, usr_pckt_len)) { 2496241593Sjhb mtx_lock(&dpt->lock); 249732801Sjulian dpt_Qpush_free(dpt, ccb); 249832801Sjulian ccb->result = EFAULT; 249932801Sjulian 250032801Sjulian wakeup(ccb); 250132801Sjulian return; 250232801Sjulian } 250332801Sjulian } 250432801Sjulian /* Copyout the status */ 250532801Sjulian result = ccb->status_packet.hba_stat; 250632801Sjulian cmd_arg = (caddr_t) ccb->result; 250732801Sjulian 250832801Sjulian if (copyout((caddr_t) & result, cmd_arg, sizeof(result))) { 2509241593Sjhb mtx_lock(&dpt->lock); 251032801Sjulian dpt_Qpush_free(dpt, ccb); 251132801Sjulian ccb->result = EFAULT; 251232801Sjulian wakeup(ccb); 251332801Sjulian return; 251432801Sjulian } 2515241593Sjhb mtx_lock(&dpt->lock); 251632801Sjulian /* Put the CCB back in the freelist */ 251732801Sjulian ccb->state |= DPT_CCB_STATE_COMPLETED; 251832801Sjulian dpt_Qpush_free(dpt, ccb); 251932801Sjulian 252032801Sjulian /* Free allocated memory */ 252132801Sjulian return; 252232801Sjulian} 252332801Sjulian 252432801Sjulian#endif 2525