1 1.51 ad /* $NetBSD: dpti.c,v 1.51 2023/09/07 20:07:03 ad Exp $ */ 2 1.1 ad 3 1.1 ad /*- 4 1.51 ad * Copyright (c) 2001, 2007, 2023 The NetBSD Foundation, Inc. 5 1.1 ad * All rights reserved. 6 1.1 ad * 7 1.1 ad * This code is derived from software contributed to The NetBSD Foundation 8 1.1 ad * by Andrew Doran. 9 1.1 ad * 10 1.1 ad * Redistribution and use in source and binary forms, with or without 11 1.1 ad * modification, are permitted provided that the following conditions 12 1.1 ad * are met: 13 1.1 ad * 1. Redistributions of source code must retain the above copyright 14 1.1 ad * notice, this list of conditions and the following disclaimer. 15 1.1 ad * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 ad * notice, this list of conditions and the following disclaimer in the 17 1.1 ad * documentation and/or other materials provided with the distribution. 18 1.1 ad * 19 1.1 ad * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 ad * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 ad * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 ad * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 ad * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 ad * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 ad * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 ad * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 ad * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 ad * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 ad * POSSIBILITY OF SUCH DAMAGE. 30 1.1 ad */ 31 1.1 ad 32 1.1 ad /* 33 1.1 ad * Copyright (c) 1996-2000 Distributed Processing Technology Corporation 34 1.1 ad * Copyright (c) 2000 Adaptec Corporation 35 1.1 ad * All rights reserved. 36 1.1 ad * 37 1.1 ad * TERMS AND CONDITIONS OF USE 38 1.1 ad * 39 1.1 ad * Redistribution and use in source form, with or without modification, are 40 1.1 ad * permitted provided that redistributions of source code must retain the 41 1.1 ad * above copyright notice, this list of conditions and the following disclaimer. 42 1.1 ad * 43 1.1 ad * This software is provided `as is' by Adaptec and any express or implied 44 1.1 ad * warranties, including, but not limited to, the implied warranties of 45 1.1 ad * merchantability and fitness for a particular purpose, are disclaimed. In no 46 1.1 ad * event shall Adaptec be liable for any direct, indirect, incidental, special, 47 1.1 ad * exemplary or consequential damages (including, but not limited to, 48 1.1 ad * procurement of substitute goods or services; loss of use, data, or profits; 49 1.1 ad * or business interruptions) however caused and on any theory of liability, 50 1.1 ad * whether in contract, strict liability, or tort (including negligence or 51 1.1 ad * otherwise) arising in any way out of the use of this driver software, even 52 1.1 ad * if advised of the possibility of such damage. 53 1.1 ad */ 54 1.1 ad 55 1.1 ad /* 56 1.1 ad * Adaptec/DPT I2O control interface. 57 1.1 ad */ 58 1.3 lukem 59 1.3 lukem #include <sys/cdefs.h> 60 1.51 ad __KERNEL_RCSID(0, "$NetBSD: dpti.c,v 1.51 2023/09/07 20:07:03 ad Exp $"); 61 1.1 ad 62 1.1 ad #include <sys/param.h> 63 1.1 ad #include <sys/systm.h> 64 1.1 ad #include <sys/kernel.h> 65 1.1 ad #include <sys/device.h> 66 1.1 ad #include <sys/queue.h> 67 1.1 ad #include <sys/proc.h> 68 1.1 ad #include <sys/endian.h> 69 1.51 ad #include <sys/kmem.h> 70 1.1 ad #include <sys/conf.h> 71 1.1 ad #include <sys/ioctl.h> 72 1.29 elad #include <sys/kauth.h> 73 1.1 ad 74 1.35 ad #include <sys/bus.h> 75 1.11 thorpej #ifdef __i386__ 76 1.2 ad #include <machine/pio.h> 77 1.38 ad #include <machine/cputypes.h> 78 1.2 ad #endif 79 1.1 ad 80 1.1 ad #include <dev/i2o/i2o.h> 81 1.1 ad #include <dev/i2o/i2odpt.h> 82 1.1 ad #include <dev/i2o/iopio.h> 83 1.1 ad #include <dev/i2o/iopvar.h> 84 1.1 ad #include <dev/i2o/dptivar.h> 85 1.1 ad 86 1.49 riastrad #include "ioconf.h" 87 1.49 riastrad 88 1.1 ad #ifdef I2ODEBUG 89 1.1 ad #define DPRINTF(x) printf x 90 1.1 ad #else 91 1.1 ad #define DPRINTF(x) 92 1.1 ad #endif 93 1.1 ad 94 1.1 ad static struct dpt_sig dpti_sig = { 95 1.47 christos .dsSignature = { 'd', 'P', 't', 'S', 'i', 'G'}, 96 1.47 christos .dsSigVersion = SIG_VERSION, 97 1.11 thorpej #if defined(__i386__) 98 1.47 christos .dsProcessorFamily = PROC_INTEL, 99 1.11 thorpej #elif defined(__powerpc__) 100 1.47 christos .dsProcessorFamily = PROC_POWERPC, 101 1.11 thorpej #elif defined(__alpha__) 102 1.47 christos .dsProcessorFamily = PROC_ALPHA, 103 1.4 thorpej #elif defined(__mips__) 104 1.47 christos .dsProcessorFamily = PROC_MIPS, 105 1.11 thorpej #elif defined(__sparc64__) 106 1.47 christos .dsProcessorFamily = PROC_ULTRASPARC, 107 1.2 ad #endif 108 1.11 thorpej #if defined(__i386__) 109 1.47 christos .dsProcessor = PROC_386 | PROC_486 | PROC_PENTIUM | PROC_SEXIUM, 110 1.2 ad #else 111 1.47 christos .dsProcessor = 0, 112 1.2 ad #endif 113 1.47 christos .dsFiletype = FT_HBADRVR, 114 1.47 christos .dsFiletypeFlags = 0, 115 1.47 christos .dsOEM = OEM_DPT, 116 1.47 christos .dsOS = (uint32_t)OS_FREE_BSD, /* XXX */ 117 1.47 christos .dsCapabilities = CAP_ABOVE16MB, 118 1.47 christos .dsDeviceSupp = DEV_ALL, 119 1.47 christos .dsAdapterSupp = ADF_ALL_SC5, 120 1.47 christos .dsApplication = 0, 121 1.47 christos .dsRequirements = 0, 122 1.47 christos .dsVersion = DPTI_VERSION, 123 1.47 christos .dsRevision = DPTI_REVISION, 124 1.47 christos .dsSubRevision = DPTI_SUBREVISION, 125 1.47 christos .dsMonth = DPTI_MONTH, 126 1.47 christos .dsDay = DPTI_DAY, 127 1.47 christos .dsYear = DPTI_YEAR, 128 1.47 christos .dsDescription = { '\0' }, /* Will be filled later */ 129 1.1 ad }; 130 1.1 ad 131 1.42 cegger void dpti_attach(device_t, device_t, void *); 132 1.1 ad int dpti_blinkled(struct dpti_softc *); 133 1.33 christos int dpti_ctlrinfo(struct dpti_softc *, int, void *); 134 1.42 cegger int dpti_match(device_t, cfdata_t, void *); 135 1.33 christos int dpti_passthrough(struct dpti_softc *, void *, struct proc *); 136 1.33 christos int dpti_sysinfo(struct dpti_softc *, int, void *); 137 1.1 ad 138 1.5 gehenna dev_type_open(dptiopen); 139 1.5 gehenna dev_type_ioctl(dptiioctl); 140 1.5 gehenna 141 1.5 gehenna const struct cdevsw dpti_cdevsw = { 142 1.46 dholland .d_open = dptiopen, 143 1.46 dholland .d_close = nullclose, 144 1.46 dholland .d_read = noread, 145 1.46 dholland .d_write = nowrite, 146 1.46 dholland .d_ioctl = dptiioctl, 147 1.46 dholland .d_stop = nostop, 148 1.46 dholland .d_tty = notty, 149 1.46 dholland .d_poll = nopoll, 150 1.46 dholland .d_mmap = nommap, 151 1.46 dholland .d_kqfilter = nokqfilter, 152 1.48 dholland .d_discard = nodiscard, 153 1.51 ad .d_flag = D_OTHER | D_MPSAFE, 154 1.5 gehenna }; 155 1.1 ad 156 1.45 chs CFATTACH_DECL_NEW(dpti, sizeof(struct dpti_softc), 157 1.8 thorpej dpti_match, dpti_attach, NULL, NULL); 158 1.1 ad 159 1.1 ad int 160 1.42 cegger dpti_match(device_t parent, cfdata_t match, void *aux) 161 1.1 ad { 162 1.1 ad struct iop_attach_args *ia; 163 1.1 ad struct iop_softc *iop; 164 1.1 ad 165 1.1 ad ia = aux; 166 1.45 chs iop = device_private(parent); 167 1.1 ad 168 1.1 ad if (ia->ia_class != I2O_CLASS_ANY || ia->ia_tid != I2O_TID_IOP) 169 1.1 ad return (0); 170 1.1 ad 171 1.1 ad if (le16toh(iop->sc_status.orgid) != I2O_ORG_DPT) 172 1.1 ad return (0); 173 1.1 ad 174 1.1 ad return (1); 175 1.1 ad } 176 1.1 ad 177 1.1 ad void 178 1.42 cegger dpti_attach(device_t parent, device_t self, void *aux) 179 1.1 ad { 180 1.1 ad struct iop_softc *iop; 181 1.1 ad struct dpti_softc *sc; 182 1.1 ad struct { 183 1.1 ad struct i2o_param_op_results pr; 184 1.1 ad struct i2o_param_read_results prr; 185 1.1 ad struct i2o_dpt_param_exec_iop_buffers dib; 186 1.40 gmcgarry } __packed param; 187 1.1 ad int rv; 188 1.1 ad 189 1.24 thorpej sc = device_private(self); 190 1.45 chs sc->sc_dev = self; 191 1.24 thorpej iop = device_private(parent); 192 1.1 ad 193 1.1 ad /* 194 1.1 ad * Tell the world what we are. The description in the signature 195 1.1 ad * must be no more than 46 bytes long (see dptivar.h). 196 1.1 ad */ 197 1.2 ad printf(": DPT/Adaptec RAID management interface\n"); 198 1.18 itojun snprintf(dpti_sig.dsDescription, sizeof(dpti_sig.dsDescription), 199 1.18 itojun "NetBSD %s I2O OSM", osrelease); 200 1.1 ad 201 1.1 ad rv = iop_field_get_all(iop, I2O_TID_IOP, 202 1.1 ad I2O_DPT_PARAM_EXEC_IOP_BUFFERS, ¶m, 203 1.1 ad sizeof(param), NULL); 204 1.1 ad if (rv != 0) 205 1.1 ad return; 206 1.1 ad 207 1.1 ad sc->sc_blinkled = le32toh(param.dib.serialoutputoff) + 8; 208 1.1 ad } 209 1.1 ad 210 1.1 ad int 211 1.30 christos dptiopen(dev_t dev, int flag, int mode, 212 1.30 christos struct lwp *l) 213 1.1 ad { 214 1.1 ad 215 1.1 ad if (device_lookup(&dpti_cd, minor(dev)) == NULL) 216 1.1 ad return (ENXIO); 217 1.1 ad 218 1.1 ad return (0); 219 1.1 ad } 220 1.1 ad 221 1.1 ad int 222 1.33 christos dptiioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 223 1.1 ad { 224 1.1 ad struct iop_softc *iop; 225 1.1 ad struct dpti_softc *sc; 226 1.1 ad struct ioctl_pt *pt; 227 1.10 ad int i, size, rv, linux; 228 1.1 ad 229 1.39 tsutsui sc = device_lookup_private(&dpti_cd, minor(dev)); 230 1.45 chs iop = device_private(device_parent(sc->sc_dev)); 231 1.17 ad rv = 0; 232 1.1 ad 233 1.1 ad if (cmd == PTIOCLINUX) { 234 1.1 ad pt = (struct ioctl_pt *)data; 235 1.10 ad size = IOCPARM_LEN(pt->com); 236 1.10 ad cmd = pt->com & 0xffff; 237 1.1 ad data = pt->data; 238 1.10 ad linux = 1; 239 1.10 ad } else { 240 1.10 ad size = IOCPARM_LEN(cmd); 241 1.10 ad cmd = cmd & 0xffff; 242 1.10 ad linux = 0; 243 1.10 ad } 244 1.1 ad 245 1.51 ad mutex_enter(&iop->sc_conflock); 246 1.10 ad switch (cmd) { 247 1.1 ad case DPT_SIGNATURE: 248 1.1 ad if (size > sizeof(dpti_sig)) 249 1.1 ad size = sizeof(dpti_sig); 250 1.1 ad memcpy(data, &dpti_sig, size); 251 1.17 ad break; 252 1.1 ad 253 1.1 ad case DPT_CTRLINFO: 254 1.17 ad rv = dpti_ctlrinfo(sc, size, data); 255 1.17 ad break; 256 1.1 ad 257 1.1 ad case DPT_SYSINFO: 258 1.17 ad rv = dpti_sysinfo(sc, size, data); 259 1.17 ad break; 260 1.1 ad 261 1.1 ad case DPT_BLINKLED: 262 1.1 ad if ((i = dpti_blinkled(sc)) == -1) 263 1.1 ad i = 0; 264 1.1 ad 265 1.17 ad if (size == 0) { 266 1.33 christos rv = copyout(&i, *(void **)data, sizeof(i)); 267 1.17 ad break; 268 1.17 ad } 269 1.1 ad 270 1.1 ad *(int *)data = i; 271 1.17 ad break; 272 1.1 ad 273 1.1 ad case DPT_TARGET_BUSY: 274 1.1 ad /* 275 1.1 ad * XXX This is here to stop linux_machdepioctl() from 276 1.10 ad * whining about an unknown ioctl. 277 1.1 ad */ 278 1.17 ad rv = EIO; 279 1.17 ad break; 280 1.1 ad 281 1.1 ad case DPT_I2OUSRCMD: 282 1.31 elad rv = kauth_authorize_device_passthru(l->l_cred, dev, 283 1.31 elad KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_ALL, data); 284 1.29 elad if (rv) 285 1.25 christos break; 286 1.25 christos 287 1.44 rmind if (linux) { 288 1.21 christos rv = dpti_passthrough(sc, data, l->l_proc); 289 1.44 rmind } else { 290 1.33 christos rv = dpti_passthrough(sc, *(void **)data, l->l_proc); 291 1.44 rmind } 292 1.17 ad break; 293 1.1 ad 294 1.1 ad case DPT_I2ORESETCMD: 295 1.1 ad printf("%s: I2ORESETCMD not implemented\n", 296 1.45 chs device_xname(sc->sc_dev)); 297 1.17 ad rv = EOPNOTSUPP; 298 1.17 ad break; 299 1.1 ad 300 1.1 ad case DPT_I2ORESCANCMD: 301 1.17 ad rv = iop_reconfigure(iop, 0); 302 1.17 ad break; 303 1.1 ad 304 1.1 ad default: 305 1.17 ad rv = ENOTTY; 306 1.17 ad break; 307 1.1 ad } 308 1.51 ad mutex_exit(&iop->sc_conflock); 309 1.17 ad 310 1.17 ad return (rv); 311 1.1 ad } 312 1.1 ad 313 1.1 ad int 314 1.1 ad dpti_blinkled(struct dpti_softc *sc) 315 1.1 ad { 316 1.1 ad struct iop_softc *iop; 317 1.1 ad u_int v; 318 1.1 ad 319 1.45 chs iop = device_private(device_parent(sc->sc_dev)); 320 1.1 ad 321 1.1 ad v = bus_space_read_1(iop->sc_iot, iop->sc_ioh, sc->sc_blinkled + 0); 322 1.1 ad if (v == 0xbc) { 323 1.1 ad v = bus_space_read_1(iop->sc_iot, iop->sc_ioh, 324 1.1 ad sc->sc_blinkled + 1); 325 1.1 ad return (v); 326 1.1 ad } 327 1.1 ad 328 1.1 ad return (-1); 329 1.1 ad } 330 1.1 ad 331 1.1 ad int 332 1.33 christos dpti_ctlrinfo(struct dpti_softc *sc, int size, void *data) 333 1.1 ad { 334 1.2 ad struct dpt_ctlrinfo info; 335 1.1 ad struct iop_softc *iop; 336 1.1 ad int rv, i; 337 1.1 ad 338 1.45 chs iop = device_private(device_parent(sc->sc_dev)); 339 1.1 ad 340 1.2 ad memset(&info, 0, sizeof(info)); 341 1.1 ad 342 1.2 ad info.length = sizeof(info) - sizeof(u_int16_t); 343 1.45 chs info.drvrHBAnum = device_unit(sc->sc_dev); 344 1.2 ad info.baseAddr = iop->sc_memaddr; 345 1.1 ad if ((i = dpti_blinkled(sc)) == -1) 346 1.1 ad i = 0; 347 1.2 ad info.blinkState = i; 348 1.2 ad info.pciBusNum = iop->sc_pcibus; 349 1.2 ad info.pciDeviceNum = iop->sc_pcidev; 350 1.2 ad info.hbaFlags = FLG_OSD_PCI_VALID | FLG_OSD_DMA | FLG_OSD_I2O; 351 1.2 ad info.Interrupt = 10; /* XXX */ 352 1.1 ad 353 1.33 christos if (size > sizeof(char)) { 354 1.50 riastrad memcpy(data, &info, uimin(sizeof(info), size)); 355 1.1 ad rv = 0; 356 1.1 ad } else 357 1.33 christos rv = copyout(&info, *(void **)data, sizeof(info)); 358 1.1 ad 359 1.1 ad return (rv); 360 1.1 ad } 361 1.1 ad 362 1.1 ad int 363 1.33 christos dpti_sysinfo(struct dpti_softc *sc, int size, void *data) 364 1.1 ad { 365 1.2 ad struct dpt_sysinfo info; 366 1.2 ad int rv; 367 1.11 thorpej #ifdef __i386__ 368 1.2 ad int i, j; 369 1.2 ad #endif 370 1.2 ad 371 1.2 ad memset(&info, 0, sizeof(info)); 372 1.2 ad 373 1.11 thorpej #ifdef __i386__ 374 1.2 ad outb (0x70, 0x12); 375 1.2 ad i = inb(0x71); 376 1.2 ad j = i >> 4; 377 1.2 ad if (i == 0x0f) { 378 1.2 ad outb (0x70, 0x19); 379 1.2 ad j = inb (0x71); 380 1.2 ad } 381 1.2 ad info.drive0CMOS = j; 382 1.2 ad 383 1.2 ad j = i & 0x0f; 384 1.2 ad if (i == 0x0f) { 385 1.2 ad outb (0x70, 0x1a); 386 1.2 ad j = inb (0x71); 387 1.2 ad } 388 1.2 ad info.drive1CMOS = j; 389 1.2 ad info.processorFamily = dpti_sig.dsProcessorFamily; 390 1.2 ad 391 1.2 ad /* 392 1.2 ad * Get the conventional memory size from CMOS. 393 1.2 ad */ 394 1.2 ad outb(0x70, 0x16); 395 1.2 ad j = inb(0x71); 396 1.2 ad j <<= 8; 397 1.2 ad outb(0x70, 0x15); 398 1.2 ad j |= inb(0x71); 399 1.2 ad info.conventionalMemSize = j; 400 1.2 ad 401 1.2 ad /* 402 1.2 ad * Get the extended memory size from CMOS. 403 1.2 ad */ 404 1.2 ad outb(0x70, 0x31); 405 1.2 ad j = inb(0x71); 406 1.2 ad j <<= 8; 407 1.2 ad outb(0x70, 0x30); 408 1.2 ad j |= inb(0x71); 409 1.2 ad info.extendedMemSize = j; 410 1.2 ad 411 1.2 ad switch (cpu_class) { 412 1.2 ad case CPUCLASS_386: 413 1.2 ad info.processorType = PROC_386; 414 1.2 ad break; 415 1.2 ad case CPUCLASS_486: 416 1.2 ad info.processorType = PROC_486; 417 1.2 ad break; 418 1.2 ad case CPUCLASS_586: 419 1.2 ad info.processorType = PROC_PENTIUM; 420 1.2 ad break; 421 1.2 ad case CPUCLASS_686: 422 1.2 ad default: 423 1.2 ad info.processorType = PROC_SEXIUM; 424 1.2 ad break; 425 1.2 ad } 426 1.2 ad 427 1.2 ad info.flags = SI_CMOS_Valid | SI_BusTypeValid | 428 1.2 ad SI_MemorySizeValid | SI_NO_SmartROM; 429 1.2 ad #else 430 1.2 ad info.flags = SI_BusTypeValid | SI_NO_SmartROM; 431 1.2 ad #endif 432 1.2 ad 433 1.2 ad info.busType = SI_PCI_BUS; 434 1.1 ad 435 1.1 ad /* 436 1.2 ad * Copy out the info structure to the user. 437 1.1 ad */ 438 1.33 christos if (size > sizeof(char)) { 439 1.50 riastrad memcpy(data, &info, uimin(sizeof(info), size)); 440 1.2 ad rv = 0; 441 1.2 ad } else 442 1.33 christos rv = copyout(&info, *(void **)data, sizeof(info)); 443 1.2 ad 444 1.2 ad return (rv); 445 1.1 ad } 446 1.1 ad 447 1.1 ad int 448 1.33 christos dpti_passthrough(struct dpti_softc *sc, void *data, struct proc *proc) 449 1.1 ad { 450 1.1 ad struct iop_softc *iop; 451 1.1 ad struct i2o_msg mh, *mf; 452 1.1 ad struct i2o_reply rh; 453 1.1 ad struct iop_msg *im; 454 1.1 ad struct dpti_ptbuf bufs[IOP_MAX_MSG_XFERS]; 455 1.1 ad u_int32_t mbtmp[IOP_MAX_MSG_SIZE / sizeof(u_int32_t)]; 456 1.1 ad u_int32_t rbtmp[IOP_MAX_MSG_SIZE / sizeof(u_int32_t)]; 457 1.2 ad int rv, msgsize, repsize, sgoff, i, mapped, nbuf, nfrag, j, sz; 458 1.16 simonb u_int32_t *p, *pmax; 459 1.1 ad 460 1.45 chs iop = device_private(device_parent(sc->sc_dev)); 461 1.2 ad im = NULL; 462 1.1 ad 463 1.1 ad if ((rv = dpti_blinkled(sc)) != -1) { 464 1.1 ad if (rv != 0) { 465 1.45 chs aprint_error_dev(sc->sc_dev, "adapter blinkled = 0x%02x\n", rv); 466 1.1 ad return (EIO); 467 1.1 ad } 468 1.1 ad } 469 1.1 ad 470 1.1 ad /* 471 1.1 ad * Copy in the message frame header and determine the size of the 472 1.1 ad * full message frame. 473 1.1 ad */ 474 1.1 ad if ((rv = copyin(data, &mh, sizeof(mh))) != 0) { 475 1.1 ad DPRINTF(("%s: message copyin failed\n", 476 1.45 chs device_xname(sc->sc_dev))); 477 1.1 ad return (rv); 478 1.1 ad } 479 1.1 ad 480 1.1 ad msgsize = (mh.msgflags >> 14) & ~3; 481 1.1 ad if (msgsize < sizeof(mh) || msgsize >= IOP_MAX_MSG_SIZE) { 482 1.1 ad DPRINTF(("%s: bad message frame size\n", 483 1.45 chs device_xname(sc->sc_dev))); 484 1.1 ad return (EINVAL); 485 1.1 ad } 486 1.1 ad 487 1.1 ad /* 488 1.1 ad * Handle special commands. 489 1.1 ad */ 490 1.1 ad switch (mh.msgfunc >> 24) { 491 1.1 ad case I2O_EXEC_IOP_RESET: 492 1.2 ad printf("%s: I2O_EXEC_IOP_RESET not implemented\n", 493 1.45 chs device_xname(sc->sc_dev)); 494 1.2 ad return (EOPNOTSUPP); 495 1.1 ad 496 1.1 ad case I2O_EXEC_OUTBOUND_INIT: 497 1.2 ad printf("%s: I2O_EXEC_OUTBOUND_INIT not implemented\n", 498 1.45 chs device_xname(sc->sc_dev)); 499 1.2 ad return (EOPNOTSUPP); 500 1.1 ad 501 1.1 ad case I2O_EXEC_SYS_TAB_SET: 502 1.2 ad printf("%s: I2O_EXEC_SYS_TAB_SET not implemented\n", 503 1.45 chs device_xname(sc->sc_dev)); 504 1.2 ad return (EOPNOTSUPP); 505 1.1 ad 506 1.1 ad case I2O_EXEC_STATUS_GET: 507 1.2 ad if ((rv = iop_status_get(iop, 0)) == 0) 508 1.33 christos rv = copyout(&iop->sc_status, (char *)data + msgsize, 509 1.2 ad sizeof(iop->sc_status)); 510 1.1 ad return (rv); 511 1.1 ad } 512 1.1 ad 513 1.1 ad /* 514 1.1 ad * Copy in the full message frame. 515 1.1 ad */ 516 1.1 ad if ((rv = copyin(data, mbtmp, msgsize)) != 0) { 517 1.1 ad DPRINTF(("%s: full message copyin failed\n", 518 1.45 chs device_xname(sc->sc_dev))); 519 1.1 ad return (rv); 520 1.1 ad } 521 1.1 ad 522 1.1 ad /* 523 1.1 ad * Determine the size of the reply frame, and copy it in. 524 1.1 ad */ 525 1.33 christos if ((rv = copyin((char *)data + msgsize, &rh, sizeof(rh))) != 0) { 526 1.1 ad DPRINTF(("%s: reply copyin failed\n", 527 1.45 chs device_xname(sc->sc_dev))); 528 1.1 ad return (rv); 529 1.1 ad } 530 1.1 ad 531 1.1 ad repsize = (rh.msgflags >> 14) & ~3; 532 1.1 ad if (repsize < sizeof(rh) || repsize >= IOP_MAX_MSG_SIZE) { 533 1.1 ad DPRINTF(("%s: bad reply header size\n", 534 1.45 chs device_xname(sc->sc_dev))); 535 1.1 ad return (EINVAL); 536 1.1 ad } 537 1.1 ad 538 1.33 christos if ((rv = copyin((char *)data + msgsize, rbtmp, repsize)) != 0) { 539 1.45 chs DPRINTF(("%s: reply too large\n", device_xname(sc->sc_dev))); 540 1.1 ad return (rv); 541 1.1 ad } 542 1.1 ad 543 1.1 ad /* 544 1.1 ad * If the message has a scatter gather list, it must be comprised of 545 1.1 ad * simple elements. If any one transfer contains multiple segments, 546 1.1 ad * we allocate a temporary buffer for it; otherwise, the buffer will 547 1.2 ad * be mapped directly. 548 1.1 ad */ 549 1.20 fredb mapped = 0; 550 1.1 ad if ((sgoff = ((mh.msgflags >> 4) & 15)) != 0) { 551 1.1 ad if ((sgoff + 2) > (msgsize >> 2)) { 552 1.1 ad DPRINTF(("%s: invalid message size fields\n", 553 1.45 chs device_xname(sc->sc_dev))); 554 1.1 ad return (EINVAL); 555 1.1 ad } 556 1.2 ad 557 1.2 ad memset(bufs, 0, sizeof(bufs)); 558 1.2 ad 559 1.1 ad p = mbtmp + sgoff; 560 1.2 ad pmax = mbtmp + (msgsize >> 2) - 2; 561 1.1 ad 562 1.2 ad for (nbuf = 0; nbuf < IOP_MAX_MSG_XFERS; nbuf++, p += 2) { 563 1.2 ad if (p > pmax) { 564 1.1 ad DPRINTF(("%s: invalid SGL (1)\n", 565 1.45 chs device_xname(sc->sc_dev))); 566 1.2 ad goto bad; 567 1.1 ad } 568 1.1 ad 569 1.1 ad if ((p[0] & 0x30000000) != I2O_SGL_SIMPLE) { 570 1.1 ad DPRINTF(("%s: invalid SGL (2)\n", 571 1.45 chs device_xname(sc->sc_dev))); 572 1.2 ad goto bad; 573 1.1 ad } 574 1.1 ad 575 1.1 ad bufs[nbuf].db_out = (p[0] & I2O_SGL_DATA_OUT) != 0; 576 1.2 ad bufs[nbuf].db_ptr = NULL; 577 1.1 ad 578 1.1 ad if ((p[0] & I2O_SGL_END_BUFFER) != 0) { 579 1.1 ad if ((p[0] & 0x00ffffff) > IOP_MAX_XFER) { 580 1.1 ad DPRINTF(("%s: buffer too large\n", 581 1.45 chs device_xname(sc->sc_dev))); 582 1.2 ad goto bad; 583 1.1 ad } 584 1.1 ad 585 1.47 christos // XXX: 32 bits 586 1.47 christos bufs[nbuf].db_ptr = (void *)(intptr_t)p[1]; 587 1.1 ad bufs[nbuf].db_proc = proc; 588 1.1 ad bufs[nbuf].db_size = p[0] & 0x00ffffff; 589 1.1 ad 590 1.1 ad if ((p[0] & I2O_SGL_END) != 0) 591 1.1 ad break; 592 1.1 ad 593 1.1 ad continue; 594 1.1 ad } 595 1.1 ad 596 1.2 ad /* 597 1.2 ad * The buffer has multiple segments. Determine the 598 1.2 ad * total size. 599 1.2 ad */ 600 1.2 ad nfrag = 0; 601 1.2 ad sz = 0; 602 1.16 simonb for (; p <= pmax; p += 2) { 603 1.2 ad if (nfrag == DPTI_MAX_SEGS) { 604 1.2 ad DPRINTF(("%s: too many segments\n", 605 1.45 chs device_xname(sc->sc_dev))); 606 1.2 ad goto bad; 607 1.2 ad } 608 1.2 ad 609 1.2 ad bufs[nbuf].db_frags[nfrag].iov_len = 610 1.2 ad p[0] & 0x00ffffff; 611 1.47 christos // XXX: 32 bits 612 1.19 perry bufs[nbuf].db_frags[nfrag].iov_base = 613 1.47 christos (void *)(intptr_t)p[1]; 614 1.2 ad 615 1.2 ad sz += p[0] & 0x00ffffff; 616 1.2 ad nfrag++; 617 1.2 ad 618 1.2 ad if ((p[0] & I2O_SGL_END) != 0) { 619 1.2 ad if ((p[0] & I2O_SGL_END_BUFFER) == 0) { 620 1.2 ad DPRINTF(( 621 1.2 ad "%s: invalid SGL (3)\n", 622 1.45 chs device_xname(sc->sc_dev))); 623 1.2 ad goto bad; 624 1.2 ad } 625 1.2 ad break; 626 1.2 ad } 627 1.2 ad if ((p[0] & I2O_SGL_END_BUFFER) != 0) 628 1.2 ad break; 629 1.2 ad } 630 1.2 ad bufs[nbuf].db_nfrag = nfrag; 631 1.2 ad 632 1.2 ad if (p > pmax) { 633 1.2 ad DPRINTF(("%s: invalid SGL (4)\n", 634 1.45 chs device_xname(sc->sc_dev))); 635 1.2 ad goto bad; 636 1.2 ad } 637 1.2 ad 638 1.2 ad if (sz > IOP_MAX_XFER) { 639 1.2 ad DPRINTF(("%s: buffer too large\n", 640 1.45 chs device_xname(sc->sc_dev))); 641 1.2 ad goto bad; 642 1.2 ad } 643 1.2 ad 644 1.2 ad bufs[nbuf].db_size = sz; 645 1.51 ad bufs[nbuf].db_ptr = kmem_zalloc(sz, KM_SLEEP); 646 1.2 ad 647 1.2 ad for (i = 0, sz = 0; i < bufs[nbuf].db_nfrag; i++) { 648 1.2 ad rv = copyin(bufs[nbuf].db_frags[i].iov_base, 649 1.33 christos (char *)bufs[nbuf].db_ptr + sz, 650 1.2 ad bufs[nbuf].db_frags[i].iov_len); 651 1.2 ad if (rv != 0) { 652 1.2 ad DPRINTF(("%s: frag copyin\n", 653 1.45 chs device_xname(sc->sc_dev))); 654 1.2 ad goto bad; 655 1.2 ad } 656 1.2 ad sz += bufs[nbuf].db_frags[i].iov_len; 657 1.2 ad } 658 1.2 ad 659 1.2 ad if ((p[0] & I2O_SGL_END) != 0) 660 1.2 ad break; 661 1.1 ad } 662 1.1 ad 663 1.1 ad if (nbuf == IOP_MAX_MSG_XFERS) { 664 1.1 ad DPRINTF(("%s: too many transfers\n", 665 1.45 chs device_xname(sc->sc_dev))); 666 1.2 ad goto bad; 667 1.1 ad } 668 1.15 mycroft } else 669 1.15 mycroft nbuf = -1; 670 1.1 ad 671 1.1 ad /* 672 1.1 ad * Allocate a wrapper, and adjust the message header fields to 673 1.1 ad * indicate that no scatter-gather list is currently present. 674 1.1 ad */ 675 1.2 ad 676 1.1 ad im = iop_msg_alloc(iop, IM_WAIT | IM_NOSTATUS); 677 1.1 ad im->im_rb = (struct i2o_reply *)rbtmp; 678 1.1 ad mf = (struct i2o_msg *)mbtmp; 679 1.1 ad mf->msgictx = IOP_ICTX; 680 1.1 ad mf->msgtctx = im->im_tctx; 681 1.1 ad 682 1.1 ad if (sgoff != 0) 683 1.1 ad mf->msgflags = (mf->msgflags & 0xff0f) | (sgoff << 16); 684 1.1 ad 685 1.1 ad /* 686 1.1 ad * Map the data transfer(s). 687 1.1 ad */ 688 1.1 ad for (i = 0; i <= nbuf; i++) { 689 1.1 ad rv = iop_msg_map(iop, im, mbtmp, bufs[i].db_ptr, 690 1.1 ad bufs[i].db_size, bufs[i].db_out, bufs[i].db_proc); 691 1.1 ad if (rv != 0) { 692 1.2 ad DPRINTF(("%s: msg_map failed, rv = %d\n", 693 1.45 chs device_xname(sc->sc_dev), rv)); 694 1.1 ad goto bad; 695 1.1 ad } 696 1.1 ad mapped = 1; 697 1.1 ad } 698 1.1 ad 699 1.1 ad /* 700 1.1 ad * Start the command and sleep until it completes. 701 1.1 ad */ 702 1.1 ad if ((rv = iop_msg_post(iop, im, mbtmp, 5*60*1000)) != 0) 703 1.1 ad goto bad; 704 1.1 ad 705 1.1 ad /* 706 1.1 ad * Copy out the reply frame. 707 1.1 ad */ 708 1.33 christos if ((rv = copyout(rbtmp, (char *)data + msgsize, repsize)) != 0) { 709 1.1 ad DPRINTF(("%s: reply copyout() failed\n", 710 1.45 chs device_xname(sc->sc_dev))); 711 1.27 christos } 712 1.1 ad 713 1.1 ad bad: 714 1.2 ad /* 715 1.2 ad * Free resources and return to the caller. 716 1.2 ad */ 717 1.2 ad if (im != NULL) { 718 1.2 ad if (mapped) 719 1.2 ad iop_msg_unmap(iop, im); 720 1.2 ad iop_msg_free(iop, im); 721 1.2 ad } 722 1.2 ad 723 1.2 ad for (i = 0; i <= nbuf; i++) { 724 1.2 ad if (bufs[i].db_proc != NULL) 725 1.2 ad continue; 726 1.2 ad 727 1.2 ad if (!bufs[i].db_out && rv == 0) { 728 1.2 ad for (j = 0, sz = 0; j < bufs[i].db_nfrag; j++) { 729 1.33 christos rv = copyout((char *)bufs[i].db_ptr + sz, 730 1.2 ad bufs[i].db_frags[j].iov_base, 731 1.2 ad bufs[i].db_frags[j].iov_len); 732 1.2 ad if (rv != 0) 733 1.2 ad break; 734 1.2 ad sz += bufs[i].db_frags[j].iov_len; 735 1.2 ad } 736 1.2 ad } 737 1.1 ad 738 1.2 ad if (bufs[i].db_ptr != NULL) 739 1.51 ad kmem_free(bufs[i].db_ptr, bufs[i].db_size); 740 1.2 ad } 741 1.1 ad 742 1.1 ad return (rv); 743 1.1 ad } 744