1 /* $NetBSD: ct.c,v 1.6 2006/06/25 17:37:43 tsutsui Exp $ */ 2 3 /* 4 * Copyright (c) 1982, 1990, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 * @(#)ct.c 8.1 (Berkeley) 7/15/93 32 */ 33 34 /* 35 * CS80 tape driver 36 */ 37 #include <sys/param.h> 38 39 #include <machine/stdarg.h> 40 41 #include <hp300/dev/ctreg.h> 42 43 #include <lib/libsa/stand.h> 44 #include <hp300/stand/common/conf.h> 45 #include <hp300/stand/common/hpibvar.h> 46 #include <hp300/stand/common/samachdep.h> 47 48 struct ct_iocmd ct_ioc; 49 struct ct_rscmd ct_rsc; 50 struct ct_stat ct_stat; 51 struct ct_ssmcmd ct_ssmc; 52 53 struct ct_softc { 54 int sc_ctlr; 55 int sc_unit; 56 char sc_retry; 57 char sc_alive; 58 short sc_punit; 59 int sc_blkno; 60 } ct_softc[NHPIB][NCT]; 61 62 #define CTRETRY 5 63 #define MTFSF 10 64 #define MTREW 11 65 66 char ctio_buf[MAXBSIZE]; 67 68 struct ctinfo { 69 short hwid; 70 short punit; 71 } ctinfo[] = { 72 { CT7946ID, 1 }, 73 { CT7912PID, 1 }, 74 { CT7914PID, 1 }, 75 { CT9144ID, 0 }, 76 { CT9145ID, 0 }, 77 }; 78 int nctinfo = sizeof(ctinfo) / sizeof(ctinfo[0]); 79 80 static int ctinit(int, int); 81 static int ctident(int, int); 82 static int cterror(int, int); 83 84 int 85 ctinit(int ctlr, int unit) 86 { 87 struct ct_softc *rs = &ct_softc[ctlr][unit]; 88 uint8_t stat; 89 90 if (hpibrecv(ctlr, unit, C_QSTAT, &stat, 1) != 1 || stat) 91 return 0; 92 if (ctident(ctlr, unit) < 0) 93 return 0; 94 memset(&ct_ssmc, 0, sizeof(ct_ssmc)); 95 ct_ssmc.unit = C_SUNIT(rs->sc_punit); 96 ct_ssmc.cmd = C_SSM; 97 ct_ssmc.fefm = FEF_MASK; 98 ct_ssmc.refm = REF_MASK; 99 ct_ssmc.aefm = AEF_MASK; 100 ct_ssmc.iefm = IEF_MASK; 101 hpibsend(ctlr, unit, C_CMD, (uint8_t *)&ct_ssmc, sizeof(ct_ssmc)); 102 hpibswait(ctlr, unit); 103 hpibrecv(ctlr, unit, C_QSTAT, &stat, 1); 104 rs->sc_alive = 1; 105 return 1; 106 } 107 108 int 109 ctident(int ctlr, int unit) 110 { 111 struct ct_describe desc; 112 uint8_t stat, cmd[3]; 113 char name[7]; 114 int id, i; 115 116 id = hpibid(ctlr, unit); 117 if ((id & 0x200) == 0) 118 return -1; 119 for (i = 0; i < nctinfo; i++) 120 if (id == ctinfo[i].hwid) 121 break; 122 if (i == nctinfo) 123 return -1; 124 ct_softc[ctlr][unit].sc_punit = ctinfo[i].punit; 125 id = i; 126 127 /* 128 * Collect device description. 129 * Right now we only need this to differentiate 7945 from 7946. 130 * Note that we always issue the describe command to unit 0. 131 */ 132 cmd[0] = C_SUNIT(0); 133 cmd[1] = C_SVOL(0); 134 cmd[2] = C_DESC; 135 hpibsend(ctlr, unit, C_CMD, cmd, sizeof(cmd)); 136 hpibrecv(ctlr, unit, C_EXEC, (uint8_t *)&desc, 37); 137 hpibrecv(ctlr, unit, C_QSTAT, &stat, sizeof(stat)); 138 memset(name, 0, sizeof(name)); 139 if (!stat) { 140 int n = desc.d_name; 141 for (i = 5; i >= 0; i--) { 142 name[i] = (n & 0xf) + '0'; 143 n >>= 4; 144 } 145 } 146 switch (ctinfo[id].hwid) { 147 case CT7946ID: 148 if (memcmp(name, "079450", 6) == 0) 149 id = -1; /* not really a 7946 */ 150 break; 151 default: 152 break; 153 } 154 return id; 155 } 156 157 int 158 ctpunit(int ctlr, int slave, int *punit) 159 { 160 struct ct_softc *rs; 161 162 if (ctlr >= NHPIB || hpibalive(ctlr) == 0) 163 return EADAPT; 164 if (slave >= NCT) 165 return ECTLR; 166 rs = &ct_softc[ctlr][slave]; 167 168 if (rs->sc_alive == 0) 169 return ENXIO; 170 171 *punit = rs->sc_punit; 172 return 0; 173 } 174 175 int 176 ctopen(struct open_file *f, ...) 177 { 178 va_list ap; 179 int ctlr, unit, part; 180 struct ct_softc *rs; 181 int skip; 182 size_t resid; 183 184 va_start(ap, f); 185 ctlr = va_arg(ap, int); 186 unit = va_arg(ap, int); 187 part = va_arg(ap, int); 188 va_end(ap); 189 190 if (ctlr >= NHPIB || hpibalive(ctlr) == 0) 191 return EADAPT; 192 if (unit >= NCT) 193 return ECTLR; 194 rs = &ct_softc[ctlr][unit]; 195 rs->sc_blkno = 0; 196 rs->sc_unit = unit; 197 rs->sc_ctlr = ctlr; 198 if (rs->sc_alive == 0) 199 if (ctinit(ctlr, unit) == 0) 200 return ENXIO; 201 f->f_devdata = (void *)rs; 202 ctstrategy(f->f_devdata, MTREW, 0, 0, ctio_buf, &resid); 203 skip = part; 204 while (skip--) 205 ctstrategy(f->f_devdata, MTFSF, 0, 0, ctio_buf, &resid); 206 return 0; 207 } 208 209 int 210 ctclose(struct open_file *f) 211 { 212 size_t resid; 213 214 ctstrategy(f->f_devdata, MTREW, 0, 0, ctio_buf, &resid); 215 return 0; 216 } 217 218 int 219 ctstrategy(void *devdata, int func, daddr_t dblk, size_t size, void *v_buf, 220 size_t *rsize) 221 { 222 struct ct_softc *rs = devdata; 223 uint8_t *buf = v_buf; 224 int ctlr = rs->sc_ctlr; 225 int unit = rs->sc_unit; 226 uint8_t stat; 227 228 if (size == 0 && (func == F_READ || func == F_WRITE)) 229 return 0; 230 231 rs->sc_retry = 0; 232 memset(&ct_ioc, 0, sizeof(ct_ioc)); 233 ct_ioc.unit = C_SUNIT(rs->sc_punit); 234 ct_ioc.saddr = C_SADDR; 235 ct_ioc.nop2 = C_NOP; 236 ct_ioc.slen = C_SLEN; 237 ct_ioc.nop3 = C_NOP; 238 top: 239 if (func == F_READ) { 240 ct_ioc.cmd = C_READ; 241 ct_ioc.addr = rs->sc_blkno; 242 ct_ioc.len = size; 243 } 244 else if (func == F_WRITE) { 245 ct_ioc.cmd = C_WRITE; 246 ct_ioc.addr = rs->sc_blkno; 247 ct_ioc.len = size; 248 } 249 else if (func == MTFSF) { 250 ct_ioc.cmd = C_READ; 251 ct_ioc.addr = rs->sc_blkno; 252 ct_ioc.len = size = MAXBSIZE; 253 } 254 else { 255 ct_ioc.cmd = C_READ; 256 ct_ioc.addr = 0; 257 ct_ioc.len = 0; 258 rs->sc_blkno = 0; 259 size = 0; 260 } 261 retry: 262 hpibsend(ctlr, unit, C_CMD, (uint8_t *)&ct_ioc, sizeof(ct_ioc)); 263 if (func != MTREW) { 264 hpibswait(ctlr, unit); 265 hpibgo(ctlr, unit, C_EXEC, buf, size, 266 func != F_WRITE ? F_READ : F_WRITE); 267 hpibswait(ctlr, unit); 268 } else { 269 while (hpibswait(ctlr, unit) < 0) 270 ; 271 } 272 hpibrecv(ctlr, unit, C_QSTAT, &stat, 1); 273 if (stat) { 274 stat = cterror(ctlr, unit); 275 if (stat == 0) 276 return -1; 277 if (stat == 2) 278 return 0; 279 if (++rs->sc_retry > CTRETRY) 280 return -1; 281 goto retry; 282 } 283 rs->sc_blkno += CTBTOK(size); 284 if (func == MTFSF) 285 goto top; 286 *rsize = size; 287 288 return 0; 289 } 290 291 int 292 cterror(int ctlr, int unit) 293 { 294 struct ct_softc *rs = &ct_softc[ctlr][unit]; 295 uint8_t stat; 296 297 memset(&ct_rsc, 0, sizeof(ct_rsc)); 298 memset(&ct_stat, 0, sizeof(ct_stat)); 299 ct_rsc.unit = C_SUNIT(rs->sc_punit); 300 ct_rsc.cmd = C_STATUS; 301 hpibsend(ctlr, unit, C_CMD, (uint8_t *)&ct_rsc, sizeof(ct_rsc)); 302 hpibrecv(ctlr, unit, C_EXEC, (uint8_t *)&ct_stat, sizeof(ct_stat)); 303 hpibrecv(ctlr, unit, C_QSTAT, &stat, 1); 304 if (stat) { 305 printf("ct%d: request status fail %d\n", unit, stat); 306 return 0; 307 } 308 if (ct_stat.c_aef & AEF_EOF) { 309 /* 9145 drives don't increment block number at EOF */ 310 if ((ct_stat.c_blk - rs->sc_blkno) == 0) 311 rs->sc_blkno++; 312 else 313 rs->sc_blkno = ct_stat.c_blk; 314 return 2; 315 } 316 printf("ct%d err: vu 0x%x, pend 0x%x, bn%ld", unit, 317 ct_stat.c_vu, ct_stat.c_pend, ct_stat.c_blk); 318 printf(", R 0x%x F 0x%x A 0x%x I 0x%x\n", ct_stat.c_ref, 319 ct_stat.c_fef, ct_stat.c_aef, ct_stat.c_ief); 320 return 1; 321 } 322