Home | History | Annotate | Line # | Download | only in pci
ips.c revision 1.7
      1  1.7       chs /*	$NetBSD: ips.c,v 1.7 2024/01/08 18:38:25 chs 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.7       chs __KERNEL_RCSID(0, "$NetBSD: ips.c,v 1.7 2024/01/08 18:38:25 chs 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.5  riastrad 	device_t		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.7       chs void	ips_attach(device_t, device_t, 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.7       chs ips_attach(device_t parent, device_t self, void *aux)
    621  1.1  jdolecek {
    622  1.7       chs 	struct ips_softc *sc = device_private(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.5  riastrad 	sc->sc_dev = self;
    638  1.1  jdolecek 	sc->sc_dmat = pa->pa_dmat;
    639  1.1  jdolecek 
    640  1.1  jdolecek 	/* Identify chipset */
    641  1.1  jdolecek 	if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_IBM_SERVERAID)
    642  1.1  jdolecek 		sc->sc_chip = &ips_chips[IPS_CHIP_COPPERHEAD];
    643  1.1  jdolecek 	else
    644  1.1  jdolecek 		sc->sc_chip = &ips_chips[IPS_CHIP_MORPHEUS];
    645  1.1  jdolecek 
    646  1.1  jdolecek 	/* Map registers */
    647  1.1  jdolecek 	// XXX check IPS_IOSIZE as old code used to do?
    648  1.1  jdolecek 	maptype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, sc->sc_chip->ic_bar);
    649  1.1  jdolecek 	if (pci_mapreg_map(pa, sc->sc_chip->ic_bar, maptype, 0, &sc->sc_iot,
    650  1.1  jdolecek 	    &sc->sc_ioh, NULL, &iosize)) {
    651  1.1  jdolecek 		printf(": can't map regs\n");
    652  1.1  jdolecek 		return;
    653  1.1  jdolecek 	}
    654  1.1  jdolecek 
    655  1.1  jdolecek 	/* Allocate command buffer */
    656  1.1  jdolecek 	if (ips_dmamem_alloc(&sc->sc_cmdbm, sc->sc_dmat,
    657  1.1  jdolecek 	    IPS_MAXCMDS * sizeof(struct ips_cmdb))) {
    658  1.1  jdolecek 		printf(": can't alloc cmd buffer\n");
    659  1.1  jdolecek 		goto fail1;
    660  1.1  jdolecek 	}
    661  1.1  jdolecek 
    662  1.1  jdolecek 	/* Allocate info buffer */
    663  1.1  jdolecek 	if (ips_dmamem_alloc(&sc->sc_infom, sc->sc_dmat,
    664  1.1  jdolecek 	    sizeof(struct ips_info))) {
    665  1.1  jdolecek 		printf(": can't alloc info buffer\n");
    666  1.1  jdolecek 		goto fail2;
    667  1.1  jdolecek 	}
    668  1.1  jdolecek 	sc->sc_info = sc->sc_infom.dm_vaddr;
    669  1.1  jdolecek 	ai = &sc->sc_info->adapter;
    670  1.1  jdolecek 	di = &sc->sc_info->drive;
    671  1.1  jdolecek 	pg5 = &sc->sc_info->pg5;
    672  1.1  jdolecek 
    673  1.1  jdolecek 	/* Allocate status queue for the Copperhead chipset */
    674  1.1  jdolecek 	if (sc->sc_chip->ic_id == IPS_CHIP_COPPERHEAD) {
    675  1.1  jdolecek 		if (ips_dmamem_alloc(&sc->sc_sqm, sc->sc_dmat, IPS_SQSZ)) {
    676  1.1  jdolecek 			printf(": can't alloc status queue\n");
    677  1.1  jdolecek 			goto fail3;
    678  1.1  jdolecek 		}
    679  1.1  jdolecek 		sc->sc_sqtail = sc->sc_sqm.dm_paddr;
    680  1.1  jdolecek 		sc->sc_sqbuf = sc->sc_sqm.dm_vaddr;
    681  1.1  jdolecek 		sc->sc_sqidx = 0;
    682  1.1  jdolecek 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, IPS_REG_SQS,
    683  1.1  jdolecek 		    sc->sc_sqm.dm_paddr);
    684  1.1  jdolecek 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, IPS_REG_SQE,
    685  1.1  jdolecek 		    sc->sc_sqm.dm_paddr + IPS_SQSZ);
    686  1.1  jdolecek 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, IPS_REG_SQH,
    687  1.1  jdolecek 		    sc->sc_sqm.dm_paddr + sizeof(u_int32_t));
    688  1.1  jdolecek 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, IPS_REG_SQT,
    689  1.1  jdolecek 		    sc->sc_sqm.dm_paddr);
    690  1.1  jdolecek 	}
    691  1.1  jdolecek 
    692  1.1  jdolecek 	/* Bootstrap CCB queue */
    693  1.1  jdolecek 	sc->sc_nccbs = 1;
    694  1.1  jdolecek 	sc->sc_ccb = &ccb0;
    695  1.1  jdolecek 	bzero(&ccb0, sizeof(ccb0));
    696  1.1  jdolecek 	ccb0.c_cmdbva = sc->sc_cmdbm.dm_vaddr;
    697  1.1  jdolecek 	ccb0.c_cmdbpa = sc->sc_cmdbm.dm_paddr;
    698  1.1  jdolecek 	SLIST_INIT(&sc->sc_ccbq_free);
    699  1.1  jdolecek 	SLIST_INSERT_HEAD(&sc->sc_ccbq_free, &ccb0, c_link);
    700  1.1  jdolecek 	mutex_init(&sc->sc_ccb_mtx, MUTEX_DEFAULT, IPL_BIO);
    701  1.1  jdolecek 
    702  1.1  jdolecek 	/* Get adapter info */
    703  1.1  jdolecek 	if (ips_getadapterinfo(sc, XS_CTL_NOSLEEP)) {
    704  1.1  jdolecek 		printf(": can't get adapter info\n");
    705  1.1  jdolecek 		goto fail4;
    706  1.1  jdolecek 	}
    707  1.1  jdolecek 
    708  1.1  jdolecek 	/* Get logical drives info */
    709  1.1  jdolecek 	if (ips_getdriveinfo(sc, XS_CTL_NOSLEEP)) {
    710  1.1  jdolecek 		printf(": can't get ld info\n");
    711  1.1  jdolecek 		goto fail4;
    712  1.1  jdolecek 	}
    713  1.1  jdolecek 	sc->sc_nunits = di->drivecnt;
    714  1.1  jdolecek 
    715  1.1  jdolecek 	/* Get configuration */
    716  1.1  jdolecek 	if (ips_getconf(sc, XS_CTL_NOSLEEP)) {
    717  1.1  jdolecek 		printf(": can't get config\n");
    718  1.1  jdolecek 		goto fail4;
    719  1.1  jdolecek 	}
    720  1.1  jdolecek 
    721  1.1  jdolecek 	/* Read NVRAM page 5 for additional info */
    722  1.1  jdolecek 	(void)ips_getpg5(sc, XS_CTL_NOSLEEP);
    723  1.1  jdolecek 
    724  1.1  jdolecek 	/* Initialize CCB queue */
    725  1.1  jdolecek 	sc->sc_nccbs = ai->cmdcnt;
    726  1.1  jdolecek 	if ((sc->sc_ccb = ips_ccb_alloc(sc, sc->sc_nccbs)) == NULL) {
    727  1.1  jdolecek 		printf(": can't alloc ccb queue\n");
    728  1.1  jdolecek 		goto fail4;
    729  1.1  jdolecek 	}
    730  1.1  jdolecek 	SLIST_INIT(&sc->sc_ccbq_free);
    731  1.1  jdolecek 	for (i = 0; i < sc->sc_nccbs; i++)
    732  1.1  jdolecek 		SLIST_INSERT_HEAD(&sc->sc_ccbq_free,
    733  1.1  jdolecek 		    &sc->sc_ccb[i], c_link);
    734  1.1  jdolecek 
    735  1.1  jdolecek 	/* Install interrupt handler */
    736  1.1  jdolecek 	if (pci_intr_map(pa, &ih)) {
    737  1.1  jdolecek 		printf(": can't map interrupt\n");
    738  1.1  jdolecek 		goto fail5;
    739  1.1  jdolecek 	}
    740  1.1  jdolecek 	intrstr = pci_intr_string(pa->pa_pc, ih, intrbuf, sizeof(intrbuf));
    741  1.1  jdolecek 	if (pci_intr_establish_xname(pa->pa_pc, ih, IPL_BIO, ips_intr, sc,
    742  1.5  riastrad 		device_xname(sc->sc_dev)) == NULL) {
    743  1.1  jdolecek 		printf(": can't establish interrupt");
    744  1.1  jdolecek 		if (intrstr != NULL)
    745  1.1  jdolecek 			printf(" at %s", intrstr);
    746  1.1  jdolecek 		printf("\n");
    747  1.1  jdolecek 		goto fail5;
    748  1.1  jdolecek 	}
    749  1.1  jdolecek 	printf(": %s\n", intrstr);
    750  1.1  jdolecek 
    751  1.1  jdolecek 	/* Display adapter info */
    752  1.5  riastrad 	device_printf(sc->sc_dev, "ServeRAID");
    753  1.1  jdolecek 	type = htole16(pg5->type);
    754  1.1  jdolecek 	if (type < sizeof(ips_names) / sizeof(ips_names[0]) && ips_names[type])
    755  1.1  jdolecek 		printf(" %s", ips_names[type]);
    756  1.1  jdolecek 	printf(", FW %c%c%c%c%c%c%c", ai->firmware[0], ai->firmware[1],
    757  1.1  jdolecek 	    ai->firmware[2], ai->firmware[3], ai->firmware[4], ai->firmware[5],
    758  1.1  jdolecek 	    ai->firmware[6]);
    759  1.1  jdolecek 	printf(", BIOS %c%c%c%c%c%c%c", ai->bios[0], ai->bios[1], ai->bios[2],
    760  1.1  jdolecek 	    ai->bios[3], ai->bios[4], ai->bios[5], ai->bios[6]);
    761  1.1  jdolecek 	printf(", %d cmds, %d LD%s", sc->sc_nccbs, sc->sc_nunits,
    762  1.1  jdolecek 	    (sc->sc_nunits == 1 ? "" : "s"));
    763  1.1  jdolecek 	printf("\n");
    764  1.1  jdolecek 
    765  1.1  jdolecek 	/*
    766  1.1  jdolecek 	 * Attach to scsipi.
    767  1.1  jdolecek 	 */
    768  1.1  jdolecek 	adapt = &sc->sc_adapt;
    769  1.1  jdolecek 	memset(adapt, 0, sizeof(*adapt));
    770  1.1  jdolecek 	adapt->adapt_dev = self;
    771  1.1  jdolecek 	adapt->adapt_nchannels = IPS_MAXCHANS;
    772  1.1  jdolecek 	if (sc->sc_nunits > 0)
    773  1.1  jdolecek 		adapt->adapt_openings = sc->sc_nccbs / sc->sc_nunits;
    774  1.1  jdolecek 	adapt->adapt_max_periph = adapt->adapt_openings;
    775  1.1  jdolecek 	adapt->adapt_request = ips_scsipi_request;
    776  1.1  jdolecek 	adapt->adapt_minphys = minphys;
    777  1.1  jdolecek 	adapt->adapt_ioctl = ips_scsi_ioctl;
    778  1.1  jdolecek 
    779  1.1  jdolecek 	/* For each channel attach SCSI pass-through bus */
    780  1.1  jdolecek 	for (i = 0; i < IPS_MAXCHANS; i++) {
    781  1.1  jdolecek 		struct ips_pt *pt;
    782  1.1  jdolecek 		int target, lastarget;
    783  1.1  jdolecek 
    784  1.1  jdolecek 		pt = &sc->sc_pt[i];
    785  1.1  jdolecek 		pt->pt_sc = sc;
    786  1.1  jdolecek 		pt->pt_nchan = i;
    787  1.1  jdolecek 		pt->pt_proctgt = -1;
    788  1.1  jdolecek 
    789  1.1  jdolecek 		/* Check if channel has any devices besides disks */
    790  1.1  jdolecek 		for (target = 0, lastarget = -1; target < IPS_MAXTARGETS;
    791  1.1  jdolecek 		    target++) {
    792  1.1  jdolecek 			struct ips_dev *idev;
    793  1.1  jdolecek 			int dev_type;
    794  1.1  jdolecek 
    795  1.1  jdolecek 			idev = &sc->sc_info->conf.dev[i][target];
    796  1.1  jdolecek 			dev_type = idev->params & SID_TYPE;
    797  1.1  jdolecek 			if (idev->state && dev_type != T_DIRECT) {
    798  1.1  jdolecek 				lastarget = target;
    799  1.1  jdolecek 				if (type == T_PROCESSOR ||
    800  1.1  jdolecek 				    type == T_ENCLOSURE)
    801  1.1  jdolecek 					/* remember enclosure address */
    802  1.1  jdolecek 					pt->pt_proctgt = target;
    803  1.1  jdolecek 			}
    804  1.1  jdolecek 		}
    805  1.1  jdolecek 		if (lastarget == -1)
    806  1.1  jdolecek 			continue;
    807  1.1  jdolecek 
    808  1.1  jdolecek 		chan = &pt->pt_chan;
    809  1.1  jdolecek 		memset(chan, 0, sizeof(*chan));
    810  1.1  jdolecek 		chan->chan_adapter = adapt;
    811  1.1  jdolecek 		chan->chan_bustype = &scsi_bustype;
    812  1.1  jdolecek 		chan->chan_channel = i;
    813  1.1  jdolecek 		chan->chan_ntargets = IPS_MAXTARGETS;
    814  1.1  jdolecek 		chan->chan_nluns = lastarget + 1;
    815  1.1  jdolecek 		chan->chan_id = i;
    816  1.1  jdolecek 		chan->chan_flags = SCSIPI_CHAN_NOSETTLE;
    817  1.4   thorpej 		config_found(self, chan, scsiprint, CFARGS_NONE);
    818  1.1  jdolecek 	}
    819  1.1  jdolecek 
    820  1.1  jdolecek 	/* Enable interrupts */
    821  1.1  jdolecek 	ips_intren(sc);
    822  1.1  jdolecek 
    823  1.1  jdolecek #if NBIO > 0
    824  1.1  jdolecek 	/* Install ioctl handler */
    825  1.6  riastrad 	if (bio_register(sc->sc_dev, ips_ioctl))
    826  1.5  riastrad 		device_printf(sc->sc_dev, "no ioctl support\n");
    827  1.1  jdolecek #endif
    828  1.1  jdolecek 
    829  1.1  jdolecek 	return;
    830  1.1  jdolecek fail5:
    831  1.1  jdolecek 	ips_ccb_free(sc, sc->sc_ccb, sc->sc_nccbs);
    832  1.1  jdolecek fail4:
    833  1.1  jdolecek 	if (sc->sc_chip->ic_id == IPS_CHIP_COPPERHEAD)
    834  1.1  jdolecek 		ips_dmamem_free(&sc->sc_sqm);
    835  1.1  jdolecek fail3:
    836  1.1  jdolecek 	ips_dmamem_free(&sc->sc_infom);
    837  1.1  jdolecek fail2:
    838  1.1  jdolecek 	ips_dmamem_free(&sc->sc_cmdbm);
    839  1.1  jdolecek fail1:
    840  1.1  jdolecek 	bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize);
    841  1.1  jdolecek }
    842  1.1  jdolecek 
    843  1.1  jdolecek void
    844  1.1  jdolecek ips_scsi_cmd(struct ips_ccb *ccb)
    845  1.1  jdolecek {
    846  1.1  jdolecek 	struct scsipi_xfer *xs = ccb->c_xfer;
    847  1.1  jdolecek 	struct scsipi_periph *periph = xs->xs_periph;
    848  1.1  jdolecek 	struct scsipi_channel *chan = periph->periph_channel;
    849  1.1  jdolecek 	struct ips_softc *sc = device_private(chan->chan_adapter->adapt_dev);
    850  1.1  jdolecek 	struct ips_driveinfo *di = &sc->sc_info->drive;
    851  1.1  jdolecek 	struct ips_drive *drive;
    852  1.1  jdolecek 	struct ips_cmd *cmd;
    853  1.1  jdolecek 	int target = periph->periph_target;
    854  1.1  jdolecek 	u_int32_t blkno, blkcnt;
    855  1.1  jdolecek 	int code;
    856  1.1  jdolecek 
    857  1.1  jdolecek 	DPRINTF(IPS_D_XFER, ("%s: ips_scsi_cmd: xs %p, target %d, "
    858  1.5  riastrad 	    "opcode 0x%02x, flags 0x%x\n", device_xname(sc->sc_dev), xs, target,
    859  1.1  jdolecek 	    xs->cmd->opcode, xs->xs_control));
    860  1.1  jdolecek 
    861  1.1  jdolecek 	if (target >= sc->sc_nunits || periph->periph_lun != 0) {
    862  1.1  jdolecek 		DPRINTF(IPS_D_INFO, ("%s: ips_scsi_cmd: invalid params "
    863  1.5  riastrad 		    "target %d, lun %d\n", device_xname(sc->sc_dev),
    864  1.1  jdolecek 		    target, periph->periph_lun));
    865  1.1  jdolecek 		xs->error = XS_DRIVER_STUFFUP;
    866  1.1  jdolecek 		ips_ccb_put(sc, ccb);
    867  1.1  jdolecek 		scsipi_done(xs);
    868  1.1  jdolecek 		return;
    869  1.1  jdolecek 	}
    870  1.1  jdolecek 
    871  1.1  jdolecek 	drive = &di->drive[target];
    872  1.1  jdolecek 	xs->error = XS_NOERROR;
    873  1.1  jdolecek 
    874  1.1  jdolecek 	/* Fake SCSI commands */
    875  1.1  jdolecek 	switch (xs->cmd->opcode) {
    876  1.1  jdolecek 	case READ_10:
    877  1.1  jdolecek 	case SCSI_READ_6_COMMAND:
    878  1.1  jdolecek 	case WRITE_10:
    879  1.1  jdolecek 	case SCSI_WRITE_6_COMMAND: {
    880  1.1  jdolecek 		struct scsi_rw_6 *rw;
    881  1.1  jdolecek 		struct scsipi_rw_10 *rwb;
    882  1.1  jdolecek 
    883  1.1  jdolecek 		if (xs->cmdlen == sizeof(struct scsi_rw_6)) {
    884  1.1  jdolecek 			rw = (void *)xs->cmd;
    885  1.1  jdolecek 			blkno = _3btol(rw->addr) &
    886  1.1  jdolecek 			    (SRW_TOPADDR << 16 | 0xffff);
    887  1.1  jdolecek 			blkcnt = rw->length ? rw->length : 0x100;
    888  1.1  jdolecek 		} else {
    889  1.1  jdolecek 			rwb = (void *)xs->cmd;
    890  1.1  jdolecek 			blkno = _4btol(rwb->addr);
    891  1.1  jdolecek 			blkcnt = _2btol(rwb->length);
    892  1.1  jdolecek 		}
    893  1.1  jdolecek 
    894  1.1  jdolecek 		if (blkno >= htole32(drive->seccnt) || blkno + blkcnt >
    895  1.1  jdolecek 		    htole32(drive->seccnt)) {
    896  1.1  jdolecek 			DPRINTF(IPS_D_ERR, ("%s: ips_scsi_cmd: invalid params "
    897  1.5  riastrad 			    "blkno %u, blkcnt %u\n", device_xname(sc->sc_dev),
    898  1.1  jdolecek 			    blkno, blkcnt));
    899  1.1  jdolecek 			xs->error = XS_DRIVER_STUFFUP;
    900  1.1  jdolecek 			break;
    901  1.1  jdolecek 		}
    902  1.1  jdolecek 
    903  1.1  jdolecek 		if (xs->xs_control & XS_CTL_DATA_IN)
    904  1.1  jdolecek 			code = IPS_CMD_READ;
    905  1.1  jdolecek 		else
    906  1.1  jdolecek 			code = IPS_CMD_WRITE;
    907  1.1  jdolecek 
    908  1.1  jdolecek 		cmd = ccb->c_cmdbva;
    909  1.1  jdolecek 		cmd->code = code;
    910  1.1  jdolecek 		cmd->drive = target;
    911  1.1  jdolecek 		cmd->lba = htole32(blkno);
    912  1.1  jdolecek 		cmd->seccnt = htole16(blkcnt);
    913  1.1  jdolecek 
    914  1.1  jdolecek 		if (ips_load_xs(sc, ccb, xs)) {
    915  1.1  jdolecek 			DPRINTF(IPS_D_ERR, ("%s: ips_scsi_cmd: ips_load_xs "
    916  1.5  riastrad 			    "failed\n", device_xname(sc->sc_dev)));
    917  1.1  jdolecek 			xs->error = XS_DRIVER_STUFFUP;
    918  1.1  jdolecek 			ips_ccb_put(sc, ccb);
    919  1.1  jdolecek 			scsipi_done(xs);
    920  1.1  jdolecek 			return;
    921  1.1  jdolecek 		}
    922  1.1  jdolecek 
    923  1.1  jdolecek 		if (cmd->sgcnt > 0)
    924  1.1  jdolecek 			cmd->code |= IPS_CMD_SG;
    925  1.1  jdolecek 
    926  1.1  jdolecek 		ccb->c_done = ips_done_xs;
    927  1.1  jdolecek 		ips_start_xs(sc, ccb, xs);
    928  1.1  jdolecek 		return;
    929  1.1  jdolecek 	}
    930  1.1  jdolecek 	case INQUIRY: {
    931  1.1  jdolecek 		struct scsipi_inquiry_data inq;
    932  1.1  jdolecek 
    933  1.1  jdolecek 		bzero(&inq, sizeof(inq));
    934  1.1  jdolecek 		inq.device = T_DIRECT;
    935  1.1  jdolecek 		inq.version = 2;
    936  1.1  jdolecek 		inq.response_format = 2;
    937  1.1  jdolecek 		inq.additional_length = 32;
    938  1.1  jdolecek 		inq.flags3 |= SID_CmdQue;
    939  1.1  jdolecek 		strlcpy(inq.vendor, "IBM", sizeof(inq.vendor));
    940  1.1  jdolecek 		snprintf(inq.product, sizeof(inq.product),
    941  1.1  jdolecek 		    "LD%d RAID%d", target, drive->raid);
    942  1.1  jdolecek 		strlcpy(inq.revision, "1.0", sizeof(inq.revision));
    943  1.1  jdolecek 		memcpy(xs->data, &inq, MIN(xs->datalen, sizeof(inq)));
    944  1.1  jdolecek 		break;
    945  1.1  jdolecek 	}
    946  1.1  jdolecek 	case READ_CAPACITY_10: {
    947  1.1  jdolecek 		struct scsipi_read_capacity_10_data rcd;
    948  1.1  jdolecek 
    949  1.1  jdolecek 		bzero(&rcd, sizeof(rcd));
    950  1.1  jdolecek 		_lto4b(htole32(drive->seccnt) - 1, rcd.addr);
    951  1.1  jdolecek 		_lto4b(IPS_SECSZ, rcd.length);
    952  1.1  jdolecek 		memcpy(xs->data, &rcd, MIN(xs->datalen, sizeof(rcd)));
    953  1.1  jdolecek 		break;
    954  1.1  jdolecek 	}
    955  1.1  jdolecek 	case SCSI_REQUEST_SENSE: {
    956  1.1  jdolecek 		struct scsi_sense_data sd;
    957  1.1  jdolecek 
    958  1.1  jdolecek 		bzero(&sd, sizeof(sd));
    959  1.1  jdolecek 		sd.response_code = SSD_RCODE_CURRENT;
    960  1.1  jdolecek 		sd.flags = SKEY_NO_SENSE;
    961  1.1  jdolecek 		memcpy(xs->data, &sd, MIN(xs->datalen, sizeof(sd)));
    962  1.1  jdolecek 		break;
    963  1.1  jdolecek 	}
    964  1.1  jdolecek 	case SCSI_SYNCHRONIZE_CACHE_10:
    965  1.1  jdolecek 		cmd = ccb->c_cmdbva;
    966  1.1  jdolecek 		cmd->code = IPS_CMD_FLUSH;
    967  1.1  jdolecek 
    968  1.1  jdolecek 		ccb->c_done = ips_done_xs;
    969  1.1  jdolecek 		ips_start_xs(sc, ccb, xs);
    970  1.1  jdolecek 		return;
    971  1.1  jdolecek 	case SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL:
    972  1.1  jdolecek 	case START_STOP:
    973  1.1  jdolecek 	case SCSI_TEST_UNIT_READY:
    974  1.1  jdolecek 		break;
    975  1.1  jdolecek 	default:
    976  1.1  jdolecek 		DPRINTF(IPS_D_INFO, ("%s: unsupported scsi command 0x%02x\n",
    977  1.5  riastrad 		    device_xname(sc->sc_dev), xs->cmd->opcode));
    978  1.1  jdolecek 		xs->error = XS_DRIVER_STUFFUP;
    979  1.1  jdolecek 	}
    980  1.1  jdolecek 
    981  1.1  jdolecek 	ips_ccb_put(sc, ccb);
    982  1.1  jdolecek 	scsipi_done(xs);
    983  1.1  jdolecek }
    984  1.1  jdolecek 
    985  1.1  jdolecek /*
    986  1.1  jdolecek  * Start a SCSI command.
    987  1.1  jdolecek  */
    988  1.1  jdolecek static void
    989  1.1  jdolecek ips_scsipi_request(struct scsipi_channel *chan, scsipi_adapter_req_t req,
    990  1.1  jdolecek 		   void *arg)
    991  1.1  jdolecek {
    992  1.1  jdolecek 	switch (req) {
    993  1.1  jdolecek 	case ADAPTER_REQ_RUN_XFER: {
    994  1.1  jdolecek 		struct ips_ccb *ccb;
    995  1.1  jdolecek 		struct scsipi_xfer *xs;
    996  1.1  jdolecek 		struct ips_softc *sc;
    997  1.1  jdolecek 
    998  1.1  jdolecek 		sc = device_private(chan->chan_adapter->adapt_dev);
    999  1.1  jdolecek 		xs = (struct scsipi_xfer *)arg;
   1000  1.1  jdolecek 
   1001  1.1  jdolecek 		if ((ccb = ips_ccb_get(sc)) == NULL) {
   1002  1.1  jdolecek 			xs->error = XS_RESOURCE_SHORTAGE;
   1003  1.1  jdolecek 			scsipi_done(xs);
   1004  1.1  jdolecek 			break;
   1005  1.1  jdolecek 		}
   1006  1.1  jdolecek 
   1007  1.1  jdolecek 		ccb->c_xfer = xs;
   1008  1.1  jdolecek 		ips_scsi_cmd(ccb);
   1009  1.1  jdolecek 
   1010  1.1  jdolecek 		break;
   1011  1.1  jdolecek 	}
   1012  1.1  jdolecek 
   1013  1.1  jdolecek 	case ADAPTER_REQ_SET_XFER_MODE: {
   1014  1.1  jdolecek 		struct scsipi_xfer_mode *xm = arg;
   1015  1.1  jdolecek 		xm->xm_mode = PERIPH_CAP_TQING;
   1016  1.1  jdolecek 		xm->xm_period = 0;
   1017  1.1  jdolecek 		xm->xm_offset = 0;
   1018  1.1  jdolecek 		scsipi_async_event(chan, ASYNC_EVENT_XFER_MODE, xm);
   1019  1.1  jdolecek 		return;
   1020  1.1  jdolecek 	}
   1021  1.1  jdolecek 
   1022  1.1  jdolecek 	case ADAPTER_REQ_GROW_RESOURCES:
   1023  1.1  jdolecek 		/*
   1024  1.1  jdolecek 		 * Not supported.
   1025  1.1  jdolecek 		 */
   1026  1.1  jdolecek 		break;
   1027  1.1  jdolecek 	}
   1028  1.1  jdolecek }
   1029  1.1  jdolecek 
   1030  1.1  jdolecek int
   1031  1.1  jdolecek ips_scsi_ioctl(struct scsipi_channel *chan, u_long cmd, void *data,
   1032  1.1  jdolecek     int flag, struct proc *p)
   1033  1.1  jdolecek {
   1034  1.1  jdolecek #if NBIO > 0
   1035  1.1  jdolecek 	return (ips_ioctl(chan->chan_adapter->adapt_dev, cmd, data));
   1036  1.1  jdolecek #else
   1037  1.1  jdolecek 	return (ENOTTY);
   1038  1.1  jdolecek #endif
   1039  1.1  jdolecek }
   1040  1.1  jdolecek 
   1041  1.1  jdolecek #if NBIO > 0
   1042  1.1  jdolecek int
   1043  1.1  jdolecek ips_ioctl(device_t dev, u_long cmd, void *data)
   1044  1.1  jdolecek {
   1045  1.7       chs 	struct ips_softc *sc = device_private(dev);
   1046  1.1  jdolecek 
   1047  1.1  jdolecek 	DPRINTF(IPS_D_INFO, ("%s: ips_ioctl: cmd %lu\n",
   1048  1.5  riastrad 	    device_xname(sc->sc_dev), cmd));
   1049  1.1  jdolecek 
   1050  1.1  jdolecek 	switch (cmd) {
   1051  1.1  jdolecek 	case BIOCINQ:
   1052  1.1  jdolecek 		return (ips_ioctl_inq(sc, (struct bioc_inq *)data));
   1053  1.1  jdolecek 	case BIOCVOL:
   1054  1.1  jdolecek 		return (ips_ioctl_vol(sc, (struct bioc_vol *)data));
   1055  1.1  jdolecek 	case BIOCDISK:
   1056  1.1  jdolecek 		return (ips_ioctl_disk(sc, (struct bioc_disk *)data));
   1057  1.1  jdolecek 	case BIOCSETSTATE:
   1058  1.1  jdolecek 		return (ips_ioctl_setstate(sc, (struct bioc_setstate *)data));
   1059  1.1  jdolecek 	default:
   1060  1.1  jdolecek 		return (ENOTTY);
   1061  1.1  jdolecek 	}
   1062  1.1  jdolecek }
   1063  1.1  jdolecek 
   1064  1.1  jdolecek int
   1065  1.1  jdolecek ips_ioctl_inq(struct ips_softc *sc, struct bioc_inq *bi)
   1066  1.1  jdolecek {
   1067  1.1  jdolecek 	struct ips_conf *conf = &sc->sc_info->conf;
   1068  1.1  jdolecek 	int i;
   1069  1.1  jdolecek 
   1070  1.5  riastrad 	strlcpy(bi->bi_dev, device_xname(sc->sc_dev), sizeof(bi->bi_dev));
   1071  1.1  jdolecek 	bi->bi_novol = sc->sc_nunits;
   1072  1.1  jdolecek 	for (i = 0, bi->bi_nodisk = 0; i < sc->sc_nunits; i++)
   1073  1.1  jdolecek 		bi->bi_nodisk += conf->ld[i].chunkcnt;
   1074  1.1  jdolecek 
   1075  1.1  jdolecek 	DPRINTF(IPS_D_INFO, ("%s: ips_ioctl_inq: novol %d, nodisk %d\n",
   1076  1.1  jdolecek 	    bi->bi_dev, bi->bi_novol, bi->bi_nodisk));
   1077  1.1  jdolecek 
   1078  1.1  jdolecek 	return (0);
   1079  1.1  jdolecek }
   1080  1.1  jdolecek 
   1081  1.1  jdolecek int
   1082  1.1  jdolecek ips_ioctl_vol(struct ips_softc *sc, struct bioc_vol *bv)
   1083  1.1  jdolecek {
   1084  1.1  jdolecek 	struct ips_driveinfo *di = &sc->sc_info->drive;
   1085  1.1  jdolecek 	struct ips_conf *conf = &sc->sc_info->conf;
   1086  1.1  jdolecek 	struct ips_rblstat *rblstat = &sc->sc_info->rblstat;
   1087  1.1  jdolecek 	struct ips_ld *ld;
   1088  1.1  jdolecek 	int vid = bv->bv_volid;
   1089  1.7       chs 	device_t dv;
   1090  1.1  jdolecek 	int error, rebuild = 0;
   1091  1.1  jdolecek 	u_int32_t total = 0, done = 0;
   1092  1.1  jdolecek 
   1093  1.1  jdolecek 	if (vid >= sc->sc_nunits)
   1094  1.1  jdolecek 		return (EINVAL);
   1095  1.1  jdolecek 	if ((error = ips_getconf(sc, 0)))
   1096  1.1  jdolecek 		return (error);
   1097  1.1  jdolecek 	ld = &conf->ld[vid];
   1098  1.1  jdolecek 
   1099  1.1  jdolecek 	switch (ld->state) {
   1100  1.1  jdolecek 	case IPS_DS_ONLINE:
   1101  1.1  jdolecek 		bv->bv_status = BIOC_SVONLINE;
   1102  1.1  jdolecek 		break;
   1103  1.1  jdolecek 	case IPS_DS_DEGRADED:
   1104  1.1  jdolecek 		bv->bv_status = BIOC_SVDEGRADED;
   1105  1.1  jdolecek 		rebuild++;
   1106  1.1  jdolecek 		break;
   1107  1.1  jdolecek 	case IPS_DS_OFFLINE:
   1108  1.1  jdolecek 		bv->bv_status = BIOC_SVOFFLINE;
   1109  1.1  jdolecek 		break;
   1110  1.1  jdolecek 	default:
   1111  1.1  jdolecek 		bv->bv_status = BIOC_SVINVALID;
   1112  1.1  jdolecek 	}
   1113  1.1  jdolecek 
   1114  1.1  jdolecek 	if (rebuild && ips_getrblstat(sc, 0) == 0) {
   1115  1.1  jdolecek 		total = htole32(rblstat->ld[vid].total);
   1116  1.1  jdolecek 		done = total - htole32(rblstat->ld[vid].remain);
   1117  1.1  jdolecek 		if (total && total > done) {
   1118  1.1  jdolecek 			bv->bv_status = BIOC_SVREBUILD;
   1119  1.1  jdolecek 			bv->bv_percent = 100 * done / total;
   1120  1.1  jdolecek 		}
   1121  1.1  jdolecek 	}
   1122  1.1  jdolecek 
   1123  1.1  jdolecek 	bv->bv_size = (uint64_t)htole32(ld->size) * IPS_SECSZ;
   1124  1.1  jdolecek 	bv->bv_level = di->drive[vid].raid;
   1125  1.1  jdolecek 	bv->bv_nodisk = ld->chunkcnt;
   1126  1.1  jdolecek 
   1127  1.1  jdolecek 	/* Associate all unused and spare drives with first volume */
   1128  1.1  jdolecek 	if (vid == 0) {
   1129  1.1  jdolecek 		struct ips_dev *dev;
   1130  1.1  jdolecek 		int chan, target;
   1131  1.1  jdolecek 
   1132  1.1  jdolecek 		for (chan = 0; chan < IPS_MAXCHANS; chan++)
   1133  1.1  jdolecek 			for (target = 0; target < IPS_MAXTARGETS; target++) {
   1134  1.1  jdolecek 				dev = &conf->dev[chan][target];
   1135  1.1  jdolecek 				if (dev->state && !(dev->state &
   1136  1.1  jdolecek 				    IPS_DVS_MEMBER) &&
   1137  1.1  jdolecek 				    (dev->params & SID_TYPE) == T_DIRECT)
   1138  1.1  jdolecek 					bv->bv_nodisk++;
   1139  1.1  jdolecek 			}
   1140  1.1  jdolecek 	}
   1141  1.1  jdolecek 
   1142  1.6  riastrad 	dv = sc->sc_dev;
   1143  1.5  riastrad 	strlcpy(bv->bv_dev, device_xname(dv), sizeof(bv->bv_dev));
   1144  1.1  jdolecek 	strlcpy(bv->bv_vendor, "IBM", sizeof(bv->bv_vendor));
   1145  1.1  jdolecek 
   1146  1.1  jdolecek 	DPRINTF(IPS_D_INFO, ("%s: ips_ioctl_vol: vid %d, state 0x%02x, "
   1147  1.1  jdolecek 	    "total %u, done %u, size %llu, level %d, nodisk %d, dev %s\n",
   1148  1.5  riastrad 	    device_xname(sc->sc_dev), vid, ld->state, total, done, bv->bv_size,
   1149  1.1  jdolecek 	    bv->bv_level, bv->bv_nodisk, bv->bv_dev));
   1150  1.1  jdolecek 
   1151  1.1  jdolecek 	return (0);
   1152  1.1  jdolecek }
   1153  1.1  jdolecek 
   1154  1.1  jdolecek int
   1155  1.1  jdolecek ips_ioctl_disk(struct ips_softc *sc, struct bioc_disk *bd)
   1156  1.1  jdolecek {
   1157  1.1  jdolecek 	struct ips_conf *conf = &sc->sc_info->conf;
   1158  1.1  jdolecek 	struct ips_ld *ld;
   1159  1.1  jdolecek 	struct ips_chunk *chunk;
   1160  1.1  jdolecek 	struct ips_dev *dev;
   1161  1.1  jdolecek 	int vid = bd->bd_volid, did = bd->bd_diskid;
   1162  1.1  jdolecek 	int chan, target, error, i;
   1163  1.1  jdolecek 
   1164  1.1  jdolecek 	if (vid >= sc->sc_nunits)
   1165  1.1  jdolecek 		return (EINVAL);
   1166  1.1  jdolecek 	if ((error = ips_getconf(sc, 0)))
   1167  1.1  jdolecek 		return (error);
   1168  1.1  jdolecek 	ld = &conf->ld[vid];
   1169  1.1  jdolecek 
   1170  1.1  jdolecek 	if (did >= ld->chunkcnt) {
   1171  1.1  jdolecek 		/* Probably unused or spare drives */
   1172  1.1  jdolecek 		if (vid != 0)
   1173  1.1  jdolecek 			return (EINVAL);
   1174  1.1  jdolecek 
   1175  1.1  jdolecek 		i = ld->chunkcnt;
   1176  1.1  jdolecek 		for (chan = 0; chan < IPS_MAXCHANS; chan++)
   1177  1.1  jdolecek 			for (target = 0; target < IPS_MAXTARGETS; target++) {
   1178  1.1  jdolecek 				dev = &conf->dev[chan][target];
   1179  1.1  jdolecek 				if (dev->state && !(dev->state &
   1180  1.1  jdolecek 				    IPS_DVS_MEMBER) &&
   1181  1.1  jdolecek 				    (dev->params & SID_TYPE) == T_DIRECT)
   1182  1.1  jdolecek 					if (i++ == did)
   1183  1.1  jdolecek 						goto out;
   1184  1.1  jdolecek 			}
   1185  1.1  jdolecek 	} else {
   1186  1.1  jdolecek 		chunk = &ld->chunk[did];
   1187  1.1  jdolecek 		chan = chunk->channel;
   1188  1.1  jdolecek 		target = chunk->target;
   1189  1.1  jdolecek 	}
   1190  1.1  jdolecek 
   1191  1.1  jdolecek out:
   1192  1.1  jdolecek 	if (chan >= IPS_MAXCHANS || target >= IPS_MAXTARGETS)
   1193  1.1  jdolecek 		return (EINVAL);
   1194  1.1  jdolecek 	dev = &conf->dev[chan][target];
   1195  1.1  jdolecek 
   1196  1.1  jdolecek 	bd->bd_channel = chan;
   1197  1.1  jdolecek 	bd->bd_target = target;
   1198  1.1  jdolecek 	bd->bd_lun = 0;
   1199  1.1  jdolecek 	bd->bd_size = (uint64_t)htole32(dev->seccnt) * IPS_SECSZ;
   1200  1.1  jdolecek 
   1201  1.1  jdolecek 	bzero(bd->bd_vendor, sizeof(bd->bd_vendor));
   1202  1.1  jdolecek 	memcpy(bd->bd_vendor, dev->devid, MIN(sizeof(bd->bd_vendor),
   1203  1.1  jdolecek 	    sizeof(dev->devid)));
   1204  1.1  jdolecek 	strlcpy(bd->bd_procdev, sc->sc_pt[chan].pt_procdev,
   1205  1.1  jdolecek 	    sizeof(bd->bd_procdev));
   1206  1.1  jdolecek 
   1207  1.1  jdolecek 	if (dev->state & IPS_DVS_READY) {
   1208  1.1  jdolecek 		bd->bd_status = BIOC_SDUNUSED;
   1209  1.1  jdolecek 		if (dev->state & IPS_DVS_MEMBER)
   1210  1.1  jdolecek 			bd->bd_status = BIOC_SDONLINE;
   1211  1.1  jdolecek 		if (dev->state & IPS_DVS_SPARE)
   1212  1.1  jdolecek 			bd->bd_status = BIOC_SDHOTSPARE;
   1213  1.1  jdolecek 		if (dev->state & IPS_DVS_REBUILD)
   1214  1.1  jdolecek 			bd->bd_status = BIOC_SDREBUILD;
   1215  1.1  jdolecek 	} else {
   1216  1.1  jdolecek 		bd->bd_status = BIOC_SDOFFLINE;
   1217  1.1  jdolecek 	}
   1218  1.1  jdolecek 
   1219  1.1  jdolecek 	DPRINTF(IPS_D_INFO, ("%s: ips_ioctl_disk: vid %d, did %d, channel %d, "
   1220  1.5  riastrad 	    "target %d, size %llu, state 0x%02x\n", device_xname(sc->sc_dev),
   1221  1.1  jdolecek 	    vid, did, bd->bd_channel, bd->bd_target, bd->bd_size, dev->state));
   1222  1.1  jdolecek 
   1223  1.1  jdolecek 	return (0);
   1224  1.1  jdolecek }
   1225  1.1  jdolecek 
   1226  1.1  jdolecek int
   1227  1.1  jdolecek ips_ioctl_setstate(struct ips_softc *sc, struct bioc_setstate *bs)
   1228  1.1  jdolecek {
   1229  1.1  jdolecek 	struct ips_conf *conf = &sc->sc_info->conf;
   1230  1.1  jdolecek 	struct ips_dev *dev;
   1231  1.1  jdolecek 	int state, error;
   1232  1.1  jdolecek 
   1233  1.1  jdolecek 	if (bs->bs_channel >= IPS_MAXCHANS || bs->bs_target >= IPS_MAXTARGETS)
   1234  1.1  jdolecek 		return (EINVAL);
   1235  1.1  jdolecek 	if ((error = ips_getconf(sc, 0)))
   1236  1.1  jdolecek 		return (error);
   1237  1.1  jdolecek 	dev = &conf->dev[bs->bs_channel][bs->bs_target];
   1238  1.1  jdolecek 	state = dev->state;
   1239  1.1  jdolecek 
   1240  1.1  jdolecek 	switch (bs->bs_status) {
   1241  1.1  jdolecek 	case BIOC_SSONLINE:
   1242  1.1  jdolecek 		state |= IPS_DVS_READY;
   1243  1.1  jdolecek 		break;
   1244  1.1  jdolecek 	case BIOC_SSOFFLINE:
   1245  1.1  jdolecek 		state &= ~IPS_DVS_READY;
   1246  1.1  jdolecek 		break;
   1247  1.1  jdolecek 	case BIOC_SSHOTSPARE:
   1248  1.1  jdolecek 		state |= IPS_DVS_SPARE;
   1249  1.1  jdolecek 		break;
   1250  1.1  jdolecek 	case BIOC_SSREBUILD:
   1251  1.1  jdolecek 		return (ips_rebuild(sc, bs->bs_channel, bs->bs_target,
   1252  1.1  jdolecek 		    bs->bs_channel, bs->bs_target, 0));
   1253  1.1  jdolecek 	default:
   1254  1.1  jdolecek 		return (EINVAL);
   1255  1.1  jdolecek 	}
   1256  1.1  jdolecek 
   1257  1.1  jdolecek 	return (ips_setstate(sc, bs->bs_channel, bs->bs_target, state, 0));
   1258  1.1  jdolecek }
   1259  1.1  jdolecek #endif	/* NBIO > 0 */
   1260  1.1  jdolecek 
   1261  1.1  jdolecek int
   1262  1.1  jdolecek ips_load_xs(struct ips_softc *sc, struct ips_ccb *ccb, struct scsipi_xfer *xs)
   1263  1.1  jdolecek {
   1264  1.1  jdolecek 	struct ips_cmdb *cmdb = ccb->c_cmdbva;
   1265  1.1  jdolecek 	struct ips_cmd *cmd = &cmdb->cmd;
   1266  1.1  jdolecek 	struct ips_sg *sg = cmdb->sg;
   1267  1.1  jdolecek 	int nsegs, i;
   1268  1.1  jdolecek 
   1269  1.1  jdolecek 	if (xs->datalen == 0)
   1270  1.1  jdolecek 		return (0);
   1271  1.1  jdolecek 
   1272  1.1  jdolecek 	/* Map data buffer into DMA segments */
   1273  1.1  jdolecek 	if (bus_dmamap_load(sc->sc_dmat, ccb->c_dmam, xs->data, xs->datalen,
   1274  1.1  jdolecek 	    NULL, (xs->xs_control & XS_CTL_NOSLEEP ? BUS_DMA_NOWAIT : 0)))
   1275  1.1  jdolecek 		return (1);
   1276  1.1  jdolecek 	bus_dmamap_sync(sc->sc_dmat, ccb->c_dmam, 0,ccb->c_dmam->dm_mapsize,
   1277  1.1  jdolecek 	    xs->xs_control & XS_CTL_DATA_IN ? BUS_DMASYNC_PREREAD :
   1278  1.1  jdolecek 	    BUS_DMASYNC_PREWRITE);
   1279  1.1  jdolecek 
   1280  1.1  jdolecek 	if ((nsegs = ccb->c_dmam->dm_nsegs) > IPS_MAXSGS)
   1281  1.1  jdolecek 		return (1);
   1282  1.1  jdolecek 
   1283  1.1  jdolecek 	if (nsegs > 1) {
   1284  1.1  jdolecek 		cmd->sgcnt = nsegs;
   1285  1.1  jdolecek 		cmd->sgaddr = htole32(ccb->c_cmdbpa + offsetof(struct ips_cmdb,
   1286  1.1  jdolecek 		    sg));
   1287  1.1  jdolecek 
   1288  1.1  jdolecek 		/* Fill in scatter-gather array */
   1289  1.1  jdolecek 		for (i = 0; i < nsegs; i++) {
   1290  1.1  jdolecek 			sg[i].addr = htole32(ccb->c_dmam->dm_segs[i].ds_addr);
   1291  1.1  jdolecek 			sg[i].size = htole32(ccb->c_dmam->dm_segs[i].ds_len);
   1292  1.1  jdolecek 		}
   1293  1.1  jdolecek 	} else {
   1294  1.1  jdolecek 		cmd->sgcnt = 0;
   1295  1.1  jdolecek 		cmd->sgaddr = htole32(ccb->c_dmam->dm_segs[0].ds_addr);
   1296  1.1  jdolecek 	}
   1297  1.1  jdolecek 
   1298  1.1  jdolecek 	return (0);
   1299  1.1  jdolecek }
   1300  1.1  jdolecek 
   1301  1.1  jdolecek void
   1302  1.1  jdolecek ips_start_xs(struct ips_softc *sc, struct ips_ccb *ccb, struct scsipi_xfer *xs)
   1303  1.1  jdolecek {
   1304  1.1  jdolecek 	ccb->c_flags = xs->xs_control;
   1305  1.1  jdolecek 	ccb->c_xfer = xs;
   1306  1.1  jdolecek 	int ispoll = xs->xs_control & XS_CTL_POLL;
   1307  1.1  jdolecek 
   1308  1.1  jdolecek 	if (!ispoll) {
   1309  1.1  jdolecek 		int timeout = mstohz(xs->timeout);
   1310  1.1  jdolecek 		if (timeout == 0)
   1311  1.1  jdolecek 			timeout = 1;
   1312  1.1  jdolecek 
   1313  1.1  jdolecek 		callout_reset(&xs->xs_callout, timeout, ips_timeout, ccb);
   1314  1.1  jdolecek 	}
   1315  1.1  jdolecek 
   1316  1.1  jdolecek 	/*
   1317  1.1  jdolecek 	 * Return value not used here because ips_cmd() must complete
   1318  1.1  jdolecek 	 * scsipi_xfer on any failure and SCSI layer will handle possible
   1319  1.1  jdolecek 	 * errors.
   1320  1.1  jdolecek 	 */
   1321  1.1  jdolecek 	ips_cmd(sc, ccb);
   1322  1.1  jdolecek }
   1323  1.1  jdolecek 
   1324  1.1  jdolecek int
   1325  1.1  jdolecek ips_cmd(struct ips_softc *sc, struct ips_ccb *ccb)
   1326  1.1  jdolecek {
   1327  1.1  jdolecek 	struct ips_cmd *cmd = ccb->c_cmdbva;
   1328  1.1  jdolecek 	int s, error = 0;
   1329  1.1  jdolecek 
   1330  1.1  jdolecek 	DPRINTF(IPS_D_XFER, ("%s: ips_cmd: id 0x%02x, flags 0x%x, xs %p, "
   1331  1.1  jdolecek 	    "code 0x%02x, drive %d, sgcnt %d, lba %d, sgaddr 0x%08x, "
   1332  1.5  riastrad 	    "seccnt %d\n", device_xname(sc->sc_dev), ccb->c_id, ccb->c_flags,
   1333  1.1  jdolecek 	    ccb->c_xfer, cmd->code, cmd->drive, cmd->sgcnt, htole32(cmd->lba),
   1334  1.1  jdolecek 	    htole32(cmd->sgaddr), htole16(cmd->seccnt)));
   1335  1.1  jdolecek 
   1336  1.1  jdolecek 	cmd->id = ccb->c_id;
   1337  1.1  jdolecek 
   1338  1.1  jdolecek 	/* Post command to controller and optionally wait for completion */
   1339  1.1  jdolecek 	s = splbio();
   1340  1.1  jdolecek 	ips_exec(sc, ccb);
   1341  1.1  jdolecek 	ccb->c_state = IPS_CCB_QUEUED;
   1342  1.1  jdolecek 	if (ccb->c_flags & XS_CTL_POLL)
   1343  1.1  jdolecek 		error = ips_poll(sc, ccb);
   1344  1.1  jdolecek 	splx(s);
   1345  1.1  jdolecek 
   1346  1.1  jdolecek 	return (error);
   1347  1.1  jdolecek }
   1348  1.1  jdolecek 
   1349  1.1  jdolecek int
   1350  1.1  jdolecek ips_poll(struct ips_softc *sc, struct ips_ccb *ccb)
   1351  1.1  jdolecek {
   1352  1.1  jdolecek 	struct timeval tv;
   1353  1.1  jdolecek 	int error, timo;
   1354  1.1  jdolecek 
   1355  1.1  jdolecek 	if (ccb->c_flags & XS_CTL_NOSLEEP) {
   1356  1.1  jdolecek 		/* busy-wait */
   1357  1.1  jdolecek 		DPRINTF(IPS_D_XFER, ("%s: ips_poll: busy-wait\n",
   1358  1.5  riastrad 		    device_xname(sc->sc_dev)));
   1359  1.1  jdolecek 
   1360  1.1  jdolecek 		for (timo = 10000; timo > 0; timo--) {
   1361  1.1  jdolecek 			delay(100);
   1362  1.1  jdolecek 			ips_intr(sc);
   1363  1.1  jdolecek 			if (ccb->c_state == IPS_CCB_DONE)
   1364  1.1  jdolecek 				break;
   1365  1.1  jdolecek 		}
   1366  1.1  jdolecek 	} else {
   1367  1.1  jdolecek 		/* sleep */
   1368  1.1  jdolecek 		timo = ccb->c_xfer ? ccb->c_xfer->timeout : IPS_TIMEOUT;
   1369  1.1  jdolecek 		tv.tv_sec = timo / 1000;
   1370  1.1  jdolecek 		tv.tv_usec = (timo % 1000) * 1000;
   1371  1.1  jdolecek 		timo = tvtohz(&tv);
   1372  1.1  jdolecek 
   1373  1.1  jdolecek 		DPRINTF(IPS_D_XFER, ("%s: ips_poll: sleep %d hz\n",
   1374  1.5  riastrad 		    device_xname(sc->sc_dev), timo));
   1375  1.1  jdolecek 		tsleep(ccb, PRIBIO + 1, "ipscmd", timo);
   1376  1.1  jdolecek 	}
   1377  1.5  riastrad 	DPRINTF(IPS_D_XFER, ("%s: ips_poll: state %d\n",
   1378  1.5  riastrad 	    device_xname(sc->sc_dev),
   1379  1.1  jdolecek 	    ccb->c_state));
   1380  1.1  jdolecek 
   1381  1.1  jdolecek 	if (ccb->c_state != IPS_CCB_DONE)
   1382  1.1  jdolecek 		/*
   1383  1.1  jdolecek 		 * Command never completed. Fake hardware status byte
   1384  1.1  jdolecek 		 * to indicate timeout.
   1385  1.1  jdolecek 		 */
   1386  1.1  jdolecek 		ccb->c_stat = IPS_STAT_TIMO;
   1387  1.1  jdolecek 
   1388  1.1  jdolecek 	ips_done(sc, ccb);
   1389  1.1  jdolecek 	error = ccb->c_error;
   1390  1.1  jdolecek 
   1391  1.1  jdolecek 	return (error);
   1392  1.1  jdolecek }
   1393  1.1  jdolecek 
   1394  1.1  jdolecek void
   1395  1.1  jdolecek ips_done(struct ips_softc *sc, struct ips_ccb *ccb)
   1396  1.1  jdolecek {
   1397  1.1  jdolecek 	DPRINTF(IPS_D_XFER, ("%s: ips_done: id 0x%02x, flags 0x%x, xs %p\n",
   1398  1.5  riastrad 	    device_xname(sc->sc_dev), ccb->c_id, ccb->c_flags, ccb->c_xfer));
   1399  1.1  jdolecek 
   1400  1.1  jdolecek 	ccb->c_error = ips_error(sc, ccb);
   1401  1.1  jdolecek 	ccb->c_done(sc, ccb);
   1402  1.1  jdolecek }
   1403  1.1  jdolecek 
   1404  1.1  jdolecek void
   1405  1.1  jdolecek ips_done_xs(struct ips_softc *sc, struct ips_ccb *ccb)
   1406  1.1  jdolecek {
   1407  1.1  jdolecek 	struct scsipi_xfer *xs = ccb->c_xfer;
   1408  1.1  jdolecek 
   1409  1.1  jdolecek 	if (!(xs->xs_control & XS_CTL_POLL))
   1410  1.1  jdolecek 		callout_stop(&xs->xs_callout);
   1411  1.1  jdolecek 
   1412  1.1  jdolecek 	if (xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) {
   1413  1.1  jdolecek 		bus_dmamap_sync(sc->sc_dmat, ccb->c_dmam, 0,
   1414  1.1  jdolecek 		    ccb->c_dmam->dm_mapsize, xs->xs_control & XS_CTL_DATA_IN ?
   1415  1.1  jdolecek 		    BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
   1416  1.1  jdolecek 		bus_dmamap_unload(sc->sc_dmat, ccb->c_dmam);
   1417  1.1  jdolecek 	}
   1418  1.1  jdolecek 
   1419  1.1  jdolecek 	xs->resid = 0;
   1420  1.1  jdolecek 	xs->error = ips_error_xs(sc, ccb);
   1421  1.1  jdolecek 	ips_ccb_put(sc, ccb);
   1422  1.1  jdolecek 	scsipi_done(xs);
   1423  1.1  jdolecek }
   1424  1.1  jdolecek 
   1425  1.1  jdolecek void
   1426  1.1  jdolecek ips_done_pt(struct ips_softc *sc, struct ips_ccb *ccb)
   1427  1.1  jdolecek {
   1428  1.1  jdolecek 	struct scsipi_xfer *xs = ccb->c_xfer;
   1429  1.1  jdolecek 	struct ips_cmdb *cmdb = ccb->c_cmdbva;
   1430  1.1  jdolecek 	struct ips_dcdb *dcdb = &cmdb->dcdb;
   1431  1.1  jdolecek 	int done = htole16(dcdb->datalen);
   1432  1.1  jdolecek 
   1433  1.1  jdolecek 	if (!(xs->xs_control & XS_CTL_POLL))
   1434  1.1  jdolecek 		callout_stop(&xs->xs_callout);
   1435  1.1  jdolecek 
   1436  1.1  jdolecek 	if (xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) {
   1437  1.1  jdolecek 		bus_dmamap_sync(sc->sc_dmat, ccb->c_dmam, 0,
   1438  1.1  jdolecek 		    ccb->c_dmam->dm_mapsize, xs->xs_control & XS_CTL_DATA_IN ?
   1439  1.1  jdolecek 		    BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
   1440  1.1  jdolecek 		bus_dmamap_unload(sc->sc_dmat, ccb->c_dmam);
   1441  1.1  jdolecek 	}
   1442  1.1  jdolecek 
   1443  1.1  jdolecek 	if (done && done < xs->datalen)
   1444  1.1  jdolecek 		xs->resid = xs->datalen - done;
   1445  1.1  jdolecek 	else
   1446  1.1  jdolecek 		xs->resid = 0;
   1447  1.1  jdolecek 	xs->error = ips_error_xs(sc, ccb);
   1448  1.1  jdolecek 	xs->status = dcdb->status;
   1449  1.1  jdolecek 
   1450  1.1  jdolecek 	if (xs->error == XS_SENSE)
   1451  1.1  jdolecek 		memcpy(&xs->sense, dcdb->sense, MIN(sizeof(xs->sense),
   1452  1.1  jdolecek 		    sizeof(dcdb->sense)));
   1453  1.1  jdolecek 
   1454  1.1  jdolecek 	if (xs->cmd->opcode == INQUIRY && xs->error == XS_NOERROR) {
   1455  1.1  jdolecek 		int type = ((struct scsipi_inquiry_data *)xs->data)->device &
   1456  1.1  jdolecek 		    SID_TYPE;
   1457  1.1  jdolecek 
   1458  1.1  jdolecek 		if (type == T_DIRECT)
   1459  1.1  jdolecek 			/* mask physical drives */
   1460  1.1  jdolecek 			xs->error = XS_DRIVER_STUFFUP;
   1461  1.1  jdolecek 	}
   1462  1.1  jdolecek 
   1463  1.1  jdolecek 	ips_ccb_put(sc, ccb);
   1464  1.1  jdolecek 	scsipi_done(xs);
   1465  1.1  jdolecek }
   1466  1.1  jdolecek 
   1467  1.1  jdolecek void
   1468  1.1  jdolecek ips_done_mgmt(struct ips_softc *sc, struct ips_ccb *ccb)
   1469  1.1  jdolecek {
   1470  1.1  jdolecek 	if (ccb->c_flags & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT))
   1471  1.1  jdolecek 		bus_dmamap_sync(sc->sc_dmat, sc->sc_infom.dm_map, 0,
   1472  1.1  jdolecek 		    sc->sc_infom.dm_map->dm_mapsize,
   1473  1.1  jdolecek 		    ccb->c_flags & XS_CTL_DATA_IN ? BUS_DMASYNC_POSTREAD :
   1474  1.1  jdolecek 		    BUS_DMASYNC_POSTWRITE);
   1475  1.1  jdolecek 
   1476  1.1  jdolecek 	ips_ccb_put(sc, ccb);
   1477  1.1  jdolecek }
   1478  1.1  jdolecek 
   1479  1.1  jdolecek int
   1480  1.1  jdolecek ips_error(struct ips_softc *sc, struct ips_ccb *ccb)
   1481  1.1  jdolecek {
   1482  1.1  jdolecek 	struct ips_cmdb *cmdb = ccb->c_cmdbva;
   1483  1.1  jdolecek 	struct ips_cmd *cmd = &cmdb->cmd;
   1484  1.1  jdolecek 	struct ips_dcdb *dcdb = &cmdb->dcdb;
   1485  1.1  jdolecek 	struct scsipi_xfer *xs = ccb->c_xfer;
   1486  1.1  jdolecek 	u_int8_t gsc = IPS_STAT_GSC(ccb->c_stat);
   1487  1.1  jdolecek 
   1488  1.1  jdolecek 	if (gsc == IPS_STAT_OK)
   1489  1.1  jdolecek 		return (0);
   1490  1.1  jdolecek 
   1491  1.1  jdolecek 	DPRINTF(IPS_D_ERR, ("%s: ips_error: stat 0x%02x, estat 0x%02x, "
   1492  1.1  jdolecek 	    "cmd code 0x%02x, drive %d, sgcnt %d, lba %u, seccnt %d",
   1493  1.5  riastrad 	    device_xname(sc->sc_dev), ccb->c_stat, ccb->c_estat, cmd->code,
   1494  1.1  jdolecek 	    cmd->drive, cmd->sgcnt, htole32(cmd->lba), htole16(cmd->seccnt)));
   1495  1.1  jdolecek 	if (cmd->code == IPS_CMD_DCDB || cmd->code == IPS_CMD_DCDB_SG) {
   1496  1.1  jdolecek 		int i;
   1497  1.1  jdolecek 
   1498  1.1  jdolecek 		DPRINTF(IPS_D_ERR, (", dcdb device 0x%02x, attr 0x%02x, "
   1499  1.1  jdolecek 		    "datalen %d, sgcnt %d, status 0x%02x",
   1500  1.1  jdolecek 		    dcdb->device, dcdb->attr, htole16(dcdb->datalen),
   1501  1.1  jdolecek 		    dcdb->sgcnt, dcdb->status));
   1502  1.1  jdolecek 
   1503  1.1  jdolecek 		DPRINTF(IPS_D_ERR, (", cdb"));
   1504  1.1  jdolecek 		for (i = 0; i < dcdb->cdblen; i++)
   1505  1.1  jdolecek 			DPRINTF(IPS_D_ERR, (" %x", dcdb->cdb[i]));
   1506  1.1  jdolecek 		if (ccb->c_estat == IPS_ESTAT_CKCOND) {
   1507  1.1  jdolecek 			DPRINTF(IPS_D_ERR, (", sense"));
   1508  1.1  jdolecek 			for (i = 0; i < dcdb->senselen; i++)
   1509  1.1  jdolecek 				DPRINTF(IPS_D_ERR, (" %x", dcdb->sense[i]));
   1510  1.1  jdolecek 		}
   1511  1.1  jdolecek 	}
   1512  1.1  jdolecek 	DPRINTF(IPS_D_ERR, ("\n"));
   1513  1.1  jdolecek 
   1514  1.1  jdolecek 	switch (gsc) {
   1515  1.1  jdolecek 	case IPS_STAT_RECOV:
   1516  1.1  jdolecek 		return (0);
   1517  1.1  jdolecek 	case IPS_STAT_INVOP:
   1518  1.1  jdolecek 	case IPS_STAT_INVCMD:
   1519  1.1  jdolecek 	case IPS_STAT_INVPARM:
   1520  1.1  jdolecek 		return (EINVAL);
   1521  1.1  jdolecek 	case IPS_STAT_BUSY:
   1522  1.1  jdolecek 		return (EBUSY);
   1523  1.1  jdolecek 	case IPS_STAT_TIMO:
   1524  1.1  jdolecek 		return (ETIMEDOUT);
   1525  1.1  jdolecek 	case IPS_STAT_PDRVERR:
   1526  1.1  jdolecek 		switch (ccb->c_estat) {
   1527  1.1  jdolecek 		case IPS_ESTAT_SELTIMO:
   1528  1.1  jdolecek 			return (ENODEV);
   1529  1.1  jdolecek 		case IPS_ESTAT_OURUN:
   1530  1.1  jdolecek 			if (xs && htole16(dcdb->datalen) < xs->datalen)
   1531  1.1  jdolecek 				/* underrun */
   1532  1.1  jdolecek 				return (0);
   1533  1.1  jdolecek 			break;
   1534  1.1  jdolecek 		case IPS_ESTAT_RECOV:
   1535  1.1  jdolecek 			return (0);
   1536  1.1  jdolecek 		}
   1537  1.1  jdolecek 		break;
   1538  1.1  jdolecek 	}
   1539  1.1  jdolecek 
   1540  1.1  jdolecek 	return (EIO);
   1541  1.1  jdolecek }
   1542  1.1  jdolecek 
   1543  1.1  jdolecek int
   1544  1.1  jdolecek ips_error_xs(struct ips_softc *sc, struct ips_ccb *ccb)
   1545  1.1  jdolecek {
   1546  1.1  jdolecek 	struct ips_cmdb *cmdb = ccb->c_cmdbva;
   1547  1.1  jdolecek 	struct ips_dcdb *dcdb = &cmdb->dcdb;
   1548  1.1  jdolecek 	struct scsipi_xfer *xs = ccb->c_xfer;
   1549  1.1  jdolecek 	u_int8_t gsc = IPS_STAT_GSC(ccb->c_stat);
   1550  1.1  jdolecek 
   1551  1.1  jdolecek 	/* Map hardware error codes to SCSI ones */
   1552  1.1  jdolecek 	switch (gsc) {
   1553  1.1  jdolecek 	case IPS_STAT_OK:
   1554  1.1  jdolecek 	case IPS_STAT_RECOV:
   1555  1.1  jdolecek 		return (XS_NOERROR);
   1556  1.1  jdolecek 	case IPS_STAT_BUSY:
   1557  1.1  jdolecek 		return (XS_BUSY);
   1558  1.1  jdolecek 	case IPS_STAT_TIMO:
   1559  1.1  jdolecek 		return (XS_TIMEOUT);
   1560  1.1  jdolecek 	case IPS_STAT_PDRVERR:
   1561  1.1  jdolecek 		switch (ccb->c_estat) {
   1562  1.1  jdolecek 		case IPS_ESTAT_SELTIMO:
   1563  1.1  jdolecek 			return (XS_SELTIMEOUT);
   1564  1.1  jdolecek 		case IPS_ESTAT_OURUN:
   1565  1.1  jdolecek 			if (xs && htole16(dcdb->datalen) < xs->datalen)
   1566  1.1  jdolecek 				/* underrun */
   1567  1.1  jdolecek 				return (XS_NOERROR);
   1568  1.1  jdolecek 			break;
   1569  1.1  jdolecek 		case IPS_ESTAT_HOSTRST:
   1570  1.1  jdolecek 		case IPS_ESTAT_DEVRST:
   1571  1.1  jdolecek 			return (XS_RESET);
   1572  1.1  jdolecek 		case IPS_ESTAT_RECOV:
   1573  1.1  jdolecek 			return (XS_NOERROR);
   1574  1.1  jdolecek 		case IPS_ESTAT_CKCOND:
   1575  1.1  jdolecek 			return (XS_SENSE);
   1576  1.1  jdolecek 		}
   1577  1.1  jdolecek 		break;
   1578  1.1  jdolecek 	}
   1579  1.1  jdolecek 
   1580  1.1  jdolecek 	return (XS_DRIVER_STUFFUP);
   1581  1.1  jdolecek }
   1582  1.1  jdolecek 
   1583  1.1  jdolecek int
   1584  1.1  jdolecek ips_intr(void *arg)
   1585  1.1  jdolecek {
   1586  1.1  jdolecek 	struct ips_softc *sc = arg;
   1587  1.1  jdolecek 	struct ips_ccb *ccb;
   1588  1.1  jdolecek 	u_int32_t status;
   1589  1.1  jdolecek 	int id;
   1590  1.1  jdolecek 
   1591  1.5  riastrad 	DPRINTF(IPS_D_XFER, ("%s: ips_intr", device_xname(sc->sc_dev)));
   1592  1.1  jdolecek 	if (!ips_isintr(sc)) {
   1593  1.1  jdolecek 		DPRINTF(IPS_D_XFER, (": not ours\n"));
   1594  1.1  jdolecek 		return (0);
   1595  1.1  jdolecek 	}
   1596  1.1  jdolecek 	DPRINTF(IPS_D_XFER, ("\n"));
   1597  1.1  jdolecek 
   1598  1.1  jdolecek 	/* Process completed commands */
   1599  1.1  jdolecek 	while ((status = ips_status(sc)) != 0xffffffff) {
   1600  1.1  jdolecek 		DPRINTF(IPS_D_XFER, ("%s: ips_intr: status 0x%08x\n",
   1601  1.5  riastrad 		    device_xname(sc->sc_dev), status));
   1602  1.1  jdolecek 
   1603  1.1  jdolecek 		id = IPS_STAT_ID(status);
   1604  1.1  jdolecek 		if (id >= sc->sc_nccbs) {
   1605  1.1  jdolecek 			DPRINTF(IPS_D_ERR, ("%s: ips_intr: invalid id %d\n",
   1606  1.5  riastrad 			    device_xname(sc->sc_dev), id));
   1607  1.1  jdolecek 			continue;
   1608  1.1  jdolecek 		}
   1609  1.1  jdolecek 
   1610  1.1  jdolecek 		ccb = &sc->sc_ccb[id];
   1611  1.1  jdolecek 		if (ccb->c_state != IPS_CCB_QUEUED) {
   1612  1.1  jdolecek 			DPRINTF(IPS_D_ERR, ("%s: ips_intr: cmd 0x%02x not "
   1613  1.1  jdolecek 			    "queued, state %d, status 0x%08x\n",
   1614  1.5  riastrad 			    device_xname(sc->sc_dev), ccb->c_id, ccb->c_state,
   1615  1.1  jdolecek 			    status));
   1616  1.1  jdolecek 			continue;
   1617  1.1  jdolecek 		}
   1618  1.1  jdolecek 
   1619  1.1  jdolecek 		ccb->c_state = IPS_CCB_DONE;
   1620  1.1  jdolecek 		ccb->c_stat = IPS_STAT_BASIC(status);
   1621  1.1  jdolecek 		ccb->c_estat = IPS_STAT_EXT(status);
   1622  1.1  jdolecek 
   1623  1.1  jdolecek 		if (ccb->c_flags & XS_CTL_POLL) {
   1624  1.1  jdolecek 			wakeup(ccb);
   1625  1.1  jdolecek 		} else {
   1626  1.1  jdolecek 			ips_done(sc, ccb);
   1627  1.1  jdolecek 		}
   1628  1.1  jdolecek 	}
   1629  1.1  jdolecek 
   1630  1.1  jdolecek 	return (1);
   1631  1.1  jdolecek }
   1632  1.1  jdolecek 
   1633  1.1  jdolecek void
   1634  1.1  jdolecek ips_timeout(void *arg)
   1635  1.1  jdolecek {
   1636  1.1  jdolecek 	struct ips_ccb *ccb = arg;
   1637  1.1  jdolecek 	struct ips_softc *sc = ccb->c_sc;
   1638  1.1  jdolecek 	struct scsipi_xfer *xs = ccb->c_xfer;
   1639  1.1  jdolecek 	int s;
   1640  1.1  jdolecek 
   1641  1.1  jdolecek 	s = splbio();
   1642  1.1  jdolecek 	if (xs)
   1643  1.1  jdolecek 		scsi_print_addr(xs->xs_periph);
   1644  1.1  jdolecek 	else
   1645  1.5  riastrad 		printf("%s: ", device_xname(sc->sc_dev));
   1646  1.1  jdolecek 	printf("timeout\n");
   1647  1.1  jdolecek 
   1648  1.1  jdolecek 	/*
   1649  1.1  jdolecek 	 * Command never completed. Fake hardware status byte
   1650  1.1  jdolecek 	 * to indicate timeout.
   1651  1.1  jdolecek 	 * XXX: need to remove command from controller.
   1652  1.1  jdolecek 	 */
   1653  1.1  jdolecek 	ccb->c_stat = IPS_STAT_TIMO;
   1654  1.1  jdolecek 	ips_done(sc, ccb);
   1655  1.1  jdolecek 	splx(s);
   1656  1.1  jdolecek }
   1657  1.1  jdolecek 
   1658  1.1  jdolecek int
   1659  1.1  jdolecek ips_getadapterinfo(struct ips_softc *sc, int flags)
   1660  1.1  jdolecek {
   1661  1.1  jdolecek 	struct ips_ccb *ccb;
   1662  1.1  jdolecek 	struct ips_cmd *cmd;
   1663  1.1  jdolecek 
   1664  1.1  jdolecek 	ccb = ips_ccb_get(sc);
   1665  1.1  jdolecek 	if (ccb == NULL)
   1666  1.1  jdolecek 		return (1);
   1667  1.1  jdolecek 
   1668  1.1  jdolecek 	ccb->c_flags = XS_CTL_DATA_IN | XS_CTL_POLL | flags;
   1669  1.1  jdolecek 	ccb->c_done = ips_done_mgmt;
   1670  1.1  jdolecek 
   1671  1.1  jdolecek 	cmd = ccb->c_cmdbva;
   1672  1.1  jdolecek 	cmd->code = IPS_CMD_GETADAPTERINFO;
   1673  1.1  jdolecek 	cmd->sgaddr = htole32(sc->sc_infom.dm_paddr + offsetof(struct ips_info,
   1674  1.1  jdolecek 	    adapter));
   1675  1.1  jdolecek 
   1676  1.1  jdolecek 	return (ips_cmd(sc, ccb));
   1677  1.1  jdolecek }
   1678  1.1  jdolecek 
   1679  1.1  jdolecek int
   1680  1.1  jdolecek ips_getdriveinfo(struct ips_softc *sc, int flags)
   1681  1.1  jdolecek {
   1682  1.1  jdolecek 	struct ips_ccb *ccb;
   1683  1.1  jdolecek 	struct ips_cmd *cmd;
   1684  1.1  jdolecek 
   1685  1.1  jdolecek 	ccb = ips_ccb_get(sc);
   1686  1.1  jdolecek 	if (ccb == NULL)
   1687  1.1  jdolecek 		return (1);
   1688  1.1  jdolecek 
   1689  1.1  jdolecek 	ccb->c_flags = XS_CTL_DATA_IN | XS_CTL_POLL | flags;
   1690  1.1  jdolecek 	ccb->c_done = ips_done_mgmt;
   1691  1.1  jdolecek 
   1692  1.1  jdolecek 	cmd = ccb->c_cmdbva;
   1693  1.1  jdolecek 	cmd->code = IPS_CMD_GETDRIVEINFO;
   1694  1.1  jdolecek 	cmd->sgaddr = htole32(sc->sc_infom.dm_paddr + offsetof(struct ips_info,
   1695  1.1  jdolecek 	    drive));
   1696  1.1  jdolecek 
   1697  1.1  jdolecek 	return (ips_cmd(sc, ccb));
   1698  1.1  jdolecek }
   1699  1.1  jdolecek 
   1700  1.1  jdolecek int
   1701  1.1  jdolecek ips_getconf(struct ips_softc *sc, int flags)
   1702  1.1  jdolecek {
   1703  1.1  jdolecek 	struct ips_ccb *ccb;
   1704  1.1  jdolecek 	struct ips_cmd *cmd;
   1705  1.1  jdolecek 
   1706  1.1  jdolecek 	ccb = ips_ccb_get(sc);
   1707  1.1  jdolecek 	if (ccb == NULL)
   1708  1.1  jdolecek 		return (1);
   1709  1.1  jdolecek 
   1710  1.1  jdolecek 	ccb->c_flags = XS_CTL_DATA_IN | XS_CTL_POLL | flags;
   1711  1.1  jdolecek 	ccb->c_done = ips_done_mgmt;
   1712  1.1  jdolecek 
   1713  1.1  jdolecek 	cmd = ccb->c_cmdbva;
   1714  1.1  jdolecek 	cmd->code = IPS_CMD_READCONF;
   1715  1.1  jdolecek 	cmd->sgaddr = htole32(sc->sc_infom.dm_paddr + offsetof(struct ips_info,
   1716  1.1  jdolecek 	    conf));
   1717  1.1  jdolecek 
   1718  1.1  jdolecek 	return (ips_cmd(sc, ccb));
   1719  1.1  jdolecek }
   1720  1.1  jdolecek 
   1721  1.1  jdolecek int
   1722  1.1  jdolecek ips_getpg5(struct ips_softc *sc, int flags)
   1723  1.1  jdolecek {
   1724  1.1  jdolecek 	struct ips_ccb *ccb;
   1725  1.1  jdolecek 	struct ips_cmd *cmd;
   1726  1.1  jdolecek 
   1727  1.1  jdolecek 	ccb = ips_ccb_get(sc);
   1728  1.1  jdolecek 	if (ccb == NULL)
   1729  1.1  jdolecek 		return (1);
   1730  1.1  jdolecek 
   1731  1.1  jdolecek 	ccb->c_flags = XS_CTL_DATA_IN | XS_CTL_POLL | flags;
   1732  1.1  jdolecek 	ccb->c_done = ips_done_mgmt;
   1733  1.1  jdolecek 
   1734  1.1  jdolecek 	cmd = ccb->c_cmdbva;
   1735  1.1  jdolecek 	cmd->code = IPS_CMD_RWNVRAM;
   1736  1.1  jdolecek 	cmd->drive = 5;
   1737  1.1  jdolecek 	cmd->sgaddr = htole32(sc->sc_infom.dm_paddr + offsetof(struct ips_info,
   1738  1.1  jdolecek 	    pg5));
   1739  1.1  jdolecek 
   1740  1.1  jdolecek 	return (ips_cmd(sc, ccb));
   1741  1.1  jdolecek }
   1742  1.1  jdolecek 
   1743  1.1  jdolecek #if NBIO > 0
   1744  1.1  jdolecek int
   1745  1.1  jdolecek ips_getrblstat(struct ips_softc *sc, int flags)
   1746  1.1  jdolecek {
   1747  1.1  jdolecek 	struct ips_ccb *ccb;
   1748  1.1  jdolecek 	struct ips_cmd *cmd;
   1749  1.1  jdolecek 
   1750  1.1  jdolecek 	ccb = ips_ccb_get(sc);
   1751  1.1  jdolecek 	if (ccb == NULL)
   1752  1.1  jdolecek 		return (1);
   1753  1.1  jdolecek 
   1754  1.1  jdolecek 	ccb->c_flags = XS_CTL_DATA_IN | XS_CTL_POLL | flags;
   1755  1.1  jdolecek 	ccb->c_done = ips_done_mgmt;
   1756  1.1  jdolecek 
   1757  1.1  jdolecek 	cmd = ccb->c_cmdbva;
   1758  1.1  jdolecek 	cmd->code = IPS_CMD_REBUILDSTATUS;
   1759  1.1  jdolecek 	cmd->sgaddr = htole32(sc->sc_infom.dm_paddr + offsetof(struct ips_info,
   1760  1.1  jdolecek 	    rblstat));
   1761  1.1  jdolecek 
   1762  1.1  jdolecek 	return (ips_cmd(sc, ccb));
   1763  1.1  jdolecek }
   1764  1.1  jdolecek 
   1765  1.1  jdolecek int
   1766  1.1  jdolecek ips_setstate(struct ips_softc *sc, int chan, int target, int state, int flags)
   1767  1.1  jdolecek {
   1768  1.1  jdolecek 	struct ips_ccb *ccb;
   1769  1.1  jdolecek 	struct ips_cmd *cmd;
   1770  1.1  jdolecek 
   1771  1.1  jdolecek 	ccb = ips_ccb_get(sc);
   1772  1.1  jdolecek 	if (ccb == NULL)
   1773  1.1  jdolecek 		return (1);
   1774  1.1  jdolecek 
   1775  1.1  jdolecek 	ccb->c_flags = XS_CTL_POLL | flags;
   1776  1.1  jdolecek 	ccb->c_done = ips_done_mgmt;
   1777  1.1  jdolecek 
   1778  1.1  jdolecek 	cmd = ccb->c_cmdbva;
   1779  1.1  jdolecek 	cmd->code = IPS_CMD_SETSTATE;
   1780  1.1  jdolecek 	cmd->drive = chan;
   1781  1.1  jdolecek 	cmd->sgcnt = target;
   1782  1.1  jdolecek 	cmd->seg4g = state;
   1783  1.1  jdolecek 
   1784  1.1  jdolecek 	return (ips_cmd(sc, ccb));
   1785  1.1  jdolecek }
   1786  1.1  jdolecek 
   1787  1.1  jdolecek int
   1788  1.1  jdolecek ips_rebuild(struct ips_softc *sc, int chan, int target, int nchan,
   1789  1.1  jdolecek     int ntarget, int flags)
   1790  1.1  jdolecek {
   1791  1.1  jdolecek 	struct ips_ccb *ccb;
   1792  1.1  jdolecek 	struct ips_cmd *cmd;
   1793  1.1  jdolecek 
   1794  1.1  jdolecek 	ccb = ips_ccb_get(sc);
   1795  1.1  jdolecek 	if (ccb == NULL)
   1796  1.1  jdolecek 		return (1);
   1797  1.1  jdolecek 
   1798  1.1  jdolecek 	ccb->c_flags = XS_CTL_POLL | flags;
   1799  1.1  jdolecek 	ccb->c_done = ips_done_mgmt;
   1800  1.1  jdolecek 
   1801  1.1  jdolecek 	cmd = ccb->c_cmdbva;
   1802  1.1  jdolecek 	cmd->code = IPS_CMD_REBUILD;
   1803  1.1  jdolecek 	cmd->drive = chan;
   1804  1.1  jdolecek 	cmd->sgcnt = target;
   1805  1.1  jdolecek 	cmd->seccnt = htole16(ntarget << 8 | nchan);
   1806  1.1  jdolecek 
   1807  1.1  jdolecek 	return (ips_cmd(sc, ccb));
   1808  1.1  jdolecek }
   1809  1.1  jdolecek #endif	/* NBIO > 0 */
   1810  1.1  jdolecek 
   1811  1.1  jdolecek void
   1812  1.1  jdolecek ips_copperhead_exec(struct ips_softc *sc, struct ips_ccb *ccb)
   1813  1.1  jdolecek {
   1814  1.1  jdolecek 	u_int32_t reg;
   1815  1.1  jdolecek 	int timeout;
   1816  1.1  jdolecek 
   1817  1.1  jdolecek 	for (timeout = 100; timeout-- > 0; delay(100)) {
   1818  1.1  jdolecek 		reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, IPS_REG_CCC);
   1819  1.1  jdolecek 		if ((reg & IPS_REG_CCC_SEM) == 0)
   1820  1.1  jdolecek 			break;
   1821  1.1  jdolecek 	}
   1822  1.1  jdolecek 	if (timeout < 0) {
   1823  1.5  riastrad 		device_printf(sc->sc_dev, "semaphore timeout\n");
   1824  1.1  jdolecek 		return;
   1825  1.1  jdolecek 	}
   1826  1.1  jdolecek 
   1827  1.1  jdolecek 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, IPS_REG_CCSA, ccb->c_cmdbpa);
   1828  1.1  jdolecek 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, IPS_REG_CCC,
   1829  1.1  jdolecek 	    IPS_REG_CCC_START);
   1830  1.1  jdolecek }
   1831  1.1  jdolecek 
   1832  1.1  jdolecek void
   1833  1.1  jdolecek ips_copperhead_intren(struct ips_softc *sc)
   1834  1.1  jdolecek {
   1835  1.1  jdolecek 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, IPS_REG_HIS, IPS_REG_HIS_EN);
   1836  1.1  jdolecek }
   1837  1.1  jdolecek 
   1838  1.1  jdolecek int
   1839  1.1  jdolecek ips_copperhead_isintr(struct ips_softc *sc)
   1840  1.1  jdolecek {
   1841  1.1  jdolecek 	u_int8_t reg;
   1842  1.1  jdolecek 
   1843  1.1  jdolecek 	reg = bus_space_read_1(sc->sc_iot, sc->sc_ioh, IPS_REG_HIS);
   1844  1.1  jdolecek 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, IPS_REG_HIS, reg);
   1845  1.1  jdolecek 	if (reg != 0xff && (reg & IPS_REG_HIS_SCE))
   1846  1.1  jdolecek 		return (1);
   1847  1.1  jdolecek 
   1848  1.1  jdolecek 	return (0);
   1849  1.1  jdolecek }
   1850  1.1  jdolecek 
   1851  1.1  jdolecek u_int32_t
   1852  1.1  jdolecek ips_copperhead_status(struct ips_softc *sc)
   1853  1.1  jdolecek {
   1854  1.1  jdolecek 	u_int32_t sqhead, sqtail, status;
   1855  1.1  jdolecek 
   1856  1.1  jdolecek 	sqhead = bus_space_read_4(sc->sc_iot, sc->sc_ioh, IPS_REG_SQH);
   1857  1.1  jdolecek 	DPRINTF(IPS_D_XFER, ("%s: sqhead 0x%08x, sqtail 0x%08x\n",
   1858  1.5  riastrad 	    device_xname(sc->sc_dev), sqhead, sc->sc_sqtail));
   1859  1.1  jdolecek 
   1860  1.1  jdolecek 	sqtail = sc->sc_sqtail + sizeof(u_int32_t);
   1861  1.1  jdolecek 	if (sqtail == sc->sc_sqm.dm_paddr + IPS_SQSZ)
   1862  1.1  jdolecek 		sqtail = sc->sc_sqm.dm_paddr;
   1863  1.1  jdolecek 	if (sqtail == sqhead)
   1864  1.1  jdolecek 		return (0xffffffff);
   1865  1.1  jdolecek 
   1866  1.1  jdolecek 	sc->sc_sqtail = sqtail;
   1867  1.1  jdolecek 	if (++sc->sc_sqidx == IPS_MAXCMDS)
   1868  1.1  jdolecek 		sc->sc_sqidx = 0;
   1869  1.1  jdolecek 	status = htole32(sc->sc_sqbuf[sc->sc_sqidx]);
   1870  1.1  jdolecek 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, IPS_REG_SQT, sqtail);
   1871  1.1  jdolecek 
   1872  1.1  jdolecek 	return (status);
   1873  1.1  jdolecek }
   1874  1.1  jdolecek 
   1875  1.1  jdolecek void
   1876  1.1  jdolecek ips_morpheus_exec(struct ips_softc *sc, struct ips_ccb *ccb)
   1877  1.1  jdolecek {
   1878  1.1  jdolecek 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, IPS_REG_IQP, ccb->c_cmdbpa);
   1879  1.1  jdolecek }
   1880  1.1  jdolecek 
   1881  1.1  jdolecek void
   1882  1.1  jdolecek ips_morpheus_intren(struct ips_softc *sc)
   1883  1.1  jdolecek {
   1884  1.1  jdolecek 	u_int32_t reg;
   1885  1.1  jdolecek 
   1886  1.1  jdolecek 	reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, IPS_REG_OIM);
   1887  1.1  jdolecek 	reg &= ~IPS_REG_OIM_DS;
   1888  1.1  jdolecek 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, IPS_REG_OIM, reg);
   1889  1.1  jdolecek }
   1890  1.1  jdolecek 
   1891  1.1  jdolecek int
   1892  1.1  jdolecek ips_morpheus_isintr(struct ips_softc *sc)
   1893  1.1  jdolecek {
   1894  1.1  jdolecek 	return (bus_space_read_4(sc->sc_iot, sc->sc_ioh, IPS_REG_OIS) &
   1895  1.1  jdolecek 	    IPS_REG_OIS_PEND);
   1896  1.1  jdolecek }
   1897  1.1  jdolecek 
   1898  1.1  jdolecek u_int32_t
   1899  1.1  jdolecek ips_morpheus_status(struct ips_softc *sc)
   1900  1.1  jdolecek {
   1901  1.1  jdolecek 	u_int32_t reg;
   1902  1.1  jdolecek 
   1903  1.1  jdolecek 	reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, IPS_REG_OQP);
   1904  1.5  riastrad 	DPRINTF(IPS_D_XFER, ("%s: status 0x%08x\n", device_xname(sc->sc_dev),
   1905  1.5  riastrad 	    reg));
   1906  1.1  jdolecek 
   1907  1.1  jdolecek 	return (reg);
   1908  1.1  jdolecek }
   1909  1.1  jdolecek 
   1910  1.1  jdolecek struct ips_ccb *
   1911  1.1  jdolecek ips_ccb_alloc(struct ips_softc *sc, int n)
   1912  1.1  jdolecek {
   1913  1.1  jdolecek 	struct ips_ccb *ccb;
   1914  1.1  jdolecek 	int i;
   1915  1.1  jdolecek 
   1916  1.2       chs 	ccb = malloc(n * sizeof(*ccb), M_DEVBUF, M_WAITOK | M_ZERO);
   1917  1.1  jdolecek 	for (i = 0; i < n; i++) {
   1918  1.1  jdolecek 		ccb[i].c_sc = sc;
   1919  1.1  jdolecek 		ccb[i].c_id = i;
   1920  1.1  jdolecek 		ccb[i].c_cmdbva = (char *)sc->sc_cmdbm.dm_vaddr +
   1921  1.1  jdolecek 		    i * sizeof(struct ips_cmdb);
   1922  1.1  jdolecek 		ccb[i].c_cmdbpa = sc->sc_cmdbm.dm_paddr +
   1923  1.1  jdolecek 		    i * sizeof(struct ips_cmdb);
   1924  1.1  jdolecek 		if (bus_dmamap_create(sc->sc_dmat, IPS_MAXFER, IPS_MAXSGS,
   1925  1.1  jdolecek 		    IPS_MAXFER, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
   1926  1.1  jdolecek 		    &ccb[i].c_dmam))
   1927  1.1  jdolecek 			goto fail;
   1928  1.1  jdolecek 	}
   1929  1.1  jdolecek 
   1930  1.1  jdolecek 	return (ccb);
   1931  1.1  jdolecek fail:
   1932  1.1  jdolecek 	for (; i > 0; i--)
   1933  1.1  jdolecek 		bus_dmamap_destroy(sc->sc_dmat, ccb[i - 1].c_dmam);
   1934  1.1  jdolecek 	free(ccb, M_DEVBUF);
   1935  1.1  jdolecek 	return (NULL);
   1936  1.1  jdolecek }
   1937  1.1  jdolecek 
   1938  1.1  jdolecek void
   1939  1.1  jdolecek ips_ccb_free(struct ips_softc *sc, struct ips_ccb *ccb, int n)
   1940  1.1  jdolecek {
   1941  1.1  jdolecek 	int i;
   1942  1.1  jdolecek 
   1943  1.1  jdolecek 	for (i = 0; i < n; i++)
   1944  1.1  jdolecek 		bus_dmamap_destroy(sc->sc_dmat, ccb[i - 1].c_dmam);
   1945  1.1  jdolecek 	free(ccb, M_DEVBUF);
   1946  1.1  jdolecek }
   1947  1.1  jdolecek 
   1948  1.1  jdolecek struct ips_ccb *
   1949  1.1  jdolecek ips_ccb_get(struct ips_softc *sc)
   1950  1.1  jdolecek {
   1951  1.1  jdolecek 	struct ips_ccb *ccb;
   1952  1.1  jdolecek 
   1953  1.1  jdolecek 	mutex_enter(&sc->sc_ccb_mtx);
   1954  1.1  jdolecek 	if ((ccb = SLIST_FIRST(&sc->sc_ccbq_free)) != NULL) {
   1955  1.1  jdolecek 		SLIST_REMOVE_HEAD(&sc->sc_ccbq_free, c_link);
   1956  1.1  jdolecek 		ccb->c_flags = 0;
   1957  1.1  jdolecek 		ccb->c_xfer = NULL;
   1958  1.1  jdolecek 		bzero(ccb->c_cmdbva, sizeof(struct ips_cmdb));
   1959  1.1  jdolecek 	}
   1960  1.1  jdolecek 	mutex_exit(&sc->sc_ccb_mtx);
   1961  1.1  jdolecek 
   1962  1.1  jdolecek 	return (ccb);
   1963  1.1  jdolecek }
   1964  1.1  jdolecek 
   1965  1.1  jdolecek void
   1966  1.1  jdolecek ips_ccb_put(struct ips_softc *sc, struct ips_ccb *ccb)
   1967  1.1  jdolecek {
   1968  1.1  jdolecek 	ccb->c_state = IPS_CCB_FREE;
   1969  1.1  jdolecek 	mutex_enter(&sc->sc_ccb_mtx);
   1970  1.1  jdolecek 	SLIST_INSERT_HEAD(&sc->sc_ccbq_free, ccb, c_link);
   1971  1.1  jdolecek 	mutex_exit(&sc->sc_ccb_mtx);
   1972  1.1  jdolecek }
   1973  1.1  jdolecek 
   1974  1.1  jdolecek int
   1975  1.1  jdolecek ips_dmamem_alloc(struct dmamem *dm, bus_dma_tag_t tag, bus_size_t size)
   1976  1.1  jdolecek {
   1977  1.1  jdolecek 	int nsegs;
   1978  1.1  jdolecek 
   1979  1.1  jdolecek 	dm->dm_tag = tag;
   1980  1.1  jdolecek 	dm->dm_size = size;
   1981  1.1  jdolecek 
   1982  1.1  jdolecek 	if (bus_dmamap_create(tag, size, 1, size, 0,
   1983  1.1  jdolecek 	    BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &dm->dm_map))
   1984  1.1  jdolecek 		return (1);
   1985  1.1  jdolecek 	if (bus_dmamem_alloc(tag, size, 0, 0, &dm->dm_seg, 1, &nsegs,
   1986  1.1  jdolecek 	    BUS_DMA_NOWAIT))
   1987  1.1  jdolecek 		goto fail1;
   1988  1.1  jdolecek 	if (bus_dmamem_map(tag, &dm->dm_seg, 1, size, &dm->dm_vaddr,
   1989  1.1  jdolecek 	    BUS_DMA_NOWAIT))
   1990  1.1  jdolecek 		goto fail2;
   1991  1.1  jdolecek 	if (bus_dmamap_load(tag, dm->dm_map, dm->dm_vaddr, size, NULL,
   1992  1.1  jdolecek 	    BUS_DMA_NOWAIT))
   1993  1.1  jdolecek 		goto fail3;
   1994  1.1  jdolecek 
   1995  1.1  jdolecek 	return (0);
   1996  1.1  jdolecek 
   1997  1.1  jdolecek fail3:
   1998  1.1  jdolecek 	bus_dmamem_unmap(tag, dm->dm_vaddr, size);
   1999  1.1  jdolecek fail2:
   2000  1.1  jdolecek 	bus_dmamem_free(tag, &dm->dm_seg, 1);
   2001  1.1  jdolecek fail1:
   2002  1.1  jdolecek 	bus_dmamap_destroy(tag, dm->dm_map);
   2003  1.1  jdolecek 	return (1);
   2004  1.1  jdolecek }
   2005  1.1  jdolecek 
   2006  1.1  jdolecek void
   2007  1.1  jdolecek ips_dmamem_free(struct dmamem *dm)
   2008  1.1  jdolecek {
   2009  1.1  jdolecek 	bus_dmamap_unload(dm->dm_tag, dm->dm_map);
   2010  1.1  jdolecek 	bus_dmamem_unmap(dm->dm_tag, dm->dm_vaddr, dm->dm_size);
   2011  1.1  jdolecek 	bus_dmamem_free(dm->dm_tag, &dm->dm_seg, 1);
   2012  1.1  jdolecek 	bus_dmamap_destroy(dm->dm_tag, dm->dm_map);
   2013  1.1  jdolecek }
   2014