1139749Simp/*- 2113584Ssimokawa * Copyright (c) 2002-2003 3103285Sikob * Hidetoshi Shimokawa. All rights reserved. 4272214Skan * 5103285Sikob * Redistribution and use in source and binary forms, with or without 6103285Sikob * modification, are permitted provided that the following conditions 7103285Sikob * are met: 8103285Sikob * 1. Redistributions of source code must retain the above copyright 9103285Sikob * notice, this list of conditions and the following disclaimer. 10103285Sikob * 2. Redistributions in binary form must reproduce the above copyright 11103285Sikob * notice, this list of conditions and the following disclaimer in the 12103285Sikob * documentation and/or other materials provided with the distribution. 13103285Sikob * 3. All advertising materials mentioning features or use of this software 14103285Sikob * must display the following acknowledgement: 15103285Sikob * 16103285Sikob * This product includes software developed by Hidetoshi Shimokawa. 17103285Sikob * 18103285Sikob * 4. Neither the name of the author nor the names of its contributors 19103285Sikob * may be used to endorse or promote products derived from this software 20103285Sikob * without specific prior written permission. 21272214Skan * 22103285Sikob * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23103285Sikob * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24103285Sikob * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25103285Sikob * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26103285Sikob * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27103285Sikob * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28103285Sikob * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29103285Sikob * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30103285Sikob * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31103285Sikob * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32103285Sikob * SUCH DAMAGE. 33272214Skan * 34103285Sikob */ 35103285Sikob 36127468Ssimokawa#ifdef __FreeBSD__ 37119418Sobrien#include <sys/cdefs.h> 38119418Sobrien__FBSDID("$FreeBSD$"); 39127468Ssimokawa#endif 40119418Sobrien 41103285Sikob#include <sys/param.h> 42103285Sikob#include <sys/systm.h> 43103285Sikob#include <sys/types.h> 44103285Sikob 45103285Sikob#include <sys/kernel.h> 46103285Sikob#include <sys/malloc.h> 47103285Sikob#include <sys/conf.h> 48103285Sikob#include <sys/sysctl.h> 49120660Ssimokawa#include <sys/bio.h> 50103285Sikob 51103285Sikob#include <sys/bus.h> 52113584Ssimokawa#include <machine/bus.h> 53103285Sikob 54103285Sikob#include <sys/signal.h> 55103285Sikob#include <sys/mman.h> 56103285Sikob#include <sys/ioccom.h> 57122228Ssimokawa#include <sys/fcntl.h> 58103285Sikob 59103285Sikob#include <dev/firewire/firewire.h> 60103285Sikob#include <dev/firewire/firewirereg.h> 61103285Sikob#include <dev/firewire/fwmem.h> 62103285Sikob 63272214Skanstatic int fwmem_speed = 2, fwmem_debug = 0; 64106810Ssimokawastatic struct fw_eui64 fwmem_eui64; 65103285SikobSYSCTL_DECL(_hw_firewire); 66227309Sedstatic SYSCTL_NODE(_hw_firewire, OID_AUTO, fwmem, CTLFLAG_RD, 0, 67108281Ssimokawa "FireWire Memory Access"); 68106810SsimokawaSYSCTL_UINT(_hw_firewire_fwmem, OID_AUTO, eui64_hi, CTLFLAG_RW, 69106810Ssimokawa &fwmem_eui64.hi, 0, "Fwmem target EUI64 high"); 70110582SsimokawaSYSCTL_UINT(_hw_firewire_fwmem, OID_AUTO, eui64_lo, CTLFLAG_RW, 71106810Ssimokawa &fwmem_eui64.lo, 0, "Fwmem target EUI64 low"); 72103285SikobSYSCTL_INT(_hw_firewire_fwmem, OID_AUTO, speed, CTLFLAG_RW, &fwmem_speed, 0, 73103285Sikob "Fwmem link speed"); 74103285SikobSYSCTL_INT(_debug, OID_AUTO, fwmem_debug, CTLFLAG_RW, &fwmem_debug, 0, 75103285Sikob "Fwmem driver debug flag"); 76103285Sikob 77227293Sedstatic MALLOC_DEFINE(M_FWMEM, "fwmem", "fwmem/FireWire"); 78124145Ssimokawa 79120660Ssimokawa#define MAXLEN (512 << fwmem_speed) 80120660Ssimokawa 81122228Ssimokawastruct fwmem_softc { 82122228Ssimokawa struct fw_eui64 eui; 83170374Ssimokawa struct firewire_softc *sc; 84122228Ssimokawa int refcount; 85122228Ssimokawa}; 86122228Ssimokawa 87106816Ssimokawastatic struct fw_xfer * 88106816Ssimokawafwmem_xfer_req( 89106810Ssimokawa struct fw_device *fwdev, 90106816Ssimokawa caddr_t sc, 91106816Ssimokawa int spd, 92113584Ssimokawa int slen, 93113584Ssimokawa int rlen, 94106816Ssimokawa void *hand) 95103285Sikob{ 96103285Sikob struct fw_xfer *xfer; 97103285Sikob 98124145Ssimokawa xfer = fw_xfer_alloc(M_FWMEM); 99106804Ssimokawa if (xfer == NULL) 100103285Sikob return NULL; 101106804Ssimokawa 102106810Ssimokawa xfer->fc = fwdev->fc; 103120660Ssimokawa xfer->send.hdr.mode.hdr.dst = FWLOCALBUS | fwdev->dst; 104106816Ssimokawa if (spd < 0) 105120660Ssimokawa xfer->send.spd = fwdev->speed; 106106816Ssimokawa else 107120660Ssimokawa xfer->send.spd = min(spd, fwdev->speed); 108167632Ssimokawa xfer->hand = hand; 109106816Ssimokawa xfer->sc = sc; 110120660Ssimokawa xfer->send.pay_len = slen; 111120660Ssimokawa xfer->recv.pay_len = rlen; 112103285Sikob 113106816Ssimokawa return xfer; 114106816Ssimokawa} 115106816Ssimokawa 116106816Ssimokawastruct fw_xfer * 117106816Ssimokawafwmem_read_quad( 118106816Ssimokawa struct fw_device *fwdev, 119106816Ssimokawa caddr_t sc, 120129585Sdfr uint8_t spd, 121129585Sdfr uint16_t dst_hi, 122129585Sdfr uint32_t dst_lo, 123120660Ssimokawa void *data, 124106816Ssimokawa void (*hand)(struct fw_xfer *)) 125106816Ssimokawa{ 126106816Ssimokawa struct fw_xfer *xfer; 127106816Ssimokawa struct fw_pkt *fp; 128106816Ssimokawa 129272214Skan xfer = fwmem_xfer_req(fwdev, sc, spd, 0, 4, hand); 130120660Ssimokawa if (xfer == NULL) { 131106816Ssimokawa return NULL; 132120660Ssimokawa } 133106816Ssimokawa 134120660Ssimokawa fp = &xfer->send.hdr; 135103285Sikob fp->mode.rreqq.tcode = FWTCODE_RREQQ; 136113584Ssimokawa fp->mode.rreqq.dest_hi = dst_hi; 137113584Ssimokawa fp->mode.rreqq.dest_lo = dst_lo; 138103285Sikob 139120660Ssimokawa xfer->send.payload = NULL; 140129585Sdfr xfer->recv.payload = (uint32_t *)data; 141120660Ssimokawa 142103285Sikob if (fwmem_debug) 143106816Ssimokawa printf("fwmem_read_quad: %d %04x:%08x\n", fwdev->dst, 144272214Skan dst_hi, dst_lo); 145106804Ssimokawa 146106810Ssimokawa if (fw_asyreq(xfer->fc, -1, xfer) == 0) 147103285Sikob return xfer; 148106804Ssimokawa 149103285Sikob fw_xfer_free(xfer); 150103285Sikob return NULL; 151103285Sikob} 152103285Sikob 153103285Sikobstruct fw_xfer * 154106810Ssimokawafwmem_write_quad( 155106810Ssimokawa struct fw_device *fwdev, 156106810Ssimokawa caddr_t sc, 157129585Sdfr uint8_t spd, 158129585Sdfr uint16_t dst_hi, 159129585Sdfr uint32_t dst_lo, 160120660Ssimokawa void *data, 161106810Ssimokawa void (*hand)(struct fw_xfer *)) 162106810Ssimokawa{ 163106810Ssimokawa struct fw_xfer *xfer; 164106810Ssimokawa struct fw_pkt *fp; 165106810Ssimokawa 166120660Ssimokawa xfer = fwmem_xfer_req(fwdev, sc, spd, 0, 0, hand); 167106810Ssimokawa if (xfer == NULL) 168106810Ssimokawa return NULL; 169106810Ssimokawa 170120660Ssimokawa fp = &xfer->send.hdr; 171110072Ssimokawa fp->mode.wreqq.tcode = FWTCODE_WREQQ; 172113584Ssimokawa fp->mode.wreqq.dest_hi = dst_hi; 173113584Ssimokawa fp->mode.wreqq.dest_lo = dst_lo; 174129585Sdfr fp->mode.wreqq.data = *(uint32_t *)data; 175106810Ssimokawa 176120660Ssimokawa xfer->send.payload = xfer->recv.payload = NULL; 177106810Ssimokawa 178106810Ssimokawa if (fwmem_debug) 179106816Ssimokawa printf("fwmem_write_quad: %d %04x:%08x %08x\n", fwdev->dst, 180272214Skan dst_hi, dst_lo, *(uint32_t *)data); 181106810Ssimokawa 182106810Ssimokawa if (fw_asyreq(xfer->fc, -1, xfer) == 0) 183106810Ssimokawa return xfer; 184106810Ssimokawa 185106810Ssimokawa fw_xfer_free(xfer); 186106810Ssimokawa return NULL; 187106810Ssimokawa} 188106810Ssimokawa 189106810Ssimokawastruct fw_xfer * 190103285Sikobfwmem_read_block( 191106810Ssimokawa struct fw_device *fwdev, 192106810Ssimokawa caddr_t sc, 193129585Sdfr uint8_t spd, 194129585Sdfr uint16_t dst_hi, 195129585Sdfr uint32_t dst_lo, 196106804Ssimokawa int len, 197120660Ssimokawa void *data, 198106804Ssimokawa void (*hand)(struct fw_xfer *)) 199103285Sikob{ 200103285Sikob struct fw_xfer *xfer; 201103285Sikob struct fw_pkt *fp; 202272214Skan 203120660Ssimokawa xfer = fwmem_xfer_req(fwdev, sc, spd, 0, roundup2(len, 4), hand); 204106804Ssimokawa if (xfer == NULL) 205103285Sikob return NULL; 206106804Ssimokawa 207120660Ssimokawa fp = &xfer->send.hdr; 208103285Sikob fp->mode.rreqb.tcode = FWTCODE_RREQB; 209113584Ssimokawa fp->mode.rreqb.dest_hi = dst_hi; 210113584Ssimokawa fp->mode.rreqb.dest_lo = dst_lo; 211113584Ssimokawa fp->mode.rreqb.len = len; 212120660Ssimokawa fp->mode.rreqb.extcode = 0; 213103285Sikob 214120660Ssimokawa xfer->send.payload = NULL; 215120660Ssimokawa xfer->recv.payload = data; 216120660Ssimokawa 217103285Sikob if (fwmem_debug) 218106816Ssimokawa printf("fwmem_read_block: %d %04x:%08x %d\n", fwdev->dst, 219272214Skan dst_hi, dst_lo, len); 220106810Ssimokawa if (fw_asyreq(xfer->fc, -1, xfer) == 0) 221103285Sikob return xfer; 222106804Ssimokawa 223103285Sikob fw_xfer_free(xfer); 224103285Sikob return NULL; 225103285Sikob} 226103285Sikob 227110337Ssimokawastruct fw_xfer * 228110337Ssimokawafwmem_write_block( 229110337Ssimokawa struct fw_device *fwdev, 230110337Ssimokawa caddr_t sc, 231129585Sdfr uint8_t spd, 232129585Sdfr uint16_t dst_hi, 233129585Sdfr uint32_t dst_lo, 234110337Ssimokawa int len, 235120660Ssimokawa void *data, 236110337Ssimokawa void (*hand)(struct fw_xfer *)) 237110337Ssimokawa{ 238110337Ssimokawa struct fw_xfer *xfer; 239110337Ssimokawa struct fw_pkt *fp; 240110337Ssimokawa 241120660Ssimokawa xfer = fwmem_xfer_req(fwdev, sc, spd, len, 0, hand); 242110337Ssimokawa if (xfer == NULL) 243110337Ssimokawa return NULL; 244110337Ssimokawa 245120660Ssimokawa fp = &xfer->send.hdr; 246110406Ssimokawa fp->mode.wreqb.tcode = FWTCODE_WREQB; 247113584Ssimokawa fp->mode.wreqb.dest_hi = dst_hi; 248113584Ssimokawa fp->mode.wreqb.dest_lo = dst_lo; 249113584Ssimokawa fp->mode.wreqb.len = len; 250120660Ssimokawa fp->mode.wreqb.extcode = 0; 251110337Ssimokawa 252120660Ssimokawa xfer->send.payload = data; 253120660Ssimokawa xfer->recv.payload = NULL; 254120660Ssimokawa 255110337Ssimokawa if (fwmem_debug) 256110337Ssimokawa printf("fwmem_write_block: %d %04x:%08x %d\n", fwdev->dst, 257110337Ssimokawa dst_hi, dst_lo, len); 258110337Ssimokawa if (fw_asyreq(xfer->fc, -1, xfer) == 0) 259110337Ssimokawa return xfer; 260110337Ssimokawa 261110337Ssimokawa fw_xfer_free(xfer); 262110337Ssimokawa return NULL; 263110337Ssimokawa} 264110337Ssimokawa 265103285Sikobint 266272214Skanfwmem_open(struct cdev *dev, int flags, int fmt, fw_proc *td) 267103285Sikob{ 268122228Ssimokawa struct fwmem_softc *fms; 269170374Ssimokawa struct firewire_softc *sc; 270170374Ssimokawa int unit = DEV2UNIT(dev); 271110582Ssimokawa 272170374Ssimokawa sc = devclass_get_softc(firewire_devclass, unit); 273170374Ssimokawa if (sc == NULL) 274170374Ssimokawa return (ENXIO); 275170374Ssimokawa 276170374Ssimokawa FW_GLOCK(sc->fc); 277122228Ssimokawa if (dev->si_drv1 != NULL) { 278170374Ssimokawa if ((flags & FWRITE) != 0) { 279170374Ssimokawa FW_GUNLOCK(sc->fc); 280272214Skan return (EBUSY); 281170374Ssimokawa } 282170374Ssimokawa FW_GUNLOCK(sc->fc); 283272214Skan fms = dev->si_drv1; 284272214Skan fms->refcount++; 285122228Ssimokawa } else { 286170374Ssimokawa dev->si_drv1 = (void *)-1; 287170374Ssimokawa FW_GUNLOCK(sc->fc); 288170374Ssimokawa dev->si_drv1 = malloc(sizeof(struct fwmem_softc), 289272214Skan M_FWMEM, M_WAITOK); 290170374Ssimokawa dev->si_iosize_max = DFLTPHYS; 291272214Skan fms = dev->si_drv1; 292122228Ssimokawa bcopy(&fwmem_eui64, &fms->eui, sizeof(struct fw_eui64)); 293170374Ssimokawa fms->sc = sc; 294122228Ssimokawa fms->refcount = 1; 295122228Ssimokawa } 296122228Ssimokawa if (fwmem_debug) 297127468Ssimokawa printf("%s: refcount=%d\n", __func__, fms->refcount); 298110582Ssimokawa 299110582Ssimokawa return (0); 300103285Sikob} 301103285Sikob 302103285Sikobint 303130585Sphkfwmem_close (struct cdev *dev, int flags, int fmt, fw_proc *td) 304103285Sikob{ 305122228Ssimokawa struct fwmem_softc *fms; 306115786Ssimokawa 307272214Skan fms = dev->si_drv1; 308170374Ssimokawa 309170374Ssimokawa FW_GLOCK(fms->sc->fc); 310272214Skan fms->refcount--; 311170374Ssimokawa FW_GUNLOCK(fms->sc->fc); 312122228Ssimokawa if (fwmem_debug) 313127468Ssimokawa printf("%s: refcount=%d\n", __func__, fms->refcount); 314122228Ssimokawa if (fms->refcount < 1) { 315137503Ssimokawa free(dev->si_drv1, M_FWMEM); 316122228Ssimokawa dev->si_drv1 = NULL; 317122228Ssimokawa } 318122228Ssimokawa 319110582Ssimokawa return (0); 320103285Sikob} 321103285Sikob 322120660Ssimokawa 323120660Ssimokawastatic void 324120660Ssimokawafwmem_biodone(struct fw_xfer *xfer) 325103285Sikob{ 326120660Ssimokawa struct bio *bp; 327103285Sikob 328120660Ssimokawa bp = (struct bio *)xfer->sc; 329120660Ssimokawa bp->bio_error = xfer->resp; 330120660Ssimokawa 331120660Ssimokawa if (bp->bio_error != 0) { 332121381Ssimokawa if (fwmem_debug) 333127468Ssimokawa printf("%s: err=%d\n", __func__, bp->bio_error); 334120660Ssimokawa bp->bio_flags |= BIO_ERROR; 335120660Ssimokawa bp->bio_resid = bp->bio_bcount; 336106810Ssimokawa } 337103285Sikob 338120660Ssimokawa fw_xfer_free(xfer); 339120660Ssimokawa biodone(bp); 340103285Sikob} 341120660Ssimokawa 342120660Ssimokawavoid 343120660Ssimokawafwmem_strategy(struct bio *bp) 344103285Sikob{ 345122228Ssimokawa struct fwmem_softc *fms; 346110337Ssimokawa struct fw_device *fwdev; 347110337Ssimokawa struct fw_xfer *xfer; 348130585Sphk struct cdev *dev; 349277509Swill int err = 0, iolen; 350110337Ssimokawa 351120660Ssimokawa dev = bp->bio_dev; 352120660Ssimokawa /* XXX check request length */ 353120660Ssimokawa 354272214Skan fms = dev->si_drv1; 355170374Ssimokawa fwdev = fw_noderesolve_eui64(fms->sc->fc, &fms->eui); 356110337Ssimokawa if (fwdev == NULL) { 357110577Ssimokawa if (fwmem_debug) 358110577Ssimokawa printf("fwmem: no such device ID:%08x%08x\n", 359272214Skan fms->eui.hi, fms->eui.lo); 360120660Ssimokawa err = EINVAL; 361120660Ssimokawa goto error; 362110337Ssimokawa } 363110337Ssimokawa 364120660Ssimokawa iolen = MIN(bp->bio_bcount, MAXLEN); 365296591Simp if (bp->bio_cmd == BIO_READ) { 366120660Ssimokawa if (iolen == 4 && (bp->bio_offset & 3) == 0) 367120660Ssimokawa xfer = fwmem_read_quad(fwdev, 368272214Skan (void *)bp, fwmem_speed, 369120660Ssimokawa bp->bio_offset >> 32, bp->bio_offset & 0xffffffff, 370120660Ssimokawa bp->bio_data, fwmem_biodone); 371120660Ssimokawa else 372120660Ssimokawa xfer = fwmem_read_block(fwdev, 373272214Skan (void *)bp, fwmem_speed, 374120660Ssimokawa bp->bio_offset >> 32, bp->bio_offset & 0xffffffff, 375120660Ssimokawa iolen, bp->bio_data, fwmem_biodone); 376120660Ssimokawa } else { 377120660Ssimokawa if (iolen == 4 && (bp->bio_offset & 3) == 0) 378120660Ssimokawa xfer = fwmem_write_quad(fwdev, 379120660Ssimokawa (void *)bp, fwmem_speed, 380120660Ssimokawa bp->bio_offset >> 32, bp->bio_offset & 0xffffffff, 381120660Ssimokawa bp->bio_data, fwmem_biodone); 382120660Ssimokawa else 383120660Ssimokawa xfer = fwmem_write_block(fwdev, 384120660Ssimokawa (void *)bp, fwmem_speed, 385120660Ssimokawa bp->bio_offset >> 32, bp->bio_offset & 0xffffffff, 386120660Ssimokawa iolen, bp->bio_data, fwmem_biodone); 387110337Ssimokawa } 388120660Ssimokawa if (xfer == NULL) { 389120660Ssimokawa err = EIO; 390120660Ssimokawa goto error; 391120660Ssimokawa } 392120660Ssimokawa /* XXX */ 393120660Ssimokawa bp->bio_resid = bp->bio_bcount - iolen; 394120660Ssimokawaerror: 395120660Ssimokawa if (err != 0) { 396121381Ssimokawa if (fwmem_debug) 397127468Ssimokawa printf("%s: err=%d\n", __func__, err); 398120660Ssimokawa bp->bio_error = err; 399120660Ssimokawa bp->bio_flags |= BIO_ERROR; 400120660Ssimokawa bp->bio_resid = bp->bio_bcount; 401120660Ssimokawa biodone(bp); 402120660Ssimokawa } 403103285Sikob} 404110337Ssimokawa 405103285Sikobint 406272214Skanfwmem_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, fw_proc *td) 407103285Sikob{ 408122228Ssimokawa struct fwmem_softc *fms; 409110582Ssimokawa int err = 0; 410122228Ssimokawa 411272214Skan fms = dev->si_drv1; 412110582Ssimokawa switch (cmd) { 413110582Ssimokawa case FW_SDEUI64: 414122228Ssimokawa bcopy(data, &fms->eui, sizeof(struct fw_eui64)); 415110582Ssimokawa break; 416110582Ssimokawa case FW_GDEUI64: 417122228Ssimokawa bcopy(&fms->eui, data, sizeof(struct fw_eui64)); 418110582Ssimokawa break; 419110582Ssimokawa default: 420110582Ssimokawa err = EINVAL; 421110582Ssimokawa } 422272214Skan return (err); 423103285Sikob} 424272214Skan 425103285Sikobint 426272214Skanfwmem_poll(struct cdev *dev, int events, fw_proc *td) 427272214Skan{ 428103285Sikob return EINVAL; 429103285Sikob} 430272214Skan 431103285Sikobint 432272214Skanfwmem_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, 433201223Srnoland int nproto, vm_memattr_t *memattr) 434272214Skan{ 435103285Sikob return EINVAL; 436103285Sikob} 437