fwmem.c revision 124145
11592Srgrimes/* 215645Sjoerg * Copyright (c) 2002-2003 315645Sjoerg * Hidetoshi Shimokawa. All rights reserved. 41592Srgrimes * 51592Srgrimes * Redistribution and use in source and binary forms, with or without 61592Srgrimes * modification, are permitted provided that the following conditions 71592Srgrimes * are met: 81592Srgrimes * 1. Redistributions of source code must retain the above copyright 91592Srgrimes * notice, this list of conditions and the following disclaimer. 101592Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111592Srgrimes * notice, this list of conditions and the following disclaimer in the 121592Srgrimes * documentation and/or other materials provided with the distribution. 131592Srgrimes * 3. All advertising materials mentioning features or use of this software 141592Srgrimes * must display the following acknowledgement: 151592Srgrimes * 161592Srgrimes * This product includes software developed by Hidetoshi Shimokawa. 171592Srgrimes * 181592Srgrimes * 4. Neither the name of the author nor the names of its contributors 191592Srgrimes * may be used to endorse or promote products derived from this software 201592Srgrimes * without specific prior written permission. 211592Srgrimes * 221592Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 231592Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 241592Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 251592Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 261592Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 271592Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 281592Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 291592Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 301592Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 311592Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 321592Srgrimes * SUCH DAMAGE. 331592Srgrimes * 341592Srgrimes */ 3531331Scharnier 3615645Sjoerg#include <sys/cdefs.h> 3715645Sjoerg__FBSDID("$FreeBSD: head/sys/dev/firewire/fwmem.c 124145 2004-01-05 14:21:18Z simokawa $"); 381592Srgrimes 391592Srgrimes#include <sys/param.h> 401592Srgrimes#include <sys/systm.h> 4131331Scharnier#include <sys/types.h> 4231331Scharnier 4331331Scharnier#include <sys/kernel.h> 4431331Scharnier#include <sys/malloc.h> 4550476Speter#include <sys/conf.h> 461592Srgrimes#include <sys/sysctl.h> 471592Srgrimes#if __FreeBSD_version < 500000 481592Srgrimes#include <sys/buf.h> 491592Srgrimes#else 5015645Sjoerg#include <sys/bio.h> 5115645Sjoerg#endif 5215645Sjoerg 5315645Sjoerg#include <sys/bus.h> 5431331Scharnier#include <machine/bus.h> 5515645Sjoerg 562286Sjkh#include <sys/signal.h> 5731331Scharnier#include <sys/mman.h> 5815645Sjoerg#include <sys/ioccom.h> 5931331Scharnier#include <sys/fcntl.h> 602286Sjkh 6115645Sjoerg#include <dev/firewire/firewire.h> 6215645Sjoerg#include <dev/firewire/firewirereg.h> 6315645Sjoerg#include <dev/firewire/fwmem.h> 642286Sjkh 6515645Sjoergstatic int fwmem_speed=2, fwmem_debug=0; 6615645Sjoergstatic struct fw_eui64 fwmem_eui64; 672286SjkhSYSCTL_DECL(_hw_firewire); 6815645SjoergSYSCTL_NODE(_hw_firewire, OID_AUTO, fwmem, CTLFLAG_RD, 0, 691592Srgrimes "FireWire Memory Access"); 701592SrgrimesSYSCTL_UINT(_hw_firewire_fwmem, OID_AUTO, eui64_hi, CTLFLAG_RW, 7115645Sjoerg &fwmem_eui64.hi, 0, "Fwmem target EUI64 high"); 721592SrgrimesSYSCTL_UINT(_hw_firewire_fwmem, OID_AUTO, eui64_lo, CTLFLAG_RW, 7315645Sjoerg &fwmem_eui64.lo, 0, "Fwmem target EUI64 low"); 7415645SjoergSYSCTL_INT(_hw_firewire_fwmem, OID_AUTO, speed, CTLFLAG_RW, &fwmem_speed, 0, 7515645Sjoerg "Fwmem link speed"); 7615645SjoergSYSCTL_INT(_debug, OID_AUTO, fwmem_debug, CTLFLAG_RW, &fwmem_debug, 0, 7715645Sjoerg "Fwmem driver debug flag"); 781592Srgrimes 7915645SjoergMALLOC_DEFINE(M_FWMEM, "fwmem", "fwmem/FireWire"); 8015645Sjoerg 8115645Sjoerg#define MAXLEN (512 << fwmem_speed) 8219697Spst 8319697Spststruct fwmem_softc { 8419697Spst struct fw_eui64 eui; 8519697Spst int refcount; 8619697Spst}; 8719697Spst 8819697Spststatic struct fw_xfer * 8919697Spstfwmem_xfer_req( 9019697Spst struct fw_device *fwdev, 9119697Spst caddr_t sc, 9215645Sjoerg int spd, 9315645Sjoerg int slen, 941592Srgrimes int rlen, 951592Srgrimes void *hand) 961592Srgrimes{ 9722400Sdavidn struct fw_xfer *xfer; 981592Srgrimes 991592Srgrimes xfer = fw_xfer_alloc(M_FWMEM); 1001592Srgrimes if (xfer == NULL) 1011592Srgrimes return NULL; 1021592Srgrimes 1031592Srgrimes xfer->fc = fwdev->fc; 1041592Srgrimes xfer->send.hdr.mode.hdr.dst = FWLOCALBUS | fwdev->dst; 1051592Srgrimes if (spd < 0) 1061592Srgrimes xfer->send.spd = fwdev->speed; 1071592Srgrimes else 1081592Srgrimes xfer->send.spd = min(spd, fwdev->speed); 1091592Srgrimes xfer->act.hand = hand; 1101592Srgrimes xfer->retry_req = fw_asybusy; 1111592Srgrimes xfer->sc = sc; 1121592Srgrimes xfer->send.pay_len = slen; 1131592Srgrimes xfer->recv.pay_len = rlen; 1141592Srgrimes 1151592Srgrimes return xfer; 1161592Srgrimes} 1171592Srgrimes 1181592Srgrimesstruct fw_xfer * 1191592Srgrimesfwmem_read_quad( 1201592Srgrimes struct fw_device *fwdev, 1211592Srgrimes caddr_t sc, 1221592Srgrimes u_int8_t spd, 1231592Srgrimes u_int16_t dst_hi, 1241592Srgrimes u_int32_t dst_lo, 1251592Srgrimes void *data, 1261592Srgrimes void (*hand)(struct fw_xfer *)) 1271592Srgrimes{ 12815645Sjoerg struct fw_xfer *xfer; 12915645Sjoerg struct fw_pkt *fp; 13015645Sjoerg 1311592Srgrimes xfer = fwmem_xfer_req(fwdev, (void *)sc, spd, 0, 4, hand); 13240083Sjkh if (xfer == NULL) { 13340083Sjkh return NULL; 13415645Sjoerg } 13515645Sjoerg 13615645Sjoerg fp = &xfer->send.hdr; 13715645Sjoerg fp->mode.rreqq.tcode = FWTCODE_RREQQ; 13815645Sjoerg fp->mode.rreqq.dest_hi = dst_hi; 13915645Sjoerg fp->mode.rreqq.dest_lo = dst_lo; 14015645Sjoerg 14115645Sjoerg xfer->send.payload = NULL; 14215645Sjoerg xfer->recv.payload = (u_int32_t *)data; 14315645Sjoerg 14422208Sdavidn if (fwmem_debug) 14522208Sdavidn printf("fwmem_read_quad: %d %04x:%08x\n", fwdev->dst, 14622208Sdavidn dst_hi, dst_lo); 14722208Sdavidn 14815645Sjoerg if (fw_asyreq(xfer->fc, -1, xfer) == 0) 14915645Sjoerg return xfer; 15015645Sjoerg 15122208Sdavidn fw_xfer_free(xfer); 15222208Sdavidn return NULL; 1531592Srgrimes} 15415645Sjoerg 15515645Sjoergstruct fw_xfer * 1561592Srgrimesfwmem_write_quad( 1571592Srgrimes struct fw_device *fwdev, 1581592Srgrimes caddr_t sc, 1591592Srgrimes u_int8_t spd, 1601592Srgrimes u_int16_t dst_hi, 1611592Srgrimes u_int32_t dst_lo, 1621592Srgrimes void *data, 1631592Srgrimes void (*hand)(struct fw_xfer *)) 16415645Sjoerg{ 16515645Sjoerg struct fw_xfer *xfer; 1661592Srgrimes struct fw_pkt *fp; 1671592Srgrimes 1681592Srgrimes xfer = fwmem_xfer_req(fwdev, sc, spd, 0, 0, hand); 1691592Srgrimes if (xfer == NULL) 17015645Sjoerg return NULL; 17115645Sjoerg 17215645Sjoerg fp = &xfer->send.hdr; 17315645Sjoerg fp->mode.wreqq.tcode = FWTCODE_WREQQ; 17415645Sjoerg fp->mode.wreqq.dest_hi = dst_hi; 17515645Sjoerg fp->mode.wreqq.dest_lo = dst_lo; 17615645Sjoerg fp->mode.wreqq.data = *(u_int32_t *)data; 17715645Sjoerg 17831331Scharnier xfer->send.payload = xfer->recv.payload = NULL; 17915645Sjoerg 18015645Sjoerg if (fwmem_debug) 18115645Sjoerg printf("fwmem_write_quad: %d %04x:%08x %08x\n", fwdev->dst, 18215645Sjoerg dst_hi, dst_lo, *(u_int32_t *)data); 1831592Srgrimes 1841592Srgrimes if (fw_asyreq(xfer->fc, -1, xfer) == 0) 1852286Sjkh return xfer; 1861592Srgrimes 1872286Sjkh fw_xfer_free(xfer); 18815645Sjoerg return NULL; 18922491Sdavidn} 19015645Sjoerg 19119697Spststruct fw_xfer * 1921592Srgrimesfwmem_read_block( 1931592Srgrimes struct fw_device *fwdev, 1942391Sache caddr_t sc, 1952286Sjkh u_int8_t spd, 19615645Sjoerg u_int16_t dst_hi, 19745422Sbrian u_int32_t dst_lo, 19845422Sbrian int len, 1991592Srgrimes void *data, 2001592Srgrimes void (*hand)(struct fw_xfer *)) 20115645Sjoerg{ 2021592Srgrimes struct fw_xfer *xfer; 20315645Sjoerg struct fw_pkt *fp; 20415645Sjoerg 20515645Sjoerg xfer = fwmem_xfer_req(fwdev, sc, spd, 0, roundup2(len, 4), hand); 20615645Sjoerg if (xfer == NULL) 20715645Sjoerg return NULL; 20815645Sjoerg 20915645Sjoerg fp = &xfer->send.hdr; 21022208Sdavidn fp->mode.rreqb.tcode = FWTCODE_RREQB; 21122208Sdavidn fp->mode.rreqb.dest_hi = dst_hi; 21222208Sdavidn fp->mode.rreqb.dest_lo = dst_lo; 21322208Sdavidn fp->mode.rreqb.len = len; 21422208Sdavidn fp->mode.rreqb.extcode = 0; 21522208Sdavidn 21615645Sjoerg xfer->send.payload = NULL; 2171592Srgrimes xfer->recv.payload = data; 2181592Srgrimes 2191592Srgrimes if (fwmem_debug) 2208870Srgrimes printf("fwmem_read_block: %d %04x:%08x %d\n", fwdev->dst, 2211592Srgrimes dst_hi, dst_lo, len); 2221592Srgrimes if (fw_asyreq(xfer->fc, -1, xfer) == 0) 2231592Srgrimes return xfer; 22422208Sdavidn 2251592Srgrimes fw_xfer_free(xfer); 2261592Srgrimes return NULL; 2271592Srgrimes} 2281592Srgrimes 2291592Srgrimesstruct fw_xfer * 2301592Srgrimesfwmem_write_block( 2311592Srgrimes struct fw_device *fwdev, 23222208Sdavidn caddr_t sc, 23322208Sdavidn u_int8_t spd, 23422208Sdavidn u_int16_t dst_hi, 23522208Sdavidn u_int32_t dst_lo, 23622208Sdavidn int len, 23722208Sdavidn void *data, 23822208Sdavidn void (*hand)(struct fw_xfer *)) 23922208Sdavidn{ 24022208Sdavidn struct fw_xfer *xfer; 24122208Sdavidn struct fw_pkt *fp; 24222208Sdavidn 24322491Sdavidn xfer = fwmem_xfer_req(fwdev, sc, spd, len, 0, hand); 24422208Sdavidn if (xfer == NULL) 2451592Srgrimes return NULL; 2461592Srgrimes 24722208Sdavidn fp = &xfer->send.hdr; 24822208Sdavidn fp->mode.wreqb.tcode = FWTCODE_WREQB; 24922208Sdavidn fp->mode.wreqb.dest_hi = dst_hi; 25022208Sdavidn fp->mode.wreqb.dest_lo = dst_lo; 25122208Sdavidn fp->mode.wreqb.len = len; 25222208Sdavidn fp->mode.wreqb.extcode = 0; 25322208Sdavidn 25422208Sdavidn xfer->send.payload = data; 25522208Sdavidn xfer->recv.payload = NULL; 25622208Sdavidn 25722208Sdavidn if (fwmem_debug) 25822208Sdavidn printf("fwmem_write_block: %d %04x:%08x %d\n", fwdev->dst, 25922208Sdavidn dst_hi, dst_lo, len); 26022208Sdavidn if (fw_asyreq(xfer->fc, -1, xfer) == 0) 26122208Sdavidn return xfer; 26222208Sdavidn 26322208Sdavidn fw_xfer_free(xfer); 26422491Sdavidn return NULL; 26522208Sdavidn} 26622208Sdavidn 26722208Sdavidn 26822208Sdavidnint 26922208Sdavidnfwmem_open (dev_t dev, int flags, int fmt, fw_proc *td) 27022491Sdavidn{ 27122208Sdavidn struct fwmem_softc *fms; 27222208Sdavidn 27322208Sdavidn if (dev->si_drv1 != NULL) { 27422208Sdavidn if ((flags & FWRITE) != 0) 27522208Sdavidn return (EBUSY); 27622208Sdavidn fms = (struct fwmem_softc *)dev->si_drv1; 2771592Srgrimes fms->refcount ++; 2781592Srgrimes } else { 2791592Srgrimes fms = (struct fwmem_softc *)malloc(sizeof(struct fwmem_softc), 28015645Sjoerg M_FWMEM, M_WAITOK); 28122208Sdavidn if (fms == NULL) 28222208Sdavidn return ENOMEM; 28315645Sjoerg bcopy(&fwmem_eui64, &fms->eui, sizeof(struct fw_eui64)); 28415645Sjoerg dev->si_drv1 = (void *)fms; 28515645Sjoerg dev->si_iosize_max = DFLTPHYS; 28615645Sjoerg fms->refcount = 1; 28715645Sjoerg } 28815645Sjoerg if (fwmem_debug) 28915645Sjoerg printf("%s: refcount=%d\n", __FUNCTION__, fms->refcount); 29015645Sjoerg 29115645Sjoerg return (0); 29215645Sjoerg} 29315645Sjoerg 29415645Sjoergint 29515645Sjoergfwmem_close (dev_t dev, int flags, int fmt, fw_proc *td) 29615645Sjoerg{ 29715645Sjoerg struct fwmem_softc *fms; 2981592Srgrimes 2991592Srgrimes fms = (struct fwmem_softc *)dev->si_drv1; 30022491Sdavidn fms->refcount --; 30122491Sdavidn if (fwmem_debug) 30222491Sdavidn printf("%s: refcount=%d\n", __FUNCTION__, fms->refcount); 30322491Sdavidn if (fms->refcount < 1) { 30422491Sdavidn free(dev->si_drv1, M_FW); 30522491Sdavidn dev->si_drv1 = NULL; 30622491Sdavidn } 30722491Sdavidn 30822491Sdavidn return (0); 30922491Sdavidn} 31022491Sdavidn 31122208Sdavidn 3121592Srgrimesstatic void 3131592Srgrimesfwmem_biodone(struct fw_xfer *xfer) 3141592Srgrimes{ 3151592Srgrimes struct bio *bp; 3161592Srgrimes 3171592Srgrimes bp = (struct bio *)xfer->sc; 3181592Srgrimes bp->bio_error = xfer->resp; 3191592Srgrimes 3201592Srgrimes if (bp->bio_error != 0) { 3211592Srgrimes if (fwmem_debug) 3221592Srgrimes printf("%s: err=%d\n", __FUNCTION__, bp->bio_error); 32321120Smsmith bp->bio_flags |= BIO_ERROR; 32422208Sdavidn bp->bio_resid = bp->bio_bcount; 32522208Sdavidn } 32622208Sdavidn 32722208Sdavidn fw_xfer_free(xfer); 32822208Sdavidn biodone(bp); 32922208Sdavidn} 33022208Sdavidn 33122208Sdavidnvoid 33222208Sdavidnfwmem_strategy(struct bio *bp) 33322208Sdavidn{ 33422208Sdavidn struct firewire_softc *sc; 33522208Sdavidn struct fwmem_softc *fms; 33622208Sdavidn struct fw_device *fwdev; 33722208Sdavidn struct fw_xfer *xfer; 33822491Sdavidn dev_t dev; 33922208Sdavidn int unit, err=0, s, iolen; 3401592Srgrimes 3411592Srgrimes dev = bp->bio_dev; 3421592Srgrimes /* XXX check request length */ 34315659Sache 34415659Sache unit = DEV2UNIT(dev); 34522208Sdavidn sc = devclass_get_softc(firewire_devclass, unit); 3461592Srgrimes 3471592Srgrimes s = splfw(); 3481592Srgrimes fms = (struct fwmem_softc *)dev->si_drv1; 3491592Srgrimes fwdev = fw_noderesolve_eui64(sc->fc, &fms->eui); 3501592Srgrimes if (fwdev == NULL) { 3511592Srgrimes if (fwmem_debug) 35245291Speter printf("fwmem: no such device ID:%08x%08x\n", 35345291Speter fms->eui.hi, fms->eui.lo); 35445291Speter err = EINVAL; 35545291Speter goto error; 35645291Speter } 35745291Speter 35845291Speter iolen = MIN(bp->bio_bcount, MAXLEN); 35945291Speter if ((bp->bio_cmd & BIO_READ) == BIO_READ) { 36045291Speter if (iolen == 4 && (bp->bio_offset & 3) == 0) 36145291Speter xfer = fwmem_read_quad(fwdev, 36245291Speter (void *) bp, fwmem_speed, 36345291Speter bp->bio_offset >> 32, bp->bio_offset & 0xffffffff, 36445291Speter bp->bio_data, fwmem_biodone); 36545291Speter else 36645291Speter xfer = fwmem_read_block(fwdev, 36745291Speter (void *) bp, fwmem_speed, 36845291Speter bp->bio_offset >> 32, bp->bio_offset & 0xffffffff, 36926415Sdavidn iolen, bp->bio_data, fwmem_biodone); 37026415Sdavidn } else { 37144615Sbrian if (iolen == 4 && (bp->bio_offset & 3) == 0) 37244615Sbrian xfer = fwmem_write_quad(fwdev, 37344615Sbrian (void *)bp, fwmem_speed, 37419697Spst bp->bio_offset >> 32, bp->bio_offset & 0xffffffff, 37519697Spst bp->bio_data, fwmem_biodone); 37619697Spst else 37745291Speter xfer = fwmem_write_block(fwdev, 3781592Srgrimes (void *)bp, fwmem_speed, 3791592Srgrimes bp->bio_offset >> 32, bp->bio_offset & 0xffffffff, 38015645Sjoerg iolen, bp->bio_data, fwmem_biodone); 3811592Srgrimes } 3821592Srgrimes if (xfer == NULL) { 3831592Srgrimes err = EIO; 3841592Srgrimes goto error; 3851592Srgrimes } 3861592Srgrimes /* XXX */ 3871592Srgrimes bp->bio_resid = bp->bio_bcount - iolen; 3881592Srgrimeserror: 38915645Sjoerg splx(s); 39015645Sjoerg if (err != 0) { 39115645Sjoerg if (fwmem_debug) 39215645Sjoerg printf("%s: err=%d\n", __FUNCTION__, err); 39315645Sjoerg bp->bio_error = err; 39415645Sjoerg bp->bio_flags |= BIO_ERROR; 39515645Sjoerg bp->bio_resid = bp->bio_bcount; 39615645Sjoerg biodone(bp); 39715645Sjoerg } 39815645Sjoerg} 39915645Sjoerg 40022208Sdavidnint 40122208Sdavidnfwmem_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td) 40215645Sjoerg{ 40315645Sjoerg struct fwmem_softc *fms; 40415645Sjoerg int err = 0; 4051592Srgrimes 4061592Srgrimes fms = (struct fwmem_softc *)dev->si_drv1; 4071592Srgrimes switch (cmd) { 4081592Srgrimes case FW_SDEUI64: 40915645Sjoerg bcopy(data, &fms->eui, sizeof(struct fw_eui64)); 41015645Sjoerg break; 41115645Sjoerg case FW_GDEUI64: 41245291Speter bcopy(&fms->eui, data, sizeof(struct fw_eui64)); 41345291Speter break; 4141592Srgrimes default: 4151592Srgrimes err = EINVAL; 4161592Srgrimes } 4171592Srgrimes return(err); 4181592Srgrimes} 41915645Sjoergint 4201592Srgrimesfwmem_poll (dev_t dev, int events, fw_proc *td) 4211592Srgrimes{ 4221592Srgrimes return EINVAL; 4231592Srgrimes} 4241592Srgrimesint 42515645Sjoerg#if __FreeBSD_version < 500102 42622208Sdavidnfwmem_mmap (dev_t dev, vm_offset_t offset, int nproto) 42722208Sdavidn#else 42822208Sdavidnfwmem_mmap (dev_t dev, vm_offset_t offset, vm_paddr_t *paddr, int nproto) 42922208Sdavidn#endif 43022208Sdavidn{ 43122208Sdavidn return EINVAL; 43222208Sdavidn} 43322208Sdavidn