| 1 | /* udc.c 1.2 86/01/21 */ |
| 2 | |
| 3 | #include "../machine/mtpr.h" |
| 4 | |
| 5 | #include "param.h" |
| 6 | #include "inode.h" |
| 7 | #include "fs.h" |
| 8 | |
| 9 | #include "../tahoevba/vbaparam.h" |
| 10 | #include "../tahoestand/udc.h" |
| 11 | |
| 12 | #include "saio.h" |
| 13 | |
| 14 | #ifdef NOIO |
| 15 | #define MEMDISK 0x80000 /* Memory mapped disk at 1/2 Mega */ |
| 16 | #endif |
| 17 | |
| 18 | /* Some I/O addresses used to generate pulses for scopes */ |
| 19 | #define OUT1 0xffffb034 |
| 20 | #define OUT2 0xffffb018 |
| 21 | #define OUT3 0xffffb020 |
| 22 | #define OUT4 0xffffb004 |
| 23 | #define OUT5 0xffffb024 |
| 24 | #define OUT6 0xffffb00c |
| 25 | #define OUT7 0xffffb02c |
| 26 | |
| 27 | #define IN1 0xffffb030 |
| 28 | #define IN2 0xffffb03c |
| 29 | #define IN3 0xffffb004 |
| 30 | #define IN4 0xffffb00c |
| 31 | #define IN5 0xffffb02c |
| 32 | |
| 33 | #undef scope_in |
| 34 | #undef scope_out |
| 35 | #define scope_out(x) movob(OUT/**/x,0) |
| 36 | #define scope_in(x) dummy = *(char *)(IN/**/x) |
| 37 | |
| 38 | /* |
| 39 | * Universal disk controller driver for the Motorola M68000/IPC. |
| 40 | * Stand-alone version (no interrupts, etc.) |
| 41 | */ |
| 42 | |
| 43 | |
| 44 | static struct UDPAC udpkt = { |
| 45 | 2, 0, 21, 0, 0, 0, 0, SECTSIZ, {0, 0}, 0, 0, 3 |
| 46 | } ; |
| 47 | |
| 48 | long udstd[] = { /* May be used some day to boot from any of |
| 49 | * several UDC controllers */ |
| 50 | 0xf0000 |
| 51 | }; |
| 52 | |
| 53 | /***************************************************** |
| 54 | /* |
| 55 | /*The next layout of major/minor number assignments are for the UDC |
| 56 | /*devices. |
| 57 | /* |
| 58 | /* 1 |
| 59 | /* 5 8 7 4 3 2 0 |
| 60 | /* +----------------+-----+-+-+-----+ |
| 61 | /* | Major device # | |D|R| FLS | |
| 62 | /* +----------------+-----+-+-+-----+ |
| 63 | /* | | |_____ File system # ( 0-7 ) |
| 64 | /* | |_________ Fixed (0) or removable(1) media |
| 65 | /* |___________ Drive # (0-1) |
| 66 | /* |
| 67 | /* For the floppy drives, the major / minor assignment will be |
| 68 | /* 1 |
| 69 | /* 5 8 7 4 3 2 0 |
| 70 | /* +----------------+-----+---+-----+ |
| 71 | /* | 4 | | D | FLS | |
| 72 | /* +----------------+-----+---+-----+ |
| 73 | /* | |_____ File system # ( 0-7 ) |
| 74 | /* |____________ Drive # (0-3) |
| 75 | /* |
| 76 | /****************************************************/ |
| 77 | |
| 78 | #define UDCUNIT(x) ((minor(x) & 0x18) >> 3) |
| 79 | |
| 80 | udstrategy(io, func) |
| 81 | register struct iob *io; |
| 82 | long func; /* Known to be 'read' */ |
| 83 | { |
| 84 | |
| 85 | register unit = io->i_unit; |
| 86 | register bn = io->i_bn; |
| 87 | register char *cntaddr ; |
| 88 | register char *addr ; |
| 89 | register timeout , retries , i; |
| 90 | #ifdef NOIO |
| 91 | register int *memory = (int *)(bn*1024 + MEMDISK); |
| 92 | #endif |
| 93 | |
| 94 | cntaddr = (char *)(udstd[0] + VBIOBASE); /* Booting from cntrlr 0 */ |
| 95 | /* |
| 96 | * prepare a command packet for the controller. |
| 97 | */ |
| 98 | retries = 3; |
| 99 | loop: |
| 100 | #ifndef NOIO |
| 101 | #ifndef SIMIO |
| 102 | if (cntaddr[OB1]) { |
| 103 | printf("UDC controller not ready, %x=%x\n",OB1+cntaddr, |
| 104 | cntaddr[OB1] & 0xff); |
| 105 | return(0); |
| 106 | } |
| 107 | #endif |
| 108 | #endif |
| 109 | udpkt._pkid = 0xAA ; |
| 110 | udpkt._pkdev = UDCUNIT(unit); |
| 111 | if (io->i_ino.i_dev == 3) udpkt._pkdev += 4; /* Floppy */ |
| 112 | udpkt._pkmem[0] = (((long)io->i_ma) >> 16) & 0xffff; |
| 113 | udpkt._pkmem[1] = ((long)io->i_ma) & 0xffff; |
| 114 | if (func == READ) { |
| 115 | udpkt._pkcmd = UDREAD ; |
| 116 | udpkt._pkfnc = UDWTRY ; |
| 117 | } else { |
| 118 | udpkt._pkcmd = UDWRITE ; |
| 119 | udpkt._pkfnc = UDWSECT ; |
| 120 | } |
| 121 | udpkt._psecno = bn * (DEV_BSIZE/SECTSIZ); |
| 122 | udpkt._pkcnt = (io->i_cc + SECTSIZ-1)/SECTSIZ ; |
| 123 | if (movep21(&udpkt,cntaddr+0x105,sizeof(udpkt) )) { |
| 124 | #ifndef NOIO |
| 125 | #ifndef SIMIO |
| 126 | cntaddr[OB1] = (char)0x80 ; /* signal packet transmitted */ |
| 127 | cntaddr[IB2] = (char)0 ; /* clear ACK/NAK field */ |
| 128 | cntaddr[INT] = (char)0x0 ; /* interrupt the controller */ |
| 129 | scope_out(1); |
| 130 | #else |
| 131 | dskio(&udpkt); |
| 132 | #endif |
| 133 | #endif |
| 134 | } |
| 135 | else { |
| 136 | printf ("Wrong command packet arrived at UDC\n"); |
| 137 | printf ("Original UDC\n"); |
| 138 | for (i = 0; i < sizeof(udpkt); i++ ) |
| 139 | printf(" %0x\t%0x\n", ((char *)&udpkt)[i*2] & 0xff, |
| 140 | cntaddr[0x105+i*2] & 0xff); |
| 141 | } |
| 142 | /* |
| 143 | * |
| 144 | * Wait until done (no interrupts now). |
| 145 | * |
| 146 | */ |
| 147 | wait: |
| 148 | #ifndef SIMIO |
| 149 | #ifndef NOIO |
| 150 | timeout = 100; |
| 151 | while (cntaddr[IB2] != (char)0x06 && cntaddr[IB2] != (char)0x15) { |
| 152 | /************** |
| 153 | DELAY(10000); |
| 154 | timeout--; |
| 155 | if (timeout <= 0) { |
| 156 | printf("UDC controller timeout\n"); |
| 157 | return(0); |
| 158 | } |
| 159 | *****************/ |
| 160 | } |
| 161 | scope_out(2); |
| 162 | if (cntaddr[IB2] == (char)0x15) { |
| 163 | if (retries-- < 0) { |
| 164 | printf("Too many NAK from UDC - give up\n"); |
| 165 | return(0); |
| 166 | } else goto loop; |
| 167 | } |
| 168 | |
| 169 | while (cntaddr[IB1] != (char)DEVRDY) |
| 170 | /* DELAY (10000); /* Wait for his response */; |
| 171 | scope_out(3); |
| 172 | |
| 173 | |
| 174 | /* Ignore unsolicited status messages */ |
| 175 | if (cntaddr[PKID] != (char)udpkt._pkid && cntaddr[PKSTT] == (char)0x80) |
| 176 | { |
| 177 | cntaddr[IB1] = (char)0; |
| 178 | cntaddr[OB2] = (char)6; |
| 179 | cntaddr[INT] = (char)0x80; |
| 180 | goto loop; |
| 181 | } |
| 182 | if (cntaddr[PKID] != (char)udpkt._pkid || |
| 183 | cntaddr[PKDEV] != (char)udpkt._pkdev || |
| 184 | cntaddr[PKLEN] != (char)19 || |
| 185 | cntaddr[PKCMD] != (char)udpkt._pkcmd || |
| 186 | cntaddr[PKSTT] != (char)0x70 || /* Command completion */ |
| 187 | cntaddr[STAT1] != (char)0 || |
| 188 | cntaddr[STAT2] != (char)0 ) { |
| 189 | printf ("Strange status from UDC:\n"); |
| 190 | printf("Packet id=%x,unit=%x,original command=%x,status type=%x,status=%x\n", |
| 191 | cntaddr[PKID] & 0xff, |
| 192 | cntaddr[PKDEV] & 0xff, |
| 193 | cntaddr[PKCMD] & 0xff, |
| 194 | cntaddr[PKSTT] & 0xff, |
| 195 | (cntaddr[STAT1]*256+cntaddr[STAT2]) & 0xffff); |
| 196 | if (cntaddr[PKLEN] > 9) { |
| 197 | printf("More response info : "); |
| 198 | for (i=1; i<=cntaddr[PKLEN]-9; i++) |
| 199 | printf("%x ", cntaddr[STAT2+2*i] & 0xff); |
| 200 | printf("\n"); |
| 201 | } |
| 202 | cntaddr[IB1] = (char)0; |
| 203 | cntaddr[OB2] = (char)6; |
| 204 | cntaddr[INT] = (char)0x80; |
| 205 | return(0); |
| 206 | } else { |
| 207 | cntaddr[IB1] = (char)0; |
| 208 | cntaddr[OB2] = (char)6; |
| 209 | cntaddr[INT] = (char)0x80; |
| 210 | scope_out(4); |
| 211 | mtpr(PADC, 0); /* So data will come in right */ |
| 212 | return(io->i_cc); |
| 213 | } |
| 214 | #else |
| 215 | for (i=0; i<io->i_cc/4; i++) |
| 216 | ((int *)io->i_buf)[i] = *memory++; |
| 217 | return(io->i_cc); |
| 218 | #endif |
| 219 | #else |
| 220 | while (udpkt._pkfnc != 0x7f) ; /* wait for completion */ |
| 221 | return(io->i_cc); |
| 222 | #endif |
| 223 | |
| 224 | } |
| 225 | |
| 226 | /* |
| 227 | * Transfer a 21 bytes packet to the controller. |
| 228 | * the message is written to odd addresses, starting from |
| 229 | * the given address. |
| 230 | * For reliability, read it back and see if it's the same. If not, |
| 231 | * return an error code. |
| 232 | */ |
| 233 | movep21(src, dest,cnt) |
| 234 | |
| 235 | char *src, *dest; |
| 236 | int cnt; |
| 237 | { |
| 238 | #ifndef NOIO |
| 239 | #ifndef SIMIO |
| 240 | register char *running_src, *running_dest; |
| 241 | register long running_cnt; |
| 242 | |
| 243 | running_src = src; |
| 244 | running_dest = dest; |
| 245 | running_cnt = cnt; |
| 246 | |
| 247 | for (; running_cnt>0; running_cnt--) { |
| 248 | *running_dest++ = *running_src++; |
| 249 | running_dest++; |
| 250 | } |
| 251 | running_src = src; |
| 252 | running_dest = dest; |
| 253 | running_cnt = cnt; |
| 254 | for (; running_cnt>0; running_cnt--) { |
| 255 | if (*running_dest++ != *running_src++) return(0); |
| 256 | running_dest++; |
| 257 | } |
| 258 | return(1); |
| 259 | #endif |
| 260 | #endif |
| 261 | } |
| 262 | |
| 263 | udopen(io) |
| 264 | struct iob *io; |
| 265 | { |
| 266 | register char *cntaddr; |
| 267 | /* |
| 268 | * Just clean up any junk in the controller's response buffers. |
| 269 | */ |
| 270 | #ifndef NOIO |
| 271 | #ifndef SIMIO |
| 272 | cntaddr = (char *)(udstd[0] + VBIOBASE); /* Booting from cntrlr 0 */ |
| 273 | while (cntaddr[IB1] == (char)DEVRDY) { |
| 274 | cntaddr[IB1] = (char)0; |
| 275 | cntaddr[OB2] = (char)0x06; /* ACK */ |
| 276 | cntaddr[INT] = (char)0; /* Force him to listen and to respond */ |
| 277 | DELAY(50000); |
| 278 | } |
| 279 | #endif |
| 280 | #endif |
| 281 | } |
| 282 | #ifdef SIMIO |
| 283 | dskio(addr) |
| 284 | { |
| 285 | asm(".byte 0x2"); |
| 286 | } |
| 287 | #endif |