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