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