|
|
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: long readback; ! 136: ! 137: if(p->flag&NEXTWR) ! 138: p->flag &= ~NEXTWR; ! 139: else { ! 140: u.u_error = EGREG; ! 141: return; ! 142: } ! 143: if(copyin(u.u_base, &p->tran_id, 4) || copyin(u.u_base+4, &bus_id, 1) ! 144: || copyin(u.u_base+5, &flag, 1) ! 145: || copyin(u.u_base+6, &readback, 4) ! 146: || copyin(u.u_base+10, &cmd->mscp_scsi, SCSICMD)){ ! 147: u.u_error = EFAULT; ! 148: return; ! 149: } ! 150: if(flag & SCSI_RESET){ ! 151: if(scsiinit(dev) == 0){ ! 152: printf("scsi%d: reset failed\n", minor(dev)); ! 153: p->flag = 0; ! 154: u.u_error = ENXIO; ! 155: return; ! 156: } ! 157: printf("scsi%d: reset\n", minor(dev)); ! 158: p->flag = USED|OPEN|NEXTWR|DONE; ! 159: u.u_count = 0; ! 160: return; ! 161: } ! 162: p->timeout = (flag&SCSI_LTMOUT)? SCSILTMT:SCSISTMT; ! 163: count = u.u_count - (10+SCSICMD); ! 164: u.u_base += 10+SCSICMD; ! 165: if((count < 0) || (count > SCSIDATA)){ ! 166: u.u_error = EINVAL; ! 167: return; ! 168: } ! 169: memset(p->data, 0xEE, BUFSIZE); ! 170: if(flag&SCSI_RD){ ! 171: cmd->m__r1 = 0106; ! 172: count = readback; ! 173: } else if(flag&SCSI_WR){ ! 174: if(copyin(u.u_base, p->data, count)){ ! 175: u.u_error = EFAULT; ! 176: return; ! 177: } ! 178: cmd->m__r1 = 0107; ! 179: } else { ! 180: u.u_error = EINVAL; ! 181: return; ! 182: } ! 183: cmd->m_opcd = (flag & SCSI_BRESET)? 0160 : 0130; ! 184: if(scsi_dbg) ! 185: printf("c=%d uc=%d, dir=0%o, bus_id=%d, new count=%d timeout=%d\n", ! 186: count, u.u_count, cmd->m__r1, bus_id, count, p->timeout); ! 187: cmd->m_unit = bus_id; ! 188: cmd->m_bcnt = count; ! 189: cmd->m_fcnt = p->u1; ! 190: p->flag = (p->flag&~DONE)|PEND; ! 191: if(flag&SCSI_SENSE) ! 192: p->flag |= ERRSNSE; ! 193: p->junk->ca.ca_cmdint = 0; ! 194: p->junk->ca.ca_rspint = 0; ! 195: SETDSC(p->junk->ca.ca_cmddsc[0], UDA_OWN); ! 196: bus_id = p->addr->udaip; /* start controller */ ! 197: u.u_count = 0; ! 198: } ! 199: ! 200: scsiread(dev) ! 201: dev_t dev; ! 202: { ! 203: register struct scsi *p = &scsi[minor(dev)]; ! 204: register count; ! 205: ! 206: if(p->flag&NEXTWR){ ! 207: u.u_error = EGREG; ! 208: return; ! 209: } else ! 210: p->flag |= NEXTWR; ! 211: if((p->flag&DONE) == 0){ ! 212: if(tsleep((caddr_t)p, PZERO+1, p->timeout) != TS_OK){ ! 213: u.u_error = ENXIO; ! 214: return; ! 215: } ! 216: } ! 217: if(p->sa&0x8000){ ! 218: printf("scsi%d: error sa=#%x\n", minor(dev), p->sa&0xFFFF); ! 219: u.u_error = EIO; ! 220: scsiinit(dev); ! 221: return; ! 222: } ! 223: count = u.u_count - SCSIRET; ! 224: if(count > p->junk->rsp.msg.m_bcnt) ! 225: count = p->junk->rsp.msg.m_bcnt; ! 226: if((count < 0) || (count > SCSIDATA)){ ! 227: u.u_error = EINVAL; ! 228: return; ! 229: } ! 230: ((unsigned long *)p->status)[0] = p->tran_id; ! 231: p->status[4] = p->junk->rsp.msg.m_fbbk; ! 232: p->status[5] = p->junk->rsp.msg.m_fbbk>>8; ! 233: p->status[6] = 0; /* flags */ ! 234: p->status[7] = 1; /* viking */ ! 235: ((short *)p->status)[4] = p->sa; ! 236: ((short *)p->status)[5] = p->junk->rsp.msg.m_sts; ! 237: if(copyout(p->status, u.u_base, SCSIRET)){ ! 238: u.u_error = EFAULT; ! 239: return; ! 240: } ! 241: if(count) ! 242: if(copyout(p->data, u.u_base+SCSIRET, count)){ ! 243: u.u_error = EFAULT; ! 244: return; ! 245: } ! 246: if(p->junk->rsp.msg.m_sts){ ! 247: printf("scsi%d: stat=#%x\n", minor(dev), p->junk->rsp.msg.m_sts); ! 248: u.u_error = (p->junk->rsp.msg.m_sts == 0x80a)? ESRCH : EIO; ! 249: return; ! 250: } ! 251: u.u_count -= SCSIRET+count; ! 252: SETDSC(p->junk->ca.ca_rspdsc[0], UDA_OWN|UDA_INT); ! 253: } ! 254: ! 255: scsi0int(dev) ! 256: dev_t dev; ! 257: { ! 258: register struct scsi *p = &scsi[minor(dev)]; ! 259: register s; ! 260: ! 261: if((p->flag&PEND) == 0){ ! 262: printf("scsi%d: unexpected interrupt\n", minor(dev)); ! 263: return; ! 264: } ! 265: if(p->junk->ca.ca_rspint == 0){ ! 266: 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]); ! 267: return; ! 268: } ! 269: p->sa = p->addr->udasa; ! 270: s = spl6(); ! 271: p->flag = (p->flag&~PEND)|DONE; ! 272: splx(s); ! 273: wakeup((caddr_t)p); ! 274: } ! 275: ! 276: /* ! 277: * hardware initialization handshake ! 278: * for simplicity, don't bother with init interrupts ! 279: * returns nonzero if ok ! 280: */ ! 281: ! 282: #define UDA_STEPS (UDA_ERR|UDA_STEP4|UDA_STEP3|UDA_STEP2|UDA_STEP1) ! 283: ! 284: scsiinit(d) ! 285: int d; ! 286: { ! 287: register struct scsi *p = &scsi[minor(d)]; ! 288: register struct udadevice *udaddr; ! 289: register int i; ! 290: time_t out; ! 291: int s; ! 292: ! 293: udaddr = p->addr; ! 294: out = time + 11; ! 295: s = spl0(); ! 296: printf("scsi1"); ! 297: udaddr->udaip = 0; ! 298: while((udaddr->udasa & (UDA_ERR|UDA_STEP1)) == 0 && time <= out) ! 299: ; ! 300: if((udaddr->udasa & UDA_STEPS) != UDA_STEP1) { ! 301: steperr("1", udaddr->udasa, d); ! 302: splx(s); ! 303: return (0); ! 304: } ! 305: udaddr->udasa = UDA_ERR|(SCSIINTR/4); ! 306: /* no diagnostic wrap, no interrupts during initialization */ ! 307: printf("2"); ! 308: out = time + 21; ! 309: while((udaddr->udasa & (UDA_ERR|UDA_STEP2)) == 0 && time <= out) ! 310: ; ! 311: if((udaddr->udasa & UDA_STEPS) != UDA_STEP2) { ! 312: steperr("2", udaddr->udasa, d); ! 313: splx(s); ! 314: return (0); ! 315: } ! 316: i = p->u2; /* unibus address of bag */ ! 317: i += (long)&p->junk->ca.ca_rspdsc[0] - (long)p->junk; ! 318: udaddr->udasa = (short)i; ! 319: out = time + 11; ! 320: printf("3"); ! 321: while((udaddr->udasa & (UDA_ERR|UDA_STEP3)) == 0 && time <= out) ! 322: ; ! 323: if((udaddr->udasa & UDA_STEPS) != UDA_STEP3) { ! 324: steperr("3", udaddr->udasa, d); ! 325: splx(s); ! 326: return (0); ! 327: } ! 328: udaddr->udasa = (i >> 16)&0x3F; ! 329: out = time + 11; ! 330: printf("4"); ! 331: while((udaddr->udasa & (UDA_ERR|UDA_STEP4)) == 0 && time <= out) ! 332: ; ! 333: if((udaddr->udasa & UDA_STEPS) != UDA_STEP4) { ! 334: steperr("4", udaddr->udasa, d); ! 335: splx(s); ! 336: return (0); ! 337: } ! 338: i = p->u2 + (long)&p->junk->rsp.msg.m_crf - (long)p->junk; ! 339: p->junk->ca.ca_rspdsc[0] = UDA_OWN|UDA_INT|i; ! 340: i = p->u2 + (long)&p->junk->cmd.msg.m_crf - (long)p->junk; ! 341: p->junk->ca.ca_cmddsc[0] = i; ! 342: if (udaddr->udasa & UDA_ERR) { ! 343: steperr("5", udaddr->udasa, d); ! 344: splx(s); ! 345: return (0); ! 346: } ! 347: udaddr->udasa = UDA_GO; /* finish init */ ! 348: /* finish cmd packet init */ ! 349: p->junk->cmd.msg_len = 44; ! 350: p->junk->cmd.msg.m_crf = (long)p->junk; ! 351: p->junk->cmd.msg.m_opcd = 0130; ! 352: splx(s); ! 353: printf(" done\n"); ! 354: return (1); ! 355: } ! 356: ! 357: steperr(str, sa, dev) ! 358: char *str; ! 359: { ! 360: printf("scsi%d: step%s error, sa=#%x\n", minor(dev), str, sa&0xFFFF); ! 361: } ! 362: ! 363: /* ! 364: dreck to figure out how much we should read back ! 365: */ ! 366: ! 367: scsilen(cmd) ! 368: unsigned char *cmd; ! 369: { ! 370: switch(cmd[0]) ! 371: { ! 372: case 0x03: return(cmd[4]); ! 373: case 0x08: return(cmd[4]*1024); ! 374: case 0x12: return(cmd[4]); ! 375: case 0x1A: return(cmd[4]); ! 376: case 0x1C: return(cmd[3]*256 + cmd[4]); ! 377: case 0x25: return(8); ! 378: case 0x28: return(1024*(256*cmd[7] + cmd[8])); ! 379: case 0x2C: return(6); ! 380: case 0x2D: return(6); ! 381: case 0x4D: return(1*(256*cmd[7] + cmd[8])); ! 382: case 0xC2: return(1024); ! 383: case 0xC3: return(4096); ! 384: case 0xD3: return(20); ! 385: } ! 386: return(0); ! 387: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.