1139749Simp/*- 2129449Sscottl * Copyright (c) 2000-04 ICP vortex GmbH 3129449Sscottl * Copyright (c) 2002-04 Intel Corporation 4129449Sscottl * Copyright (c) 2003-04 Adaptec Inc. 589580Smsmith * All Rights Reserved 689580Smsmith * 789580Smsmith * Redistribution and use in source and binary forms, with or without 889580Smsmith * modification, are permitted provided that the following conditions 989580Smsmith * are met: 1089580Smsmith * 1. Redistributions of source code must retain the above copyright 1189580Smsmith * notice, this list of conditions, and the following disclaimer, 1289580Smsmith * without modification, immediately at the beginning of the file. 1389580Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1489580Smsmith * notice, this list of conditions and the following disclaimer in the 1589580Smsmith * documentation and/or other materials provided with the distribution. 1689580Smsmith * 3. The name of the author may not be used to endorse or promote products 1789580Smsmith * derived from this software without specific prior written permission. 1889580Smsmith * 1989580Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2089580Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2189580Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2289580Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 2389580Smsmith * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2489580Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2589580Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2689580Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2789580Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2889580Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2989580Smsmith * SUCH DAMAGE. 3089580Smsmith */ 3189580Smsmith 3289580Smsmith/* 3389580Smsmith * iir.c: SCSI dependant code for the Intel Integrated RAID Controller driver 3489580Smsmith * 35120477Sscottl * Written by: Achim Leubner <achim_leubner@adaptec.com> 3689580Smsmith * Fixes/Additions: Boji Tony Kannanthanam <boji.t.kannanthanam@intel.com> 3789580Smsmith * 3889580Smsmith * credits: Niklas Hallqvist; OpenBSD driver for the ICP Controllers. 3989580Smsmith * Mike Smith; Some driver source code. 4089580Smsmith * FreeBSD.ORG; Great O/S to work on and for. 4189580Smsmith * 42129449Sscottl * $Id: iir.c 1.5 2004/03/30 10:17:53 achim Exp $" 4389580Smsmith */ 4489580Smsmith 45119418Sobrien#include <sys/cdefs.h> 46119418Sobrien__FBSDID("$FreeBSD$"); 4789580Smsmith 4889580Smsmith#define _IIR_C_ 4989580Smsmith 5089580Smsmith/* #include "opt_iir.h" */ 5189580Smsmith#include <sys/param.h> 5289580Smsmith#include <sys/systm.h> 5395533Smike#include <sys/endian.h> 5489580Smsmith#include <sys/eventhandler.h> 5589580Smsmith#include <sys/malloc.h> 5689580Smsmith#include <sys/kernel.h> 5789580Smsmith#include <sys/bus.h> 5889580Smsmith 5989580Smsmith#include <machine/bus.h> 6089580Smsmith#include <machine/stdarg.h> 6189580Smsmith 6289580Smsmith#include <cam/cam.h> 6389580Smsmith#include <cam/cam_ccb.h> 6489580Smsmith#include <cam/cam_sim.h> 6589580Smsmith#include <cam/cam_xpt_sim.h> 6689580Smsmith#include <cam/cam_debug.h> 6789580Smsmith#include <cam/scsi/scsi_all.h> 6889580Smsmith#include <cam/scsi/scsi_message.h> 6989580Smsmith 7089580Smsmith#include <dev/iir/iir.h> 7189580Smsmith 72227293Sedstatic MALLOC_DEFINE(M_GDTBUF, "iirbuf", "iir driver buffer"); 73156139Sscottl 7489580Smsmithstruct gdt_softc *gdt_wait_gdt; 7589580Smsmithint gdt_wait_index; 7689580Smsmith 7789580Smsmith#ifdef GDT_DEBUG 7889580Smsmithint gdt_debug = GDT_DEBUG; 7989580Smsmith#ifdef __SERIAL__ 8089580Smsmith#define MAX_SERBUF 160 8189580Smsmithstatic void ser_init(void); 8289580Smsmithstatic void ser_puts(char *str); 8389580Smsmithstatic void ser_putc(int c); 8489580Smsmithstatic char strbuf[MAX_SERBUF+1]; 8589580Smsmith#ifdef __COM2__ 8689580Smsmith#define COM_BASE 0x2f8 8789580Smsmith#else 8889580Smsmith#define COM_BASE 0x3f8 8989580Smsmith#endif 9089580Smsmithstatic void ser_init() 9189580Smsmith{ 9289580Smsmith unsigned port=COM_BASE; 9389580Smsmith 9489580Smsmith outb(port+3, 0x80); 9589580Smsmith outb(port+1, 0); 9689580Smsmith /* 19200 Baud, if 9600: outb(12,port) */ 9789580Smsmith outb(port, 6); 9889580Smsmith outb(port+3, 3); 9989580Smsmith outb(port+1, 0); 10089580Smsmith} 10189580Smsmith 10289580Smsmithstatic void ser_puts(char *str) 10389580Smsmith{ 10489580Smsmith char *ptr; 10589580Smsmith 10689580Smsmith ser_init(); 10789580Smsmith for (ptr=str;*ptr;++ptr) 10889580Smsmith ser_putc((int)(*ptr)); 10989580Smsmith} 11089580Smsmith 11189580Smsmithstatic void ser_putc(int c) 11289580Smsmith{ 11389580Smsmith unsigned port=COM_BASE; 11489580Smsmith 11589580Smsmith while ((inb(port+5) & 0x20)==0); 11689580Smsmith outb(port, c); 11789580Smsmith if (c==0x0a) 11889580Smsmith { 11989580Smsmith while ((inb(port+5) & 0x20)==0); 12089580Smsmith outb(port, 0x0d); 12189580Smsmith } 12289580Smsmith} 12389580Smsmith 12489580Smsmithint ser_printf(const char *fmt, ...) 12589580Smsmith{ 12689580Smsmith va_list args; 12789580Smsmith int i; 12889580Smsmith 12989580Smsmith va_start(args,fmt); 13089580Smsmith i = vsprintf(strbuf,fmt,args); 13189580Smsmith ser_puts(strbuf); 13289580Smsmith va_end(args); 13389580Smsmith return i; 13489580Smsmith} 13589580Smsmith#endif 13689580Smsmith#endif 13789580Smsmith 13889580Smsmith/* The linked list of softc structures */ 13989580Smsmithstruct gdt_softc_list gdt_softcs = TAILQ_HEAD_INITIALIZER(gdt_softcs); 14089580Smsmith/* controller cnt. */ 14189580Smsmithint gdt_cnt = 0; 14289580Smsmith/* event buffer */ 14389580Smsmithstatic gdt_evt_str ebuffer[GDT_MAX_EVENTS]; 14489580Smsmithstatic int elastidx, eoldidx; 14589580Smsmith/* statistics */ 14689580Smsmithgdt_statist_t gdt_stat; 14789580Smsmith 14889580Smsmith/* Definitions for our use of the SIM private CCB area */ 14989580Smsmith#define ccb_sim_ptr spriv_ptr0 15089580Smsmith#define ccb_priority spriv_field1 15189580Smsmith 15289580Smsmithstatic void iir_action(struct cam_sim *sim, union ccb *ccb); 15389580Smsmithstatic void iir_poll(struct cam_sim *sim); 15489580Smsmithstatic void iir_shutdown(void *arg, int howto); 15589580Smsmithstatic void iir_timeout(void *arg); 15689580Smsmith 15789580Smsmithstatic void gdt_eval_mapping(u_int32_t size, int *cyls, int *heads, 15889580Smsmith int *secs); 15989580Smsmithstatic int gdt_internal_cmd(struct gdt_softc *gdt, struct gdt_ccb *gccb, 16089580Smsmith u_int8_t service, u_int16_t opcode, 16189580Smsmith u_int32_t arg1, u_int32_t arg2, u_int32_t arg3); 16289580Smsmithstatic int gdt_wait(struct gdt_softc *gdt, struct gdt_ccb *ccb, 16389580Smsmith int timeout); 16489580Smsmith 16589580Smsmithstatic struct gdt_ccb *gdt_get_ccb(struct gdt_softc *gdt); 16689580Smsmith 16789580Smsmithstatic int gdt_sync_event(struct gdt_softc *gdt, int service, 16889580Smsmith u_int8_t index, struct gdt_ccb *gccb); 16989580Smsmithstatic int gdt_async_event(struct gdt_softc *gdt, int service); 17089580Smsmithstatic struct gdt_ccb *gdt_raw_cmd(struct gdt_softc *gdt, 17189580Smsmith union ccb *ccb, int *lock); 17289580Smsmithstatic struct gdt_ccb *gdt_cache_cmd(struct gdt_softc *gdt, 17389580Smsmith union ccb *ccb, int *lock); 17489580Smsmithstatic struct gdt_ccb *gdt_ioctl_cmd(struct gdt_softc *gdt, 17589580Smsmith gdt_ucmd_t *ucmd, int *lock); 17689580Smsmithstatic void gdt_internal_cache_cmd(struct gdt_softc *gdt,union ccb *ccb); 17789580Smsmith 17889580Smsmithstatic void gdtmapmem(void *arg, bus_dma_segment_t *dm_segs, 17989580Smsmith int nseg, int error); 18089580Smsmithstatic void gdtexecuteccb(void *arg, bus_dma_segment_t *dm_segs, 18189580Smsmith int nseg, int error); 18289580Smsmith 18389580Smsmithint 18489580Smsmithiir_init(struct gdt_softc *gdt) 18589580Smsmith{ 18689580Smsmith u_int16_t cdev_cnt; 18789580Smsmith int i, id, drv_cyls, drv_hds, drv_secs; 18889580Smsmith struct gdt_ccb *gccb; 18989580Smsmith 19089580Smsmith GDT_DPRINTF(GDT_D_DEBUG, ("iir_init()\n")); 19189580Smsmith 19289580Smsmith gdt->sc_state = GDT_POLLING; 19389580Smsmith gdt_clear_events(); 19489580Smsmith bzero(&gdt_stat, sizeof(gdt_statist_t)); 19589580Smsmith 19689580Smsmith SLIST_INIT(&gdt->sc_free_gccb); 19789580Smsmith SLIST_INIT(&gdt->sc_pending_gccb); 19889580Smsmith TAILQ_INIT(&gdt->sc_ccb_queue); 19989580Smsmith TAILQ_INIT(&gdt->sc_ucmd_queue); 20089580Smsmith TAILQ_INSERT_TAIL(&gdt_softcs, gdt, links); 20189580Smsmith 20289580Smsmith /* DMA tag for mapping buffers into device visible space. */ 20389580Smsmith if (bus_dma_tag_create(gdt->sc_parent_dmat, /*alignment*/1, /*boundary*/0, 204114001Sscottl /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, 20589580Smsmith /*highaddr*/BUS_SPACE_MAXADDR, 20689580Smsmith /*filter*/NULL, /*filterarg*/NULL, 20789580Smsmith /*maxsize*/MAXBSIZE, /*nsegments*/GDT_MAXSG, 20889580Smsmith /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, 20989580Smsmith /*flags*/BUS_DMA_ALLOCNOW, 210117126Sscottl /*lockfunc*/busdma_lock_mutex, /*lockarg*/&Giant, 21189580Smsmith &gdt->sc_buffer_dmat) != 0) { 21289580Smsmith printf("iir%d: bus_dma_tag_create(...,gdt->sc_buffer_dmat) failed\n", 21389580Smsmith gdt->sc_hanum); 21489580Smsmith return (1); 21589580Smsmith } 21689580Smsmith gdt->sc_init_level++; 21789580Smsmith 21889580Smsmith /* DMA tag for our ccb structures */ 219114001Sscottl if (bus_dma_tag_create(gdt->sc_parent_dmat, 220114001Sscottl /*alignment*/1, 221114001Sscottl /*boundary*/0, 222114001Sscottl /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, 22389580Smsmith /*highaddr*/BUS_SPACE_MAXADDR, 224114001Sscottl /*filter*/NULL, 225114001Sscottl /*filterarg*/NULL, 226156139Sscottl GDT_MAXCMDS * GDT_SCRATCH_SZ, /* maxsize */ 22789580Smsmith /*nsegments*/1, 22889580Smsmith /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, 229117126Sscottl /*flags*/0, /*lockfunc*/busdma_lock_mutex, 230156139Sscottl /*lockarg*/&Giant, &gdt->sc_gcscratch_dmat) != 0) { 231156139Sscottl printf("iir%d: bus_dma_tag_create(...,gdt->sc_gcscratch_dmat) failed\n", 23289580Smsmith gdt->sc_hanum); 23389580Smsmith return (1); 23489580Smsmith } 23589580Smsmith gdt->sc_init_level++; 23689580Smsmith 237156139Sscottl /* Allocation for our ccb scratch area */ 238156139Sscottl if (bus_dmamem_alloc(gdt->sc_gcscratch_dmat, (void **)&gdt->sc_gcscratch, 239156139Sscottl BUS_DMA_NOWAIT, &gdt->sc_gcscratch_dmamap) != 0) { 24089580Smsmith printf("iir%d: bus_dmamem_alloc(...,&gdt->sc_gccbs,...) failed\n", 24189580Smsmith gdt->sc_hanum); 24289580Smsmith return (1); 24389580Smsmith } 24489580Smsmith gdt->sc_init_level++; 24589580Smsmith 24689580Smsmith /* And permanently map them */ 247156139Sscottl bus_dmamap_load(gdt->sc_gcscratch_dmat, gdt->sc_gcscratch_dmamap, 248156139Sscottl gdt->sc_gcscratch, GDT_MAXCMDS * GDT_SCRATCH_SZ, 249156139Sscottl gdtmapmem, &gdt->sc_gcscratch_busbase, /*flags*/0); 25089580Smsmith gdt->sc_init_level++; 25189580Smsmith 25289580Smsmith /* Clear them out. */ 253156139Sscottl bzero(gdt->sc_gcscratch, GDT_MAXCMDS * GDT_SCRATCH_SZ); 25489580Smsmith 25589580Smsmith /* Initialize the ccbs */ 256156139Sscottl gdt->sc_gccbs = malloc(sizeof(struct gdt_ccb) * GDT_MAXCMDS, M_GDTBUF, 257156139Sscottl M_NOWAIT | M_ZERO); 258156139Sscottl if (gdt->sc_gccbs == NULL) { 259156139Sscottl printf("iir%d: no memory for gccbs.\n", gdt->sc_hanum); 260156139Sscottl return (1); 261156139Sscottl } 26289580Smsmith for (i = GDT_MAXCMDS-1; i >= 0; i--) { 263156139Sscottl gccb = &gdt->sc_gccbs[i]; 264156139Sscottl gccb->gc_cmd_index = i + 2; 265156139Sscottl gccb->gc_flags = GDT_GCF_UNUSED; 266156139Sscottl gccb->gc_map_flag = FALSE; 26789580Smsmith if (bus_dmamap_create(gdt->sc_buffer_dmat, /*flags*/0, 268156139Sscottl &gccb->gc_dmamap) != 0) 26989580Smsmith return(1); 270156139Sscottl gccb->gc_map_flag = TRUE; 271156139Sscottl gccb->gc_scratch = &gdt->sc_gcscratch[GDT_SCRATCH_SZ * i]; 272156139Sscottl gccb->gc_scratch_busbase = gdt->sc_gcscratch_busbase + GDT_SCRATCH_SZ * i; 273255871Sscottl callout_handle_init(&gccb->gc_timeout_ch); 274156139Sscottl SLIST_INSERT_HEAD(&gdt->sc_free_gccb, gccb, sle); 27589580Smsmith } 27689580Smsmith gdt->sc_init_level++; 27789580Smsmith 27889580Smsmith /* create the control device */ 27989580Smsmith gdt->sc_dev = gdt_make_dev(gdt->sc_hanum); 28089580Smsmith 28189580Smsmith /* allocate ccb for gdt_internal_cmd() */ 28289580Smsmith gccb = gdt_get_ccb(gdt); 28389580Smsmith if (gccb == NULL) { 28489580Smsmith printf("iir%d: No free command index found\n", 28589580Smsmith gdt->sc_hanum); 28689580Smsmith return (1); 28789580Smsmith } 288156139Sscottl bzero(gccb->gc_cmd, GDT_CMD_SZ); 28989580Smsmith 29089580Smsmith if (!gdt_internal_cmd(gdt, gccb, GDT_SCREENSERVICE, GDT_INIT, 29189580Smsmith 0, 0, 0)) { 29289580Smsmith printf("iir%d: Screen service initialization error %d\n", 29389580Smsmith gdt->sc_hanum, gdt->sc_status); 29489580Smsmith gdt_free_ccb(gdt, gccb); 29589580Smsmith return (1); 29689580Smsmith } 29789580Smsmith 29889580Smsmith gdt_internal_cmd(gdt, gccb, GDT_CACHESERVICE, GDT_UNFREEZE_IO, 29989580Smsmith 0, 0, 0); 30089580Smsmith 30189580Smsmith if (!gdt_internal_cmd(gdt, gccb, GDT_CACHESERVICE, GDT_INIT, 30289580Smsmith GDT_LINUX_OS, 0, 0)) { 303129449Sscottl printf("iir%d: Cache service initialization error %d\n", 30489580Smsmith gdt->sc_hanum, gdt->sc_status); 30589580Smsmith gdt_free_ccb(gdt, gccb); 30689580Smsmith return (1); 30789580Smsmith } 30889580Smsmith cdev_cnt = (u_int16_t)gdt->sc_info; 30989580Smsmith gdt->sc_fw_vers = gdt->sc_service; 31089580Smsmith 31189580Smsmith /* Detect number of buses */ 31289580Smsmith gdt_enc32(gccb->gc_scratch + GDT_IOC_VERSION, GDT_IOC_NEWEST); 31389580Smsmith gccb->gc_scratch[GDT_IOC_LIST_ENTRIES] = GDT_MAXBUS; 31489580Smsmith gccb->gc_scratch[GDT_IOC_FIRST_CHAN] = 0; 31589580Smsmith gccb->gc_scratch[GDT_IOC_LAST_CHAN] = GDT_MAXBUS - 1; 31689580Smsmith gdt_enc32(gccb->gc_scratch + GDT_IOC_LIST_OFFSET, GDT_IOC_HDR_SZ); 31789580Smsmith if (gdt_internal_cmd(gdt, gccb, GDT_CACHESERVICE, GDT_IOCTL, 31889580Smsmith GDT_IOCHAN_RAW_DESC, GDT_INVALID_CHANNEL, 31989580Smsmith GDT_IOC_HDR_SZ + GDT_MAXBUS * GDT_RAWIOC_SZ)) { 32089580Smsmith gdt->sc_bus_cnt = gccb->gc_scratch[GDT_IOC_CHAN_COUNT]; 32189580Smsmith for (i = 0; i < gdt->sc_bus_cnt; i++) { 32289580Smsmith id = gccb->gc_scratch[GDT_IOC_HDR_SZ + 32389580Smsmith i * GDT_RAWIOC_SZ + GDT_RAWIOC_PROC_ID]; 32489580Smsmith gdt->sc_bus_id[i] = id < GDT_MAXID_FC ? id : 0xff; 32589580Smsmith } 32689580Smsmith } else { 32789580Smsmith /* New method failed, use fallback. */ 32889580Smsmith for (i = 0; i < GDT_MAXBUS; i++) { 32989580Smsmith gdt_enc32(gccb->gc_scratch + GDT_GETCH_CHANNEL_NO, i); 33089580Smsmith if (!gdt_internal_cmd(gdt, gccb, GDT_CACHESERVICE, GDT_IOCTL, 33189580Smsmith GDT_SCSI_CHAN_CNT | GDT_L_CTRL_PATTERN, 33289580Smsmith GDT_IO_CHANNEL | GDT_INVALID_CHANNEL, 33389580Smsmith GDT_GETCH_SZ)) { 33489580Smsmith if (i == 0) { 33589580Smsmith printf("iir%d: Cannot get channel count, " 33689580Smsmith "error %d\n", gdt->sc_hanum, gdt->sc_status); 33789580Smsmith gdt_free_ccb(gdt, gccb); 33889580Smsmith return (1); 33989580Smsmith } 34089580Smsmith break; 34189580Smsmith } 34289580Smsmith gdt->sc_bus_id[i] = 34389580Smsmith (gccb->gc_scratch[GDT_GETCH_SIOP_ID] < GDT_MAXID_FC) ? 34489580Smsmith gccb->gc_scratch[GDT_GETCH_SIOP_ID] : 0xff; 34589580Smsmith } 34689580Smsmith gdt->sc_bus_cnt = i; 34789580Smsmith } 34889580Smsmith /* add one "virtual" channel for the host drives */ 34989580Smsmith gdt->sc_virt_bus = gdt->sc_bus_cnt; 35089580Smsmith gdt->sc_bus_cnt++; 35189580Smsmith 35289580Smsmith if (!gdt_internal_cmd(gdt, gccb, GDT_SCSIRAWSERVICE, GDT_INIT, 35389580Smsmith 0, 0, 0)) { 35489580Smsmith printf("iir%d: Raw service initialization error %d\n", 35589580Smsmith gdt->sc_hanum, gdt->sc_status); 35689580Smsmith gdt_free_ccb(gdt, gccb); 35789580Smsmith return (1); 35889580Smsmith } 35989580Smsmith 36089580Smsmith /* Set/get features raw service (scatter/gather) */ 36189580Smsmith gdt->sc_raw_feat = 0; 36289580Smsmith if (gdt_internal_cmd(gdt, gccb, GDT_SCSIRAWSERVICE, GDT_SET_FEAT, 36389580Smsmith GDT_SCATTER_GATHER, 0, 0)) { 36489580Smsmith if (gdt_internal_cmd(gdt, gccb, GDT_SCSIRAWSERVICE, GDT_GET_FEAT, 36589580Smsmith 0, 0, 0)) { 36689580Smsmith gdt->sc_raw_feat = gdt->sc_info; 36789580Smsmith if (!(gdt->sc_info & GDT_SCATTER_GATHER)) { 36889580Smsmith panic("iir%d: Scatter/Gather Raw Service " 36989580Smsmith "required but not supported!\n", gdt->sc_hanum); 37089580Smsmith gdt_free_ccb(gdt, gccb); 37189580Smsmith return (1); 37289580Smsmith } 37389580Smsmith } 37489580Smsmith } 37589580Smsmith 37689580Smsmith /* Set/get features cache service (scatter/gather) */ 37789580Smsmith gdt->sc_cache_feat = 0; 37889580Smsmith if (gdt_internal_cmd(gdt, gccb, GDT_CACHESERVICE, GDT_SET_FEAT, 37989580Smsmith 0, GDT_SCATTER_GATHER, 0)) { 38089580Smsmith if (gdt_internal_cmd(gdt, gccb, GDT_CACHESERVICE, GDT_GET_FEAT, 38189580Smsmith 0, 0, 0)) { 38289580Smsmith gdt->sc_cache_feat = gdt->sc_info; 38389580Smsmith if (!(gdt->sc_info & GDT_SCATTER_GATHER)) { 38489580Smsmith panic("iir%d: Scatter/Gather Cache Service " 38589580Smsmith "required but not supported!\n", gdt->sc_hanum); 38689580Smsmith gdt_free_ccb(gdt, gccb); 38789580Smsmith return (1); 38889580Smsmith } 38989580Smsmith } 39089580Smsmith } 39189580Smsmith 392114001Sscottl /* OEM */ 393114001Sscottl gdt_enc32(gccb->gc_scratch + GDT_OEM_VERSION, 0x01); 394114001Sscottl gdt_enc32(gccb->gc_scratch + GDT_OEM_BUFSIZE, sizeof(gdt_oem_record_t)); 395114001Sscottl if (gdt_internal_cmd(gdt, gccb, GDT_CACHESERVICE, GDT_IOCTL, 396114001Sscottl GDT_OEM_STR_RECORD, GDT_INVALID_CHANNEL, 397114001Sscottl sizeof(gdt_oem_str_record_t))) { 398114001Sscottl strncpy(gdt->oem_name, ((gdt_oem_str_record_t *) 399114001Sscottl gccb->gc_scratch)->text.scsi_host_drive_inquiry_vendor_id, 7); 400114001Sscottl gdt->oem_name[7]='\0'; 401114001Sscottl } else { 402114001Sscottl /* Old method, based on PCI ID */ 403254379Sjkim if (gdt->sc_vendor == INTEL_VENDOR_ID_IIR) 404114001Sscottl strcpy(gdt->oem_name,"Intel "); 405114001Sscottl else 406114001Sscottl strcpy(gdt->oem_name,"ICP "); 407114001Sscottl } 408114001Sscottl 40989580Smsmith /* Scan for cache devices */ 41089580Smsmith for (i = 0; i < cdev_cnt && i < GDT_MAX_HDRIVES; i++) { 41189580Smsmith if (gdt_internal_cmd(gdt, gccb, GDT_CACHESERVICE, GDT_INFO, 41289580Smsmith i, 0, 0)) { 41389580Smsmith gdt->sc_hdr[i].hd_present = 1; 41489580Smsmith gdt->sc_hdr[i].hd_size = gdt->sc_info; 41589580Smsmith 41689580Smsmith /* 41789580Smsmith * Evaluate mapping (sectors per head, heads per cyl) 41889580Smsmith */ 41989580Smsmith gdt->sc_hdr[i].hd_size &= ~GDT_SECS32; 42089580Smsmith if (gdt->sc_info2 == 0) 42189580Smsmith gdt_eval_mapping(gdt->sc_hdr[i].hd_size, 42289580Smsmith &drv_cyls, &drv_hds, &drv_secs); 42389580Smsmith else { 42489580Smsmith drv_hds = gdt->sc_info2 & 0xff; 42589580Smsmith drv_secs = (gdt->sc_info2 >> 8) & 0xff; 42689580Smsmith drv_cyls = gdt->sc_hdr[i].hd_size / drv_hds / 42789580Smsmith drv_secs; 42889580Smsmith } 42989580Smsmith gdt->sc_hdr[i].hd_heads = drv_hds; 43089580Smsmith gdt->sc_hdr[i].hd_secs = drv_secs; 43189580Smsmith /* Round the size */ 43289580Smsmith gdt->sc_hdr[i].hd_size = drv_cyls * drv_hds * drv_secs; 43389580Smsmith 43489580Smsmith if (gdt_internal_cmd(gdt, gccb, GDT_CACHESERVICE, 43589580Smsmith GDT_DEVTYPE, i, 0, 0)) 43689580Smsmith gdt->sc_hdr[i].hd_devtype = gdt->sc_info; 43789580Smsmith } 43889580Smsmith } 43989580Smsmith 44089580Smsmith GDT_DPRINTF(GDT_D_INIT, ("dpmem %x %d-bus %d cache device%s\n", 44189580Smsmith gdt->sc_dpmembase, 44289580Smsmith gdt->sc_bus_cnt, cdev_cnt, 44389580Smsmith cdev_cnt == 1 ? "" : "s")); 44489580Smsmith gdt_free_ccb(gdt, gccb); 44589580Smsmith 44689580Smsmith gdt_cnt++; 44789580Smsmith return (0); 44889580Smsmith} 44989580Smsmith 45089580Smsmithvoid 45189580Smsmithiir_free(struct gdt_softc *gdt) 45289580Smsmith{ 45389580Smsmith int i; 45489580Smsmith 45589580Smsmith GDT_DPRINTF(GDT_D_INIT, ("iir_free()\n")); 45689580Smsmith 45789580Smsmith switch (gdt->sc_init_level) { 45889580Smsmith default: 45989580Smsmith gdt_destroy_dev(gdt->sc_dev); 46089580Smsmith case 5: 46189580Smsmith for (i = GDT_MAXCMDS-1; i >= 0; i--) 46289580Smsmith if (gdt->sc_gccbs[i].gc_map_flag) 46389580Smsmith bus_dmamap_destroy(gdt->sc_buffer_dmat, 46489580Smsmith gdt->sc_gccbs[i].gc_dmamap); 465156139Sscottl bus_dmamap_unload(gdt->sc_gcscratch_dmat, gdt->sc_gcscratch_dmamap); 466156139Sscottl free(gdt->sc_gccbs, M_GDTBUF); 46789580Smsmith case 4: 468156139Sscottl bus_dmamem_free(gdt->sc_gcscratch_dmat, gdt->sc_gcscratch, gdt->sc_gcscratch_dmamap); 46989580Smsmith case 3: 470156139Sscottl bus_dma_tag_destroy(gdt->sc_gcscratch_dmat); 47189580Smsmith case 2: 47289580Smsmith bus_dma_tag_destroy(gdt->sc_buffer_dmat); 47389580Smsmith case 1: 47489580Smsmith bus_dma_tag_destroy(gdt->sc_parent_dmat); 47589580Smsmith case 0: 47689580Smsmith break; 47789580Smsmith } 47889580Smsmith TAILQ_REMOVE(&gdt_softcs, gdt, links); 47989580Smsmith} 48089580Smsmith 48189580Smsmithvoid 48289580Smsmithiir_attach(struct gdt_softc *gdt) 48389580Smsmith{ 48489580Smsmith struct cam_devq *devq; 48589580Smsmith int i; 48689580Smsmith 48789580Smsmith GDT_DPRINTF(GDT_D_INIT, ("iir_attach()\n")); 48889580Smsmith 48989580Smsmith /* 49089580Smsmith * Create the device queue for our SIM. 491156139Sscottl * XXX Throttle this down since the card has problems under load. 49289580Smsmith */ 493156139Sscottl devq = cam_simq_alloc(32); 49489580Smsmith if (devq == NULL) 49589580Smsmith return; 49689580Smsmith 49789580Smsmith for (i = 0; i < gdt->sc_bus_cnt; i++) { 49889580Smsmith /* 49989580Smsmith * Construct our SIM entry 50089580Smsmith */ 50189580Smsmith gdt->sims[i] = cam_sim_alloc(iir_action, iir_poll, "iir", 502168752Sscottl gdt, gdt->sc_hanum, &Giant, 503168752Sscottl /*untagged*/1, 50489580Smsmith /*tagged*/GDT_MAXCMDS, devq); 505170872Sscottl if (xpt_bus_register(gdt->sims[i], gdt->sc_devnode, i) != CAM_SUCCESS) { 50689580Smsmith cam_sim_free(gdt->sims[i], /*free_devq*/i == 0); 50789580Smsmith break; 50889580Smsmith } 50989580Smsmith 51089580Smsmith if (xpt_create_path(&gdt->paths[i], /*periph*/NULL, 51189580Smsmith cam_sim_path(gdt->sims[i]), 51289580Smsmith CAM_TARGET_WILDCARD, 51389580Smsmith CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 51489580Smsmith xpt_bus_deregister(cam_sim_path(gdt->sims[i])); 51589580Smsmith cam_sim_free(gdt->sims[i], /*free_devq*/i == 0); 51689580Smsmith break; 51789580Smsmith } 51889580Smsmith } 51989580Smsmith if (i > 0) 52089580Smsmith EVENTHANDLER_REGISTER(shutdown_final, iir_shutdown, 52189580Smsmith gdt, SHUTDOWN_PRI_DEFAULT); 52289580Smsmith /* iir_watchdog(gdt); */ 52389580Smsmith gdt->sc_state = GDT_NORMAL; 52489580Smsmith} 52589580Smsmith 52689580Smsmithstatic void 52789580Smsmithgdt_eval_mapping(u_int32_t size, int *cyls, int *heads, int *secs) 52889580Smsmith{ 52989580Smsmith *cyls = size / GDT_HEADS / GDT_SECS; 53089580Smsmith if (*cyls < GDT_MAXCYLS) { 53189580Smsmith *heads = GDT_HEADS; 53289580Smsmith *secs = GDT_SECS; 53389580Smsmith } else { 53489580Smsmith /* Too high for 64 * 32 */ 53589580Smsmith *cyls = size / GDT_MEDHEADS / GDT_MEDSECS; 53689580Smsmith if (*cyls < GDT_MAXCYLS) { 53789580Smsmith *heads = GDT_MEDHEADS; 53889580Smsmith *secs = GDT_MEDSECS; 53989580Smsmith } else { 54089580Smsmith /* Too high for 127 * 63 */ 54189580Smsmith *cyls = size / GDT_BIGHEADS / GDT_BIGSECS; 54289580Smsmith *heads = GDT_BIGHEADS; 54389580Smsmith *secs = GDT_BIGSECS; 54489580Smsmith } 54589580Smsmith } 54689580Smsmith} 54789580Smsmith 54889580Smsmithstatic int 54989580Smsmithgdt_wait(struct gdt_softc *gdt, struct gdt_ccb *gccb, 55089580Smsmith int timeout) 55189580Smsmith{ 55289580Smsmith int rv = 0; 55389580Smsmith 55489580Smsmith GDT_DPRINTF(GDT_D_INIT, 55589580Smsmith ("gdt_wait(%p, %p, %d)\n", gdt, gccb, timeout)); 55689580Smsmith 55789580Smsmith gdt->sc_state |= GDT_POLL_WAIT; 55889580Smsmith do { 55989580Smsmith iir_intr(gdt); 56089580Smsmith if (gdt == gdt_wait_gdt && 56189580Smsmith gccb->gc_cmd_index == gdt_wait_index) { 56289580Smsmith rv = 1; 56389580Smsmith break; 56489580Smsmith } 56589580Smsmith DELAY(1); 56689580Smsmith } while (--timeout); 56789580Smsmith gdt->sc_state &= ~GDT_POLL_WAIT; 56889580Smsmith 56989580Smsmith while (gdt->sc_test_busy(gdt)) 57089580Smsmith DELAY(1); /* XXX correct? */ 57189580Smsmith 57289580Smsmith return (rv); 57389580Smsmith} 57489580Smsmith 57589580Smsmithstatic int 57689580Smsmithgdt_internal_cmd(struct gdt_softc *gdt, struct gdt_ccb *gccb, 57789580Smsmith u_int8_t service, u_int16_t opcode, 57889580Smsmith u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 57989580Smsmith{ 58089580Smsmith int retries; 58189580Smsmith 58289580Smsmith GDT_DPRINTF(GDT_D_CMD, ("gdt_internal_cmd(%p, %d, %d, %d, %d, %d)\n", 58389580Smsmith gdt, service, opcode, arg1, arg2, arg3)); 58489580Smsmith 585156139Sscottl bzero(gccb->gc_cmd, GDT_CMD_SZ); 58689580Smsmith 58789580Smsmith for (retries = GDT_RETRIES; ; ) { 58889580Smsmith gccb->gc_service = service; 58989580Smsmith gccb->gc_flags = GDT_GCF_INTERNAL; 59089580Smsmith 591156139Sscottl gdt_enc32(gccb->gc_cmd + GDT_CMD_COMMANDINDEX, 59289580Smsmith gccb->gc_cmd_index); 593156139Sscottl gdt_enc16(gccb->gc_cmd + GDT_CMD_OPCODE, opcode); 59489580Smsmith 59589580Smsmith switch (service) { 59689580Smsmith case GDT_CACHESERVICE: 59789580Smsmith if (opcode == GDT_IOCTL) { 598156139Sscottl gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + 59989580Smsmith GDT_IOCTL_SUBFUNC, arg1); 600156139Sscottl gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + 60189580Smsmith GDT_IOCTL_CHANNEL, arg2); 602156139Sscottl gdt_enc16(gccb->gc_cmd + GDT_CMD_UNION + 60389580Smsmith GDT_IOCTL_PARAM_SIZE, (u_int16_t)arg3); 604156139Sscottl gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_IOCTL_P_PARAM, 605156139Sscottl gccb->gc_scratch_busbase); 60689580Smsmith } else { 607156139Sscottl gdt_enc16(gccb->gc_cmd + GDT_CMD_UNION + 60889580Smsmith GDT_CACHE_DEVICENO, (u_int16_t)arg1); 609156139Sscottl gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + 61089580Smsmith GDT_CACHE_BLOCKNO, arg2); 61189580Smsmith } 61289580Smsmith break; 61389580Smsmith 61489580Smsmith case GDT_SCSIRAWSERVICE: 615156139Sscottl gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + 61689580Smsmith GDT_RAW_DIRECTION, arg1); 617156139Sscottl gccb->gc_cmd[GDT_CMD_UNION + GDT_RAW_BUS] = 61889580Smsmith (u_int8_t)arg2; 619156139Sscottl gccb->gc_cmd[GDT_CMD_UNION + GDT_RAW_TARGET] = 62089580Smsmith (u_int8_t)arg3; 621156139Sscottl gccb->gc_cmd[GDT_CMD_UNION + GDT_RAW_LUN] = 62289580Smsmith (u_int8_t)(arg3 >> 8); 62389580Smsmith } 62489580Smsmith 625156139Sscottl gdt->sc_set_sema0(gdt); 626156139Sscottl gccb->gc_cmd_len = GDT_CMD_SZ; 62789580Smsmith gdt->sc_cmd_off = 0; 62889580Smsmith gdt->sc_cmd_cnt = 0; 62989580Smsmith gdt->sc_copy_cmd(gdt, gccb); 63089580Smsmith gdt->sc_release_event(gdt); 63189580Smsmith DELAY(20); 63289580Smsmith if (!gdt_wait(gdt, gccb, GDT_POLL_TIMEOUT)) 63389580Smsmith return (0); 63489580Smsmith if (gdt->sc_status != GDT_S_BSY || --retries == 0) 63589580Smsmith break; 63689580Smsmith DELAY(1); 63789580Smsmith } 63889580Smsmith return (gdt->sc_status == GDT_S_OK); 63989580Smsmith} 64089580Smsmith 64189580Smsmithstatic struct gdt_ccb * 64289580Smsmithgdt_get_ccb(struct gdt_softc *gdt) 64389580Smsmith{ 64489580Smsmith struct gdt_ccb *gccb; 64589580Smsmith int lock; 64689580Smsmith 64789580Smsmith GDT_DPRINTF(GDT_D_QUEUE, ("gdt_get_ccb(%p)\n", gdt)); 64889580Smsmith 64989580Smsmith lock = splcam(); 65089580Smsmith gccb = SLIST_FIRST(&gdt->sc_free_gccb); 65189580Smsmith if (gccb != NULL) { 65289580Smsmith SLIST_REMOVE_HEAD(&gdt->sc_free_gccb, sle); 65389580Smsmith SLIST_INSERT_HEAD(&gdt->sc_pending_gccb, gccb, sle); 65489580Smsmith ++gdt_stat.cmd_index_act; 65589580Smsmith if (gdt_stat.cmd_index_act > gdt_stat.cmd_index_max) 65689580Smsmith gdt_stat.cmd_index_max = gdt_stat.cmd_index_act; 65789580Smsmith } 65889580Smsmith splx(lock); 65989580Smsmith return (gccb); 66089580Smsmith} 66189580Smsmith 66289580Smsmithvoid 66389580Smsmithgdt_free_ccb(struct gdt_softc *gdt, struct gdt_ccb *gccb) 66489580Smsmith{ 66589580Smsmith int lock; 66689580Smsmith 66789580Smsmith GDT_DPRINTF(GDT_D_QUEUE, ("gdt_free_ccb(%p, %p)\n", gdt, gccb)); 66889580Smsmith 66989580Smsmith lock = splcam(); 67089580Smsmith gccb->gc_flags = GDT_GCF_UNUSED; 67189580Smsmith SLIST_REMOVE(&gdt->sc_pending_gccb, gccb, gdt_ccb, sle); 67289580Smsmith SLIST_INSERT_HEAD(&gdt->sc_free_gccb, gccb, sle); 67389580Smsmith --gdt_stat.cmd_index_act; 67489580Smsmith splx(lock); 67589580Smsmith if (gdt->sc_state & GDT_SHUTDOWN) 67689580Smsmith wakeup(gccb); 67789580Smsmith} 67889580Smsmith 67989580Smsmithvoid 68089580Smsmithgdt_next(struct gdt_softc *gdt) 68189580Smsmith{ 68289580Smsmith int lock; 68389580Smsmith union ccb *ccb; 68489580Smsmith gdt_ucmd_t *ucmd; 68589580Smsmith struct cam_sim *sim; 68689580Smsmith int bus, target, lun; 68789580Smsmith int next_cmd; 68889580Smsmith 68989580Smsmith struct ccb_scsiio *csio; 69089580Smsmith struct ccb_hdr *ccbh; 69189580Smsmith struct gdt_ccb *gccb = NULL; 69289580Smsmith u_int8_t cmd; 69389580Smsmith 69489580Smsmith GDT_DPRINTF(GDT_D_QUEUE, ("gdt_next(%p)\n", gdt)); 69589580Smsmith 69689580Smsmith lock = splcam(); 69789580Smsmith if (gdt->sc_test_busy(gdt)) { 69889580Smsmith if (!(gdt->sc_state & GDT_POLLING)) { 69989580Smsmith splx(lock); 70089580Smsmith return; 70189580Smsmith } 70289580Smsmith while (gdt->sc_test_busy(gdt)) 70389580Smsmith DELAY(1); 70489580Smsmith } 70589580Smsmith 70689580Smsmith gdt->sc_cmd_cnt = gdt->sc_cmd_off = 0; 70789580Smsmith next_cmd = TRUE; 70889580Smsmith for (;;) { 70989580Smsmith /* I/Os in queue? controller ready? */ 71089580Smsmith if (!TAILQ_FIRST(&gdt->sc_ucmd_queue) && 71189580Smsmith !TAILQ_FIRST(&gdt->sc_ccb_queue)) 71289580Smsmith break; 71389580Smsmith 71489580Smsmith /* 1.: I/Os without ccb (IOCTLs) */ 71589580Smsmith ucmd = TAILQ_FIRST(&gdt->sc_ucmd_queue); 71689580Smsmith if (ucmd != NULL) { 71789580Smsmith TAILQ_REMOVE(&gdt->sc_ucmd_queue, ucmd, links); 71889580Smsmith if ((gccb = gdt_ioctl_cmd(gdt, ucmd, &lock)) == NULL) { 71989580Smsmith TAILQ_INSERT_HEAD(&gdt->sc_ucmd_queue, ucmd, links); 72089580Smsmith break; 72189580Smsmith } 72289580Smsmith break; 72389580Smsmith /* wenn mehrere Kdos. zulassen: if (!gdt_polling) continue; */ 72489580Smsmith } 72589580Smsmith 72689580Smsmith /* 2.: I/Os with ccb */ 72789580Smsmith ccb = (union ccb *)TAILQ_FIRST(&gdt->sc_ccb_queue); 72889580Smsmith /* ist dann immer != NULL, da oben getestet */ 72989580Smsmith sim = (struct cam_sim *)ccb->ccb_h.ccb_sim_ptr; 73089580Smsmith bus = cam_sim_bus(sim); 73189580Smsmith target = ccb->ccb_h.target_id; 73289580Smsmith lun = ccb->ccb_h.target_lun; 73389580Smsmith 73489580Smsmith TAILQ_REMOVE(&gdt->sc_ccb_queue, &ccb->ccb_h, sim_links.tqe); 73589580Smsmith --gdt_stat.req_queue_act; 73689580Smsmith /* ccb->ccb_h.func_code is XPT_SCSI_IO */ 73789580Smsmith GDT_DPRINTF(GDT_D_QUEUE, ("XPT_SCSI_IO flags 0x%x)\n", 73889580Smsmith ccb->ccb_h.flags)); 73989580Smsmith csio = &ccb->csio; 74089580Smsmith ccbh = &ccb->ccb_h; 74189580Smsmith cmd = csio->cdb_io.cdb_bytes[0]; 74289580Smsmith /* Max CDB length is 12 bytes */ 74389580Smsmith if (csio->cdb_len > 12) { 74489580Smsmith ccbh->status = CAM_REQ_INVALID; 74589580Smsmith --gdt_stat.io_count_act; 74689580Smsmith xpt_done(ccb); 74789580Smsmith } else if (bus != gdt->sc_virt_bus) { 74889580Smsmith /* raw service command */ 74989580Smsmith if ((gccb = gdt_raw_cmd(gdt, ccb, &lock)) == NULL) { 75089580Smsmith TAILQ_INSERT_HEAD(&gdt->sc_ccb_queue, &ccb->ccb_h, 75189580Smsmith sim_links.tqe); 75289580Smsmith ++gdt_stat.req_queue_act; 75389580Smsmith if (gdt_stat.req_queue_act > gdt_stat.req_queue_max) 75489580Smsmith gdt_stat.req_queue_max = gdt_stat.req_queue_act; 75589580Smsmith next_cmd = FALSE; 75689580Smsmith } 75789580Smsmith } else if (target >= GDT_MAX_HDRIVES || 75889580Smsmith !gdt->sc_hdr[target].hd_present || lun != 0) { 759114001Sscottl ccbh->status = CAM_DEV_NOT_THERE; 76089580Smsmith --gdt_stat.io_count_act; 76189580Smsmith xpt_done(ccb); 76289580Smsmith } else { 76389580Smsmith /* cache service command */ 76489580Smsmith if (cmd == READ_6 || cmd == WRITE_6 || 76589580Smsmith cmd == READ_10 || cmd == WRITE_10) { 76689580Smsmith if ((gccb = gdt_cache_cmd(gdt, ccb, &lock)) == NULL) { 76789580Smsmith TAILQ_INSERT_HEAD(&gdt->sc_ccb_queue, &ccb->ccb_h, 76889580Smsmith sim_links.tqe); 76989580Smsmith ++gdt_stat.req_queue_act; 77089580Smsmith if (gdt_stat.req_queue_act > gdt_stat.req_queue_max) 77189580Smsmith gdt_stat.req_queue_max = gdt_stat.req_queue_act; 77289580Smsmith next_cmd = FALSE; 77389580Smsmith } 77489580Smsmith } else { 77589580Smsmith splx(lock); 77689580Smsmith gdt_internal_cache_cmd(gdt, ccb); 77789580Smsmith lock = splcam(); 77889580Smsmith } 77989580Smsmith } 78089580Smsmith if ((gdt->sc_state & GDT_POLLING) || !next_cmd) 78189580Smsmith break; 78289580Smsmith } 78389580Smsmith if (gdt->sc_cmd_cnt > 0) 78489580Smsmith gdt->sc_release_event(gdt); 78589580Smsmith 78689580Smsmith splx(lock); 78789580Smsmith 78889580Smsmith if ((gdt->sc_state & GDT_POLLING) && gdt->sc_cmd_cnt > 0) { 78989580Smsmith gdt_wait(gdt, gccb, GDT_POLL_TIMEOUT); 79089580Smsmith } 79189580Smsmith} 79289580Smsmith 79389580Smsmithstatic struct gdt_ccb * 79489580Smsmithgdt_raw_cmd(struct gdt_softc *gdt, union ccb *ccb, int *lock) 79589580Smsmith{ 79689580Smsmith struct gdt_ccb *gccb; 79789580Smsmith struct cam_sim *sim; 798246713Skib int error; 79989580Smsmith 80089580Smsmith GDT_DPRINTF(GDT_D_CMD, ("gdt_raw_cmd(%p, %p)\n", gdt, ccb)); 80189580Smsmith 80289580Smsmith if (roundup(GDT_CMD_UNION + GDT_RAW_SZ, sizeof(u_int32_t)) + 80389580Smsmith gdt->sc_cmd_off + GDT_DPMEM_COMMAND_OFFSET > 80489580Smsmith gdt->sc_ic_all_size) { 80589580Smsmith GDT_DPRINTF(GDT_D_INVALID, ("iir%d: gdt_raw_cmd(): DPMEM overflow\n", 80689580Smsmith gdt->sc_hanum)); 80789580Smsmith return (NULL); 80889580Smsmith } 80989580Smsmith 81089580Smsmith gccb = gdt_get_ccb(gdt); 81189580Smsmith if (gccb == NULL) { 81289580Smsmith GDT_DPRINTF(GDT_D_INVALID, ("iir%d: No free command index found\n", 81389580Smsmith gdt->sc_hanum)); 81489580Smsmith return (gccb); 81589580Smsmith } 816156139Sscottl bzero(gccb->gc_cmd, GDT_CMD_SZ); 81789580Smsmith sim = (struct cam_sim *)ccb->ccb_h.ccb_sim_ptr; 81889580Smsmith gccb->gc_ccb = ccb; 81989580Smsmith gccb->gc_service = GDT_SCSIRAWSERVICE; 82089580Smsmith gccb->gc_flags = GDT_GCF_SCSI; 82189580Smsmith 82289580Smsmith if (gdt->sc_cmd_cnt == 0) 82389580Smsmith gdt->sc_set_sema0(gdt); 82489580Smsmith splx(*lock); 825156139Sscottl gdt_enc32(gccb->gc_cmd + GDT_CMD_COMMANDINDEX, 82689580Smsmith gccb->gc_cmd_index); 827156139Sscottl gdt_enc16(gccb->gc_cmd + GDT_CMD_OPCODE, GDT_WRITE); 82889580Smsmith 829156139Sscottl gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_DIRECTION, 83089580Smsmith (ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN ? 83189580Smsmith GDT_DATA_IN : GDT_DATA_OUT); 832156139Sscottl gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_SDLEN, 83389580Smsmith ccb->csio.dxfer_len); 834156139Sscottl gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_CLEN, 83589580Smsmith ccb->csio.cdb_len); 836156139Sscottl bcopy(ccb->csio.cdb_io.cdb_bytes, gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_CMD, 83789580Smsmith ccb->csio.cdb_len); 838156139Sscottl gccb->gc_cmd[GDT_CMD_UNION + GDT_RAW_TARGET] = 83989580Smsmith ccb->ccb_h.target_id; 840156139Sscottl gccb->gc_cmd[GDT_CMD_UNION + GDT_RAW_LUN] = 84189580Smsmith ccb->ccb_h.target_lun; 842156139Sscottl gccb->gc_cmd[GDT_CMD_UNION + GDT_RAW_BUS] = 84389580Smsmith cam_sim_bus(sim); 844156139Sscottl gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_SENSE_LEN, 84589580Smsmith sizeof(struct scsi_sense_data)); 846156139Sscottl gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_SENSE_DATA, 847156139Sscottl gccb->gc_scratch_busbase); 84889580Smsmith 849246713Skib error = bus_dmamap_load_ccb(gdt->sc_buffer_dmat, 850246713Skib gccb->gc_dmamap, 851246713Skib ccb, 852246713Skib gdtexecuteccb, 853246713Skib gccb, /*flags*/0); 854246713Skib if (error == EINPROGRESS) { 855246713Skib xpt_freeze_simq(sim, 1); 856246713Skib gccb->gc_ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 85789580Smsmith } 85889580Smsmith 85989580Smsmith *lock = splcam(); 86089580Smsmith return (gccb); 86189580Smsmith} 86289580Smsmith 86389580Smsmithstatic struct gdt_ccb * 86489580Smsmithgdt_cache_cmd(struct gdt_softc *gdt, union ccb *ccb, int *lock) 86589580Smsmith{ 86689580Smsmith struct gdt_ccb *gccb; 86789580Smsmith struct cam_sim *sim; 86889580Smsmith u_int8_t *cmdp; 86989580Smsmith u_int16_t opcode; 87089580Smsmith u_int32_t blockno, blockcnt; 871246713Skib int error; 87289580Smsmith 87389580Smsmith GDT_DPRINTF(GDT_D_CMD, ("gdt_cache_cmd(%p, %p)\n", gdt, ccb)); 87489580Smsmith 87589580Smsmith if (roundup(GDT_CMD_UNION + GDT_CACHE_SZ, sizeof(u_int32_t)) + 87689580Smsmith gdt->sc_cmd_off + GDT_DPMEM_COMMAND_OFFSET > 87789580Smsmith gdt->sc_ic_all_size) { 87889580Smsmith GDT_DPRINTF(GDT_D_INVALID, ("iir%d: gdt_cache_cmd(): DPMEM overflow\n", 87989580Smsmith gdt->sc_hanum)); 88089580Smsmith return (NULL); 88189580Smsmith } 88289580Smsmith 88389580Smsmith gccb = gdt_get_ccb(gdt); 88489580Smsmith if (gccb == NULL) { 88589580Smsmith GDT_DPRINTF(GDT_D_DEBUG, ("iir%d: No free command index found\n", 88689580Smsmith gdt->sc_hanum)); 88789580Smsmith return (gccb); 88889580Smsmith } 889156139Sscottl bzero(gccb->gc_cmd, GDT_CMD_SZ); 89089580Smsmith sim = (struct cam_sim *)ccb->ccb_h.ccb_sim_ptr; 89189580Smsmith gccb->gc_ccb = ccb; 89289580Smsmith gccb->gc_service = GDT_CACHESERVICE; 89389580Smsmith gccb->gc_flags = GDT_GCF_SCSI; 89489580Smsmith 89589580Smsmith if (gdt->sc_cmd_cnt == 0) 89689580Smsmith gdt->sc_set_sema0(gdt); 89789580Smsmith splx(*lock); 898156139Sscottl gdt_enc32(gccb->gc_cmd + GDT_CMD_COMMANDINDEX, 89989580Smsmith gccb->gc_cmd_index); 90089580Smsmith cmdp = ccb->csio.cdb_io.cdb_bytes; 90189580Smsmith opcode = (*cmdp == WRITE_6 || *cmdp == WRITE_10) ? GDT_WRITE : GDT_READ; 90289580Smsmith if ((gdt->sc_state & GDT_SHUTDOWN) && opcode == GDT_WRITE) 90389580Smsmith opcode = GDT_WRITE_THR; 904156139Sscottl gdt_enc16(gccb->gc_cmd + GDT_CMD_OPCODE, opcode); 90589580Smsmith 906156139Sscottl gdt_enc16(gccb->gc_cmd + GDT_CMD_UNION + GDT_CACHE_DEVICENO, 90789580Smsmith ccb->ccb_h.target_id); 90889580Smsmith if (ccb->csio.cdb_len == 6) { 90989580Smsmith struct scsi_rw_6 *rw = (struct scsi_rw_6 *)cmdp; 91089580Smsmith blockno = scsi_3btoul(rw->addr) & ((SRW_TOPADDR<<16) | 0xffff); 91189580Smsmith blockcnt = rw->length ? rw->length : 0x100; 91289580Smsmith } else { 91389580Smsmith struct scsi_rw_10 *rw = (struct scsi_rw_10 *)cmdp; 91489580Smsmith blockno = scsi_4btoul(rw->addr); 91589580Smsmith blockcnt = scsi_2btoul(rw->length); 91689580Smsmith } 917156139Sscottl gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_CACHE_BLOCKNO, 91889580Smsmith blockno); 919156139Sscottl gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_CACHE_BLOCKCNT, 92089580Smsmith blockcnt); 92189580Smsmith 922246713Skib error = bus_dmamap_load_ccb(gdt->sc_buffer_dmat, 92389580Smsmith gccb->gc_dmamap, 924246713Skib ccb, 92589580Smsmith gdtexecuteccb, 92689580Smsmith gccb, /*flags*/0); 927246713Skib if (error == EINPROGRESS) { 928246713Skib xpt_freeze_simq(sim, 1); 929246713Skib gccb->gc_ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 93089580Smsmith } 93189580Smsmith *lock = splcam(); 93289580Smsmith return (gccb); 93389580Smsmith} 93489580Smsmith 93589580Smsmithstatic struct gdt_ccb * 93689580Smsmithgdt_ioctl_cmd(struct gdt_softc *gdt, gdt_ucmd_t *ucmd, int *lock) 93789580Smsmith{ 93889580Smsmith struct gdt_ccb *gccb; 93989580Smsmith u_int32_t cnt; 94089580Smsmith 94189580Smsmith GDT_DPRINTF(GDT_D_DEBUG, ("gdt_ioctl_cmd(%p, %p)\n", gdt, ucmd)); 94289580Smsmith 94389580Smsmith gccb = gdt_get_ccb(gdt); 94489580Smsmith if (gccb == NULL) { 94589580Smsmith GDT_DPRINTF(GDT_D_DEBUG, ("iir%d: No free command index found\n", 94689580Smsmith gdt->sc_hanum)); 94789580Smsmith return (gccb); 94889580Smsmith } 949156139Sscottl bzero(gccb->gc_cmd, GDT_CMD_SZ); 95089580Smsmith gccb->gc_ucmd = ucmd; 95189580Smsmith gccb->gc_service = ucmd->service; 95289580Smsmith gccb->gc_flags = GDT_GCF_IOCTL; 95389580Smsmith 95489580Smsmith /* check DPMEM space, copy data buffer from user space */ 95589580Smsmith if (ucmd->service == GDT_CACHESERVICE) { 95689580Smsmith if (ucmd->OpCode == GDT_IOCTL) { 957156139Sscottl gccb->gc_cmd_len = roundup(GDT_CMD_UNION + GDT_IOCTL_SZ, 95889580Smsmith sizeof(u_int32_t)); 95989580Smsmith cnt = ucmd->u.ioctl.param_size; 96089580Smsmith if (cnt > GDT_SCRATCH_SZ) { 96189580Smsmith printf("iir%d: Scratch buffer too small (%d/%d)\n", 96289580Smsmith gdt->sc_hanum, GDT_SCRATCH_SZ, cnt); 96389580Smsmith gdt_free_ccb(gdt, gccb); 96489580Smsmith return (NULL); 96589580Smsmith } 96689580Smsmith } else { 967156139Sscottl gccb->gc_cmd_len = roundup(GDT_CMD_UNION + GDT_CACHE_SG_LST + 96889580Smsmith GDT_SG_SZ, sizeof(u_int32_t)); 96989580Smsmith cnt = ucmd->u.cache.BlockCnt * GDT_SECTOR_SIZE; 97089580Smsmith if (cnt > GDT_SCRATCH_SZ) { 97189580Smsmith printf("iir%d: Scratch buffer too small (%d/%d)\n", 97289580Smsmith gdt->sc_hanum, GDT_SCRATCH_SZ, cnt); 97389580Smsmith gdt_free_ccb(gdt, gccb); 97489580Smsmith return (NULL); 97589580Smsmith } 97689580Smsmith } 97789580Smsmith } else { 978156139Sscottl gccb->gc_cmd_len = roundup(GDT_CMD_UNION + GDT_RAW_SG_LST + 97989580Smsmith GDT_SG_SZ, sizeof(u_int32_t)); 98089580Smsmith cnt = ucmd->u.raw.sdlen; 98189580Smsmith if (cnt + ucmd->u.raw.sense_len > GDT_SCRATCH_SZ) { 98289580Smsmith printf("iir%d: Scratch buffer too small (%d/%d)\n", 98389580Smsmith gdt->sc_hanum, GDT_SCRATCH_SZ, cnt + ucmd->u.raw.sense_len); 98489580Smsmith gdt_free_ccb(gdt, gccb); 98589580Smsmith return (NULL); 98689580Smsmith } 98789580Smsmith } 98889580Smsmith if (cnt != 0) 98989580Smsmith bcopy(ucmd->data, gccb->gc_scratch, cnt); 99089580Smsmith 991156139Sscottl if (gdt->sc_cmd_off + gccb->gc_cmd_len + GDT_DPMEM_COMMAND_OFFSET > 99289580Smsmith gdt->sc_ic_all_size) { 99389580Smsmith GDT_DPRINTF(GDT_D_INVALID, ("iir%d: gdt_ioctl_cmd(): DPMEM overflow\n", 99489580Smsmith gdt->sc_hanum)); 99589580Smsmith gdt_free_ccb(gdt, gccb); 99689580Smsmith return (NULL); 99789580Smsmith } 99889580Smsmith 99989580Smsmith if (gdt->sc_cmd_cnt == 0) 100089580Smsmith gdt->sc_set_sema0(gdt); 100189580Smsmith splx(*lock); 100289580Smsmith 100389580Smsmith /* fill cmd structure */ 1004156139Sscottl gdt_enc32(gccb->gc_cmd + GDT_CMD_COMMANDINDEX, 100589580Smsmith gccb->gc_cmd_index); 1006156139Sscottl gdt_enc16(gccb->gc_cmd + GDT_CMD_OPCODE, 100789580Smsmith ucmd->OpCode); 100889580Smsmith 100989580Smsmith if (ucmd->service == GDT_CACHESERVICE) { 101089580Smsmith if (ucmd->OpCode == GDT_IOCTL) { 101189580Smsmith /* IOCTL */ 1012156139Sscottl gdt_enc16(gccb->gc_cmd + GDT_CMD_UNION + GDT_IOCTL_PARAM_SIZE, 101389580Smsmith ucmd->u.ioctl.param_size); 1014156139Sscottl gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_IOCTL_SUBFUNC, 101589580Smsmith ucmd->u.ioctl.subfunc); 1016156139Sscottl gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_IOCTL_CHANNEL, 101789580Smsmith ucmd->u.ioctl.channel); 1018156139Sscottl gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_IOCTL_P_PARAM, 1019156139Sscottl gccb->gc_scratch_busbase); 102089580Smsmith } else { 102189580Smsmith /* cache service command */ 1022156139Sscottl gdt_enc16(gccb->gc_cmd + GDT_CMD_UNION + GDT_CACHE_DEVICENO, 102389580Smsmith ucmd->u.cache.DeviceNo); 1024156139Sscottl gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_CACHE_BLOCKNO, 102589580Smsmith ucmd->u.cache.BlockNo); 1026156139Sscottl gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_CACHE_BLOCKCNT, 102789580Smsmith ucmd->u.cache.BlockCnt); 1028156139Sscottl gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_CACHE_DESTADDR, 102989580Smsmith 0xffffffffUL); 1030156139Sscottl gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_CACHE_SG_CANZ, 103189580Smsmith 1); 1032156139Sscottl gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_CACHE_SG_LST + 1033156139Sscottl GDT_SG_PTR, gccb->gc_scratch_busbase); 1034156139Sscottl gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_CACHE_SG_LST + 103589580Smsmith GDT_SG_LEN, ucmd->u.cache.BlockCnt * GDT_SECTOR_SIZE); 103689580Smsmith } 103789580Smsmith } else { 103889580Smsmith /* raw service command */ 1039156139Sscottl gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_DIRECTION, 104089580Smsmith ucmd->u.raw.direction); 1041156139Sscottl gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_SDATA, 104289580Smsmith 0xffffffffUL); 1043156139Sscottl gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_SDLEN, 104489580Smsmith ucmd->u.raw.sdlen); 1045156139Sscottl gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_CLEN, 104689580Smsmith ucmd->u.raw.clen); 1047156139Sscottl bcopy(ucmd->u.raw.cmd, gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_CMD, 104889580Smsmith 12); 1049156139Sscottl gccb->gc_cmd[GDT_CMD_UNION + GDT_RAW_TARGET] = 105089580Smsmith ucmd->u.raw.target; 1051156139Sscottl gccb->gc_cmd[GDT_CMD_UNION + GDT_RAW_LUN] = 105289580Smsmith ucmd->u.raw.lun; 1053156139Sscottl gccb->gc_cmd[GDT_CMD_UNION + GDT_RAW_BUS] = 105489580Smsmith ucmd->u.raw.bus; 1055156139Sscottl gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_SENSE_LEN, 105689580Smsmith ucmd->u.raw.sense_len); 1057156139Sscottl gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_SENSE_DATA, 1058156139Sscottl gccb->gc_scratch_busbase + ucmd->u.raw.sdlen); 1059156139Sscottl gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_SG_RANZ, 106089580Smsmith 1); 1061156139Sscottl gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_SG_LST + 1062156139Sscottl GDT_SG_PTR, gccb->gc_scratch_busbase); 1063156139Sscottl gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_SG_LST + 106489580Smsmith GDT_SG_LEN, ucmd->u.raw.sdlen); 106589580Smsmith } 106689580Smsmith 106789580Smsmith *lock = splcam(); 106889580Smsmith gdt_stat.sg_count_act = 1; 106989580Smsmith gdt->sc_copy_cmd(gdt, gccb); 107089580Smsmith return (gccb); 107189580Smsmith} 107289580Smsmith 107389580Smsmithstatic void 107489580Smsmithgdt_internal_cache_cmd(struct gdt_softc *gdt,union ccb *ccb) 107589580Smsmith{ 107689580Smsmith int t; 107789580Smsmith 107889580Smsmith t = ccb->ccb_h.target_id; 107989580Smsmith GDT_DPRINTF(GDT_D_CMD, ("gdt_internal_cache_cmd(%p, %p, 0x%x, %d)\n", 108089580Smsmith gdt, ccb, ccb->csio.cdb_io.cdb_bytes[0], t)); 108189580Smsmith 108289580Smsmith switch (ccb->csio.cdb_io.cdb_bytes[0]) { 108389580Smsmith case TEST_UNIT_READY: 108489580Smsmith case START_STOP: 108589580Smsmith break; 108689580Smsmith case REQUEST_SENSE: 108789580Smsmith GDT_DPRINTF(GDT_D_MISC, ("REQUEST_SENSE\n")); 108889580Smsmith break; 108989580Smsmith case INQUIRY: 109089580Smsmith { 1091175197Sscottl struct scsi_inquiry_data inq; 1092175197Sscottl size_t copylen = MIN(sizeof(inq), ccb->csio.dxfer_len); 109389580Smsmith 1094175197Sscottl bzero(&inq, sizeof(inq)); 1095175197Sscottl inq.device = (gdt->sc_hdr[t].hd_devtype & 4) ? 109689580Smsmith T_CDROM : T_DIRECT; 1097175197Sscottl inq.dev_qual2 = (gdt->sc_hdr[t].hd_devtype & 1) ? 0x80 : 0; 1098175197Sscottl inq.version = SCSI_REV_2; 1099175197Sscottl inq.response_format = 2; 1100175197Sscottl inq.additional_length = 32; 1101175197Sscottl inq.flags = SID_CmdQue | SID_Sync; 1102175197Sscottl strncpy(inq.vendor, gdt->oem_name, sizeof(inq.vendor)); 1103175197Sscottl snprintf(inq.product, sizeof(inq.product), 1104175197Sscottl "Host Drive #%02d", t); 1105175197Sscottl strncpy(inq.revision, " ", sizeof(inq.revision)); 1106175197Sscottl bcopy(&inq, ccb->csio.data_ptr, copylen ); 1107175197Sscottl if( ccb->csio.dxfer_len > copylen ) 1108175197Sscottl bzero( ccb->csio.data_ptr+copylen, 1109175197Sscottl ccb->csio.dxfer_len - copylen ); 111089580Smsmith break; 111189580Smsmith } 111289580Smsmith case MODE_SENSE_6: 111389580Smsmith { 111489580Smsmith struct mpd_data { 111589580Smsmith struct scsi_mode_hdr_6 hd; 111689580Smsmith struct scsi_mode_block_descr bd; 111789580Smsmith struct scsi_control_page cp; 1118175197Sscottl } mpd; 1119175197Sscottl size_t copylen = MIN(sizeof(mpd), ccb->csio.dxfer_len); 112089580Smsmith u_int8_t page; 112189580Smsmith 1122175197Sscottl /*mpd = (struct mpd_data *)ccb->csio.data_ptr;*/ 1123175197Sscottl bzero(&mpd, sizeof(mpd)); 1124175197Sscottl mpd.hd.datalen = sizeof(struct scsi_mode_hdr_6) + 112589580Smsmith sizeof(struct scsi_mode_block_descr); 1126175197Sscottl mpd.hd.dev_specific = (gdt->sc_hdr[t].hd_devtype & 2) ? 0x80 : 0; 1127175197Sscottl mpd.hd.block_descr_len = sizeof(struct scsi_mode_block_descr); 1128175197Sscottl mpd.bd.block_len[0] = (GDT_SECTOR_SIZE & 0x00ff0000) >> 16; 1129175197Sscottl mpd.bd.block_len[1] = (GDT_SECTOR_SIZE & 0x0000ff00) >> 8; 1130175197Sscottl mpd.bd.block_len[2] = (GDT_SECTOR_SIZE & 0x000000ff); 1131175197Sscottl 1132175197Sscottl bcopy(&mpd, ccb->csio.data_ptr, copylen ); 1133175197Sscottl if( ccb->csio.dxfer_len > copylen ) 1134175197Sscottl bzero( ccb->csio.data_ptr+copylen, 1135175197Sscottl ccb->csio.dxfer_len - copylen ); 113689580Smsmith page=((struct scsi_mode_sense_6 *)ccb->csio.cdb_io.cdb_bytes)->page; 113789580Smsmith switch (page) { 113889580Smsmith default: 113989580Smsmith GDT_DPRINTF(GDT_D_MISC, ("MODE_SENSE_6: page 0x%x\n", page)); 114089580Smsmith break; 114189580Smsmith } 114289580Smsmith break; 114389580Smsmith } 114489580Smsmith case READ_CAPACITY: 114589580Smsmith { 1146175197Sscottl struct scsi_read_capacity_data rcd; 1147175197Sscottl size_t copylen = MIN(sizeof(rcd), ccb->csio.dxfer_len); 114889580Smsmith 1149175197Sscottl /*rcd = (struct scsi_read_capacity_data *)ccb->csio.data_ptr;*/ 1150175197Sscottl bzero(&rcd, sizeof(rcd)); 1151175197Sscottl scsi_ulto4b(gdt->sc_hdr[t].hd_size - 1, rcd.addr); 1152175197Sscottl scsi_ulto4b(GDT_SECTOR_SIZE, rcd.length); 1153175197Sscottl bcopy(&rcd, ccb->csio.data_ptr, copylen ); 1154175197Sscottl if( ccb->csio.dxfer_len > copylen ) 1155175197Sscottl bzero( ccb->csio.data_ptr+copylen, 1156175197Sscottl ccb->csio.dxfer_len - copylen ); 115789580Smsmith break; 115889580Smsmith } 115989580Smsmith default: 116089580Smsmith GDT_DPRINTF(GDT_D_MISC, ("gdt_internal_cache_cmd(%d) unknown\n", 116189580Smsmith ccb->csio.cdb_io.cdb_bytes[0])); 116289580Smsmith break; 116389580Smsmith } 1164156139Sscottl ccb->ccb_h.status |= CAM_REQ_CMP; 116589580Smsmith --gdt_stat.io_count_act; 116689580Smsmith xpt_done(ccb); 116789580Smsmith} 116889580Smsmith 116989580Smsmithstatic void 117089580Smsmithgdtmapmem(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) 117189580Smsmith{ 117289580Smsmith bus_addr_t *busaddrp; 117389580Smsmith 117489580Smsmith busaddrp = (bus_addr_t *)arg; 117589580Smsmith *busaddrp = dm_segs->ds_addr; 117689580Smsmith} 117789580Smsmith 117889580Smsmithstatic void 117989580Smsmithgdtexecuteccb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) 118089580Smsmith{ 118189580Smsmith struct gdt_ccb *gccb; 118289580Smsmith union ccb *ccb; 118389580Smsmith struct gdt_softc *gdt; 118489580Smsmith int i, lock; 118589580Smsmith 118689580Smsmith lock = splcam(); 118789580Smsmith 118889580Smsmith gccb = (struct gdt_ccb *)arg; 118989580Smsmith ccb = gccb->gc_ccb; 119089580Smsmith gdt = cam_sim_softc((struct cam_sim *)ccb->ccb_h.ccb_sim_ptr); 119189580Smsmith 119289580Smsmith GDT_DPRINTF(GDT_D_CMD, ("gdtexecuteccb(%p, %p, %p, %d, %d)\n", 119389580Smsmith gdt, gccb, dm_segs, nseg, error)); 119489580Smsmith gdt_stat.sg_count_act = nseg; 119589580Smsmith if (nseg > gdt_stat.sg_count_max) 119689580Smsmith gdt_stat.sg_count_max = nseg; 119789580Smsmith 119889580Smsmith /* Copy the segments into our SG list */ 119989580Smsmith if (gccb->gc_service == GDT_CACHESERVICE) { 120089580Smsmith for (i = 0; i < nseg; ++i) { 1201156139Sscottl gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_CACHE_SG_LST + 120289580Smsmith i * GDT_SG_SZ + GDT_SG_PTR, dm_segs->ds_addr); 1203156139Sscottl gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_CACHE_SG_LST + 120489580Smsmith i * GDT_SG_SZ + GDT_SG_LEN, dm_segs->ds_len); 120589580Smsmith dm_segs++; 120689580Smsmith } 1207156139Sscottl gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_CACHE_SG_CANZ, 120889580Smsmith nseg); 1209156139Sscottl gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_CACHE_DESTADDR, 121089580Smsmith 0xffffffffUL); 121189580Smsmith 1212156139Sscottl gccb->gc_cmd_len = roundup(GDT_CMD_UNION + GDT_CACHE_SG_LST + 121389580Smsmith nseg * GDT_SG_SZ, sizeof(u_int32_t)); 121489580Smsmith } else { 121589580Smsmith for (i = 0; i < nseg; ++i) { 1216156139Sscottl gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_SG_LST + 121789580Smsmith i * GDT_SG_SZ + GDT_SG_PTR, dm_segs->ds_addr); 1218156139Sscottl gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_SG_LST + 121989580Smsmith i * GDT_SG_SZ + GDT_SG_LEN, dm_segs->ds_len); 122089580Smsmith dm_segs++; 122189580Smsmith } 1222156139Sscottl gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_SG_RANZ, 122389580Smsmith nseg); 1224156139Sscottl gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_SDATA, 122589580Smsmith 0xffffffffUL); 122689580Smsmith 1227156139Sscottl gccb->gc_cmd_len = roundup(GDT_CMD_UNION + GDT_RAW_SG_LST + 122889580Smsmith nseg * GDT_SG_SZ, sizeof(u_int32_t)); 122989580Smsmith } 123089580Smsmith 123189580Smsmith if (nseg != 0) { 1232114001Sscottl bus_dmamap_sync(gdt->sc_buffer_dmat, gccb->gc_dmamap, 1233114001Sscottl (ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN ? 1234114001Sscottl BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); 123589580Smsmith } 123689580Smsmith 123789580Smsmith /* We must NOT abort the command here if CAM_REQ_INPROG is not set, 123889580Smsmith * because command semaphore is already set! 123989580Smsmith */ 124089580Smsmith 124189580Smsmith ccb->ccb_h.status |= CAM_SIM_QUEUED; 124289580Smsmith /* timeout handling */ 1243255871Sscottl gccb->gc_timeout_ch = 124489580Smsmith timeout(iir_timeout, (caddr_t)gccb, 124589580Smsmith (ccb->ccb_h.timeout * hz) / 1000); 124689580Smsmith 124789580Smsmith gdt->sc_copy_cmd(gdt, gccb); 124889580Smsmith splx(lock); 124989580Smsmith} 125089580Smsmith 125189580Smsmith 125289580Smsmithstatic void 125389580Smsmithiir_action( struct cam_sim *sim, union ccb *ccb ) 125489580Smsmith{ 125589580Smsmith struct gdt_softc *gdt; 125689580Smsmith int lock, bus, target, lun; 125789580Smsmith 125889580Smsmith gdt = (struct gdt_softc *)cam_sim_softc( sim ); 125989580Smsmith ccb->ccb_h.ccb_sim_ptr = sim; 126089580Smsmith bus = cam_sim_bus(sim); 126189580Smsmith target = ccb->ccb_h.target_id; 126289580Smsmith lun = ccb->ccb_h.target_lun; 126389580Smsmith GDT_DPRINTF(GDT_D_CMD, 126489580Smsmith ("iir_action(%p) func 0x%x cmd 0x%x bus %d target %d lun %d\n", 126589580Smsmith gdt, ccb->ccb_h.func_code, ccb->csio.cdb_io.cdb_bytes[0], 126689580Smsmith bus, target, lun)); 126789580Smsmith ++gdt_stat.io_count_act; 126889580Smsmith if (gdt_stat.io_count_act > gdt_stat.io_count_max) 126989580Smsmith gdt_stat.io_count_max = gdt_stat.io_count_act; 127089580Smsmith 127189580Smsmith switch (ccb->ccb_h.func_code) { 127289580Smsmith case XPT_SCSI_IO: 127389580Smsmith lock = splcam(); 127489580Smsmith TAILQ_INSERT_TAIL(&gdt->sc_ccb_queue, &ccb->ccb_h, sim_links.tqe); 127589580Smsmith ++gdt_stat.req_queue_act; 127689580Smsmith if (gdt_stat.req_queue_act > gdt_stat.req_queue_max) 127789580Smsmith gdt_stat.req_queue_max = gdt_stat.req_queue_act; 127889580Smsmith splx(lock); 127989580Smsmith gdt_next(gdt); 128089580Smsmith break; 128189580Smsmith case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */ 128289580Smsmith case XPT_ABORT: /* Abort the specified CCB */ 128389580Smsmith /* XXX Implement */ 128489580Smsmith ccb->ccb_h.status = CAM_REQ_INVALID; 128589580Smsmith --gdt_stat.io_count_act; 128689580Smsmith xpt_done(ccb); 128789580Smsmith break; 128889580Smsmith case XPT_SET_TRAN_SETTINGS: 128989580Smsmith ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 129089580Smsmith --gdt_stat.io_count_act; 129189580Smsmith xpt_done(ccb); 129289580Smsmith break; 129389580Smsmith case XPT_GET_TRAN_SETTINGS: 129489580Smsmith /* Get default/user set transfer settings for the target */ 129589580Smsmith { 1296163816Smjacob struct ccb_trans_settings *cts = &ccb->cts; 1297163816Smjacob struct ccb_trans_settings_scsi *scsi = &cts->proto_specific.scsi; 1298163816Smjacob struct ccb_trans_settings_spi *spi = &cts->xport_specific.spi; 1299163816Smjacob 1300163816Smjacob cts->protocol = PROTO_SCSI; 1301163816Smjacob cts->protocol_version = SCSI_REV_2; 1302163816Smjacob cts->transport = XPORT_SPI; 1303163816Smjacob cts->transport_version = 2; 1304163816Smjacob 1305163816Smjacob if (cts->type == CTS_TYPE_USER_SETTINGS) { 1306163816Smjacob spi->flags = CTS_SPI_FLAGS_DISC_ENB; 1307163816Smjacob scsi->flags = CTS_SCSI_FLAGS_TAG_ENB; 1308163816Smjacob spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT; 1309163816Smjacob spi->sync_period = 25; /* 10MHz */ 1310163816Smjacob if (spi->sync_period != 0) 1311163816Smjacob spi->sync_offset = 15; 1312163816Smjacob 1313163816Smjacob spi->valid = CTS_SPI_VALID_SYNC_RATE 1314163816Smjacob | CTS_SPI_VALID_SYNC_OFFSET 1315163816Smjacob | CTS_SPI_VALID_BUS_WIDTH 1316163816Smjacob | CTS_SPI_VALID_DISC; 1317163816Smjacob scsi->valid = CTS_SCSI_VALID_TQ; 1318163816Smjacob ccb->ccb_h.status = CAM_REQ_CMP; 1319163816Smjacob } else { 1320163816Smjacob ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 1321163816Smjacob } 132289580Smsmith --gdt_stat.io_count_act; 132389580Smsmith xpt_done(ccb); 132489580Smsmith break; 132589580Smsmith } 132689580Smsmith case XPT_CALC_GEOMETRY: 132789580Smsmith { 132889580Smsmith struct ccb_calc_geometry *ccg; 132989580Smsmith u_int32_t secs_per_cylinder; 133089580Smsmith 133189580Smsmith ccg = &ccb->ccg; 133289580Smsmith ccg->heads = gdt->sc_hdr[target].hd_heads; 133389580Smsmith ccg->secs_per_track = gdt->sc_hdr[target].hd_secs; 133489580Smsmith secs_per_cylinder = ccg->heads * ccg->secs_per_track; 133589580Smsmith ccg->cylinders = ccg->volume_size / secs_per_cylinder; 133689580Smsmith ccb->ccb_h.status = CAM_REQ_CMP; 133789580Smsmith --gdt_stat.io_count_act; 133889580Smsmith xpt_done(ccb); 133989580Smsmith break; 134089580Smsmith } 134189580Smsmith case XPT_RESET_BUS: /* Reset the specified SCSI bus */ 134289580Smsmith { 134389580Smsmith /* XXX Implement */ 134489580Smsmith ccb->ccb_h.status = CAM_REQ_CMP; 134589580Smsmith --gdt_stat.io_count_act; 134689580Smsmith xpt_done(ccb); 134789580Smsmith break; 134889580Smsmith } 134989580Smsmith case XPT_TERM_IO: /* Terminate the I/O process */ 135089580Smsmith /* XXX Implement */ 135189580Smsmith ccb->ccb_h.status = CAM_REQ_INVALID; 135289580Smsmith --gdt_stat.io_count_act; 135389580Smsmith xpt_done(ccb); 135489580Smsmith break; 135589580Smsmith case XPT_PATH_INQ: /* Path routing inquiry */ 135689580Smsmith { 135789580Smsmith struct ccb_pathinq *cpi = &ccb->cpi; 135889580Smsmith 135989580Smsmith cpi->version_num = 1; 136089580Smsmith cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE; 136189580Smsmith cpi->hba_inquiry |= PI_WIDE_16; 136289580Smsmith cpi->target_sprt = 1; 136389580Smsmith cpi->hba_misc = 0; 136489580Smsmith cpi->hba_eng_cnt = 0; 136589580Smsmith if (bus == gdt->sc_virt_bus) 136689580Smsmith cpi->max_target = GDT_MAX_HDRIVES - 1; 136789580Smsmith else if (gdt->sc_class & GDT_FC) 136889580Smsmith cpi->max_target = GDT_MAXID_FC - 1; 136989580Smsmith else 137089580Smsmith cpi->max_target = GDT_MAXID - 1; 137189580Smsmith cpi->max_lun = 7; 137289580Smsmith cpi->unit_number = cam_sim_unit(sim); 137389580Smsmith cpi->bus_id = bus; 137489580Smsmith cpi->initiator_id = 137589580Smsmith (bus == gdt->sc_virt_bus ? 127 : gdt->sc_bus_id[bus]); 137689580Smsmith cpi->base_transfer_speed = 3300; 137789580Smsmith strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 1378254379Sjkim if (gdt->sc_vendor == INTEL_VENDOR_ID_IIR) 1379120477Sscottl strncpy(cpi->hba_vid, "Intel Corp.", HBA_IDLEN); 1380120477Sscottl else 1381120477Sscottl strncpy(cpi->hba_vid, "ICP vortex ", HBA_IDLEN); 138289580Smsmith strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 1383163816Smjacob cpi->transport = XPORT_SPI; 1384163816Smjacob cpi->transport_version = 2; 1385163816Smjacob cpi->protocol = PROTO_SCSI; 1386163816Smjacob cpi->protocol_version = SCSI_REV_2; 138789580Smsmith cpi->ccb_h.status = CAM_REQ_CMP; 138889580Smsmith --gdt_stat.io_count_act; 138989580Smsmith xpt_done(ccb); 139089580Smsmith break; 139189580Smsmith } 139289580Smsmith default: 139389580Smsmith GDT_DPRINTF(GDT_D_INVALID, ("gdt_next(%p) cmd 0x%x invalid\n", 139489580Smsmith gdt, ccb->ccb_h.func_code)); 139589580Smsmith ccb->ccb_h.status = CAM_REQ_INVALID; 139689580Smsmith --gdt_stat.io_count_act; 139789580Smsmith xpt_done(ccb); 139889580Smsmith break; 139989580Smsmith } 140089580Smsmith} 140189580Smsmith 140289580Smsmithstatic void 140389580Smsmithiir_poll( struct cam_sim *sim ) 140489580Smsmith{ 140589580Smsmith struct gdt_softc *gdt; 140689580Smsmith 140789580Smsmith gdt = (struct gdt_softc *)cam_sim_softc( sim ); 140889580Smsmith GDT_DPRINTF(GDT_D_CMD, ("iir_poll sim %p gdt %p\n", sim, gdt)); 140989580Smsmith iir_intr(gdt); 141089580Smsmith} 141189580Smsmith 141289580Smsmithstatic void 141389580Smsmithiir_timeout(void *arg) 141489580Smsmith{ 1415156139Sscottl GDT_DPRINTF(GDT_D_TIMEOUT, ("iir_timeout(%p)\n", gccb)); 141689580Smsmith} 141789580Smsmith 141889580Smsmithstatic void 141989580Smsmithiir_shutdown( void *arg, int howto ) 142089580Smsmith{ 142189580Smsmith struct gdt_softc *gdt; 142289580Smsmith struct gdt_ccb *gccb; 142389580Smsmith gdt_ucmd_t *ucmd; 142489580Smsmith int lock, i; 142589580Smsmith 142689580Smsmith gdt = (struct gdt_softc *)arg; 142789580Smsmith GDT_DPRINTF(GDT_D_CMD, ("iir_shutdown(%p, %d)\n", gdt, howto)); 142889580Smsmith 142989580Smsmith printf("iir%d: Flushing all Host Drives. Please wait ... ", 143089580Smsmith gdt->sc_hanum); 143189580Smsmith 143289580Smsmith /* allocate ucmd buffer */ 1433156139Sscottl ucmd = malloc(sizeof(gdt_ucmd_t), M_GDTBUF, M_NOWAIT); 143489580Smsmith if (ucmd == NULL) { 143589580Smsmith printf("iir%d: iir_shutdown(): Cannot allocate resource\n", 143689580Smsmith gdt->sc_hanum); 143789580Smsmith return; 143889580Smsmith } 143989580Smsmith bzero(ucmd, sizeof(gdt_ucmd_t)); 144089580Smsmith 144189580Smsmith /* wait for pending IOs */ 144289580Smsmith lock = splcam(); 144389580Smsmith gdt->sc_state = GDT_SHUTDOWN; 144489580Smsmith splx(lock); 144589580Smsmith if ((gccb = SLIST_FIRST(&gdt->sc_pending_gccb)) != NULL) 144689580Smsmith (void) tsleep((void *)gccb, PCATCH | PRIBIO, "iirshw", 100 * hz); 144789580Smsmith 144889580Smsmith /* flush */ 144989580Smsmith for (i = 0; i < GDT_MAX_HDRIVES; ++i) { 145089580Smsmith if (gdt->sc_hdr[i].hd_present) { 145189580Smsmith ucmd->service = GDT_CACHESERVICE; 145289580Smsmith ucmd->OpCode = GDT_FLUSH; 145389580Smsmith ucmd->u.cache.DeviceNo = i; 145489580Smsmith lock = splcam(); 145589580Smsmith TAILQ_INSERT_TAIL(&gdt->sc_ucmd_queue, ucmd, links); 145689580Smsmith ucmd->complete_flag = FALSE; 145789580Smsmith splx(lock); 145889580Smsmith gdt_next(gdt); 145989580Smsmith if (!ucmd->complete_flag) 146089580Smsmith (void) tsleep((void *)ucmd, PCATCH|PRIBIO, "iirshw", 10*hz); 146189580Smsmith } 146289580Smsmith } 146389580Smsmith 146489580Smsmith free(ucmd, M_DEVBUF); 146589580Smsmith printf("Done.\n"); 146689580Smsmith} 146789580Smsmith 146889580Smsmithvoid 146989580Smsmithiir_intr(void *arg) 147089580Smsmith{ 147189580Smsmith struct gdt_softc *gdt = arg; 147289580Smsmith struct gdt_intr_ctx ctx; 147389580Smsmith int lock = 0; 147489580Smsmith struct gdt_ccb *gccb; 147589580Smsmith gdt_ucmd_t *ucmd; 147689580Smsmith u_int32_t cnt; 147789580Smsmith 147889580Smsmith GDT_DPRINTF(GDT_D_INTR, ("gdt_intr(%p)\n", gdt)); 147989580Smsmith 148089580Smsmith /* If polling and we were not called from gdt_wait, just return */ 148189580Smsmith if ((gdt->sc_state & GDT_POLLING) && 148289580Smsmith !(gdt->sc_state & GDT_POLL_WAIT)) 148389580Smsmith return; 148489580Smsmith 148589580Smsmith if (!(gdt->sc_state & GDT_POLLING)) 148689580Smsmith lock = splcam(); 148789580Smsmith gdt_wait_index = 0; 148889580Smsmith 148989580Smsmith ctx.istatus = gdt->sc_get_status(gdt); 1490156139Sscottl if (ctx.istatus == 0x00) { 149189580Smsmith if (!(gdt->sc_state & GDT_POLLING)) 149289580Smsmith splx(lock); 149389580Smsmith gdt->sc_status = GDT_S_NO_STATUS; 149489580Smsmith return; 149589580Smsmith } 149689580Smsmith 149789580Smsmith gdt->sc_intr(gdt, &ctx); 149889580Smsmith 149989580Smsmith gdt->sc_status = ctx.cmd_status; 150089580Smsmith gdt->sc_service = ctx.service; 150189580Smsmith gdt->sc_info = ctx.info; 150289580Smsmith gdt->sc_info2 = ctx.info2; 150389580Smsmith 150489580Smsmith if (gdt->sc_state & GDT_POLL_WAIT) { 150589580Smsmith gdt_wait_gdt = gdt; 150689580Smsmith gdt_wait_index = ctx.istatus; 150789580Smsmith } 150889580Smsmith 150989580Smsmith if (ctx.istatus == GDT_ASYNCINDEX) { 151089580Smsmith gdt_async_event(gdt, ctx.service); 151189580Smsmith if (!(gdt->sc_state & GDT_POLLING)) 151289580Smsmith splx(lock); 151389580Smsmith return; 151489580Smsmith } 151589580Smsmith if (ctx.istatus == GDT_SPEZINDEX) { 151689580Smsmith GDT_DPRINTF(GDT_D_INVALID, 151789580Smsmith ("iir%d: Service unknown or not initialized!\n", 151889580Smsmith gdt->sc_hanum)); 151989580Smsmith gdt->sc_dvr.size = sizeof(gdt->sc_dvr.eu.driver); 152089580Smsmith gdt->sc_dvr.eu.driver.ionode = gdt->sc_hanum; 152189580Smsmith gdt_store_event(GDT_ES_DRIVER, 4, &gdt->sc_dvr); 152289580Smsmith if (!(gdt->sc_state & GDT_POLLING)) 152389580Smsmith splx(lock); 152489580Smsmith return; 152589580Smsmith } 152689580Smsmith 152789580Smsmith gccb = &gdt->sc_gccbs[ctx.istatus - 2]; 152889580Smsmith ctx.service = gccb->gc_service; 152989580Smsmith 153089580Smsmith switch (gccb->gc_flags) { 153189580Smsmith case GDT_GCF_UNUSED: 153289580Smsmith GDT_DPRINTF(GDT_D_INVALID, ("iir%d: Index (%d) to unused command!\n", 153389580Smsmith gdt->sc_hanum, ctx.istatus)); 153489580Smsmith gdt->sc_dvr.size = sizeof(gdt->sc_dvr.eu.driver); 153589580Smsmith gdt->sc_dvr.eu.driver.ionode = gdt->sc_hanum; 153689580Smsmith gdt->sc_dvr.eu.driver.index = ctx.istatus; 153789580Smsmith gdt_store_event(GDT_ES_DRIVER, 1, &gdt->sc_dvr); 153889580Smsmith gdt_free_ccb(gdt, gccb); 153989580Smsmith /* fallthrough */ 154089580Smsmith 154189580Smsmith case GDT_GCF_INTERNAL: 154289580Smsmith if (!(gdt->sc_state & GDT_POLLING)) 154389580Smsmith splx(lock); 154489580Smsmith break; 154589580Smsmith 154689580Smsmith case GDT_GCF_IOCTL: 154789580Smsmith ucmd = gccb->gc_ucmd; 154889580Smsmith if (gdt->sc_status == GDT_S_BSY) { 154989580Smsmith GDT_DPRINTF(GDT_D_DEBUG, ("iir_intr(%p) ioctl: gccb %p busy\n", 155089580Smsmith gdt, gccb)); 155189580Smsmith TAILQ_INSERT_HEAD(&gdt->sc_ucmd_queue, ucmd, links); 155289580Smsmith if (!(gdt->sc_state & GDT_POLLING)) 155389580Smsmith splx(lock); 155489580Smsmith } else { 155589580Smsmith ucmd->status = gdt->sc_status; 155689580Smsmith ucmd->info = gdt->sc_info; 155789580Smsmith ucmd->complete_flag = TRUE; 155889580Smsmith if (ucmd->service == GDT_CACHESERVICE) { 155989580Smsmith if (ucmd->OpCode == GDT_IOCTL) { 156089580Smsmith cnt = ucmd->u.ioctl.param_size; 156189580Smsmith if (cnt != 0) 156289580Smsmith bcopy(gccb->gc_scratch, ucmd->data, cnt); 156389580Smsmith } else { 156489580Smsmith cnt = ucmd->u.cache.BlockCnt * GDT_SECTOR_SIZE; 156589580Smsmith if (cnt != 0) 156689580Smsmith bcopy(gccb->gc_scratch, ucmd->data, cnt); 156789580Smsmith } 156889580Smsmith } else { 156989580Smsmith cnt = ucmd->u.raw.sdlen; 157089580Smsmith if (cnt != 0) 157189580Smsmith bcopy(gccb->gc_scratch, ucmd->data, cnt); 157289580Smsmith if (ucmd->u.raw.sense_len != 0) 157389580Smsmith bcopy(gccb->gc_scratch, ucmd->data, cnt); 157489580Smsmith } 157589580Smsmith gdt_free_ccb(gdt, gccb); 157689580Smsmith if (!(gdt->sc_state & GDT_POLLING)) 157789580Smsmith splx(lock); 157889580Smsmith /* wakeup */ 157989580Smsmith wakeup(ucmd); 158089580Smsmith } 158189580Smsmith gdt_next(gdt); 158289580Smsmith break; 158389580Smsmith 158489580Smsmith default: 158589580Smsmith gdt_free_ccb(gdt, gccb); 158689580Smsmith gdt_sync_event(gdt, ctx.service, ctx.istatus, gccb); 158789580Smsmith if (!(gdt->sc_state & GDT_POLLING)) 158889580Smsmith splx(lock); 158989580Smsmith gdt_next(gdt); 159089580Smsmith break; 159189580Smsmith } 159289580Smsmith} 159389580Smsmith 1594114001Sscottlint 159589580Smsmithgdt_async_event(struct gdt_softc *gdt, int service) 159689580Smsmith{ 159789580Smsmith struct gdt_ccb *gccb; 159889580Smsmith 159989580Smsmith GDT_DPRINTF(GDT_D_INTR, ("gdt_async_event(%p, %d)\n", gdt, service)); 160089580Smsmith 160189580Smsmith if (service == GDT_SCREENSERVICE) { 160289580Smsmith if (gdt->sc_status == GDT_MSG_REQUEST) { 160389580Smsmith while (gdt->sc_test_busy(gdt)) 160489580Smsmith DELAY(1); 160589580Smsmith gccb = gdt_get_ccb(gdt); 160689580Smsmith if (gccb == NULL) { 160789580Smsmith printf("iir%d: No free command index found\n", 160889580Smsmith gdt->sc_hanum); 160989580Smsmith return (1); 161089580Smsmith } 1611156139Sscottl bzero(gccb->gc_cmd, GDT_CMD_SZ); 161289580Smsmith gccb->gc_service = service; 161389580Smsmith gccb->gc_flags = GDT_GCF_SCREEN; 1614156139Sscottl gdt_enc32(gccb->gc_cmd + GDT_CMD_COMMANDINDEX, 161589580Smsmith gccb->gc_cmd_index); 1616156139Sscottl gdt_enc16(gccb->gc_cmd + GDT_CMD_OPCODE, GDT_READ); 1617156139Sscottl gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_SCREEN_MSG_HANDLE, 161889580Smsmith GDT_MSG_INV_HANDLE); 1619156139Sscottl gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_SCREEN_MSG_ADDR, 1620156139Sscottl gccb->gc_scratch_busbase); 1621156139Sscottl gdt->sc_set_sema0(gdt); 162289580Smsmith gdt->sc_cmd_off = 0; 1623156139Sscottl gccb->gc_cmd_len = roundup(GDT_CMD_UNION + GDT_SCREEN_SZ, 162489580Smsmith sizeof(u_int32_t)); 162589580Smsmith gdt->sc_cmd_cnt = 0; 162689580Smsmith gdt->sc_copy_cmd(gdt, gccb); 162789580Smsmith printf("iir%d: [PCI %d/%d] ", 162889580Smsmith gdt->sc_hanum,gdt->sc_bus,gdt->sc_slot); 162989580Smsmith gdt->sc_release_event(gdt); 163089580Smsmith } 163189580Smsmith 163289580Smsmith } else { 163389580Smsmith if ((gdt->sc_fw_vers & 0xff) >= 0x1a) { 163489580Smsmith gdt->sc_dvr.size = 0; 163589580Smsmith gdt->sc_dvr.eu.async.ionode = gdt->sc_hanum; 163689580Smsmith gdt->sc_dvr.eu.async.status = gdt->sc_status; 163789580Smsmith /* severity and event_string already set! */ 163889580Smsmith } else { 163989580Smsmith gdt->sc_dvr.size = sizeof(gdt->sc_dvr.eu.async); 164089580Smsmith gdt->sc_dvr.eu.async.ionode = gdt->sc_hanum; 164189580Smsmith gdt->sc_dvr.eu.async.service = service; 164289580Smsmith gdt->sc_dvr.eu.async.status = gdt->sc_status; 164389580Smsmith gdt->sc_dvr.eu.async.info = gdt->sc_info; 164489580Smsmith *(u_int32_t *)gdt->sc_dvr.eu.async.scsi_coord = gdt->sc_info2; 164589580Smsmith } 164689580Smsmith gdt_store_event(GDT_ES_ASYNC, service, &gdt->sc_dvr); 164789580Smsmith printf("iir%d: %s\n", gdt->sc_hanum, gdt->sc_dvr.event_string); 164889580Smsmith } 164989580Smsmith 165089580Smsmith return (0); 165189580Smsmith} 165289580Smsmith 1653114001Sscottlint 165489580Smsmithgdt_sync_event(struct gdt_softc *gdt, int service, 165589580Smsmith u_int8_t index, struct gdt_ccb *gccb) 165689580Smsmith{ 165789580Smsmith union ccb *ccb; 165889580Smsmith 165989580Smsmith GDT_DPRINTF(GDT_D_INTR, 166089580Smsmith ("gdt_sync_event(%p, %d, %d, %p)\n", gdt,service,index,gccb)); 166189580Smsmith 166289580Smsmith ccb = gccb->gc_ccb; 166389580Smsmith 166489580Smsmith if (service == GDT_SCREENSERVICE) { 166589580Smsmith u_int32_t msg_len; 166689580Smsmith 166789580Smsmith msg_len = gdt_dec32(gccb->gc_scratch + GDT_SCR_MSG_LEN); 166889580Smsmith if (msg_len) 166989580Smsmith if (!(gccb->gc_scratch[GDT_SCR_MSG_ANSWER] && 167089580Smsmith gccb->gc_scratch[GDT_SCR_MSG_EXT])) { 167189580Smsmith gccb->gc_scratch[GDT_SCR_MSG_TEXT + msg_len] = '\0'; 167289580Smsmith printf("%s",&gccb->gc_scratch[GDT_SCR_MSG_TEXT]); 167389580Smsmith } 167489580Smsmith 167589580Smsmith if (gccb->gc_scratch[GDT_SCR_MSG_EXT] && 167689580Smsmith !gccb->gc_scratch[GDT_SCR_MSG_ANSWER]) { 167789580Smsmith while (gdt->sc_test_busy(gdt)) 167889580Smsmith DELAY(1); 1679156139Sscottl bzero(gccb->gc_cmd, GDT_CMD_SZ); 168089580Smsmith gccb = gdt_get_ccb(gdt); 168189580Smsmith if (gccb == NULL) { 168289580Smsmith printf("iir%d: No free command index found\n", 168389580Smsmith gdt->sc_hanum); 168489580Smsmith return (1); 168589580Smsmith } 168689580Smsmith gccb->gc_service = service; 168789580Smsmith gccb->gc_flags = GDT_GCF_SCREEN; 1688156139Sscottl gdt_enc32(gccb->gc_cmd + GDT_CMD_COMMANDINDEX, 168989580Smsmith gccb->gc_cmd_index); 1690156139Sscottl gdt_enc16(gccb->gc_cmd + GDT_CMD_OPCODE, GDT_READ); 1691156139Sscottl gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_SCREEN_MSG_HANDLE, 169289580Smsmith gccb->gc_scratch[GDT_SCR_MSG_HANDLE]); 1693156139Sscottl gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_SCREEN_MSG_ADDR, 1694156139Sscottl gccb->gc_scratch_busbase); 1695156139Sscottl gdt->sc_set_sema0(gdt); 169689580Smsmith gdt->sc_cmd_off = 0; 1697156139Sscottl gccb->gc_cmd_len = roundup(GDT_CMD_UNION + GDT_SCREEN_SZ, 169889580Smsmith sizeof(u_int32_t)); 169989580Smsmith gdt->sc_cmd_cnt = 0; 170089580Smsmith gdt->sc_copy_cmd(gdt, gccb); 170189580Smsmith gdt->sc_release_event(gdt); 170289580Smsmith return (0); 170389580Smsmith } 170489580Smsmith 170589580Smsmith if (gccb->gc_scratch[GDT_SCR_MSG_ANSWER] && 170689580Smsmith gdt_dec32(gccb->gc_scratch + GDT_SCR_MSG_ALEN)) { 170789580Smsmith /* default answers (getchar() not possible) */ 170889580Smsmith if (gdt_dec32(gccb->gc_scratch + GDT_SCR_MSG_ALEN) == 1) { 170989580Smsmith gdt_enc32(gccb->gc_scratch + GDT_SCR_MSG_ALEN, 0); 171089580Smsmith gdt_enc32(gccb->gc_scratch + GDT_SCR_MSG_LEN, 1); 171189580Smsmith gccb->gc_scratch[GDT_SCR_MSG_TEXT] = 0; 171289580Smsmith } else { 171389580Smsmith gdt_enc32(gccb->gc_scratch + GDT_SCR_MSG_ALEN, 171489580Smsmith gdt_dec32(gccb->gc_scratch + GDT_SCR_MSG_ALEN) - 2); 171589580Smsmith gdt_enc32(gccb->gc_scratch + GDT_SCR_MSG_LEN, 2); 171689580Smsmith gccb->gc_scratch[GDT_SCR_MSG_TEXT] = 1; 171789580Smsmith gccb->gc_scratch[GDT_SCR_MSG_TEXT + 1] = 0; 171889580Smsmith } 171989580Smsmith gccb->gc_scratch[GDT_SCR_MSG_EXT] = 0; 172089580Smsmith gccb->gc_scratch[GDT_SCR_MSG_ANSWER] = 0; 172189580Smsmith while (gdt->sc_test_busy(gdt)) 172289580Smsmith DELAY(1); 1723156139Sscottl bzero(gccb->gc_cmd, GDT_CMD_SZ); 172489580Smsmith gccb = gdt_get_ccb(gdt); 172589580Smsmith if (gccb == NULL) { 172689580Smsmith printf("iir%d: No free command index found\n", 172789580Smsmith gdt->sc_hanum); 172889580Smsmith return (1); 172989580Smsmith } 173089580Smsmith gccb->gc_service = service; 173189580Smsmith gccb->gc_flags = GDT_GCF_SCREEN; 1732156139Sscottl gdt_enc32(gccb->gc_cmd + GDT_CMD_COMMANDINDEX, 173389580Smsmith gccb->gc_cmd_index); 1734156139Sscottl gdt_enc16(gccb->gc_cmd + GDT_CMD_OPCODE, GDT_WRITE); 1735156139Sscottl gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_SCREEN_MSG_HANDLE, 173689580Smsmith gccb->gc_scratch[GDT_SCR_MSG_HANDLE]); 1737156139Sscottl gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_SCREEN_MSG_ADDR, 1738156139Sscottl gccb->gc_scratch_busbase); 1739156139Sscottl gdt->sc_set_sema0(gdt); 174089580Smsmith gdt->sc_cmd_off = 0; 1741156139Sscottl gccb->gc_cmd_len = roundup(GDT_CMD_UNION + GDT_SCREEN_SZ, 174289580Smsmith sizeof(u_int32_t)); 174389580Smsmith gdt->sc_cmd_cnt = 0; 174489580Smsmith gdt->sc_copy_cmd(gdt, gccb); 174589580Smsmith gdt->sc_release_event(gdt); 174689580Smsmith return (0); 174789580Smsmith } 174889580Smsmith printf("\n"); 174989580Smsmith return (0); 175089580Smsmith } else { 1751255871Sscottl untimeout(iir_timeout, gccb, gccb->gc_timeout_ch); 175289580Smsmith if (gdt->sc_status == GDT_S_BSY) { 175389580Smsmith GDT_DPRINTF(GDT_D_DEBUG, ("gdt_sync_event(%p) gccb %p busy\n", 175489580Smsmith gdt, gccb)); 175589580Smsmith TAILQ_INSERT_HEAD(&gdt->sc_ccb_queue, &ccb->ccb_h, sim_links.tqe); 175689580Smsmith ++gdt_stat.req_queue_act; 175789580Smsmith if (gdt_stat.req_queue_act > gdt_stat.req_queue_max) 175889580Smsmith gdt_stat.req_queue_max = gdt_stat.req_queue_act; 175989580Smsmith return (2); 176089580Smsmith } 176189580Smsmith 1762114001Sscottl bus_dmamap_sync(gdt->sc_buffer_dmat, gccb->gc_dmamap, 1763114001Sscottl (ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN ? 1764114001Sscottl BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); 1765156139Sscottl bus_dmamap_unload(gdt->sc_buffer_dmat, gccb->gc_dmamap); 176689580Smsmith 176789580Smsmith ccb->csio.resid = 0; 176889580Smsmith if (gdt->sc_status == GDT_S_OK) { 1769156139Sscottl ccb->ccb_h.status |= CAM_REQ_CMP; 1770156139Sscottl ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 177189580Smsmith } else { 177289580Smsmith /* error */ 177389580Smsmith if (gccb->gc_service == GDT_CACHESERVICE) { 1774225950Sken struct scsi_sense_data *sense; 1775225950Sken 1776156139Sscottl ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR | CAM_AUTOSNS_VALID; 1777156139Sscottl ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 177889580Smsmith ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND; 177989580Smsmith bzero(&ccb->csio.sense_data, ccb->csio.sense_len); 1780225950Sken sense = &ccb->csio.sense_data; 1781225950Sken scsi_set_sense_data(sense, 1782225950Sken /*sense_format*/ SSD_TYPE_NONE, 1783225950Sken /*current_error*/ 1, 1784225950Sken /*sense_key*/ SSD_KEY_NOT_READY, 1785225950Sken /*asc*/ 0x4, 1786225950Sken /*ascq*/ 0x01, 1787225950Sken SSD_ELEM_NONE); 178889580Smsmith 178989580Smsmith gdt->sc_dvr.size = sizeof(gdt->sc_dvr.eu.sync); 179089580Smsmith gdt->sc_dvr.eu.sync.ionode = gdt->sc_hanum; 179189580Smsmith gdt->sc_dvr.eu.sync.service = service; 179289580Smsmith gdt->sc_dvr.eu.sync.status = gdt->sc_status; 179389580Smsmith gdt->sc_dvr.eu.sync.info = gdt->sc_info; 179489580Smsmith gdt->sc_dvr.eu.sync.hostdrive = ccb->ccb_h.target_id; 179589580Smsmith if (gdt->sc_status >= 0x8000) 179689580Smsmith gdt_store_event(GDT_ES_SYNC, 0, &gdt->sc_dvr); 179789580Smsmith else 179889580Smsmith gdt_store_event(GDT_ES_SYNC, service, &gdt->sc_dvr); 179989580Smsmith } else { 180089580Smsmith /* raw service */ 180189580Smsmith if (gdt->sc_status != GDT_S_RAW_SCSI || gdt->sc_info >= 0x100) { 1802114001Sscottl ccb->ccb_h.status = CAM_DEV_NOT_THERE; 180389580Smsmith } else { 1804156139Sscottl ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR|CAM_AUTOSNS_VALID; 1805156139Sscottl ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 180689580Smsmith ccb->csio.scsi_status = gdt->sc_info; 180789580Smsmith bcopy(gccb->gc_scratch, &ccb->csio.sense_data, 180889580Smsmith ccb->csio.sense_len); 180989580Smsmith } 181089580Smsmith } 181189580Smsmith } 181289580Smsmith --gdt_stat.io_count_act; 181389580Smsmith xpt_done(ccb); 181489580Smsmith } 181589580Smsmith return (0); 181689580Smsmith} 181789580Smsmith 181889580Smsmith/* Controller event handling functions */ 181989580Smsmithgdt_evt_str *gdt_store_event(u_int16_t source, u_int16_t idx, 182089580Smsmith gdt_evt_data *evt) 182189580Smsmith{ 182289580Smsmith gdt_evt_str *e; 182389580Smsmith struct timeval tv; 182489580Smsmith 182589580Smsmith GDT_DPRINTF(GDT_D_MISC, ("gdt_store_event(%d, %d)\n", source, idx)); 182689580Smsmith if (source == 0) /* no source -> no event */ 182789580Smsmith return 0; 182889580Smsmith 182989580Smsmith if (ebuffer[elastidx].event_source == source && 183089580Smsmith ebuffer[elastidx].event_idx == idx && 183189580Smsmith ((evt->size != 0 && ebuffer[elastidx].event_data.size != 0 && 183289580Smsmith !memcmp((char *)&ebuffer[elastidx].event_data.eu, 183389580Smsmith (char *)&evt->eu, evt->size)) || 183489580Smsmith (evt->size == 0 && ebuffer[elastidx].event_data.size == 0 && 183589580Smsmith !strcmp((char *)&ebuffer[elastidx].event_data.event_string, 183689580Smsmith (char *)&evt->event_string)))) { 183789580Smsmith e = &ebuffer[elastidx]; 183889580Smsmith getmicrotime(&tv); 183989580Smsmith e->last_stamp = tv.tv_sec; 184089580Smsmith ++e->same_count; 184189580Smsmith } else { 184289580Smsmith if (ebuffer[elastidx].event_source != 0) { /* entry not free ? */ 184389580Smsmith ++elastidx; 184489580Smsmith if (elastidx == GDT_MAX_EVENTS) 184589580Smsmith elastidx = 0; 184689580Smsmith if (elastidx == eoldidx) { /* reached mark ? */ 184789580Smsmith ++eoldidx; 184889580Smsmith if (eoldidx == GDT_MAX_EVENTS) 184989580Smsmith eoldidx = 0; 185089580Smsmith } 185189580Smsmith } 185289580Smsmith e = &ebuffer[elastidx]; 185389580Smsmith e->event_source = source; 185489580Smsmith e->event_idx = idx; 185589580Smsmith getmicrotime(&tv); 185689580Smsmith e->first_stamp = e->last_stamp = tv.tv_sec; 185789580Smsmith e->same_count = 1; 185889580Smsmith e->event_data = *evt; 185989580Smsmith e->application = 0; 186089580Smsmith } 186189580Smsmith return e; 186289580Smsmith} 186389580Smsmith 186489580Smsmithint gdt_read_event(int handle, gdt_evt_str *estr) 186589580Smsmith{ 186689580Smsmith gdt_evt_str *e; 186789580Smsmith int eindex, lock; 186889580Smsmith 186989580Smsmith GDT_DPRINTF(GDT_D_MISC, ("gdt_read_event(%d)\n", handle)); 187089580Smsmith lock = splcam(); 187189580Smsmith if (handle == -1) 187289580Smsmith eindex = eoldidx; 187389580Smsmith else 187489580Smsmith eindex = handle; 187589580Smsmith estr->event_source = 0; 187689580Smsmith 187789580Smsmith if (eindex >= GDT_MAX_EVENTS) { 187889580Smsmith splx(lock); 187989580Smsmith return eindex; 188089580Smsmith } 188189580Smsmith e = &ebuffer[eindex]; 188289580Smsmith if (e->event_source != 0) { 188389580Smsmith if (eindex != elastidx) { 188489580Smsmith if (++eindex == GDT_MAX_EVENTS) 188589580Smsmith eindex = 0; 188689580Smsmith } else { 188789580Smsmith eindex = -1; 188889580Smsmith } 188989580Smsmith memcpy(estr, e, sizeof(gdt_evt_str)); 189089580Smsmith } 189189580Smsmith splx(lock); 189289580Smsmith return eindex; 189389580Smsmith} 189489580Smsmith 189589580Smsmithvoid gdt_readapp_event(u_int8_t application, gdt_evt_str *estr) 189689580Smsmith{ 189789580Smsmith gdt_evt_str *e; 189889580Smsmith int found = FALSE; 189989580Smsmith int eindex, lock; 190089580Smsmith 190189580Smsmith GDT_DPRINTF(GDT_D_MISC, ("gdt_readapp_event(%d)\n", application)); 190289580Smsmith lock = splcam(); 190389580Smsmith eindex = eoldidx; 190489580Smsmith for (;;) { 190589580Smsmith e = &ebuffer[eindex]; 190689580Smsmith if (e->event_source == 0) 190789580Smsmith break; 190889580Smsmith if ((e->application & application) == 0) { 190989580Smsmith e->application |= application; 191089580Smsmith found = TRUE; 191189580Smsmith break; 191289580Smsmith } 191389580Smsmith if (eindex == elastidx) 191489580Smsmith break; 191589580Smsmith if (++eindex == GDT_MAX_EVENTS) 191689580Smsmith eindex = 0; 191789580Smsmith } 191889580Smsmith if (found) 191989580Smsmith memcpy(estr, e, sizeof(gdt_evt_str)); 192089580Smsmith else 192189580Smsmith estr->event_source = 0; 192289580Smsmith splx(lock); 192389580Smsmith} 192489580Smsmith 192589580Smsmithvoid gdt_clear_events() 192689580Smsmith{ 192789580Smsmith GDT_DPRINTF(GDT_D_MISC, ("gdt_clear_events\n")); 192889580Smsmith 192989580Smsmith eoldidx = elastidx = 0; 193089580Smsmith ebuffer[0].event_source = 0; 193189580Smsmith} 1932