1/*- 2 * ---------------------------------------------------------------------------- 3 * "THE BEER-WARE LICENSE" (Revision 42): 4 * <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you 5 * can do whatever you want with this stuff. If we meet some day, and you think 6 * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp 7 * ---------------------------------------------------------------------------- 8 * 9 * $FreeBSD$ 10 * 11 */ 12 13#include "opt_md.h" 14#include "opt_ski.h" 15 16#include <sys/param.h> 17#include <sys/systm.h> 18#include <sys/bio.h> 19#include <sys/conf.h> 20#include <sys/kernel.h> 21#include <sys/linker.h> 22#include <sys/lock.h> 23#include <sys/malloc.h> 24#include <sys/mutex.h> 25#include <sys/queue.h> 26#include <sys/sysctl.h> 27#include <sys/proc.h> 28#include <vm/vm.h> 29#include <vm/vm_kern.h> 30#include <vm/vm_page.h> 31#include <vm/vm_map.h> 32#include <vm/vm_extern.h> 33#include <vm/vm_object.h> 34#include <vm/vm_pager.h> 35#include <machine/md_var.h> 36#include <geom/geom_disk.h> 37 38#ifndef SKI_ROOT_FILESYSTEM 39#define SKI_ROOT_FILESYSTEM "ia64-root.fs" 40#endif 41 42#define SSC_OPEN 50 43#define SSC_CLOSE 51 44#define SSC_READ 52 45#define SSC_WRITE 53 46#define SSC_GET_COMPLETION 54 47#define SSC_WAIT_COMPLETION 55 48 49struct disk_req { 50 unsigned long addr; 51 unsigned len; 52}; 53 54struct disk_stat { 55 int fd; 56 unsigned count; 57}; 58 59static u_int64_t 60ssc(u_int64_t in0, u_int64_t in1, u_int64_t in2, u_int64_t in3, int which) 61{ 62 register u_int64_t ret0 __asm("r8"); 63 64 __asm __volatile("mov r15=%1\n\t" 65 "break 0x80001" 66 : "=r"(ret0) 67 : "r"(which), "r"(in0), "r"(in1), "r"(in2), "r"(in3)); 68 return ret0; 69} 70 71#ifndef SSC_NSECT 72#define SSC_NSECT 409600 73#endif 74 75static MALLOC_DEFINE(M_SSC, "ssc_disk", "Simulator Disk"); 76 77static d_strategy_t sscstrategy; 78 79static LIST_HEAD(, ssc_s) ssc_softc_list = LIST_HEAD_INITIALIZER(ssc_softc_list); 80 81struct ssc_s { 82 int unit; 83 LIST_ENTRY(ssc_s) list; 84 struct bio_queue_head bio_queue; 85 struct disk *disk; 86 struct cdev *dev; 87 int busy; 88 int fd; 89}; 90 91static int sscunits; 92 93static void 94sscstrategy(struct bio *bp) 95{ 96 struct ssc_s *sc; 97 int s; 98 struct disk_req req; 99 struct disk_stat stat; 100 u_long len, va, off; 101 102 sc = bp->bio_disk->d_drv1; 103 104 s = splbio(); 105 106 bioq_disksort(&sc->bio_queue, bp); 107 108 if (sc->busy) { 109 splx(s); 110 return; 111 } 112 113 sc->busy++; 114 115 while (1) { 116 bp = bioq_takefirst(&sc->bio_queue); 117 splx(s); 118 if (!bp) 119 break; 120 121 va = (u_long) bp->bio_data; 122 len = bp->bio_bcount; 123 off = bp->bio_pblkno << DEV_BSHIFT; 124 while (len > 0) { 125 u_int t; 126 if ((va & PAGE_MASK) + len > PAGE_SIZE) 127 t = PAGE_SIZE - (va & PAGE_MASK); 128 else 129 t = len; 130 req.len = t; 131 req.addr = ia64_tpa(va); 132 ssc(sc->fd, 1, ia64_tpa((long) &req), off, 133 (bp->bio_cmd == BIO_READ) ? SSC_READ : SSC_WRITE); 134 stat.fd = sc->fd; 135 ssc(ia64_tpa((long)&stat), 0, 0, 0, 136 SSC_WAIT_COMPLETION); 137 va += t; 138 len -= t; 139 off += t; 140 } 141 bp->bio_resid = 0; 142 biodone(bp); 143 s = splbio(); 144 } 145 146 sc->busy = 0; 147 return; 148} 149 150static struct ssc_s * 151ssccreate(int unit) 152{ 153 struct ssc_s *sc; 154 int fd; 155 156 fd = ssc(ia64_tpa((u_int64_t) SKI_ROOT_FILESYSTEM), 157 1, 0, 0, SSC_OPEN); 158 if (fd == -1) 159 return (NULL); 160 161 if (unit == -1) 162 unit = sscunits++; 163 /* Make sure this unit isn't already in action */ 164 LIST_FOREACH(sc, &ssc_softc_list, list) { 165 if (sc->unit == unit) 166 return (NULL); 167 } 168 sc = malloc(sizeof(*sc), M_SSC, M_WAITOK | M_ZERO); 169 LIST_INSERT_HEAD(&ssc_softc_list, sc, list); 170 sc->unit = unit; 171 bioq_init(&sc->bio_queue); 172 173 sc->disk = disk_alloc(); 174 sc->disk->d_drv1 = sc; 175 sc->disk->d_fwheads = 0; 176 sc->disk->d_fwsectors = 0; 177 sc->disk->d_maxsize = DFLTPHYS; 178 sc->disk->d_mediasize = (off_t)SSC_NSECT * DEV_BSIZE; 179 sc->disk->d_name = "sscdisk"; 180 sc->disk->d_sectorsize = DEV_BSIZE; 181 sc->disk->d_strategy = sscstrategy; 182 sc->disk->d_unit = sc->unit; 183 sc->disk->d_flags = DISKFLAG_NEEDSGIANT; 184 disk_create(sc->disk, DISK_VERSION); 185 sc->fd = fd; 186 if (sc->unit == 0) 187 rootdevnames[0] = "ufs:/dev/sscdisk0"; 188 return (sc); 189} 190 191static void 192ssc_drvinit(void *unused) 193{ 194 ssccreate(-1); 195} 196 197SYSINIT(sscdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE, ssc_drvinit,NULL); 198