|
|
1.1 ! root 1: /* ! 2: SCSI Pass-Thru driver for the TD Systems UD? -- Andrew Hume ! 3: Ninth Edition Unix ! 4: */ ! 5: ! 6: #include "sys/param.h" ! 7: #include "sys/user.h" ! 8: #include "sys/buf.h" ! 9: #include "sys/systm.h" ! 10: #include "sys/pte.h" ! 11: #include "sys/map.h" ! 12: #include "sys/ubaddr.h" ! 13: #include "sys/conf.h" ! 14: ! 15: #include "sys/uda.h" ! 16: #include "sys/mscp.h" ! 17: ! 18: #include "sys/scsi.h" ! 19: #include <scsi.h> ! 20: ! 21: #define mscp_scsi m_fmt ! 22: ! 23: struct udadevice { ! 24: short udaip; /* initialization and polling */ ! 25: short udasa; /* status and address */ ! 26: }; ! 27: #define UDA_ERR 0100000 /* error bit */ ! 28: #define UDA_STEP4 0040000 /* step 4 has started */ ! 29: #define UDA_STEP3 0020000 /* step 3 has started */ ! 30: #define UDA_STEP2 0010000 /* step 2 has started */ ! 31: #define UDA_STEP1 0004000 /* step 1 has started */ ! 32: #define UDA_GO 0000001 /* start operation, after init */ ! 33: ! 34: #define UDA_OWN 0x80000000 /* UDA owns this descriptor */ ! 35: #define UDA_INT 0x40000000 /* allow interrupt on ring transition */ ! 36: ! 37: #define WAITPRI (PZERO+1) ! 38: #define SCSILTMT 300 /* long timeout in seconds */ ! 39: #define SCSISTMT 10 /* short timeout in seconds */ ! 40: #define ERROR 0x8000 /* in csr */ ! 41: #define SCSIINTR 0700 ! 42: #define SETDSC(dsc, fl) dsc = (dsc&~(UDA_OWN|UDA_INT))|fl ! 43: ! 44: static memset(p, c, n) ! 45: register char *p, c; ! 46: register n; ! 47: { ! 48: while(n-- > 0) ! 49: *p++ = c; ! 50: } ! 51: ! 52: int scsiopen(), scsiclose(), scsiread(), scsiwrite(); ! 53: ! 54: extern struct scsi scsi[]; ! 55: extern struct ubaddr scsiaddr[]; ! 56: extern int scsicnt; ! 57: struct cdevsw scsicdev = ! 58: cdinit(scsiopen, scsiclose, scsiread, scsiwrite, nodev); ! 59: int scsi_dbg = 0; ! 60: ! 61: scsiopen(dev) ! 62: dev_t dev; ! 63: { ! 64: register struct scsi *p; ! 65: ! 66: if((dev = minor(dev)) >= scsicnt) { ! 67: u.u_error = ENODEV; ! 68: return; ! 69: } ! 70: if((p = &scsi[dev])->flag&OPEN) { ! 71: u.u_error = EBUSY; ! 72: return; ! 73: } ! 74: if(((p->addr = (struct udadevice *)ubaddr(&scsiaddr[dev])) == 0) ! 75: || ubbadaddr(scsiaddr[dev].ubno, (caddr_t)p->addr, sizeof(u_short))) { ! 76: printf("scsi%d absent\n", dev); ! 77: u.u_error = ENODEV; ! 78: return; ! 79: } ! 80: if((p->flag&USED) == 0) ! 81: if(scsistart(dev)) ! 82: return; ! 83: p->flag = USED|OPEN|NEXTWR|DONE; ! 84: } ! 85: ! 86: scsistart(dev) ! 87: dev_t dev; ! 88: { ! 89: register struct scsi *p = &scsi[minor(dev)]; ! 90: ! 91: p->flag |= DONE; ! 92: p->b1 = geteblk(); ! 93: p->b1->b_bcount = BUFSIZE; ! 94: p->b1->b_flags = B_BUSY; ! 95: clrbuf(p->b1); ! 96: p->ub1 = ubmbuf(scsiaddr[minor(dev)].ubno, p->b1, USLP); ! 97: p->u1 = ubadbuf(scsiaddr[minor(dev)].ubno, p->b1, p->ub1); ! 98: p->data = (unsigned char *)p->b1->b_un.b_addr; ! 99: p->b2 = geteblk(); ! 100: p->b2->b_bcount = BUFSIZE; ! 101: p->b2->b_flags = B_BUSY; ! 102: clrbuf(p->b2); ! 103: p->ub2 = ubmbuf(scsiaddr[minor(dev)].ubno, p->b2, USLP); ! 104: p->u2 = ubadbuf(scsiaddr[minor(dev)].ubno, p->b2, p->ub2); ! 105: p->junk = (struct bag *)p->b2->b_un.b_addr; ! 106: p->timeout = SCSISTMT; ! 107: if(scsiinit(dev) == 0){ ! 108: scsiclose(dev); ! 109: p->flag = 0; ! 110: u.u_error = ENXIO; ! 111: return(1); ! 112: } ! 113: printf("scsi%d run\n", minor(dev)); ! 114: return(0); ! 115: } ! 116: ! 117: scsiclose(dev) ! 118: dev_t dev; ! 119: { ! 120: register struct scsi *p = &scsi[minor(dev)]; ! 121: ! 122: if((p->flag&DONE) == 0){ /* wait for I/O to complete */ ! 123: (void)tsleep((caddr_t)p, PZERO+1, p->timeout); ! 124: } ! 125: p->flag = USED; ! 126: } ! 127: ! 128: scsiwrite(dev) ! 129: dev_t dev; ! 130: { ! 131: register count; ! 132: register struct scsi *p = &scsi[minor(dev)]; ! 133: register struct mscmd *cmd = &p->junk->cmd.msg; ! 134: unsigned char flag, bus_id; ! 135: ! 136: if(p->flag&NEXTWR) ! 137: p->flag &= ~NEXTWR; ! 138: else { ! 139: u.u_error = EGREG; ! 140: return; ! 141: } ! 142: if(copyin(u.u_base, &p->tran_id, 4) || copyin(u.u_base+4, &bus_id, 1) ! 143: || copyin(u.u_base+5, &flag, 1) ! 144: || copyin(u.u_base+6, &cmd->mscp_scsi, SCSICMD)){ ! 145: u.u_error = EFAULT; ! 146: return; ! 147: } ! 148: if(flag & SCSI_RESET){ ! 149: if(scsiinit(dev) == 0){ ! 150: printf("scsi%d: reset failed\n", minor(dev)); ! 151: p->flag = 0; ! 152: u.u_error = ENXIO; ! 153: return; ! 154: } ! 155: printf("scsi%d: reset\n", minor(dev)); ! 156: p->flag = USED|OPEN|NEXTWR|DONE; ! 157: u.u_count = 0; ! 158: return; ! 159: } ! 160: p->timeout = (flag&SCSI_LTMOUT)? SCSILTMT:SCSISTMT; ! 161: count = u.u_count - (6+SCSICMD); ! 162: u.u_base += 6+SCSICMD; ! 163: if((count < 0) || (count > SCSIDATA)){ ! 164: u.u_error = EINVAL; ! 165: return; ! 166: } ! 167: memset(p->data, 0xEE, BUFSIZE); ! 168: if(flag&SCSI_RD){ ! 169: cmd->m__r1 = 0106; ! 170: count = scsilen((unsigned char *)&cmd->mscp_scsi); ! 171: } else if(flag&SCSI_WR){ ! 172: if(copyin(u.u_base, p->data, count)){ ! 173: u.u_error = EFAULT; ! 174: return; ! 175: } ! 176: cmd->m__r1 = 0107; ! 177: } else { ! 178: u.u_error = EINVAL; ! 179: return; ! 180: } ! 181: cmd->m_opcd = (flag & SCSI_BRESET)? 0160 : 0130; ! 182: if(scsi_dbg) ! 183: printf("c=%d uc=%d, dir=0%o, bus_id=%d, new count=%d timeout=%d\n", ! 184: count, u.u_count, cmd->m__r1, bus_id, count, p->timeout); ! 185: cmd->m_unit = bus_id; ! 186: cmd->m_bcnt = count; ! 187: cmd->m_fcnt = p->u1; ! 188: p->flag = (p->flag&~DONE)|PEND; ! 189: if(flag&SCSI_SENSE) ! 190: p->flag |= ERRSNSE; ! 191: p->junk->ca.ca_cmdint = 0; ! 192: p->junk->ca.ca_rspint = 0; ! 193: SETDSC(p->junk->ca.ca_cmddsc[0], UDA_OWN); ! 194: bus_id = p->addr->udaip; /* start controller */ ! 195: u.u_count = 0; ! 196: } ! 197: ! 198: scsiread(dev) ! 199: dev_t dev; ! 200: { ! 201: register struct scsi *p = &scsi[minor(dev)]; ! 202: register count; ! 203: ! 204: if(p->flag&NEXTWR){ ! 205: u.u_error = EGREG; ! 206: return; ! 207: } else ! 208: p->flag |= NEXTWR; ! 209: if((p->flag&DONE) == 0){ ! 210: if(tsleep((caddr_t)p, PZERO+1, p->timeout) != TS_OK){ ! 211: u.u_error = ENXIO; ! 212: return; ! 213: } ! 214: } ! 215: if(p->sa&0x8000){ ! 216: printf("scsi%d: error sa=#%x\n", minor(dev), p->sa&0xFFFF); ! 217: u.u_error = EIO; ! 218: scsiinit(dev); ! 219: return; ! 220: } ! 221: count = u.u_count - SCSIRET; ! 222: if(count > p->junk->rsp.msg.m_bcnt) ! 223: count = p->junk->rsp.msg.m_bcnt; ! 224: if((count < 0) || (count > SCSIDATA)){ ! 225: u.u_error = EINVAL; ! 226: return; ! 227: } ! 228: ((unsigned long *)p->status)[0] = p->tran_id; ! 229: p->status[4] = p->junk->rsp.msg.m_fbbk; ! 230: p->status[5] = p->junk->rsp.msg.m_fbbk>>8; ! 231: p->status[6] = 0; /* flags */ ! 232: p->status[7] = 1; /* viking */ ! 233: ((short *)p->status)[4] = p->sa; ! 234: ((short *)p->status)[5] = p->junk->rsp.msg.m_sts; ! 235: if(copyout(p->status, u.u_base, SCSIRET)){ ! 236: u.u_error = EFAULT; ! 237: return; ! 238: } ! 239: if(count) ! 240: if(copyout(p->data, u.u_base+SCSIRET, count)){ ! 241: u.u_error = EFAULT; ! 242: return; ! 243: } ! 244: if(p->junk->rsp.msg.m_sts){ ! 245: printf("scsi%d: stat=#%x\n", minor(dev), p->junk->rsp.msg.m_sts); ! 246: u.u_error = (p->junk->rsp.msg.m_sts == 0x80a)? ESRCH : EIO; ! 247: return; ! 248: } ! 249: u.u_count -= SCSIRET+count; ! 250: SETDSC(p->junk->ca.ca_rspdsc[0], UDA_OWN|UDA_INT); ! 251: } ! 252: ! 253: scsi0int(dev) ! 254: dev_t dev; ! 255: { ! 256: register struct scsi *p = &scsi[minor(dev)]; ! 257: register s; ! 258: ! 259: if((p->flag&PEND) == 0){ ! 260: printf("scsi%d: unexpected interrupt\n", minor(dev)); ! 261: return; ! 262: } ! 263: if(p->junk->ca.ca_rspint == 0){ ! 264: printf("scsi%d: rspint=0 cmdint=%d rsp=#%x cmd=#%x\n", minor(dev), p->junk->ca.ca_cmdint, p->junk->ca.ca_rspdsc[0], p->junk->ca.ca_cmddsc[0]); ! 265: return; ! 266: } ! 267: p->sa = p->addr->udasa; ! 268: s = spl6(); ! 269: p->flag = (p->flag&~PEND)|DONE; ! 270: splx(s); ! 271: wakeup((caddr_t)p); ! 272: } ! 273: ! 274: /* ! 275: * hardware initialization handshake ! 276: * for simplicity, don't bother with init interrupts ! 277: * returns nonzero if ok ! 278: */ ! 279: ! 280: #define UDA_STEPS (UDA_ERR|UDA_STEP4|UDA_STEP3|UDA_STEP2|UDA_STEP1) ! 281: ! 282: scsiinit(d) ! 283: int d; ! 284: { ! 285: register struct scsi *p = &scsi[minor(d)]; ! 286: register struct udadevice *udaddr; ! 287: register int i; ! 288: time_t out; ! 289: int s; ! 290: ! 291: udaddr = p->addr; ! 292: out = time + 11; ! 293: s = spl0(); ! 294: printf("scsi1"); ! 295: udaddr->udaip = 0; ! 296: while((udaddr->udasa & (UDA_ERR|UDA_STEP1)) == 0 && time <= out) ! 297: ; ! 298: if((udaddr->udasa & UDA_STEPS) != UDA_STEP1) { ! 299: steperr("1", udaddr->udasa, d); ! 300: splx(s); ! 301: return (0); ! 302: } ! 303: udaddr->udasa = UDA_ERR|(SCSIINTR/4); ! 304: /* no diagnostic wrap, no interrupts during initialization */ ! 305: printf("2"); ! 306: out = time + 21; ! 307: while((udaddr->udasa & (UDA_ERR|UDA_STEP2)) == 0 && time <= out) ! 308: ; ! 309: if((udaddr->udasa & UDA_STEPS) != UDA_STEP2) { ! 310: steperr("2", udaddr->udasa, d); ! 311: splx(s); ! 312: return (0); ! 313: } ! 314: i = p->u2; /* unibus address of bag */ ! 315: i += (long)&p->junk->ca.ca_rspdsc[0] - (long)p->junk; ! 316: udaddr->udasa = (short)i; ! 317: out = time + 11; ! 318: printf("3"); ! 319: while((udaddr->udasa & (UDA_ERR|UDA_STEP3)) == 0 && time <= out) ! 320: ; ! 321: if((udaddr->udasa & UDA_STEPS) != UDA_STEP3) { ! 322: steperr("3", udaddr->udasa, d); ! 323: splx(s); ! 324: return (0); ! 325: } ! 326: udaddr->udasa = (i >> 16)&0x3F; ! 327: out = time + 11; ! 328: printf("4"); ! 329: while((udaddr->udasa & (UDA_ERR|UDA_STEP4)) == 0 && time <= out) ! 330: ; ! 331: if((udaddr->udasa & UDA_STEPS) != UDA_STEP4) { ! 332: steperr("4", udaddr->udasa, d); ! 333: splx(s); ! 334: return (0); ! 335: } ! 336: i = p->u2 + (long)&p->junk->rsp.msg.m_crf - (long)p->junk; ! 337: p->junk->ca.ca_rspdsc[0] = UDA_OWN|UDA_INT|i; ! 338: i = p->u2 + (long)&p->junk->cmd.msg.m_crf - (long)p->junk; ! 339: p->junk->ca.ca_cmddsc[0] = i; ! 340: if (udaddr->udasa & UDA_ERR) { ! 341: steperr("5", udaddr->udasa, d); ! 342: splx(s); ! 343: return (0); ! 344: } ! 345: udaddr->udasa = UDA_GO; /* finish init */ ! 346: /* finish cmd packet init */ ! 347: p->junk->cmd.msg_len = 44; ! 348: p->junk->cmd.msg.m_crf = (long)p->junk; ! 349: p->junk->cmd.msg.m_opcd = 0130; ! 350: splx(s); ! 351: printf(" done\n"); ! 352: return (1); ! 353: } ! 354: ! 355: steperr(str, sa, dev) ! 356: char *str; ! 357: { ! 358: printf("scsi%d: step%s error, sa=#%x\n", minor(dev), str, sa&0xFFFF); ! 359: } ! 360: ! 361: /* ! 362: dreck to figure out how much we should read back ! 363: */ ! 364: ! 365: scsilen(cmd) ! 366: unsigned char *cmd; ! 367: { ! 368: switch(cmd[0]) ! 369: { ! 370: case 0x03: return(cmd[4]); ! 371: case 0x08: return(cmd[4]*1024); ! 372: case 0x12: return(cmd[4]); ! 373: case 0x1A: return(cmd[4]); ! 374: case 0x1C: return(cmd[3]*256 + cmd[4]); ! 375: case 0x25: return(8); ! 376: case 0x28: return(1024*(256*cmd[7] + cmd[8])); ! 377: case 0x2C: return(6); ! 378: case 0x2D: return(6); ! 379: case 0x4D: return(1*(256*cmd[7] + cmd[8])); ! 380: case 0xC2: return(1024); ! 381: case 0xC3: return(4096); ! 382: case 0xD3: return(20); ! 383: } ! 384: return(0); ! 385: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.