amr.c revision 143121
151974Smsmith/*- 265245Smsmith * Copyright (c) 1999,2000 Michael Smith 365245Smsmith * Copyright (c) 2000 BSDi 4140687Sscottl * Copyright (c) 2005 Scott Long 551974Smsmith * All rights reserved. 651974Smsmith * 751974Smsmith * Redistribution and use in source and binary forms, with or without 851974Smsmith * modification, are permitted provided that the following conditions 951974Smsmith * are met: 1051974Smsmith * 1. Redistributions of source code must retain the above copyright 1151974Smsmith * notice, this list of conditions and the following disclaimer. 1251974Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1351974Smsmith * notice, this list of conditions and the following disclaimer in the 1451974Smsmith * documentation and/or other materials provided with the distribution. 1551974Smsmith * 1651974Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1751974Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1851974Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1951974Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2051974Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2151974Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2251974Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2351974Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2451974Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2551974Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2651974Smsmith * SUCH DAMAGE. 27119418Sobrien */ 28139749Simp/*- 29106225Semoore * Copyright (c) 2002 Eric Moore 30140688Sscottl * Copyright (c) 2002, 2004 LSI Logic Corporation 31106225Semoore * All rights reserved. 32106225Semoore * 33106225Semoore * Redistribution and use in source and binary forms, with or without 34106225Semoore * modification, are permitted provided that the following conditions 35106225Semoore * are met: 36106225Semoore * 1. Redistributions of source code must retain the above copyright 37106225Semoore * notice, this list of conditions and the following disclaimer. 38106225Semoore * 2. Redistributions in binary form must reproduce the above copyright 39106225Semoore * notice, this list of conditions and the following disclaimer in the 40106225Semoore * documentation and/or other materials provided with the distribution. 41105419Semoore * 3. The party using or redistributing the source code and binary forms 42106225Semoore * agrees to the disclaimer below and the terms and conditions set forth 43105419Semoore * herein. 44105419Semoore * 45106225Semoore * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 46106225Semoore * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 47106225Semoore * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 48106225Semoore * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 49106225Semoore * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 50106225Semoore * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 51106225Semoore * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 52106225Semoore * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 53106225Semoore * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 54106225Semoore * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 55106225Semoore * SUCH DAMAGE. 5651974Smsmith */ 5751974Smsmith 58119418Sobrien#include <sys/cdefs.h> 59119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/amr/amr.c 143121 2005-03-04 06:11:00Z scottl $"); 60119418Sobrien 6151974Smsmith/* 6265245Smsmith * Driver for the AMI MegaRaid family of controllers. 6351974Smsmith */ 6451974Smsmith 6551974Smsmith#include <sys/param.h> 6651974Smsmith#include <sys/systm.h> 6751974Smsmith#include <sys/malloc.h> 6851974Smsmith#include <sys/kernel.h> 6951974Smsmith 7065245Smsmith#include <dev/amr/amr_compat.h> 7151974Smsmith#include <sys/bus.h> 7251974Smsmith#include <sys/conf.h> 7365245Smsmith#include <sys/stat.h> 7451974Smsmith 7565245Smsmith#include <machine/bus_memio.h> 7665245Smsmith#include <machine/bus_pio.h> 7765245Smsmith#include <machine/bus.h> 7851974Smsmith#include <machine/resource.h> 7951974Smsmith#include <sys/rman.h> 8051974Smsmith 81119277Simp#include <dev/pci/pcireg.h> 82119277Simp#include <dev/pci/pcivar.h> 8365245Smsmith 8451974Smsmith#include <dev/amr/amrio.h> 8551974Smsmith#include <dev/amr/amrreg.h> 8651974Smsmith#include <dev/amr/amrvar.h> 8765245Smsmith#define AMR_DEFINE_TABLES 8865245Smsmith#include <dev/amr/amr_tables.h> 8951974Smsmith 9065245Smsmithstatic d_open_t amr_open; 9165245Smsmithstatic d_close_t amr_close; 9265245Smsmithstatic d_ioctl_t amr_ioctl; 9365245Smsmith 9451974Smsmithstatic struct cdevsw amr_cdevsw = { 95126080Sphk .d_version = D_VERSION, 96126080Sphk .d_flags = D_NEEDGIANT, 97111815Sphk .d_open = amr_open, 98111815Sphk .d_close = amr_close, 99111815Sphk .d_ioctl = amr_ioctl, 100111815Sphk .d_name = "amr", 10151974Smsmith}; 10251974Smsmith 10365245Smsmith/* 10465245Smsmith * Initialisation, bus interface. 10565245Smsmith */ 10665245Smsmithstatic void amr_startup(void *arg); 10751974Smsmith 10851974Smsmith/* 10951974Smsmith * Command wrappers 11051974Smsmith */ 11165245Smsmithstatic int amr_query_controller(struct amr_softc *sc); 11265245Smsmithstatic void *amr_enquiry(struct amr_softc *sc, size_t bufsize, 11365245Smsmith u_int8_t cmd, u_int8_t cmdsub, u_int8_t cmdqual); 11465245Smsmithstatic void amr_completeio(struct amr_command *ac); 115106225Semoorestatic int amr_support_ext_cdb(struct amr_softc *sc); 11651974Smsmith 11751974Smsmith/* 11865245Smsmith * Command buffer allocation. 11951974Smsmith */ 12065245Smsmithstatic void amr_alloccmd_cluster(struct amr_softc *sc); 12165245Smsmithstatic void amr_freecmd_cluster(struct amr_command_cluster *acc); 12251974Smsmith 12351974Smsmith/* 12465245Smsmith * Command processing. 12551974Smsmith */ 12665245Smsmithstatic int amr_bio_command(struct amr_softc *sc, struct amr_command **acp); 127138422Sscottlstatic int amr_wait_command(struct amr_command *ac) __unused; 12865245Smsmithstatic int amr_getslot(struct amr_command *ac); 129138422Sscottlstatic int amr_mapcmd(struct amr_command *ac); 13065245Smsmithstatic void amr_unmapcmd(struct amr_command *ac); 13165245Smsmithstatic int amr_start(struct amr_command *ac); 132138422Sscottlstatic int amr_start1(struct amr_softc *sc, struct amr_command *ac); 13365245Smsmithstatic void amr_complete(void *context, int pending); 134138422Sscottlstatic void amr_setup_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int error); 135138422Sscottlstatic void amr_setup_data_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int error); 13651974Smsmith 13751974Smsmith/* 13858883Smsmith * Status monitoring 13958883Smsmith */ 14065245Smsmithstatic void amr_periodic(void *data); 14158883Smsmith 14258883Smsmith/* 14351974Smsmith * Interface-specific shims 14451974Smsmith */ 14565245Smsmithstatic int amr_quartz_submit_command(struct amr_softc *sc); 14665245Smsmithstatic int amr_quartz_get_work(struct amr_softc *sc, struct amr_mailbox *mbsave); 147107756Semoorestatic int amr_quartz_poll_command(struct amr_command *ac); 148138422Sscottlstatic int amr_quartz_poll_command1(struct amr_softc *sc, struct amr_command *ac); 14951974Smsmith 15065245Smsmithstatic int amr_std_submit_command(struct amr_softc *sc); 15165245Smsmithstatic int amr_std_get_work(struct amr_softc *sc, struct amr_mailbox *mbsave); 152107756Semoorestatic int amr_std_poll_command(struct amr_command *ac); 15365245Smsmithstatic void amr_std_attach_mailbox(struct amr_softc *sc); 15451974Smsmith 15565245Smsmith#ifdef AMR_BOARD_INIT 15665245Smsmithstatic int amr_quartz_init(struct amr_softc *sc); 15765245Smsmithstatic int amr_std_init(struct amr_softc *sc); 15865245Smsmith#endif 15965245Smsmith 16051974Smsmith/* 16151974Smsmith * Debugging 16251974Smsmith */ 16365245Smsmithstatic void amr_describe_controller(struct amr_softc *sc); 16465245Smsmith#ifdef AMR_DEBUG 165107756Semoore#if 0 16665245Smsmithstatic void amr_printcommand(struct amr_command *ac); 16765245Smsmith#endif 168107756Semoore#endif 16951974Smsmith 17051974Smsmith/******************************************************************************** 17151974Smsmith ******************************************************************************** 17265245Smsmith Inline Glue 17351974Smsmith ******************************************************************************** 17451974Smsmith ********************************************************************************/ 17551974Smsmith 17651974Smsmith/******************************************************************************** 17765245Smsmith ******************************************************************************** 17865245Smsmith Public Interfaces 17965245Smsmith ******************************************************************************** 18065245Smsmith ********************************************************************************/ 18151974Smsmith 18251974Smsmith/******************************************************************************** 18351974Smsmith * Initialise the controller and softc. 18451974Smsmith */ 18551974Smsmithint 18651974Smsmithamr_attach(struct amr_softc *sc) 18751974Smsmith{ 18851974Smsmith 18965245Smsmith debug_called(1); 19065245Smsmith 19151974Smsmith /* 19251974Smsmith * Initialise per-controller queues. 19351974Smsmith */ 19465245Smsmith TAILQ_INIT(&sc->amr_completed); 19551974Smsmith TAILQ_INIT(&sc->amr_freecmds); 19665245Smsmith TAILQ_INIT(&sc->amr_cmd_clusters); 19765245Smsmith TAILQ_INIT(&sc->amr_ready); 19859249Sphk bioq_init(&sc->amr_bioq); 19951974Smsmith 20065245Smsmith debug(2, "queue init done"); 20165245Smsmith 20265245Smsmith /* 20351974Smsmith * Configure for this controller type. 20451974Smsmith */ 20565245Smsmith if (AMR_IS_QUARTZ(sc)) { 20651974Smsmith sc->amr_submit_command = amr_quartz_submit_command; 20751974Smsmith sc->amr_get_work = amr_quartz_get_work; 208107756Semoore sc->amr_poll_command = amr_quartz_poll_command; 209138422Sscottl sc->amr_poll_command1 = amr_quartz_poll_command1; 21051974Smsmith } else { 21151974Smsmith sc->amr_submit_command = amr_std_submit_command; 21251974Smsmith sc->amr_get_work = amr_std_get_work; 213107756Semoore sc->amr_poll_command = amr_std_poll_command; 21465245Smsmith amr_std_attach_mailbox(sc);; 21551974Smsmith } 21651974Smsmith 21765245Smsmith#ifdef AMR_BOARD_INIT 21865245Smsmith if ((AMR_IS_QUARTZ(sc) ? amr_quartz_init(sc) : amr_std_init(sc)))) 21965245Smsmith return(ENXIO); 22065245Smsmith#endif 22151974Smsmith 22251974Smsmith /* 22365245Smsmith * Quiz controller for features and limits. 22451974Smsmith */ 22565245Smsmith if (amr_query_controller(sc)) 22665245Smsmith return(ENXIO); 22751974Smsmith 22865245Smsmith debug(2, "controller query complete"); 22951974Smsmith 23051974Smsmith /* 23165245Smsmith * Attach our 'real' SCSI channels to CAM. 23251974Smsmith */ 23365245Smsmith if (amr_cam_attach(sc)) 23451974Smsmith return(ENXIO); 23565245Smsmith debug(2, "CAM attach done"); 23651974Smsmith 23751974Smsmith /* 23865245Smsmith * Create the control device. 23951974Smsmith */ 24065245Smsmith sc->amr_dev_t = make_dev(&amr_cdevsw, device_get_unit(sc->amr_dev), UID_ROOT, GID_OPERATOR, 24165245Smsmith S_IRUSR | S_IWUSR, "amr%d", device_get_unit(sc->amr_dev)); 24265245Smsmith sc->amr_dev_t->si_drv1 = sc; 24351974Smsmith 24451974Smsmith /* 24565245Smsmith * Schedule ourselves to bring the controller up once interrupts are 24665245Smsmith * available. 24751974Smsmith */ 24865245Smsmith bzero(&sc->amr_ich, sizeof(struct intr_config_hook)); 24965245Smsmith sc->amr_ich.ich_func = amr_startup; 25065245Smsmith sc->amr_ich.ich_arg = sc; 25165245Smsmith if (config_intrhook_establish(&sc->amr_ich) != 0) { 25265245Smsmith device_printf(sc->amr_dev, "can't establish configuration hook\n"); 25365245Smsmith return(ENOMEM); 25465245Smsmith } 25551974Smsmith 25658883Smsmith /* 25765245Smsmith * Print a little information about the controller. 25858883Smsmith */ 25965245Smsmith amr_describe_controller(sc); 26058883Smsmith 26165245Smsmith debug(2, "attach complete"); 26251974Smsmith return(0); 26351974Smsmith} 26451974Smsmith 26551974Smsmith/******************************************************************************** 26651974Smsmith * Locate disk resources and attach children to them. 26751974Smsmith */ 26865245Smsmithstatic void 26965245Smsmithamr_startup(void *arg) 27051974Smsmith{ 27165245Smsmith struct amr_softc *sc = (struct amr_softc *)arg; 27251974Smsmith struct amr_logdrive *dr; 27351974Smsmith int i, error; 27451974Smsmith 27565245Smsmith debug_called(1); 27651974Smsmith 27765245Smsmith /* pull ourselves off the intrhook chain */ 27865245Smsmith config_intrhook_disestablish(&sc->amr_ich); 27965245Smsmith 28051974Smsmith /* get up-to-date drive information */ 28151974Smsmith if (amr_query_controller(sc)) { 28265245Smsmith device_printf(sc->amr_dev, "can't scan controller for drives\n"); 28351974Smsmith return; 28451974Smsmith } 28551974Smsmith 28651974Smsmith /* iterate over available drives */ 28751974Smsmith for (i = 0, dr = &sc->amr_drive[0]; (i < AMR_MAXLD) && (dr->al_size != 0xffffffff); i++, dr++) { 28851974Smsmith /* are we already attached to this drive? */ 28951974Smsmith if (dr->al_disk == 0) { 29051974Smsmith /* generate geometry information */ 29151974Smsmith if (dr->al_size > 0x200000) { /* extended translation? */ 29251974Smsmith dr->al_heads = 255; 29351974Smsmith dr->al_sectors = 63; 29451974Smsmith } else { 29551974Smsmith dr->al_heads = 64; 29651974Smsmith dr->al_sectors = 32; 29751974Smsmith } 29851974Smsmith dr->al_cylinders = dr->al_size / (dr->al_heads * dr->al_sectors); 29951974Smsmith 30054073Smdodd dr->al_disk = device_add_child(sc->amr_dev, NULL, -1); 30151974Smsmith if (dr->al_disk == 0) 30251974Smsmith device_printf(sc->amr_dev, "device_add_child failed\n"); 30354073Smdodd device_set_ivars(dr->al_disk, dr); 30451974Smsmith } 30551974Smsmith } 30651974Smsmith 30751974Smsmith if ((error = bus_generic_attach(sc->amr_dev)) != 0) 30851974Smsmith device_printf(sc->amr_dev, "bus_generic_attach returned %d\n", error); 30951974Smsmith 31051974Smsmith /* mark controller back up */ 31151974Smsmith sc->amr_state &= ~AMR_STATE_SHUTDOWN; 31251974Smsmith 31351974Smsmith /* interrupts will be enabled before we do anything more */ 31451974Smsmith sc->amr_state |= AMR_STATE_INTEN; 31551974Smsmith 31651974Smsmith /* 31765245Smsmith * Start the timeout routine. 31851974Smsmith */ 31965245Smsmith/* sc->amr_timeout = timeout(amr_periodic, sc, hz);*/ 32051974Smsmith 32165245Smsmith return; 32251974Smsmith} 32351974Smsmith 32465245Smsmith/******************************************************************************* 32565245Smsmith * Free resources associated with a controller instance 32651974Smsmith */ 32765245Smsmithvoid 32865245Smsmithamr_free(struct amr_softc *sc) 32951974Smsmith{ 33065245Smsmith struct amr_command_cluster *acc; 33151974Smsmith 33265245Smsmith /* detach from CAM */ 333107756Semoore amr_cam_detach(sc); 33451974Smsmith 33565245Smsmith /* cancel status timeout */ 33665245Smsmith untimeout(amr_periodic, sc, sc->amr_timeout); 33751974Smsmith 33865245Smsmith /* throw away any command buffers */ 33965245Smsmith while ((acc = TAILQ_FIRST(&sc->amr_cmd_clusters)) != NULL) { 34065245Smsmith TAILQ_REMOVE(&sc->amr_cmd_clusters, acc, acc_link); 34165245Smsmith amr_freecmd_cluster(acc); 34251974Smsmith } 343107756Semoore 344107756Semoore /* destroy control device */ 345130585Sphk if( sc->amr_dev_t != (struct cdev *)NULL) 346107756Semoore destroy_dev(sc->amr_dev_t); 347140340Sscottl 348140340Sscottl if (mtx_initialized(&sc->amr_io_lock)) 349140340Sscottl mtx_destroy(&sc->amr_io_lock); 35051974Smsmith} 35151974Smsmith 35251974Smsmith/******************************************************************************* 35365245Smsmith * Receive a bio structure from a child device and queue it on a particular 35451974Smsmith * disk resource, then poke the disk resource to start as much work as it can. 35551974Smsmith */ 35651974Smsmithint 35765245Smsmithamr_submit_bio(struct amr_softc *sc, struct bio *bio) 35851974Smsmith{ 35965245Smsmith debug_called(2); 36052543Smsmith 361140340Sscottl mtx_lock(&sc->amr_io_lock); 36265245Smsmith amr_enqueue_bio(sc, bio); 36351974Smsmith amr_startio(sc); 364140340Sscottl mtx_unlock(&sc->amr_io_lock); 36551974Smsmith return(0); 36651974Smsmith} 36751974Smsmith 36851974Smsmith/******************************************************************************** 36951974Smsmith * Accept an open operation on the control device. 37051974Smsmith */ 371104094Sphkstatic int 372130585Sphkamr_open(struct cdev *dev, int flags, int fmt, d_thread_t *td) 37351974Smsmith{ 37451974Smsmith int unit = minor(dev); 37589055Smsmith struct amr_softc *sc = devclass_get_softc(devclass_find("amr"), unit); 37651974Smsmith 37765245Smsmith debug_called(1); 37865245Smsmith 37951974Smsmith sc->amr_state |= AMR_STATE_OPEN; 38051974Smsmith return(0); 38151974Smsmith} 38251974Smsmith 38351974Smsmith/******************************************************************************** 38451974Smsmith * Accept the last close on the control device. 38551974Smsmith */ 386104094Sphkstatic int 387130585Sphkamr_close(struct cdev *dev, int flags, int fmt, d_thread_t *td) 38851974Smsmith{ 38951974Smsmith int unit = minor(dev); 39089055Smsmith struct amr_softc *sc = devclass_get_softc(devclass_find("amr"), unit); 39151974Smsmith 39265245Smsmith debug_called(1); 39365245Smsmith 39451974Smsmith sc->amr_state &= ~AMR_STATE_OPEN; 39551974Smsmith return (0); 39651974Smsmith} 39751974Smsmith 39851974Smsmith/******************************************************************************** 39951974Smsmith * Handle controller-specific control operations. 40051974Smsmith */ 401104094Sphkstatic int 402130585Sphkamr_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int32_t flag, d_thread_t *td) 40351974Smsmith{ 40465245Smsmith struct amr_softc *sc = (struct amr_softc *)dev->si_drv1; 405133870Sambrisko union { 406133870Sambrisko void *_p; 407133870Sambrisko struct amr_user_ioctl *au; 408133870Sambrisko#ifdef AMR_IO_COMMAND32 409133870Sambrisko struct amr_user_ioctl32 *au32; 410133870Sambrisko#endif 411133870Sambrisko int *result; 412133870Sambrisko } arg; 41365245Smsmith struct amr_command *ac; 41465245Smsmith struct amr_mailbox_ioctl *mbi; 415133870Sambrisko void *dp, *au_buffer; 416133870Sambrisko unsigned long au_length; 417133870Sambrisko unsigned char *au_cmd; 418133870Sambrisko int *au_statusp, au_direction; 41965245Smsmith int error; 420143121Sscottl struct amr_passthrough *ap; /* 60 bytes */ 42165245Smsmith 42265245Smsmith debug_called(1); 42365245Smsmith 424133870Sambrisko arg._p = (void *)addr; 425133870Sambrisko 42651974Smsmith switch(cmd) { 42765245Smsmith 42865245Smsmith case AMR_IO_VERSION: 42965245Smsmith debug(1, "AMR_IO_VERSION"); 430133870Sambrisko *arg.result = AMR_IO_VERSION_NUMBER; 431133870Sambrisko return(0); 432133870Sambrisko 433133870Sambrisko#ifdef AMR_IO_COMMAND32 434133870Sambrisko /* 435133870Sambrisko * Accept ioctl-s from 32-bit binaries on non-32-bit 436133870Sambrisko * platforms, such as AMD. LSI's MEGAMGR utility is 437133870Sambrisko * the only example known today... -mi 438133870Sambrisko */ 439133870Sambrisko case AMR_IO_COMMAND32: 440133870Sambrisko debug(1, "AMR_IO_COMMAND32 0x%x", arg.au32->au_cmd[0]); 441133870Sambrisko au_cmd = arg.au32->au_cmd; 442133870Sambrisko au_buffer = (void *)(u_int64_t)arg.au32->au_buffer; 443133870Sambrisko au_length = arg.au32->au_length; 444133870Sambrisko au_direction = arg.au32->au_direction; 445133870Sambrisko au_statusp = &arg.au32->au_status; 44665245Smsmith break; 447133870Sambrisko#endif 44865245Smsmith 44965245Smsmith case AMR_IO_COMMAND: 450133870Sambrisko debug(1, "AMR_IO_COMMAND 0x%x", arg.au->au_cmd[0]); 451133870Sambrisko au_cmd = arg.au->au_cmd; 452133870Sambrisko au_buffer = (void *)arg.au->au_buffer; 453133870Sambrisko au_length = arg.au->au_length; 454133870Sambrisko au_direction = arg.au->au_direction; 455133870Sambrisko au_statusp = &arg.au->au_status; 456133870Sambrisko break; 45765245Smsmith 458133870Sambrisko default: 459133870Sambrisko debug(1, "unknown ioctl 0x%lx", cmd); 460133870Sambrisko return(ENOIOCTL); 461133870Sambrisko } 46265245Smsmith 463133870Sambrisko error = 0; 464133870Sambrisko dp = NULL; 465133870Sambrisko ac = NULL; 466143121Sscottl ap = NULL; 46765245Smsmith 468140688Sscottl /* Logical Drive not supported by the driver */ 469140688Sscottl if (au_cmd[0] == 0xa4 && au_cmd[1] == 0x1c) 470140688Sscottl return (ENOIOCTL); 471140688Sscottl 472133870Sambrisko /* handle inbound data buffer */ 473140688Sscottl if (au_length != 0 && au_cmd[0] != 0x06) { 474133870Sambrisko if ((dp = malloc(au_length, M_DEVBUF, M_WAITOK)) == NULL) 475133870Sambrisko return(ENOMEM); 47665245Smsmith 477143121Sscottl if ((ap = malloc(sizeof(struct amr_passthrough ), M_DEVBUF, M_WAITOK)) == NULL) 478143121Sscottl return(ENOMEM); 479143121Sscottl 480140340Sscottl if ((error = copyin(au_buffer, dp, au_length)) != 0) { 481140340Sscottl free(dp, M_DEVBUF); 482140340Sscottl return (error); 483140340Sscottl } 484133870Sambrisko debug(2, "copyin %ld bytes from %p -> %p", au_length, au_buffer, dp); 485133870Sambrisko } 48665245Smsmith 487140340Sscottl mtx_lock(&sc->amr_io_lock); 488133870Sambrisko if ((ac = amr_alloccmd(sc)) == NULL) { 489133870Sambrisko error = ENOMEM; 490133870Sambrisko goto out; 491133870Sambrisko } 49265245Smsmith 493133870Sambrisko /* handle SCSI passthrough command */ 494133870Sambrisko if (au_cmd[0] == AMR_CMD_PASS) { 495140340Sscottl int len; 49665245Smsmith 497133870Sambrisko /* copy cdb */ 498140340Sscottl len = au_cmd[2]; 499143121Sscottl ap->ap_cdb_length = len; 500143121Sscottl bcopy(au_cmd + 3, ap->ap_cdb, len); 50165245Smsmith 502133870Sambrisko /* build passthrough */ 503143121Sscottl ap->ap_timeout = au_cmd[len + 3] & 0x07; 504143121Sscottl ap->ap_ars = (au_cmd[len + 3] & 0x08) ? 1 : 0; 505143121Sscottl ap->ap_islogical = (au_cmd[len + 3] & 0x80) ? 1 : 0; 506143121Sscottl ap->ap_logical_drive_no = au_cmd[len + 4]; 507143121Sscottl ap->ap_channel = au_cmd[len + 5]; 508143121Sscottl ap->ap_scsi_id = au_cmd[len + 6]; 509143121Sscottl ap->ap_request_sense_length = 14; 510143121Sscottl ap->ap_data_transfer_length = au_length; 511133870Sambrisko /* XXX what about the request-sense area? does the caller want it? */ 51265245Smsmith 513133870Sambrisko /* build command */ 514143121Sscottl ac->ac_data = ap; 515140340Sscottl ac->ac_length = sizeof(struct amr_passthrough); 516133870Sambrisko ac->ac_flags |= AMR_CMD_DATAOUT; 517133870Sambrisko ac->ac_ccb_data = dp; 518133870Sambrisko ac->ac_ccb_length = au_length; 519133870Sambrisko if (au_direction & AMR_IO_READ) 520133870Sambrisko ac->ac_flags |= AMR_CMD_CCB_DATAIN; 521133870Sambrisko if (au_direction & AMR_IO_WRITE) 522133870Sambrisko ac->ac_flags |= AMR_CMD_CCB_DATAOUT; 52365245Smsmith 524133870Sambrisko ac->ac_mailbox.mb_command = AMR_CMD_PASS; 52565245Smsmith 526133870Sambrisko } else { 527133870Sambrisko /* direct command to controller */ 528133870Sambrisko mbi = (struct amr_mailbox_ioctl *)&ac->ac_mailbox; 529105419Semoore 530133870Sambrisko /* copy pertinent mailbox items */ 531133870Sambrisko mbi->mb_command = au_cmd[0]; 532133870Sambrisko mbi->mb_channel = au_cmd[1]; 533133870Sambrisko mbi->mb_param = au_cmd[2]; 534133870Sambrisko mbi->mb_pad[0] = au_cmd[3]; 535133870Sambrisko mbi->mb_drive = au_cmd[4]; 536133870Sambrisko 537133870Sambrisko /* build the command */ 538133870Sambrisko ac->ac_data = dp; 539133870Sambrisko ac->ac_length = au_length; 540133870Sambrisko if (au_direction & AMR_IO_READ) 541133870Sambrisko ac->ac_flags |= AMR_CMD_DATAIN; 542133870Sambrisko if (au_direction & AMR_IO_WRITE) 543133870Sambrisko ac->ac_flags |= AMR_CMD_DATAOUT; 54451974Smsmith } 54551974Smsmith 546133870Sambrisko /* run the command */ 547133870Sambrisko if ((error = amr_wait_command(ac)) != 0) 548133870Sambrisko goto out; 549133870Sambrisko 550133870Sambrisko /* copy out data and set status */ 551140340Sscottl if (au_length != 0) { 552140340Sscottl mtx_unlock(&sc->amr_io_lock); 553133870Sambrisko error = copyout(dp, au_buffer, au_length); 554140340Sscottl mtx_lock(&sc->amr_io_lock); 555140340Sscottl } 556133870Sambrisko debug(2, "copyout %ld bytes from %p -> %p", au_length, dp, au_buffer); 55765245Smsmith if (dp != NULL) 558133870Sambrisko debug(2, "%16d", (int)dp); 559133870Sambrisko *au_statusp = ac->ac_status; 560133870Sambrisko 561133870Sambriskoout: 562140340Sscottl /* 563140340Sscottl * At this point, we know that there is a lock held and that these 564140340Sscottl * objects have been allocated. 565140340Sscottl */ 566140340Sscottl free(dp, M_DEVBUF); 567143121Sscottl free(ap, M_DEVBUF); 568140340Sscottl amr_releasecmd(ac); 569140340Sscottl mtx_unlock(&sc->amr_io_lock); 57065245Smsmith return(error); 57151974Smsmith} 57251974Smsmith 57351974Smsmith/******************************************************************************** 57451974Smsmith ******************************************************************************** 57558883Smsmith Status Monitoring 57658883Smsmith ******************************************************************************** 57758883Smsmith ********************************************************************************/ 57858883Smsmith 57958883Smsmith/******************************************************************************** 58058883Smsmith * Perform a periodic check of the controller status 58158883Smsmith */ 58258883Smsmithstatic void 58358883Smsmithamr_periodic(void *data) 58458883Smsmith{ 58558883Smsmith struct amr_softc *sc = (struct amr_softc *)data; 58658883Smsmith 58765245Smsmith debug_called(2); 58858883Smsmith 58965245Smsmith /* XXX perform periodic status checks here */ 59058883Smsmith 59165245Smsmith /* compensate for missed interrupts */ 59265245Smsmith amr_done(sc); 59365245Smsmith 59458883Smsmith /* reschedule */ 59558883Smsmith sc->amr_timeout = timeout(amr_periodic, sc, hz); 59658883Smsmith} 59758883Smsmith 59858883Smsmith/******************************************************************************** 59958883Smsmith ******************************************************************************** 60051974Smsmith Command Wrappers 60151974Smsmith ******************************************************************************** 60251974Smsmith ********************************************************************************/ 60351974Smsmith 60451974Smsmith/******************************************************************************** 60551974Smsmith * Interrogate the controller for the operational parameters we require. 60651974Smsmith */ 60751974Smsmithstatic int 60851974Smsmithamr_query_controller(struct amr_softc *sc) 60951974Smsmith{ 61065245Smsmith struct amr_enquiry3 *aex; 61165245Smsmith struct amr_prodinfo *ap; 61265245Smsmith struct amr_enquiry *ae; 61365245Smsmith int ldrv; 61451974Smsmith 615140340Sscottl mtx_lock(&sc->amr_io_lock); 616140340Sscottl 61765245Smsmith /* 61865245Smsmith * If we haven't found the real limit yet, let us have a couple of commands in 61965245Smsmith * order to be able to probe. 62065245Smsmith */ 62165245Smsmith if (sc->amr_maxio == 0) 62265245Smsmith sc->amr_maxio = 2; 62351974Smsmith 624106225Semoore /* 625106225Semoore * Greater than 10 byte cdb support 626106225Semoore */ 627106225Semoore sc->support_ext_cdb = amr_support_ext_cdb(sc); 628106225Semoore 629106225Semoore if(sc->support_ext_cdb) { 630106225Semoore debug(2,"supports extended CDBs."); 631106225Semoore } 632106225Semoore 63365245Smsmith /* 63465245Smsmith * Try to issue an ENQUIRY3 command 63565245Smsmith */ 63665245Smsmith if ((aex = amr_enquiry(sc, 2048, AMR_CMD_CONFIG, AMR_CONFIG_ENQ3, 63765245Smsmith AMR_CONFIG_ENQ3_SOLICITED_FULL)) != NULL) { 63851974Smsmith 63965245Smsmith /* 64065245Smsmith * Fetch current state of logical drives. 64165245Smsmith */ 64265245Smsmith for (ldrv = 0; ldrv < aex->ae_numldrives; ldrv++) { 64365245Smsmith sc->amr_drive[ldrv].al_size = aex->ae_drivesize[ldrv]; 64465245Smsmith sc->amr_drive[ldrv].al_state = aex->ae_drivestate[ldrv]; 64565245Smsmith sc->amr_drive[ldrv].al_properties = aex->ae_driveprop[ldrv]; 64665245Smsmith debug(2, " drive %d: %d state %x properties %x\n", ldrv, sc->amr_drive[ldrv].al_size, 64765245Smsmith sc->amr_drive[ldrv].al_state, sc->amr_drive[ldrv].al_properties); 64851974Smsmith } 64965245Smsmith free(aex, M_DEVBUF); 65058883Smsmith 65165245Smsmith /* 65265245Smsmith * Get product info for channel count. 65358883Smsmith */ 65465245Smsmith if ((ap = amr_enquiry(sc, 2048, AMR_CMD_CONFIG, AMR_CONFIG_PRODUCT_INFO, 0)) == NULL) { 65565245Smsmith device_printf(sc->amr_dev, "can't obtain product data from controller\n"); 656140340Sscottl mtx_unlock(&sc->amr_io_lock); 65765245Smsmith return(1); 65865245Smsmith } 65965245Smsmith sc->amr_maxdrives = 40; 66065245Smsmith sc->amr_maxchan = ap->ap_nschan; 66165245Smsmith sc->amr_maxio = ap->ap_maxio; 66265245Smsmith sc->amr_type |= AMR_TYPE_40LD; 66365245Smsmith free(ap, M_DEVBUF); 66458883Smsmith 66565245Smsmith } else { 66665245Smsmith 66765245Smsmith /* failed, try the 8LD ENQUIRY commands */ 66865245Smsmith if ((ae = (struct amr_enquiry *)amr_enquiry(sc, 2048, AMR_CMD_EXT_ENQUIRY2, 0, 0)) == NULL) { 66965245Smsmith if ((ae = (struct amr_enquiry *)amr_enquiry(sc, 2048, AMR_CMD_ENQUIRY, 0, 0)) == NULL) { 67065245Smsmith device_printf(sc->amr_dev, "can't obtain configuration data from controller\n"); 671140340Sscottl mtx_unlock(&sc->amr_io_lock); 67265245Smsmith return(1); 67365245Smsmith } 67465245Smsmith ae->ae_signature = 0; 67551974Smsmith } 67665245Smsmith 67758883Smsmith /* 67865245Smsmith * Fetch current state of logical drives. 67958883Smsmith */ 68065245Smsmith for (ldrv = 0; ldrv < ae->ae_ldrv.al_numdrives; ldrv++) { 68165245Smsmith sc->amr_drive[ldrv].al_size = ae->ae_ldrv.al_size[ldrv]; 68265245Smsmith sc->amr_drive[ldrv].al_state = ae->ae_ldrv.al_state[ldrv]; 68365245Smsmith sc->amr_drive[ldrv].al_properties = ae->ae_ldrv.al_properties[ldrv]; 68465245Smsmith debug(2, " drive %d: %d state %x properties %x\n", ldrv, sc->amr_drive[ldrv].al_size, 68565245Smsmith sc->amr_drive[ldrv].al_state, sc->amr_drive[ldrv].al_properties); 68651974Smsmith } 68765245Smsmith 68865245Smsmith sc->amr_maxdrives = 8; 68965245Smsmith sc->amr_maxchan = ae->ae_adapter.aa_channels; 69065245Smsmith sc->amr_maxio = ae->ae_adapter.aa_maxio; 69165245Smsmith free(ae, M_DEVBUF); 69251974Smsmith } 69365245Smsmith 69465245Smsmith /* 69565245Smsmith * Mark remaining drives as unused. 69665245Smsmith */ 69765245Smsmith for (; ldrv < AMR_MAXLD; ldrv++) 69865245Smsmith sc->amr_drive[ldrv].al_size = 0xffffffff; 69965245Smsmith 70065245Smsmith /* 70165245Smsmith * Cap the maximum number of outstanding I/Os. AMI's Linux driver doesn't trust 70265245Smsmith * the controller's reported value, and lockups have been seen when we do. 70365245Smsmith */ 70465245Smsmith sc->amr_maxio = imin(sc->amr_maxio, AMR_LIMITCMD); 70565245Smsmith 706140340Sscottl mtx_unlock(&sc->amr_io_lock); 70751974Smsmith return(0); 70851974Smsmith} 70951974Smsmith 71051974Smsmith/******************************************************************************** 71151974Smsmith * Run a generic enquiry-style command. 71251974Smsmith */ 71351974Smsmithstatic void * 71451974Smsmithamr_enquiry(struct amr_softc *sc, size_t bufsize, u_int8_t cmd, u_int8_t cmdsub, u_int8_t cmdqual) 71551974Smsmith{ 71651974Smsmith struct amr_command *ac; 71751974Smsmith void *result; 71851974Smsmith u_int8_t *mbox; 71951974Smsmith int error; 72051974Smsmith 72165245Smsmith debug_called(1); 72251974Smsmith 72351974Smsmith error = 1; 72451974Smsmith result = NULL; 72551974Smsmith 72651974Smsmith /* get ourselves a command buffer */ 72751974Smsmith if ((ac = amr_alloccmd(sc)) == NULL) 72851974Smsmith goto out; 72951974Smsmith /* allocate the response structure */ 730138422Sscottl if ((result = malloc(bufsize, M_DEVBUF, M_ZERO|M_NOWAIT)) == NULL) 73151974Smsmith goto out; 73265245Smsmith /* set command flags */ 733138422Sscottl 734135236Sscottl ac->ac_flags |= AMR_CMD_PRIORITY | AMR_CMD_DATAIN; 73551974Smsmith 73665245Smsmith /* point the command at our data */ 73751974Smsmith ac->ac_data = result; 73851974Smsmith ac->ac_length = bufsize; 73951974Smsmith 74051974Smsmith /* build the command proper */ 74151974Smsmith mbox = (u_int8_t *)&ac->ac_mailbox; /* XXX want a real structure for this? */ 74251974Smsmith mbox[0] = cmd; 74351974Smsmith mbox[2] = cmdsub; 74451974Smsmith mbox[3] = cmdqual; 74551974Smsmith 74658883Smsmith /* can't assume that interrupts are going to work here, so play it safe */ 747107756Semoore if (sc->amr_poll_command(ac)) 74851974Smsmith goto out; 74951974Smsmith error = ac->ac_status; 75051974Smsmith 75151974Smsmith out: 75251974Smsmith if (ac != NULL) 75351974Smsmith amr_releasecmd(ac); 75451974Smsmith if ((error != 0) && (result != NULL)) { 75551974Smsmith free(result, M_DEVBUF); 75651974Smsmith result = NULL; 75751974Smsmith } 75851974Smsmith return(result); 75951974Smsmith} 76051974Smsmith 76151974Smsmith/******************************************************************************** 76251974Smsmith * Flush the controller's internal cache, return status. 76351974Smsmith */ 76465245Smsmithint 76551974Smsmithamr_flush(struct amr_softc *sc) 76651974Smsmith{ 76751974Smsmith struct amr_command *ac; 76851974Smsmith int error; 76951974Smsmith 77051974Smsmith /* get ourselves a command buffer */ 77151974Smsmith error = 1; 772140340Sscottl mtx_lock(&sc->amr_io_lock); 77351974Smsmith if ((ac = amr_alloccmd(sc)) == NULL) 77451974Smsmith goto out; 77565245Smsmith /* set command flags */ 77651974Smsmith ac->ac_flags |= AMR_CMD_PRIORITY | AMR_CMD_DATAOUT; 77751974Smsmith 77851974Smsmith /* build the command proper */ 77951974Smsmith ac->ac_mailbox.mb_command = AMR_CMD_FLUSH; 78051974Smsmith 78158883Smsmith /* we have to poll, as the system may be going down or otherwise damaged */ 782107756Semoore if (sc->amr_poll_command(ac)) 78351974Smsmith goto out; 78451974Smsmith error = ac->ac_status; 78551974Smsmith 78651974Smsmith out: 78751974Smsmith if (ac != NULL) 78851974Smsmith amr_releasecmd(ac); 789140340Sscottl mtx_unlock(&sc->amr_io_lock); 79051974Smsmith return(error); 79151974Smsmith} 79251974Smsmith 79351974Smsmith/******************************************************************************** 794106225Semoore * Detect extented cdb >> greater than 10 byte cdb support 795106225Semoore * returns '1' means this support exist 796106225Semoore * returns '0' means this support doesn't exist 797106225Semoore */ 798106225Semoorestatic int 799106225Semooreamr_support_ext_cdb(struct amr_softc *sc) 800106225Semoore{ 801106225Semoore struct amr_command *ac; 802106225Semoore u_int8_t *mbox; 803106225Semoore int error; 804106225Semoore 805106225Semoore /* get ourselves a command buffer */ 806106225Semoore error = 0; 807106225Semoore if ((ac = amr_alloccmd(sc)) == NULL) 808106225Semoore goto out; 809106225Semoore /* set command flags */ 810106225Semoore ac->ac_flags |= AMR_CMD_PRIORITY | AMR_CMD_DATAOUT; 811106225Semoore 812106225Semoore /* build the command proper */ 813106225Semoore mbox = (u_int8_t *)&ac->ac_mailbox; /* XXX want a real structure for this? */ 814106225Semoore mbox[0] = 0xA4; 815106225Semoore mbox[2] = 0x16; 816106225Semoore 817106225Semoore 818106225Semoore /* we have to poll, as the system may be going down or otherwise damaged */ 819107756Semoore if (sc->amr_poll_command(ac)) 820106225Semoore goto out; 821106225Semoore if( ac->ac_status == AMR_STATUS_SUCCESS ) { 822106225Semoore error = 1; 823106225Semoore } 824106225Semoore 825106225Semooreout: 826106225Semoore if (ac != NULL) 827106225Semoore amr_releasecmd(ac); 828106225Semoore return(error); 829106225Semoore} 830106225Semoore 831106225Semoore/******************************************************************************** 83265245Smsmith * Try to find I/O work for the controller from one or more of the work queues. 83351974Smsmith * 83465245Smsmith * We make the assumption that if the controller is not ready to take a command 83565245Smsmith * at some given time, it will generate an interrupt at some later time when 83665245Smsmith * it is. 83751974Smsmith */ 83865245Smsmithvoid 83951974Smsmithamr_startio(struct amr_softc *sc) 84051974Smsmith{ 84151974Smsmith struct amr_command *ac; 84251974Smsmith 84351974Smsmith /* spin until something prevents us from doing any work */ 84451974Smsmith for (;;) { 84551974Smsmith 846138422Sscottl /* Don't bother to queue commands no bounce buffers are available. */ 847138422Sscottl if (sc->amr_state & AMR_STATE_QUEUE_FRZN) 848138422Sscottl break; 849138422Sscottl 85065245Smsmith /* try to get a ready command */ 85165245Smsmith ac = amr_dequeue_ready(sc); 85251974Smsmith 85365245Smsmith /* if that failed, build a command from a bio */ 85465245Smsmith if (ac == NULL) 85565245Smsmith (void)amr_bio_command(sc, &ac); 85651974Smsmith 85765245Smsmith /* if that failed, build a command from a ccb */ 85865245Smsmith if (ac == NULL) 85965245Smsmith (void)amr_cam_command(sc, &ac); 860105419Semoore 86165245Smsmith /* if we don't have anything to do, give up */ 86265245Smsmith if (ac == NULL) 86365245Smsmith break; 86451974Smsmith 86565245Smsmith /* try to give the command to the controller; if this fails save it for later and give up */ 86665245Smsmith if (amr_start(ac)) { 86765245Smsmith debug(2, "controller busy, command deferred"); 86865245Smsmith amr_requeue_ready(ac); /* XXX schedule retry very soon? */ 86965245Smsmith break; 87051974Smsmith } 87151974Smsmith } 87251974Smsmith} 87351974Smsmith 87451974Smsmith/******************************************************************************** 87551974Smsmith * Handle completion of an I/O command. 87651974Smsmith */ 87751974Smsmithstatic void 87851974Smsmithamr_completeio(struct amr_command *ac) 87951974Smsmith{ 88051974Smsmith struct amr_softc *sc = ac->ac_sc; 881140340Sscottl 88251974Smsmith if (ac->ac_status != AMR_STATUS_SUCCESS) { /* could be more verbose here? */ 88365245Smsmith ac->ac_bio->bio_error = EIO; 88465245Smsmith ac->ac_bio->bio_flags |= BIO_ERROR; 88551974Smsmith 88665245Smsmith device_printf(sc->amr_dev, "I/O error - 0x%x\n", ac->ac_status); 88765245Smsmith/* amr_printcommand(ac);*/ 88851974Smsmith } 88965245Smsmith amrd_intr(ac->ac_bio); 89065245Smsmith amr_releasecmd(ac); 89151974Smsmith} 89251974Smsmith 89351974Smsmith/******************************************************************************** 89451974Smsmith ******************************************************************************** 89551974Smsmith Command Processing 89651974Smsmith ******************************************************************************** 89751974Smsmith ********************************************************************************/ 89851974Smsmith 89951974Smsmith/******************************************************************************** 90065245Smsmith * Convert a bio off the top of the bio queue into a command. 90165245Smsmith */ 90265245Smsmithstatic int 90365245Smsmithamr_bio_command(struct amr_softc *sc, struct amr_command **acp) 90465245Smsmith{ 90565245Smsmith struct amr_command *ac; 90665245Smsmith struct amrd_softc *amrd; 90765245Smsmith struct bio *bio; 90865245Smsmith int error; 90965245Smsmith int blkcount; 91065245Smsmith int driveno; 91165245Smsmith int cmd; 91265245Smsmith 91365245Smsmith ac = NULL; 91465245Smsmith error = 0; 91565245Smsmith 916140340Sscottl /* get a command */ 917140340Sscottl if ((ac = amr_alloccmd(sc)) == NULL) 918140340Sscottl return (ENOMEM); 919140340Sscottl 92065245Smsmith /* get a bio to work on */ 921140340Sscottl if ((bio = amr_dequeue_bio(sc)) == NULL) { 922140340Sscottl amr_releasecmd(ac); 923140340Sscottl return (0); 924140340Sscottl } 92565245Smsmith 92665245Smsmith /* connect the bio to the command */ 92765245Smsmith ac->ac_complete = amr_completeio; 92865245Smsmith ac->ac_bio = bio; 92965245Smsmith ac->ac_data = bio->bio_data; 93065245Smsmith ac->ac_length = bio->bio_bcount; 93165245Smsmith if (BIO_IS_READ(bio)) { 93265245Smsmith ac->ac_flags |= AMR_CMD_DATAIN; 93365245Smsmith cmd = AMR_CMD_LREAD; 93465245Smsmith } else { 93565245Smsmith ac->ac_flags |= AMR_CMD_DATAOUT; 93665245Smsmith cmd = AMR_CMD_LWRITE; 93765245Smsmith } 938111441Sphk amrd = (struct amrd_softc *)bio->bio_disk->d_drv1; 93965245Smsmith driveno = amrd->amrd_drive - sc->amr_drive; 94065245Smsmith blkcount = (bio->bio_bcount + AMR_BLKSIZE - 1) / AMR_BLKSIZE; 94165245Smsmith 94265245Smsmith ac->ac_mailbox.mb_command = cmd; 94365245Smsmith ac->ac_mailbox.mb_blkcount = blkcount; 94465245Smsmith ac->ac_mailbox.mb_lba = bio->bio_pblkno; 94565245Smsmith ac->ac_mailbox.mb_drive = driveno; 94665245Smsmith /* we fill in the s/g related data when the command is mapped */ 94765245Smsmith 94865245Smsmith if ((bio->bio_pblkno + blkcount) > sc->amr_drive[driveno].al_size) 94992610Sbde device_printf(sc->amr_dev, "I/O beyond end of unit (%lld,%d > %lu)\n", 95092610Sbde (long long)bio->bio_pblkno, blkcount, 95192610Sbde (u_long)sc->amr_drive[driveno].al_size); 95265245Smsmith 95365245Smsmith *acp = ac; 95465245Smsmith return(error); 95565245Smsmith} 95665245Smsmith 95765245Smsmith/******************************************************************************** 95851974Smsmith * Take a command, submit it to the controller and sleep until it completes 95951974Smsmith * or fails. Interrupts must be enabled, returns nonzero on error. 96051974Smsmith */ 96151974Smsmithstatic int 96251974Smsmithamr_wait_command(struct amr_command *ac) 96351974Smsmith{ 96451974Smsmith int error, count; 96551974Smsmith 96665245Smsmith debug_called(1); 96751974Smsmith 96851974Smsmith ac->ac_complete = NULL; 96965245Smsmith ac->ac_flags |= AMR_CMD_SLEEP; 97051974Smsmith if ((error = amr_start(ac)) != 0) 97151974Smsmith return(error); 97251974Smsmith 97351974Smsmith count = 0; 97451974Smsmith /* XXX better timeout? */ 97565245Smsmith while ((ac->ac_flags & AMR_CMD_BUSY) && (count < 30)) { 976140340Sscottl msleep(ac, &ac->ac_sc->amr_io_lock, PRIBIO | PCATCH, "amrwcmd", hz); 97751974Smsmith } 97851974Smsmith return(0); 97951974Smsmith} 98051974Smsmith 98151974Smsmith/******************************************************************************** 98251974Smsmith * Take a command, submit it to the controller and busy-wait for it to return. 98351974Smsmith * Returns nonzero on error. Can be safely called with interrupts enabled. 98451974Smsmith */ 98551974Smsmithstatic int 986107756Semooreamr_std_poll_command(struct amr_command *ac) 98751974Smsmith{ 98851974Smsmith struct amr_softc *sc = ac->ac_sc; 98965245Smsmith int error, count; 99051974Smsmith 99165245Smsmith debug_called(2); 99251974Smsmith 99351974Smsmith ac->ac_complete = NULL; 99451974Smsmith if ((error = amr_start(ac)) != 0) 99551974Smsmith return(error); 99651974Smsmith 99751974Smsmith count = 0; 99851974Smsmith do { 99951974Smsmith /* 100051974Smsmith * Poll for completion, although the interrupt handler may beat us to it. 100151974Smsmith * Note that the timeout here is somewhat arbitrary. 100251974Smsmith */ 100351974Smsmith amr_done(sc); 100465245Smsmith DELAY(1000); 100565245Smsmith } while ((ac->ac_flags & AMR_CMD_BUSY) && (count++ < 1000)); 100665245Smsmith if (!(ac->ac_flags & AMR_CMD_BUSY)) { 100751974Smsmith error = 0; 100851974Smsmith } else { 100965245Smsmith /* XXX the slot is now marked permanently busy */ 101051974Smsmith error = EIO; 101165245Smsmith device_printf(sc->amr_dev, "polled command timeout\n"); 101251974Smsmith } 101351974Smsmith return(error); 101451974Smsmith} 101551974Smsmith 1016138422Sscottlstatic void 1017138422Sscottlamr_setup_polled_dmamap(void *arg, bus_dma_segment_t *segs, int nsegs, int err) 1018138422Sscottl{ 1019138422Sscottl struct amr_command *ac = arg; 1020138422Sscottl struct amr_softc *sc = ac->ac_sc; 1021138422Sscottl 1022138422Sscottl amr_setup_dmamap(arg, segs, nsegs, err); 1023138422Sscottl bus_dmamap_sync(sc->amr_buffer_dmat,ac->ac_dmamap,BUS_DMASYNC_PREREAD); 1024138422Sscottl sc->amr_poll_command1(sc, ac); 1025138422Sscottl} 1026138422Sscottl 102751974Smsmith/******************************************************************************** 1028107756Semoore * Take a command, submit it to the controller and busy-wait for it to return. 1029107756Semoore * Returns nonzero on error. Can be safely called with interrupts enabled. 1030107756Semoore */ 1031107756Semoorestatic int 1032107756Semooreamr_quartz_poll_command(struct amr_command *ac) 1033107756Semoore{ 1034107756Semoore struct amr_softc *sc = ac->ac_sc; 1035138422Sscottl int s, error; 1036107756Semoore 1037107756Semoore debug_called(2); 1038107756Semoore 1039138422Sscottl s = splbio(); 1040138422Sscottl error = 0; 1041138422Sscottl 1042107756Semoore /* now we have a slot, we can map the command (unmapped in amr_complete) */ 1043138422Sscottl if (ac->ac_data != 0) { 1044138422Sscottl if (bus_dmamap_load(sc->amr_buffer_dmat, ac->ac_dmamap, ac->ac_data, 1045138422Sscottl ac->ac_length, amr_setup_polled_dmamap, ac, BUS_DMA_NOWAIT) != 0) { 1046138422Sscottl error = 1; 1047138422Sscottl } 1048138422Sscottl } else { 1049138422Sscottl error = amr_quartz_poll_command1(sc, ac); 1050138422Sscottl } 1051107756Semoore 1052138422Sscottl splx(s); 1053138422Sscottl return (error); 1054138422Sscottl} 1055107756Semoore 1056138422Sscottlstatic int 1057138422Sscottlamr_quartz_poll_command1(struct amr_softc *sc, struct amr_command *ac) 1058138422Sscottl{ 1059138422Sscottl int count, error; 1060138422Sscottl 1061140688Sscottl if ((sc->amr_state & AMR_STATE_INTEN) == 0) { 1062120988Sps count=0; 1063120988Sps while (sc->amr_busyslots) { 1064140340Sscottl msleep(sc, &sc->amr_io_lock, PRIBIO | PCATCH, "amrpoll", hz); 1065120988Sps if(count++>10) { 1066120988Sps break; 1067120988Sps } 1068109031Semoore } 1069109031Semoore 1070120988Sps if(sc->amr_busyslots) { 1071120988Sps device_printf(sc->amr_dev, "adapter is busy\n"); 1072138422Sscottl if (ac->ac_data != NULL) 1073138422Sscottl bus_dmamap_unload(sc->amr_buffer_dmat, ac->ac_dmamap); 1074120988Sps ac->ac_status=0; 1075120988Sps return(1); 1076120988Sps } 1077107756Semoore } 1078107756Semoore 1079107756Semoore bcopy(&ac->ac_mailbox, (void *)(uintptr_t)(volatile void *)sc->amr_mailbox, AMR_MBOX_CMDSIZE); 1080107756Semoore 1081107756Semoore /* clear the poll/ack fields in the mailbox */ 1082107756Semoore sc->amr_mailbox->mb_ident = 0xFE; 1083107756Semoore sc->amr_mailbox->mb_nstatus = 0xFF; 1084107756Semoore sc->amr_mailbox->mb_status = 0xFF; 1085107756Semoore sc->amr_mailbox->mb_poll = 0; 1086107756Semoore sc->amr_mailbox->mb_ack = 0; 1087109031Semoore sc->amr_mailbox->mb_busy = 1; 1088107756Semoore 1089107756Semoore AMR_QPUT_IDB(sc, sc->amr_mailboxphys | AMR_QIDB_SUBMIT); 1090107756Semoore 1091107756Semoore while(sc->amr_mailbox->mb_nstatus == 0xFF); 1092107756Semoore while(sc->amr_mailbox->mb_status == 0xFF); 1093107827Semoore ac->ac_status=sc->amr_mailbox->mb_status; 1094107827Semoore error = (ac->ac_status !=AMR_STATUS_SUCCESS) ? 1:0; 1095107756Semoore while(sc->amr_mailbox->mb_poll != 0x77); 1096107756Semoore sc->amr_mailbox->mb_poll = 0; 1097107756Semoore sc->amr_mailbox->mb_ack = 0x77; 1098107756Semoore 1099107756Semoore /* acknowledge that we have the commands */ 1100107756Semoore AMR_QPUT_IDB(sc, sc->amr_mailboxphys | AMR_QIDB_ACK); 1101109031Semoore while(AMR_QGET_IDB(sc) & AMR_QIDB_ACK); 1102107756Semoore 1103107756Semoore /* unmap the command's data buffer */ 1104138422Sscottl bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_dmamap, BUS_DMASYNC_POSTREAD); 1105138422Sscottl bus_dmamap_unload(sc->amr_buffer_dmat, ac->ac_dmamap); 1106107756Semoore 1107107827Semoore return(error); 1108107756Semoore} 1109107756Semoore 1110107756Semoore/******************************************************************************** 111165245Smsmith * Get a free command slot for a command if it doesn't already have one. 111265245Smsmith * 111365245Smsmith * May be safely called multiple times for a given command. 111451974Smsmith */ 111551974Smsmithstatic int 111651974Smsmithamr_getslot(struct amr_command *ac) 111751974Smsmith{ 111851974Smsmith struct amr_softc *sc = ac->ac_sc; 1119140340Sscottl int slot; 112051974Smsmith 112165245Smsmith debug_called(3); 112265245Smsmith 1123140340Sscottl slot = ac->ac_slot; 1124140340Sscottl if (sc->amr_busycmd[slot] != NULL) 1125140340Sscottl panic("amr: slot %d busy?\n", slot); 112665245Smsmith 1127140340Sscottl sc->amr_busycmd[slot] = ac; 1128140340Sscottl sc->amr_busyslots++; 112951974Smsmith 1130140340Sscottl return (0); 113151974Smsmith} 113251974Smsmith 113351974Smsmith/******************************************************************************** 113465245Smsmith * Map/unmap (ac)'s data in the controller's addressable space as required. 113565245Smsmith * 113665245Smsmith * These functions may be safely called multiple times on a given command. 113751974Smsmith */ 113851974Smsmithstatic void 113951974Smsmithamr_setup_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int error) 114051974Smsmith{ 114151974Smsmith struct amr_command *ac = (struct amr_command *)arg; 114251974Smsmith struct amr_softc *sc = ac->ac_sc; 114351974Smsmith struct amr_sgentry *sg; 114451974Smsmith int i; 114569319Smsmith u_int8_t *sgc; 114651974Smsmith 114765245Smsmith debug_called(3); 114851974Smsmith 114951974Smsmith /* get base address of s/g table */ 115051974Smsmith sg = sc->amr_sgtable + (ac->ac_slot * AMR_NSEG); 115151974Smsmith 115265245Smsmith /* save data physical address */ 115351974Smsmith ac->ac_dataphys = segs[0].ds_addr; 115451974Smsmith 115569319Smsmith /* for AMR_CMD_CONFIG the s/g count goes elsewhere */ 115669319Smsmith if (ac->ac_mailbox.mb_command == AMR_CMD_CONFIG) { 115769319Smsmith sgc = &(((struct amr_mailbox_ioctl *)&ac->ac_mailbox)->mb_param); 115869319Smsmith } else { 115969319Smsmith sgc = &ac->ac_mailbox.mb_nsgelem; 116069319Smsmith } 116169319Smsmith 116265245Smsmith /* decide whether we need to populate the s/g table */ 116365245Smsmith if (nsegments < 2) { 116469319Smsmith *sgc = 0; 1165105419Semoore ac->ac_mailbox.mb_nsgelem = 0; 116665245Smsmith ac->ac_mailbox.mb_physaddr = ac->ac_dataphys; 116765245Smsmith } else { 1168105419Semoore ac->ac_mailbox.mb_nsgelem = nsegments; 116969319Smsmith *sgc = nsegments; 1170138422Sscottl ac->ac_mailbox.mb_physaddr = sc->amr_sgbusaddr + 1171138422Sscottl (ac->ac_slot * AMR_NSEG * sizeof(struct amr_sgentry)); 117265245Smsmith for (i = 0; i < nsegments; i++, sg++) { 117365245Smsmith sg->sg_addr = segs[i].ds_addr; 117465245Smsmith sg->sg_count = segs[i].ds_len; 117565245Smsmith } 117665245Smsmith } 1177138422Sscottl 117865245Smsmith} 117965245Smsmith 118065245Smsmithstatic void 118165245Smsmithamr_setup_ccbmap(void *arg, bus_dma_segment_t *segs, int nsegments, int error) 118265245Smsmith{ 1183105419Semoore struct amr_command *ac = (struct amr_command *)arg; 1184105419Semoore struct amr_softc *sc = ac->ac_sc; 1185105419Semoore struct amr_sgentry *sg; 1186105419Semoore struct amr_passthrough *ap = (struct amr_passthrough *)ac->ac_data; 1187106252Semoore struct amr_ext_passthrough *aep = (struct amr_ext_passthrough *)ac->ac_data; 1188105419Semoore int i; 118965245Smsmith 119065245Smsmith /* get base address of s/g table */ 119165245Smsmith sg = sc->amr_sgtable + (ac->ac_slot * AMR_NSEG); 119265245Smsmith 1193105419Semoore /* decide whether we need to populate the s/g table */ 1194106225Semoore if( ac->ac_mailbox.mb_command == AMR_CMD_EXTPASS ) { 1195106225Semoore if (nsegments < 2) { 1196106225Semoore aep->ap_no_sg_elements = 0; 1197106225Semoore aep->ap_data_transfer_address = segs[0].ds_addr; 1198106225Semoore } else { 1199106225Semoore /* save s/g table information in passthrough */ 1200106225Semoore aep->ap_no_sg_elements = nsegments; 1201138422Sscottl aep->ap_data_transfer_address = sc->amr_sgbusaddr + 1202138422Sscottl (ac->ac_slot * AMR_NSEG * sizeof(struct amr_sgentry)); 1203138422Sscottl /* 1204138422Sscottl * populate s/g table (overwrites previous call which mapped the 1205138422Sscottl * passthrough) 1206138422Sscottl */ 1207106225Semoore for (i = 0; i < nsegments; i++, sg++) { 1208106225Semoore sg->sg_addr = segs[i].ds_addr; 1209106225Semoore sg->sg_count = segs[i].ds_len; 1210106225Semoore debug(3, " %d: 0x%x/%d", i, sg->sg_addr, sg->sg_count); 1211106225Semoore } 1212106225Semoore } 1213138422Sscottl debug(3, "slot %d %d segments at 0x%x, passthrough at 0x%x\n", 1214138422Sscottl ac->ac_slot, aep->ap_no_sg_elements, aep->ap_data_transfer_address, 1215138422Sscottl ac->ac_dataphys); 1216105419Semoore } else { 1217106225Semoore if (nsegments < 2) { 1218106225Semoore ap->ap_no_sg_elements = 0; 1219106225Semoore ap->ap_data_transfer_address = segs[0].ds_addr; 1220106225Semoore } else { 1221106225Semoore /* save s/g table information in passthrough */ 1222106225Semoore ap->ap_no_sg_elements = nsegments; 1223138422Sscottl ap->ap_data_transfer_address = sc->amr_sgbusaddr + 1224138422Sscottl (ac->ac_slot * AMR_NSEG * sizeof(struct amr_sgentry)); 1225138422Sscottl /* 1226138422Sscottl * populate s/g table (overwrites previous call which mapped the 1227138422Sscottl * passthrough) 1228138422Sscottl */ 1229106225Semoore for (i = 0; i < nsegments; i++, sg++) { 1230105419Semoore sg->sg_addr = segs[i].ds_addr; 1231105419Semoore sg->sg_count = segs[i].ds_len; 1232105419Semoore debug(3, " %d: 0x%x/%d", i, sg->sg_addr, sg->sg_count); 1233106225Semoore } 1234105419Semoore } 1235138422Sscottl debug(3, "slot %d %d segments at 0x%x, passthrough at 0x%x", 1236138422Sscottl ac->ac_slot, ap->ap_no_sg_elements, ap->ap_data_transfer_address, 1237138422Sscottl ac->ac_dataphys); 1238105419Semoore } 1239138422Sscottl if (ac->ac_flags & AMR_CMD_CCB_DATAIN) 1240138422Sscottl bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_ccb_dmamap, 1241138422Sscottl BUS_DMASYNC_PREREAD); 1242138422Sscottl if (ac->ac_flags & AMR_CMD_CCB_DATAOUT) 1243138422Sscottl bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_ccb_dmamap, 1244138422Sscottl BUS_DMASYNC_PREWRITE); 1245138422Sscottl if ((ac->ac_flags & (AMR_CMD_CCB_DATAIN | AMR_CMD_CCB_DATAOUT)) == 0) 1246138422Sscottl panic("no direction for ccb?\n"); 1247138422Sscottl 1248138422Sscottl if (ac->ac_flags & AMR_CMD_DATAIN) 1249138422Sscottl bus_dmamap_sync(sc->amr_buffer_dmat,ac->ac_dmamap,BUS_DMASYNC_PREREAD); 1250138422Sscottl if (ac->ac_flags & AMR_CMD_DATAOUT) 1251138422Sscottl bus_dmamap_sync(sc->amr_buffer_dmat,ac->ac_dmamap,BUS_DMASYNC_PREWRITE); 1252138422Sscottl 1253138422Sscottl ac->ac_flags |= AMR_CMD_MAPPED; 1254138422Sscottl 1255138422Sscottl amr_start1(sc, ac); 125651974Smsmith} 125751974Smsmith 1258138422Sscottlstatic int 125951974Smsmithamr_mapcmd(struct amr_command *ac) 126051974Smsmith{ 126151974Smsmith struct amr_softc *sc = ac->ac_sc; 126251974Smsmith 126369319Smsmith debug_called(3); 126451974Smsmith 126565245Smsmith /* if the command involves data at all, and hasn't been mapped */ 1266138422Sscottl if ((ac->ac_flags & AMR_CMD_MAPPED) == 0 && (ac->ac_data != NULL)) { 1267138422Sscottl if (ac->ac_ccb_data == NULL) { 126865245Smsmith /* map the data buffers into bus space and build the s/g list */ 1269138422Sscottl if (bus_dmamap_load(sc->amr_buffer_dmat, ac->ac_dmamap, ac->ac_data, 1270138422Sscottl ac->ac_length, amr_setup_data_dmamap, ac, 0) == EINPROGRESS) { 1271138422Sscottl sc->amr_state |= AMR_STATE_QUEUE_FRZN; 1272138422Sscottl } 1273138422Sscottl } else { 1274138422Sscottl if (bus_dmamap_load(sc->amr_buffer_dmat, ac->ac_dmamap, ac->ac_data, 1275138422Sscottl ac->ac_length, amr_setup_dmamap, ac, BUS_DMA_NOWAIT) != 0){ 1276138422Sscottl return (ENOMEM); 1277138422Sscottl } 1278138422Sscottl if (bus_dmamap_load(sc->amr_buffer_dmat, ac->ac_ccb_dmamap, 1279138422Sscottl ac->ac_ccb_data, ac->ac_ccb_length, amr_setup_ccbmap, ac, 1280138422Sscottl 0) == EINPROGRESS) { 1281138422Sscottl sc->amr_state |= AMR_STATE_QUEUE_FRZN; 1282138422Sscottl } 1283143121Sscottl } 1284143121Sscottl } else if ((ac->ac_flags & AMR_CMD_MAPPED) == 0) { 1285143121Sscottl amr_start1(sc, ac); 1286143121Sscottl } 1287143121Sscottl 1288138422Sscottl return (0); 128951974Smsmith} 129051974Smsmith 129151974Smsmithstatic void 129251974Smsmithamr_unmapcmd(struct amr_command *ac) 129351974Smsmith{ 129451974Smsmith struct amr_softc *sc = ac->ac_sc; 129551974Smsmith 129669319Smsmith debug_called(3); 129751974Smsmith 129865245Smsmith /* if the command involved data at all and was mapped */ 129965245Smsmith if (ac->ac_flags & AMR_CMD_MAPPED) { 130051974Smsmith 130165245Smsmith if (ac->ac_data != NULL) { 130265245Smsmith if (ac->ac_flags & AMR_CMD_DATAIN) 1303138422Sscottl bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_dmamap, 1304138422Sscottl BUS_DMASYNC_POSTREAD); 130565245Smsmith if (ac->ac_flags & AMR_CMD_DATAOUT) 1306138422Sscottl bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_dmamap, 1307138422Sscottl BUS_DMASYNC_POSTWRITE); 130865245Smsmith bus_dmamap_unload(sc->amr_buffer_dmat, ac->ac_dmamap); 130965245Smsmith } 131065245Smsmith 131165245Smsmith if (ac->ac_ccb_data != NULL) { 131265245Smsmith if (ac->ac_flags & AMR_CMD_CCB_DATAIN) 1313138422Sscottl bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_ccb_dmamap, 1314138422Sscottl BUS_DMASYNC_POSTREAD); 131565245Smsmith if (ac->ac_flags & AMR_CMD_CCB_DATAOUT) 1316138422Sscottl bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_ccb_dmamap, 1317138422Sscottl BUS_DMASYNC_POSTWRITE); 131865245Smsmith bus_dmamap_unload(sc->amr_buffer_dmat, ac->ac_ccb_dmamap); 131965245Smsmith } 132065245Smsmith ac->ac_flags &= ~AMR_CMD_MAPPED; 132151974Smsmith } 132251974Smsmith} 132351974Smsmith 1324138422Sscottlstatic void 1325138422Sscottlamr_setup_data_dmamap(void *arg, bus_dma_segment_t *segs, int nsegs, int err) 1326138422Sscottl{ 1327138422Sscottl struct amr_command *ac = arg; 1328138422Sscottl struct amr_softc *sc = ac->ac_sc; 1329138422Sscottl 1330138422Sscottl amr_setup_dmamap(arg, segs, nsegs, err); 1331138422Sscottl 1332138422Sscottl if (ac->ac_flags & AMR_CMD_DATAIN) 1333138422Sscottl bus_dmamap_sync(sc->amr_buffer_dmat,ac->ac_dmamap,BUS_DMASYNC_PREREAD); 1334138422Sscottl if (ac->ac_flags & AMR_CMD_DATAOUT) 1335138422Sscottl bus_dmamap_sync(sc->amr_buffer_dmat,ac->ac_dmamap,BUS_DMASYNC_PREWRITE); 1336138422Sscottl ac->ac_flags |= AMR_CMD_MAPPED; 1337138422Sscottl 1338138422Sscottl amr_start1(sc, ac); 1339138422Sscottl} 1340138422Sscottl 134151974Smsmith/******************************************************************************** 134265245Smsmith * Take a command and give it to the controller, returns 0 if successful, or 134365245Smsmith * EBUSY if the command should be retried later. 134451974Smsmith */ 134551974Smsmithstatic int 134651974Smsmithamr_start(struct amr_command *ac) 134751974Smsmith{ 1348138422Sscottl struct amr_softc *sc; 1349138422Sscottl int error = 0; 1350105419Semoore 135169319Smsmith debug_called(3); 135251974Smsmith 135365245Smsmith /* mark command as busy so that polling consumer can tell */ 1354138422Sscottl sc = ac->ac_sc; 135565245Smsmith ac->ac_flags |= AMR_CMD_BUSY; 135665245Smsmith 135765245Smsmith /* get a command slot (freed in amr_done) */ 1358140340Sscottl if (amr_getslot(ac)) { 135965245Smsmith return(EBUSY); 1360140340Sscottl } 136165245Smsmith 1362138422Sscottl /* Now we have a slot, we can map the command (unmapped in amr_complete). */ 1363138422Sscottl if ((error = amr_mapcmd(ac)) == ENOMEM) { 1364138422Sscottl /* 1365138422Sscottl * Memroy resources are short, so free the slot and let this be tried 1366138422Sscottl * later. 1367138422Sscottl */ 1368138422Sscottl sc->amr_busycmd[ac->ac_slot] = NULL; 1369138422Sscottl sc->amr_busyslots--; 1370138422Sscottl } 137165245Smsmith 1372138422Sscottl return (error); 1373138422Sscottl} 1374138422Sscottl 1375138422Sscottl 1376138422Sscottlstatic int 1377138422Sscottlamr_start1(struct amr_softc *sc, struct amr_command *ac) 1378138422Sscottl{ 1379138422Sscottl int done, s, i; 1380138422Sscottl 138165245Smsmith /* mark the new mailbox we are going to copy in as busy */ 138265245Smsmith ac->ac_mailbox.mb_busy = 1; 138365245Smsmith 138465245Smsmith /* clear the poll/ack fields in the mailbox */ 138565245Smsmith sc->amr_mailbox->mb_poll = 0; 138665245Smsmith sc->amr_mailbox->mb_ack = 0; 138765245Smsmith 138851974Smsmith /* 138951974Smsmith * Save the slot number so that we can locate this command when complete. 139051974Smsmith * Note that ident = 0 seems to be special, so we don't use it. 139151974Smsmith */ 139251974Smsmith ac->ac_mailbox.mb_ident = ac->ac_slot + 1; 139351974Smsmith 139458883Smsmith /* 139565245Smsmith * Spin waiting for the mailbox, give up after ~1 second. We expect the 139665245Smsmith * controller to be able to handle our I/O. 139765245Smsmith * 139865245Smsmith * XXX perhaps we should wait for less time, and count on the deferred command 139965245Smsmith * handling to deal with retries? 140058883Smsmith */ 140169319Smsmith debug(4, "wait for mailbox"); 140258883Smsmith for (i = 10000, done = 0; (i > 0) && !done; i--) { 140351974Smsmith s = splbio(); 140451974Smsmith 140551974Smsmith /* is the mailbox free? */ 140651974Smsmith if (sc->amr_mailbox->mb_busy == 0) { 140769319Smsmith debug(4, "got mailbox"); 140851974Smsmith sc->amr_mailbox64->mb64_segment = 0; 140965245Smsmith bcopy(&ac->ac_mailbox, (void *)(uintptr_t)(volatile void *)sc->amr_mailbox, AMR_MBOX_CMDSIZE); 141051974Smsmith done = 1; 141151974Smsmith 141265245Smsmith /* not free, spin waiting */ 141351974Smsmith } else { 141469319Smsmith debug(4, "busy flag %x\n", sc->amr_mailbox->mb_busy); 141558883Smsmith /* this is somewhat ugly */ 141658883Smsmith DELAY(100); 141751974Smsmith } 141858883Smsmith splx(s); /* drop spl to allow completion interrupts */ 141951974Smsmith } 142065245Smsmith 142165245Smsmith /* 142265245Smsmith * Now give the command to the controller 142365245Smsmith */ 142451974Smsmith if (done) { 142565245Smsmith if (sc->amr_submit_command(sc)) { 142665245Smsmith /* the controller wasn't ready to take the command, forget that we tried to post it */ 142765245Smsmith sc->amr_mailbox->mb_busy = 0; 142865245Smsmith return(EBUSY); 142965245Smsmith } 143069319Smsmith debug(3, "posted command"); 143151974Smsmith return(0); 143251974Smsmith } 143351974Smsmith 143451974Smsmith /* 143565245Smsmith * The controller wouldn't take the command. Return the command as busy 143665245Smsmith * so that it is retried later. 143751974Smsmith */ 143865245Smsmith return(EBUSY); 143951974Smsmith} 144051974Smsmith 144151974Smsmith/******************************************************************************** 144251974Smsmith * Extract one or more completed commands from the controller (sc) 144351974Smsmith * 144452543Smsmith * Returns nonzero if any commands on the work queue were marked as completed. 144551974Smsmith */ 1446140340Sscottl 144765245Smsmithint 144851974Smsmithamr_done(struct amr_softc *sc) 144951974Smsmith{ 145051974Smsmith struct amr_command *ac; 145151974Smsmith struct amr_mailbox mbox; 145265245Smsmith int i, idx, result; 145351974Smsmith 145469319Smsmith debug_called(3); 145551974Smsmith 145651974Smsmith /* See if there's anything for us to do */ 145751974Smsmith result = 0; 145851974Smsmith 145958883Smsmith /* loop collecting completed commands */ 146058883Smsmith for (;;) { 146158883Smsmith /* poll for a completed command's identifier and status */ 146258883Smsmith if (sc->amr_get_work(sc, &mbox)) { 146358883Smsmith result = 1; 146458883Smsmith 146558883Smsmith /* iterate over completed commands in this result */ 146658883Smsmith for (i = 0; i < mbox.mb_nstatus; i++) { 146758883Smsmith /* get pointer to busy command */ 146858883Smsmith idx = mbox.mb_completed[i] - 1; 146958883Smsmith ac = sc->amr_busycmd[idx]; 147051974Smsmith 147158883Smsmith /* really a busy command? */ 147258883Smsmith if (ac != NULL) { 147358883Smsmith 147458883Smsmith /* pull the command from the busy index */ 147558883Smsmith sc->amr_busycmd[idx] = NULL; 147665245Smsmith sc->amr_busyslots--; 147751974Smsmith 147865245Smsmith /* save status for later use */ 147965245Smsmith ac->ac_status = mbox.mb_status; 148065245Smsmith amr_enqueue_completed(ac); 148165245Smsmith debug(3, "completed command with status %x", mbox.mb_status); 148265245Smsmith } else { 148365245Smsmith device_printf(sc->amr_dev, "bad slot %d completed\n", idx); 148451974Smsmith } 148551974Smsmith } 148658883Smsmith } else { 148765245Smsmith break; /* no work */ 148851974Smsmith } 148951974Smsmith } 1490138422Sscottl 149158883Smsmith /* handle completion and timeouts */ 1492140340Sscottl amr_complete(sc, 0); 1493138422Sscottl 149451974Smsmith return(result); 149551974Smsmith} 149651974Smsmith 149751974Smsmith/******************************************************************************** 149851974Smsmith * Do completion processing on done commands on (sc) 149951974Smsmith */ 1500140340Sscottl 150151974Smsmithstatic void 150265245Smsmithamr_complete(void *context, int pending) 150351974Smsmith{ 150465245Smsmith struct amr_softc *sc = (struct amr_softc *)context; 150565245Smsmith struct amr_command *ac; 150651974Smsmith 150769319Smsmith debug_called(3); 150851974Smsmith 150965245Smsmith /* pull completed commands off the queue */ 151065245Smsmith for (;;) { 151165245Smsmith ac = amr_dequeue_completed(sc); 151265245Smsmith if (ac == NULL) 151365245Smsmith break; 151458883Smsmith 151565245Smsmith /* unmap the command's data buffer */ 151665245Smsmith amr_unmapcmd(ac); 151751974Smsmith 151865245Smsmith /* unbusy the command */ 151965245Smsmith ac->ac_flags &= ~AMR_CMD_BUSY; 152051974Smsmith 152165245Smsmith /* 152265245Smsmith * Is there a completion handler? 152365245Smsmith */ 152465245Smsmith if (ac->ac_complete != NULL) { 152565245Smsmith ac->ac_complete(ac); 152665245Smsmith 152751974Smsmith /* 152865245Smsmith * Is someone sleeping on this one? 152951974Smsmith */ 153065245Smsmith } else if (ac->ac_flags & AMR_CMD_SLEEP) { 153165245Smsmith wakeup(ac); 153251974Smsmith } 1533109031Semoore 1534109031Semoore if(!sc->amr_busyslots) { 1535109031Semoore wakeup(sc); 1536109031Semoore } 153751974Smsmith } 1538140340Sscottl 1539140340Sscottl sc->amr_state &= ~AMR_STATE_QUEUE_FRZN; 1540140340Sscottl amr_startio(sc); 154151974Smsmith} 154251974Smsmith 154351974Smsmith/******************************************************************************** 154451974Smsmith ******************************************************************************** 154551974Smsmith Command Buffer Management 154651974Smsmith ******************************************************************************** 154751974Smsmith ********************************************************************************/ 154851974Smsmith 154951974Smsmith/******************************************************************************** 155051974Smsmith * Get a new command buffer. 155151974Smsmith * 155251974Smsmith * This may return NULL in low-memory cases. 155351974Smsmith * 155451974Smsmith * If possible, we recycle a command buffer that's been used before. 155551974Smsmith */ 155665245Smsmithstruct amr_command * 155751974Smsmithamr_alloccmd(struct amr_softc *sc) 155851974Smsmith{ 155951974Smsmith struct amr_command *ac; 156051974Smsmith 156165245Smsmith debug_called(3); 156251974Smsmith 156365245Smsmith ac = amr_dequeue_free(sc); 156451974Smsmith if (ac == NULL) { 156565245Smsmith amr_alloccmd_cluster(sc); 156665245Smsmith ac = amr_dequeue_free(sc); 156751974Smsmith } 1568140340Sscottl if (ac == NULL) { 1569140340Sscottl sc->amr_state |= AMR_STATE_QUEUE_FRZN; 157065245Smsmith return(NULL); 1571140340Sscottl } 157265245Smsmith 157365245Smsmith /* clear out significant fields */ 157465245Smsmith ac->ac_status = 0; 157551974Smsmith bzero(&ac->ac_mailbox, sizeof(struct amr_mailbox)); 157665245Smsmith ac->ac_flags = 0; 157765245Smsmith ac->ac_bio = NULL; 157865245Smsmith ac->ac_data = NULL; 157965245Smsmith ac->ac_ccb_data = NULL; 158065245Smsmith ac->ac_complete = NULL; 158151974Smsmith return(ac); 158251974Smsmith} 158351974Smsmith 158451974Smsmith/******************************************************************************** 158551974Smsmith * Release a command buffer for recycling. 158651974Smsmith */ 158765245Smsmithvoid 158851974Smsmithamr_releasecmd(struct amr_command *ac) 158951974Smsmith{ 159065245Smsmith debug_called(3); 159151974Smsmith 159265245Smsmith amr_enqueue_free(ac); 159351974Smsmith} 159451974Smsmith 159551974Smsmith/******************************************************************************** 159665245Smsmith * Allocate a new command cluster and initialise it. 159751974Smsmith */ 1598104094Sphkstatic void 159965245Smsmithamr_alloccmd_cluster(struct amr_softc *sc) 160051974Smsmith{ 160165245Smsmith struct amr_command_cluster *acc; 160265245Smsmith struct amr_command *ac; 1603140340Sscottl int s, i, nextslot; 160451974Smsmith 1605140340Sscottl if (sc->amr_nextslot > sc->amr_maxio) 1606140340Sscottl return; 1607140340Sscottl acc = malloc(AMR_CMD_CLUSTERSIZE, M_DEVBUF, M_NOWAIT | M_ZERO); 160865245Smsmith if (acc != NULL) { 160965245Smsmith s = splbio(); 1610140340Sscottl nextslot = sc->amr_nextslot; 161165245Smsmith TAILQ_INSERT_TAIL(&sc->amr_cmd_clusters, acc, acc_link); 161265245Smsmith splx(s); 161365245Smsmith for (i = 0; i < AMR_CMD_CLUSTERCOUNT; i++) { 161465245Smsmith ac = &acc->acc_command[i]; 161565245Smsmith ac->ac_sc = sc; 1616140340Sscottl ac->ac_slot = nextslot; 161765245Smsmith if (!bus_dmamap_create(sc->amr_buffer_dmat, 0, &ac->ac_dmamap) && 161865245Smsmith !bus_dmamap_create(sc->amr_buffer_dmat, 0, &ac->ac_ccb_dmamap)) 161965245Smsmith amr_releasecmd(ac); 1620140340Sscottl if (++nextslot > sc->amr_maxio) 1621140340Sscottl break; 162265245Smsmith } 1623140340Sscottl sc->amr_nextslot = nextslot; 162465245Smsmith } 162551974Smsmith} 162651974Smsmith 162751974Smsmith/******************************************************************************** 162865245Smsmith * Free a command cluster 162965245Smsmith */ 1630104094Sphkstatic void 163165245Smsmithamr_freecmd_cluster(struct amr_command_cluster *acc) 163265245Smsmith{ 163365245Smsmith struct amr_softc *sc = acc->acc_command[0].ac_sc; 163465245Smsmith int i; 163565245Smsmith 163665245Smsmith for (i = 0; i < AMR_CMD_CLUSTERCOUNT; i++) 163765245Smsmith bus_dmamap_destroy(sc->amr_buffer_dmat, acc->acc_command[i].ac_dmamap); 163865245Smsmith free(acc, M_DEVBUF); 163965245Smsmith} 164065245Smsmith 164165245Smsmith/******************************************************************************** 164251974Smsmith ******************************************************************************** 164351974Smsmith Interface-specific Shims 164451974Smsmith ******************************************************************************** 164551974Smsmith ********************************************************************************/ 164651974Smsmith 164751974Smsmith/******************************************************************************** 164851974Smsmith * Tell the controller that the mailbox contains a valid command 164951974Smsmith */ 165065245Smsmithstatic int 165151974Smsmithamr_quartz_submit_command(struct amr_softc *sc) 165251974Smsmith{ 165365245Smsmith debug_called(3); 165451974Smsmith 165565245Smsmith if (AMR_QGET_IDB(sc) & AMR_QIDB_SUBMIT) 165665245Smsmith return(EBUSY); 165751974Smsmith AMR_QPUT_IDB(sc, sc->amr_mailboxphys | AMR_QIDB_SUBMIT); 165865245Smsmith return(0); 165951974Smsmith} 166051974Smsmith 166165245Smsmithstatic int 166251974Smsmithamr_std_submit_command(struct amr_softc *sc) 166351974Smsmith{ 166465245Smsmith debug_called(3); 166551974Smsmith 166665245Smsmith if (AMR_SGET_MBSTAT(sc) & AMR_SMBOX_BUSYFLAG) 166765245Smsmith return(EBUSY); 166851974Smsmith AMR_SPOST_COMMAND(sc); 166965245Smsmith return(0); 167051974Smsmith} 167151974Smsmith 167251974Smsmith/******************************************************************************** 167351974Smsmith * Claim any work that the controller has completed; acknowledge completion, 167451974Smsmith * save details of the completion in (mbsave) 167551974Smsmith */ 167651974Smsmithstatic int 167751974Smsmithamr_quartz_get_work(struct amr_softc *sc, struct amr_mailbox *mbsave) 167851974Smsmith{ 167951974Smsmith int s, worked; 168051974Smsmith u_int32_t outd; 1681140340Sscottl u_int8_t nstatus; 168251974Smsmith 168365245Smsmith debug_called(3); 168465245Smsmith 168551974Smsmith worked = 0; 168651974Smsmith s = splbio(); 168751974Smsmith 168851974Smsmith /* work waiting for us? */ 168951974Smsmith if ((outd = AMR_QGET_ODB(sc)) == AMR_QODB_READY) { 169051974Smsmith 1691140340Sscottl /* acknowledge interrupt */ 1692140340Sscottl AMR_QPUT_ODB(sc, AMR_QODB_READY); 1693140340Sscottl 1694140340Sscottl while ((nstatus = sc->amr_mailbox->mb_nstatus) == 0xff) 1695140340Sscottl ; 1696140340Sscottl sc->amr_mailbox->mb_nstatus = 0xff; 1697140340Sscottl 169851974Smsmith /* save mailbox, which contains a list of completed commands */ 169965245Smsmith bcopy((void *)(uintptr_t)(volatile void *)sc->amr_mailbox, mbsave, sizeof(*mbsave)); 1700140340Sscottl mbsave->mb_nstatus = nstatus; 170151974Smsmith 170251974Smsmith /* acknowledge that we have the commands */ 1703140340Sscottl AMR_QPUT_IDB(sc, AMR_QIDB_ACK); 170465245Smsmith 170565763Smsmith#ifndef AMR_QUARTZ_GOFASTER 170665245Smsmith /* 170765245Smsmith * This waits for the controller to notice that we've taken the 170865245Smsmith * command from it. It's very inefficient, and we shouldn't do it, 170965245Smsmith * but if we remove this code, we stop completing commands under 171065245Smsmith * load. 171165245Smsmith * 171265245Smsmith * Peter J says we shouldn't do this. The documentation says we 171365245Smsmith * should. Who is right? 171465245Smsmith */ 171551974Smsmith while(AMR_QGET_IDB(sc) & AMR_QIDB_ACK) 171651974Smsmith ; /* XXX aiee! what if it dies? */ 171765245Smsmith#endif 171865245Smsmith 171951974Smsmith worked = 1; /* got some work */ 172051974Smsmith } 172151974Smsmith 172251974Smsmith splx(s); 172351974Smsmith return(worked); 172451974Smsmith} 172551974Smsmith 172651974Smsmithstatic int 172751974Smsmithamr_std_get_work(struct amr_softc *sc, struct amr_mailbox *mbsave) 172851974Smsmith{ 172951974Smsmith int s, worked; 173051974Smsmith u_int8_t istat; 173151974Smsmith 173265245Smsmith debug_called(3); 173351974Smsmith 173451974Smsmith worked = 0; 173551974Smsmith s = splbio(); 173651974Smsmith 173751974Smsmith /* check for valid interrupt status */ 173851974Smsmith istat = AMR_SGET_ISTAT(sc); 173951974Smsmith if ((istat & AMR_SINTR_VALID) != 0) { 174051974Smsmith AMR_SPUT_ISTAT(sc, istat); /* ack interrupt status */ 174151974Smsmith 174251974Smsmith /* save mailbox, which contains a list of completed commands */ 174365245Smsmith bcopy((void *)(uintptr_t)(volatile void *)sc->amr_mailbox, mbsave, sizeof(*mbsave)); 174451974Smsmith 174551974Smsmith AMR_SACK_INTERRUPT(sc); /* acknowledge we have the mailbox */ 174651974Smsmith worked = 1; 174751974Smsmith } 174851974Smsmith 174951974Smsmith splx(s); 175051974Smsmith return(worked); 175151974Smsmith} 175251974Smsmith 175351974Smsmith/******************************************************************************** 175451974Smsmith * Notify the controller of the mailbox location. 175551974Smsmith */ 175651974Smsmithstatic void 175751974Smsmithamr_std_attach_mailbox(struct amr_softc *sc) 175851974Smsmith{ 175951974Smsmith 176051974Smsmith /* program the mailbox physical address */ 176151974Smsmith AMR_SBYTE_SET(sc, AMR_SMBOX_0, sc->amr_mailboxphys & 0xff); 176251974Smsmith AMR_SBYTE_SET(sc, AMR_SMBOX_1, (sc->amr_mailboxphys >> 8) & 0xff); 176351974Smsmith AMR_SBYTE_SET(sc, AMR_SMBOX_2, (sc->amr_mailboxphys >> 16) & 0xff); 176451974Smsmith AMR_SBYTE_SET(sc, AMR_SMBOX_3, (sc->amr_mailboxphys >> 24) & 0xff); 176551974Smsmith AMR_SBYTE_SET(sc, AMR_SMBOX_ENABLE, AMR_SMBOX_ADDR); 176651974Smsmith 176751974Smsmith /* clear any outstanding interrupt and enable interrupts proper */ 176851974Smsmith AMR_SACK_INTERRUPT(sc); 176951974Smsmith AMR_SENABLE_INTR(sc); 177051974Smsmith} 177151974Smsmith 177265245Smsmith#ifdef AMR_BOARD_INIT 177351974Smsmith/******************************************************************************** 177465245Smsmith * Initialise the controller 177565245Smsmith */ 177665245Smsmithstatic int 177765245Smsmithamr_quartz_init(struct amr_softc *sc) 177865245Smsmith{ 177965245Smsmith int status, ostatus; 178065245Smsmith 178165245Smsmith device_printf(sc->amr_dev, "initial init status %x\n", AMR_QGET_INITSTATUS(sc)); 178265245Smsmith 178365245Smsmith AMR_QRESET(sc); 178465245Smsmith 178565245Smsmith ostatus = 0xff; 178665245Smsmith while ((status = AMR_QGET_INITSTATUS(sc)) != AMR_QINIT_DONE) { 178765245Smsmith if (status != ostatus) { 178865245Smsmith device_printf(sc->amr_dev, "(%x) %s\n", status, amr_describe_code(amr_table_qinit, status)); 178965245Smsmith ostatus = status; 179065245Smsmith } 179165245Smsmith switch (status) { 179265245Smsmith case AMR_QINIT_NOMEM: 179365245Smsmith return(ENOMEM); 179465245Smsmith 179565245Smsmith case AMR_QINIT_SCAN: 179665245Smsmith /* XXX we could print channel/target here */ 179765245Smsmith break; 179865245Smsmith } 179965245Smsmith } 180065245Smsmith return(0); 180165245Smsmith} 180265245Smsmith 180365245Smsmithstatic int 180465245Smsmithamr_std_init(struct amr_softc *sc) 180565245Smsmith{ 180665245Smsmith int status, ostatus; 180765245Smsmith 180865245Smsmith device_printf(sc->amr_dev, "initial init status %x\n", AMR_SGET_INITSTATUS(sc)); 180965245Smsmith 181065245Smsmith AMR_SRESET(sc); 181165245Smsmith 181265245Smsmith ostatus = 0xff; 181365245Smsmith while ((status = AMR_SGET_INITSTATUS(sc)) != AMR_SINIT_DONE) { 181465245Smsmith if (status != ostatus) { 181565245Smsmith device_printf(sc->amr_dev, "(%x) %s\n", status, amr_describe_code(amr_table_sinit, status)); 181665245Smsmith ostatus = status; 181765245Smsmith } 181865245Smsmith switch (status) { 181965245Smsmith case AMR_SINIT_NOMEM: 182065245Smsmith return(ENOMEM); 182165245Smsmith 182265245Smsmith case AMR_SINIT_INPROG: 182365245Smsmith /* XXX we could print channel/target here? */ 182465245Smsmith break; 182565245Smsmith } 182665245Smsmith } 182765245Smsmith return(0); 182865245Smsmith} 182965245Smsmith#endif 183065245Smsmith 183165245Smsmith/******************************************************************************** 183251974Smsmith ******************************************************************************** 183351974Smsmith Debugging 183451974Smsmith ******************************************************************************** 183551974Smsmith ********************************************************************************/ 183651974Smsmith 183751974Smsmith/******************************************************************************** 183865245Smsmith * Identify the controller and print some information about it. 183965245Smsmith */ 184065245Smsmithstatic void 184165245Smsmithamr_describe_controller(struct amr_softc *sc) 184265245Smsmith{ 184365245Smsmith struct amr_prodinfo *ap; 184465245Smsmith struct amr_enquiry *ae; 184565245Smsmith char *prod; 184665245Smsmith 1847140340Sscottl mtx_lock(&sc->amr_io_lock); 184865245Smsmith /* 184965245Smsmith * Try to get 40LD product info, which tells us what the card is labelled as. 185065245Smsmith */ 185165245Smsmith if ((ap = amr_enquiry(sc, 2048, AMR_CMD_CONFIG, AMR_CONFIG_PRODUCT_INFO, 0)) != NULL) { 1852105419Semoore device_printf(sc->amr_dev, "<LSILogic %.80s> Firmware %.16s, BIOS %.16s, %dMB RAM\n", 185365245Smsmith ap->ap_product, ap->ap_firmware, ap->ap_bios, 185465245Smsmith ap->ap_memsize); 185565245Smsmith 185665245Smsmith free(ap, M_DEVBUF); 1857140340Sscottl mtx_unlock(&sc->amr_io_lock); 185865245Smsmith return; 185965245Smsmith } 186065245Smsmith 186165245Smsmith /* 186265245Smsmith * Try 8LD extended ENQUIRY to get controller signature, and use lookup table. 186365245Smsmith */ 186465245Smsmith if ((ae = (struct amr_enquiry *)amr_enquiry(sc, 2048, AMR_CMD_EXT_ENQUIRY2, 0, 0)) != NULL) { 186565245Smsmith prod = amr_describe_code(amr_table_adaptertype, ae->ae_signature); 186665245Smsmith 186765245Smsmith } else if ((ae = (struct amr_enquiry *)amr_enquiry(sc, 2048, AMR_CMD_ENQUIRY, 0, 0)) != NULL) { 186865245Smsmith 186965245Smsmith /* 187065245Smsmith * Try to work it out based on the PCI signatures. 187165245Smsmith */ 187265245Smsmith switch (pci_get_device(sc->amr_dev)) { 187365245Smsmith case 0x9010: 187465245Smsmith prod = "Series 428"; 187565245Smsmith break; 187665245Smsmith case 0x9060: 187765245Smsmith prod = "Series 434"; 187865245Smsmith break; 187965245Smsmith default: 188065245Smsmith prod = "unknown controller"; 188165245Smsmith break; 188265245Smsmith } 188365245Smsmith } else { 188465245Smsmith prod = "unsupported controller"; 188565245Smsmith } 188674936Shm 188774936Shm /* 188874936Shm * HP NetRaid controllers have a special encoding of the firmware and 188974936Shm * BIOS versions. The AMI version seems to have it as strings whereas 189074936Shm * the HP version does it with a leading uppercase character and two 189174936Shm * binary numbers. 189274936Shm */ 189374936Shm 189474936Shm if(ae->ae_adapter.aa_firmware[2] >= 'A' && 189574936Shm ae->ae_adapter.aa_firmware[2] <= 'Z' && 189674936Shm ae->ae_adapter.aa_firmware[1] < ' ' && 189774936Shm ae->ae_adapter.aa_firmware[0] < ' ' && 189874936Shm ae->ae_adapter.aa_bios[2] >= 'A' && 189974936Shm ae->ae_adapter.aa_bios[2] <= 'Z' && 190074936Shm ae->ae_adapter.aa_bios[1] < ' ' && 190174936Shm ae->ae_adapter.aa_bios[0] < ' ') { 190274936Shm 190374936Shm /* this looks like we have an HP NetRaid version of the MegaRaid */ 190474936Shm 190574936Shm if(ae->ae_signature == AMR_SIG_438) { 1906108470Sschweikh /* the AMI 438 is a NetRaid 3si in HP-land */ 190774936Shm prod = "HP NetRaid 3si"; 190874936Shm } 190974936Shm 191074936Shm device_printf(sc->amr_dev, "<%s> Firmware %c.%02d.%02d, BIOS %c.%02d.%02d, %dMB RAM\n", 191174936Shm prod, ae->ae_adapter.aa_firmware[2], 191274936Shm ae->ae_adapter.aa_firmware[1], 191374936Shm ae->ae_adapter.aa_firmware[0], 191474936Shm ae->ae_adapter.aa_bios[2], 191574936Shm ae->ae_adapter.aa_bios[1], 191674936Shm ae->ae_adapter.aa_bios[0], 191774936Shm ae->ae_adapter.aa_memorysize); 191874936Shm } else { 191974936Shm device_printf(sc->amr_dev, "<%s> Firmware %.4s, BIOS %.4s, %dMB RAM\n", 192074936Shm prod, ae->ae_adapter.aa_firmware, ae->ae_adapter.aa_bios, 192174936Shm ae->ae_adapter.aa_memorysize); 192274936Shm } 192365245Smsmith free(ae, M_DEVBUF); 1924140340Sscottl mtx_unlock(&sc->amr_io_lock); 192565245Smsmith} 192665245Smsmith 1927120988Spsint 1928120988Spsamr_dump_blocks(struct amr_softc *sc, int unit, u_int32_t lba, void *data, int blks) 1929120988Sps{ 1930120988Sps struct amr_command *ac; 1931120988Sps int error = EIO; 1932120988Sps 1933120988Sps debug_called(1); 1934120988Sps 1935140688Sscottl sc->amr_state |= AMR_STATE_INTEN; 1936120988Sps 1937120988Sps /* get ourselves a command buffer */ 1938120988Sps if ((ac = amr_alloccmd(sc)) == NULL) 1939120988Sps goto out; 1940120988Sps /* set command flags */ 1941120988Sps ac->ac_flags |= AMR_CMD_PRIORITY | AMR_CMD_DATAOUT; 1942120988Sps 1943120988Sps /* point the command at our data */ 1944120988Sps ac->ac_data = data; 1945120988Sps ac->ac_length = blks * AMR_BLKSIZE; 1946120988Sps 1947120988Sps /* build the command proper */ 1948120988Sps ac->ac_mailbox.mb_command = AMR_CMD_LWRITE; 1949120988Sps ac->ac_mailbox.mb_blkcount = blks; 1950120988Sps ac->ac_mailbox.mb_lba = lba; 1951120988Sps ac->ac_mailbox.mb_drive = unit; 1952120988Sps 1953120988Sps /* can't assume that interrupts are going to work here, so play it safe */ 1954120988Sps if (sc->amr_poll_command(ac)) 1955120988Sps goto out; 1956120988Sps error = ac->ac_status; 1957120988Sps 1958120988Sps out: 1959120988Sps if (ac != NULL) 1960120988Sps amr_releasecmd(ac); 1961120988Sps 1962140688Sscottl sc->amr_state &= ~AMR_STATE_INTEN; 1963120988Sps return (error); 1964120988Sps} 1965120988Sps 1966120988Sps 1967120988Sps 196865245Smsmith#ifdef AMR_DEBUG 196965245Smsmith/******************************************************************************** 197051974Smsmith * Print the command (ac) in human-readable format 197151974Smsmith */ 1972107756Semoore#if 0 197351974Smsmithstatic void 197451974Smsmithamr_printcommand(struct amr_command *ac) 197551974Smsmith{ 197651974Smsmith struct amr_softc *sc = ac->ac_sc; 197751974Smsmith struct amr_sgentry *sg; 197851974Smsmith int i; 197951974Smsmith 198051974Smsmith device_printf(sc->amr_dev, "cmd %x ident %d drive %d\n", 198151974Smsmith ac->ac_mailbox.mb_command, ac->ac_mailbox.mb_ident, ac->ac_mailbox.mb_drive); 198251974Smsmith device_printf(sc->amr_dev, "blkcount %d lba %d\n", 198351974Smsmith ac->ac_mailbox.mb_blkcount, ac->ac_mailbox.mb_lba); 198454512Speter device_printf(sc->amr_dev, "virtaddr %p length %lu\n", ac->ac_data, (unsigned long)ac->ac_length); 198558883Smsmith device_printf(sc->amr_dev, "sg physaddr %08x nsg %d\n", 198651974Smsmith ac->ac_mailbox.mb_physaddr, ac->ac_mailbox.mb_nsgelem); 198765245Smsmith device_printf(sc->amr_dev, "ccb %p bio %p\n", ac->ac_ccb_data, ac->ac_bio); 198851974Smsmith 198951974Smsmith /* get base address of s/g table */ 199051974Smsmith sg = sc->amr_sgtable + (ac->ac_slot * AMR_NSEG); 199151974Smsmith for (i = 0; i < ac->ac_mailbox.mb_nsgelem; i++, sg++) 199251974Smsmith device_printf(sc->amr_dev, " %x/%d\n", sg->sg_addr, sg->sg_count); 199351974Smsmith} 199465245Smsmith#endif 1995107756Semoore#endif 1996