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