ciss.c revision 172608
158314Sache/*-
221308Sache * Copyright (c) 2001 Michael Smith
321308Sache * Copyright (c) 2004 Paul Saab
4165675Sache * All rights reserved.
521308Sache *
621308Sache * Redistribution and use in source and binary forms, with or without
721308Sache * modification, are permitted provided that the following conditions
821308Sache * are met:
921308Sache * 1. Redistributions of source code must retain the above copyright
1021308Sache *    notice, this list of conditions and the following disclaimer.
1158314Sache * 2. Redistributions in binary form must reproduce the above copyright
1221308Sache *    notice, this list of conditions and the following disclaimer in the
1321308Sache *    documentation and/or other materials provided with the distribution.
1421308Sache *
1521308Sache * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1621308Sache * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1721308Sache * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1821308Sache * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1921308Sache * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2021308Sache * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2121308Sache * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2258314Sache * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2321308Sache * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2421308Sache * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2521308Sache * SUCH DAMAGE.
2621308Sache *
2721308Sache *	$FreeBSD: head/sys/dev/ciss/ciss.c 172608 2007-10-13 05:45:45Z iwasaki $
2821308Sache */
2921308Sache
3021308Sache/*
3121308Sache * Common Interface for SCSI-3 Support driver.
3221308Sache *
3321308Sache * CISS claims to provide a common interface between a generic SCSI
3421308Sache * transport and an intelligent host adapter.
3526497Sache *
3626497Sache * This driver supports CISS as defined in the document "CISS Command
3721308Sache * Interface for SCSI-3 Support Open Specification", Version 1.04,
3821308Sache * Valence Number 1, dated 20001127, produced by Compaq Computer
3921308Sache * Corporation.  This document appears to be a hastily and somewhat
4021308Sache * arbitrarlily cut-down version of a larger (and probably even more
4121308Sache * chaotic and inconsistent) Compaq internal document.  Various
4221308Sache * details were also gleaned from Compaq's "cciss" driver for Linux.
4326497Sache *
4421308Sache * We provide a shim layer between the CISS interface and CAM,
4521308Sache * offloading most of the queueing and being-a-disk chores onto CAM.
4621308Sache * Entry to the driver is via the PCI bus attachment (ciss_probe,
47119614Sache * ciss_attach, etc) and via the CAM interface (ciss_cam_action,
4821308Sache * ciss_cam_poll).  The Compaq CISS adapters are, however, poor SCSI
4921308Sache * citizens and we have to fake up some responses to get reasonable
5021308Sache * behaviour out of them.  In addition, the CISS command set is by no
5121308Sache * means adequate to support the functionality of a RAID controller,
5221308Sache * and thus the supported Compaq adapters utilise portions of the
5321308Sache * control protocol from earlier Compaq adapter families.
5421308Sache *
5521308Sache * Note that we only support the "simple" transport layer over PCI.
5658314Sache * This interface (ab)uses the I2O register set (specifically the post
5758314Sache * queues) to exchange commands with the adapter.  Other interfaces
5858314Sache * are available, but we aren't supposed to know about them, and it is
5921308Sache * dubious whether they would provide major performance improvements
6021308Sache * except under extreme load.
6121308Sache *
6221308Sache * Currently the only supported CISS adapters are the Compaq Smart
63119614Sache * Array 5* series (5300, 5i, 532).  Even with only three adapters,
64119614Sache * Compaq still manage to have interface variations.
65119614Sache *
66119614Sache *
67119614Sache * Thanks must go to Fred Harris and Darryl DeVinney at Compaq, as
6821308Sache * well as Paul Saab at Yahoo! for their assistance in making this
69119614Sache * driver happen.
70136759Speter *
71119614Sache * More thanks must go to John Cagle at HP for the countless hours
72119614Sache * spent making this driver "work" with the MSA* series storage
73119614Sache * enclosures.  Without his help (and nagging), this driver could not
74119614Sache * be used with these enclosures.
75119614Sache */
7621308Sache
7758314Sache#include <sys/param.h>
7821308Sache#include <sys/systm.h>
7921308Sache#include <sys/malloc.h>
80165675Sache#include <sys/kernel.h>
81165675Sache#include <sys/bus.h>
8221308Sache#include <sys/conf.h>
8321308Sache#include <sys/stat.h>
84165675Sache#include <sys/kthread.h>
85165675Sache#include <sys/queue.h>
86165675Sache#include <sys/sysctl.h>
87165675Sache
88165675Sache#include <cam/cam.h>
89165675Sache#include <cam/cam_ccb.h>
90165675Sache#include <cam/cam_periph.h>
91165675Sache#include <cam/cam_sim.h>
9221308Sache#include <cam/cam_xpt_sim.h>
9321308Sache#include <cam/scsi/scsi_all.h>
9421308Sache#include <cam/scsi/scsi_message.h>
9521308Sache
9621308Sache#include <machine/bus.h>
9721308Sache#include <machine/endian.h>
9821308Sache#include <machine/resource.h>
9921308Sache#include <sys/rman.h>
10021308Sache
10121308Sache#include <dev/pci/pcireg.h>
10221308Sache#include <dev/pci/pcivar.h>
10321308Sache
10421308Sache#include <dev/ciss/cissreg.h>
10521308Sache#include <dev/ciss/cissvar.h>
10621308Sache#include <dev/ciss/cissio.h>
10721308Sache
10821308SacheMALLOC_DEFINE(CISS_MALLOC_CLASS, "ciss_data", "ciss internal data buffers");
10921308Sache
11021308Sache/* pci interface */
11121308Sachestatic int	ciss_lookup(device_t dev);
11221308Sachestatic int	ciss_probe(device_t dev);
11321308Sachestatic int	ciss_attach(device_t dev);
11421308Sachestatic int	ciss_detach(device_t dev);
11521308Sachestatic int	ciss_shutdown(device_t dev);
11621308Sache
11721308Sache/* (de)initialisation functions, control wrappers */
11821308Sachestatic int	ciss_init_pci(struct ciss_softc *sc);
11921308Sachestatic int	ciss_wait_adapter(struct ciss_softc *sc);
12075409Sachestatic int	ciss_flush_adapter(struct ciss_softc *sc);
12121308Sachestatic int	ciss_init_requests(struct ciss_softc *sc);
12221308Sachestatic void	ciss_command_map_helper(void *arg, bus_dma_segment_t *segs,
12321308Sache					int nseg, int error);
12421308Sachestatic int	ciss_identify_adapter(struct ciss_softc *sc);
12521308Sachestatic int	ciss_init_logical(struct ciss_softc *sc);
12621308Sachestatic int	ciss_init_physical(struct ciss_softc *sc);
127157188Sachestatic int	ciss_filter_physical(struct ciss_softc *sc, struct ciss_lun_report *cll);
12821308Sachestatic int	ciss_identify_logical(struct ciss_softc *sc, struct ciss_ldrive *ld);
12921308Sachestatic int	ciss_get_ldrive_status(struct ciss_softc *sc,  struct ciss_ldrive *ld);
13021308Sachestatic int	ciss_update_config(struct ciss_softc *sc);
13121308Sachestatic int	ciss_accept_media(struct ciss_softc *sc, struct ciss_ldrive *ld);
13221308Sachestatic void	ciss_init_sysctl(struct ciss_softc *sc);
13321308Sachestatic void	ciss_soft_reset(struct ciss_softc *sc);
134157188Sachestatic void	ciss_free(struct ciss_softc *sc);
13521308Sachestatic void	ciss_spawn_notify_thread(struct ciss_softc *sc);
136157188Sachestatic void	ciss_kill_notify_thread(struct ciss_softc *sc);
137157188Sache
138157188Sache/* request submission/completion */
139157188Sachestatic int	ciss_start(struct ciss_request *cr);
14021308Sachestatic void	ciss_done(struct ciss_softc *sc);
14121308Sachestatic void	ciss_intr(void *arg);
14221308Sachestatic void	ciss_complete(struct ciss_softc *sc);
143157188Sachestatic int	ciss_report_request(struct ciss_request *cr, int *command_status,
144165675Sache				    int *scsi_status);
145157188Sachestatic int	ciss_synch_request(struct ciss_request *cr, int timeout);
14621308Sachestatic int	ciss_poll_request(struct ciss_request *cr, int timeout);
14721308Sachestatic int	ciss_wait_request(struct ciss_request *cr, int timeout);
14821308Sache#if 0
14921308Sachestatic int	ciss_abort_request(struct ciss_request *cr);
15021308Sache#endif
15121308Sache
15221308Sache/* request queueing */
15321308Sachestatic int	ciss_get_request(struct ciss_softc *sc, struct ciss_request **crp);
15421308Sachestatic void	ciss_preen_command(struct ciss_request *cr);
15521308Sachestatic void 	ciss_release_request(struct ciss_request *cr);
15621308Sache
15721308Sache/* request helpers */
15821308Sachestatic int	ciss_get_bmic_request(struct ciss_softc *sc, struct ciss_request **crp,
15921308Sache				      int opcode, void **bufp, size_t bufsize);
16021308Sachestatic int	ciss_user_command(struct ciss_softc *sc, IOCTL_Command_struct *ioc);
16121308Sache
16221308Sache/* DMA map/unmap */
16321308Sachestatic int	ciss_map_request(struct ciss_request *cr);
16421308Sachestatic void	ciss_request_map_helper(void *arg, bus_dma_segment_t *segs,
16521308Sache					int nseg, int error);
16621308Sachestatic void	ciss_unmap_request(struct ciss_request *cr);
16721308Sache
16875409Sache/* CAM interface */
16975409Sachestatic int	ciss_cam_init(struct ciss_softc *sc);
17075409Sachestatic void	ciss_cam_rescan_target(struct ciss_softc *sc,
17121308Sache				       int bus, int target);
172165675Sachestatic void	ciss_cam_rescan_all(struct ciss_softc *sc);
17375409Sachestatic void	ciss_cam_rescan_callback(struct cam_periph *periph, union ccb *ccb);
17421308Sachestatic void	ciss_cam_action(struct cam_sim *sim, union ccb *ccb);
17521308Sachestatic int	ciss_cam_action_io(struct cam_sim *sim, struct ccb_scsiio *csio);
17621308Sachestatic int	ciss_cam_emulate(struct ciss_softc *sc, struct ccb_scsiio *csio);
17721308Sachestatic void	ciss_cam_poll(struct cam_sim *sim);
17821308Sachestatic void	ciss_cam_complete(struct ciss_request *cr);
17975409Sachestatic void	ciss_cam_complete_fixup(struct ciss_softc *sc, struct ccb_scsiio *csio);
18075409Sachestatic struct cam_periph *ciss_find_periph(struct ciss_softc *sc,
18121308Sache					   int bus, int target);
18221308Sachestatic int	ciss_name_device(struct ciss_softc *sc, int bus, int target);
18375409Sache
18475409Sache/* periodic status monitoring */
18521308Sachestatic void	ciss_periodic(void *arg);
18621308Sachestatic void	ciss_disable_adapter(struct ciss_softc *sc);
18721308Sachestatic void	ciss_notify_event(struct ciss_softc *sc);
18821308Sachestatic void	ciss_notify_complete(struct ciss_request *cr);
18921308Sachestatic int	ciss_notify_abort(struct ciss_softc *sc);
19075409Sachestatic int	ciss_notify_abort_bmic(struct ciss_softc *sc);
19175409Sachestatic void	ciss_notify_hotplug(struct ciss_softc *sc, struct ciss_notify *cn);
19275409Sachestatic void	ciss_notify_logical(struct ciss_softc *sc, struct ciss_notify *cn);
19375409Sachestatic void	ciss_notify_physical(struct ciss_softc *sc, struct ciss_notify *cn);
19475409Sache
19575409Sache/* debugging output */
19675409Sachestatic void	ciss_print_request(struct ciss_request *cr);
197136759Speterstatic void	ciss_print_ldrive(struct ciss_softc *sc, struct ciss_ldrive *ld);
198136759Speterstatic const char *ciss_name_ldrive_status(int status);
199157188Sachestatic int	ciss_decode_ldrive_status(int status);
200157188Sachestatic const char *ciss_name_ldrive_org(int org);
201157188Sachestatic const char *ciss_name_command_status(int status);
202157188Sache
203157188Sache/*
204157188Sache * PCI bus interface.
205157188Sache */
206157188Sachestatic device_method_t ciss_methods[] = {
207157188Sache    /* Device interface */
208165675Sache    DEVMETHOD(device_probe,	ciss_probe),
209157188Sache    DEVMETHOD(device_attach,	ciss_attach),
210157188Sache    DEVMETHOD(device_detach,	ciss_detach),
211157188Sache    DEVMETHOD(device_shutdown,	ciss_shutdown),
21221308Sache    { 0, 0 }
21321308Sache};
21421308Sache
21575409Sachestatic driver_t ciss_pci_driver = {
21675409Sache    "ciss",
217136759Speter    ciss_methods,
218136759Speter    sizeof(struct ciss_softc)
21921308Sache};
22021308Sache
22121308Sachestatic devclass_t	ciss_devclass;
22221308SacheDRIVER_MODULE(ciss, pci, ciss_pci_driver, ciss_devclass, 0, 0);
22321308SacheMODULE_DEPEND(ciss, cam, 1, 1, 1);
22421308SacheMODULE_DEPEND(ciss, pci, 1, 1, 1);
22521308Sache
22621308Sache/*
22721308Sache * Control device interface.
228136759Speter */
22921308Sachestatic d_open_t		ciss_open;
230136759Speterstatic d_close_t	ciss_close;
23121308Sachestatic d_ioctl_t	ciss_ioctl;
232165675Sache
233136759Speterstatic struct cdevsw ciss_cdevsw = {
23421308Sache	.d_version =	D_VERSION,
23521308Sache	.d_flags =	0,
236136759Speter	.d_open =	ciss_open,
23721308Sache	.d_close =	ciss_close,
23821308Sache	.d_ioctl =	ciss_ioctl,
23921308Sache	.d_name =	"ciss",
24021308Sache};
241136759Speter
242136759Speter/*
243136759Speter * This tunable can be set at boot time and controls whether physical devices
244136759Speter * that are marked hidden by the firmware should be exposed anyways.
245136759Speter */
246136759Speterstatic unsigned int ciss_expose_hidden_physical = 0;
24721308SacheTUNABLE_INT("hw.ciss.expose_hidden_physical", &ciss_expose_hidden_physical);
24821308Sache
24921308Sache/************************************************************************
25021308Sache * CISS adapters amazingly don't have a defined programming interface
251119614Sache * value.  (One could say some very despairing things about PCI and
25275409Sache * people just not getting the general idea.)  So we are forced to
25375409Sache * stick with matching against subvendor/subdevice, and thus have to
254136759Speter * be updated for every new CISS adapter that appears.
25575409Sache */
256165675Sache#define CISS_BOARD_SA5	(1<<0)
257136759Speter#define CISS_BOARD_SA5B	(1<<1)
25821308Sache
25921308Sachestatic struct
26021308Sache{
261165675Sache    u_int16_t	subvendor;
26221308Sache    u_int16_t	subdevice;
263165675Sache    int		flags;
264165675Sache    char	*desc;
26521308Sache} ciss_vendor_data[] = {
26621308Sache    { 0x0e11, 0x4070, CISS_BOARD_SA5,	"Compaq Smart Array 5300" },
26721308Sache    { 0x0e11, 0x4080, CISS_BOARD_SA5B,	"Compaq Smart Array 5i" },
26821308Sache    { 0x0e11, 0x4082, CISS_BOARD_SA5B,	"Compaq Smart Array 532" },
26921308Sache    { 0x0e11, 0x4083, CISS_BOARD_SA5B,	"HP Smart Array 5312" },
270165675Sache    { 0x0e11, 0x4091, CISS_BOARD_SA5,	"HP Smart Array 6i" },
271157188Sache    { 0x0e11, 0x409A, CISS_BOARD_SA5,	"HP Smart Array 641" },
27221308Sache    { 0x0e11, 0x409B, CISS_BOARD_SA5,	"HP Smart Array 642" },
27321308Sache    { 0x0e11, 0x409C, CISS_BOARD_SA5,	"HP Smart Array 6400" },
27421308Sache    { 0x0e11, 0x409D, CISS_BOARD_SA5,	"HP Smart Array 6400 EM" },
27521308Sache    { 0x103C, 0x3211, CISS_BOARD_SA5,	"HP Smart Array E200i" },
276136759Speter    { 0x103C, 0x3212, CISS_BOARD_SA5,	"HP Smart Array E200" },
277136759Speter    { 0x103C, 0x3213, CISS_BOARD_SA5,	"HP Smart Array E200i" },
278136759Speter    { 0x103C, 0x3214, CISS_BOARD_SA5,	"HP Smart Array E200i" },
279136759Speter    { 0x103C, 0x3215, CISS_BOARD_SA5,	"HP Smart Array E200i" },
280136759Speter    { 0x103C, 0x3220, CISS_BOARD_SA5,	"HP Smart Array" },
281136759Speter    { 0x103C, 0x3222, CISS_BOARD_SA5,	"HP Smart Array" },
282136759Speter    { 0x103C, 0x3223, CISS_BOARD_SA5,	"HP Smart Array P800" },
283136759Speter    { 0x103C, 0x3225, CISS_BOARD_SA5,	"HP Smart Array P600" },
284136759Speter    { 0x103C, 0x3230, CISS_BOARD_SA5,	"HP Smart Array" },
285136759Speter    { 0x103C, 0x3231, CISS_BOARD_SA5,	"HP Smart Array" },
286136759Speter    { 0x103C, 0x3232, CISS_BOARD_SA5,	"HP Smart Array" },
287136759Speter    { 0x103C, 0x3233, CISS_BOARD_SA5,	"HP Smart Array" },
288136759Speter    { 0x103C, 0x3234, CISS_BOARD_SA5,	"HP Smart Array P400" },
289136759Speter    { 0x103C, 0x3235, CISS_BOARD_SA5,	"HP Smart Array P400i" },
290136759Speter    { 0x103C, 0x3236, CISS_BOARD_SA5,	"HP Smart Array" },
291136759Speter    { 0x103C, 0x3237, CISS_BOARD_SA5,	"HP Smart Array" },
292136759Speter    { 0x103C, 0x3238, CISS_BOARD_SA5,	"HP Smart Array" },
29375409Sache    { 0x103C, 0x3239, CISS_BOARD_SA5,	"HP Smart Array" },
294136759Speter    { 0x103C, 0x323A, CISS_BOARD_SA5,	"HP Smart Array" },
295136759Speter    { 0x103C, 0x323B, CISS_BOARD_SA5,	"HP Smart Array" },
296136759Speter    { 0x103C, 0x323C, CISS_BOARD_SA5,	"HP Smart Array" },
297136759Speter    { 0, 0, 0, NULL }
298136759Speter};
299136759Speter
300136759Speter/************************************************************************
301136759Speter * Find a match for the device in our list of known adapters.
302136759Speter */
303136759Speterstatic int
304136759Speterciss_lookup(device_t dev)
305136759Speter{
306136759Speter    int 	i;
307136759Speter
308136759Speter    for (i = 0; ciss_vendor_data[i].desc != NULL; i++)
309136759Speter	if ((pci_get_subvendor(dev) == ciss_vendor_data[i].subvendor) &&
310136759Speter	    (pci_get_subdevice(dev) == ciss_vendor_data[i].subdevice)) {
31121308Sache	    return(i);
31221308Sache	}
31321308Sache    return(-1);
31475409Sache}
31575409Sache
31675409Sache/************************************************************************
31721308Sache * Match a known CISS adapter.
31821308Sache */
31921308Sachestatic int
32021308Sacheciss_probe(device_t dev)
32121308Sache{
32275409Sache    int		i;
32375409Sache
324136759Speter    i = ciss_lookup(dev);
325136759Speter    if (i != -1) {
32621308Sache	device_set_desc(dev, ciss_vendor_data[i].desc);
32721308Sache	return(BUS_PROBE_DEFAULT);
32821308Sache    }
32958314Sache    return(ENOENT);
33058314Sache}
33158314Sache
33258314Sache/************************************************************************
33358314Sache * Attach the driver to this adapter.
33458314Sache */
33558314Sachestatic int
33658314Sacheciss_attach(device_t dev)
337136759Speter{
33858314Sache    struct ciss_softc	*sc;
33958314Sache    int			i, error;
34058314Sache
34121308Sache    debug_called(1);
34221308Sache
34321308Sache#ifdef CISS_DEBUG
34421308Sache    /* print structure/union sizes */
34521308Sache    debug_struct(ciss_command);
34621308Sache    debug_struct(ciss_header);
34721308Sache    debug_union(ciss_device_address);
34821308Sache    debug_struct(ciss_cdb);
34975409Sache    debug_struct(ciss_report_cdb);
35075409Sache    debug_struct(ciss_notify_cdb);
35121308Sache    debug_struct(ciss_notify);
35221308Sache    debug_struct(ciss_message_cdb);
35321308Sache    debug_struct(ciss_error_info_pointer);
35421308Sache    debug_struct(ciss_error_info);
35521308Sache    debug_struct(ciss_sg_entry);
35621308Sache    debug_struct(ciss_config_table);
35721308Sache    debug_struct(ciss_bmic_cdb);
35821308Sache    debug_struct(ciss_bmic_id_ldrive);
35921308Sache    debug_struct(ciss_bmic_id_lstatus);
36021308Sache    debug_struct(ciss_bmic_id_table);
36121308Sache    debug_struct(ciss_bmic_id_pdrive);
36221308Sache    debug_struct(ciss_bmic_blink_pdrive);
36321308Sache    debug_struct(ciss_bmic_flush_cache);
36421308Sache    debug_const(CISS_MAX_REQUESTS);
36521308Sache    debug_const(CISS_MAX_LOGICAL);
36675409Sache    debug_const(CISS_INTERRUPT_COALESCE_DELAY);
36775409Sache    debug_const(CISS_INTERRUPT_COALESCE_COUNT);
36875409Sache    debug_const(CISS_COMMAND_ALLOC_SIZE);
36921308Sache    debug_const(CISS_COMMAND_SG_LENGTH);
370165675Sache
371157188Sache    debug_type(cciss_pci_info_struct);
372157188Sache    debug_type(cciss_coalint_struct);
37321308Sache    debug_type(cciss_coalint_struct);
37421308Sache    debug_type(NodeName_type);
37521308Sache    debug_type(NodeName_type);
37621308Sache    debug_type(Heartbeat_type);
37721308Sache    debug_type(BusTypes_type);
37821308Sache    debug_type(FirmwareVer_type);
37921308Sache    debug_type(DriverVer_type);
38075409Sache    debug_type(IOCTL_Command_struct);
38175409Sache#endif
38275409Sache
383136759Speter    sc = device_get_softc(dev);
384136759Speter    sc->ciss_dev = dev;
38521308Sache
386165675Sache    /*
38775409Sache     * Work out adapter type.
38821308Sache     */
38921308Sache    i = ciss_lookup(dev);
39021308Sache    if (i < 0) {
39121308Sache	ciss_printf(sc, "unknown adapter type\n");
39221308Sache	error = ENXIO;
39375409Sache	goto out;
39475409Sache    }
395136759Speter    if (ciss_vendor_data[i].flags & CISS_BOARD_SA5) {
396136759Speter	sc->ciss_interrupt_mask = CISS_TL_SIMPLE_INTR_OPQ_SA5;
39721308Sache    } else if (ciss_vendor_data[i].flags & CISS_BOARD_SA5B) {
39821308Sache	sc->ciss_interrupt_mask = CISS_TL_SIMPLE_INTR_OPQ_SA5B;
39921308Sache    } else {
40075409Sache	/* really an error on our part */
40175409Sache	ciss_printf(sc, "unable to determine hardware type\n");
402136759Speter	error = ENXIO;
403136759Speter	goto out;
40421308Sache    }
405165675Sache
40675409Sache    /*
40721308Sache     * Do PCI-specific init.
40821308Sache     */
40921308Sache    if ((error = ciss_init_pci(sc)) != 0)
41058314Sache	goto out;
41158314Sache
41258314Sache    /*
41358314Sache     * Initialise driver queues.
41458314Sache     */
41558314Sache    ciss_initq_free(sc);
41658314Sache    ciss_initq_busy(sc);
41758314Sache    ciss_initq_complete(sc);
41858314Sache    ciss_initq_notify(sc);
41958314Sache    mtx_init(&sc->ciss_mtx, "cissmtx", NULL, MTX_DEF);
42058314Sache    callout_init_mtx(&sc->ciss_periodic, &sc->ciss_mtx, 0);
42158314Sache
42258314Sache    /*
42358314Sache     * Initalize device sysctls.
42458314Sache     */
425119614Sache    ciss_init_sysctl(sc);
426119614Sache
42758314Sache    /*
42858314Sache     * Initialise command/request pool.
42958314Sache     */
43058314Sache    if ((error = ciss_init_requests(sc)) != 0)
43158314Sache	goto out;
43258314Sache
433119614Sache    /*
434119614Sache     * Get adapter information.
43558314Sache     */
43658314Sache    if ((error = ciss_identify_adapter(sc)) != 0)
43758314Sache	goto out;
43858314Sache
43958314Sache    /*
44058314Sache     * Find all the physical devices.
44158314Sache     */
44258314Sache    if ((error = ciss_init_physical(sc)) != 0)
44358314Sache	goto out;
44458314Sache
44558314Sache    /*
44658314Sache     * Build our private table of logical devices.
44758314Sache     */
44858314Sache    if ((error = ciss_init_logical(sc)) != 0)
449119614Sache	goto out;
450119614Sache
451119614Sache    /*
45258314Sache     * Enable interrupts so that the CAM scan can complete.
45358314Sache     */
45458314Sache    CISS_TL_SIMPLE_ENABLE_INTERRUPTS(sc);
45558314Sache
45621308Sache    /*
45721308Sache     * Initialise the CAM interface.
45821308Sache     */
45921308Sache    if ((error = ciss_cam_init(sc)) != 0)
46021308Sache	goto out;
46121308Sache
462165675Sache    /*
463136759Speter     * Start the heartbeat routine and event chain.
46421308Sache     */
465119614Sache    ciss_periodic(sc);
466119614Sache
467119614Sache   /*
468119614Sache     * Create the control device.
469119614Sache     */
470119614Sache    sc->ciss_dev_t = make_dev(&ciss_cdevsw, device_get_unit(sc->ciss_dev),
471119614Sache			      UID_ROOT, GID_OPERATOR, S_IRUSR | S_IWUSR,
47221308Sache			      "ciss%d", device_get_unit(sc->ciss_dev));
47321308Sache    sc->ciss_dev_t->si_drv1 = sc;
47421308Sache
47521308Sache    /*
47621308Sache     * The adapter is running; synchronous commands can now sleep
47721308Sache     * waiting for an interrupt to signal completion.
47821308Sache     */
479157188Sache    sc->ciss_flags |= CISS_FLAG_RUNNING;
48021308Sache
48158314Sache    ciss_spawn_notify_thread(sc);
48221308Sache
48321308Sache    error = 0;
48421308Sache out:
48521308Sache    if (error != 0)
486165675Sache	ciss_free(sc);
48721308Sache    return(error);
48821308Sache}
48921308Sache
49021308Sache/************************************************************************
49121308Sache * Detach the driver from this adapter.
49221308Sache */
493136759Speterstatic int
49421308Sacheciss_detach(device_t dev)
49521308Sache{
49621308Sache    struct ciss_softc	*sc = device_get_softc(dev);
49721308Sache
498136759Speter    debug_called(1);
49921308Sache
50021308Sache    mtx_lock(&sc->ciss_mtx);
50121308Sache    if (sc->ciss_flags & CISS_FLAG_CONTROL_OPEN) {
50221308Sache	mtx_unlock(&sc->ciss_mtx);
50321308Sache	return (EBUSY);
50421308Sache    }
50521308Sache
50621308Sache    /* flush adapter cache */
50721308Sache    ciss_flush_adapter(sc);
50821308Sache
50921308Sache    /* release all resources.  The mutex is released and freed here too. */
51021308Sache    ciss_free(sc);
51121308Sache
51221308Sache    return(0);
51321308Sache}
51421308Sache
51521308Sache/************************************************************************
516165675Sache * Prepare adapter for system shutdown.
51721308Sache */
518165675Sachestatic int
51947563Sacheciss_shutdown(device_t dev)
52047563Sache{
52147563Sache    struct ciss_softc	*sc = device_get_softc(dev);
522119614Sache
523119614Sache    debug_called(1);
52447563Sache
525165675Sache    mtx_lock(&sc->ciss_mtx);
526165675Sache    /* flush adapter cache */
52721308Sache    ciss_flush_adapter(sc);
52821308Sache
529165675Sache    if (sc->ciss_soft_reset)
53021308Sache	ciss_soft_reset(sc);
53121308Sache    mtx_unlock(&sc->ciss_mtx);
53221308Sache
53321308Sache    return(0);
53421308Sache}
53521308Sache
53621308Sachestatic void
53721308Sacheciss_init_sysctl(struct ciss_softc *sc)
53821308Sache{
53921308Sache
54058314Sache    SYSCTL_ADD_INT(device_get_sysctl_ctx(sc->ciss_dev),
54121308Sache	SYSCTL_CHILDREN(device_get_sysctl_tree(sc->ciss_dev)),
54221308Sache	OID_AUTO, "soft_reset", CTLFLAG_RW, &sc->ciss_soft_reset, 0, "");
54358314Sache}
54421308Sache
54521308Sache/************************************************************************
54658314Sache * Perform PCI-specific attachment actions.
54721308Sache */
54821308Sachestatic int
54921308Sacheciss_init_pci(struct ciss_softc *sc)
55021308Sache{
551136759Speter    uintptr_t		cbase, csize, cofs;
55247563Sache    int			error;
55347563Sache
55447563Sache    debug_called(1);
55547563Sache
556119614Sache    /*
557119614Sache     * Allocate register window first (we need this to find the config
55847563Sache     * struct).
55921308Sache     */
56021308Sache    error = ENXIO;
56121308Sache    sc->ciss_regs_rid = CISS_TL_SIMPLE_BAR_REGS;
56275409Sache    if ((sc->ciss_regs_resource =
56321308Sache	 bus_alloc_resource_any(sc->ciss_dev, SYS_RES_MEMORY,
56421308Sache				&sc->ciss_regs_rid, RF_ACTIVE)) == NULL) {
56558314Sache	ciss_printf(sc, "can't allocate register window\n");
56658314Sache	return(ENXIO);
56758314Sache    }
56858314Sache    sc->ciss_regs_bhandle = rman_get_bushandle(sc->ciss_regs_resource);
56958314Sache    sc->ciss_regs_btag = rman_get_bustag(sc->ciss_regs_resource);
57058314Sache
57158314Sache    /*
57258314Sache     * Find the BAR holding the config structure.  If it's not the one
573119614Sache     * we already mapped for registers, map it too.
574119614Sache     */
57521308Sache    sc->ciss_cfg_rid = CISS_TL_SIMPLE_READ(sc, CISS_TL_SIMPLE_CFG_BAR) & 0xffff;
57621308Sache    if (sc->ciss_cfg_rid != sc->ciss_regs_rid) {
57747563Sache	if ((sc->ciss_cfg_resource =
57875409Sache	     bus_alloc_resource_any(sc->ciss_dev, SYS_RES_MEMORY,
57947563Sache				    &sc->ciss_cfg_rid, RF_ACTIVE)) == NULL) {
58058314Sache	    ciss_printf(sc, "can't allocate config window\n");
58158314Sache	    return(ENXIO);
58258314Sache	}
58358314Sache	cbase = (uintptr_t)rman_get_virtual(sc->ciss_cfg_resource);
584119614Sache	csize = rman_get_end(sc->ciss_cfg_resource) -
58558314Sache	    rman_get_start(sc->ciss_cfg_resource) + 1;
58647563Sache    } else {
587119614Sache	cbase = (uintptr_t)rman_get_virtual(sc->ciss_regs_resource);
58847563Sache	csize = rman_get_end(sc->ciss_regs_resource) -
58947563Sache	    rman_get_start(sc->ciss_regs_resource) + 1;
59021308Sache    }
591119614Sache    cofs = CISS_TL_SIMPLE_READ(sc, CISS_TL_SIMPLE_CFG_OFF);
592119614Sache
593119614Sache    /*
594119614Sache     * Use the base/size/offset values we just calculated to
595119614Sache     * sanity-check the config structure.  If it's OK, point to it.
596119614Sache     */
597119614Sache    if ((cofs + sizeof(struct ciss_config_table)) > csize) {
598119614Sache	ciss_printf(sc, "config table outside window\n");
599119614Sache	return(ENXIO);
600119614Sache    }
601119614Sache    sc->ciss_cfg = (struct ciss_config_table *)(cbase + cofs);
602119614Sache    debug(1, "config struct at %p", sc->ciss_cfg);
603119614Sache
604119614Sache    /*
605119614Sache     * Validate the config structure.  If we supported other transport
606119614Sache     * methods, we could select amongst them at this point in time.
60721308Sache     */
60821308Sache    if (strncmp(sc->ciss_cfg->signature, "CISS", 4)) {
60921308Sache	ciss_printf(sc, "config signature mismatch (got '%c%c%c%c')\n",
610136759Speter		    sc->ciss_cfg->signature[0], sc->ciss_cfg->signature[1],
61126497Sache		    sc->ciss_cfg->signature[2], sc->ciss_cfg->signature[3]);
612136759Speter	return(ENXIO);
613136759Speter    }
614136759Speter
615136759Speter    /*
616119614Sache     * Put the board into simple mode, and tell it we're using the low
617119614Sache     * 4GB of RAM.  Set the default interrupt coalescing options.
618136759Speter     */
619119614Sache    if (!(sc->ciss_cfg->supported_methods & CISS_TRANSPORT_METHOD_SIMPLE)) {
62021308Sache	ciss_printf(sc, "adapter does not support 'simple' transport layer\n");
62175409Sache	return(ENXIO);
62275409Sache    }
62375409Sache    sc->ciss_cfg->requested_method = CISS_TRANSPORT_METHOD_SIMPLE;
62475409Sache    sc->ciss_cfg->command_physlimit = 0;
62575409Sache    sc->ciss_cfg->interrupt_coalesce_delay = CISS_INTERRUPT_COALESCE_DELAY;
62675409Sache    sc->ciss_cfg->interrupt_coalesce_count = CISS_INTERRUPT_COALESCE_COUNT;
62726497Sache
62875409Sache#ifdef __i386__
62921308Sache    sc->ciss_cfg->host_driver |= CISS_DRIVER_SCSI_PREFETCH;
630165675Sache#endif
63175409Sache
63275409Sache    if (ciss_update_config(sc)) {
63375409Sache	ciss_printf(sc, "adapter refuses to accept config update (IDBR 0x%x)\n",
63475409Sache		    CISS_TL_SIMPLE_READ(sc, CISS_TL_SIMPLE_IDBR));
63575409Sache	return(ENXIO);
636136759Speter    }
637136759Speter    if (!(sc->ciss_cfg->active_method != CISS_TRANSPORT_METHOD_SIMPLE)) {
638136759Speter	ciss_printf(sc,
639165675Sache		    "adapter refuses to go into 'simple' transport mode (0x%x, 0x%x)\n",
640136759Speter		    sc->ciss_cfg->supported_methods, sc->ciss_cfg->active_method);
641165675Sache	return(ENXIO);
642165675Sache    }
643165675Sache
644136759Speter    /*
645165675Sache     * Wait for the adapter to come ready.
646165675Sache     */
647165675Sache    if ((error = ciss_wait_adapter(sc)) != 0)
648165675Sache	return(error);
649165675Sache
650165675Sache    /*
651165675Sache     * Turn off interrupts before we go routing anything.
652165675Sache     */
653165675Sache    CISS_TL_SIMPLE_DISABLE_INTERRUPTS(sc);
654136759Speter
655165675Sache    /*
656136759Speter     * Allocate and set up our interrupt.
657165675Sache     */
658136759Speter    sc->ciss_irq_rid = 0;
659165675Sache    if ((sc->ciss_irq_resource =
660165675Sache	 bus_alloc_resource_any(sc->ciss_dev, SYS_RES_IRQ, &sc->ciss_irq_rid,
661165675Sache				RF_ACTIVE | RF_SHAREABLE)) == NULL) {
662165675Sache	ciss_printf(sc, "can't allocate interrupt\n");
663165675Sache	return(ENXIO);
664165675Sache    }
665136759Speter    if (bus_setup_intr(sc->ciss_dev, sc->ciss_irq_resource,
666136759Speter		       INTR_TYPE_CAM|INTR_MPSAFE, NULL, ciss_intr, sc,
667136759Speter		       &sc->ciss_intr)) {
668165675Sache	ciss_printf(sc, "can't set up interrupt\n");
669165675Sache	return(ENXIO);
670165675Sache    }
671119614Sache
672165675Sache    /*
67326497Sache     * Allocate the parent bus DMA tag appropriate for our PCI
67426497Sache     * interface.
67575409Sache     *
67675409Sache     * Note that "simple" adapters can only address within a 32-bit
67775409Sache     * span.
678165675Sache     */
67975409Sache    if (bus_dma_tag_create(NULL, 			/* parent */
68075409Sache			   1, 0, 			/* alignment, boundary */
68175409Sache			   BUS_SPACE_MAXADDR,		/* lowaddr */
68226497Sache			   BUS_SPACE_MAXADDR, 		/* highaddr */
683119614Sache			   NULL, NULL, 			/* filter, filterarg */
684119614Sache			   BUS_SPACE_MAXSIZE_32BIT,	/* maxsize */
685119614Sache			   CISS_COMMAND_SG_LENGTH,	/* nsegments */
686119614Sache			   BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
687119614Sache			   BUS_DMA_ALLOCNOW,		/* flags */
688119614Sache			   NULL, NULL,			/* lockfunc, lockarg */
689119614Sache			   &sc->ciss_parent_dmat)) {
690119614Sache	ciss_printf(sc, "can't allocate parent DMA tag\n");
691119614Sache	return(ENOMEM);
692119614Sache    }
693119614Sache
69426497Sache    /*
695119614Sache     * Create DMA tag for mapping buffers into adapter-addressable
69626497Sache     * space.
69721308Sache     */
69821308Sache    if (bus_dma_tag_create(sc->ciss_parent_dmat, 	/* parent */
699119614Sache			   1, 0, 			/* alignment, boundary */
700119614Sache			   BUS_SPACE_MAXADDR,		/* lowaddr */
701119614Sache			   BUS_SPACE_MAXADDR, 		/* highaddr */
702136759Speter			   NULL, NULL, 			/* filter, filterarg */
703119614Sache			   MAXBSIZE, CISS_COMMAND_SG_LENGTH,	/* maxsize, nsegments */
704119614Sache			   BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
705119614Sache			   0,				/* flags */
706119614Sache			   busdma_lock_mutex, &sc->ciss_mtx,	/* lockfunc, lockarg */
707119614Sache			   &sc->ciss_buffer_dmat)) {
708119614Sache	ciss_printf(sc, "can't allocate buffer DMA tag\n");
709119614Sache	return(ENOMEM);
710119614Sache    }
711136759Speter    return(0);
712119614Sache}
713119614Sache
714119614Sache/************************************************************************
715119614Sache * Wait for the adapter to come ready.
716136759Speter */
717119614Sachestatic int
718119614Sacheciss_wait_adapter(struct ciss_softc *sc)
719119614Sache{
720119614Sache    int		i;
72121308Sache
72221308Sache    debug_called(1);
72321308Sache
724119614Sache    /*
725119614Sache     * Wait for the adapter to come ready.
72621308Sache     */
72721308Sache    if (!(sc->ciss_cfg->active_method & CISS_TRANSPORT_METHOD_READY)) {
72821308Sache	ciss_printf(sc, "waiting for adapter to come ready...\n");
72921308Sache	for (i = 0; !(sc->ciss_cfg->active_method & CISS_TRANSPORT_METHOD_READY); i++) {
73021308Sache	    DELAY(1000000);	/* one second */
731165675Sache	    if (i > 30) {
73221308Sache		ciss_printf(sc, "timed out waiting for adapter to come ready\n");
73321308Sache		return(EIO);
73421308Sache	    }
735119614Sache	}
736119614Sache    }
737119614Sache    return(0);
73821308Sache}
739119614Sache
74021308Sache/************************************************************************
74121308Sache * Flush the adapter cache.
74221308Sache */
74321308Sachestatic int
74421308Sacheciss_flush_adapter(struct ciss_softc *sc)
74575409Sache{
74621308Sache    struct ciss_request			*cr;
74775409Sache    struct ciss_bmic_flush_cache	*cbfc;
74858314Sache    int					error, command_status;
74921308Sache
75021308Sache    debug_called(1);
75121308Sache
75221308Sache    cr = NULL;
75321308Sache    cbfc = NULL;
75421308Sache
75521308Sache    /*
75621308Sache     * Build a BMIC request to flush the cache.  We don't disable
75721308Sache     * it, as we may be going to do more I/O (eg. we are emulating
75821308Sache     * the Synchronise Cache command).
75921308Sache     */
76021308Sache    if ((cbfc = malloc(sizeof(*cbfc), CISS_MALLOC_CLASS, M_NOWAIT | M_ZERO)) == NULL) {
76121308Sache	error = ENOMEM;
76221308Sache	goto out;
76321308Sache    }
76421308Sache    if ((error = ciss_get_bmic_request(sc, &cr, CISS_BMIC_FLUSH_CACHE,
76521308Sache				       (void **)&cbfc, sizeof(*cbfc))) != 0)
76675409Sache	goto out;
76747563Sache
76847563Sache    /*
76921308Sache     * Submit the request and wait for it to complete.
77047563Sache     */
77147563Sache    if ((error = ciss_synch_request(cr, 60 * 1000)) != 0) {
77247563Sache	ciss_printf(sc, "error sending BMIC FLUSH_CACHE command (%d)\n", error);
77321308Sache	goto out;
77475409Sache    }
77521308Sache
77621308Sache    /*
77775409Sache     * Check response.
77858314Sache     */
77921308Sache    ciss_report_request(cr, &command_status, NULL);
78021308Sache    switch(command_status) {
78121308Sache    case CISS_CMD_STATUS_SUCCESS:
78221308Sache	break;
78321308Sache    default:
78421308Sache	ciss_printf(sc, "error flushing cache (%s)\n",
78521308Sache		    ciss_name_command_status(command_status));
78621308Sache	error = EIO;
78721308Sache	goto out;
78821308Sache    }
78921308Sache
79021308Sacheout:
79121308Sache    if (cbfc != NULL)
79275409Sache	free(cbfc, CISS_MALLOC_CLASS);
79347563Sache    if (cr != NULL)
79447563Sache	ciss_release_request(cr);
79558314Sache    return(error);
79647563Sache}
79747563Sache
79847563Sachestatic void
79921308Sacheciss_soft_reset(struct ciss_softc *sc)
80021308Sache{
80121308Sache    struct ciss_request		*cr = NULL;
80221308Sache    struct ciss_command		*cc;
80321308Sache    int				i, error = 0;
80421308Sache
80521308Sache    for (i = 0; i < sc->ciss_max_logical_bus; i++) {
80621308Sache	/* only reset proxy controllers */
80721308Sache	if (sc->ciss_controllers[i].physical.bus == 0)
808119614Sache	    continue;
809119614Sache
810119614Sache	if ((error = ciss_get_request(sc, &cr)) != 0)
811119614Sache	    break;
812119614Sache
813119614Sache	if ((error = ciss_get_bmic_request(sc, &cr, CISS_BMIC_SOFT_RESET,
814119614Sache					   NULL, 0)) != 0)
815119614Sache	    break;
816119614Sache
817119614Sache	cc = CISS_FIND_COMMAND(cr);
818119614Sache	cc->header.address = sc->ciss_controllers[i];
819119614Sache
820119614Sache	if ((error = ciss_synch_request(cr, 60 * 1000)) != 0)
821119614Sache	    break;
822119614Sache
823119614Sache	ciss_release_request(cr);
824119614Sache    }
825165675Sache
826119614Sache    if (error)
827119614Sache	ciss_printf(sc, "error resetting controller (%d)\n", error);
828119614Sache
829119614Sache    if (cr != NULL)
830119614Sache	ciss_release_request(cr);
831119614Sache}
832119614Sache
833119614Sache/************************************************************************
834119614Sache * Allocate memory for the adapter command structures, initialise
835119614Sache * the request structures.
836119614Sache *
837119614Sache * Note that the entire set of commands are allocated in a single
838119614Sache * contiguous slab.
83921308Sache */
84021308Sachestatic int
841119614Sacheciss_init_requests(struct ciss_softc *sc)
84221308Sache{
843119614Sache    struct ciss_request	*cr;
844119614Sache    int			i;
845119614Sache
846119614Sache    debug_called(1);
847119614Sache
848119614Sache    /*
849119614Sache     * Calculate the number of request structures/commands we are
850119614Sache     * going to provide for this adapter.
851119614Sache     */
852119614Sache    sc->ciss_max_requests = min(CISS_MAX_REQUESTS, sc->ciss_cfg->max_outstanding_commands);
853119614Sache
85421308Sache    if (bootverbose)
85521308Sache	ciss_printf(sc, "using %d of %d available commands\n",
856165675Sache		    sc->ciss_max_requests, sc->ciss_cfg->max_outstanding_commands);
85721308Sache
858165675Sache    /*
85921308Sache     * Create the DMA tag for commands.
86021308Sache     */
86121308Sache    if (bus_dma_tag_create(sc->ciss_parent_dmat,	/* parent */
86221308Sache			   1, 0, 			/* alignment, boundary */
86358314Sache			   BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
86421308Sache			   BUS_SPACE_MAXADDR, 		/* highaddr */
86521308Sache			   NULL, NULL, 			/* filter, filterarg */
86621308Sache			   CISS_COMMAND_ALLOC_SIZE *
867165675Sache			   sc->ciss_max_requests, 1,	/* maxsize, nsegments */
86875409Sache			   BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
86921308Sache			   BUS_DMA_ALLOCNOW,		/* flags */
87021308Sache			   NULL, NULL,			/* lockfunc, lockarg */
87121308Sache			   &sc->ciss_command_dmat)) {
87221308Sache	ciss_printf(sc, "can't allocate command DMA tag\n");
87321308Sache	return(ENOMEM);
87421308Sache    }
87521308Sache    /*
87621308Sache     * Allocate memory and make it available for DMA.
87721308Sache     */
87821308Sache    if (bus_dmamem_alloc(sc->ciss_command_dmat, (void **)&sc->ciss_command,
87975409Sache			 BUS_DMA_NOWAIT, &sc->ciss_command_map)) {
88021308Sache	ciss_printf(sc, "can't allocate command memory\n");
881157188Sache	return(ENOMEM);
88221308Sache    }
88321308Sache    bus_dmamap_load(sc->ciss_command_dmat, sc->ciss_command_map, sc->ciss_command,
88421308Sache		    CISS_COMMAND_ALLOC_SIZE * sc->ciss_max_requests,
88521308Sache		    ciss_command_map_helper, sc, 0);
88621308Sache    bzero(sc->ciss_command, CISS_COMMAND_ALLOC_SIZE * sc->ciss_max_requests);
88721308Sache
88821308Sache    /*
88921308Sache     * Set up the request and command structures, push requests onto
89075409Sache     * the free queue.
891119614Sache     */
892119614Sache    for (i = 1; i < sc->ciss_max_requests; i++) {
893119614Sache	cr = &sc->ciss_request[i];
894119614Sache	cr->cr_sc = sc;
895119614Sache	cr->cr_tag = i;
896119614Sache	bus_dmamap_create(sc->ciss_buffer_dmat, 0, &cr->cr_datamap);
89721308Sache	ciss_enqueue_free(cr);
89821308Sache    }
89921308Sache    return(0);
90021308Sache}
90121308Sache
90221308Sachestatic void
90321308Sacheciss_command_map_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error)
90421308Sache{
90521308Sache    struct ciss_softc	*sc = (struct ciss_softc *)arg;
90621308Sache
90721308Sache    sc->ciss_command_phys = segs->ds_addr;
90821308Sache}
90921308Sache
91021308Sache/************************************************************************
91121308Sache * Identify the adapter, print some information about it.
912165675Sache */
913165675Sachestatic int
914157188Sacheciss_identify_adapter(struct ciss_softc *sc)
915157188Sache{
91621308Sache    struct ciss_request	*cr;
91721308Sache    int			error, command_status;
91821308Sache
919157188Sache    debug_called(1);
920157188Sache
921157188Sache    cr = NULL;
922157188Sache
923157188Sache    /*
924157188Sache     * Get a request, allocate storage for the adapter data.
925157188Sache     */
926165675Sache    if ((error = ciss_get_bmic_request(sc, &cr, CISS_BMIC_ID_CTLR,
927165675Sache				       (void **)&sc->ciss_id,
928165675Sache				       sizeof(*sc->ciss_id))) != 0)
929165675Sache	goto out;
930165675Sache
931157188Sache    /*
932157188Sache     * Submit the request and wait for it to complete.
933157188Sache     */
934157188Sache    if ((error = ciss_synch_request(cr, 60 * 1000)) != 0) {
935157188Sache	ciss_printf(sc, "error sending BMIC ID_CTLR command (%d)\n", error);
936157188Sache	goto out;
937157188Sache    }
93821308Sache
93921308Sache    /*
94021308Sache     * Check response.
94121308Sache     */
94221308Sache    ciss_report_request(cr, &command_status, NULL);
94321308Sache    switch(command_status) {
94421308Sache    case CISS_CMD_STATUS_SUCCESS:		/* buffer right size */
94521308Sache	break;
94621308Sache    case CISS_CMD_STATUS_DATA_UNDERRUN:
94721308Sache    case CISS_CMD_STATUS_DATA_OVERRUN:
94821308Sache	ciss_printf(sc, "data over/underrun reading adapter information\n");
949157188Sache    default:
950157188Sache	ciss_printf(sc, "error reading adapter information (%s)\n",
951157188Sache		    ciss_name_command_status(command_status));
952157188Sache	error = EIO;
95321308Sache	goto out;
95426497Sache    }
95521308Sache
95621308Sache    /* sanity-check reply */
95721308Sache    if (!sc->ciss_id->big_map_supported) {
95821308Sache	ciss_printf(sc, "adapter does not support BIG_MAP\n");
95921308Sache	error = ENXIO;
96021308Sache	goto out;
96121308Sache    }
96221308Sache
96321308Sache#if 0
96421308Sache    /* XXX later revisions may not need this */
96521308Sache    sc->ciss_flags |= CISS_FLAG_FAKE_SYNCH;
96621308Sache#endif
96721308Sache
96821308Sache    /* XXX only really required for old 5300 adapters? */
96921308Sache    sc->ciss_flags |= CISS_FLAG_BMIC_ABORT;
97021308Sache
97121308Sache    /* print information */
97226497Sache    if (bootverbose) {
97375409Sache#if 0	/* XXX proxy volumes??? */
97421308Sache	ciss_printf(sc, "  %d logical drive%s configured\n",
97521308Sache		    sc->ciss_id->configured_logical_drives,
97621308Sache		    (sc->ciss_id->configured_logical_drives == 1) ? "" : "s");
97721308Sache#endif
97821308Sache	ciss_printf(sc, "  firmware %4.4s\n", sc->ciss_id->running_firmware_revision);
97921308Sache	ciss_printf(sc, "  %d SCSI channels\n", sc->ciss_id->scsi_bus_count);
98021308Sache
98121308Sache	ciss_printf(sc, "  signature '%.4s'\n", sc->ciss_cfg->signature);
98221308Sache	ciss_printf(sc, "  valence %d\n", sc->ciss_cfg->valence);
98321308Sache	ciss_printf(sc, "  supported I/O methods 0x%b\n",
98475409Sache		    sc->ciss_cfg->supported_methods,
98547563Sache		    "\20\1READY\2simple\3performant\4MEMQ\n");
98647563Sache	ciss_printf(sc, "  active I/O method 0x%b\n",
98747563Sache		    sc->ciss_cfg->active_method, "\20\2simple\3performant\4MEMQ\n");
988157188Sache	ciss_printf(sc, "  4G page base 0x%08x\n",
98947563Sache		    sc->ciss_cfg->command_physlimit);
99021308Sache	ciss_printf(sc, "  interrupt coalesce delay %dus\n",
99121308Sache		    sc->ciss_cfg->interrupt_coalesce_delay);
99221308Sache	ciss_printf(sc, "  interrupt coalesce count %d\n",
99321308Sache		    sc->ciss_cfg->interrupt_coalesce_count);
99421308Sache	ciss_printf(sc, "  max outstanding commands %d\n",
99521308Sache		    sc->ciss_cfg->max_outstanding_commands);
99621308Sache	ciss_printf(sc, "  bus types 0x%b\n", sc->ciss_cfg->bus_types,
99775409Sache		    "\20\1ultra2\2ultra3\10fibre1\11fibre2\n");
99821308Sache	ciss_printf(sc, "  server name '%.16s'\n", sc->ciss_cfg->server_name);
999165675Sache	ciss_printf(sc, "  heartbeat 0x%x\n", sc->ciss_cfg->heartbeat);
1000165675Sache    }
1001165675Sache
1002165675Sacheout:
1003165675Sache    if (error) {
100421308Sache	if (sc->ciss_id != NULL) {
100558314Sache	    free(sc->ciss_id, CISS_MALLOC_CLASS);
100658314Sache	    sc->ciss_id = NULL;
100758314Sache	}
100875409Sache    }
100975409Sache    if (cr != NULL)
101058314Sache	ciss_release_request(cr);
101121308Sache    return(error);
1012119614Sache}
1013157188Sache
1014119614Sache/************************************************************************
1015119614Sache * Helper routine for generating a list of logical and physical luns.
101621308Sache */
101721308Sachestatic struct ciss_lun_report *
101821308Sacheciss_report_luns(struct ciss_softc *sc, int opcode, int nunits)
101921308Sache{
102021308Sache    struct ciss_request		*cr;
102121308Sache    struct ciss_command		*cc;
1022165675Sache    struct ciss_report_cdb	*crc;
1023165675Sache    struct ciss_lun_report	*cll;
102421308Sache    int				command_status;
1025157188Sache    int				report_size;
1026157188Sache    int				error = 0;
1027157188Sache
1028157188Sache    debug_called(1);
1029157188Sache
103021308Sache    cr = NULL;
103121308Sache    cll = NULL;
103221308Sache
103321308Sache    /*
103421308Sache     * Get a request, allocate storage for the address list.
1035165675Sache     */
1036119614Sache    if ((error = ciss_get_request(sc, &cr)) != 0)
1037157188Sache	goto out;
1038119614Sache    report_size = sizeof(*cll) + nunits * sizeof(union ciss_device_address);
1039157188Sache    if ((cll = malloc(report_size, CISS_MALLOC_CLASS, M_NOWAIT | M_ZERO)) == NULL) {
1040157188Sache	ciss_printf(sc, "can't allocate memory for lun report\n");
1041157188Sache	error = ENOMEM;
1042157188Sache	goto out;
1043157188Sache    }
1044157188Sache
104521308Sache    /*
104621308Sache     * Build the Report Logical/Physical LUNs command.
1047157188Sache     */
1048157188Sache    cc = CISS_FIND_COMMAND(cr);
1049157188Sache    cr->cr_data = cll;
1050157188Sache    cr->cr_length = report_size;
1051119614Sache    cr->cr_flags = CISS_REQ_DATAIN;
105221308Sache
1053119614Sache    cc->header.address.physical.mode = CISS_HDR_ADDRESS_MODE_PERIPHERAL;
1054119614Sache    cc->header.address.physical.bus = 0;
105521308Sache    cc->header.address.physical.target = 0;
105621308Sache    cc->cdb.cdb_length = sizeof(*crc);
105721308Sache    cc->cdb.type = CISS_CDB_TYPE_COMMAND;
105821308Sache    cc->cdb.attribute = CISS_CDB_ATTRIBUTE_SIMPLE;
105921308Sache    cc->cdb.direction = CISS_CDB_DIRECTION_READ;
106021308Sache    cc->cdb.timeout = 30;	/* XXX better suggestions? */
106121308Sache
106221308Sache    crc = (struct ciss_report_cdb *)&(cc->cdb.cdb[0]);
106321308Sache    bzero(crc, sizeof(*crc));
106421308Sache    crc->opcode = opcode;
106521308Sache    crc->length = htonl(report_size);			/* big-endian field */
106621308Sache    cll->list_size = htonl(report_size - sizeof(*cll));	/* big-endian field */
106721308Sache
106821308Sache    /*
1069165675Sache     * Submit the request and wait for it to complete.  (timeout
107075409Sache     * here should be much greater than above)
107121308Sache     */
107247563Sache    if ((error = ciss_synch_request(cr, 60 * 1000)) != 0) {
1073165675Sache	ciss_printf(sc, "error sending %d LUN command (%d)\n", opcode, error);
107475409Sache	goto out;
107521308Sache    }
107621308Sache
107747563Sache    /*
107821308Sache     * Check response.  Note that data over/underrun is OK.
107921308Sache     */
108047563Sache    ciss_report_request(cr, &command_status, NULL);
108147563Sache    switch(command_status) {
108275409Sache    case CISS_CMD_STATUS_SUCCESS:	/* buffer right size */
108321308Sache    case CISS_CMD_STATUS_DATA_UNDERRUN:	/* buffer too large, not bad */
1084165675Sache	break;
108521308Sache    case CISS_CMD_STATUS_DATA_OVERRUN:
108621308Sache	ciss_printf(sc, "WARNING: more units than driver limit (%d)\n",
108721308Sache		    CISS_MAX_LOGICAL);
108821308Sache	break;
108921308Sache    default:
109021308Sache	ciss_printf(sc, "error detecting logical drive configuration (%s)\n",
109121308Sache		    ciss_name_command_status(command_status));
109275409Sache	error = EIO;
109347563Sache	goto out;
109421308Sache    }
109521308Sache    ciss_release_request(cr);
109621308Sache    cr = NULL;
109721308Sache
1098165675Sacheout:
109921308Sache    if (cr != NULL)
110021308Sache	ciss_release_request(cr);
110121308Sache    if (error && cll != NULL) {
110221308Sache	free(cll, CISS_MALLOC_CLASS);
110347563Sache	cll = NULL;
110421308Sache    }
110521308Sache    return(cll);
110621308Sache}
110721308Sache
110821308Sache/************************************************************************
110921308Sache * Find logical drives on the adapter.
111021308Sache */
111147563Sachestatic int
111247563Sacheciss_init_logical(struct ciss_softc *sc)
111347563Sache{
111475409Sache    struct ciss_lun_report	*cll;
111521308Sache    int				error = 0, i, j;
111647563Sache    int				ndrives;
111721308Sache
111821308Sache    debug_called(1);
111921308Sache
112021308Sache    cll = ciss_report_luns(sc, CISS_OPCODE_REPORT_LOGICAL_LUNS,
112121308Sache			   CISS_MAX_LOGICAL);
112221308Sache    if (cll == NULL) {
112321308Sache	error = ENXIO;
112475409Sache	goto out;
112575409Sache    }
112621308Sache
112721308Sache    /* sanity-check reply */
112821308Sache    ndrives = (ntohl(cll->list_size) / sizeof(union ciss_device_address));
112921308Sache    if ((ndrives < 0) || (ndrives >= CISS_MAX_LOGICAL)) {
113021308Sache	ciss_printf(sc, "adapter claims to report absurd number of logical drives (%d > %d)\n",
113121308Sache		    ndrives, CISS_MAX_LOGICAL);
113221308Sache	error = ENXIO;
113321308Sache	goto out;
113421308Sache    }
113521308Sache
113675409Sache    /*
113726497Sache     * Save logical drive information.
113821308Sache     */
113921308Sache    if (bootverbose) {
114075409Sache	ciss_printf(sc, "%d logical drive%s\n",
114175409Sache	    ndrives, (ndrives > 1 || ndrives == 0) ? "s" : "");
114221308Sache    }
1143165675Sache
114421308Sache    sc->ciss_logical =
114521308Sache	malloc(sc->ciss_max_logical_bus * sizeof(struct ciss_ldrive *),
114621308Sache	       CISS_MALLOC_CLASS, M_NOWAIT | M_ZERO);
114721308Sache    if (sc->ciss_logical == NULL) {
114821308Sache	error = ENXIO;
114921308Sache	goto out;
115021308Sache    }
115175409Sache
115258314Sache    for (i = 0; i <= sc->ciss_max_logical_bus; i++) {
115358314Sache	sc->ciss_logical[i] =
115421308Sache	    malloc(CISS_MAX_LOGICAL * sizeof(struct ciss_ldrive),
115575409Sache		   CISS_MALLOC_CLASS, M_NOWAIT | M_ZERO);
115658314Sache	if (sc->ciss_logical[i] == NULL) {
115721308Sache	    error = ENXIO;
115821308Sache	    goto out;
115958314Sache	}
116058314Sache
116158314Sache	for (j = 0; j < CISS_MAX_LOGICAL; j++)
116258314Sache	    sc->ciss_logical[i][j].cl_status = CISS_LD_NONEXISTENT;
116321308Sache    }
116421308Sache
116521308Sache
116621308Sache    for (i = 0; i < CISS_MAX_LOGICAL; i++) {
116721308Sache	if (i < ndrives) {
116821308Sache	    struct ciss_ldrive	*ld;
116921308Sache	    int			bus, target;
117021308Sache
117121308Sache	    bus		= CISS_LUN_TO_BUS(cll->lun[i].logical.lun);
117221308Sache	    target	= CISS_LUN_TO_TARGET(cll->lun[i].logical.lun);
117321308Sache	    ld		= &sc->ciss_logical[bus][target];
117421308Sache
117521308Sache	    ld->cl_address	= cll->lun[i];
117621308Sache	    ld->cl_controller	= &sc->ciss_controllers[bus];
117721308Sache	    if (ciss_identify_logical(sc, ld) != 0)
117821308Sache		continue;
117921308Sache	    /*
118021308Sache	     * If the drive has had media exchanged, we should bring it online.
118121308Sache	     */
118221308Sache	    if (ld->cl_lstatus->media_exchanged)
118321308Sache		ciss_accept_media(sc, ld);
118421308Sache
118521308Sache	}
118621308Sache    }
118747563Sache
118821308Sache out:
118921308Sache    if (cll != NULL)
119021308Sache	free(cll, CISS_MALLOC_CLASS);
119121308Sache    return(error);
119221308Sache}
119321308Sache
119421308Sachestatic int
119521308Sacheciss_init_physical(struct ciss_softc *sc)
119621308Sache{
119721308Sache    struct ciss_lun_report	*cll;
1198119614Sache    int				error = 0, i;
1199119614Sache    int				nphys;
1200119614Sache    int				bus, target;
1201165675Sache
1202119614Sache    debug_called(1);
120321308Sache
120421308Sache    bus = 0;
120521308Sache    target = 0;
120621308Sache
120721308Sache    cll = ciss_report_luns(sc, CISS_OPCODE_REPORT_PHYSICAL_LUNS,
120821308Sache			   CISS_MAX_PHYSICAL);
1209157188Sache    if (cll == NULL) {
1210157188Sache	error = ENXIO;
1211157188Sache	goto out;
1212157188Sache    }
121375409Sache
1214119614Sache    nphys = (ntohl(cll->list_size) / sizeof(union ciss_device_address));
121521308Sache
1216119614Sache    if (bootverbose) {
1217119614Sache	ciss_printf(sc, "%d physical device%s\n",
1218119614Sache	    nphys, (nphys > 1 || nphys == 0) ? "s" : "");
1219119614Sache    }
1220119614Sache
1221119614Sache    /*
1222119614Sache     * Figure out the bus mapping.
1223119614Sache     * Logical buses include both the local logical bus for local arrays and
1224119614Sache     * proxy buses for remote arrays.  Physical buses are numbered by the
1225119614Sache     * controller and represent physical buses that hold physical devices.
1226119614Sache     * We shift these bus numbers so that everything fits into a single flat
1227119614Sache     * numbering space for CAM.  Logical buses occupy the first 32 CAM bus
1228119614Sache     * numbers, and the physical bus numbers are shifted to be above that.
1229119614Sache     * This results in the various driver arrays being indexed as follows:
1230119614Sache     *
1231119614Sache     * ciss_controllers[] - indexed by logical bus
1232136759Speter     * ciss_cam_sim[]     - indexed by both logical and physical, with physical
1233119614Sache     *                      being shifted by 32.
1234119614Sache     * ciss_logical[][]   - indexed by logical bus
1235119614Sache     * ciss_physical[][]  - indexed by physical bus
1236119614Sache     *
1237136759Speter     * XXX This is getting more and more hackish.  CISS really doesn't play
1238119614Sache     *     well with a standard SCSI model; devices are addressed via magic
1239119614Sache     *     cookies, not via b/t/l addresses.  Since there is no way to store
1240119614Sache     *     the cookie in the CAM device object, we have to keep these lookup
1241119614Sache     *     tables handy so that the devices can be found quickly at the cost
1242119614Sache     *     of wasting memory and having a convoluted lookup scheme.  This
1243119614Sache     *     driver should probably be converted to block interface.
1244119614Sache     */
1245119614Sache    /*
1246119614Sache     * If the L2 and L3 SCSI addresses are 0, this signifies a proxy
1247119614Sache     * controller. A proxy controller is another physical controller
1248119614Sache     * behind the primary PCI controller. We need to know about this
1249119614Sache     * so that BMIC commands can be properly targeted.  There can be
1250119614Sache     * proxy controllers attached to a single PCI controller, so
1251119614Sache     * find the highest numbered one so the array can be properly
1252119614Sache     * sized.
1253119614Sache     */
1254136759Speter    sc->ciss_max_logical_bus = 1;
1255119614Sache    for (i = 0; i < nphys; i++) {
1256119614Sache	if (cll->lun[i].physical.extra_address == 0) {
1257119614Sache	    bus = cll->lun[i].physical.bus;
1258119614Sache	    sc->ciss_max_logical_bus = max(sc->ciss_max_logical_bus, bus) + 1;
1259119614Sache	} else {
1260119614Sache	    bus = CISS_EXTRA_BUS2(cll->lun[i].physical.extra_address);
1261119614Sache	    sc->ciss_max_physical_bus = max(sc->ciss_max_physical_bus, bus);
1262119614Sache	}
1263119614Sache    }
1264119614Sache
1265119614Sache    sc->ciss_controllers =
1266119614Sache	malloc(sc->ciss_max_logical_bus * sizeof (union ciss_device_address),
1267119614Sache	       CISS_MALLOC_CLASS, M_NOWAIT | M_ZERO);
1268119614Sache
1269119614Sache    if (sc->ciss_controllers == NULL) {
127021308Sache	ciss_printf(sc, "Could not allocate memory for controller map\n");
1271119614Sache	error = ENOMEM;
1272119614Sache	goto out;
1273119614Sache    }
1274119614Sache
1275119614Sache    /* setup a map of controller addresses */
1276119614Sache    for (i = 0; i < nphys; i++) {
1277157188Sache	if (cll->lun[i].physical.extra_address == 0) {
1278119614Sache	    sc->ciss_controllers[cll->lun[i].physical.bus] = cll->lun[i];
1279119614Sache	}
1280119614Sache    }
1281119614Sache
128221308Sache    sc->ciss_physical =
1283119614Sache	malloc(sc->ciss_max_physical_bus * sizeof(struct ciss_pdrive *),
128421308Sache	       CISS_MALLOC_CLASS, M_NOWAIT | M_ZERO);
128521308Sache    if (sc->ciss_physical == NULL) {
1286119614Sache	ciss_printf(sc, "Could not allocate memory for physical device map\n");
1287119614Sache	error = ENOMEM;
1288119614Sache	goto out;
1289136759Speter    }
1290136759Speter
1291136759Speter    for (i = 0; i < sc->ciss_max_physical_bus; i++) {
1292136759Speter	sc->ciss_physical[i] =
1293119614Sache	    malloc(sizeof(struct ciss_pdrive) * CISS_MAX_PHYSTGT,
1294136759Speter		   CISS_MALLOC_CLASS, M_NOWAIT | M_ZERO);
1295136759Speter	if (sc->ciss_physical[i] == NULL) {
1296119614Sache	    ciss_printf(sc, "Could not allocate memory for target map\n");
1297136759Speter	    error = ENOMEM;
1298136759Speter	    goto out;
1299136759Speter	}
1300136759Speter    }
1301136759Speter
1302136759Speter    ciss_filter_physical(sc, cll);
1303136759Speter
1304136759Speterout:
1305136759Speter    if (cll != NULL)
1306136759Speter	free(cll, CISS_MALLOC_CLASS);
1307136759Speter
1308136759Speter    return(error);
1309136759Speter}
1310136759Speter
1311136759Speterstatic int
1312136759Speterciss_filter_physical(struct ciss_softc *sc, struct ciss_lun_report *cll)
1313136759Speter{
1314136759Speter    u_int32_t ea;
1315136759Speter    int i, nphys;
1316136759Speter    int	bus, target;
1317136759Speter
1318136759Speter    nphys = (ntohl(cll->list_size) / sizeof(union ciss_device_address));
1319136759Speter    for (i = 0; i < nphys; i++) {
1320136759Speter	if (cll->lun[i].physical.extra_address == 0)
1321119614Sache	    continue;
1322119614Sache
1323119614Sache	/*
132421308Sache	 * Filter out devices that we don't want.  Level 3 LUNs could
132521308Sache	 * probably be supported, but the docs don't give enough of a
132621308Sache	 * hint to know how.
132721308Sache	 *
132821308Sache	 * The mode field of the physical address is likely set to have
132921308Sache	 * hard disks masked out.  Honor it unless the user has overridden
133021308Sache	 * us with the tunable.  We also munge the inquiry data for these
133121308Sache	 * disks so that they only show up as passthrough devices.  Keeping
133221308Sache	 * them visible in this fashion is useful for doing things like
133321308Sache	 * flashing firmware.
133421308Sache	 */
133521308Sache	ea = cll->lun[i].physical.extra_address;
133621308Sache	if ((CISS_EXTRA_BUS3(ea) != 0) || (CISS_EXTRA_TARGET3(ea) != 0) ||
133721308Sache	    (CISS_EXTRA_MODE2(ea) == 0x3))
133821308Sache	    continue;
133921308Sache	if ((ciss_expose_hidden_physical == 0) &&
1340119614Sache	   (cll->lun[i].physical.mode == CISS_HDR_ADDRESS_MODE_MASK_PERIPHERAL))
1341119614Sache	    continue;
1342119614Sache
1343119614Sache	/*
1344119614Sache	 * Note: CISS firmware numbers physical busses starting at '1', not
1345119614Sache	 *       '0'.  This numbering is internal to the firmware and is only
1346119614Sache	 *       used as a hint here.
1347119614Sache	 */
1348119614Sache	bus = CISS_EXTRA_BUS2(ea) - 1;
1349119614Sache	target = CISS_EXTRA_TARGET2(ea);
1350119614Sache	sc->ciss_physical[bus][target].cp_address = cll->lun[i];
1351136759Speter	sc->ciss_physical[bus][target].cp_online = 1;
1352136759Speter    }
1353119614Sache
1354119614Sache    return (0);
1355136759Speter}
1356119614Sache
1357119614Sachestatic int
1358119614Sacheciss_inquiry_logical(struct ciss_softc *sc, struct ciss_ldrive *ld)
1359119614Sache{
1360119614Sache    struct ciss_request			*cr;
1361119614Sache    struct ciss_command			*cc;
1362119614Sache    struct scsi_inquiry			*inq;
1363119614Sache    int					error;
1364119614Sache    int					command_status;
1365119614Sache
1366119614Sache    cr = NULL;
1367119614Sache
1368119614Sache    bzero(&ld->cl_geometry, sizeof(ld->cl_geometry));
1369119614Sache
137021308Sache    if ((error = ciss_get_request(sc, &cr)) != 0)
137121308Sache	goto out;
137221308Sache
137321308Sache    cc = CISS_FIND_COMMAND(cr);
137421308Sache    cr->cr_data = &ld->cl_geometry;
137521308Sache    cr->cr_length = sizeof(ld->cl_geometry);
137621308Sache    cr->cr_flags = CISS_REQ_DATAIN;
137721308Sache
137821308Sache    cc->header.address = ld->cl_address;
1379119614Sache    cc->cdb.cdb_length = 6;
1380119614Sache    cc->cdb.type = CISS_CDB_TYPE_COMMAND;
1381119614Sache    cc->cdb.attribute = CISS_CDB_ATTRIBUTE_SIMPLE;
138221308Sache    cc->cdb.direction = CISS_CDB_DIRECTION_READ;
138321308Sache    cc->cdb.timeout = 30;
138421308Sache
138521308Sache    inq = (struct scsi_inquiry *)&(cc->cdb.cdb[0]);
138621308Sache    inq->opcode = INQUIRY;
138721308Sache    inq->byte2 = SI_EVPD;
1388119614Sache    inq->page_code = CISS_VPD_LOGICAL_DRIVE_GEOMETRY;
1389119614Sache    inq->length = sizeof(ld->cl_geometry);
1390119614Sache
1391119614Sache    if ((error = ciss_synch_request(cr, 60 * 1000)) != 0) {
1392119614Sache	ciss_printf(sc, "error getting geometry (%d)\n", error);
1393119614Sache	goto out;
139421308Sache    }
1395119614Sache
139621308Sache    ciss_report_request(cr, &command_status, NULL);
139721308Sache    switch(command_status) {
1398119614Sache    case CISS_CMD_STATUS_SUCCESS:
1399119614Sache    case CISS_CMD_STATUS_DATA_UNDERRUN:
1400119614Sache	break;
1401119614Sache    case CISS_CMD_STATUS_DATA_OVERRUN:
1402119614Sache	ciss_printf(sc, "WARNING: Data overrun\n");
1403119614Sache	break;
140421308Sache    default:
1405119614Sache	ciss_printf(sc, "Error detecting logical drive geometry (%s)\n",
1406119614Sache		    ciss_name_command_status(command_status));
1407119614Sache	break;
1408119614Sache    }
1409119614Sache
1410119614Sacheout:
141121308Sache    if (cr != NULL)
141221308Sache	ciss_release_request(cr);
141321308Sache    return(error);
141421308Sache}
141521308Sache/************************************************************************
141621308Sache * Identify a logical drive, initialise state related to it.
141721308Sache */
1418157188Sachestatic int
141921308Sacheciss_identify_logical(struct ciss_softc *sc, struct ciss_ldrive *ld)
142021308Sache{
142121308Sache    struct ciss_request		*cr;
142221308Sache    struct ciss_command		*cc;
142321308Sache    struct ciss_bmic_cdb	*cbc;
142421308Sache    int				error, command_status;
142521308Sache
142621308Sache    debug_called(1);
142721308Sache
142821308Sache    cr = NULL;
142921308Sache
143021308Sache    /*
143121308Sache     * Build a BMIC request to fetch the drive ID.
143221308Sache     */
143321308Sache    if ((error = ciss_get_bmic_request(sc, &cr, CISS_BMIC_ID_LDRIVE,
1434165675Sache				       (void **)&ld->cl_ldrive,
143521308Sache				       sizeof(*ld->cl_ldrive))) != 0)
143621308Sache	goto out;
143775409Sache    cc = CISS_FIND_COMMAND(cr);
1438165675Sache    cc->header.address = *ld->cl_controller;	/* target controller */
143921308Sache    cbc = (struct ciss_bmic_cdb *)&(cc->cdb.cdb[0]);
144058314Sache    cbc->log_drive = CISS_LUN_TO_TARGET(ld->cl_address.logical.lun);
144158314Sache
144258314Sache    /*
144375409Sache     * Submit the request and wait for it to complete.
144458314Sache     */
144521308Sache    if ((error = ciss_synch_request(cr, 60 * 1000)) != 0) {
1446119614Sache	ciss_printf(sc, "error sending BMIC LDRIVE command (%d)\n", error);
1447157188Sache	goto out;
1448157188Sache    }
1449157188Sache
1450157188Sache    /*
1451157188Sache     * Check response.
1452157188Sache     */
1453119614Sache    ciss_report_request(cr, &command_status, NULL);
1454119614Sache    switch(command_status) {
145521308Sache    case CISS_CMD_STATUS_SUCCESS:		/* buffer right size */
145621308Sache	break;
1457165675Sache    case CISS_CMD_STATUS_DATA_UNDERRUN:
1458165675Sache    case CISS_CMD_STATUS_DATA_OVERRUN:
1459165675Sache	ciss_printf(sc, "data over/underrun reading logical drive ID\n");
146021308Sache    default:
1461165675Sache	ciss_printf(sc, "error reading logical drive ID (%s)\n",
1462165675Sache		    ciss_name_command_status(command_status));
1463165675Sache	error = EIO;
1464165675Sache	goto out;
1465165675Sache    }
1466165675Sache    ciss_release_request(cr);
1467165675Sache    cr = NULL;
1468165675Sache
1469165675Sache    /*
147021308Sache     * Build a CISS BMIC command to get the logical drive status.
1471119614Sache     */
1472119614Sache    if ((error = ciss_get_ldrive_status(sc, ld)) != 0)
1473119614Sache	goto out;
1474119614Sache
147521308Sache    /*
1476119614Sache     * Get the logical drive geometry.
1477119614Sache     */
1478119614Sache    if ((error = ciss_inquiry_logical(sc, ld)) != 0)
1479119614Sache	goto out;
148021308Sache
148121308Sache    /*
148221308Sache     * Print the drive's basic characteristics.
148321308Sache     */
148421308Sache    if (bootverbose) {
148521308Sache	ciss_printf(sc, "logical drive (b%dt%d): %s, %dMB ",
1486119614Sache		    CISS_LUN_TO_BUS(ld->cl_address.logical.lun),
1487119614Sache		    CISS_LUN_TO_TARGET(ld->cl_address.logical.lun),
1488119614Sache		    ciss_name_ldrive_org(ld->cl_ldrive->fault_tolerance),
1489119614Sache		    ((ld->cl_ldrive->blocks_available / (1024 * 1024)) *
1490119614Sache		     ld->cl_ldrive->block_size));
1491119614Sache
1492119614Sache	ciss_print_ldrive(sc, ld);
1493119614Sache    }
1494119614Sacheout:
1495119614Sache    if (error != 0) {
1496119614Sache	/* make the drive not-exist */
1497119614Sache	ld->cl_status = CISS_LD_NONEXISTENT;
149821308Sache	if (ld->cl_ldrive != NULL) {
149921308Sache	    free(ld->cl_ldrive, CISS_MALLOC_CLASS);
150021308Sache	    ld->cl_ldrive = NULL;
1501119614Sache	}
1502119614Sache	if (ld->cl_lstatus != NULL) {
1503119614Sache	    free(ld->cl_lstatus, CISS_MALLOC_CLASS);
1504119614Sache	    ld->cl_lstatus = NULL;
1505119614Sache	}
1506119614Sache    }
150721308Sache    if (cr != NULL)
150821308Sache	ciss_release_request(cr);
150921308Sache
151021308Sache    return(error);
151121308Sache}
151221308Sache
151321308Sache/************************************************************************
1514119614Sache * Get status for a logical drive.
151521308Sache *
151675409Sache * XXX should we also do this in response to Test Unit Ready?
151721308Sache */
151875409Sachestatic int
151921308Sacheciss_get_ldrive_status(struct ciss_softc *sc,  struct ciss_ldrive *ld)
152021308Sache{
152175409Sache    struct ciss_request		*cr;
152221308Sache    struct ciss_command		*cc;
1523119614Sache    struct ciss_bmic_cdb	*cbc;
1524119614Sache    int				error, command_status;
152521308Sache
1526157188Sache    /*
152721308Sache     * Build a CISS BMIC command to get the logical drive status.
152821308Sache     */
152921308Sache    if ((error = ciss_get_bmic_request(sc, &cr, CISS_BMIC_ID_LSTATUS,
153021308Sache				       (void **)&ld->cl_lstatus,
153147563Sache				       sizeof(*ld->cl_lstatus))) != 0)
153221308Sache	goto out;
1533119614Sache    cc = CISS_FIND_COMMAND(cr);
153421308Sache    cc->header.address = *ld->cl_controller;	/* target controller */
153521308Sache    cbc = (struct ciss_bmic_cdb *)&(cc->cdb.cdb[0]);
153621308Sache    cbc->log_drive = CISS_LUN_TO_TARGET(ld->cl_address.logical.lun);
153721308Sache
153821308Sache    /*
153921308Sache     * Submit the request and wait for it to complete.
154021308Sache     */
1541119614Sache    if ((error = ciss_synch_request(cr, 60 * 1000)) != 0) {
154221308Sache	ciss_printf(sc, "error sending BMIC LSTATUS command (%d)\n", error);
154321308Sache	goto out;
154421308Sache    }
154521308Sache
154621308Sache    /*
154721308Sache     * Check response.
154821308Sache     */
1549136759Speter    ciss_report_request(cr, &command_status, NULL);
1550136759Speter    switch(command_status) {
1551136759Speter    case CISS_CMD_STATUS_SUCCESS:		/* buffer right size */
1552136759Speter	break;
1553136759Speter    case CISS_CMD_STATUS_DATA_UNDERRUN:
1554136759Speter    case CISS_CMD_STATUS_DATA_OVERRUN:
1555119614Sache	ciss_printf(sc, "data over/underrun reading logical drive status\n");
1556136759Speter    default:
1557119614Sache	ciss_printf(sc, "error reading logical drive status (%s)\n",
155821308Sache		    ciss_name_command_status(command_status));
155921308Sache	error = EIO;
156021308Sache	goto out;
156121308Sache    }
156221308Sache
156321308Sache    /*
1564119614Sache     * Set the drive's summary status based on the returned status.
1565157188Sache     *
1566157188Sache     * XXX testing shows that a failed JBOD drive comes back at next
1567157188Sache     * boot in "queued for expansion" mode.  WTF?
1568157188Sache     */
156921308Sache    ld->cl_status = ciss_decode_ldrive_status(ld->cl_lstatus->status);
157021308Sache
157121308Sacheout:
157221308Sache    if (cr != NULL)
157321308Sache	ciss_release_request(cr);
1574119614Sache    return(error);
157521308Sache}
157621308Sache
157721308Sache/************************************************************************
157821308Sache * Notify the adapter of a config update.
157921308Sache */
158021308Sachestatic int
1581119614Sacheciss_update_config(struct ciss_softc *sc)
158221308Sache{
1583119614Sache    int		i;
1584119614Sache
158521308Sache    debug_called(1);
158621308Sache
158721308Sache    CISS_TL_SIMPLE_WRITE(sc, CISS_TL_SIMPLE_IDBR, CISS_TL_SIMPLE_IDBR_CFG_TABLE);
158821308Sache    for (i = 0; i < 1000; i++) {
158921308Sache	if (!(CISS_TL_SIMPLE_READ(sc, CISS_TL_SIMPLE_IDBR) &
159021308Sache	      CISS_TL_SIMPLE_IDBR_CFG_TABLE)) {
1591119614Sache	    return(0);
159221308Sache	}
159321308Sache	DELAY(1000);
159421308Sache    }
159521308Sache    return(1);
159621308Sache}
159721308Sache
159821308Sache/************************************************************************
159921308Sache * Accept new media into a logical drive.
1600157188Sache *
160121308Sache * XXX The drive has previously been offline; it would be good if we
160221308Sache *     could make sure it's not open right now.
1603119614Sache */
1604119614Sachestatic int
1605119614Sacheciss_accept_media(struct ciss_softc *sc, struct ciss_ldrive *ld)
1606119614Sache{
1607119614Sache    struct ciss_request		*cr;
1608119614Sache    struct ciss_command		*cc;
160947563Sache    struct ciss_bmic_cdb	*cbc;
161047563Sache    int				command_status;
1611119614Sache    int				error = 0, ldrive;
161247563Sache
1613119614Sache    ldrive = CISS_LUN_TO_TARGET(ld->cl_address.logical.lun);
161447563Sache
161521308Sache    debug(0, "bringing logical drive %d back online");
161621308Sache
161721308Sache    /*
161821308Sache     * Build a CISS BMIC command to bring the drive back online.
161921308Sache     */
162021308Sache    if ((error = ciss_get_bmic_request(sc, &cr, CISS_BMIC_ACCEPT_MEDIA,
162121308Sache				       NULL, 0)) != 0)
162221308Sache	goto out;
162321308Sache    cc = CISS_FIND_COMMAND(cr);
162421308Sache    cc->header.address = *ld->cl_controller;	/* target controller */
162521308Sache    cbc = (struct ciss_bmic_cdb *)&(cc->cdb.cdb[0]);
162621308Sache    cbc->log_drive = ldrive;
162721308Sache
162821308Sache    /*
162921308Sache     * Submit the request and wait for it to complete.
163021308Sache     */
163121308Sache    if ((error = ciss_synch_request(cr, 60 * 1000)) != 0) {
163221308Sache	ciss_printf(sc, "error sending BMIC ACCEPT MEDIA command (%d)\n", error);
163321308Sache	goto out;
163458314Sache    }
163558314Sache
1636136759Speter    /*
1637136759Speter     * Check response.
163858314Sache     */
163958314Sache    ciss_report_request(cr, &command_status, NULL);
164058314Sache    switch(command_status) {
164158314Sache    case CISS_CMD_STATUS_SUCCESS:		/* all OK */
1642136759Speter	/* we should get a logical drive status changed event here */
164358314Sache	break;
164458314Sache    default:
164558314Sache	ciss_printf(cr->cr_sc, "error accepting media into failed logical drive (%s)\n",
164658314Sache		    ciss_name_command_status(command_status));
164758314Sache	break;
164858314Sache    }
164958314Sache
165058314Sacheout:
1651136759Speter    if (cr != NULL)
1652136759Speter	ciss_release_request(cr);
1653136759Speter    return(error);
165458314Sache}
165558314Sache
165658314Sache/************************************************************************
165758314Sache * Release adapter resources.
165858314Sache */
165958314Sachestatic void
166058314Sacheciss_free(struct ciss_softc *sc)
1661119614Sache{
1662157188Sache    struct ciss_request *cr;
1663119614Sache    int			i, j;
1664119614Sache
166558314Sache    debug_called(1);
166658314Sache
166758314Sache    /* we're going away */
166858314Sache    sc->ciss_flags |= CISS_FLAG_ABORTING;
166975409Sache
167058314Sache    /* terminate the periodic heartbeat routine */
167158314Sache    callout_stop(&sc->ciss_periodic);
167258314Sache
167358314Sache    /* cancel the Event Notify chain */
167458314Sache    ciss_notify_abort(sc);
167558314Sache
167658314Sache    ciss_kill_notify_thread(sc);
167758314Sache
167858314Sache    /* disconnect from CAM */
167958314Sache    if (sc->ciss_cam_sim) {
168058314Sache	for (i = 0; i < sc->ciss_max_logical_bus; i++) {
168158314Sache	    if (sc->ciss_cam_sim[i]) {
168258314Sache		xpt_bus_deregister(cam_sim_path(sc->ciss_cam_sim[i]));
168358314Sache		cam_sim_free(sc->ciss_cam_sim[i], 0);
168458314Sache	    }
168558314Sache	}
168658314Sache	for (i = CISS_PHYSICAL_BASE; i < sc->ciss_max_physical_bus +
168758314Sache	     CISS_PHYSICAL_BASE; i++) {
1688136759Speter	    if (sc->ciss_cam_sim[i]) {
1689136759Speter		xpt_bus_deregister(cam_sim_path(sc->ciss_cam_sim[i]));
169058314Sache		cam_sim_free(sc->ciss_cam_sim[i], 0);
169158314Sache	    }
169258314Sache	}
169321308Sache	free(sc->ciss_cam_sim, CISS_MALLOC_CLASS);
169421308Sache    }
169521308Sache    if (sc->ciss_cam_devq)
169621308Sache	cam_simq_free(sc->ciss_cam_devq);
1697165675Sache
1698165675Sache    /* remove the control device */
169921308Sache    mtx_unlock(&sc->ciss_mtx);
170021308Sache    if (sc->ciss_dev_t != NULL)
1701165675Sache	destroy_dev(sc->ciss_dev_t);
170221308Sache
170347563Sache    /* Final cleanup of the callout. */
170421308Sache    callout_drain(&sc->ciss_periodic);
170521308Sache    mtx_destroy(&sc->ciss_mtx);
170621308Sache
170721308Sache    /* free the controller data */
170821308Sache    if (sc->ciss_id != NULL)
170921308Sache	free(sc->ciss_id, CISS_MALLOC_CLASS);
171021308Sache
171121308Sache    /* release I/O resources */
1712157188Sache    if (sc->ciss_regs_resource != NULL)
1713157188Sache	bus_release_resource(sc->ciss_dev, SYS_RES_MEMORY,
171421308Sache			     sc->ciss_regs_rid, sc->ciss_regs_resource);
171521308Sache    if (sc->ciss_cfg_resource != NULL)
171621308Sache	bus_release_resource(sc->ciss_dev, SYS_RES_MEMORY,
171721308Sache			     sc->ciss_cfg_rid, sc->ciss_cfg_resource);
171821308Sache    if (sc->ciss_intr != NULL)
171975409Sache	bus_teardown_intr(sc->ciss_dev, sc->ciss_irq_resource, sc->ciss_intr);
172021308Sache    if (sc->ciss_irq_resource != NULL)
172121308Sache	bus_release_resource(sc->ciss_dev, SYS_RES_IRQ,
1722157188Sache			     sc->ciss_irq_rid, sc->ciss_irq_resource);
1723157188Sache
172421308Sache    /* destroy DMA tags */
1725157188Sache    if (sc->ciss_parent_dmat)
1726157188Sache	bus_dma_tag_destroy(sc->ciss_parent_dmat);
1727119614Sache
1728119614Sache    while ((cr = ciss_dequeue_free(sc)) != NULL)
1729119614Sache	bus_dmamap_destroy(sc->ciss_buffer_dmat, cr->cr_datamap);
1730136759Speter    if (sc->ciss_buffer_dmat)
1731157188Sache	bus_dma_tag_destroy(sc->ciss_buffer_dmat);
1732157188Sache
1733157188Sache    /* destroy command memory and DMA tag */
1734136759Speter    if (sc->ciss_command != NULL) {
1735157188Sache	bus_dmamap_unload(sc->ciss_command_dmat, sc->ciss_command_map);
1736165675Sache	bus_dmamem_free(sc->ciss_command_dmat, sc->ciss_command, sc->ciss_command_map);
1737165675Sache    }
1738165675Sache    if (sc->ciss_command_dmat)
1739165675Sache	bus_dma_tag_destroy(sc->ciss_command_dmat);
1740165675Sache
1741165675Sache    if (sc->ciss_logical) {
1742165675Sache	for (i = 0; i <= sc->ciss_max_logical_bus; i++) {
1743165675Sache	    for (j = 0; j < CISS_MAX_LOGICAL; j++) {
1744136759Speter		if (sc->ciss_logical[i][j].cl_ldrive)
1745157188Sache		    free(sc->ciss_logical[i][j].cl_ldrive, CISS_MALLOC_CLASS);
1746119614Sache		if (sc->ciss_logical[i][j].cl_lstatus)
1747157188Sache		    free(sc->ciss_logical[i][j].cl_lstatus, CISS_MALLOC_CLASS);
174821308Sache	    }
1749157188Sache	    free(sc->ciss_logical[i], CISS_MALLOC_CLASS);
1750157188Sache	}
1751157188Sache	free(sc->ciss_logical, CISS_MALLOC_CLASS);
1752157188Sache    }
175321308Sache
175421308Sache    if (sc->ciss_physical) {
175521308Sache	for (i = 0; i < sc->ciss_max_physical_bus; i++)
1756157188Sache	    free(sc->ciss_physical[i], CISS_MALLOC_CLASS);
1757157188Sache	free(sc->ciss_physical, CISS_MALLOC_CLASS);
1758157188Sache    }
1759157188Sache
1760157188Sache    if (sc->ciss_controllers)
1761157188Sache	free(sc->ciss_controllers, CISS_MALLOC_CLASS);
1762165675Sache
176375409Sache}
176421308Sache
176521308Sache/************************************************************************
176621308Sache * Give a command to the adapter.
176721308Sache *
176875409Sache * Note that this uses the simple transport layer directly.  If we
176921308Sache * want to add support for other layers, we'll need a switch of some
1770157188Sache * sort.
177121308Sache *
177221308Sache * Note that the simple transport layer has no way of refusing a
1773157188Sache * command; we only have as many request structures as the adapter
177421308Sache * supports commands, so we don't have to check (this presumes that
177521308Sache * the adapter can handle commands as fast as we throw them at it).
177621308Sache */
177721308Sachestatic int
177821308Sacheciss_start(struct ciss_request *cr)
177921308Sache{
178021308Sache    struct ciss_command	*cc;	/* XXX debugging only */
178121308Sache    int			error;
178221308Sache
178321308Sache    cc = CISS_FIND_COMMAND(cr);
1784165675Sache    debug(2, "post command %d tag %d ", cr->cr_tag, cc->header.host_tag);
1785165675Sache
1786165675Sache    /*
1787165675Sache     * Map the request's data.
1788165675Sache     */
1789165675Sache    if ((error = ciss_map_request(cr)))
1790165675Sache	return(error);
1791165675Sache
1792119614Sache#if 0
1793119614Sache    ciss_print_request(cr);
1794165675Sache#endif
1795165675Sache
1796165675Sache    return(0);
1797165675Sache}
1798165675Sache
1799165675Sache/************************************************************************
1800165675Sache * Fetch completed request(s) from the adapter, queue them for
1801165675Sache * completion handling.
1802165675Sache *
1803165675Sache * Note that this uses the simple transport layer directly.  If we
1804165675Sache * want to add support for other layers, we'll need a switch of some
1805119614Sache * sort.
180621308Sache *
1807157188Sache * Note that the simple transport mechanism does not require any
180821308Sache * reentrancy protection; the OPQ read is atomic.  If there is a
1809157188Sache * chance of a race with something else that might move the request
1810119614Sache * off the busy list, then we will have to lock against that
1811119614Sache * (eg. timeouts, etc.)
1812119614Sache */
1813119614Sachestatic void
1814119614Sacheciss_done(struct ciss_softc *sc)
1815119614Sache{
1816119614Sache    struct ciss_request	*cr;
1817157188Sache    struct ciss_command	*cc;
1818157188Sache    u_int32_t		tag, index;
1819119614Sache    int			complete;
1820157188Sache
182121308Sache    debug_called(3);
182221308Sache
182321308Sache    /*
182421308Sache     * Loop quickly taking requests from the adapter and moving them
182521308Sache     * from the busy queue to the completed queue.
182621308Sache     */
182721308Sache    complete = 0;
182821308Sache    for (;;) {
182921308Sache
183075409Sache	/* see if the OPQ contains anything */
183121308Sache	if (!CISS_TL_SIMPLE_OPQ_INTERRUPT(sc))
183221308Sache	    break;
183321308Sache
183421308Sache	tag = CISS_TL_SIMPLE_FETCH_CMD(sc);
183521308Sache	if (tag == CISS_TL_SIMPLE_OPQ_EMPTY)
183621308Sache	    break;
183758314Sache	index = tag >> 2;
183858314Sache	debug(2, "completed command %d%s", index,
183958314Sache	      (tag & CISS_HDR_HOST_TAG_ERROR) ? " with error" : "");
184075409Sache	if (index >= sc->ciss_max_requests) {
184158314Sache	    ciss_printf(sc, "completed invalid request %d (0x%x)\n", index, tag);
184221308Sache	    continue;
184321308Sache	}
184421308Sache	cr = &(sc->ciss_request[index]);
184521308Sache	cc = CISS_FIND_COMMAND(cr);
184675409Sache	cc->header.host_tag = tag;	/* not updated by adapter */
184721308Sache	if (ciss_remove_busy(cr)) {
184875409Sache	    /* assume this is garbage out of the adapter */
184921308Sache	    ciss_printf(sc, "completed nonbusy request %d\n", index);
185058314Sache	} else {
185121308Sache	    ciss_enqueue_complete(cr);
185221308Sache	}
185321308Sache	complete = 1;
185421308Sache    }
185521308Sache
185621308Sache    /*
185721308Sache     * Invoke completion processing.  If we can defer this out of
185821308Sache     * interrupt context, that'd be good.
185921308Sache     */
186021308Sache    if (complete)
186121308Sache	ciss_complete(sc);
186221308Sache}
186321308Sache
186421308Sache/************************************************************************
186521308Sache * Take an interrupt from the adapter.
186621308Sache */
186721308Sachestatic void
186821308Sacheciss_intr(void *arg)
186921308Sache{
187021308Sache    struct ciss_softc	*sc = (struct ciss_softc *)arg;
187121308Sache
187221308Sache    /*
187321308Sache     * The only interrupt we recognise indicates that there are
187421308Sache     * entries in the outbound post queue.
187521308Sache     */
187621308Sache    mtx_lock(&sc->ciss_mtx);
187721308Sache    ciss_done(sc);
187821308Sache    mtx_unlock(&sc->ciss_mtx);
187921308Sache}
188021308Sache
188121308Sache/************************************************************************
188221308Sache * Process completed requests.
188321308Sache *
188421308Sache * Requests can be completed in three fashions:
188521308Sache *
188621308Sache * - by invoking a callback function (cr_complete is non-null)
188721308Sache * - by waking up a sleeper (cr_flags has CISS_REQ_SLEEP set)
188821308Sache * - by clearing the CISS_REQ_POLL flag in interrupt/timeout context
188921308Sache */
189021308Sachestatic void
189121308Sacheciss_complete(struct ciss_softc *sc)
189221308Sache{
189321308Sache    struct ciss_request	*cr;
189421308Sache
189521308Sache    debug_called(2);
189621308Sache
189721308Sache    /*
189821308Sache     * Loop taking requests off the completed queue and performing
189921308Sache     * completion processing on them.
190021308Sache     */
190121308Sache    for (;;) {
190221308Sache	if ((cr = ciss_dequeue_complete(sc)) == NULL)
190321308Sache	    break;
190421308Sache	ciss_unmap_request(cr);
190521308Sache
190621308Sache	/*
1907119614Sache	 * If the request has a callback, invoke it.
190821308Sache	 */
190921308Sache	if (cr->cr_complete != NULL) {
191021308Sache	    cr->cr_complete(cr);
1911157188Sache	    continue;
191221308Sache	}
191321308Sache
191421308Sache	/*
191521308Sache	 * If someone is sleeping on this request, wake them up.
191621308Sache	 */
191721308Sache	if (cr->cr_flags & CISS_REQ_SLEEP) {
191821308Sache	    cr->cr_flags &= ~CISS_REQ_SLEEP;
191921308Sache	    wakeup(cr);
192021308Sache	    continue;
192121308Sache	}
192221308Sache
192321308Sache	/*
192421308Sache	 * If someone is polling this request for completion, signal.
192521308Sache	 */
192621308Sache	if (cr->cr_flags & CISS_REQ_POLL) {
192721308Sache	    cr->cr_flags &= ~CISS_REQ_POLL;
192821308Sache	    continue;
192921308Sache	}
193021308Sache
193121308Sache	/*
193221308Sache	 * Give up and throw the request back on the free queue.  This
193321308Sache	 * should never happen; resources will probably be lost.
1934119614Sache	 */
1935119614Sache	ciss_printf(sc, "WARNING: completed command with no submitter\n");
1936119614Sache	ciss_enqueue_free(cr);
193721308Sache    }
1938119614Sache}
1939119614Sache
194021308Sache/************************************************************************
194121308Sache * Report on the completion status of a request, and pass back SCSI
1942157188Sache * and command status values.
1943157188Sache */
1944157188Sachestatic int
1945157188Sacheciss_report_request(struct ciss_request *cr, int *command_status, int *scsi_status)
1946157188Sache{
194721308Sache    struct ciss_command		*cc;
1948157188Sache    struct ciss_error_info	*ce;
1949157188Sache
1950157188Sache    debug_called(2);
1951157188Sache
1952157188Sache    cc = CISS_FIND_COMMAND(cr);
1953165675Sache    ce = (struct ciss_error_info *)&(cc->sg[0]);
195421308Sache
1955157188Sache    /*
195621308Sache     * We don't consider data under/overrun an error for the Report
195721308Sache     * Logical/Physical LUNs commands.
195821308Sache     */
195921308Sache    if ((cc->header.host_tag & CISS_HDR_HOST_TAG_ERROR) &&
196021308Sache	((ce->command_status == CISS_CMD_STATUS_DATA_OVERRUN) ||
196121308Sache	 (ce->command_status == CISS_CMD_STATUS_DATA_UNDERRUN)) &&
196221308Sache	((cc->cdb.cdb[0] == CISS_OPCODE_REPORT_LOGICAL_LUNS) ||
196321308Sache	 (cc->cdb.cdb[0] == CISS_OPCODE_REPORT_PHYSICAL_LUNS) ||
1964119614Sache	 (cc->cdb.cdb[0] == INQUIRY))) {
1965157188Sache	cc->header.host_tag &= ~CISS_HDR_HOST_TAG_ERROR;
196621308Sache	debug(2, "ignoring irrelevant under/overrun error");
1967157188Sache    }
1968157188Sache
1969157188Sache    /*
1970157188Sache     * Check the command's error bit, if clear, there's no status and
1971157188Sache     * everything is OK.
1972157188Sache     */
1973157188Sache    if (!(cc->header.host_tag & CISS_HDR_HOST_TAG_ERROR)) {
1974157188Sache	if (scsi_status != NULL)
1975157188Sache	    *scsi_status = SCSI_STATUS_OK;
1976157188Sache	if (command_status != NULL)
1977165675Sache	    *command_status = CISS_CMD_STATUS_SUCCESS;
197821308Sache	return(0);
1979157188Sache    } else {
198021308Sache	if (command_status != NULL)
198121308Sache	    *command_status = ce->command_status;
198221308Sache	if (scsi_status != NULL) {
198321308Sache	    if (ce->command_status == CISS_CMD_STATUS_TARGET_STATUS) {
198421308Sache		*scsi_status = ce->scsi_status;
198521308Sache	    } else {
198621308Sache		*scsi_status = -1;
198721308Sache	    }
198821308Sache	}
1989157188Sache	if (bootverbose)
1990157188Sache	    ciss_printf(cr->cr_sc, "command status 0x%x (%s) scsi status 0x%x\n",
1991157188Sache			ce->command_status, ciss_name_command_status(ce->command_status),
1992157188Sache			ce->scsi_status);
1993157188Sache	if (ce->command_status == CISS_CMD_STATUS_INVALID_COMMAND) {
199421308Sache	    ciss_printf(cr->cr_sc, "invalid command, offense size %d at %d, value 0x%x\n",
199521308Sache			ce->additional_error_info.invalid_command.offense_size,
199621308Sache			ce->additional_error_info.invalid_command.offense_offset,
199721308Sache			ce->additional_error_info.invalid_command.offense_value);
199821308Sache	}
199921308Sache    }
200021308Sache#if 0
200121308Sache    ciss_print_request(cr);
200221308Sache#endif
200321308Sache    return(1);
200421308Sache}
200521308Sache
200621308Sache/************************************************************************
200721308Sache * Issue a request and don't return until it's completed.
200821308Sache *
200947563Sache * Depending on adapter status, we may poll or sleep waiting for
201021308Sache * completion.
201121308Sache */
201221308Sachestatic int
2013157188Sacheciss_synch_request(struct ciss_request *cr, int timeout)
2014165675Sache{
201575409Sache    if (cr->cr_sc->ciss_flags & CISS_FLAG_RUNNING) {
201675409Sache	return(ciss_wait_request(cr, timeout));
2017136759Speter    } else {
2018136759Speter	return(ciss_poll_request(cr, timeout));
201921308Sache    }
202021308Sache}
2021165675Sache
2022157188Sache/************************************************************************
2023136759Speter * Issue a request and poll for completion.
202421308Sache *
202521308Sache * Timeout in milliseconds.
202621308Sache */
202747563Sachestatic int
202821308Sacheciss_poll_request(struct ciss_request *cr, int timeout)
202975409Sache{
203075409Sache    int		error;
203121308Sache
203221308Sache    debug_called(2);
203321308Sache
2034165675Sache    cr->cr_flags |= CISS_REQ_POLL;
2035157188Sache    if ((error = ciss_start(cr)) != 0)
203675409Sache	return(error);
203775409Sache
2038136759Speter    do {
2039136759Speter	ciss_done(cr->cr_sc);
2040157188Sache	if (!(cr->cr_flags & CISS_REQ_POLL))
2041157188Sache	    return(0);
2042157188Sache	DELAY(1000);
2043165675Sache    } while (timeout-- >= 0);
2044157188Sache    return(EWOULDBLOCK);
2045157188Sache}
204621308Sache
204721308Sache/************************************************************************
204821308Sache * Issue a request and sleep waiting for completion.
204921308Sache *
205021308Sache * Timeout in milliseconds.  Note that a spurious wakeup will reset
205121308Sache * the timeout.
205221308Sache */
2053157195Sachestatic int
205421308Sacheciss_wait_request(struct ciss_request *cr, int timeout)
205547563Sache{
205621308Sache    int		s, error;
2057157195Sache
2058157195Sache    debug_called(2);
2059157195Sache
2060157195Sache    cr->cr_flags |= CISS_REQ_SLEEP;
2061157195Sache    if ((error = ciss_start(cr)) != 0)
206221308Sache	return(error);
206321308Sache
2064119614Sache    s = splcam();
206521308Sache    while ((cr->cr_flags & CISS_REQ_SLEEP) && (error != EWOULDBLOCK)) {
206647563Sache	error = msleep(cr, &cr->cr_sc->ciss_mtx, PRIBIO, "cissREQ", (timeout * hz) / 1000);
206721308Sache    }
206821308Sache    splx(s);
206921308Sache    return(error);
207021308Sache}
207121308Sache
2072157195Sache#if 0
2073157195Sache/************************************************************************
2074119614Sache * Abort a request.  Note that a potential exists here to race the
207521308Sache * request being completed; the caller must deal with this.
2076157195Sache */
207721308Sachestatic int
207821308Sacheciss_abort_request(struct ciss_request *ar)
2079157195Sache{
2080136759Speter    struct ciss_request		*cr;
2081157195Sache    struct ciss_command		*cc;
2082157188Sache    struct ciss_message_cdb	*cmc;
208321308Sache    int				error;
208421308Sache
208521308Sache    debug_called(1);
208621308Sache
208721308Sache    /* get a request */
208821308Sache    if ((error = ciss_get_request(ar->cr_sc, &cr)) != 0)
208921308Sache	return(error);
209021308Sache
209121308Sache    /* build the abort command */
209221308Sache    cc = CISS_FIND_COMMAND(cr);
209321308Sache    cc->header.address.mode.mode = CISS_HDR_ADDRESS_MODE_PERIPHERAL;	/* addressing? */
209421308Sache    cc->header.address.physical.target = 0;
209521308Sache    cc->header.address.physical.bus = 0;
209621308Sache    cc->cdb.cdb_length = sizeof(*cmc);
209721308Sache    cc->cdb.type = CISS_CDB_TYPE_MESSAGE;
209821308Sache    cc->cdb.attribute = CISS_CDB_ATTRIBUTE_SIMPLE;
209921308Sache    cc->cdb.direction = CISS_CDB_DIRECTION_NONE;
210021308Sache    cc->cdb.timeout = 30;
210121308Sache
210221308Sache    cmc = (struct ciss_message_cdb *)&(cc->cdb.cdb[0]);
210321308Sache    cmc->opcode = CISS_OPCODE_MESSAGE_ABORT;
210426497Sache    cmc->type = CISS_MESSAGE_ABORT_TASK;
210526497Sache    cmc->abort_tag = ar->cr_tag;	/* endianness?? */
210621308Sache
210721308Sache    /*
210875409Sache     * Send the request and wait for a response.  If we believe we
210975409Sache     * aborted the request OK, clear the flag that indicates it's
211026497Sache     * running.
211121308Sache     */
211221308Sache    error = ciss_synch_request(cr, 35 * 1000);
211321308Sache    if (!error)
211421308Sache	error = ciss_report_request(cr, NULL, NULL);
211521308Sache    ciss_release_request(cr);
211621308Sache
211721308Sache    return(error);
211821308Sache}
211921308Sache#endif
212021308Sache
212121308Sache
212221308Sache/************************************************************************
212321308Sache * Fetch and initialise a request
212421308Sache */
212521308Sachestatic int
212621308Sacheciss_get_request(struct ciss_softc *sc, struct ciss_request **crp)
212721308Sache{
212826497Sache    struct ciss_request *cr;
212926497Sache
213026497Sache    debug_called(2);
213175409Sache
213275409Sache    /*
213326497Sache     * Get a request and clean it up.
213475409Sache     */
213526497Sache    if ((cr = ciss_dequeue_free(sc)) == NULL)
213626497Sache	return(ENOMEM);
2137119614Sache
213821308Sache    cr->cr_data = NULL;
2139119614Sache    cr->cr_flags = 0;
214021308Sache    cr->cr_complete = NULL;
2141119614Sache    cr->cr_private = NULL;
214221308Sache
2143157188Sache    ciss_preen_command(cr);
2144157188Sache    *crp = cr;
2145157188Sache    return(0);
2146119614Sache}
2147119614Sache
2148119614Sachestatic void
2149119614Sacheciss_preen_command(struct ciss_request *cr)
2150119614Sache{
215121308Sache    struct ciss_command	*cc;
215275409Sache    u_int32_t		cmdphys;
215321308Sache
215421308Sache    /*
2155119614Sache     * Clean up the command structure.
2156119614Sache     *
215721308Sache     * Note that we set up the error_info structure here, since the
215821308Sache     * length can be overwritten by any command.
215921308Sache     */
216021308Sache    cc = CISS_FIND_COMMAND(cr);
216121308Sache    cc->header.sg_in_list = 0;		/* kinda inefficient this way */
216221308Sache    cc->header.sg_total = 0;
216321308Sache    cc->header.host_tag = cr->cr_tag << 2;
216421308Sache    cc->header.host_tag_zeroes = 0;
216575409Sache    cmdphys = CISS_FIND_COMMANDPHYS(cr);
216675409Sache    cc->error_info.error_info_address = cmdphys + sizeof(struct ciss_command);
216721308Sache    cc->error_info.error_info_length = CISS_COMMAND_ALLOC_SIZE - sizeof(struct ciss_command);
216821308Sache}
216921308Sache
217075409Sache/************************************************************************
217121308Sache * Release a request to the free list.
2172119614Sache */
217375409Sachestatic void
217421308Sacheciss_release_request(struct ciss_request *cr)
217521308Sache{
217621308Sache    struct ciss_softc	*sc;
217721308Sache
217821308Sache    debug_called(2);
217921308Sache
218021308Sache    sc = cr->cr_sc;
218175409Sache
218275409Sache    /* release the request to the free queue */
218321308Sache    ciss_requeue_free(cr);
2184157188Sache}
218521308Sache
218621308Sache/************************************************************************
218721308Sache * Allocate a request that will be used to send a BMIC command.  Do some
218821308Sache * of the common setup here to avoid duplicating it everywhere else.
218921308Sache */
219021308Sachestatic int
219121308Sacheciss_get_bmic_request(struct ciss_softc *sc, struct ciss_request **crp,
219275409Sache		      int opcode, void **bufp, size_t bufsize)
219321308Sache{
219421308Sache    struct ciss_request		*cr;
2195157188Sache    struct ciss_command		*cc;
219675409Sache    struct ciss_bmic_cdb	*cbc;
219721308Sache    void			*buf;
219821308Sache    int				error;
219975409Sache    int				dataout;
220021308Sache
220121308Sache    debug_called(2);
220221308Sache
220321308Sache    cr = NULL;
220475409Sache    buf = NULL;
220521308Sache
220675409Sache    /*
220721308Sache     * Get a request.
2208157188Sache     */
220921308Sache    if ((error = ciss_get_request(sc, &cr)) != 0)
221021308Sache	goto out;
221121308Sache
221221308Sache    /*
221321308Sache     * Allocate data storage if requested, determine the data direction.
221421308Sache     */
221521308Sache    dataout = 0;
221621308Sache    if ((bufsize > 0) && (bufp != NULL)) {
221721308Sache	if (*bufp == NULL) {
221821308Sache	    if ((buf = malloc(bufsize, CISS_MALLOC_CLASS, M_NOWAIT | M_ZERO)) == NULL) {
221921308Sache		error = ENOMEM;
222026497Sache		goto out;
222121308Sache	    }
222221308Sache	} else {
222321308Sache	    buf = *bufp;
222421308Sache	    dataout = 1;	/* we are given a buffer, so we are writing */
222521308Sache	}
222621308Sache    }
222775409Sache
222821308Sache    /*
222921308Sache     * Build a CISS BMIC command to get the logical drive ID.
2230119614Sache     */
223158314Sache    cr->cr_data = buf;
2232165675Sache    cr->cr_length = bufsize;
2233165675Sache    if (!dataout)
223426497Sache	cr->cr_flags = CISS_REQ_DATAIN;
223575409Sache
223621308Sache    cc = CISS_FIND_COMMAND(cr);
223721308Sache    cc->header.address.physical.mode = CISS_HDR_ADDRESS_MODE_PERIPHERAL;
223875409Sache    cc->header.address.physical.bus = 0;
223921308Sache    cc->header.address.physical.target = 0;
224021308Sache    cc->cdb.cdb_length = sizeof(*cbc);
224121308Sache    cc->cdb.type = CISS_CDB_TYPE_COMMAND;
224221308Sache    cc->cdb.attribute = CISS_CDB_ATTRIBUTE_SIMPLE;
224321308Sache    cc->cdb.direction = dataout ? CISS_CDB_DIRECTION_WRITE : CISS_CDB_DIRECTION_READ;
224421308Sache    cc->cdb.timeout = 0;
224521308Sache
224621308Sache    cbc = (struct ciss_bmic_cdb *)&(cc->cdb.cdb[0]);
224775409Sache    bzero(cbc, sizeof(*cbc));
224821308Sache    cbc->opcode = dataout ? CISS_ARRAY_CONTROLLER_WRITE : CISS_ARRAY_CONTROLLER_READ;
224958314Sache    cbc->bmic_opcode = opcode;
225058314Sache    cbc->size = htons((u_int16_t)bufsize);
225158314Sache
225275409Sacheout:
225358314Sache    if (error) {
225421308Sache	if (cr != NULL)
225521308Sache	    ciss_release_request(cr);
225621308Sache    } else {
225721308Sache	*crp = cr;
225858314Sache	if ((bufp != NULL) && (*bufp == NULL) && (buf != NULL))
225958314Sache	    *bufp = buf;
226058314Sache    }
226158314Sache    return(error);
226258314Sache}
226358314Sache
226458314Sache/************************************************************************
2265157188Sache * Handle a command passed in from userspace.
226658314Sache */
226758314Sachestatic int
2268157188Sacheciss_user_command(struct ciss_softc *sc, IOCTL_Command_struct *ioc)
226958314Sache{
227058314Sache    struct ciss_request		*cr;
227175409Sache    struct ciss_command		*cc;
227275409Sache    struct ciss_error_info	*ce;
2273136759Speter    int				error = 0;
2274136759Speter
227558314Sache    debug_called(1);
2276165675Sache
2277157188Sache    cr = NULL;
227858314Sache
227958314Sache    /*
228058314Sache     * Get a request.
2281157188Sache     */
228258314Sache    while (ciss_get_request(sc, &cr) != 0)
228358314Sache	msleep(sc, &sc->ciss_mtx, PPAUSE, "cissREQ", hz);
228421308Sache    cc = CISS_FIND_COMMAND(cr);
228521308Sache
228621308Sache    /*
228721308Sache     * Allocate an in-kernel databuffer if required, copy in user data.
228858314Sache     */
228921308Sache    cr->cr_length = ioc->buf_size;
229021308Sache    if (ioc->buf_size > 0) {
229121308Sache	if ((cr->cr_data = malloc(ioc->buf_size, CISS_MALLOC_CLASS, M_NOWAIT)) == NULL) {
229275409Sache	    error = ENOMEM;
229321308Sache	    goto out;
229458314Sache	}
229558314Sache	if ((error = copyin(ioc->buf, cr->cr_data, ioc->buf_size))) {
229658314Sache	    debug(0, "copyin: bad data buffer %p/%d", ioc->buf, ioc->buf_size);
229775409Sache	    goto out;
229858314Sache	}
229921308Sache    }
230058314Sache
230175409Sache    /*
230258314Sache     * Build the request based on the user command.
230358314Sache     */
230475409Sache    bcopy(&ioc->LUN_info, &cc->header.address, sizeof(cc->header.address));
230575409Sache    bcopy(&ioc->Request, &cc->cdb, sizeof(cc->cdb));
230621308Sache
230721308Sache    /* XXX anything else to populate here? */
230875409Sache
230975409Sache    /*
231021308Sache     * Run the command.
231158314Sache     */
231221308Sache    if ((error = ciss_synch_request(cr, 60 * 1000))) {
231321308Sache	debug(0, "request failed - %d", error);
231421308Sache	goto out;
231521308Sache    }
231675409Sache
231721308Sache    /*
231821308Sache     * Check to see if the command succeeded.
231921308Sache     */
232021308Sache    ce = (struct ciss_error_info *)&(cc->sg[0]);
232158314Sache    if ((cc->header.host_tag & CISS_HDR_HOST_TAG_ERROR) == 0)
232221308Sache	bzero(ce, sizeof(*ce));
232321308Sache
232421308Sache    /*
232521308Sache     * Copy the results back to the user.
232621308Sache     */
232721308Sache    bcopy(ce, &ioc->error_info, sizeof(*ce));
232821308Sache    if ((ioc->buf_size > 0) &&
232921308Sache	(error = copyout(cr->cr_data, ioc->buf, ioc->buf_size))) {
233021308Sache	debug(0, "copyout: bad data buffer %p/%d", ioc->buf, ioc->buf_size);
233121308Sache	goto out;
233221308Sache    }
233321308Sache
233447563Sache    /* done OK */
233521308Sache    error = 0;
233621308Sache
233747563Sacheout:
233847563Sache    if ((cr != NULL) && (cr->cr_data != NULL))
233947563Sache	free(cr->cr_data, CISS_MALLOC_CLASS);
234047563Sache    if (cr != NULL)
234147563Sache	ciss_release_request(cr);
234247563Sache    return(error);
234347563Sache}
234447563Sache
234547563Sache/************************************************************************
234658314Sache * Map a request into bus-visible space, initialise the scatter/gather
234758314Sache * list.
234858314Sache */
234958314Sachestatic int
235058314Sacheciss_map_request(struct ciss_request *cr)
235158314Sache{
235258314Sache    struct ciss_softc	*sc;
235358314Sache    int			error = 0;
235458314Sache
235558314Sache    debug_called(2);
235658314Sache
235775409Sache    sc = cr->cr_sc;
235858314Sache
235975409Sache    /* check that mapping is necessary */
236058314Sache    if (cr->cr_flags & CISS_REQ_MAPPED)
236158314Sache	return(0);
236275409Sache
236358314Sache    cr->cr_flags |= CISS_REQ_MAPPED;
236458314Sache
236558314Sache    bus_dmamap_sync(sc->ciss_command_dmat, sc->ciss_command_map,
236658314Sache		    BUS_DMASYNC_PREWRITE);
236758314Sache
2368119614Sache    if (cr->cr_data != NULL) {
2369119614Sache	error = bus_dmamap_load(sc->ciss_buffer_dmat, cr->cr_datamap,
2370119614Sache				cr->cr_data, cr->cr_length,
2371119614Sache				ciss_request_map_helper, cr, 0);
2372119614Sache	if (error != 0)
2373119614Sache	    return (error);
2374119614Sache    } else {
2375136759Speter	/*
2376119614Sache	 * Post the command to the adapter.
2377119614Sache	 */
2378119614Sache	ciss_enqueue_busy(cr);
2379165675Sache	CISS_TL_SIMPLE_POST_CMD(cr->cr_sc, CISS_FIND_COMMANDPHYS(cr));
2380119614Sache    }
2381119614Sache
2382119614Sache    return(0);
2383119614Sache}
2384119614Sache
2385165675Sachestatic void
2386165675Sacheciss_request_map_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error)
2387119614Sache{
2388119614Sache    struct ciss_command	*cc;
2389119614Sache    struct ciss_request *cr;
2390119614Sache    struct ciss_softc	*sc;
2391119614Sache    int			i;
2392119614Sache
2393136759Speter    debug_called(2);
2394119614Sache
2395119614Sache    cr = (struct ciss_request *)arg;
2396119614Sache    sc = cr->cr_sc;
2397119614Sache    cc = CISS_FIND_COMMAND(cr);
2398119614Sache
2399119614Sache    for (i = 0; i < nseg; i++) {
2400119614Sache	cc->sg[i].address = segs[i].ds_addr;
2401119614Sache	cc->sg[i].length = segs[i].ds_len;
2402119614Sache	cc->sg[i].extension = 0;
2403119614Sache    }
2404119614Sache    /* we leave the s/g table entirely within the command */
2405136759Speter    cc->header.sg_in_list = nseg;
2406136759Speter    cc->header.sg_total = nseg;
2407119614Sache
2408119614Sache    if (cr->cr_flags & CISS_REQ_DATAIN)
2409119614Sache	bus_dmamap_sync(sc->ciss_buffer_dmat, cr->cr_datamap, BUS_DMASYNC_PREREAD);
2410119614Sache    if (cr->cr_flags & CISS_REQ_DATAOUT)
2411119614Sache	bus_dmamap_sync(sc->ciss_buffer_dmat, cr->cr_datamap, BUS_DMASYNC_PREWRITE);
2412119614Sache
2413119614Sache    /*
2414119614Sache     * Post the command to the adapter.
2415119614Sache     */
2416119614Sache    ciss_enqueue_busy(cr);
2417119614Sache    CISS_TL_SIMPLE_POST_CMD(cr->cr_sc, CISS_FIND_COMMANDPHYS(cr));
2418119614Sache}
2419119614Sache
2420119614Sache/************************************************************************
2421119614Sache * Unmap a request from bus-visible space.
2422136759Speter */
2423119614Sachestatic void
2424119614Sacheciss_unmap_request(struct ciss_request *cr)
2425119614Sache{
2426119614Sache    struct ciss_softc	*sc;
2427119614Sache
2428119614Sache    debug_called(2);
2429119614Sache
2430119614Sache    sc = cr->cr_sc;
2431119614Sache
2432119614Sache    /* check that unmapping is necessary */
2433119614Sache    if ((cr->cr_flags & CISS_REQ_MAPPED) == 0)
2434119614Sache	return;
2435119614Sache
2436119614Sache    bus_dmamap_sync(sc->ciss_command_dmat, sc->ciss_command_map,
2437136759Speter		    BUS_DMASYNC_POSTWRITE);
2438136759Speter
2439119614Sache    if (cr->cr_data == NULL)
2440119614Sache	goto out;
2441119614Sache
2442119614Sache    if (cr->cr_flags & CISS_REQ_DATAIN)
2443119614Sache	bus_dmamap_sync(sc->ciss_buffer_dmat, cr->cr_datamap, BUS_DMASYNC_POSTREAD);
2444119614Sache    if (cr->cr_flags & CISS_REQ_DATAOUT)
2445119614Sache	bus_dmamap_sync(sc->ciss_buffer_dmat, cr->cr_datamap, BUS_DMASYNC_POSTWRITE);
2446119614Sache
2447119614Sache    bus_dmamap_unload(sc->ciss_buffer_dmat, cr->cr_datamap);
2448119614Sacheout:
2449119614Sache    cr->cr_flags &= ~CISS_REQ_MAPPED;
2450119614Sache}
2451119614Sache
2452119614Sache/************************************************************************
2453 * Attach the driver to CAM.
2454 *
2455 * We put all the logical drives on a single SCSI bus.
2456 */
2457static int
2458ciss_cam_init(struct ciss_softc *sc)
2459{
2460    int			i, maxbus;
2461
2462    debug_called(1);
2463
2464    /*
2465     * Allocate a devq.  We can reuse this for the masked physical
2466     * devices if we decide to export these as well.
2467     */
2468    if ((sc->ciss_cam_devq = cam_simq_alloc(sc->ciss_max_requests)) == NULL) {
2469	ciss_printf(sc, "can't allocate CAM SIM queue\n");
2470	return(ENOMEM);
2471    }
2472
2473    /*
2474     * Create a SIM.
2475     *
2476     * This naturally wastes a bit of memory.  The alternative is to allocate
2477     * and register each bus as it is found, and then track them on a linked
2478     * list.  Unfortunately, the driver has a few places where it needs to
2479     * look up the SIM based solely on bus number, and it's unclear whether
2480     * a list traversal would work for these situations.
2481     */
2482    maxbus = max(sc->ciss_max_logical_bus, sc->ciss_max_physical_bus +
2483		 CISS_PHYSICAL_BASE);
2484    sc->ciss_cam_sim = malloc(maxbus * sizeof(struct cam_sim*),
2485			      CISS_MALLOC_CLASS, M_NOWAIT | M_ZERO);
2486    if (sc->ciss_cam_sim == NULL) {
2487	ciss_printf(sc, "can't allocate memory for controller SIM\n");
2488	return(ENOMEM);
2489    }
2490
2491    for (i = 0; i < sc->ciss_max_logical_bus; i++) {
2492	if ((sc->ciss_cam_sim[i] = cam_sim_alloc(ciss_cam_action, ciss_cam_poll,
2493						 "ciss", sc,
2494						 device_get_unit(sc->ciss_dev),
2495						 &sc->ciss_mtx,
2496						 sc->ciss_max_requests - 2,
2497						 sc->ciss_max_requests - 2,
2498						 sc->ciss_cam_devq)) == NULL) {
2499	    ciss_printf(sc, "can't allocate CAM SIM for controller %d\n", i);
2500	    return(ENOMEM);
2501	}
2502
2503	/*
2504	 * Register bus with this SIM.
2505	 */
2506	mtx_lock(&sc->ciss_mtx);
2507	if (i == 0 || sc->ciss_controllers[i].physical.bus != 0) {
2508	    if (xpt_bus_register(sc->ciss_cam_sim[i], sc->ciss_dev, i) != 0) {
2509		ciss_printf(sc, "can't register SCSI bus %d\n", i);
2510		mtx_unlock(&sc->ciss_mtx);
2511		return (ENXIO);
2512	    }
2513	}
2514	mtx_unlock(&sc->ciss_mtx);
2515    }
2516
2517    for (i = CISS_PHYSICAL_BASE; i < sc->ciss_max_physical_bus +
2518	 CISS_PHYSICAL_BASE; i++) {
2519	if ((sc->ciss_cam_sim[i] = cam_sim_alloc(ciss_cam_action, ciss_cam_poll,
2520						 "ciss", sc,
2521						 device_get_unit(sc->ciss_dev),
2522						 &sc->ciss_mtx, 1,
2523						 sc->ciss_max_requests - 2,
2524						 sc->ciss_cam_devq)) == NULL) {
2525	    ciss_printf(sc, "can't allocate CAM SIM for controller %d\n", i);
2526	    return (ENOMEM);
2527	}
2528
2529	mtx_lock(&sc->ciss_mtx);
2530	if (xpt_bus_register(sc->ciss_cam_sim[i], sc->ciss_dev, i) != 0) {
2531	    ciss_printf(sc, "can't register SCSI bus %d\n", i);
2532	    mtx_unlock(&sc->ciss_mtx);
2533	    return (ENXIO);
2534	}
2535	mtx_unlock(&sc->ciss_mtx);
2536    }
2537
2538    /*
2539     * Initiate a rescan of the bus.
2540     */
2541    mtx_lock(&sc->ciss_mtx);
2542    ciss_cam_rescan_all(sc);
2543    mtx_unlock(&sc->ciss_mtx);
2544
2545    return(0);
2546}
2547
2548/************************************************************************
2549 * Initiate a rescan of the 'logical devices' SIM
2550 */
2551static void
2552ciss_cam_rescan_target(struct ciss_softc *sc, int bus, int target)
2553{
2554    struct cam_path	*path;
2555    union ccb		*ccb;
2556
2557    debug_called(1);
2558
2559    if ((ccb = malloc(sizeof(union ccb), CISS_MALLOC_CLASS, M_NOWAIT | M_ZERO)) == NULL) {
2560	ciss_printf(sc, "rescan failed (can't allocate CCB)\n");
2561	return;
2562    }
2563
2564    if (xpt_create_path(&path, xpt_periph, cam_sim_path(sc->ciss_cam_sim[bus]),
2565			target, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
2566	ciss_printf(sc, "rescan failed (can't create path)\n");
2567	free(ccb, CISS_MALLOC_CLASS);
2568	return;
2569    }
2570
2571    xpt_setup_ccb(&ccb->ccb_h, path, 5/*priority (low)*/);
2572    ccb->ccb_h.func_code = XPT_SCAN_BUS;
2573    ccb->ccb_h.cbfcnp = ciss_cam_rescan_callback;
2574    ccb->crcn.flags = CAM_FLAG_NONE;
2575    xpt_action(ccb);
2576
2577    /* scan is now in progress */
2578}
2579
2580static void
2581ciss_cam_rescan_all(struct ciss_softc *sc)
2582{
2583    int i;
2584
2585    /* Rescan the logical buses */
2586    for (i = 0; i < sc->ciss_max_logical_bus; i++)
2587	ciss_cam_rescan_target(sc, i, CAM_TARGET_WILDCARD);
2588    /* Rescan the physical buses */
2589    for (i = CISS_PHYSICAL_BASE; i < sc->ciss_max_physical_bus +
2590	 CISS_PHYSICAL_BASE; i++)
2591	ciss_cam_rescan_target(sc, i, CAM_TARGET_WILDCARD);
2592}
2593
2594static void
2595ciss_cam_rescan_callback(struct cam_periph *periph, union ccb *ccb)
2596{
2597    xpt_free_path(ccb->ccb_h.path);
2598    free(ccb, CISS_MALLOC_CLASS);
2599}
2600
2601/************************************************************************
2602 * Handle requests coming from CAM
2603 */
2604static void
2605ciss_cam_action(struct cam_sim *sim, union ccb *ccb)
2606{
2607    struct ciss_softc	*sc;
2608    struct ccb_scsiio	*csio;
2609    int			bus, target;
2610    int			physical;
2611
2612    sc = cam_sim_softc(sim);
2613    bus = cam_sim_bus(sim);
2614    csio = (struct ccb_scsiio *)&ccb->csio;
2615    target = csio->ccb_h.target_id;
2616    physical = CISS_IS_PHYSICAL(bus);
2617
2618    switch (ccb->ccb_h.func_code) {
2619
2620	/* perform SCSI I/O */
2621    case XPT_SCSI_IO:
2622	if (!ciss_cam_action_io(sim, csio))
2623	    return;
2624	break;
2625
2626	/* perform geometry calculations */
2627    case XPT_CALC_GEOMETRY:
2628    {
2629	struct ccb_calc_geometry	*ccg = &ccb->ccg;
2630	struct ciss_ldrive		*ld;
2631
2632	debug(1, "XPT_CALC_GEOMETRY %d:%d:%d", cam_sim_bus(sim), ccb->ccb_h.target_id, ccb->ccb_h.target_lun);
2633
2634	ld = NULL;
2635	if (!physical)
2636	    ld = &sc->ciss_logical[bus][target];
2637
2638	/*
2639	 * Use the cached geometry settings unless the fault tolerance
2640	 * is invalid.
2641	 */
2642	if (physical || ld->cl_geometry.fault_tolerance == 0xFF) {
2643	    u_int32_t			secs_per_cylinder;
2644
2645	    ccg->heads = 255;
2646	    ccg->secs_per_track = 32;
2647	    secs_per_cylinder = ccg->heads * ccg->secs_per_track;
2648	    ccg->cylinders = ccg->volume_size / secs_per_cylinder;
2649	} else {
2650	    ccg->heads = ld->cl_geometry.heads;
2651	    ccg->secs_per_track = ld->cl_geometry.sectors;
2652	    ccg->cylinders = ntohs(ld->cl_geometry.cylinders);
2653	}
2654	ccb->ccb_h.status = CAM_REQ_CMP;
2655        break;
2656    }
2657
2658	/* handle path attribute inquiry */
2659    case XPT_PATH_INQ:
2660    {
2661	struct ccb_pathinq	*cpi = &ccb->cpi;
2662
2663	debug(1, "XPT_PATH_INQ %d:%d:%d", cam_sim_bus(sim), ccb->ccb_h.target_id, ccb->ccb_h.target_lun);
2664
2665	cpi->version_num = 1;
2666	cpi->hba_inquiry = PI_TAG_ABLE;	/* XXX is this correct? */
2667	cpi->target_sprt = 0;
2668	cpi->hba_misc = 0;
2669	cpi->max_target = CISS_MAX_LOGICAL;
2670	cpi->max_lun = 0;		/* 'logical drive' channel only */
2671	cpi->initiator_id = CISS_MAX_LOGICAL;
2672	strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
2673        strncpy(cpi->hba_vid, "msmith@freebsd.org", HBA_IDLEN);
2674        strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
2675        cpi->unit_number = cam_sim_unit(sim);
2676        cpi->bus_id = cam_sim_bus(sim);
2677	cpi->base_transfer_speed = 132 * 1024;	/* XXX what to set this to? */
2678	cpi->transport = XPORT_SPI;
2679	cpi->transport_version = 2;
2680	cpi->protocol = PROTO_SCSI;
2681	cpi->protocol_version = SCSI_REV_2;
2682	ccb->ccb_h.status = CAM_REQ_CMP;
2683	break;
2684    }
2685
2686    case XPT_GET_TRAN_SETTINGS:
2687    {
2688	struct ccb_trans_settings	*cts = &ccb->cts;
2689	int				bus, target;
2690	struct ccb_trans_settings_spi *spi =
2691	    &cts->xport_specific.spi;
2692
2693	bus = cam_sim_bus(sim);
2694	target = cts->ccb_h.target_id;
2695
2696	debug(1, "XPT_GET_TRAN_SETTINGS %d:%d", bus, target);
2697	/* disconnect always OK */
2698	cts->protocol = PROTO_SCSI;
2699	cts->protocol_version = SCSI_REV_2;
2700	cts->transport = XPORT_SPI;
2701	cts->transport_version = 2;
2702
2703	spi->valid = CTS_SPI_VALID_DISC;
2704	spi->flags = CTS_SPI_FLAGS_DISC_ENB;
2705
2706	cts->ccb_h.status = CAM_REQ_CMP;
2707	break;
2708    }
2709
2710    default:		/* we can't do this */
2711	debug(1, "unspported func_code = 0x%x", ccb->ccb_h.func_code);
2712	ccb->ccb_h.status = CAM_REQ_INVALID;
2713	break;
2714    }
2715
2716    xpt_done(ccb);
2717}
2718
2719/************************************************************************
2720 * Handle a CAM SCSI I/O request.
2721 */
2722static int
2723ciss_cam_action_io(struct cam_sim *sim, struct ccb_scsiio *csio)
2724{
2725    struct ciss_softc	*sc;
2726    int			bus, target;
2727    struct ciss_request	*cr;
2728    struct ciss_command	*cc;
2729    int			error;
2730
2731    sc = cam_sim_softc(sim);
2732    bus = cam_sim_bus(sim);
2733    target = csio->ccb_h.target_id;
2734
2735    debug(2, "XPT_SCSI_IO %d:%d:%d", bus, target, csio->ccb_h.target_lun);
2736
2737    /* firmware does not support commands > 10 bytes */
2738    if (csio->cdb_len > 12/*CISS_CDB_BUFFER_SIZE*/) {
2739	debug(3, "  command too large (%d > %d)", csio->cdb_len, CISS_CDB_BUFFER_SIZE);
2740	csio->ccb_h.status = CAM_REQ_CMP_ERR;
2741    }
2742
2743    /* check that the CDB pointer is not to a physical address */
2744    if ((csio->ccb_h.flags & CAM_CDB_POINTER) && (csio->ccb_h.flags & CAM_CDB_PHYS)) {
2745	debug(3, "  CDB pointer is to physical address");
2746	csio->ccb_h.status = CAM_REQ_CMP_ERR;
2747    }
2748
2749    /* if there is data transfer, it must be to/from a virtual address */
2750    if ((csio->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
2751	if (csio->ccb_h.flags & CAM_DATA_PHYS) {		/* we can't map it */
2752	    debug(3, "  data pointer is to physical address");
2753	    csio->ccb_h.status = CAM_REQ_CMP_ERR;
2754	}
2755	if (csio->ccb_h.flags & CAM_SCATTER_VALID) {	/* we want to do the s/g setup */
2756	    debug(3, "  data has premature s/g setup");
2757	    csio->ccb_h.status = CAM_REQ_CMP_ERR;
2758	}
2759    }
2760
2761    /* abandon aborted ccbs or those that have failed validation */
2762    if ((csio->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_INPROG) {
2763	debug(3, "abandoning CCB due to abort/validation failure");
2764	return(EINVAL);
2765    }
2766
2767    /* handle emulation of some SCSI commands ourself */
2768    if (ciss_cam_emulate(sc, csio))
2769	return(0);
2770
2771    /*
2772     * Get a request to manage this command.  If we can't, return the
2773     * ccb, freeze the queue and flag so that we unfreeze it when a
2774     * request completes.
2775     */
2776    if ((error = ciss_get_request(sc, &cr)) != 0) {
2777	xpt_freeze_simq(sim, 1);
2778	csio->ccb_h.status |= CAM_REQUEUE_REQ;
2779	return(error);
2780    }
2781
2782    /*
2783     * Build the command.
2784     */
2785    cc = CISS_FIND_COMMAND(cr);
2786    cr->cr_data = csio->data_ptr;
2787    cr->cr_length = csio->dxfer_len;
2788    cr->cr_complete = ciss_cam_complete;
2789    cr->cr_private = csio;
2790
2791    /*
2792     * Target the right logical volume.
2793     */
2794    if (CISS_IS_PHYSICAL(bus))
2795	cc->header.address =
2796	    sc->ciss_physical[CISS_CAM_TO_PBUS(bus)][target].cp_address;
2797    else
2798	cc->header.address =
2799	    sc->ciss_logical[bus][target].cl_address;
2800    cc->cdb.cdb_length = csio->cdb_len;
2801    cc->cdb.type = CISS_CDB_TYPE_COMMAND;
2802    cc->cdb.attribute = CISS_CDB_ATTRIBUTE_SIMPLE;	/* XXX ordered tags? */
2803    if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) {
2804	cr->cr_flags = CISS_REQ_DATAOUT;
2805	cc->cdb.direction = CISS_CDB_DIRECTION_WRITE;
2806    } else if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
2807	cr->cr_flags = CISS_REQ_DATAIN;
2808	cc->cdb.direction = CISS_CDB_DIRECTION_READ;
2809    } else {
2810	cr->cr_flags = 0;
2811	cc->cdb.direction = CISS_CDB_DIRECTION_NONE;
2812    }
2813    cc->cdb.timeout = (csio->ccb_h.timeout / 1000) + 1;
2814    if (csio->ccb_h.flags & CAM_CDB_POINTER) {
2815	bcopy(csio->cdb_io.cdb_ptr, &cc->cdb.cdb[0], csio->cdb_len);
2816    } else {
2817	bcopy(csio->cdb_io.cdb_bytes, &cc->cdb.cdb[0], csio->cdb_len);
2818    }
2819
2820    /*
2821     * Submit the request to the adapter.
2822     *
2823     * Note that this may fail if we're unable to map the request (and
2824     * if we ever learn a transport layer other than simple, may fail
2825     * if the adapter rejects the command).
2826     */
2827    if ((error = ciss_start(cr)) != 0) {
2828	xpt_freeze_simq(sim, 1);
2829	if (error == EINPROGRESS) {
2830	    csio->ccb_h.status |= CAM_RELEASE_SIMQ;
2831	    error = 0;
2832	} else {
2833	    csio->ccb_h.status |= CAM_REQUEUE_REQ;
2834	    ciss_release_request(cr);
2835	}
2836	return(error);
2837    }
2838
2839    return(0);
2840}
2841
2842/************************************************************************
2843 * Emulate SCSI commands the adapter doesn't handle as we might like.
2844 */
2845static int
2846ciss_cam_emulate(struct ciss_softc *sc, struct ccb_scsiio *csio)
2847{
2848    int		bus, target;
2849    u_int8_t	opcode;
2850
2851    target = csio->ccb_h.target_id;
2852    bus = cam_sim_bus(xpt_path_sim(csio->ccb_h.path));
2853    opcode = (csio->ccb_h.flags & CAM_CDB_POINTER) ?
2854	*(u_int8_t *)csio->cdb_io.cdb_ptr : csio->cdb_io.cdb_bytes[0];
2855
2856    if (CISS_IS_PHYSICAL(bus)) {
2857	if (sc->ciss_physical[CISS_CAM_TO_PBUS(bus)][target].cp_online != 1) {
2858	    csio->ccb_h.status = CAM_SEL_TIMEOUT;
2859	    xpt_done((union ccb *)csio);
2860	    return(1);
2861	} else
2862	    return(0);
2863    }
2864
2865    /*
2866     * Handle requests for volumes that don't exist or are not online.
2867     * A selection timeout is slightly better than an illegal request.
2868     * Other errors might be better.
2869     */
2870    if (sc->ciss_logical[bus][target].cl_status != CISS_LD_ONLINE) {
2871	csio->ccb_h.status = CAM_SEL_TIMEOUT;
2872	xpt_done((union ccb *)csio);
2873	return(1);
2874    }
2875
2876    /* if we have to fake Synchronise Cache */
2877    if (sc->ciss_flags & CISS_FLAG_FAKE_SYNCH) {
2878	/*
2879	 * If this is a Synchronise Cache command, typically issued when
2880	 * a device is closed, flush the adapter and complete now.
2881	 */
2882	if (((csio->ccb_h.flags & CAM_CDB_POINTER) ?
2883	     *(u_int8_t *)csio->cdb_io.cdb_ptr : csio->cdb_io.cdb_bytes[0]) == SYNCHRONIZE_CACHE) {
2884	    ciss_flush_adapter(sc);
2885	    csio->ccb_h.status = CAM_REQ_CMP;
2886	    xpt_done((union ccb *)csio);
2887	    return(1);
2888	}
2889    }
2890
2891    return(0);
2892}
2893
2894/************************************************************************
2895 * Check for possibly-completed commands.
2896 */
2897static void
2898ciss_cam_poll(struct cam_sim *sim)
2899{
2900    struct ciss_softc	*sc = cam_sim_softc(sim);
2901
2902    debug_called(2);
2903
2904    ciss_done(sc);
2905}
2906
2907/************************************************************************
2908 * Handle completion of a command - pass results back through the CCB
2909 */
2910static void
2911ciss_cam_complete(struct ciss_request *cr)
2912{
2913    struct ciss_softc		*sc;
2914    struct ciss_command		*cc;
2915    struct ciss_error_info	*ce;
2916    struct ccb_scsiio		*csio;
2917    int				scsi_status;
2918    int				command_status;
2919
2920    debug_called(2);
2921
2922    sc = cr->cr_sc;
2923    cc = CISS_FIND_COMMAND(cr);
2924    ce = (struct ciss_error_info *)&(cc->sg[0]);
2925    csio = (struct ccb_scsiio *)cr->cr_private;
2926
2927    /*
2928     * Extract status values from request.
2929     */
2930    ciss_report_request(cr, &command_status, &scsi_status);
2931    csio->scsi_status = scsi_status;
2932
2933    /*
2934     * Handle specific SCSI status values.
2935     */
2936    switch(scsi_status) {
2937	/* no status due to adapter error */
2938    case -1:
2939	debug(0, "adapter error");
2940	csio->ccb_h.status = CAM_REQ_CMP_ERR;
2941	break;
2942
2943	/* no status due to command completed OK */
2944    case SCSI_STATUS_OK:		/* CISS_SCSI_STATUS_GOOD */
2945	debug(2, "SCSI_STATUS_OK");
2946	csio->ccb_h.status = CAM_REQ_CMP;
2947	break;
2948
2949	/* check condition, sense data included */
2950    case SCSI_STATUS_CHECK_COND:	/* CISS_SCSI_STATUS_CHECK_CONDITION */
2951	debug(0, "SCSI_STATUS_CHECK_COND  sense size %d  resid %d\n",
2952	      ce->sense_length, ce->residual_count);
2953	bzero(&csio->sense_data, SSD_FULL_SIZE);
2954	bcopy(&ce->sense_info[0], &csio->sense_data, ce->sense_length);
2955	csio->sense_len = ce->sense_length;
2956	csio->resid = ce->residual_count;
2957	csio->ccb_h.status = CAM_SCSI_STATUS_ERROR | CAM_AUTOSNS_VALID;
2958#ifdef CISS_DEBUG
2959	{
2960	    struct scsi_sense_data	*sns = (struct scsi_sense_data *)&ce->sense_info[0];
2961	    debug(0, "sense key %x", sns->flags & SSD_KEY);
2962	}
2963#endif
2964	break;
2965
2966    case SCSI_STATUS_BUSY:		/* CISS_SCSI_STATUS_BUSY */
2967	debug(0, "SCSI_STATUS_BUSY");
2968	csio->ccb_h.status = CAM_SCSI_BUSY;
2969	break;
2970
2971    default:
2972	debug(0, "unknown status 0x%x", csio->scsi_status);
2973	csio->ccb_h.status = CAM_REQ_CMP_ERR;
2974	break;
2975    }
2976
2977    /* handle post-command fixup */
2978    ciss_cam_complete_fixup(sc, csio);
2979
2980    /* tell CAM we're ready for more commands */
2981    csio->ccb_h.status |= CAM_RELEASE_SIMQ;
2982
2983    xpt_done((union ccb *)csio);
2984    ciss_release_request(cr);
2985}
2986
2987/********************************************************************************
2988 * Fix up the result of some commands here.
2989 */
2990static void
2991ciss_cam_complete_fixup(struct ciss_softc *sc, struct ccb_scsiio *csio)
2992{
2993    struct scsi_inquiry_data	*inq;
2994    struct ciss_ldrive		*cl;
2995    int				bus, target;
2996
2997    if (((csio->ccb_h.flags & CAM_CDB_POINTER) ?
2998	 *(u_int8_t *)csio->cdb_io.cdb_ptr : csio->cdb_io.cdb_bytes[0]) == INQUIRY) {
2999
3000	inq = (struct scsi_inquiry_data *)csio->data_ptr;
3001	target = csio->ccb_h.target_id;
3002	bus = cam_sim_bus(xpt_path_sim(csio->ccb_h.path));
3003
3004	/*
3005	 * Don't let hard drives be seen by the DA driver.  They will still be
3006	 * attached by the PASS driver.
3007	 */
3008	if (CISS_IS_PHYSICAL(bus)) {
3009	    if (SID_TYPE(inq) == T_DIRECT)
3010		inq->device = (inq->device & 0xe0) | T_NODEVICE;
3011	    return;
3012	}
3013
3014	cl = &sc->ciss_logical[bus][target];
3015
3016	padstr(inq->vendor, "COMPAQ", 8);
3017	padstr(inq->product, ciss_name_ldrive_org(cl->cl_ldrive->fault_tolerance), 8);
3018	padstr(inq->revision, ciss_name_ldrive_status(cl->cl_lstatus->status), 16);
3019    }
3020}
3021
3022
3023/********************************************************************************
3024 * Find a peripheral attached at (target)
3025 */
3026static struct cam_periph *
3027ciss_find_periph(struct ciss_softc *sc, int bus, int target)
3028{
3029    struct cam_periph	*periph;
3030    struct cam_path	*path;
3031    int			status;
3032
3033    status = xpt_create_path(&path, NULL, cam_sim_path(sc->ciss_cam_sim[bus]),
3034			     target, 0);
3035    if (status == CAM_REQ_CMP) {
3036	periph = cam_periph_find(path, NULL);
3037	xpt_free_path(path);
3038    } else {
3039	periph = NULL;
3040    }
3041    return(periph);
3042}
3043
3044/********************************************************************************
3045 * Name the device at (target)
3046 *
3047 * XXX is this strictly correct?
3048 */
3049static int
3050ciss_name_device(struct ciss_softc *sc, int bus, int target)
3051{
3052    struct cam_periph	*periph;
3053
3054    if (CISS_IS_PHYSICAL(bus))
3055	return (0);
3056    if ((periph = ciss_find_periph(sc, bus, target)) != NULL) {
3057	sprintf(sc->ciss_logical[bus][target].cl_name, "%s%d",
3058		periph->periph_name, periph->unit_number);
3059	return(0);
3060    }
3061    sc->ciss_logical[bus][target].cl_name[0] = 0;
3062    return(ENOENT);
3063}
3064
3065/************************************************************************
3066 * Periodic status monitoring.
3067 */
3068static void
3069ciss_periodic(void *arg)
3070{
3071    struct ciss_softc	*sc;
3072    struct ciss_request	*cr = NULL;
3073    struct ciss_command	*cc = NULL;
3074    int			error = 0;
3075
3076    debug_called(1);
3077
3078    sc = (struct ciss_softc *)arg;
3079
3080    /*
3081     * Check the adapter heartbeat.
3082     */
3083    if (sc->ciss_cfg->heartbeat == sc->ciss_heartbeat) {
3084	sc->ciss_heart_attack++;
3085	debug(0, "adapter heart attack in progress 0x%x/%d",
3086	      sc->ciss_heartbeat, sc->ciss_heart_attack);
3087	if (sc->ciss_heart_attack == 3) {
3088	    ciss_printf(sc, "ADAPTER HEARTBEAT FAILED\n");
3089	    ciss_disable_adapter(sc);
3090	    return;
3091	}
3092    } else {
3093	sc->ciss_heartbeat = sc->ciss_cfg->heartbeat;
3094	sc->ciss_heart_attack = 0;
3095	debug(3, "new heartbeat 0x%x", sc->ciss_heartbeat);
3096    }
3097
3098    /*
3099     * Send the NOP message and wait for a response.
3100     */
3101    if ((error = ciss_get_request(sc, &cr)) == 0) {
3102	cc = CISS_FIND_COMMAND(cr);
3103	cc->cdb.cdb_length = 1;
3104	cc->cdb.type = CISS_CDB_TYPE_MESSAGE;
3105	cc->cdb.attribute = CISS_CDB_ATTRIBUTE_SIMPLE;
3106	cc->cdb.direction = CISS_CDB_DIRECTION_WRITE;
3107	cc->cdb.timeout = 0;
3108	cc->cdb.cdb[0] = CISS_OPCODE_MESSAGE_NOP;
3109
3110	if ((error = ciss_synch_request(cr, 10 * 1000)) != 0) {
3111	    ciss_printf(sc, "SENDING NOP MESSAGE FAILED\n");
3112	}
3113
3114	ciss_release_request(cr);
3115    }
3116
3117    /*
3118     * If the notify event request has died for some reason, or has
3119     * not started yet, restart it.
3120     */
3121    if (!(sc->ciss_flags & CISS_FLAG_NOTIFY_OK)) {
3122	debug(0, "(re)starting Event Notify chain");
3123	ciss_notify_event(sc);
3124    }
3125
3126    /*
3127     * Reschedule.
3128     */
3129    callout_reset(&sc->ciss_periodic, CISS_HEARTBEAT_RATE * hz, ciss_periodic, sc);
3130}
3131
3132/************************************************************************
3133 * Disable the adapter.
3134 *
3135 * The all requests in completed queue is failed with hardware error.
3136 * This will cause failover in a multipath configuration.
3137 */
3138static void
3139ciss_disable_adapter(struct ciss_softc *sc)
3140{
3141    struct ciss_request		*cr;
3142    struct ciss_command		*cc;
3143    struct ciss_error_info	*ce;
3144    int				s;
3145
3146    s = splcam();
3147
3148    CISS_TL_SIMPLE_DISABLE_INTERRUPTS(sc);
3149    pci_disable_busmaster(sc->ciss_dev);
3150    sc->ciss_flags &= ~CISS_FLAG_RUNNING;
3151
3152    for (;;) {
3153	if ((cr = ciss_dequeue_busy(sc)) == NULL)
3154	    break;
3155
3156	cc = CISS_FIND_COMMAND(cr);
3157	ce = (struct ciss_error_info *)&(cc->sg[0]);
3158	ce->command_status = CISS_CMD_STATUS_HARDWARE_ERROR;
3159	ciss_enqueue_complete(cr);
3160    }
3161
3162    for (;;) {
3163	if ((cr = ciss_dequeue_complete(sc)) == NULL)
3164	    break;
3165
3166	/*
3167	 * If the request has a callback, invoke it.
3168	 */
3169	if (cr->cr_complete != NULL) {
3170	    cr->cr_complete(cr);
3171	    continue;
3172	}
3173
3174	/*
3175	 * If someone is sleeping on this request, wake them up.
3176	 */
3177	if (cr->cr_flags & CISS_REQ_SLEEP) {
3178	    cr->cr_flags &= ~CISS_REQ_SLEEP;
3179	    wakeup(cr);
3180	    continue;
3181	}
3182    }
3183
3184    splx(s);
3185}
3186
3187/************************************************************************
3188 * Request a notification response from the adapter.
3189 *
3190 * If (cr) is NULL, this is the first request of the adapter, so
3191 * reset the adapter's message pointer and start with the oldest
3192 * message available.
3193 */
3194static void
3195ciss_notify_event(struct ciss_softc *sc)
3196{
3197    struct ciss_request		*cr;
3198    struct ciss_command		*cc;
3199    struct ciss_notify_cdb	*cnc;
3200    int				error;
3201
3202    debug_called(1);
3203
3204    cr = sc->ciss_periodic_notify;
3205
3206    /* get a request if we don't already have one */
3207    if (cr == NULL) {
3208	if ((error = ciss_get_request(sc, &cr)) != 0) {
3209	    debug(0, "can't get notify event request");
3210	    goto out;
3211	}
3212	sc->ciss_periodic_notify = cr;
3213	cr->cr_complete = ciss_notify_complete;
3214	debug(1, "acquired request %d", cr->cr_tag);
3215    }
3216
3217    /*
3218     * Get a databuffer if we don't already have one, note that the
3219     * adapter command wants a larger buffer than the actual
3220     * structure.
3221     */
3222    if (cr->cr_data == NULL) {
3223	if ((cr->cr_data = malloc(CISS_NOTIFY_DATA_SIZE, CISS_MALLOC_CLASS, M_NOWAIT)) == NULL) {
3224	    debug(0, "can't get notify event request buffer");
3225	    error = ENOMEM;
3226	    goto out;
3227	}
3228	cr->cr_length = CISS_NOTIFY_DATA_SIZE;
3229    }
3230
3231    /* re-setup the request's command (since we never release it) XXX overkill*/
3232    ciss_preen_command(cr);
3233
3234    /* (re)build the notify event command */
3235    cc = CISS_FIND_COMMAND(cr);
3236    cc->header.address.physical.mode = CISS_HDR_ADDRESS_MODE_PERIPHERAL;
3237    cc->header.address.physical.bus = 0;
3238    cc->header.address.physical.target = 0;
3239
3240    cc->cdb.cdb_length = sizeof(*cnc);
3241    cc->cdb.type = CISS_CDB_TYPE_COMMAND;
3242    cc->cdb.attribute = CISS_CDB_ATTRIBUTE_SIMPLE;
3243    cc->cdb.direction = CISS_CDB_DIRECTION_READ;
3244    cc->cdb.timeout = 0;	/* no timeout, we hope */
3245
3246    cnc = (struct ciss_notify_cdb *)&(cc->cdb.cdb[0]);
3247    bzero(cr->cr_data, CISS_NOTIFY_DATA_SIZE);
3248    cnc->opcode = CISS_OPCODE_READ;
3249    cnc->command = CISS_COMMAND_NOTIFY_ON_EVENT;
3250    cnc->timeout = 0;		/* no timeout, we hope */
3251    cnc->synchronous = 0;
3252    cnc->ordered = 0;
3253    cnc->seek_to_oldest = 0;
3254    if ((sc->ciss_flags & CISS_FLAG_RUNNING) == 0)
3255	cnc->new_only = 1;
3256    else
3257	cnc->new_only = 0;
3258    cnc->length = htonl(CISS_NOTIFY_DATA_SIZE);
3259
3260    /* submit the request */
3261    error = ciss_start(cr);
3262
3263 out:
3264    if (error) {
3265	if (cr != NULL) {
3266	    if (cr->cr_data != NULL)
3267		free(cr->cr_data, CISS_MALLOC_CLASS);
3268	    ciss_release_request(cr);
3269	}
3270	sc->ciss_periodic_notify = NULL;
3271	debug(0, "can't submit notify event request");
3272	sc->ciss_flags &= ~CISS_FLAG_NOTIFY_OK;
3273    } else {
3274	debug(1, "notify event submitted");
3275	sc->ciss_flags |= CISS_FLAG_NOTIFY_OK;
3276    }
3277}
3278
3279static void
3280ciss_notify_complete(struct ciss_request *cr)
3281{
3282    struct ciss_command	*cc;
3283    struct ciss_notify	*cn;
3284    struct ciss_softc	*sc;
3285    int			scsi_status;
3286    int			command_status;
3287    debug_called(1);
3288
3289    cc = CISS_FIND_COMMAND(cr);
3290    cn = (struct ciss_notify *)cr->cr_data;
3291    sc = cr->cr_sc;
3292
3293    /*
3294     * Report request results, decode status.
3295     */
3296    ciss_report_request(cr, &command_status, &scsi_status);
3297
3298    /*
3299     * Abort the chain on a fatal error.
3300     *
3301     * XXX which of these are actually errors?
3302     */
3303    if ((command_status != CISS_CMD_STATUS_SUCCESS) &&
3304	(command_status != CISS_CMD_STATUS_TARGET_STATUS) &&
3305	(command_status != CISS_CMD_STATUS_TIMEOUT)) {	/* XXX timeout? */
3306	ciss_printf(sc, "fatal error in Notify Event request (%s)\n",
3307		    ciss_name_command_status(command_status));
3308	ciss_release_request(cr);
3309	sc->ciss_flags &= ~CISS_FLAG_NOTIFY_OK;
3310	return;
3311    }
3312
3313    /*
3314     * If the adapter gave us a text message, print it.
3315     */
3316    if (cn->message[0] != 0)
3317	ciss_printf(sc, "*** %.80s\n", cn->message);
3318
3319    debug(0, "notify event class %d subclass %d detail %d",
3320		cn->class, cn->subclass, cn->detail);
3321
3322    /*
3323     * If the response indicates that the notifier has been aborted,
3324     * release the notifier command.
3325     */
3326    if ((cn->class == CISS_NOTIFY_NOTIFIER) &&
3327	(cn->subclass == CISS_NOTIFY_NOTIFIER_STATUS) &&
3328	(cn->detail == 1)) {
3329	debug(0, "notifier exiting");
3330	sc->ciss_flags &= ~CISS_FLAG_NOTIFY_OK;
3331	ciss_release_request(cr);
3332	sc->ciss_periodic_notify = NULL;
3333	wakeup(&sc->ciss_periodic_notify);
3334    } else {
3335	/* Handle notify events in a kernel thread */
3336	ciss_enqueue_notify(cr);
3337	sc->ciss_periodic_notify = NULL;
3338	wakeup(&sc->ciss_periodic_notify);
3339	wakeup(&sc->ciss_notify);
3340    }
3341    /*
3342     * Send a new notify event command, if we're not aborting.
3343     */
3344    if (!(sc->ciss_flags & CISS_FLAG_ABORTING)) {
3345	ciss_notify_event(sc);
3346    }
3347}
3348
3349/************************************************************************
3350 * Abort the Notify Event chain.
3351 *
3352 * Note that we can't just abort the command in progress; we have to
3353 * explicitly issue an Abort Notify Event command in order for the
3354 * adapter to clean up correctly.
3355 *
3356 * If we are called with CISS_FLAG_ABORTING set in the adapter softc,
3357 * the chain will not restart itself.
3358 */
3359static int
3360ciss_notify_abort(struct ciss_softc *sc)
3361{
3362    struct ciss_request		*cr;
3363    struct ciss_command		*cc;
3364    struct ciss_notify_cdb	*cnc;
3365    int				error, s, command_status, scsi_status;
3366
3367    debug_called(1);
3368
3369    cr = NULL;
3370    error = 0;
3371
3372    /* verify that there's an outstanding command */
3373    if (!(sc->ciss_flags & CISS_FLAG_NOTIFY_OK))
3374	goto out;
3375
3376    /* get a command to issue the abort with */
3377    if ((error = ciss_get_request(sc, &cr)))
3378	goto out;
3379
3380    /* get a buffer for the result */
3381    if ((cr->cr_data = malloc(CISS_NOTIFY_DATA_SIZE, CISS_MALLOC_CLASS, M_NOWAIT)) == NULL) {
3382	debug(0, "can't get notify event request buffer");
3383	error = ENOMEM;
3384	goto out;
3385    }
3386    cr->cr_length = CISS_NOTIFY_DATA_SIZE;
3387
3388    /* build the CDB */
3389    cc = CISS_FIND_COMMAND(cr);
3390    cc->header.address.physical.mode = CISS_HDR_ADDRESS_MODE_PERIPHERAL;
3391    cc->header.address.physical.bus = 0;
3392    cc->header.address.physical.target = 0;
3393    cc->cdb.cdb_length = sizeof(*cnc);
3394    cc->cdb.type = CISS_CDB_TYPE_COMMAND;
3395    cc->cdb.attribute = CISS_CDB_ATTRIBUTE_SIMPLE;
3396    cc->cdb.direction = CISS_CDB_DIRECTION_READ;
3397    cc->cdb.timeout = 0;	/* no timeout, we hope */
3398
3399    cnc = (struct ciss_notify_cdb *)&(cc->cdb.cdb[0]);
3400    bzero(cnc, sizeof(*cnc));
3401    cnc->opcode = CISS_OPCODE_WRITE;
3402    cnc->command = CISS_COMMAND_ABORT_NOTIFY;
3403    cnc->length = htonl(CISS_NOTIFY_DATA_SIZE);
3404
3405    ciss_print_request(cr);
3406
3407    /*
3408     * Submit the request and wait for it to complete.
3409     */
3410    if ((error = ciss_synch_request(cr, 60 * 1000)) != 0) {
3411	ciss_printf(sc, "Abort Notify Event command failed (%d)\n", error);
3412	goto out;
3413    }
3414
3415    /*
3416     * Check response.
3417     */
3418    ciss_report_request(cr, &command_status, &scsi_status);
3419    switch(command_status) {
3420    case CISS_CMD_STATUS_SUCCESS:
3421	break;
3422    case CISS_CMD_STATUS_INVALID_COMMAND:
3423	/*
3424	 * Some older adapters don't support the CISS version of this
3425	 * command.  Fall back to using the BMIC version.
3426	 */
3427	error = ciss_notify_abort_bmic(sc);
3428	if (error != 0)
3429	    goto out;
3430	break;
3431
3432    case CISS_CMD_STATUS_TARGET_STATUS:
3433	/*
3434	 * This can happen if the adapter thinks there wasn't an outstanding
3435	 * Notify Event command but we did.  We clean up here.
3436	 */
3437	if (scsi_status == CISS_SCSI_STATUS_CHECK_CONDITION) {
3438	    if (sc->ciss_periodic_notify != NULL)
3439		ciss_release_request(sc->ciss_periodic_notify);
3440	    error = 0;
3441	    goto out;
3442	}
3443	/* FALLTHROUGH */
3444
3445    default:
3446	ciss_printf(sc, "Abort Notify Event command failed (%s)\n",
3447		    ciss_name_command_status(command_status));
3448	error = EIO;
3449	goto out;
3450    }
3451
3452    /*
3453     * Sleep waiting for the notifier command to complete.  Note
3454     * that if it doesn't, we may end up in a bad situation, since
3455     * the adapter may deliver it later.  Also note that the adapter
3456     * requires the Notify Event command to be cancelled in order to
3457     * maintain internal bookkeeping.
3458     */
3459    s = splcam();
3460    while (sc->ciss_periodic_notify != NULL) {
3461	error = msleep(&sc->ciss_periodic_notify, &sc->ciss_mtx, PRIBIO, "cissNEA", hz * 5);
3462	if (error == EWOULDBLOCK) {
3463	    ciss_printf(sc, "Notify Event command failed to abort, adapter may wedge.\n");
3464	    break;
3465	}
3466    }
3467    splx(s);
3468
3469 out:
3470    /* release the cancel request */
3471    if (cr != NULL) {
3472	if (cr->cr_data != NULL)
3473	    free(cr->cr_data, CISS_MALLOC_CLASS);
3474	ciss_release_request(cr);
3475    }
3476    if (error == 0)
3477	sc->ciss_flags &= ~CISS_FLAG_NOTIFY_OK;
3478    return(error);
3479}
3480
3481/************************************************************************
3482 * Abort the Notify Event chain using a BMIC command.
3483 */
3484static int
3485ciss_notify_abort_bmic(struct ciss_softc *sc)
3486{
3487    struct ciss_request			*cr;
3488    int					error, command_status;
3489
3490    debug_called(1);
3491
3492    cr = NULL;
3493    error = 0;
3494
3495    /* verify that there's an outstanding command */
3496    if (!(sc->ciss_flags & CISS_FLAG_NOTIFY_OK))
3497	goto out;
3498
3499    /*
3500     * Build a BMIC command to cancel the Notify on Event command.
3501     *
3502     * Note that we are sending a CISS opcode here.  Odd.
3503     */
3504    if ((error = ciss_get_bmic_request(sc, &cr, CISS_COMMAND_ABORT_NOTIFY,
3505				       NULL, 0)) != 0)
3506	goto out;
3507
3508    /*
3509     * Submit the request and wait for it to complete.
3510     */
3511    if ((error = ciss_synch_request(cr, 60 * 1000)) != 0) {
3512	ciss_printf(sc, "error sending BMIC Cancel Notify on Event command (%d)\n", error);
3513	goto out;
3514    }
3515
3516    /*
3517     * Check response.
3518     */
3519    ciss_report_request(cr, &command_status, NULL);
3520    switch(command_status) {
3521    case CISS_CMD_STATUS_SUCCESS:
3522	break;
3523    default:
3524	ciss_printf(sc, "error cancelling Notify on Event (%s)\n",
3525		    ciss_name_command_status(command_status));
3526	error = EIO;
3527	goto out;
3528    }
3529
3530out:
3531    if (cr != NULL)
3532	ciss_release_request(cr);
3533    return(error);
3534}
3535
3536/************************************************************************
3537 * Handle rescanning all the logical volumes when a notify event
3538 * causes the drives to come online or offline.
3539 */
3540static void
3541ciss_notify_rescan_logical(struct ciss_softc *sc)
3542{
3543    struct ciss_lun_report      *cll;
3544    struct ciss_ldrive		*ld;
3545    int                         i, j, ndrives;
3546
3547    /*
3548     * We must rescan all logical volumes to get the right logical
3549     * drive address.
3550     */
3551    cll = ciss_report_luns(sc, CISS_OPCODE_REPORT_LOGICAL_LUNS,
3552                           CISS_MAX_LOGICAL);
3553    if (cll == NULL)
3554        return;
3555
3556    ndrives = (ntohl(cll->list_size) / sizeof(union ciss_device_address));
3557
3558    /*
3559     * Delete any of the drives which were destroyed by the
3560     * firmware.
3561     */
3562    for (i = 0; i < sc->ciss_max_logical_bus; i++) {
3563	for (j = 0; j < CISS_MAX_LOGICAL; j++) {
3564	    ld = &sc->ciss_logical[i][j];
3565
3566	    if (ld->cl_update == 0)
3567		continue;
3568
3569	    if (ld->cl_status != CISS_LD_ONLINE) {
3570		ciss_cam_rescan_target(sc, i, j);
3571		ld->cl_update = 0;
3572		if (ld->cl_ldrive)
3573		    free(ld->cl_ldrive, CISS_MALLOC_CLASS);
3574		if (ld->cl_lstatus)
3575		    free(ld->cl_lstatus, CISS_MALLOC_CLASS);
3576
3577		ld->cl_ldrive = NULL;
3578		ld->cl_lstatus = NULL;
3579	    }
3580	}
3581    }
3582
3583    /*
3584     * Scan for new drives.
3585     */
3586    for (i = 0; i < ndrives; i++) {
3587	int	bus, target;
3588
3589	bus 	= CISS_LUN_TO_BUS(cll->lun[i].logical.lun);
3590	target	= CISS_LUN_TO_TARGET(cll->lun[i].logical.lun);
3591	ld	= &sc->ciss_logical[bus][target];
3592
3593	if (ld->cl_update == 0)
3594		continue;
3595
3596	ld->cl_update		= 0;
3597	ld->cl_address		= cll->lun[i];
3598	ld->cl_controller	= &sc->ciss_controllers[bus];
3599	if (ciss_identify_logical(sc, ld) == 0) {
3600	    ciss_cam_rescan_target(sc, bus, target);
3601	}
3602    }
3603    free(cll, CISS_MALLOC_CLASS);
3604}
3605
3606/************************************************************************
3607 * Handle a notify event relating to the status of a logical drive.
3608 *
3609 * XXX need to be able to defer some of these to properly handle
3610 *     calling the "ID Physical drive" command, unless the 'extended'
3611 *     drive IDs are always in BIG_MAP format.
3612 */
3613static void
3614ciss_notify_logical(struct ciss_softc *sc, struct ciss_notify *cn)
3615{
3616    struct ciss_ldrive	*ld;
3617    int			ostatus, bus, target;
3618
3619    debug_called(2);
3620
3621    bus		= cn->device.physical.bus;
3622    target	= cn->data.logical_status.logical_drive;
3623    ld		= &sc->ciss_logical[bus][target];
3624
3625    switch (cn->subclass) {
3626    case CISS_NOTIFY_LOGICAL_STATUS:
3627	switch (cn->detail) {
3628	case 0:
3629	    ciss_name_device(sc, bus, target);
3630	    ciss_printf(sc, "logical drive %d (%s) changed status %s->%s, spare status 0x%b\n",
3631			cn->data.logical_status.logical_drive, ld->cl_name,
3632			ciss_name_ldrive_status(cn->data.logical_status.previous_state),
3633			ciss_name_ldrive_status(cn->data.logical_status.new_state),
3634			cn->data.logical_status.spare_state,
3635			"\20\1configured\2rebuilding\3failed\4in use\5available\n");
3636
3637	    /*
3638	     * Update our idea of the drive's status.
3639	     */
3640	    ostatus = ciss_decode_ldrive_status(cn->data.logical_status.previous_state);
3641	    ld->cl_status = ciss_decode_ldrive_status(cn->data.logical_status.new_state);
3642	    if (ld->cl_lstatus != NULL)
3643		ld->cl_lstatus->status = cn->data.logical_status.new_state;
3644
3645	    /*
3646	     * Have CAM rescan the drive if its status has changed.
3647	     */
3648	    if (ostatus != ld->cl_status) {
3649		ld->cl_update = 1;
3650		ciss_notify_rescan_logical(sc);
3651	    }
3652
3653	    break;
3654
3655	case 1:	/* logical drive has recognised new media, needs Accept Media Exchange */
3656	    ciss_name_device(sc, bus, target);
3657	    ciss_printf(sc, "logical drive %d (%s) media exchanged, ready to go online\n",
3658			cn->data.logical_status.logical_drive, ld->cl_name);
3659	    ciss_accept_media(sc, ld);
3660
3661	    ld->cl_update = 1;
3662	    ld->cl_status = ciss_decode_ldrive_status(cn->data.logical_status.new_state);
3663	    ciss_notify_rescan_logical(sc);
3664	    break;
3665
3666	case 2:
3667	case 3:
3668	    ciss_printf(sc, "rebuild of logical drive %d (%s) failed due to %s error\n",
3669			cn->data.rebuild_aborted.logical_drive,
3670			ld->cl_name,
3671			(cn->detail == 2) ? "read" : "write");
3672	    break;
3673	}
3674	break;
3675
3676    case CISS_NOTIFY_LOGICAL_ERROR:
3677	if (cn->detail == 0) {
3678	    ciss_printf(sc, "FATAL I/O ERROR on logical drive %d (%s), SCSI port %d ID %d\n",
3679			cn->data.io_error.logical_drive,
3680			ld->cl_name,
3681			cn->data.io_error.failure_bus,
3682			cn->data.io_error.failure_drive);
3683	    /* XXX should we take the drive down at this point, or will we be told? */
3684	}
3685	break;
3686
3687    case CISS_NOTIFY_LOGICAL_SURFACE:
3688	if (cn->detail == 0)
3689	    ciss_printf(sc, "logical drive %d (%s) completed consistency initialisation\n",
3690			cn->data.consistency_completed.logical_drive,
3691			ld->cl_name);
3692	break;
3693    }
3694}
3695
3696/************************************************************************
3697 * Handle a notify event relating to the status of a physical drive.
3698 */
3699static void
3700ciss_notify_physical(struct ciss_softc *sc, struct ciss_notify *cn)
3701{
3702}
3703
3704/************************************************************************
3705 * Handle a notify event relating to the status of a physical drive.
3706 */
3707static void
3708ciss_notify_hotplug(struct ciss_softc *sc, struct ciss_notify *cn)
3709{
3710    struct ciss_lun_report *cll = NULL;
3711    int bus, target;
3712    int s;
3713
3714    switch (cn->subclass) {
3715    case CISS_NOTIFY_HOTPLUG_PHYSICAL:
3716    case CISS_NOTIFY_HOTPLUG_NONDISK:
3717	bus = CISS_BIG_MAP_BUS(sc, cn->data.drive.big_physical_drive_number);
3718	target =
3719	    CISS_BIG_MAP_TARGET(sc, cn->data.drive.big_physical_drive_number);
3720
3721	s = splcam();
3722	if (cn->detail == 0) {
3723	    /*
3724	     * Mark the device offline so that it'll start producing selection
3725	     * timeouts to the upper layer.
3726	     */
3727	    if ((bus >= 0) && (target >= 0))
3728		sc->ciss_physical[bus][target].cp_online = 0;
3729	} else {
3730	    /*
3731	     * Rescan the physical lun list for new items
3732	     */
3733	    cll = ciss_report_luns(sc, CISS_OPCODE_REPORT_PHYSICAL_LUNS,
3734				   CISS_MAX_PHYSICAL);
3735	    if (cll == NULL) {
3736		ciss_printf(sc, "Warning, cannot get physical lun list\n");
3737		break;
3738	    }
3739	    ciss_filter_physical(sc, cll);
3740	}
3741	splx(s);
3742	break;
3743
3744    default:
3745	ciss_printf(sc, "Unknown hotplug event %d\n", cn->subclass);
3746	return;
3747    }
3748
3749    if (cll != NULL)
3750	free(cll, CISS_MALLOC_CLASS);
3751}
3752
3753/************************************************************************
3754 * Handle deferred processing of notify events.  Notify events may need
3755 * sleep which is unsafe during an interrupt.
3756 */
3757static void
3758ciss_notify_thread(void *arg)
3759{
3760    struct ciss_softc		*sc;
3761    struct ciss_request		*cr;
3762    struct ciss_notify		*cn;
3763    int				s;
3764
3765    sc = (struct ciss_softc *)arg;
3766#if __FreeBSD_version >= 500000
3767    mtx_lock(&sc->ciss_mtx);
3768#endif
3769
3770    s = splcam();
3771    for (;;) {
3772	if (TAILQ_EMPTY(&sc->ciss_notify) != 0 &&
3773	    (sc->ciss_flags & CISS_FLAG_THREAD_SHUT) == 0) {
3774	    msleep(&sc->ciss_notify, &sc->ciss_mtx, PUSER, "idle", 0);
3775	}
3776
3777	if (sc->ciss_flags & CISS_FLAG_THREAD_SHUT)
3778	    break;
3779
3780	cr = ciss_dequeue_notify(sc);
3781	splx(s);
3782
3783	if (cr == NULL)
3784		panic("cr null");
3785	cn = (struct ciss_notify *)cr->cr_data;
3786
3787	switch (cn->class) {
3788	case CISS_NOTIFY_HOTPLUG:
3789	    ciss_notify_hotplug(sc, cn);
3790	    break;
3791	case CISS_NOTIFY_LOGICAL:
3792	    ciss_notify_logical(sc, cn);
3793	    break;
3794	case CISS_NOTIFY_PHYSICAL:
3795	    ciss_notify_physical(sc, cn);
3796	    break;
3797	}
3798
3799	ciss_release_request(cr);
3800
3801	s = splcam();
3802    }
3803    sc->ciss_notify_thread = NULL;
3804    wakeup(&sc->ciss_notify_thread);
3805    splx(s);
3806
3807#if __FreeBSD_version >= 500000
3808    mtx_unlock(&sc->ciss_mtx);
3809#endif
3810    kthread_exit(0);
3811}
3812
3813/************************************************************************
3814 * Start the notification kernel thread.
3815 */
3816static void
3817ciss_spawn_notify_thread(struct ciss_softc *sc)
3818{
3819
3820#if __FreeBSD_version > 500005
3821    if (kthread_create((void(*)(void *))ciss_notify_thread, sc,
3822		       &sc->ciss_notify_thread, 0, 0, "ciss_notify%d",
3823		       device_get_unit(sc->ciss_dev)))
3824#else
3825    if (kthread_create((void(*)(void *))ciss_notify_thread, sc,
3826		       &sc->ciss_notify_thread, "ciss_notify%d",
3827		       device_get_unit(sc->ciss_dev)))
3828#endif
3829	panic("Could not create notify thread\n");
3830}
3831
3832/************************************************************************
3833 * Kill the notification kernel thread.
3834 */
3835static void
3836ciss_kill_notify_thread(struct ciss_softc *sc)
3837{
3838
3839    if (sc->ciss_notify_thread == NULL)
3840	return;
3841
3842    sc->ciss_flags |= CISS_FLAG_THREAD_SHUT;
3843    wakeup(&sc->ciss_notify);
3844    msleep(&sc->ciss_notify_thread, &sc->ciss_mtx, PUSER, "thtrm", 0);
3845}
3846
3847/************************************************************************
3848 * Print a request.
3849 */
3850static void
3851ciss_print_request(struct ciss_request *cr)
3852{
3853    struct ciss_softc	*sc;
3854    struct ciss_command	*cc;
3855    int			i;
3856
3857    sc = cr->cr_sc;
3858    cc = CISS_FIND_COMMAND(cr);
3859
3860    ciss_printf(sc, "REQUEST @ %p\n", cr);
3861    ciss_printf(sc, "  data %p/%d  tag %d  flags %b\n",
3862	      cr->cr_data, cr->cr_length, cr->cr_tag, cr->cr_flags,
3863	      "\20\1mapped\2sleep\3poll\4dataout\5datain\n");
3864    ciss_printf(sc, "  sg list/total %d/%d  host tag 0x%x\n",
3865		cc->header.sg_in_list, cc->header.sg_total, cc->header.host_tag);
3866    switch(cc->header.address.mode.mode) {
3867    case CISS_HDR_ADDRESS_MODE_PERIPHERAL:
3868    case CISS_HDR_ADDRESS_MODE_MASK_PERIPHERAL:
3869	ciss_printf(sc, "  physical bus %d target %d\n",
3870		    cc->header.address.physical.bus, cc->header.address.physical.target);
3871	break;
3872    case CISS_HDR_ADDRESS_MODE_LOGICAL:
3873	ciss_printf(sc, "  logical unit %d\n", cc->header.address.logical.lun);
3874	break;
3875    }
3876    ciss_printf(sc, "  %s cdb length %d type %s attribute %s\n",
3877		(cc->cdb.direction == CISS_CDB_DIRECTION_NONE) ? "no-I/O" :
3878		(cc->cdb.direction == CISS_CDB_DIRECTION_READ) ? "READ" :
3879		(cc->cdb.direction == CISS_CDB_DIRECTION_WRITE) ? "WRITE" : "??",
3880		cc->cdb.cdb_length,
3881		(cc->cdb.type == CISS_CDB_TYPE_COMMAND) ? "command" :
3882		(cc->cdb.type == CISS_CDB_TYPE_MESSAGE) ? "message" : "??",
3883		(cc->cdb.attribute == CISS_CDB_ATTRIBUTE_UNTAGGED) ? "untagged" :
3884		(cc->cdb.attribute == CISS_CDB_ATTRIBUTE_SIMPLE) ? "simple" :
3885		(cc->cdb.attribute == CISS_CDB_ATTRIBUTE_HEAD_OF_QUEUE) ? "head-of-queue" :
3886		(cc->cdb.attribute == CISS_CDB_ATTRIBUTE_ORDERED) ? "ordered" :
3887		(cc->cdb.attribute == CISS_CDB_ATTRIBUTE_AUTO_CONTINGENT) ? "auto-contingent" : "??");
3888    ciss_printf(sc, "  %*D\n", cc->cdb.cdb_length, &cc->cdb.cdb[0], " ");
3889
3890    if (cc->header.host_tag & CISS_HDR_HOST_TAG_ERROR) {
3891	/* XXX print error info */
3892    } else {
3893	/* since we don't use chained s/g, don't support it here */
3894	for (i = 0; i < cc->header.sg_in_list; i++) {
3895	    if ((i % 4) == 0)
3896		ciss_printf(sc, "   ");
3897	    printf("0x%08x/%d ", (u_int32_t)cc->sg[i].address, cc->sg[i].length);
3898	    if ((((i + 1) % 4) == 0) || (i == (cc->header.sg_in_list - 1)))
3899		printf("\n");
3900	}
3901    }
3902}
3903
3904/************************************************************************
3905 * Print information about the status of a logical drive.
3906 */
3907static void
3908ciss_print_ldrive(struct ciss_softc *sc, struct ciss_ldrive *ld)
3909{
3910    int		bus, target, i;
3911
3912    if (ld->cl_lstatus == NULL) {
3913	printf("does not exist\n");
3914	return;
3915    }
3916
3917    /* print drive status */
3918    switch(ld->cl_lstatus->status) {
3919    case CISS_LSTATUS_OK:
3920	printf("online\n");
3921	break;
3922    case CISS_LSTATUS_INTERIM_RECOVERY:
3923	printf("in interim recovery mode\n");
3924	break;
3925    case CISS_LSTATUS_READY_RECOVERY:
3926	printf("ready to begin recovery\n");
3927	break;
3928    case CISS_LSTATUS_RECOVERING:
3929	bus = CISS_BIG_MAP_BUS(sc, ld->cl_lstatus->drive_rebuilding);
3930	target = CISS_BIG_MAP_BUS(sc, ld->cl_lstatus->drive_rebuilding);
3931	printf("being recovered, working on physical drive %d.%d, %u blocks remaining\n",
3932	       bus, target, ld->cl_lstatus->blocks_to_recover);
3933	break;
3934    case CISS_LSTATUS_EXPANDING:
3935	printf("being expanded, %u blocks remaining\n",
3936	       ld->cl_lstatus->blocks_to_recover);
3937	break;
3938    case CISS_LSTATUS_QUEUED_FOR_EXPANSION:
3939	printf("queued for expansion\n");
3940	break;
3941    case CISS_LSTATUS_FAILED:
3942	printf("queued for expansion\n");
3943	break;
3944    case CISS_LSTATUS_WRONG_PDRIVE:
3945	printf("wrong physical drive inserted\n");
3946	break;
3947    case CISS_LSTATUS_MISSING_PDRIVE:
3948	printf("missing a needed physical drive\n");
3949	break;
3950    case CISS_LSTATUS_BECOMING_READY:
3951	printf("becoming ready\n");
3952	break;
3953    }
3954
3955    /* print failed physical drives */
3956    for (i = 0; i < CISS_BIG_MAP_ENTRIES / 8; i++) {
3957	bus = CISS_BIG_MAP_BUS(sc, ld->cl_lstatus->drive_failure_map[i]);
3958	target = CISS_BIG_MAP_TARGET(sc, ld->cl_lstatus->drive_failure_map[i]);
3959	if (bus == -1)
3960	    continue;
3961	ciss_printf(sc, "physical drive %d:%d (%x) failed\n", bus, target,
3962		    ld->cl_lstatus->drive_failure_map[i]);
3963    }
3964}
3965
3966#ifdef CISS_DEBUG
3967/************************************************************************
3968 * Print information about the controller/driver.
3969 */
3970static void
3971ciss_print_adapter(struct ciss_softc *sc)
3972{
3973    int		i, j;
3974
3975    ciss_printf(sc, "ADAPTER:\n");
3976    for (i = 0; i < CISSQ_COUNT; i++) {
3977	ciss_printf(sc, "%s     %d/%d\n",
3978	    i == 0 ? "free" :
3979	    i == 1 ? "busy" : "complete",
3980	    sc->ciss_qstat[i].q_length,
3981	    sc->ciss_qstat[i].q_max);
3982    }
3983    ciss_printf(sc, "max_requests %d\n", sc->ciss_max_requests);
3984    ciss_printf(sc, "flags %b\n", sc->ciss_flags,
3985	"\20\1notify_ok\2control_open\3aborting\4running\21fake_synch\22bmic_abort\n");
3986
3987    for (i = 0; i < sc->ciss_max_logical_bus; i++) {
3988	for (j = 0; j < CISS_MAX_LOGICAL; j++) {
3989	    ciss_printf(sc, "LOGICAL DRIVE %d:  ", i);
3990	    ciss_print_ldrive(sc, &sc->ciss_logical[i][j]);
3991	}
3992    }
3993
3994    /* XXX Should physical drives be printed out here? */
3995
3996    for (i = 1; i < sc->ciss_max_requests; i++)
3997	ciss_print_request(sc->ciss_request + i);
3998}
3999
4000/* DDB hook */
4001static void
4002ciss_print0(void)
4003{
4004    struct ciss_softc	*sc;
4005
4006    sc = devclass_get_softc(devclass_find("ciss"), 0);
4007    if (sc == NULL) {
4008	printf("no ciss controllers\n");
4009    } else {
4010	ciss_print_adapter(sc);
4011    }
4012}
4013#endif
4014
4015/************************************************************************
4016 * Return a name for a logical drive status value.
4017 */
4018static const char *
4019ciss_name_ldrive_status(int status)
4020{
4021    switch (status) {
4022    case CISS_LSTATUS_OK:
4023	return("OK");
4024    case CISS_LSTATUS_FAILED:
4025	return("failed");
4026    case CISS_LSTATUS_NOT_CONFIGURED:
4027	return("not configured");
4028    case CISS_LSTATUS_INTERIM_RECOVERY:
4029	return("interim recovery");
4030    case CISS_LSTATUS_READY_RECOVERY:
4031	return("ready for recovery");
4032    case CISS_LSTATUS_RECOVERING:
4033	return("recovering");
4034    case CISS_LSTATUS_WRONG_PDRIVE:
4035	return("wrong physical drive inserted");
4036    case CISS_LSTATUS_MISSING_PDRIVE:
4037	return("missing physical drive");
4038    case CISS_LSTATUS_EXPANDING:
4039	return("expanding");
4040    case CISS_LSTATUS_BECOMING_READY:
4041	return("becoming ready");
4042    case CISS_LSTATUS_QUEUED_FOR_EXPANSION:
4043	return("queued for expansion");
4044    }
4045    return("unknown status");
4046}
4047
4048/************************************************************************
4049 * Return an online/offline/nonexistent value for a logical drive
4050 * status value.
4051 */
4052static int
4053ciss_decode_ldrive_status(int status)
4054{
4055    switch(status) {
4056    case CISS_LSTATUS_NOT_CONFIGURED:
4057	return(CISS_LD_NONEXISTENT);
4058
4059    case CISS_LSTATUS_OK:
4060    case CISS_LSTATUS_INTERIM_RECOVERY:
4061    case CISS_LSTATUS_READY_RECOVERY:
4062    case CISS_LSTATUS_RECOVERING:
4063    case CISS_LSTATUS_EXPANDING:
4064    case CISS_LSTATUS_QUEUED_FOR_EXPANSION:
4065	return(CISS_LD_ONLINE);
4066
4067    case CISS_LSTATUS_FAILED:
4068    case CISS_LSTATUS_WRONG_PDRIVE:
4069    case CISS_LSTATUS_MISSING_PDRIVE:
4070    case CISS_LSTATUS_BECOMING_READY:
4071    default:
4072	return(CISS_LD_OFFLINE);
4073    }
4074}
4075
4076
4077/************************************************************************
4078 * Return a name for a logical drive's organisation.
4079 */
4080static const char *
4081ciss_name_ldrive_org(int org)
4082{
4083    switch(org) {
4084    case CISS_LDRIVE_RAID0:
4085	return("RAID 0");
4086    case CISS_LDRIVE_RAID1:
4087	return("RAID 1");
4088    case CISS_LDRIVE_RAID4:
4089	return("RAID 4");
4090    case CISS_LDRIVE_RAID5:
4091	return("RAID 5");
4092    case CISS_LDRIVE_RAID51:
4093	return("RAID 5+1");
4094    case CISS_LDRIVE_RAIDADG:
4095	return("RAID ADG");
4096    }
4097    return("unkown");
4098}
4099
4100/************************************************************************
4101 * Return a name for a command status value.
4102 */
4103static const char *
4104ciss_name_command_status(int status)
4105{
4106    switch(status) {
4107    case CISS_CMD_STATUS_SUCCESS:
4108	return("success");
4109    case CISS_CMD_STATUS_TARGET_STATUS:
4110	return("target status");
4111    case CISS_CMD_STATUS_DATA_UNDERRUN:
4112	return("data underrun");
4113    case CISS_CMD_STATUS_DATA_OVERRUN:
4114	return("data overrun");
4115    case CISS_CMD_STATUS_INVALID_COMMAND:
4116	return("invalid command");
4117    case CISS_CMD_STATUS_PROTOCOL_ERROR:
4118	return("protocol error");
4119    case CISS_CMD_STATUS_HARDWARE_ERROR:
4120	return("hardware error");
4121    case CISS_CMD_STATUS_CONNECTION_LOST:
4122	return("connection lost");
4123    case CISS_CMD_STATUS_ABORTED:
4124	return("aborted");
4125    case CISS_CMD_STATUS_ABORT_FAILED:
4126	return("abort failed");
4127    case CISS_CMD_STATUS_UNSOLICITED_ABORT:
4128	return("unsolicited abort");
4129    case CISS_CMD_STATUS_TIMEOUT:
4130	return("timeout");
4131    case CISS_CMD_STATUS_UNABORTABLE:
4132	return("unabortable");
4133    }
4134    return("unknown status");
4135}
4136
4137/************************************************************************
4138 * Handle an open on the control device.
4139 */
4140static int
4141ciss_open(struct cdev *dev, int flags, int fmt, d_thread_t *p)
4142{
4143    struct ciss_softc	*sc;
4144
4145    debug_called(1);
4146
4147    sc = (struct ciss_softc *)dev->si_drv1;
4148
4149    /* we might want to veto if someone already has us open */
4150
4151    mtx_lock(&sc->ciss_mtx);
4152    sc->ciss_flags |= CISS_FLAG_CONTROL_OPEN;
4153    mtx_unlock(&sc->ciss_mtx);
4154    return(0);
4155}
4156
4157/************************************************************************
4158 * Handle the last close on the control device.
4159 */
4160static int
4161ciss_close(struct cdev *dev, int flags, int fmt, d_thread_t *p)
4162{
4163    struct ciss_softc	*sc;
4164
4165    debug_called(1);
4166
4167    sc = (struct ciss_softc *)dev->si_drv1;
4168
4169    mtx_lock(&sc->ciss_mtx);
4170    sc->ciss_flags &= ~CISS_FLAG_CONTROL_OPEN;
4171    mtx_unlock(&sc->ciss_mtx);
4172    return (0);
4173}
4174
4175/********************************************************************************
4176 * Handle adapter-specific control operations.
4177 *
4178 * Note that the API here is compatible with the Linux driver, in order to
4179 * simplify the porting of Compaq's userland tools.
4180 */
4181static int
4182ciss_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int32_t flag, d_thread_t *p)
4183{
4184    struct ciss_softc		*sc;
4185    IOCTL_Command_struct	*ioc	= (IOCTL_Command_struct *)addr;
4186#ifdef __amd64__
4187    IOCTL_Command_struct32	*ioc32	= (IOCTL_Command_struct32 *)addr;
4188    IOCTL_Command_struct	ioc_swab;
4189#endif
4190    int				error;
4191
4192    debug_called(1);
4193
4194    sc = (struct ciss_softc *)dev->si_drv1;
4195    error = 0;
4196    mtx_lock(&sc->ciss_mtx);
4197
4198    switch(cmd) {
4199    case CCISS_GETPCIINFO:
4200    {
4201	cciss_pci_info_struct	*pis = (cciss_pci_info_struct *)addr;
4202
4203	pis->bus = pci_get_bus(sc->ciss_dev);
4204	pis->dev_fn = pci_get_slot(sc->ciss_dev);
4205	pis->board_id = pci_get_devid(sc->ciss_dev);
4206
4207	break;
4208    }
4209
4210    case CCISS_GETINTINFO:
4211    {
4212	cciss_coalint_struct	*cis = (cciss_coalint_struct *)addr;
4213
4214	cis->delay = sc->ciss_cfg->interrupt_coalesce_delay;
4215	cis->count = sc->ciss_cfg->interrupt_coalesce_count;
4216
4217	break;
4218    }
4219
4220    case CCISS_SETINTINFO:
4221    {
4222	cciss_coalint_struct	*cis = (cciss_coalint_struct *)addr;
4223
4224	if ((cis->delay == 0) && (cis->count == 0)) {
4225	    error = EINVAL;
4226	    break;
4227	}
4228
4229	/*
4230	 * XXX apparently this is only safe if the controller is idle,
4231	 *     we should suspend it before doing this.
4232	 */
4233	sc->ciss_cfg->interrupt_coalesce_delay = cis->delay;
4234	sc->ciss_cfg->interrupt_coalesce_count = cis->count;
4235
4236	if (ciss_update_config(sc))
4237	    error = EIO;
4238
4239	/* XXX resume the controller here */
4240	break;
4241    }
4242
4243    case CCISS_GETNODENAME:
4244	bcopy(sc->ciss_cfg->server_name, (NodeName_type *)addr,
4245	      sizeof(NodeName_type));
4246	break;
4247
4248    case CCISS_SETNODENAME:
4249	bcopy((NodeName_type *)addr, sc->ciss_cfg->server_name,
4250	      sizeof(NodeName_type));
4251	if (ciss_update_config(sc))
4252	    error = EIO;
4253	break;
4254
4255    case CCISS_GETHEARTBEAT:
4256	*(Heartbeat_type *)addr = sc->ciss_cfg->heartbeat;
4257	break;
4258
4259    case CCISS_GETBUSTYPES:
4260	*(BusTypes_type *)addr = sc->ciss_cfg->bus_types;
4261	break;
4262
4263    case CCISS_GETFIRMVER:
4264	bcopy(sc->ciss_id->running_firmware_revision, (FirmwareVer_type *)addr,
4265	      sizeof(FirmwareVer_type));
4266	break;
4267
4268    case CCISS_GETDRIVERVER:
4269	*(DriverVer_type *)addr = CISS_DRIVER_VERSION;
4270	break;
4271
4272    case CCISS_REVALIDVOLS:
4273	/*
4274	 * This is a bit ugly; to do it "right" we really need
4275	 * to find any disks that have changed, kick CAM off them,
4276	 * then rescan only these disks.  It'd be nice if they
4277	 * a) told us which disk(s) they were going to play with,
4278	 * and b) which ones had arrived. 8(
4279	 */
4280	break;
4281
4282#ifdef __amd64__
4283    case CCISS_PASSTHRU32:
4284	ioc_swab.LUN_info	= ioc32->LUN_info;
4285	ioc_swab.Request	= ioc32->Request;
4286	ioc_swab.error_info	= ioc32->error_info;
4287	ioc_swab.buf_size	= ioc32->buf_size;
4288	ioc_swab.buf		= (u_int8_t *)(uintptr_t)ioc32->buf;
4289	ioc			= &ioc_swab;
4290	/* FALLTHROUGH */
4291#endif
4292
4293    case CCISS_PASSTHRU:
4294	error = ciss_user_command(sc, ioc);
4295	break;
4296
4297    default:
4298	debug(0, "unknown ioctl 0x%lx", cmd);
4299
4300	debug(1, "CCISS_GETPCIINFO:   0x%lx", CCISS_GETPCIINFO);
4301	debug(1, "CCISS_GETINTINFO:   0x%lx", CCISS_GETINTINFO);
4302	debug(1, "CCISS_SETINTINFO:   0x%lx", CCISS_SETINTINFO);
4303	debug(1, "CCISS_GETNODENAME:  0x%lx", CCISS_GETNODENAME);
4304	debug(1, "CCISS_SETNODENAME:  0x%lx", CCISS_SETNODENAME);
4305	debug(1, "CCISS_GETHEARTBEAT: 0x%lx", CCISS_GETHEARTBEAT);
4306	debug(1, "CCISS_GETBUSTYPES:  0x%lx", CCISS_GETBUSTYPES);
4307	debug(1, "CCISS_GETFIRMVER:   0x%lx", CCISS_GETFIRMVER);
4308	debug(1, "CCISS_GETDRIVERVER: 0x%lx", CCISS_GETDRIVERVER);
4309	debug(1, "CCISS_REVALIDVOLS:  0x%lx", CCISS_REVALIDVOLS);
4310	debug(1, "CCISS_PASSTHRU:     0x%lx", CCISS_PASSTHRU);
4311
4312	error = ENOIOCTL;
4313	break;
4314    }
4315
4316    mtx_unlock(&sc->ciss_mtx);
4317    return(error);
4318}
4319