Home | History | Annotate | Line # | Download | only in pci
ips.c revision 1.4
      1  1.4   thorpej /*	$NetBSD: ips.c,v 1.4 2021/08/07 16:19:14 thorpej Exp $	*/
      2  1.1  jdolecek /*	$OpenBSD: ips.c,v 1.113 2016/08/14 04:08:03 dlg Exp $	*/
      3  1.1  jdolecek 
      4  1.1  jdolecek /*-
      5  1.1  jdolecek  * Copyright (c) 2017 The NetBSD Foundation, Inc.
      6  1.1  jdolecek  * All rights reserved.
      7  1.1  jdolecek  *
      8  1.1  jdolecek  * Redistribution and use in source and binary forms, with or without
      9  1.1  jdolecek  * modification, are permitted provided that the following conditions
     10  1.1  jdolecek  * are met:
     11  1.1  jdolecek  * 1. Redistributions of source code must retain the above copyright
     12  1.1  jdolecek  *    notice, this list of conditions and the following disclaimer.
     13  1.1  jdolecek  * 2. Redistributions in binary form must reproduce the above copyright
     14  1.1  jdolecek  *    notice, this list of conditions and the following disclaimer in the
     15  1.1  jdolecek  *    documentation and/or other materials provided with the distribution.
     16  1.1  jdolecek  *
     17  1.1  jdolecek  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     18  1.1  jdolecek  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     19  1.1  jdolecek  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     20  1.1  jdolecek  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     21  1.1  jdolecek  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     22  1.1  jdolecek  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     23  1.1  jdolecek  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     24  1.1  jdolecek  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     25  1.1  jdolecek  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     26  1.1  jdolecek  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     27  1.1  jdolecek  * POSSIBILITY OF SUCH DAMAGE.
     28  1.1  jdolecek  */
     29  1.1  jdolecek 
     30  1.1  jdolecek /*
     31  1.1  jdolecek  * Copyright (c) 2006, 2007, 2009 Alexander Yurchenko <grange (at) openbsd.org>
     32  1.1  jdolecek  *
     33  1.1  jdolecek  * Permission to use, copy, modify, and distribute this software for any
     34  1.1  jdolecek  * purpose with or without fee is hereby granted, provided that the above
     35  1.1  jdolecek  * copyright notice and this permission notice appear in all copies.
     36  1.1  jdolecek  *
     37  1.1  jdolecek  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     38  1.1  jdolecek  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     39  1.1  jdolecek  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     40  1.1  jdolecek  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     41  1.1  jdolecek  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     42  1.1  jdolecek  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     43  1.1  jdolecek  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     44  1.1  jdolecek  */
     45  1.1  jdolecek 
     46  1.1  jdolecek /*
     47  1.1  jdolecek  * IBM (Adaptec) ServeRAID controllers driver.
     48  1.1  jdolecek  */
     49  1.1  jdolecek 
     50  1.1  jdolecek #include <sys/cdefs.h>
     51  1.4   thorpej __KERNEL_RCSID(0, "$NetBSD: ips.c,v 1.4 2021/08/07 16:19:14 thorpej Exp $");
     52  1.1  jdolecek 
     53  1.1  jdolecek #include "bio.h"
     54  1.1  jdolecek 
     55  1.1  jdolecek #include <sys/param.h>
     56  1.1  jdolecek #include <sys/systm.h>
     57  1.1  jdolecek #include <sys/device.h>
     58  1.1  jdolecek #include <sys/kernel.h>
     59  1.1  jdolecek #include <sys/queue.h>
     60  1.1  jdolecek #include <sys/buf.h>
     61  1.1  jdolecek #include <sys/endian.h>
     62  1.1  jdolecek #include <sys/conf.h>
     63  1.1  jdolecek #include <sys/malloc.h>
     64  1.1  jdolecek #include <sys/ioctl.h>
     65  1.1  jdolecek #include <sys/kthread.h>
     66  1.1  jdolecek 
     67  1.1  jdolecek #include <sys/bus.h>
     68  1.1  jdolecek #include <sys/intr.h>
     69  1.1  jdolecek 
     70  1.1  jdolecek #include <dev/scsipi/scsi_all.h>
     71  1.1  jdolecek #include <dev/scsipi/scsipi_all.h>
     72  1.1  jdolecek #include <dev/scsipi/scsi_disk.h>
     73  1.1  jdolecek #include <dev/scsipi/scsipi_disk.h>
     74  1.1  jdolecek #include <dev/scsipi/scsiconf.h>
     75  1.1  jdolecek 
     76  1.1  jdolecek #include <dev/biovar.h>
     77  1.1  jdolecek #include <dev/sysmon/sysmonvar.h>
     78  1.1  jdolecek #include <sys/envsys.h>
     79  1.1  jdolecek 
     80  1.1  jdolecek #include <dev/pci/pcireg.h>
     81  1.1  jdolecek #include <dev/pci/pcivar.h>
     82  1.1  jdolecek #include <dev/pci/pcidevs.h>
     83  1.1  jdolecek 
     84  1.1  jdolecek /* Debug levels */
     85  1.1  jdolecek #define IPS_D_ERR	0x0001	/* errors */
     86  1.1  jdolecek #define IPS_D_INFO	0x0002	/* information */
     87  1.1  jdolecek #define IPS_D_XFER	0x0004	/* transfers */
     88  1.1  jdolecek 
     89  1.1  jdolecek #ifdef IPS_DEBUG
     90  1.1  jdolecek #define DPRINTF(a, b)	do { if (ips_debug & (a)) printf b; } while (0)
     91  1.1  jdolecek int ips_debug = IPS_D_ERR;
     92  1.1  jdolecek #else
     93  1.1  jdolecek #define DPRINTF(a, b)
     94  1.1  jdolecek #endif
     95  1.1  jdolecek 
     96  1.1  jdolecek #define IPS_MAXDRIVES		8
     97  1.1  jdolecek #define IPS_MAXCHANS		4
     98  1.1  jdolecek #define IPS_MAXTARGETS		16
     99  1.1  jdolecek #define IPS_MAXCHUNKS		16
    100  1.1  jdolecek #define IPS_MAXCMDS		128
    101  1.1  jdolecek 
    102  1.1  jdolecek #define IPS_MAXFER		(64 * 1024)
    103  1.1  jdolecek #define IPS_MAXSGS		16
    104  1.1  jdolecek #define IPS_MAXCDB		12
    105  1.1  jdolecek 
    106  1.1  jdolecek #define IPS_SECSZ		512
    107  1.1  jdolecek #define IPS_NVRAMPGSZ		128
    108  1.1  jdolecek #define IPS_SQSZ		(IPS_MAXCMDS * sizeof(u_int32_t))
    109  1.1  jdolecek 
    110  1.1  jdolecek #define	IPS_TIMEOUT		60000	/* ms */
    111  1.1  jdolecek 
    112  1.1  jdolecek /* Command codes */
    113  1.1  jdolecek #define IPS_CMD_READ		0x02
    114  1.1  jdolecek #define IPS_CMD_WRITE		0x03
    115  1.1  jdolecek #define IPS_CMD_DCDB		0x04
    116  1.1  jdolecek #define IPS_CMD_GETADAPTERINFO	0x05
    117  1.1  jdolecek #define IPS_CMD_FLUSH		0x0a
    118  1.1  jdolecek #define IPS_CMD_REBUILDSTATUS	0x0c
    119  1.1  jdolecek #define IPS_CMD_SETSTATE	0x10
    120  1.1  jdolecek #define IPS_CMD_REBUILD		0x16
    121  1.1  jdolecek #define IPS_CMD_ERRORTABLE	0x17
    122  1.1  jdolecek #define IPS_CMD_GETDRIVEINFO	0x19
    123  1.1  jdolecek #define IPS_CMD_RESETCHAN	0x1a
    124  1.1  jdolecek #define IPS_CMD_DOWNLOAD	0x20
    125  1.1  jdolecek #define IPS_CMD_RWBIOSFW	0x22
    126  1.1  jdolecek #define IPS_CMD_READCONF	0x38
    127  1.1  jdolecek #define IPS_CMD_GETSUBSYS	0x40
    128  1.1  jdolecek #define IPS_CMD_CONFIGSYNC	0x58
    129  1.1  jdolecek #define IPS_CMD_READ_SG		0x82
    130  1.1  jdolecek #define IPS_CMD_WRITE_SG	0x83
    131  1.1  jdolecek #define IPS_CMD_DCDB_SG		0x84
    132  1.1  jdolecek #define IPS_CMD_EDCDB		0x95
    133  1.1  jdolecek #define IPS_CMD_EDCDB_SG	0x96
    134  1.1  jdolecek #define IPS_CMD_RWNVRAMPAGE	0xbc
    135  1.1  jdolecek #define IPS_CMD_GETVERINFO	0xc6
    136  1.1  jdolecek #define IPS_CMD_FFDC		0xd7
    137  1.1  jdolecek #define IPS_CMD_SG		0x80
    138  1.1  jdolecek #define IPS_CMD_RWNVRAM		0xbc
    139  1.1  jdolecek 
    140  1.1  jdolecek /* DCDB attributes */
    141  1.1  jdolecek #define IPS_DCDB_DATAIN		0x01	/* data input */
    142  1.1  jdolecek #define IPS_DCDB_DATAOUT	0x02	/* data output */
    143  1.1  jdolecek #define IPS_DCDB_XFER64K	0x08	/* 64K transfer */
    144  1.1  jdolecek #define IPS_DCDB_TIMO10		0x10	/* 10 secs timeout */
    145  1.1  jdolecek #define IPS_DCDB_TIMO60		0x20	/* 60 secs timeout */
    146  1.1  jdolecek #define IPS_DCDB_TIMO20M	0x30	/* 20 mins timeout */
    147  1.1  jdolecek #define IPS_DCDB_NOAUTOREQSEN	0x40	/* no auto request sense */
    148  1.1  jdolecek #define IPS_DCDB_DISCON		0x80	/* disconnect allowed */
    149  1.1  jdolecek 
    150  1.1  jdolecek /* Register definitions */
    151  1.1  jdolecek #define IPS_REG_HIS		0x08	/* host interrupt status */
    152  1.1  jdolecek #define IPS_REG_HIS_SCE			0x01	/* status channel enqueue */
    153  1.1  jdolecek #define IPS_REG_HIS_EN			0x80	/* enable interrupts */
    154  1.1  jdolecek #define IPS_REG_CCSA		0x10	/* command channel system address */
    155  1.1  jdolecek #define IPS_REG_CCC		0x14	/* command channel control */
    156  1.1  jdolecek #define IPS_REG_CCC_SEM			0x0008	/* semaphore */
    157  1.1  jdolecek #define IPS_REG_CCC_START		0x101a	/* start command */
    158  1.1  jdolecek #define IPS_REG_SQH		0x20	/* status queue head */
    159  1.1  jdolecek #define IPS_REG_SQT		0x24	/* status queue tail */
    160  1.1  jdolecek #define IPS_REG_SQE		0x28	/* status queue end */
    161  1.1  jdolecek #define IPS_REG_SQS		0x2c	/* status queue start */
    162  1.1  jdolecek 
    163  1.1  jdolecek #define IPS_REG_OIS		0x30	/* outbound interrupt status */
    164  1.1  jdolecek #define IPS_REG_OIS_PEND		0x0008	/* interrupt is pending */
    165  1.1  jdolecek #define IPS_REG_OIM		0x34	/* outbound interrupt mask */
    166  1.1  jdolecek #define IPS_REG_OIM_DS			0x0008	/* disable interrupts */
    167  1.1  jdolecek #define IPS_REG_IQP		0x40	/* inbound queue port */
    168  1.1  jdolecek #define IPS_REG_OQP		0x44	/* outbound queue port */
    169  1.1  jdolecek 
    170  1.1  jdolecek /* Status word fields */
    171  1.1  jdolecek #define IPS_STAT_ID(x)		(((x) >> 8) & 0xff)	/* command id */
    172  1.1  jdolecek #define IPS_STAT_BASIC(x)	(((x) >> 16) & 0xff)	/* basic status */
    173  1.1  jdolecek #define IPS_STAT_EXT(x)		(((x) >> 24) & 0xff)	/* ext status */
    174  1.1  jdolecek #define IPS_STAT_GSC(x)		((x) & 0x0f)
    175  1.1  jdolecek 
    176  1.1  jdolecek /* Basic status codes */
    177  1.1  jdolecek #define IPS_STAT_OK		0x00	/* success */
    178  1.1  jdolecek #define IPS_STAT_RECOV		0x01	/* recovered error */
    179  1.1  jdolecek #define IPS_STAT_INVOP		0x03	/* invalid opcode */
    180  1.1  jdolecek #define IPS_STAT_INVCMD		0x04	/* invalid command block */
    181  1.1  jdolecek #define IPS_STAT_INVPARM	0x05	/* invalid parameters block */
    182  1.1  jdolecek #define IPS_STAT_BUSY		0x08	/* busy */
    183  1.1  jdolecek #define IPS_STAT_CMPLERR	0x0c	/* completed with error */
    184  1.1  jdolecek #define IPS_STAT_LDERR		0x0d	/* logical drive error */
    185  1.1  jdolecek #define IPS_STAT_TIMO		0x0e	/* timeout */
    186  1.1  jdolecek #define IPS_STAT_PDRVERR	0x0f	/* physical drive error */
    187  1.1  jdolecek 
    188  1.1  jdolecek /* Extended status codes */
    189  1.1  jdolecek #define IPS_ESTAT_SELTIMO	0xf0	/* select timeout */
    190  1.1  jdolecek #define IPS_ESTAT_OURUN		0xf2	/* over/underrun */
    191  1.1  jdolecek #define IPS_ESTAT_HOSTRST	0xf7	/* host reset */
    192  1.1  jdolecek #define IPS_ESTAT_DEVRST	0xf8	/* device reset */
    193  1.1  jdolecek #define IPS_ESTAT_RECOV		0xfc	/* recovered error */
    194  1.1  jdolecek #define IPS_ESTAT_CKCOND	0xff	/* check condition */
    195  1.1  jdolecek 
    196  1.1  jdolecek #define IPS_IOSIZE		128	/* max space size to map */
    197  1.1  jdolecek 
    198  1.1  jdolecek /* Command frame */
    199  1.1  jdolecek struct ips_cmd {
    200  1.1  jdolecek 	u_int8_t	code;
    201  1.1  jdolecek 	u_int8_t	id;
    202  1.1  jdolecek 	u_int8_t	drive;
    203  1.1  jdolecek 	u_int8_t	sgcnt;
    204  1.1  jdolecek 	u_int32_t	lba;
    205  1.1  jdolecek 	u_int32_t	sgaddr;
    206  1.1  jdolecek 	u_int16_t	seccnt;
    207  1.1  jdolecek 	u_int8_t	seg4g;
    208  1.1  jdolecek 	u_int8_t	esg;
    209  1.1  jdolecek 	u_int32_t	ccsar;
    210  1.1  jdolecek 	u_int32_t	cccr;
    211  1.1  jdolecek };
    212  1.1  jdolecek 
    213  1.1  jdolecek /* Direct CDB (SCSI pass-through) frame */
    214  1.1  jdolecek struct ips_dcdb {
    215  1.1  jdolecek 	u_int8_t	device;
    216  1.1  jdolecek 	u_int8_t	attr;
    217  1.1  jdolecek 	u_int16_t	datalen;
    218  1.1  jdolecek 	u_int32_t	sgaddr;
    219  1.1  jdolecek 	u_int8_t	cdblen;
    220  1.1  jdolecek 	u_int8_t	senselen;
    221  1.1  jdolecek 	u_int8_t	sgcnt;
    222  1.1  jdolecek 	u_int8_t	__reserved1;
    223  1.1  jdolecek 	u_int8_t	cdb[IPS_MAXCDB];
    224  1.1  jdolecek 	u_int8_t	sense[64];
    225  1.1  jdolecek 	u_int8_t	status;
    226  1.1  jdolecek 	u_int8_t	__reserved2[3];
    227  1.1  jdolecek };
    228  1.1  jdolecek 
    229  1.1  jdolecek /* Scatter-gather array element */
    230  1.1  jdolecek struct ips_sg {
    231  1.1  jdolecek 	u_int32_t	addr;
    232  1.1  jdolecek 	u_int32_t	size;
    233  1.1  jdolecek };
    234  1.1  jdolecek 
    235  1.1  jdolecek /* Command block */
    236  1.1  jdolecek struct ips_cmdb {
    237  1.1  jdolecek 	struct ips_cmd	cmd;
    238  1.1  jdolecek 	struct ips_dcdb	dcdb;
    239  1.1  jdolecek 	struct ips_sg	sg[IPS_MAXSGS];
    240  1.1  jdolecek };
    241  1.1  jdolecek 
    242  1.1  jdolecek /* Data frames */
    243  1.1  jdolecek struct ips_adapterinfo {
    244  1.1  jdolecek 	u_int8_t	drivecnt;
    245  1.1  jdolecek 	u_int8_t	miscflag;
    246  1.1  jdolecek 	u_int8_t	sltflag;
    247  1.1  jdolecek 	u_int8_t	bstflag;
    248  1.1  jdolecek 	u_int8_t	pwrchgcnt;
    249  1.1  jdolecek 	u_int8_t	wrongaddrcnt;
    250  1.1  jdolecek 	u_int8_t	unidentcnt;
    251  1.1  jdolecek 	u_int8_t	nvramdevchgcnt;
    252  1.1  jdolecek 	u_int8_t	firmware[8];
    253  1.1  jdolecek 	u_int8_t	bios[8];
    254  1.1  jdolecek 	u_int32_t	drivesize[IPS_MAXDRIVES];
    255  1.1  jdolecek 	u_int8_t	cmdcnt;
    256  1.1  jdolecek 	u_int8_t	maxphysdevs;
    257  1.1  jdolecek 	u_int16_t	flashrepgmcnt;
    258  1.1  jdolecek 	u_int8_t	defunctdiskcnt;
    259  1.1  jdolecek 	u_int8_t	rebuildflag;
    260  1.1  jdolecek 	u_int8_t	offdrivecnt;
    261  1.1  jdolecek 	u_int8_t	critdrivecnt;
    262  1.1  jdolecek 	u_int16_t	confupdcnt;
    263  1.1  jdolecek 	u_int8_t	blkflag;
    264  1.1  jdolecek 	u_int8_t	__reserved;
    265  1.1  jdolecek 	u_int16_t	deaddisk[IPS_MAXCHANS][IPS_MAXTARGETS];
    266  1.1  jdolecek };
    267  1.1  jdolecek 
    268  1.1  jdolecek struct ips_driveinfo {
    269  1.1  jdolecek 	u_int8_t	drivecnt;
    270  1.1  jdolecek 	u_int8_t	__reserved[3];
    271  1.1  jdolecek 	struct ips_drive {
    272  1.1  jdolecek 		u_int8_t	id;
    273  1.1  jdolecek 		u_int8_t	__reserved;
    274  1.1  jdolecek 		u_int8_t	raid;
    275  1.1  jdolecek 		u_int8_t	state;
    276  1.1  jdolecek #define IPS_DS_FREE	0x00
    277  1.1  jdolecek #define IPS_DS_OFFLINE	0x02
    278  1.1  jdolecek #define IPS_DS_ONLINE	0x03
    279  1.1  jdolecek #define IPS_DS_DEGRADED	0x04
    280  1.1  jdolecek #define IPS_DS_SYS	0x06
    281  1.1  jdolecek #define IPS_DS_CRS	0x24
    282  1.1  jdolecek 
    283  1.1  jdolecek 		u_int32_t	seccnt;
    284  1.1  jdolecek 	}		drive[IPS_MAXDRIVES];
    285  1.1  jdolecek };
    286  1.1  jdolecek 
    287  1.1  jdolecek struct ips_conf {
    288  1.1  jdolecek 	u_int8_t	ldcnt;
    289  1.1  jdolecek 	u_int8_t	day;
    290  1.1  jdolecek 	u_int8_t	month;
    291  1.1  jdolecek 	u_int8_t	year;
    292  1.1  jdolecek 	u_int8_t	initid[4];
    293  1.1  jdolecek 	u_int8_t	hostid[12];
    294  1.1  jdolecek 	u_int8_t	time[8];
    295  1.1  jdolecek 	u_int32_t	useropt;
    296  1.1  jdolecek 	u_int16_t	userfield;
    297  1.1  jdolecek 	u_int8_t	rebuildrate;
    298  1.1  jdolecek 	u_int8_t	__reserved1;
    299  1.1  jdolecek 
    300  1.1  jdolecek 	struct ips_hw {
    301  1.1  jdolecek 		u_int8_t	board[8];
    302  1.1  jdolecek 		u_int8_t	cpu[8];
    303  1.1  jdolecek 		u_int8_t	nchantype;
    304  1.1  jdolecek 		u_int8_t	nhostinttype;
    305  1.1  jdolecek 		u_int8_t	compression;
    306  1.1  jdolecek 		u_int8_t	nvramtype;
    307  1.1  jdolecek 		u_int32_t	nvramsize;
    308  1.1  jdolecek 	}		hw;
    309  1.1  jdolecek 
    310  1.1  jdolecek 	struct ips_ld {
    311  1.1  jdolecek 		u_int16_t	userfield;
    312  1.1  jdolecek 		u_int8_t	state;
    313  1.1  jdolecek 		u_int8_t	raidcacheparam;
    314  1.1  jdolecek 		u_int8_t	chunkcnt;
    315  1.1  jdolecek 		u_int8_t	stripesize;
    316  1.1  jdolecek 		u_int8_t	params;
    317  1.1  jdolecek 		u_int8_t	__reserved;
    318  1.1  jdolecek 		u_int32_t	size;
    319  1.1  jdolecek 
    320  1.1  jdolecek 		struct ips_chunk {
    321  1.1  jdolecek 			u_int8_t	channel;
    322  1.1  jdolecek 			u_int8_t	target;
    323  1.1  jdolecek 			u_int16_t	__reserved;
    324  1.1  jdolecek 			u_int32_t	startsec;
    325  1.1  jdolecek 			u_int32_t	seccnt;
    326  1.1  jdolecek 		}		chunk[IPS_MAXCHUNKS];
    327  1.1  jdolecek 	}		ld[IPS_MAXDRIVES];
    328  1.1  jdolecek 
    329  1.1  jdolecek 	struct ips_dev {
    330  1.1  jdolecek 		u_int8_t	initiator;
    331  1.1  jdolecek 		u_int8_t	params;
    332  1.1  jdolecek 		u_int8_t	miscflag;
    333  1.1  jdolecek 		u_int8_t	state;
    334  1.1  jdolecek #define IPS_DVS_STANDBY	0x01
    335  1.1  jdolecek #define IPS_DVS_REBUILD	0x02
    336  1.1  jdolecek #define IPS_DVS_SPARE	0x04
    337  1.1  jdolecek #define IPS_DVS_MEMBER	0x08
    338  1.1  jdolecek #define IPS_DVS_ONLINE	0x80
    339  1.1  jdolecek #define IPS_DVS_READY	(IPS_DVS_STANDBY | IPS_DVS_ONLINE)
    340  1.1  jdolecek 
    341  1.1  jdolecek 		u_int32_t	seccnt;
    342  1.1  jdolecek 		u_int8_t	devid[28];
    343  1.1  jdolecek 	}		dev[IPS_MAXCHANS][IPS_MAXTARGETS];
    344  1.1  jdolecek 
    345  1.1  jdolecek 	u_int8_t	reserved[512];
    346  1.1  jdolecek };
    347  1.1  jdolecek 
    348  1.1  jdolecek struct ips_rblstat {
    349  1.1  jdolecek 	u_int8_t	__unknown[20];
    350  1.1  jdolecek 	struct {
    351  1.1  jdolecek 		u_int8_t	__unknown[4];
    352  1.1  jdolecek 		u_int32_t	total;
    353  1.1  jdolecek 		u_int32_t	remain;
    354  1.1  jdolecek 	}		ld[IPS_MAXDRIVES];
    355  1.1  jdolecek };
    356  1.1  jdolecek 
    357  1.1  jdolecek struct ips_pg5 {
    358  1.1  jdolecek 	u_int32_t	signature;
    359  1.1  jdolecek 	u_int8_t	__reserved1;
    360  1.1  jdolecek 	u_int8_t	slot;
    361  1.1  jdolecek 	u_int16_t	type;
    362  1.1  jdolecek 	u_int8_t	bioshi[4];
    363  1.1  jdolecek 	u_int8_t	bioslo[4];
    364  1.1  jdolecek 	u_int16_t	__reserved2;
    365  1.1  jdolecek 	u_int8_t	__reserved3;
    366  1.1  jdolecek 	u_int8_t	os;
    367  1.1  jdolecek 	u_int8_t	driverhi[4];
    368  1.1  jdolecek 	u_int8_t	driverlo[4];
    369  1.1  jdolecek 	u_int8_t	__reserved4[100];
    370  1.1  jdolecek };
    371  1.1  jdolecek 
    372  1.1  jdolecek struct ips_info {
    373  1.1  jdolecek 	struct ips_adapterinfo	adapter;
    374  1.1  jdolecek 	struct ips_driveinfo	drive;
    375  1.1  jdolecek 	struct ips_conf		conf;
    376  1.1  jdolecek 	struct ips_rblstat	rblstat;
    377  1.1  jdolecek 	struct ips_pg5		pg5;
    378  1.1  jdolecek };
    379  1.1  jdolecek 
    380  1.1  jdolecek /* Command control block */
    381  1.1  jdolecek struct ips_softc;
    382  1.1  jdolecek struct ips_ccb {
    383  1.1  jdolecek 	struct ips_softc *	c_sc;		/* driver softc */
    384  1.1  jdolecek 	int			c_id;		/* command id */
    385  1.1  jdolecek 	int			c_flags;	/* SCSI_* flags */
    386  1.1  jdolecek 	enum {
    387  1.1  jdolecek 		IPS_CCB_FREE,
    388  1.1  jdolecek 		IPS_CCB_QUEUED,
    389  1.1  jdolecek 		IPS_CCB_DONE
    390  1.1  jdolecek 	}			c_state;	/* command state */
    391  1.1  jdolecek 
    392  1.1  jdolecek 	void *			c_cmdbva;	/* command block virt addr */
    393  1.1  jdolecek 	paddr_t			c_cmdbpa;	/* command block phys addr */
    394  1.1  jdolecek 	bus_dmamap_t		c_dmam;		/* data buffer DMA map */
    395  1.1  jdolecek 
    396  1.1  jdolecek 	struct scsipi_xfer *	c_xfer;		/* corresponding SCSI xfer */
    397  1.1  jdolecek 
    398  1.1  jdolecek 	u_int8_t		c_stat;		/* status byte copy */
    399  1.1  jdolecek 	u_int8_t		c_estat;	/* ext status byte copy */
    400  1.1  jdolecek 	int			c_error;	/* completion error */
    401  1.1  jdolecek 
    402  1.1  jdolecek 	void			(*c_done)(struct ips_softc *,	/* cmd done */
    403  1.1  jdolecek 				    struct ips_ccb *);		/* callback */
    404  1.1  jdolecek 
    405  1.1  jdolecek 	SLIST_ENTRY(ips_ccb)	c_link;		/* queue link */
    406  1.1  jdolecek };
    407  1.1  jdolecek 
    408  1.1  jdolecek /* CCB queue */
    409  1.1  jdolecek SLIST_HEAD(ips_ccbq, ips_ccb);
    410  1.1  jdolecek 
    411  1.1  jdolecek /* DMA-able chunk of memory */
    412  1.1  jdolecek struct dmamem {
    413  1.1  jdolecek 	bus_dma_tag_t		dm_tag;
    414  1.1  jdolecek 	bus_dmamap_t		dm_map;
    415  1.1  jdolecek 	bus_dma_segment_t	dm_seg;
    416  1.1  jdolecek 	bus_size_t		dm_size;
    417  1.1  jdolecek 	void *			dm_vaddr;
    418  1.1  jdolecek #define dm_paddr dm_seg.ds_addr
    419  1.1  jdolecek };
    420  1.1  jdolecek 
    421  1.1  jdolecek struct ips_softc {
    422  1.1  jdolecek 	struct device		sc_dev;
    423  1.1  jdolecek 
    424  1.1  jdolecek 	/* SCSI mid-layer connection. */
    425  1.1  jdolecek 	struct scsipi_adapter   sc_adapt;
    426  1.1  jdolecek 
    427  1.1  jdolecek 	struct ips_pt {
    428  1.1  jdolecek 		struct scsipi_channel	pt_chan;
    429  1.1  jdolecek 		int			pt_nchan;
    430  1.1  jdolecek 		struct ips_softc *	pt_sc;
    431  1.1  jdolecek 
    432  1.1  jdolecek 		int			pt_proctgt;
    433  1.1  jdolecek 		char			pt_procdev[16];
    434  1.1  jdolecek 	}			sc_pt[IPS_MAXCHANS];
    435  1.1  jdolecek 
    436  1.1  jdolecek 	bus_space_tag_t		sc_iot;
    437  1.1  jdolecek 	bus_space_handle_t	sc_ioh;
    438  1.1  jdolecek 	bus_dma_tag_t		sc_dmat;
    439  1.1  jdolecek 
    440  1.1  jdolecek 	const struct ips_chipset *sc_chip;
    441  1.1  jdolecek 
    442  1.1  jdolecek 	struct ips_info *	sc_info;
    443  1.1  jdolecek 	struct dmamem		sc_infom;
    444  1.1  jdolecek 
    445  1.1  jdolecek 	int			sc_nunits;
    446  1.1  jdolecek 
    447  1.1  jdolecek 	struct dmamem		sc_cmdbm;
    448  1.1  jdolecek 
    449  1.1  jdolecek 	struct ips_ccb *	sc_ccb;
    450  1.1  jdolecek 	int			sc_nccbs;
    451  1.1  jdolecek 	struct ips_ccbq		sc_ccbq_free;
    452  1.1  jdolecek 	struct kmutex		sc_ccb_mtx;
    453  1.1  jdolecek 
    454  1.1  jdolecek 	struct dmamem		sc_sqm;
    455  1.1  jdolecek 	paddr_t			sc_sqtail;
    456  1.1  jdolecek 	u_int32_t *		sc_sqbuf;
    457  1.1  jdolecek 	int			sc_sqidx;
    458  1.1  jdolecek };
    459  1.1  jdolecek 
    460  1.1  jdolecek int	ips_match(device_t, cfdata_t, void *);
    461  1.1  jdolecek void	ips_attach(struct device *, struct device *, void *);
    462  1.1  jdolecek 
    463  1.1  jdolecek void	ips_scsi_cmd(struct ips_ccb *);
    464  1.1  jdolecek void	ips_scsi_pt_cmd(struct scsipi_xfer *);
    465  1.1  jdolecek static void ips_scsipi_request(struct scsipi_channel *,
    466  1.1  jdolecek 	    scsipi_adapter_req_t, void *);
    467  1.1  jdolecek int	ips_scsi_ioctl(struct scsipi_channel *, u_long, void *,
    468  1.1  jdolecek 	    int, struct proc *);
    469  1.1  jdolecek 
    470  1.1  jdolecek #if NBIO > 0
    471  1.1  jdolecek int	ips_ioctl(device_t, u_long, void *);
    472  1.1  jdolecek int	ips_ioctl_inq(struct ips_softc *, struct bioc_inq *);
    473  1.1  jdolecek int	ips_ioctl_vol(struct ips_softc *, struct bioc_vol *);
    474  1.1  jdolecek int	ips_ioctl_disk(struct ips_softc *, struct bioc_disk *);
    475  1.1  jdolecek int	ips_ioctl_setstate(struct ips_softc *, struct bioc_setstate *);
    476  1.1  jdolecek #endif
    477  1.1  jdolecek 
    478  1.1  jdolecek int	ips_load_xs(struct ips_softc *, struct ips_ccb *, struct scsipi_xfer *);
    479  1.1  jdolecek void	ips_start_xs(struct ips_softc *, struct ips_ccb *, struct scsipi_xfer *);
    480  1.1  jdolecek 
    481  1.1  jdolecek int	ips_cmd(struct ips_softc *, struct ips_ccb *);
    482  1.1  jdolecek int	ips_poll(struct ips_softc *, struct ips_ccb *);
    483  1.1  jdolecek void	ips_done(struct ips_softc *, struct ips_ccb *);
    484  1.1  jdolecek void	ips_done_xs(struct ips_softc *, struct ips_ccb *);
    485  1.1  jdolecek void	ips_done_pt(struct ips_softc *, struct ips_ccb *);
    486  1.1  jdolecek void	ips_done_mgmt(struct ips_softc *, struct ips_ccb *);
    487  1.1  jdolecek int	ips_error(struct ips_softc *, struct ips_ccb *);
    488  1.1  jdolecek int	ips_error_xs(struct ips_softc *, struct ips_ccb *);
    489  1.1  jdolecek int	ips_intr(void *);
    490  1.1  jdolecek void	ips_timeout(void *);
    491  1.1  jdolecek 
    492  1.1  jdolecek int	ips_getadapterinfo(struct ips_softc *, int);
    493  1.1  jdolecek int	ips_getdriveinfo(struct ips_softc *, int);
    494  1.1  jdolecek int	ips_getconf(struct ips_softc *, int);
    495  1.1  jdolecek int	ips_getpg5(struct ips_softc *, int);
    496  1.1  jdolecek 
    497  1.1  jdolecek #if NBIO > 0
    498  1.1  jdolecek int	ips_getrblstat(struct ips_softc *, int);
    499  1.1  jdolecek int	ips_setstate(struct ips_softc *, int, int, int, int);
    500  1.1  jdolecek int	ips_rebuild(struct ips_softc *, int, int, int, int, int);
    501  1.1  jdolecek #endif
    502  1.1  jdolecek 
    503  1.1  jdolecek void	ips_copperhead_exec(struct ips_softc *, struct ips_ccb *);
    504  1.1  jdolecek void	ips_copperhead_intren(struct ips_softc *);
    505  1.1  jdolecek int	ips_copperhead_isintr(struct ips_softc *);
    506  1.1  jdolecek u_int32_t ips_copperhead_status(struct ips_softc *);
    507  1.1  jdolecek 
    508  1.1  jdolecek void	ips_morpheus_exec(struct ips_softc *, struct ips_ccb *);
    509  1.1  jdolecek void	ips_morpheus_intren(struct ips_softc *);
    510  1.1  jdolecek int	ips_morpheus_isintr(struct ips_softc *);
    511  1.1  jdolecek u_int32_t ips_morpheus_status(struct ips_softc *);
    512  1.1  jdolecek 
    513  1.1  jdolecek struct ips_ccb *ips_ccb_alloc(struct ips_softc *, int);
    514  1.1  jdolecek void	ips_ccb_free(struct ips_softc *, struct ips_ccb *, int);
    515  1.1  jdolecek struct ips_ccb *ips_ccb_get(struct ips_softc *);
    516  1.1  jdolecek void	ips_ccb_put(struct ips_softc *, struct ips_ccb *);
    517  1.1  jdolecek 
    518  1.1  jdolecek int	ips_dmamem_alloc(struct dmamem *, bus_dma_tag_t, bus_size_t);
    519  1.1  jdolecek void	ips_dmamem_free(struct dmamem *);
    520  1.1  jdolecek 
    521  1.1  jdolecek extern struct  cfdriver ips_cd;
    522  1.1  jdolecek 
    523  1.1  jdolecek CFATTACH_DECL_NEW(ips, sizeof(struct ips_softc),
    524  1.1  jdolecek     ips_match, ips_attach, NULL, NULL);
    525  1.1  jdolecek 
    526  1.1  jdolecek static struct ips_ident {
    527  1.1  jdolecek         pci_vendor_id_t vendor;
    528  1.1  jdolecek         pci_product_id_t product;
    529  1.1  jdolecek } const ips_ids[] = {
    530  1.1  jdolecek 	{ PCI_VENDOR_IBM,	PCI_PRODUCT_IBM_SERVERAID },
    531  1.1  jdolecek 	{ PCI_VENDOR_IBM,	PCI_PRODUCT_IBM_SERVERAID4 },
    532  1.1  jdolecek 	{ PCI_VENDOR_ADP2,	PCI_PRODUCT_ADP2_SERVERAID }
    533  1.1  jdolecek };
    534  1.1  jdolecek 
    535  1.1  jdolecek static const struct ips_chipset {
    536  1.1  jdolecek 	enum {
    537  1.1  jdolecek 		IPS_CHIP_COPPERHEAD = 0,
    538  1.1  jdolecek 		IPS_CHIP_MORPHEUS
    539  1.1  jdolecek 	}		ic_id;
    540  1.1  jdolecek 
    541  1.1  jdolecek 	int		ic_bar;
    542  1.1  jdolecek 
    543  1.1  jdolecek 	void		(*ic_exec)(struct ips_softc *, struct ips_ccb *);
    544  1.1  jdolecek 	void		(*ic_intren)(struct ips_softc *);
    545  1.1  jdolecek 	int		(*ic_isintr)(struct ips_softc *);
    546  1.1  jdolecek 	u_int32_t	(*ic_status)(struct ips_softc *);
    547  1.1  jdolecek } ips_chips[] = {
    548  1.1  jdolecek 	{
    549  1.1  jdolecek 		IPS_CHIP_COPPERHEAD,
    550  1.1  jdolecek 		0x14,
    551  1.1  jdolecek 		ips_copperhead_exec,
    552  1.1  jdolecek 		ips_copperhead_intren,
    553  1.1  jdolecek 		ips_copperhead_isintr,
    554  1.1  jdolecek 		ips_copperhead_status
    555  1.1  jdolecek 	},
    556  1.1  jdolecek 	{
    557  1.1  jdolecek 		IPS_CHIP_MORPHEUS,
    558  1.1  jdolecek 		0x10,
    559  1.1  jdolecek 		ips_morpheus_exec,
    560  1.1  jdolecek 		ips_morpheus_intren,
    561  1.1  jdolecek 		ips_morpheus_isintr,
    562  1.1  jdolecek 		ips_morpheus_status
    563  1.1  jdolecek 	}
    564  1.1  jdolecek };
    565  1.1  jdolecek 
    566  1.1  jdolecek #define ips_exec(s, c)	(s)->sc_chip->ic_exec((s), (c))
    567  1.1  jdolecek #define ips_intren(s)	(s)->sc_chip->ic_intren((s))
    568  1.1  jdolecek #define ips_isintr(s)	(s)->sc_chip->ic_isintr((s))
    569  1.1  jdolecek #define ips_status(s)	(s)->sc_chip->ic_status((s))
    570  1.1  jdolecek 
    571  1.1  jdolecek static const char *ips_names[] = {
    572  1.1  jdolecek 	NULL,
    573  1.1  jdolecek 	NULL,
    574  1.1  jdolecek 	"II",
    575  1.1  jdolecek 	"onboard",
    576  1.1  jdolecek 	"onboard",
    577  1.1  jdolecek 	"3H",
    578  1.1  jdolecek 	"3L",
    579  1.1  jdolecek 	"4H",
    580  1.1  jdolecek 	"4M",
    581  1.1  jdolecek 	"4L",
    582  1.1  jdolecek 	"4Mx",
    583  1.1  jdolecek 	"4Lx",
    584  1.1  jdolecek 	"5i",
    585  1.1  jdolecek 	"5i",
    586  1.1  jdolecek 	"6M",
    587  1.1  jdolecek 	"6i",
    588  1.1  jdolecek 	"7t",
    589  1.1  jdolecek 	"7k",
    590  1.1  jdolecek 	"7M"
    591  1.1  jdolecek };
    592  1.1  jdolecek 
    593  1.1  jdolecek /* Lookup supported device table */
    594  1.1  jdolecek static const struct ips_ident *
    595  1.1  jdolecek ips_lookup(const struct pci_attach_args *pa)
    596  1.1  jdolecek {
    597  1.1  jdolecek         const struct ips_ident *imp;
    598  1.1  jdolecek 	int i;
    599  1.1  jdolecek 
    600  1.1  jdolecek 	for (i = 0, imp = ips_ids; i < __arraycount(ips_ids); i++, imp++) {
    601  1.1  jdolecek                 if (PCI_VENDOR(pa->pa_id) == imp->vendor &&
    602  1.1  jdolecek                     PCI_PRODUCT(pa->pa_id) == imp->product)
    603  1.1  jdolecek                         return imp;
    604  1.1  jdolecek         }
    605  1.1  jdolecek         return NULL;
    606  1.1  jdolecek }
    607  1.1  jdolecek 
    608  1.1  jdolecek int
    609  1.1  jdolecek ips_match(device_t parent, cfdata_t cfdata, void *aux)
    610  1.1  jdolecek {
    611  1.1  jdolecek 	struct pci_attach_args *pa = aux;
    612  1.1  jdolecek 
    613  1.1  jdolecek 	if (ips_lookup(pa) != NULL)
    614  1.1  jdolecek 		return 1;
    615  1.1  jdolecek 
    616  1.1  jdolecek 	return 0;
    617  1.1  jdolecek }
    618  1.1  jdolecek 
    619  1.1  jdolecek void
    620  1.1  jdolecek ips_attach(struct device *parent, struct device *self, void *aux)
    621  1.1  jdolecek {
    622  1.1  jdolecek 	struct ips_softc *sc = (struct ips_softc *)self;
    623  1.1  jdolecek 	struct pci_attach_args *pa = aux;
    624  1.1  jdolecek 	struct ips_ccb ccb0;
    625  1.1  jdolecek 	struct ips_adapterinfo *ai;
    626  1.1  jdolecek 	struct ips_driveinfo *di;
    627  1.1  jdolecek 	struct ips_pg5 *pg5;
    628  1.1  jdolecek 	pcireg_t maptype;
    629  1.1  jdolecek 	bus_size_t iosize;
    630  1.1  jdolecek 	pci_intr_handle_t ih;
    631  1.1  jdolecek 	const char *intrstr;
    632  1.1  jdolecek 	int type, i;
    633  1.1  jdolecek 	struct scsipi_adapter *adapt;
    634  1.1  jdolecek 	struct scsipi_channel *chan;
    635  1.1  jdolecek 	char intrbuf[PCI_INTRSTR_LEN];
    636  1.1  jdolecek 
    637  1.1  jdolecek 	sc->sc_dmat = pa->pa_dmat;
    638  1.1  jdolecek 
    639  1.1  jdolecek 	/* Identify chipset */
    640  1.1  jdolecek 	if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_IBM_SERVERAID)
    641  1.1  jdolecek 		sc->sc_chip = &ips_chips[IPS_CHIP_COPPERHEAD];
    642  1.1  jdolecek 	else
    643  1.1  jdolecek 		sc->sc_chip = &ips_chips[IPS_CHIP_MORPHEUS];
    644  1.1  jdolecek 
    645  1.1  jdolecek 	/* Map registers */
    646  1.1  jdolecek 	// XXX check IPS_IOSIZE as old code used to do?
    647  1.1  jdolecek 	maptype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, sc->sc_chip->ic_bar);
    648  1.1  jdolecek 	if (pci_mapreg_map(pa, sc->sc_chip->ic_bar, maptype, 0, &sc->sc_iot,
    649  1.1  jdolecek 	    &sc->sc_ioh, NULL, &iosize)) {
    650  1.1  jdolecek 		printf(": can't map regs\n");
    651  1.1  jdolecek 		return;
    652  1.1  jdolecek 	}
    653  1.1  jdolecek 
    654  1.1  jdolecek 	/* Allocate command buffer */
    655  1.1  jdolecek 	if (ips_dmamem_alloc(&sc->sc_cmdbm, sc->sc_dmat,
    656  1.1  jdolecek 	    IPS_MAXCMDS * sizeof(struct ips_cmdb))) {
    657  1.1  jdolecek 		printf(": can't alloc cmd buffer\n");
    658  1.1  jdolecek 		goto fail1;
    659  1.1  jdolecek 	}
    660  1.1  jdolecek 
    661  1.1  jdolecek 	/* Allocate info buffer */
    662  1.1  jdolecek 	if (ips_dmamem_alloc(&sc->sc_infom, sc->sc_dmat,
    663  1.1  jdolecek 	    sizeof(struct ips_info))) {
    664  1.1  jdolecek 		printf(": can't alloc info buffer\n");
    665  1.1  jdolecek 		goto fail2;
    666  1.1  jdolecek 	}
    667  1.1  jdolecek 	sc->sc_info = sc->sc_infom.dm_vaddr;
    668  1.1  jdolecek 	ai = &sc->sc_info->adapter;
    669  1.1  jdolecek 	di = &sc->sc_info->drive;
    670  1.1  jdolecek 	pg5 = &sc->sc_info->pg5;
    671  1.1  jdolecek 
    672  1.1  jdolecek 	/* Allocate status queue for the Copperhead chipset */
    673  1.1  jdolecek 	if (sc->sc_chip->ic_id == IPS_CHIP_COPPERHEAD) {
    674  1.1  jdolecek 		if (ips_dmamem_alloc(&sc->sc_sqm, sc->sc_dmat, IPS_SQSZ)) {
    675  1.1  jdolecek 			printf(": can't alloc status queue\n");
    676  1.1  jdolecek 			goto fail3;
    677  1.1  jdolecek 		}
    678  1.1  jdolecek 		sc->sc_sqtail = sc->sc_sqm.dm_paddr;
    679  1.1  jdolecek 		sc->sc_sqbuf = sc->sc_sqm.dm_vaddr;
    680  1.1  jdolecek 		sc->sc_sqidx = 0;
    681  1.1  jdolecek 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, IPS_REG_SQS,
    682  1.1  jdolecek 		    sc->sc_sqm.dm_paddr);
    683  1.1  jdolecek 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, IPS_REG_SQE,
    684  1.1  jdolecek 		    sc->sc_sqm.dm_paddr + IPS_SQSZ);
    685  1.1  jdolecek 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, IPS_REG_SQH,
    686  1.1  jdolecek 		    sc->sc_sqm.dm_paddr + sizeof(u_int32_t));
    687  1.1  jdolecek 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, IPS_REG_SQT,
    688  1.1  jdolecek 		    sc->sc_sqm.dm_paddr);
    689  1.1  jdolecek 	}
    690  1.1  jdolecek 
    691  1.1  jdolecek 	/* Bootstrap CCB queue */
    692  1.1  jdolecek 	sc->sc_nccbs = 1;
    693  1.1  jdolecek 	sc->sc_ccb = &ccb0;
    694  1.1  jdolecek 	bzero(&ccb0, sizeof(ccb0));
    695  1.1  jdolecek 	ccb0.c_cmdbva = sc->sc_cmdbm.dm_vaddr;
    696  1.1  jdolecek 	ccb0.c_cmdbpa = sc->sc_cmdbm.dm_paddr;
    697  1.1  jdolecek 	SLIST_INIT(&sc->sc_ccbq_free);
    698  1.1  jdolecek 	SLIST_INSERT_HEAD(&sc->sc_ccbq_free, &ccb0, c_link);
    699  1.1  jdolecek 	mutex_init(&sc->sc_ccb_mtx, MUTEX_DEFAULT, IPL_BIO);
    700  1.1  jdolecek 
    701  1.1  jdolecek 	/* Get adapter info */
    702  1.1  jdolecek 	if (ips_getadapterinfo(sc, XS_CTL_NOSLEEP)) {
    703  1.1  jdolecek 		printf(": can't get adapter info\n");
    704  1.1  jdolecek 		goto fail4;
    705  1.1  jdolecek 	}
    706  1.1  jdolecek 
    707  1.1  jdolecek 	/* Get logical drives info */
    708  1.1  jdolecek 	if (ips_getdriveinfo(sc, XS_CTL_NOSLEEP)) {
    709  1.1  jdolecek 		printf(": can't get ld info\n");
    710  1.1  jdolecek 		goto fail4;
    711  1.1  jdolecek 	}
    712  1.1  jdolecek 	sc->sc_nunits = di->drivecnt;
    713  1.1  jdolecek 
    714  1.1  jdolecek 	/* Get configuration */
    715  1.1  jdolecek 	if (ips_getconf(sc, XS_CTL_NOSLEEP)) {
    716  1.1  jdolecek 		printf(": can't get config\n");
    717  1.1  jdolecek 		goto fail4;
    718  1.1  jdolecek 	}
    719  1.1  jdolecek 
    720  1.1  jdolecek 	/* Read NVRAM page 5 for additional info */
    721  1.1  jdolecek 	(void)ips_getpg5(sc, XS_CTL_NOSLEEP);
    722  1.1  jdolecek 
    723  1.1  jdolecek 	/* Initialize CCB queue */
    724  1.1  jdolecek 	sc->sc_nccbs = ai->cmdcnt;
    725  1.1  jdolecek 	if ((sc->sc_ccb = ips_ccb_alloc(sc, sc->sc_nccbs)) == NULL) {
    726  1.1  jdolecek 		printf(": can't alloc ccb queue\n");
    727  1.1  jdolecek 		goto fail4;
    728  1.1  jdolecek 	}
    729  1.1  jdolecek 	SLIST_INIT(&sc->sc_ccbq_free);
    730  1.1  jdolecek 	for (i = 0; i < sc->sc_nccbs; i++)
    731  1.1  jdolecek 		SLIST_INSERT_HEAD(&sc->sc_ccbq_free,
    732  1.1  jdolecek 		    &sc->sc_ccb[i], c_link);
    733  1.1  jdolecek 
    734  1.1  jdolecek 	/* Install interrupt handler */
    735  1.1  jdolecek 	if (pci_intr_map(pa, &ih)) {
    736  1.1  jdolecek 		printf(": can't map interrupt\n");
    737  1.1  jdolecek 		goto fail5;
    738  1.1  jdolecek 	}
    739  1.1  jdolecek 	intrstr = pci_intr_string(pa->pa_pc, ih, intrbuf, sizeof(intrbuf));
    740  1.1  jdolecek 	if (pci_intr_establish_xname(pa->pa_pc, ih, IPL_BIO, ips_intr, sc,
    741  1.1  jdolecek 	    sc->sc_dev.dv_xname) == NULL) {
    742  1.1  jdolecek 		printf(": can't establish interrupt");
    743  1.1  jdolecek 		if (intrstr != NULL)
    744  1.1  jdolecek 			printf(" at %s", intrstr);
    745  1.1  jdolecek 		printf("\n");
    746  1.1  jdolecek 		goto fail5;
    747  1.1  jdolecek 	}
    748  1.1  jdolecek 	printf(": %s\n", intrstr);
    749  1.1  jdolecek 
    750  1.1  jdolecek 	/* Display adapter info */
    751  1.1  jdolecek 	printf("%s: ServeRAID", sc->sc_dev.dv_xname);
    752  1.1  jdolecek 	type = htole16(pg5->type);
    753  1.1  jdolecek 	if (type < sizeof(ips_names) / sizeof(ips_names[0]) && ips_names[type])
    754  1.1  jdolecek 		printf(" %s", ips_names[type]);
    755  1.1  jdolecek 	printf(", FW %c%c%c%c%c%c%c", ai->firmware[0], ai->firmware[1],
    756  1.1  jdolecek 	    ai->firmware[2], ai->firmware[3], ai->firmware[4], ai->firmware[5],
    757  1.1  jdolecek 	    ai->firmware[6]);
    758  1.1  jdolecek 	printf(", BIOS %c%c%c%c%c%c%c", ai->bios[0], ai->bios[1], ai->bios[2],
    759  1.1  jdolecek 	    ai->bios[3], ai->bios[4], ai->bios[5], ai->bios[6]);
    760  1.1  jdolecek 	printf(", %d cmds, %d LD%s", sc->sc_nccbs, sc->sc_nunits,
    761  1.1  jdolecek 	    (sc->sc_nunits == 1 ? "" : "s"));
    762  1.1  jdolecek 	printf("\n");
    763  1.1  jdolecek 
    764  1.1  jdolecek 	/*
    765  1.1  jdolecek 	 * Attach to scsipi.
    766  1.1  jdolecek 	 */
    767  1.1  jdolecek 	adapt = &sc->sc_adapt;
    768  1.1  jdolecek 	memset(adapt, 0, sizeof(*adapt));
    769  1.1  jdolecek 	adapt->adapt_dev = self;
    770  1.1  jdolecek 	adapt->adapt_nchannels = IPS_MAXCHANS;
    771  1.1  jdolecek 	if (sc->sc_nunits > 0)
    772  1.1  jdolecek 		adapt->adapt_openings = sc->sc_nccbs / sc->sc_nunits;
    773  1.1  jdolecek 	adapt->adapt_max_periph = adapt->adapt_openings;
    774  1.1  jdolecek 	adapt->adapt_request = ips_scsipi_request;
    775  1.1  jdolecek 	adapt->adapt_minphys = minphys;
    776  1.1  jdolecek 	adapt->adapt_ioctl = ips_scsi_ioctl;
    777  1.1  jdolecek 
    778  1.1  jdolecek 	/* For each channel attach SCSI pass-through bus */
    779  1.1  jdolecek 	for (i = 0; i < IPS_MAXCHANS; i++) {
    780  1.1  jdolecek 		struct ips_pt *pt;
    781  1.1  jdolecek 		int target, lastarget;
    782  1.1  jdolecek 
    783  1.1  jdolecek 		pt = &sc->sc_pt[i];
    784  1.1  jdolecek 		pt->pt_sc = sc;
    785  1.1  jdolecek 		pt->pt_nchan = i;
    786  1.1  jdolecek 		pt->pt_proctgt = -1;
    787  1.1  jdolecek 
    788  1.1  jdolecek 		/* Check if channel has any devices besides disks */
    789  1.1  jdolecek 		for (target = 0, lastarget = -1; target < IPS_MAXTARGETS;
    790  1.1  jdolecek 		    target++) {
    791  1.1  jdolecek 			struct ips_dev *idev;
    792  1.1  jdolecek 			int dev_type;
    793  1.1  jdolecek 
    794  1.1  jdolecek 			idev = &sc->sc_info->conf.dev[i][target];
    795  1.1  jdolecek 			dev_type = idev->params & SID_TYPE;
    796  1.1  jdolecek 			if (idev->state && dev_type != T_DIRECT) {
    797  1.1  jdolecek 				lastarget = target;
    798  1.1  jdolecek 				if (type == T_PROCESSOR ||
    799  1.1  jdolecek 				    type == T_ENCLOSURE)
    800  1.1  jdolecek 					/* remember enclosure address */
    801  1.1  jdolecek 					pt->pt_proctgt = target;
    802  1.1  jdolecek 			}
    803  1.1  jdolecek 		}
    804  1.1  jdolecek 		if (lastarget == -1)
    805  1.1  jdolecek 			continue;
    806  1.1  jdolecek 
    807  1.1  jdolecek 		chan = &pt->pt_chan;
    808  1.1  jdolecek 		memset(chan, 0, sizeof(*chan));
    809  1.1  jdolecek 		chan->chan_adapter = adapt;
    810  1.1  jdolecek 		chan->chan_bustype = &scsi_bustype;
    811  1.1  jdolecek 		chan->chan_channel = i;
    812  1.1  jdolecek 		chan->chan_ntargets = IPS_MAXTARGETS;
    813  1.1  jdolecek 		chan->chan_nluns = lastarget + 1;
    814  1.1  jdolecek 		chan->chan_id = i;
    815  1.1  jdolecek 		chan->chan_flags = SCSIPI_CHAN_NOSETTLE;
    816  1.4   thorpej 		config_found(self, chan, scsiprint, CFARGS_NONE);
    817  1.1  jdolecek 	}
    818  1.1  jdolecek 
    819  1.1  jdolecek 	/* Enable interrupts */
    820  1.1  jdolecek 	ips_intren(sc);
    821  1.1  jdolecek 
    822  1.1  jdolecek #if NBIO > 0
    823  1.1  jdolecek 	/* Install ioctl handler */
    824  1.1  jdolecek 	if (bio_register(&sc->sc_dev, ips_ioctl))
    825  1.1  jdolecek 		printf("%s: no ioctl support\n", sc->sc_dev.dv_xname);
    826  1.1  jdolecek #endif
    827  1.1  jdolecek 
    828  1.1  jdolecek 	return;
    829  1.1  jdolecek fail5:
    830  1.1  jdolecek 	ips_ccb_free(sc, sc->sc_ccb, sc->sc_nccbs);
    831  1.1  jdolecek fail4:
    832  1.1  jdolecek 	if (sc->sc_chip->ic_id == IPS_CHIP_COPPERHEAD)
    833  1.1  jdolecek 		ips_dmamem_free(&sc->sc_sqm);
    834  1.1  jdolecek fail3:
    835  1.1  jdolecek 	ips_dmamem_free(&sc->sc_infom);
    836  1.1  jdolecek fail2:
    837  1.1  jdolecek 	ips_dmamem_free(&sc->sc_cmdbm);
    838  1.1  jdolecek fail1:
    839  1.1  jdolecek 	bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize);
    840  1.1  jdolecek }
    841  1.1  jdolecek 
    842  1.1  jdolecek void
    843  1.1  jdolecek ips_scsi_cmd(struct ips_ccb *ccb)
    844  1.1  jdolecek {
    845  1.1  jdolecek 	struct scsipi_xfer *xs = ccb->c_xfer;
    846  1.1  jdolecek 	struct scsipi_periph *periph = xs->xs_periph;
    847  1.1  jdolecek 	struct scsipi_channel *chan = periph->periph_channel;
    848  1.1  jdolecek 	struct ips_softc *sc = device_private(chan->chan_adapter->adapt_dev);
    849  1.1  jdolecek 	struct ips_driveinfo *di = &sc->sc_info->drive;
    850  1.1  jdolecek 	struct ips_drive *drive;
    851  1.1  jdolecek 	struct ips_cmd *cmd;
    852  1.1  jdolecek 	int target = periph->periph_target;
    853  1.1  jdolecek 	u_int32_t blkno, blkcnt;
    854  1.1  jdolecek 	int code;
    855  1.1  jdolecek 
    856  1.1  jdolecek 	DPRINTF(IPS_D_XFER, ("%s: ips_scsi_cmd: xs %p, target %d, "
    857  1.1  jdolecek 	    "opcode 0x%02x, flags 0x%x\n", sc->sc_dev.dv_xname, xs, target,
    858  1.1  jdolecek 	    xs->cmd->opcode, xs->xs_control));
    859  1.1  jdolecek 
    860  1.1  jdolecek 	if (target >= sc->sc_nunits || periph->periph_lun != 0) {
    861  1.1  jdolecek 		DPRINTF(IPS_D_INFO, ("%s: ips_scsi_cmd: invalid params "
    862  1.1  jdolecek 		    "target %d, lun %d\n", sc->sc_dev.dv_xname,
    863  1.1  jdolecek 		    target, periph->periph_lun));
    864  1.1  jdolecek 		xs->error = XS_DRIVER_STUFFUP;
    865  1.1  jdolecek 		ips_ccb_put(sc, ccb);
    866  1.1  jdolecek 		scsipi_done(xs);
    867  1.1  jdolecek 		return;
    868  1.1  jdolecek 	}
    869  1.1  jdolecek 
    870  1.1  jdolecek 	drive = &di->drive[target];
    871  1.1  jdolecek 	xs->error = XS_NOERROR;
    872  1.1  jdolecek 
    873  1.1  jdolecek 	/* Fake SCSI commands */
    874  1.1  jdolecek 	switch (xs->cmd->opcode) {
    875  1.1  jdolecek 	case READ_10:
    876  1.1  jdolecek 	case SCSI_READ_6_COMMAND:
    877  1.1  jdolecek 	case WRITE_10:
    878  1.1  jdolecek 	case SCSI_WRITE_6_COMMAND: {
    879  1.1  jdolecek 		struct scsi_rw_6 *rw;
    880  1.1  jdolecek 		struct scsipi_rw_10 *rwb;
    881  1.1  jdolecek 
    882  1.1  jdolecek 		if (xs->cmdlen == sizeof(struct scsi_rw_6)) {
    883  1.1  jdolecek 			rw = (void *)xs->cmd;
    884  1.1  jdolecek 			blkno = _3btol(rw->addr) &
    885  1.1  jdolecek 			    (SRW_TOPADDR << 16 | 0xffff);
    886  1.1  jdolecek 			blkcnt = rw->length ? rw->length : 0x100;
    887  1.1  jdolecek 		} else {
    888  1.1  jdolecek 			rwb = (void *)xs->cmd;
    889  1.1  jdolecek 			blkno = _4btol(rwb->addr);
    890  1.1  jdolecek 			blkcnt = _2btol(rwb->length);
    891  1.1  jdolecek 		}
    892  1.1  jdolecek 
    893  1.1  jdolecek 		if (blkno >= htole32(drive->seccnt) || blkno + blkcnt >
    894  1.1  jdolecek 		    htole32(drive->seccnt)) {
    895  1.1  jdolecek 			DPRINTF(IPS_D_ERR, ("%s: ips_scsi_cmd: invalid params "
    896  1.1  jdolecek 			    "blkno %u, blkcnt %u\n", sc->sc_dev.dv_xname,
    897  1.1  jdolecek 			    blkno, blkcnt));
    898  1.1  jdolecek 			xs->error = XS_DRIVER_STUFFUP;
    899  1.1  jdolecek 			break;
    900  1.1  jdolecek 		}
    901  1.1  jdolecek 
    902  1.1  jdolecek 		if (xs->xs_control & XS_CTL_DATA_IN)
    903  1.1  jdolecek 			code = IPS_CMD_READ;
    904  1.1  jdolecek 		else
    905  1.1  jdolecek 			code = IPS_CMD_WRITE;
    906  1.1  jdolecek 
    907  1.1  jdolecek 		cmd = ccb->c_cmdbva;
    908  1.1  jdolecek 		cmd->code = code;
    909  1.1  jdolecek 		cmd->drive = target;
    910  1.1  jdolecek 		cmd->lba = htole32(blkno);
    911  1.1  jdolecek 		cmd->seccnt = htole16(blkcnt);
    912  1.1  jdolecek 
    913  1.1  jdolecek 		if (ips_load_xs(sc, ccb, xs)) {
    914  1.1  jdolecek 			DPRINTF(IPS_D_ERR, ("%s: ips_scsi_cmd: ips_load_xs "
    915  1.1  jdolecek 			    "failed\n", sc->sc_dev.dv_xname));
    916  1.1  jdolecek 			xs->error = XS_DRIVER_STUFFUP;
    917  1.1  jdolecek 			ips_ccb_put(sc, ccb);
    918  1.1  jdolecek 			scsipi_done(xs);
    919  1.1  jdolecek 			return;
    920  1.1  jdolecek 		}
    921  1.1  jdolecek 
    922  1.1  jdolecek 		if (cmd->sgcnt > 0)
    923  1.1  jdolecek 			cmd->code |= IPS_CMD_SG;
    924  1.1  jdolecek 
    925  1.1  jdolecek 		ccb->c_done = ips_done_xs;
    926  1.1  jdolecek 		ips_start_xs(sc, ccb, xs);
    927  1.1  jdolecek 		return;
    928  1.1  jdolecek 	}
    929  1.1  jdolecek 	case INQUIRY: {
    930  1.1  jdolecek 		struct scsipi_inquiry_data inq;
    931  1.1  jdolecek 
    932  1.1  jdolecek 		bzero(&inq, sizeof(inq));
    933  1.1  jdolecek 		inq.device = T_DIRECT;
    934  1.1  jdolecek 		inq.version = 2;
    935  1.1  jdolecek 		inq.response_format = 2;
    936  1.1  jdolecek 		inq.additional_length = 32;
    937  1.1  jdolecek 		inq.flags3 |= SID_CmdQue;
    938  1.1  jdolecek 		strlcpy(inq.vendor, "IBM", sizeof(inq.vendor));
    939  1.1  jdolecek 		snprintf(inq.product, sizeof(inq.product),
    940  1.1  jdolecek 		    "LD%d RAID%d", target, drive->raid);
    941  1.1  jdolecek 		strlcpy(inq.revision, "1.0", sizeof(inq.revision));
    942  1.1  jdolecek 		memcpy(xs->data, &inq, MIN(xs->datalen, sizeof(inq)));
    943  1.1  jdolecek 		break;
    944  1.1  jdolecek 	}
    945  1.1  jdolecek 	case READ_CAPACITY_10: {
    946  1.1  jdolecek 		struct scsipi_read_capacity_10_data rcd;
    947  1.1  jdolecek 
    948  1.1  jdolecek 		bzero(&rcd, sizeof(rcd));
    949  1.1  jdolecek 		_lto4b(htole32(drive->seccnt) - 1, rcd.addr);
    950  1.1  jdolecek 		_lto4b(IPS_SECSZ, rcd.length);
    951  1.1  jdolecek 		memcpy(xs->data, &rcd, MIN(xs->datalen, sizeof(rcd)));
    952  1.1  jdolecek 		break;
    953  1.1  jdolecek 	}
    954  1.1  jdolecek 	case SCSI_REQUEST_SENSE: {
    955  1.1  jdolecek 		struct scsi_sense_data sd;
    956  1.1  jdolecek 
    957  1.1  jdolecek 		bzero(&sd, sizeof(sd));
    958  1.1  jdolecek 		sd.response_code = SSD_RCODE_CURRENT;
    959  1.1  jdolecek 		sd.flags = SKEY_NO_SENSE;
    960  1.1  jdolecek 		memcpy(xs->data, &sd, MIN(xs->datalen, sizeof(sd)));
    961  1.1  jdolecek 		break;
    962  1.1  jdolecek 	}
    963  1.1  jdolecek 	case SCSI_SYNCHRONIZE_CACHE_10:
    964  1.1  jdolecek 		cmd = ccb->c_cmdbva;
    965  1.1  jdolecek 		cmd->code = IPS_CMD_FLUSH;
    966  1.1  jdolecek 
    967  1.1  jdolecek 		ccb->c_done = ips_done_xs;
    968  1.1  jdolecek 		ips_start_xs(sc, ccb, xs);
    969  1.1  jdolecek 		return;
    970  1.1  jdolecek 	case SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL:
    971  1.1  jdolecek 	case START_STOP:
    972  1.1  jdolecek 	case SCSI_TEST_UNIT_READY:
    973  1.1  jdolecek 		break;
    974  1.1  jdolecek 	default:
    975  1.1  jdolecek 		DPRINTF(IPS_D_INFO, ("%s: unsupported scsi command 0x%02x\n",
    976  1.1  jdolecek 		    sc->sc_dev.dv_xname, xs->cmd->opcode));
    977  1.1  jdolecek 		xs->error = XS_DRIVER_STUFFUP;
    978  1.1  jdolecek 	}
    979  1.1  jdolecek 
    980  1.1  jdolecek 	ips_ccb_put(sc, ccb);
    981  1.1  jdolecek 	scsipi_done(xs);
    982  1.1  jdolecek }
    983  1.1  jdolecek 
    984  1.1  jdolecek /*
    985  1.1  jdolecek  * Start a SCSI command.
    986  1.1  jdolecek  */
    987  1.1  jdolecek static void
    988  1.1  jdolecek ips_scsipi_request(struct scsipi_channel *chan, scsipi_adapter_req_t req,
    989  1.1  jdolecek 		   void *arg)
    990  1.1  jdolecek {
    991  1.1  jdolecek 	switch (req) {
    992  1.1  jdolecek 	case ADAPTER_REQ_RUN_XFER: {
    993  1.1  jdolecek 		struct ips_ccb *ccb;
    994  1.1  jdolecek 		struct scsipi_xfer *xs;
    995  1.1  jdolecek 		struct ips_softc *sc;
    996  1.1  jdolecek 
    997  1.1  jdolecek 		sc = device_private(chan->chan_adapter->adapt_dev);
    998  1.1  jdolecek 		xs = (struct scsipi_xfer *)arg;
    999  1.1  jdolecek 
   1000  1.1  jdolecek 		if ((ccb = ips_ccb_get(sc)) == NULL) {
   1001  1.1  jdolecek 			xs->error = XS_RESOURCE_SHORTAGE;
   1002  1.1  jdolecek 			scsipi_done(xs);
   1003  1.1  jdolecek 			break;
   1004  1.1  jdolecek 		}
   1005  1.1  jdolecek 
   1006  1.1  jdolecek 		ccb->c_xfer = xs;
   1007  1.1  jdolecek 		ips_scsi_cmd(ccb);
   1008  1.1  jdolecek 
   1009  1.1  jdolecek 		break;
   1010  1.1  jdolecek 	}
   1011  1.1  jdolecek 
   1012  1.1  jdolecek 	case ADAPTER_REQ_SET_XFER_MODE: {
   1013  1.1  jdolecek 		struct scsipi_xfer_mode *xm = arg;
   1014  1.1  jdolecek 		xm->xm_mode = PERIPH_CAP_TQING;
   1015  1.1  jdolecek 		xm->xm_period = 0;
   1016  1.1  jdolecek 		xm->xm_offset = 0;
   1017  1.1  jdolecek 		scsipi_async_event(chan, ASYNC_EVENT_XFER_MODE, xm);
   1018  1.1  jdolecek 		return;
   1019  1.1  jdolecek 	}
   1020  1.1  jdolecek 
   1021  1.1  jdolecek 	case ADAPTER_REQ_GROW_RESOURCES:
   1022  1.1  jdolecek 		/*
   1023  1.1  jdolecek 		 * Not supported.
   1024  1.1  jdolecek 		 */
   1025  1.1  jdolecek 		break;
   1026  1.1  jdolecek 	}
   1027  1.1  jdolecek }
   1028  1.1  jdolecek 
   1029  1.1  jdolecek int
   1030  1.1  jdolecek ips_scsi_ioctl(struct scsipi_channel *chan, u_long cmd, void *data,
   1031  1.1  jdolecek     int flag, struct proc *p)
   1032  1.1  jdolecek {
   1033  1.1  jdolecek #if NBIO > 0
   1034  1.1  jdolecek 	return (ips_ioctl(chan->chan_adapter->adapt_dev, cmd, data));
   1035  1.1  jdolecek #else
   1036  1.1  jdolecek 	return (ENOTTY);
   1037  1.1  jdolecek #endif
   1038  1.1  jdolecek }
   1039  1.1  jdolecek 
   1040  1.1  jdolecek #if NBIO > 0
   1041  1.1  jdolecek int
   1042  1.1  jdolecek ips_ioctl(device_t dev, u_long cmd, void *data)
   1043  1.1  jdolecek {
   1044  1.1  jdolecek 	struct ips_softc *sc = (struct ips_softc *)dev;
   1045  1.1  jdolecek 
   1046  1.1  jdolecek 	DPRINTF(IPS_D_INFO, ("%s: ips_ioctl: cmd %lu\n",
   1047  1.1  jdolecek 	    sc->sc_dev.dv_xname, cmd));
   1048  1.1  jdolecek 
   1049  1.1  jdolecek 	switch (cmd) {
   1050  1.1  jdolecek 	case BIOCINQ:
   1051  1.1  jdolecek 		return (ips_ioctl_inq(sc, (struct bioc_inq *)data));
   1052  1.1  jdolecek 	case BIOCVOL:
   1053  1.1  jdolecek 		return (ips_ioctl_vol(sc, (struct bioc_vol *)data));
   1054  1.1  jdolecek 	case BIOCDISK:
   1055  1.1  jdolecek 		return (ips_ioctl_disk(sc, (struct bioc_disk *)data));
   1056  1.1  jdolecek 	case BIOCSETSTATE:
   1057  1.1  jdolecek 		return (ips_ioctl_setstate(sc, (struct bioc_setstate *)data));
   1058  1.1  jdolecek 	default:
   1059  1.1  jdolecek 		return (ENOTTY);
   1060  1.1  jdolecek 	}
   1061  1.1  jdolecek }
   1062  1.1  jdolecek 
   1063  1.1  jdolecek int
   1064  1.1  jdolecek ips_ioctl_inq(struct ips_softc *sc, struct bioc_inq *bi)
   1065  1.1  jdolecek {
   1066  1.1  jdolecek 	struct ips_conf *conf = &sc->sc_info->conf;
   1067  1.1  jdolecek 	int i;
   1068  1.1  jdolecek 
   1069  1.1  jdolecek 	strlcpy(bi->bi_dev, sc->sc_dev.dv_xname, sizeof(bi->bi_dev));
   1070  1.1  jdolecek 	bi->bi_novol = sc->sc_nunits;
   1071  1.1  jdolecek 	for (i = 0, bi->bi_nodisk = 0; i < sc->sc_nunits; i++)
   1072  1.1  jdolecek 		bi->bi_nodisk += conf->ld[i].chunkcnt;
   1073  1.1  jdolecek 
   1074  1.1  jdolecek 	DPRINTF(IPS_D_INFO, ("%s: ips_ioctl_inq: novol %d, nodisk %d\n",
   1075  1.1  jdolecek 	    bi->bi_dev, bi->bi_novol, bi->bi_nodisk));
   1076  1.1  jdolecek 
   1077  1.1  jdolecek 	return (0);
   1078  1.1  jdolecek }
   1079  1.1  jdolecek 
   1080  1.1  jdolecek int
   1081  1.1  jdolecek ips_ioctl_vol(struct ips_softc *sc, struct bioc_vol *bv)
   1082  1.1  jdolecek {
   1083  1.1  jdolecek 	struct ips_driveinfo *di = &sc->sc_info->drive;
   1084  1.1  jdolecek 	struct ips_conf *conf = &sc->sc_info->conf;
   1085  1.1  jdolecek 	struct ips_rblstat *rblstat = &sc->sc_info->rblstat;
   1086  1.1  jdolecek 	struct ips_ld *ld;
   1087  1.1  jdolecek 	int vid = bv->bv_volid;
   1088  1.1  jdolecek 	struct device *dv;
   1089  1.1  jdolecek 	int error, rebuild = 0;
   1090  1.1  jdolecek 	u_int32_t total = 0, done = 0;
   1091  1.1  jdolecek 
   1092  1.1  jdolecek 	if (vid >= sc->sc_nunits)
   1093  1.1  jdolecek 		return (EINVAL);
   1094  1.1  jdolecek 	if ((error = ips_getconf(sc, 0)))
   1095  1.1  jdolecek 		return (error);
   1096  1.1  jdolecek 	ld = &conf->ld[vid];
   1097  1.1  jdolecek 
   1098  1.1  jdolecek 	switch (ld->state) {
   1099  1.1  jdolecek 	case IPS_DS_ONLINE:
   1100  1.1  jdolecek 		bv->bv_status = BIOC_SVONLINE;
   1101  1.1  jdolecek 		break;
   1102  1.1  jdolecek 	case IPS_DS_DEGRADED:
   1103  1.1  jdolecek 		bv->bv_status = BIOC_SVDEGRADED;
   1104  1.1  jdolecek 		rebuild++;
   1105  1.1  jdolecek 		break;
   1106  1.1  jdolecek 	case IPS_DS_OFFLINE:
   1107  1.1  jdolecek 		bv->bv_status = BIOC_SVOFFLINE;
   1108  1.1  jdolecek 		break;
   1109  1.1  jdolecek 	default:
   1110  1.1  jdolecek 		bv->bv_status = BIOC_SVINVALID;
   1111  1.1  jdolecek 	}
   1112  1.1  jdolecek 
   1113  1.1  jdolecek 	if (rebuild && ips_getrblstat(sc, 0) == 0) {
   1114  1.1  jdolecek 		total = htole32(rblstat->ld[vid].total);
   1115  1.1  jdolecek 		done = total - htole32(rblstat->ld[vid].remain);
   1116  1.1  jdolecek 		if (total && total > done) {
   1117  1.1  jdolecek 			bv->bv_status = BIOC_SVREBUILD;
   1118  1.1  jdolecek 			bv->bv_percent = 100 * done / total;
   1119  1.1  jdolecek 		}
   1120  1.1  jdolecek 	}
   1121  1.1  jdolecek 
   1122  1.1  jdolecek 	bv->bv_size = (uint64_t)htole32(ld->size) * IPS_SECSZ;
   1123  1.1  jdolecek 	bv->bv_level = di->drive[vid].raid;
   1124  1.1  jdolecek 	bv->bv_nodisk = ld->chunkcnt;
   1125  1.1  jdolecek 
   1126  1.1  jdolecek 	/* Associate all unused and spare drives with first volume */
   1127  1.1  jdolecek 	if (vid == 0) {
   1128  1.1  jdolecek 		struct ips_dev *dev;
   1129  1.1  jdolecek 		int chan, target;
   1130  1.1  jdolecek 
   1131  1.1  jdolecek 		for (chan = 0; chan < IPS_MAXCHANS; chan++)
   1132  1.1  jdolecek 			for (target = 0; target < IPS_MAXTARGETS; target++) {
   1133  1.1  jdolecek 				dev = &conf->dev[chan][target];
   1134  1.1  jdolecek 				if (dev->state && !(dev->state &
   1135  1.1  jdolecek 				    IPS_DVS_MEMBER) &&
   1136  1.1  jdolecek 				    (dev->params & SID_TYPE) == T_DIRECT)
   1137  1.1  jdolecek 					bv->bv_nodisk++;
   1138  1.1  jdolecek 			}
   1139  1.1  jdolecek 	}
   1140  1.1  jdolecek 
   1141  1.1  jdolecek 	dv = &sc->sc_dev;
   1142  1.1  jdolecek 	strlcpy(bv->bv_dev, dv->dv_xname, sizeof(bv->bv_dev));
   1143  1.1  jdolecek 	strlcpy(bv->bv_vendor, "IBM", sizeof(bv->bv_vendor));
   1144  1.1  jdolecek 
   1145  1.1  jdolecek 	DPRINTF(IPS_D_INFO, ("%s: ips_ioctl_vol: vid %d, state 0x%02x, "
   1146  1.1  jdolecek 	    "total %u, done %u, size %llu, level %d, nodisk %d, dev %s\n",
   1147  1.1  jdolecek 	    sc->sc_dev.dv_xname, vid, ld->state, total, done, bv->bv_size,
   1148  1.1  jdolecek 	    bv->bv_level, bv->bv_nodisk, bv->bv_dev));
   1149  1.1  jdolecek 
   1150  1.1  jdolecek 	return (0);
   1151  1.1  jdolecek }
   1152  1.1  jdolecek 
   1153  1.1  jdolecek int
   1154  1.1  jdolecek ips_ioctl_disk(struct ips_softc *sc, struct bioc_disk *bd)
   1155  1.1  jdolecek {
   1156  1.1  jdolecek 	struct ips_conf *conf = &sc->sc_info->conf;
   1157  1.1  jdolecek 	struct ips_ld *ld;
   1158  1.1  jdolecek 	struct ips_chunk *chunk;
   1159  1.1  jdolecek 	struct ips_dev *dev;
   1160  1.1  jdolecek 	int vid = bd->bd_volid, did = bd->bd_diskid;
   1161  1.1  jdolecek 	int chan, target, error, i;
   1162  1.1  jdolecek 
   1163  1.1  jdolecek 	if (vid >= sc->sc_nunits)
   1164  1.1  jdolecek 		return (EINVAL);
   1165  1.1  jdolecek 	if ((error = ips_getconf(sc, 0)))
   1166  1.1  jdolecek 		return (error);
   1167  1.1  jdolecek 	ld = &conf->ld[vid];
   1168  1.1  jdolecek 
   1169  1.1  jdolecek 	if (did >= ld->chunkcnt) {
   1170  1.1  jdolecek 		/* Probably unused or spare drives */
   1171  1.1  jdolecek 		if (vid != 0)
   1172  1.1  jdolecek 			return (EINVAL);
   1173  1.1  jdolecek 
   1174  1.1  jdolecek 		i = ld->chunkcnt;
   1175  1.1  jdolecek 		for (chan = 0; chan < IPS_MAXCHANS; chan++)
   1176  1.1  jdolecek 			for (target = 0; target < IPS_MAXTARGETS; target++) {
   1177  1.1  jdolecek 				dev = &conf->dev[chan][target];
   1178  1.1  jdolecek 				if (dev->state && !(dev->state &
   1179  1.1  jdolecek 				    IPS_DVS_MEMBER) &&
   1180  1.1  jdolecek 				    (dev->params & SID_TYPE) == T_DIRECT)
   1181  1.1  jdolecek 					if (i++ == did)
   1182  1.1  jdolecek 						goto out;
   1183  1.1  jdolecek 			}
   1184  1.1  jdolecek 	} else {
   1185  1.1  jdolecek 		chunk = &ld->chunk[did];
   1186  1.1  jdolecek 		chan = chunk->channel;
   1187  1.1  jdolecek 		target = chunk->target;
   1188  1.1  jdolecek 	}
   1189  1.1  jdolecek 
   1190  1.1  jdolecek out:
   1191  1.1  jdolecek 	if (chan >= IPS_MAXCHANS || target >= IPS_MAXTARGETS)
   1192  1.1  jdolecek 		return (EINVAL);
   1193  1.1  jdolecek 	dev = &conf->dev[chan][target];
   1194  1.1  jdolecek 
   1195  1.1  jdolecek 	bd->bd_channel = chan;
   1196  1.1  jdolecek 	bd->bd_target = target;
   1197  1.1  jdolecek 	bd->bd_lun = 0;
   1198  1.1  jdolecek 	bd->bd_size = (uint64_t)htole32(dev->seccnt) * IPS_SECSZ;
   1199  1.1  jdolecek 
   1200  1.1  jdolecek 	bzero(bd->bd_vendor, sizeof(bd->bd_vendor));
   1201  1.1  jdolecek 	memcpy(bd->bd_vendor, dev->devid, MIN(sizeof(bd->bd_vendor),
   1202  1.1  jdolecek 	    sizeof(dev->devid)));
   1203  1.1  jdolecek 	strlcpy(bd->bd_procdev, sc->sc_pt[chan].pt_procdev,
   1204  1.1  jdolecek 	    sizeof(bd->bd_procdev));
   1205  1.1  jdolecek 
   1206  1.1  jdolecek 	if (dev->state & IPS_DVS_READY) {
   1207  1.1  jdolecek 		bd->bd_status = BIOC_SDUNUSED;
   1208  1.1  jdolecek 		if (dev->state & IPS_DVS_MEMBER)
   1209  1.1  jdolecek 			bd->bd_status = BIOC_SDONLINE;
   1210  1.1  jdolecek 		if (dev->state & IPS_DVS_SPARE)
   1211  1.1  jdolecek 			bd->bd_status = BIOC_SDHOTSPARE;
   1212  1.1  jdolecek 		if (dev->state & IPS_DVS_REBUILD)
   1213  1.1  jdolecek 			bd->bd_status = BIOC_SDREBUILD;
   1214  1.1  jdolecek 	} else {
   1215  1.1  jdolecek 		bd->bd_status = BIOC_SDOFFLINE;
   1216  1.1  jdolecek 	}
   1217  1.1  jdolecek 
   1218  1.1  jdolecek 	DPRINTF(IPS_D_INFO, ("%s: ips_ioctl_disk: vid %d, did %d, channel %d, "
   1219  1.1  jdolecek 	    "target %d, size %llu, state 0x%02x\n", sc->sc_dev.dv_xname,
   1220  1.1  jdolecek 	    vid, did, bd->bd_channel, bd->bd_target, bd->bd_size, dev->state));
   1221  1.1  jdolecek 
   1222  1.1  jdolecek 	return (0);
   1223  1.1  jdolecek }
   1224  1.1  jdolecek 
   1225  1.1  jdolecek int
   1226  1.1  jdolecek ips_ioctl_setstate(struct ips_softc *sc, struct bioc_setstate *bs)
   1227  1.1  jdolecek {
   1228  1.1  jdolecek 	struct ips_conf *conf = &sc->sc_info->conf;
   1229  1.1  jdolecek 	struct ips_dev *dev;
   1230  1.1  jdolecek 	int state, error;
   1231  1.1  jdolecek 
   1232  1.1  jdolecek 	if (bs->bs_channel >= IPS_MAXCHANS || bs->bs_target >= IPS_MAXTARGETS)
   1233  1.1  jdolecek 		return (EINVAL);
   1234  1.1  jdolecek 	if ((error = ips_getconf(sc, 0)))
   1235  1.1  jdolecek 		return (error);
   1236  1.1  jdolecek 	dev = &conf->dev[bs->bs_channel][bs->bs_target];
   1237  1.1  jdolecek 	state = dev->state;
   1238  1.1  jdolecek 
   1239  1.1  jdolecek 	switch (bs->bs_status) {
   1240  1.1  jdolecek 	case BIOC_SSONLINE:
   1241  1.1  jdolecek 		state |= IPS_DVS_READY;
   1242  1.1  jdolecek 		break;
   1243  1.1  jdolecek 	case BIOC_SSOFFLINE:
   1244  1.1  jdolecek 		state &= ~IPS_DVS_READY;
   1245  1.1  jdolecek 		break;
   1246  1.1  jdolecek 	case BIOC_SSHOTSPARE:
   1247  1.1  jdolecek 		state |= IPS_DVS_SPARE;
   1248  1.1  jdolecek 		break;
   1249  1.1  jdolecek 	case BIOC_SSREBUILD:
   1250  1.1  jdolecek 		return (ips_rebuild(sc, bs->bs_channel, bs->bs_target,
   1251  1.1  jdolecek 		    bs->bs_channel, bs->bs_target, 0));
   1252  1.1  jdolecek 	default:
   1253  1.1  jdolecek 		return (EINVAL);
   1254  1.1  jdolecek 	}
   1255  1.1  jdolecek 
   1256  1.1  jdolecek 	return (ips_setstate(sc, bs->bs_channel, bs->bs_target, state, 0));
   1257  1.1  jdolecek }
   1258  1.1  jdolecek #endif	/* NBIO > 0 */
   1259  1.1  jdolecek 
   1260  1.1  jdolecek int
   1261  1.1  jdolecek ips_load_xs(struct ips_softc *sc, struct ips_ccb *ccb, struct scsipi_xfer *xs)
   1262  1.1  jdolecek {
   1263  1.1  jdolecek 	struct ips_cmdb *cmdb = ccb->c_cmdbva;
   1264  1.1  jdolecek 	struct ips_cmd *cmd = &cmdb->cmd;
   1265  1.1  jdolecek 	struct ips_sg *sg = cmdb->sg;
   1266  1.1  jdolecek 	int nsegs, i;
   1267  1.1  jdolecek 
   1268  1.1  jdolecek 	if (xs->datalen == 0)
   1269  1.1  jdolecek 		return (0);
   1270  1.1  jdolecek 
   1271  1.1  jdolecek 	/* Map data buffer into DMA segments */
   1272  1.1  jdolecek 	if (bus_dmamap_load(sc->sc_dmat, ccb->c_dmam, xs->data, xs->datalen,
   1273  1.1  jdolecek 	    NULL, (xs->xs_control & XS_CTL_NOSLEEP ? BUS_DMA_NOWAIT : 0)))
   1274  1.1  jdolecek 		return (1);
   1275  1.1  jdolecek 	bus_dmamap_sync(sc->sc_dmat, ccb->c_dmam, 0,ccb->c_dmam->dm_mapsize,
   1276  1.1  jdolecek 	    xs->xs_control & XS_CTL_DATA_IN ? BUS_DMASYNC_PREREAD :
   1277  1.1  jdolecek 	    BUS_DMASYNC_PREWRITE);
   1278  1.1  jdolecek 
   1279  1.1  jdolecek 	if ((nsegs = ccb->c_dmam->dm_nsegs) > IPS_MAXSGS)
   1280  1.1  jdolecek 		return (1);
   1281  1.1  jdolecek 
   1282  1.1  jdolecek 	if (nsegs > 1) {
   1283  1.1  jdolecek 		cmd->sgcnt = nsegs;
   1284  1.1  jdolecek 		cmd->sgaddr = htole32(ccb->c_cmdbpa + offsetof(struct ips_cmdb,
   1285  1.1  jdolecek 		    sg));
   1286  1.1  jdolecek 
   1287  1.1  jdolecek 		/* Fill in scatter-gather array */
   1288  1.1  jdolecek 		for (i = 0; i < nsegs; i++) {
   1289  1.1  jdolecek 			sg[i].addr = htole32(ccb->c_dmam->dm_segs[i].ds_addr);
   1290  1.1  jdolecek 			sg[i].size = htole32(ccb->c_dmam->dm_segs[i].ds_len);
   1291  1.1  jdolecek 		}
   1292  1.1  jdolecek 	} else {
   1293  1.1  jdolecek 		cmd->sgcnt = 0;
   1294  1.1  jdolecek 		cmd->sgaddr = htole32(ccb->c_dmam->dm_segs[0].ds_addr);
   1295  1.1  jdolecek 	}
   1296  1.1  jdolecek 
   1297  1.1  jdolecek 	return (0);
   1298  1.1  jdolecek }
   1299  1.1  jdolecek 
   1300  1.1  jdolecek void
   1301  1.1  jdolecek ips_start_xs(struct ips_softc *sc, struct ips_ccb *ccb, struct scsipi_xfer *xs)
   1302  1.1  jdolecek {
   1303  1.1  jdolecek 	ccb->c_flags = xs->xs_control;
   1304  1.1  jdolecek 	ccb->c_xfer = xs;
   1305  1.1  jdolecek 	int ispoll = xs->xs_control & XS_CTL_POLL;
   1306  1.1  jdolecek 
   1307  1.1  jdolecek 	if (!ispoll) {
   1308  1.1  jdolecek 		int timeout = mstohz(xs->timeout);
   1309  1.1  jdolecek 		if (timeout == 0)
   1310  1.1  jdolecek 			timeout = 1;
   1311  1.1  jdolecek 
   1312  1.1  jdolecek 		callout_reset(&xs->xs_callout, timeout, ips_timeout, ccb);
   1313  1.1  jdolecek 	}
   1314  1.1  jdolecek 
   1315  1.1  jdolecek 	/*
   1316  1.1  jdolecek 	 * Return value not used here because ips_cmd() must complete
   1317  1.1  jdolecek 	 * scsipi_xfer on any failure and SCSI layer will handle possible
   1318  1.1  jdolecek 	 * errors.
   1319  1.1  jdolecek 	 */
   1320  1.1  jdolecek 	ips_cmd(sc, ccb);
   1321  1.1  jdolecek }
   1322  1.1  jdolecek 
   1323  1.1  jdolecek int
   1324  1.1  jdolecek ips_cmd(struct ips_softc *sc, struct ips_ccb *ccb)
   1325  1.1  jdolecek {
   1326  1.1  jdolecek 	struct ips_cmd *cmd = ccb->c_cmdbva;
   1327  1.1  jdolecek 	int s, error = 0;
   1328  1.1  jdolecek 
   1329  1.1  jdolecek 	DPRINTF(IPS_D_XFER, ("%s: ips_cmd: id 0x%02x, flags 0x%x, xs %p, "
   1330  1.1  jdolecek 	    "code 0x%02x, drive %d, sgcnt %d, lba %d, sgaddr 0x%08x, "
   1331  1.1  jdolecek 	    "seccnt %d\n", sc->sc_dev.dv_xname, ccb->c_id, ccb->c_flags,
   1332  1.1  jdolecek 	    ccb->c_xfer, cmd->code, cmd->drive, cmd->sgcnt, htole32(cmd->lba),
   1333  1.1  jdolecek 	    htole32(cmd->sgaddr), htole16(cmd->seccnt)));
   1334  1.1  jdolecek 
   1335  1.1  jdolecek 	cmd->id = ccb->c_id;
   1336  1.1  jdolecek 
   1337  1.1  jdolecek 	/* Post command to controller and optionally wait for completion */
   1338  1.1  jdolecek 	s = splbio();
   1339  1.1  jdolecek 	ips_exec(sc, ccb);
   1340  1.1  jdolecek 	ccb->c_state = IPS_CCB_QUEUED;
   1341  1.1  jdolecek 	if (ccb->c_flags & XS_CTL_POLL)
   1342  1.1  jdolecek 		error = ips_poll(sc, ccb);
   1343  1.1  jdolecek 	splx(s);
   1344  1.1  jdolecek 
   1345  1.1  jdolecek 	return (error);
   1346  1.1  jdolecek }
   1347  1.1  jdolecek 
   1348  1.1  jdolecek int
   1349  1.1  jdolecek ips_poll(struct ips_softc *sc, struct ips_ccb *ccb)
   1350  1.1  jdolecek {
   1351  1.1  jdolecek 	struct timeval tv;
   1352  1.1  jdolecek 	int error, timo;
   1353  1.1  jdolecek 
   1354  1.1  jdolecek 	if (ccb->c_flags & XS_CTL_NOSLEEP) {
   1355  1.1  jdolecek 		/* busy-wait */
   1356  1.1  jdolecek 		DPRINTF(IPS_D_XFER, ("%s: ips_poll: busy-wait\n",
   1357  1.1  jdolecek 		    sc->sc_dev.dv_xname));
   1358  1.1  jdolecek 
   1359  1.1  jdolecek 		for (timo = 10000; timo > 0; timo--) {
   1360  1.1  jdolecek 			delay(100);
   1361  1.1  jdolecek 			ips_intr(sc);
   1362  1.1  jdolecek 			if (ccb->c_state == IPS_CCB_DONE)
   1363  1.1  jdolecek 				break;
   1364  1.1  jdolecek 		}
   1365  1.1  jdolecek 	} else {
   1366  1.1  jdolecek 		/* sleep */
   1367  1.1  jdolecek 		timo = ccb->c_xfer ? ccb->c_xfer->timeout : IPS_TIMEOUT;
   1368  1.1  jdolecek 		tv.tv_sec = timo / 1000;
   1369  1.1  jdolecek 		tv.tv_usec = (timo % 1000) * 1000;
   1370  1.1  jdolecek 		timo = tvtohz(&tv);
   1371  1.1  jdolecek 
   1372  1.1  jdolecek 		DPRINTF(IPS_D_XFER, ("%s: ips_poll: sleep %d hz\n",
   1373  1.1  jdolecek 		    sc->sc_dev.dv_xname, timo));
   1374  1.1  jdolecek 		tsleep(ccb, PRIBIO + 1, "ipscmd", timo);
   1375  1.1  jdolecek 	}
   1376  1.1  jdolecek 	DPRINTF(IPS_D_XFER, ("%s: ips_poll: state %d\n", sc->sc_dev.dv_xname,
   1377  1.1  jdolecek 	    ccb->c_state));
   1378  1.1  jdolecek 
   1379  1.1  jdolecek 	if (ccb->c_state != IPS_CCB_DONE)
   1380  1.1  jdolecek 		/*
   1381  1.1  jdolecek 		 * Command never completed. Fake hardware status byte
   1382  1.1  jdolecek 		 * to indicate timeout.
   1383  1.1  jdolecek 		 */
   1384  1.1  jdolecek 		ccb->c_stat = IPS_STAT_TIMO;
   1385  1.1  jdolecek 
   1386  1.1  jdolecek 	ips_done(sc, ccb);
   1387  1.1  jdolecek 	error = ccb->c_error;
   1388  1.1  jdolecek 
   1389  1.1  jdolecek 	return (error);
   1390  1.1  jdolecek }
   1391  1.1  jdolecek 
   1392  1.1  jdolecek void
   1393  1.1  jdolecek ips_done(struct ips_softc *sc, struct ips_ccb *ccb)
   1394  1.1  jdolecek {
   1395  1.1  jdolecek 	DPRINTF(IPS_D_XFER, ("%s: ips_done: id 0x%02x, flags 0x%x, xs %p\n",
   1396  1.1  jdolecek 	    sc->sc_dev.dv_xname, ccb->c_id, ccb->c_flags, ccb->c_xfer));
   1397  1.1  jdolecek 
   1398  1.1  jdolecek 	ccb->c_error = ips_error(sc, ccb);
   1399  1.1  jdolecek 	ccb->c_done(sc, ccb);
   1400  1.1  jdolecek }
   1401  1.1  jdolecek 
   1402  1.1  jdolecek void
   1403  1.1  jdolecek ips_done_xs(struct ips_softc *sc, struct ips_ccb *ccb)
   1404  1.1  jdolecek {
   1405  1.1  jdolecek 	struct scsipi_xfer *xs = ccb->c_xfer;
   1406  1.1  jdolecek 
   1407  1.1  jdolecek 	if (!(xs->xs_control & XS_CTL_POLL))
   1408  1.1  jdolecek 		callout_stop(&xs->xs_callout);
   1409  1.1  jdolecek 
   1410  1.1  jdolecek 	if (xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) {
   1411  1.1  jdolecek 		bus_dmamap_sync(sc->sc_dmat, ccb->c_dmam, 0,
   1412  1.1  jdolecek 		    ccb->c_dmam->dm_mapsize, xs->xs_control & XS_CTL_DATA_IN ?
   1413  1.1  jdolecek 		    BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
   1414  1.1  jdolecek 		bus_dmamap_unload(sc->sc_dmat, ccb->c_dmam);
   1415  1.1  jdolecek 	}
   1416  1.1  jdolecek 
   1417  1.1  jdolecek 	xs->resid = 0;
   1418  1.1  jdolecek 	xs->error = ips_error_xs(sc, ccb);
   1419  1.1  jdolecek 	ips_ccb_put(sc, ccb);
   1420  1.1  jdolecek 	scsipi_done(xs);
   1421  1.1  jdolecek }
   1422  1.1  jdolecek 
   1423  1.1  jdolecek void
   1424  1.1  jdolecek ips_done_pt(struct ips_softc *sc, struct ips_ccb *ccb)
   1425  1.1  jdolecek {
   1426  1.1  jdolecek 	struct scsipi_xfer *xs = ccb->c_xfer;
   1427  1.1  jdolecek 	struct ips_cmdb *cmdb = ccb->c_cmdbva;
   1428  1.1  jdolecek 	struct ips_dcdb *dcdb = &cmdb->dcdb;
   1429  1.1  jdolecek 	int done = htole16(dcdb->datalen);
   1430  1.1  jdolecek 
   1431  1.1  jdolecek 	if (!(xs->xs_control & XS_CTL_POLL))
   1432  1.1  jdolecek 		callout_stop(&xs->xs_callout);
   1433  1.1  jdolecek 
   1434  1.1  jdolecek 	if (xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) {
   1435  1.1  jdolecek 		bus_dmamap_sync(sc->sc_dmat, ccb->c_dmam, 0,
   1436  1.1  jdolecek 		    ccb->c_dmam->dm_mapsize, xs->xs_control & XS_CTL_DATA_IN ?
   1437  1.1  jdolecek 		    BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
   1438  1.1  jdolecek 		bus_dmamap_unload(sc->sc_dmat, ccb->c_dmam);
   1439  1.1  jdolecek 	}
   1440  1.1  jdolecek 
   1441  1.1  jdolecek 	if (done && done < xs->datalen)
   1442  1.1  jdolecek 		xs->resid = xs->datalen - done;
   1443  1.1  jdolecek 	else
   1444  1.1  jdolecek 		xs->resid = 0;
   1445  1.1  jdolecek 	xs->error = ips_error_xs(sc, ccb);
   1446  1.1  jdolecek 	xs->status = dcdb->status;
   1447  1.1  jdolecek 
   1448  1.1  jdolecek 	if (xs->error == XS_SENSE)
   1449  1.1  jdolecek 		memcpy(&xs->sense, dcdb->sense, MIN(sizeof(xs->sense),
   1450  1.1  jdolecek 		    sizeof(dcdb->sense)));
   1451  1.1  jdolecek 
   1452  1.1  jdolecek 	if (xs->cmd->opcode == INQUIRY && xs->error == XS_NOERROR) {
   1453  1.1  jdolecek 		int type = ((struct scsipi_inquiry_data *)xs->data)->device &
   1454  1.1  jdolecek 		    SID_TYPE;
   1455  1.1  jdolecek 
   1456  1.1  jdolecek 		if (type == T_DIRECT)
   1457  1.1  jdolecek 			/* mask physical drives */
   1458  1.1  jdolecek 			xs->error = XS_DRIVER_STUFFUP;
   1459  1.1  jdolecek 	}
   1460  1.1  jdolecek 
   1461  1.1  jdolecek 	ips_ccb_put(sc, ccb);
   1462  1.1  jdolecek 	scsipi_done(xs);
   1463  1.1  jdolecek }
   1464  1.1  jdolecek 
   1465  1.1  jdolecek void
   1466  1.1  jdolecek ips_done_mgmt(struct ips_softc *sc, struct ips_ccb *ccb)
   1467  1.1  jdolecek {
   1468  1.1  jdolecek 	if (ccb->c_flags & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT))
   1469  1.1  jdolecek 		bus_dmamap_sync(sc->sc_dmat, sc->sc_infom.dm_map, 0,
   1470  1.1  jdolecek 		    sc->sc_infom.dm_map->dm_mapsize,
   1471  1.1  jdolecek 		    ccb->c_flags & XS_CTL_DATA_IN ? BUS_DMASYNC_POSTREAD :
   1472  1.1  jdolecek 		    BUS_DMASYNC_POSTWRITE);
   1473  1.1  jdolecek 
   1474  1.1  jdolecek 	ips_ccb_put(sc, ccb);
   1475  1.1  jdolecek }
   1476  1.1  jdolecek 
   1477  1.1  jdolecek int
   1478  1.1  jdolecek ips_error(struct ips_softc *sc, struct ips_ccb *ccb)
   1479  1.1  jdolecek {
   1480  1.1  jdolecek 	struct ips_cmdb *cmdb = ccb->c_cmdbva;
   1481  1.1  jdolecek 	struct ips_cmd *cmd = &cmdb->cmd;
   1482  1.1  jdolecek 	struct ips_dcdb *dcdb = &cmdb->dcdb;
   1483  1.1  jdolecek 	struct scsipi_xfer *xs = ccb->c_xfer;
   1484  1.1  jdolecek 	u_int8_t gsc = IPS_STAT_GSC(ccb->c_stat);
   1485  1.1  jdolecek 
   1486  1.1  jdolecek 	if (gsc == IPS_STAT_OK)
   1487  1.1  jdolecek 		return (0);
   1488  1.1  jdolecek 
   1489  1.1  jdolecek 	DPRINTF(IPS_D_ERR, ("%s: ips_error: stat 0x%02x, estat 0x%02x, "
   1490  1.1  jdolecek 	    "cmd code 0x%02x, drive %d, sgcnt %d, lba %u, seccnt %d",
   1491  1.1  jdolecek 	    sc->sc_dev.dv_xname, ccb->c_stat, ccb->c_estat, cmd->code,
   1492  1.1  jdolecek 	    cmd->drive, cmd->sgcnt, htole32(cmd->lba), htole16(cmd->seccnt)));
   1493  1.1  jdolecek 	if (cmd->code == IPS_CMD_DCDB || cmd->code == IPS_CMD_DCDB_SG) {
   1494  1.1  jdolecek 		int i;
   1495  1.1  jdolecek 
   1496  1.1  jdolecek 		DPRINTF(IPS_D_ERR, (", dcdb device 0x%02x, attr 0x%02x, "
   1497  1.1  jdolecek 		    "datalen %d, sgcnt %d, status 0x%02x",
   1498  1.1  jdolecek 		    dcdb->device, dcdb->attr, htole16(dcdb->datalen),
   1499  1.1  jdolecek 		    dcdb->sgcnt, dcdb->status));
   1500  1.1  jdolecek 
   1501  1.1  jdolecek 		DPRINTF(IPS_D_ERR, (", cdb"));
   1502  1.1  jdolecek 		for (i = 0; i < dcdb->cdblen; i++)
   1503  1.1  jdolecek 			DPRINTF(IPS_D_ERR, (" %x", dcdb->cdb[i]));
   1504  1.1  jdolecek 		if (ccb->c_estat == IPS_ESTAT_CKCOND) {
   1505  1.1  jdolecek 			DPRINTF(IPS_D_ERR, (", sense"));
   1506  1.1  jdolecek 			for (i = 0; i < dcdb->senselen; i++)
   1507  1.1  jdolecek 				DPRINTF(IPS_D_ERR, (" %x", dcdb->sense[i]));
   1508  1.1  jdolecek 		}
   1509  1.1  jdolecek 	}
   1510  1.1  jdolecek 	DPRINTF(IPS_D_ERR, ("\n"));
   1511  1.1  jdolecek 
   1512  1.1  jdolecek 	switch (gsc) {
   1513  1.1  jdolecek 	case IPS_STAT_RECOV:
   1514  1.1  jdolecek 		return (0);
   1515  1.1  jdolecek 	case IPS_STAT_INVOP:
   1516  1.1  jdolecek 	case IPS_STAT_INVCMD:
   1517  1.1  jdolecek 	case IPS_STAT_INVPARM:
   1518  1.1  jdolecek 		return (EINVAL);
   1519  1.1  jdolecek 	case IPS_STAT_BUSY:
   1520  1.1  jdolecek 		return (EBUSY);
   1521  1.1  jdolecek 	case IPS_STAT_TIMO:
   1522  1.1  jdolecek 		return (ETIMEDOUT);
   1523  1.1  jdolecek 	case IPS_STAT_PDRVERR:
   1524  1.1  jdolecek 		switch (ccb->c_estat) {
   1525  1.1  jdolecek 		case IPS_ESTAT_SELTIMO:
   1526  1.1  jdolecek 			return (ENODEV);
   1527  1.1  jdolecek 		case IPS_ESTAT_OURUN:
   1528  1.1  jdolecek 			if (xs && htole16(dcdb->datalen) < xs->datalen)
   1529  1.1  jdolecek 				/* underrun */
   1530  1.1  jdolecek 				return (0);
   1531  1.1  jdolecek 			break;
   1532  1.1  jdolecek 		case IPS_ESTAT_RECOV:
   1533  1.1  jdolecek 			return (0);
   1534  1.1  jdolecek 		}
   1535  1.1  jdolecek 		break;
   1536  1.1  jdolecek 	}
   1537  1.1  jdolecek 
   1538  1.1  jdolecek 	return (EIO);
   1539  1.1  jdolecek }
   1540  1.1  jdolecek 
   1541  1.1  jdolecek int
   1542  1.1  jdolecek ips_error_xs(struct ips_softc *sc, struct ips_ccb *ccb)
   1543  1.1  jdolecek {
   1544  1.1  jdolecek 	struct ips_cmdb *cmdb = ccb->c_cmdbva;
   1545  1.1  jdolecek 	struct ips_dcdb *dcdb = &cmdb->dcdb;
   1546  1.1  jdolecek 	struct scsipi_xfer *xs = ccb->c_xfer;
   1547  1.1  jdolecek 	u_int8_t gsc = IPS_STAT_GSC(ccb->c_stat);
   1548  1.1  jdolecek 
   1549  1.1  jdolecek 	/* Map hardware error codes to SCSI ones */
   1550  1.1  jdolecek 	switch (gsc) {
   1551  1.1  jdolecek 	case IPS_STAT_OK:
   1552  1.1  jdolecek 	case IPS_STAT_RECOV:
   1553  1.1  jdolecek 		return (XS_NOERROR);
   1554  1.1  jdolecek 	case IPS_STAT_BUSY:
   1555  1.1  jdolecek 		return (XS_BUSY);
   1556  1.1  jdolecek 	case IPS_STAT_TIMO:
   1557  1.1  jdolecek 		return (XS_TIMEOUT);
   1558  1.1  jdolecek 	case IPS_STAT_PDRVERR:
   1559  1.1  jdolecek 		switch (ccb->c_estat) {
   1560  1.1  jdolecek 		case IPS_ESTAT_SELTIMO:
   1561  1.1  jdolecek 			return (XS_SELTIMEOUT);
   1562  1.1  jdolecek 		case IPS_ESTAT_OURUN:
   1563  1.1  jdolecek 			if (xs && htole16(dcdb->datalen) < xs->datalen)
   1564  1.1  jdolecek 				/* underrun */
   1565  1.1  jdolecek 				return (XS_NOERROR);
   1566  1.1  jdolecek 			break;
   1567  1.1  jdolecek 		case IPS_ESTAT_HOSTRST:
   1568  1.1  jdolecek 		case IPS_ESTAT_DEVRST:
   1569  1.1  jdolecek 			return (XS_RESET);
   1570  1.1  jdolecek 		case IPS_ESTAT_RECOV:
   1571  1.1  jdolecek 			return (XS_NOERROR);
   1572  1.1  jdolecek 		case IPS_ESTAT_CKCOND:
   1573  1.1  jdolecek 			return (XS_SENSE);
   1574  1.1  jdolecek 		}
   1575  1.1  jdolecek 		break;
   1576  1.1  jdolecek 	}
   1577  1.1  jdolecek 
   1578  1.1  jdolecek 	return (XS_DRIVER_STUFFUP);
   1579  1.1  jdolecek }
   1580  1.1  jdolecek 
   1581  1.1  jdolecek int
   1582  1.1  jdolecek ips_intr(void *arg)
   1583  1.1  jdolecek {
   1584  1.1  jdolecek 	struct ips_softc *sc = arg;
   1585  1.1  jdolecek 	struct ips_ccb *ccb;
   1586  1.1  jdolecek 	u_int32_t status;
   1587  1.1  jdolecek 	int id;
   1588  1.1  jdolecek 
   1589  1.1  jdolecek 	DPRINTF(IPS_D_XFER, ("%s: ips_intr", sc->sc_dev.dv_xname));
   1590  1.1  jdolecek 	if (!ips_isintr(sc)) {
   1591  1.1  jdolecek 		DPRINTF(IPS_D_XFER, (": not ours\n"));
   1592  1.1  jdolecek 		return (0);
   1593  1.1  jdolecek 	}
   1594  1.1  jdolecek 	DPRINTF(IPS_D_XFER, ("\n"));
   1595  1.1  jdolecek 
   1596  1.1  jdolecek 	/* Process completed commands */
   1597  1.1  jdolecek 	while ((status = ips_status(sc)) != 0xffffffff) {
   1598  1.1  jdolecek 		DPRINTF(IPS_D_XFER, ("%s: ips_intr: status 0x%08x\n",
   1599  1.1  jdolecek 		    sc->sc_dev.dv_xname, status));
   1600  1.1  jdolecek 
   1601  1.1  jdolecek 		id = IPS_STAT_ID(status);
   1602  1.1  jdolecek 		if (id >= sc->sc_nccbs) {
   1603  1.1  jdolecek 			DPRINTF(IPS_D_ERR, ("%s: ips_intr: invalid id %d\n",
   1604  1.1  jdolecek 			    sc->sc_dev.dv_xname, id));
   1605  1.1  jdolecek 			continue;
   1606  1.1  jdolecek 		}
   1607  1.1  jdolecek 
   1608  1.1  jdolecek 		ccb = &sc->sc_ccb[id];
   1609  1.1  jdolecek 		if (ccb->c_state != IPS_CCB_QUEUED) {
   1610  1.1  jdolecek 			DPRINTF(IPS_D_ERR, ("%s: ips_intr: cmd 0x%02x not "
   1611  1.1  jdolecek 			    "queued, state %d, status 0x%08x\n",
   1612  1.1  jdolecek 			    sc->sc_dev.dv_xname, ccb->c_id, ccb->c_state,
   1613  1.1  jdolecek 			    status));
   1614  1.1  jdolecek 			continue;
   1615  1.1  jdolecek 		}
   1616  1.1  jdolecek 
   1617  1.1  jdolecek 		ccb->c_state = IPS_CCB_DONE;
   1618  1.1  jdolecek 		ccb->c_stat = IPS_STAT_BASIC(status);
   1619  1.1  jdolecek 		ccb->c_estat = IPS_STAT_EXT(status);
   1620  1.1  jdolecek 
   1621  1.1  jdolecek 		if (ccb->c_flags & XS_CTL_POLL) {
   1622  1.1  jdolecek 			wakeup(ccb);
   1623  1.1  jdolecek 		} else {
   1624  1.1  jdolecek 			ips_done(sc, ccb);
   1625  1.1  jdolecek 		}
   1626  1.1  jdolecek 	}
   1627  1.1  jdolecek 
   1628  1.1  jdolecek 	return (1);
   1629  1.1  jdolecek }
   1630  1.1  jdolecek 
   1631  1.1  jdolecek void
   1632  1.1  jdolecek ips_timeout(void *arg)
   1633  1.1  jdolecek {
   1634  1.1  jdolecek 	struct ips_ccb *ccb = arg;
   1635  1.1  jdolecek 	struct ips_softc *sc = ccb->c_sc;
   1636  1.1  jdolecek 	struct scsipi_xfer *xs = ccb->c_xfer;
   1637  1.1  jdolecek 	int s;
   1638  1.1  jdolecek 
   1639  1.1  jdolecek 	s = splbio();
   1640  1.1  jdolecek 	if (xs)
   1641  1.1  jdolecek 		scsi_print_addr(xs->xs_periph);
   1642  1.1  jdolecek 	else
   1643  1.1  jdolecek 		printf("%s: ", sc->sc_dev.dv_xname);
   1644  1.1  jdolecek 	printf("timeout\n");
   1645  1.1  jdolecek 
   1646  1.1  jdolecek 	/*
   1647  1.1  jdolecek 	 * Command never completed. Fake hardware status byte
   1648  1.1  jdolecek 	 * to indicate timeout.
   1649  1.1  jdolecek 	 * XXX: need to remove command from controller.
   1650  1.1  jdolecek 	 */
   1651  1.1  jdolecek 	ccb->c_stat = IPS_STAT_TIMO;
   1652  1.1  jdolecek 	ips_done(sc, ccb);
   1653  1.1  jdolecek 	splx(s);
   1654  1.1  jdolecek }
   1655  1.1  jdolecek 
   1656  1.1  jdolecek int
   1657  1.1  jdolecek ips_getadapterinfo(struct ips_softc *sc, int flags)
   1658  1.1  jdolecek {
   1659  1.1  jdolecek 	struct ips_ccb *ccb;
   1660  1.1  jdolecek 	struct ips_cmd *cmd;
   1661  1.1  jdolecek 
   1662  1.1  jdolecek 	ccb = ips_ccb_get(sc);
   1663  1.1  jdolecek 	if (ccb == NULL)
   1664  1.1  jdolecek 		return (1);
   1665  1.1  jdolecek 
   1666  1.1  jdolecek 	ccb->c_flags = XS_CTL_DATA_IN | XS_CTL_POLL | flags;
   1667  1.1  jdolecek 	ccb->c_done = ips_done_mgmt;
   1668  1.1  jdolecek 
   1669  1.1  jdolecek 	cmd = ccb->c_cmdbva;
   1670  1.1  jdolecek 	cmd->code = IPS_CMD_GETADAPTERINFO;
   1671  1.1  jdolecek 	cmd->sgaddr = htole32(sc->sc_infom.dm_paddr + offsetof(struct ips_info,
   1672  1.1  jdolecek 	    adapter));
   1673  1.1  jdolecek 
   1674  1.1  jdolecek 	return (ips_cmd(sc, ccb));
   1675  1.1  jdolecek }
   1676  1.1  jdolecek 
   1677  1.1  jdolecek int
   1678  1.1  jdolecek ips_getdriveinfo(struct ips_softc *sc, int flags)
   1679  1.1  jdolecek {
   1680  1.1  jdolecek 	struct ips_ccb *ccb;
   1681  1.1  jdolecek 	struct ips_cmd *cmd;
   1682  1.1  jdolecek 
   1683  1.1  jdolecek 	ccb = ips_ccb_get(sc);
   1684  1.1  jdolecek 	if (ccb == NULL)
   1685  1.1  jdolecek 		return (1);
   1686  1.1  jdolecek 
   1687  1.1  jdolecek 	ccb->c_flags = XS_CTL_DATA_IN | XS_CTL_POLL | flags;
   1688  1.1  jdolecek 	ccb->c_done = ips_done_mgmt;
   1689  1.1  jdolecek 
   1690  1.1  jdolecek 	cmd = ccb->c_cmdbva;
   1691  1.1  jdolecek 	cmd->code = IPS_CMD_GETDRIVEINFO;
   1692  1.1  jdolecek 	cmd->sgaddr = htole32(sc->sc_infom.dm_paddr + offsetof(struct ips_info,
   1693  1.1  jdolecek 	    drive));
   1694  1.1  jdolecek 
   1695  1.1  jdolecek 	return (ips_cmd(sc, ccb));
   1696  1.1  jdolecek }
   1697  1.1  jdolecek 
   1698  1.1  jdolecek int
   1699  1.1  jdolecek ips_getconf(struct ips_softc *sc, int flags)
   1700  1.1  jdolecek {
   1701  1.1  jdolecek 	struct ips_ccb *ccb;
   1702  1.1  jdolecek 	struct ips_cmd *cmd;
   1703  1.1  jdolecek 
   1704  1.1  jdolecek 	ccb = ips_ccb_get(sc);
   1705  1.1  jdolecek 	if (ccb == NULL)
   1706  1.1  jdolecek 		return (1);
   1707  1.1  jdolecek 
   1708  1.1  jdolecek 	ccb->c_flags = XS_CTL_DATA_IN | XS_CTL_POLL | flags;
   1709  1.1  jdolecek 	ccb->c_done = ips_done_mgmt;
   1710  1.1  jdolecek 
   1711  1.1  jdolecek 	cmd = ccb->c_cmdbva;
   1712  1.1  jdolecek 	cmd->code = IPS_CMD_READCONF;
   1713  1.1  jdolecek 	cmd->sgaddr = htole32(sc->sc_infom.dm_paddr + offsetof(struct ips_info,
   1714  1.1  jdolecek 	    conf));
   1715  1.1  jdolecek 
   1716  1.1  jdolecek 	return (ips_cmd(sc, ccb));
   1717  1.1  jdolecek }
   1718  1.1  jdolecek 
   1719  1.1  jdolecek int
   1720  1.1  jdolecek ips_getpg5(struct ips_softc *sc, int flags)
   1721  1.1  jdolecek {
   1722  1.1  jdolecek 	struct ips_ccb *ccb;
   1723  1.1  jdolecek 	struct ips_cmd *cmd;
   1724  1.1  jdolecek 
   1725  1.1  jdolecek 	ccb = ips_ccb_get(sc);
   1726  1.1  jdolecek 	if (ccb == NULL)
   1727  1.1  jdolecek 		return (1);
   1728  1.1  jdolecek 
   1729  1.1  jdolecek 	ccb->c_flags = XS_CTL_DATA_IN | XS_CTL_POLL | flags;
   1730  1.1  jdolecek 	ccb->c_done = ips_done_mgmt;
   1731  1.1  jdolecek 
   1732  1.1  jdolecek 	cmd = ccb->c_cmdbva;
   1733  1.1  jdolecek 	cmd->code = IPS_CMD_RWNVRAM;
   1734  1.1  jdolecek 	cmd->drive = 5;
   1735  1.1  jdolecek 	cmd->sgaddr = htole32(sc->sc_infom.dm_paddr + offsetof(struct ips_info,
   1736  1.1  jdolecek 	    pg5));
   1737  1.1  jdolecek 
   1738  1.1  jdolecek 	return (ips_cmd(sc, ccb));
   1739  1.1  jdolecek }
   1740  1.1  jdolecek 
   1741  1.1  jdolecek #if NBIO > 0
   1742  1.1  jdolecek int
   1743  1.1  jdolecek ips_getrblstat(struct ips_softc *sc, int flags)
   1744  1.1  jdolecek {
   1745  1.1  jdolecek 	struct ips_ccb *ccb;
   1746  1.1  jdolecek 	struct ips_cmd *cmd;
   1747  1.1  jdolecek 
   1748  1.1  jdolecek 	ccb = ips_ccb_get(sc);
   1749  1.1  jdolecek 	if (ccb == NULL)
   1750  1.1  jdolecek 		return (1);
   1751  1.1  jdolecek 
   1752  1.1  jdolecek 	ccb->c_flags = XS_CTL_DATA_IN | XS_CTL_POLL | flags;
   1753  1.1  jdolecek 	ccb->c_done = ips_done_mgmt;
   1754  1.1  jdolecek 
   1755  1.1  jdolecek 	cmd = ccb->c_cmdbva;
   1756  1.1  jdolecek 	cmd->code = IPS_CMD_REBUILDSTATUS;
   1757  1.1  jdolecek 	cmd->sgaddr = htole32(sc->sc_infom.dm_paddr + offsetof(struct ips_info,
   1758  1.1  jdolecek 	    rblstat));
   1759  1.1  jdolecek 
   1760  1.1  jdolecek 	return (ips_cmd(sc, ccb));
   1761  1.1  jdolecek }
   1762  1.1  jdolecek 
   1763  1.1  jdolecek int
   1764  1.1  jdolecek ips_setstate(struct ips_softc *sc, int chan, int target, int state, int flags)
   1765  1.1  jdolecek {
   1766  1.1  jdolecek 	struct ips_ccb *ccb;
   1767  1.1  jdolecek 	struct ips_cmd *cmd;
   1768  1.1  jdolecek 
   1769  1.1  jdolecek 	ccb = ips_ccb_get(sc);
   1770  1.1  jdolecek 	if (ccb == NULL)
   1771  1.1  jdolecek 		return (1);
   1772  1.1  jdolecek 
   1773  1.1  jdolecek 	ccb->c_flags = XS_CTL_POLL | flags;
   1774  1.1  jdolecek 	ccb->c_done = ips_done_mgmt;
   1775  1.1  jdolecek 
   1776  1.1  jdolecek 	cmd = ccb->c_cmdbva;
   1777  1.1  jdolecek 	cmd->code = IPS_CMD_SETSTATE;
   1778  1.1  jdolecek 	cmd->drive = chan;
   1779  1.1  jdolecek 	cmd->sgcnt = target;
   1780  1.1  jdolecek 	cmd->seg4g = state;
   1781  1.1  jdolecek 
   1782  1.1  jdolecek 	return (ips_cmd(sc, ccb));
   1783  1.1  jdolecek }
   1784  1.1  jdolecek 
   1785  1.1  jdolecek int
   1786  1.1  jdolecek ips_rebuild(struct ips_softc *sc, int chan, int target, int nchan,
   1787  1.1  jdolecek     int ntarget, int flags)
   1788  1.1  jdolecek {
   1789  1.1  jdolecek 	struct ips_ccb *ccb;
   1790  1.1  jdolecek 	struct ips_cmd *cmd;
   1791  1.1  jdolecek 
   1792  1.1  jdolecek 	ccb = ips_ccb_get(sc);
   1793  1.1  jdolecek 	if (ccb == NULL)
   1794  1.1  jdolecek 		return (1);
   1795  1.1  jdolecek 
   1796  1.1  jdolecek 	ccb->c_flags = XS_CTL_POLL | flags;
   1797  1.1  jdolecek 	ccb->c_done = ips_done_mgmt;
   1798  1.1  jdolecek 
   1799  1.1  jdolecek 	cmd = ccb->c_cmdbva;
   1800  1.1  jdolecek 	cmd->code = IPS_CMD_REBUILD;
   1801  1.1  jdolecek 	cmd->drive = chan;
   1802  1.1  jdolecek 	cmd->sgcnt = target;
   1803  1.1  jdolecek 	cmd->seccnt = htole16(ntarget << 8 | nchan);
   1804  1.1  jdolecek 
   1805  1.1  jdolecek 	return (ips_cmd(sc, ccb));
   1806  1.1  jdolecek }
   1807  1.1  jdolecek #endif	/* NBIO > 0 */
   1808  1.1  jdolecek 
   1809  1.1  jdolecek void
   1810  1.1  jdolecek ips_copperhead_exec(struct ips_softc *sc, struct ips_ccb *ccb)
   1811  1.1  jdolecek {
   1812  1.1  jdolecek 	u_int32_t reg;
   1813  1.1  jdolecek 	int timeout;
   1814  1.1  jdolecek 
   1815  1.1  jdolecek 	for (timeout = 100; timeout-- > 0; delay(100)) {
   1816  1.1  jdolecek 		reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, IPS_REG_CCC);
   1817  1.1  jdolecek 		if ((reg & IPS_REG_CCC_SEM) == 0)
   1818  1.1  jdolecek 			break;
   1819  1.1  jdolecek 	}
   1820  1.1  jdolecek 	if (timeout < 0) {
   1821  1.1  jdolecek 		printf("%s: semaphore timeout\n", sc->sc_dev.dv_xname);
   1822  1.1  jdolecek 		return;
   1823  1.1  jdolecek 	}
   1824  1.1  jdolecek 
   1825  1.1  jdolecek 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, IPS_REG_CCSA, ccb->c_cmdbpa);
   1826  1.1  jdolecek 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, IPS_REG_CCC,
   1827  1.1  jdolecek 	    IPS_REG_CCC_START);
   1828  1.1  jdolecek }
   1829  1.1  jdolecek 
   1830  1.1  jdolecek void
   1831  1.1  jdolecek ips_copperhead_intren(struct ips_softc *sc)
   1832  1.1  jdolecek {
   1833  1.1  jdolecek 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, IPS_REG_HIS, IPS_REG_HIS_EN);
   1834  1.1  jdolecek }
   1835  1.1  jdolecek 
   1836  1.1  jdolecek int
   1837  1.1  jdolecek ips_copperhead_isintr(struct ips_softc *sc)
   1838  1.1  jdolecek {
   1839  1.1  jdolecek 	u_int8_t reg;
   1840  1.1  jdolecek 
   1841  1.1  jdolecek 	reg = bus_space_read_1(sc->sc_iot, sc->sc_ioh, IPS_REG_HIS);
   1842  1.1  jdolecek 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, IPS_REG_HIS, reg);
   1843  1.1  jdolecek 	if (reg != 0xff && (reg & IPS_REG_HIS_SCE))
   1844  1.1  jdolecek 		return (1);
   1845  1.1  jdolecek 
   1846  1.1  jdolecek 	return (0);
   1847  1.1  jdolecek }
   1848  1.1  jdolecek 
   1849  1.1  jdolecek u_int32_t
   1850  1.1  jdolecek ips_copperhead_status(struct ips_softc *sc)
   1851  1.1  jdolecek {
   1852  1.1  jdolecek 	u_int32_t sqhead, sqtail, status;
   1853  1.1  jdolecek 
   1854  1.1  jdolecek 	sqhead = bus_space_read_4(sc->sc_iot, sc->sc_ioh, IPS_REG_SQH);
   1855  1.1  jdolecek 	DPRINTF(IPS_D_XFER, ("%s: sqhead 0x%08x, sqtail 0x%08x\n",
   1856  1.1  jdolecek 	    sc->sc_dev.dv_xname, sqhead, sc->sc_sqtail));
   1857  1.1  jdolecek 
   1858  1.1  jdolecek 	sqtail = sc->sc_sqtail + sizeof(u_int32_t);
   1859  1.1  jdolecek 	if (sqtail == sc->sc_sqm.dm_paddr + IPS_SQSZ)
   1860  1.1  jdolecek 		sqtail = sc->sc_sqm.dm_paddr;
   1861  1.1  jdolecek 	if (sqtail == sqhead)
   1862  1.1  jdolecek 		return (0xffffffff);
   1863  1.1  jdolecek 
   1864  1.1  jdolecek 	sc->sc_sqtail = sqtail;
   1865  1.1  jdolecek 	if (++sc->sc_sqidx == IPS_MAXCMDS)
   1866  1.1  jdolecek 		sc->sc_sqidx = 0;
   1867  1.1  jdolecek 	status = htole32(sc->sc_sqbuf[sc->sc_sqidx]);
   1868  1.1  jdolecek 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, IPS_REG_SQT, sqtail);
   1869  1.1  jdolecek 
   1870  1.1  jdolecek 	return (status);
   1871  1.1  jdolecek }
   1872  1.1  jdolecek 
   1873  1.1  jdolecek void
   1874  1.1  jdolecek ips_morpheus_exec(struct ips_softc *sc, struct ips_ccb *ccb)
   1875  1.1  jdolecek {
   1876  1.1  jdolecek 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, IPS_REG_IQP, ccb->c_cmdbpa);
   1877  1.1  jdolecek }
   1878  1.1  jdolecek 
   1879  1.1  jdolecek void
   1880  1.1  jdolecek ips_morpheus_intren(struct ips_softc *sc)
   1881  1.1  jdolecek {
   1882  1.1  jdolecek 	u_int32_t reg;
   1883  1.1  jdolecek 
   1884  1.1  jdolecek 	reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, IPS_REG_OIM);
   1885  1.1  jdolecek 	reg &= ~IPS_REG_OIM_DS;
   1886  1.1  jdolecek 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, IPS_REG_OIM, reg);
   1887  1.1  jdolecek }
   1888  1.1  jdolecek 
   1889  1.1  jdolecek int
   1890  1.1  jdolecek ips_morpheus_isintr(struct ips_softc *sc)
   1891  1.1  jdolecek {
   1892  1.1  jdolecek 	return (bus_space_read_4(sc->sc_iot, sc->sc_ioh, IPS_REG_OIS) &
   1893  1.1  jdolecek 	    IPS_REG_OIS_PEND);
   1894  1.1  jdolecek }
   1895  1.1  jdolecek 
   1896  1.1  jdolecek u_int32_t
   1897  1.1  jdolecek ips_morpheus_status(struct ips_softc *sc)
   1898  1.1  jdolecek {
   1899  1.1  jdolecek 	u_int32_t reg;
   1900  1.1  jdolecek 
   1901  1.1  jdolecek 	reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, IPS_REG_OQP);
   1902  1.1  jdolecek 	DPRINTF(IPS_D_XFER, ("%s: status 0x%08x\n", sc->sc_dev.dv_xname, reg));
   1903  1.1  jdolecek 
   1904  1.1  jdolecek 	return (reg);
   1905  1.1  jdolecek }
   1906  1.1  jdolecek 
   1907  1.1  jdolecek struct ips_ccb *
   1908  1.1  jdolecek ips_ccb_alloc(struct ips_softc *sc, int n)
   1909  1.1  jdolecek {
   1910  1.1  jdolecek 	struct ips_ccb *ccb;
   1911  1.1  jdolecek 	int i;
   1912  1.1  jdolecek 
   1913  1.2       chs 	ccb = malloc(n * sizeof(*ccb), M_DEVBUF, M_WAITOK | M_ZERO);
   1914  1.1  jdolecek 	for (i = 0; i < n; i++) {
   1915  1.1  jdolecek 		ccb[i].c_sc = sc;
   1916  1.1  jdolecek 		ccb[i].c_id = i;
   1917  1.1  jdolecek 		ccb[i].c_cmdbva = (char *)sc->sc_cmdbm.dm_vaddr +
   1918  1.1  jdolecek 		    i * sizeof(struct ips_cmdb);
   1919  1.1  jdolecek 		ccb[i].c_cmdbpa = sc->sc_cmdbm.dm_paddr +
   1920  1.1  jdolecek 		    i * sizeof(struct ips_cmdb);
   1921  1.1  jdolecek 		if (bus_dmamap_create(sc->sc_dmat, IPS_MAXFER, IPS_MAXSGS,
   1922  1.1  jdolecek 		    IPS_MAXFER, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
   1923  1.1  jdolecek 		    &ccb[i].c_dmam))
   1924  1.1  jdolecek 			goto fail;
   1925  1.1  jdolecek 	}
   1926  1.1  jdolecek 
   1927  1.1  jdolecek 	return (ccb);
   1928  1.1  jdolecek fail:
   1929  1.1  jdolecek 	for (; i > 0; i--)
   1930  1.1  jdolecek 		bus_dmamap_destroy(sc->sc_dmat, ccb[i - 1].c_dmam);
   1931  1.1  jdolecek 	free(ccb, M_DEVBUF);
   1932  1.1  jdolecek 	return (NULL);
   1933  1.1  jdolecek }
   1934  1.1  jdolecek 
   1935  1.1  jdolecek void
   1936  1.1  jdolecek ips_ccb_free(struct ips_softc *sc, struct ips_ccb *ccb, int n)
   1937  1.1  jdolecek {
   1938  1.1  jdolecek 	int i;
   1939  1.1  jdolecek 
   1940  1.1  jdolecek 	for (i = 0; i < n; i++)
   1941  1.1  jdolecek 		bus_dmamap_destroy(sc->sc_dmat, ccb[i - 1].c_dmam);
   1942  1.1  jdolecek 	free(ccb, M_DEVBUF);
   1943  1.1  jdolecek }
   1944  1.1  jdolecek 
   1945  1.1  jdolecek struct ips_ccb *
   1946  1.1  jdolecek ips_ccb_get(struct ips_softc *sc)
   1947  1.1  jdolecek {
   1948  1.1  jdolecek 	struct ips_ccb *ccb;
   1949  1.1  jdolecek 
   1950  1.1  jdolecek 	mutex_enter(&sc->sc_ccb_mtx);
   1951  1.1  jdolecek 	if ((ccb = SLIST_FIRST(&sc->sc_ccbq_free)) != NULL) {
   1952  1.1  jdolecek 		SLIST_REMOVE_HEAD(&sc->sc_ccbq_free, c_link);
   1953  1.1  jdolecek 		ccb->c_flags = 0;
   1954  1.1  jdolecek 		ccb->c_xfer = NULL;
   1955  1.1  jdolecek 		bzero(ccb->c_cmdbva, sizeof(struct ips_cmdb));
   1956  1.1  jdolecek 	}
   1957  1.1  jdolecek 	mutex_exit(&sc->sc_ccb_mtx);
   1958  1.1  jdolecek 
   1959  1.1  jdolecek 	return (ccb);
   1960  1.1  jdolecek }
   1961  1.1  jdolecek 
   1962  1.1  jdolecek void
   1963  1.1  jdolecek ips_ccb_put(struct ips_softc *sc, struct ips_ccb *ccb)
   1964  1.1  jdolecek {
   1965  1.1  jdolecek 	ccb->c_state = IPS_CCB_FREE;
   1966  1.1  jdolecek 	mutex_enter(&sc->sc_ccb_mtx);
   1967  1.1  jdolecek 	SLIST_INSERT_HEAD(&sc->sc_ccbq_free, ccb, c_link);
   1968  1.1  jdolecek 	mutex_exit(&sc->sc_ccb_mtx);
   1969  1.1  jdolecek }
   1970  1.1  jdolecek 
   1971  1.1  jdolecek int
   1972  1.1  jdolecek ips_dmamem_alloc(struct dmamem *dm, bus_dma_tag_t tag, bus_size_t size)
   1973  1.1  jdolecek {
   1974  1.1  jdolecek 	int nsegs;
   1975  1.1  jdolecek 
   1976  1.1  jdolecek 	dm->dm_tag = tag;
   1977  1.1  jdolecek 	dm->dm_size = size;
   1978  1.1  jdolecek 
   1979  1.1  jdolecek 	if (bus_dmamap_create(tag, size, 1, size, 0,
   1980  1.1  jdolecek 	    BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &dm->dm_map))
   1981  1.1  jdolecek 		return (1);
   1982  1.1  jdolecek 	if (bus_dmamem_alloc(tag, size, 0, 0, &dm->dm_seg, 1, &nsegs,
   1983  1.1  jdolecek 	    BUS_DMA_NOWAIT))
   1984  1.1  jdolecek 		goto fail1;
   1985  1.1  jdolecek 	if (bus_dmamem_map(tag, &dm->dm_seg, 1, size, &dm->dm_vaddr,
   1986  1.1  jdolecek 	    BUS_DMA_NOWAIT))
   1987  1.1  jdolecek 		goto fail2;
   1988  1.1  jdolecek 	if (bus_dmamap_load(tag, dm->dm_map, dm->dm_vaddr, size, NULL,
   1989  1.1  jdolecek 	    BUS_DMA_NOWAIT))
   1990  1.1  jdolecek 		goto fail3;
   1991  1.1  jdolecek 
   1992  1.1  jdolecek 	return (0);
   1993  1.1  jdolecek 
   1994  1.1  jdolecek fail3:
   1995  1.1  jdolecek 	bus_dmamem_unmap(tag, dm->dm_vaddr, size);
   1996  1.1  jdolecek fail2:
   1997  1.1  jdolecek 	bus_dmamem_free(tag, &dm->dm_seg, 1);
   1998  1.1  jdolecek fail1:
   1999  1.1  jdolecek 	bus_dmamap_destroy(tag, dm->dm_map);
   2000  1.1  jdolecek 	return (1);
   2001  1.1  jdolecek }
   2002  1.1  jdolecek 
   2003  1.1  jdolecek void
   2004  1.1  jdolecek ips_dmamem_free(struct dmamem *dm)
   2005  1.1  jdolecek {
   2006  1.1  jdolecek 	bus_dmamap_unload(dm->dm_tag, dm->dm_map);
   2007  1.1  jdolecek 	bus_dmamem_unmap(dm->dm_tag, dm->dm_vaddr, dm->dm_size);
   2008  1.1  jdolecek 	bus_dmamem_free(dm->dm_tag, &dm->dm_seg, 1);
   2009  1.1  jdolecek 	bus_dmamap_destroy(dm->dm_tag, dm->dm_map);
   2010  1.1  jdolecek }
   2011