Commit | Line | Data |
---|---|---|
a6a4e5d4 PH |
1 | #include <stdint.h> |
2 | #include <stdio.h> | |
3 | #include <string.h> | |
4 | #include <errno.h> | |
5 | #include <math.h> | |
6 | ||
7 | #include "rk05.h" | |
8 | #include "speed8.h" | |
9 | #include "link.h" | |
10 | #include "log.h" | |
11 | ||
12 | /* Commands for the RK8E controller */ | |
13 | #define RK_CM_READ 00000 | |
14 | #define RK_CM_SEEK_ONLY 03000 | |
15 | #define RK_CM_WRITE 04000 | |
16 | #define RK_CM_TRANS256 00000 | |
17 | #define RK_CM_TRANS128 00100 | |
18 | ||
19 | static char * bars(int width, int max, int current){ | |
20 | static char buffer[100]; | |
21 | if (width>80) width=80; | |
22 | int i; | |
23 | float width_f=width; | |
24 | float max_f=max; | |
25 | float current_f=current; | |
26 | float step=width_f/max_f; | |
27 | float dots=step*current_f; | |
28 | int actual=round(dots); | |
29 | buffer[0]='['; | |
30 | buffer[width+1]=']'; | |
31 | for (i=0; i<width; i++){ | |
32 | if (i<actual) buffer[i+1]='*'; | |
33 | else buffer[i+1]=' '; | |
34 | } | |
35 | int perc=round((current_f/max_f)*100); | |
36 | sprintf(buffer+width+2," %3i%%",perc); | |
37 | return buffer; | |
38 | } | |
39 | ||
40 | int rk05_write_sector(uint8_t drive, uint16_t disk_address, uint16_t mem_address){ | |
41 | uint16_t cb[5]; | |
42 | debug("rk05_write_sector(): Drive %i, DA: %05o, CA: %04o\n",drive,disk_address, mem_address); | |
43 | if ((disk_address>=203*2*16*256)||(mem_address>4095)||(drive>3)) { | |
44 | debug("rk05_write_sector(): Invalid parameters!\n"); | |
45 | errno=EINVAL; | |
46 | return -1; | |
47 | } | |
48 | cb[0]=ATTENTION; | |
49 | cb[1]=CMD_RK_GO; | |
50 | cb[2]=mem_address; // Current address | |
51 | cb[3]=RK_CM_WRITE|(drive&3)<<1 | |
52 | | ((disk_address>>12)&1) | |
53 | | RK_CM_TRANS256 | |
54 | | 010; // Field!! | |
55 | cb[4]=disk_address&07777; | |
56 | return link_write(cb,5); | |
57 | } | |
58 | ||
59 | int rk05_read_sector(uint8_t drive, uint16_t disk_address, uint16_t mem_address){ | |
60 | debug("rk05_read_sector(): Drive %i, DA: %05o, CA: %04o\n",drive,disk_address, mem_address); | |
61 | uint16_t cb[5]; | |
62 | if ((disk_address>=RK05_TRACKS*16)||(mem_address>4095)||(drive>3)) { | |
63 | debug("rk05_read_sector(): Invalid parameters!\n"); | |
64 | errno=EINVAL; | |
65 | return -1; | |
66 | } | |
67 | cb[0]=ATTENTION; | |
68 | cb[1]=CMD_RK_GO; | |
69 | cb[2]=mem_address; // Current address | |
70 | cb[3]=RK_CM_READ|(drive&3)<<1 | |
71 | | ((disk_address>>12)&1) | |
72 | | 010; // Field!! | |
73 | cb[4]=disk_address&07777; | |
74 | link_write(cb,5); | |
75 | return 0; | |
76 | } | |
77 | ||
78 | int rk05_write_track(uint8_t drive, uint16_t track){ | |
79 | uint16_t cb[4]; | |
80 | uint16_t sector=track*16+0; | |
81 | debug("rk05_write_track(): Drive %i, Track: %i\n",drive,track); | |
82 | if ((drive>3)||(track>=RK05_TRACKS)){ | |
83 | debug("rk05_write_track(): Invalid parameters!\n"); | |
84 | errno=EINVAL; | |
85 | return -1; | |
86 | } | |
87 | cb[0]=ATTENTION; | |
88 | cb[1]=CMD_RK_W_TRACK; | |
89 | cb[2]=((drive&3)<<1) | |
90 | |((sector>>12)&1); | |
91 | cb[3]=(sector)&07777; | |
92 | return link_write(cb,4); | |
93 | } | |
94 | ||
95 | int rk05_read_track(uint8_t drive, uint16_t track){ | |
96 | uint16_t cb[4]; | |
97 | uint16_t sector=track*16+0; | |
98 | debug("rk05_read_track(): Drive %i, Track: %i\n",drive,track); | |
99 | if ((drive>3)||(track>=RK05_TRACKS)){ | |
100 | debug("rk05_read_track(): Invalid parameters!\n"); | |
101 | errno=EINVAL; | |
102 | return -1; | |
103 | } | |
104 | cb[0]=ATTENTION; | |
105 | cb[1]=CMD_RK_R_TRACK; | |
106 | cb[2]=((drive&3)<<1) | |
107 | |((sector>>12)&1); | |
108 | cb[3]=sector&07777; | |
109 | return link_write(cb,4); | |
110 | } | |
111 | ||
112 | int rk05_status(uint16_t * status){ | |
113 | uint16_t cb[2]; | |
114 | int res; | |
115 | debug("rk05_status()\n"); | |
116 | cb[0]=ATTENTION; | |
117 | cb[1]=CMD_RK_STATUS; | |
118 | res=link_write(cb,2); | |
119 | if (res<0) return res; | |
120 | res=link_read(cb,1); | |
121 | if (res<0) return res; | |
122 | if (status) *status=cb[0]; | |
123 | debug("rk05_status(): %04o\n",cb[0]); | |
124 | return 0; | |
125 | } | |
126 | ||
127 | int rk05_recalibrate(uint8_t drive){ | |
128 | uint16_t cb[2]; | |
129 | debug("rk05_recalibrate(): Drive: %i\n",drive); | |
130 | if (drive>3){ | |
131 | debug("rk05_recalibrate(): Invalid drive!\n"); | |
132 | errno=EINVAL; | |
133 | return -1; | |
134 | } | |
135 | cb[0]=ATTENTION; | |
136 | cb[1]=CMD_RK_RECAL0 + 0100*drive; | |
137 | return link_write(cb,2); | |
138 | } | |
139 | ||
140 | ||
141 | int order1[16]={0, 2, 4, 6, 8, 10, 12, 14, 1,3,5,7,9,11,13,15}; | |
142 | int order2[16]={0, 3, 6, 9, 12, 15, 1, 4, 7,10,13,2,5,8,11,14}; | |
143 | int order3[16]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; | |
144 | int order4[16]={0,4,8,12,1,5,9,13,2,6,10,14,3,7,11,15}; | |
145 | ||
146 | int rk05_read_disk(uint8_t disk, uint16_t * target){ | |
147 | int track,sector; | |
148 | int res; | |
149 | uint16_t status; | |
150 | if (!target){ | |
151 | errno=EINVAL; | |
152 | return -1; | |
153 | } | |
154 | res=rk05_recalibrate(disk); | |
155 | if (res<0) return res; | |
156 | res=rk05_status(&status); | |
157 | if (res<0) return res; | |
158 | if (status != RK05_STATUS_OK){ | |
159 | err("Status error while recalibrating!\n"); | |
160 | ERROR rk05_perror(status); | |
161 | errno=EIO; | |
162 | return -1; | |
163 | } | |
164 | ||
165 | for (track=0; track<RK05_TRACKS; track++){ | |
166 | info("\rReading drive %i: CYL: %3i, SIDE: %i %s", | |
167 | disk, track/2, track%2,bars(70,RK05_TRACKS-1,track)); | |
168 | res=rk05_read_track(disk, track); | |
169 | if (res<0) return res; | |
170 | res=rk05_status(&status); | |
171 | if (res<0) return res; | |
172 | ||
173 | if (status != RK05_STATUS_OK){ | |
174 | int retries; | |
175 | info("\nAn error occured!\n"); | |
176 | INFO rk05_perror(status); | |
177 | warning("Reading of track %i failed. Will try individual sectors now.\n", track); | |
178 | res=rk05_recalibrate(disk); | |
179 | if (res<0) return res; | |
180 | res=rk05_status(&status); | |
181 | if (res<0) return res; | |
182 | for (sector=0; sector<16; sector++){ | |
183 | retries=16; | |
184 | while(retries){ | |
185 | debug("Reading sector %i with %i tries left\n",sector,retries); | |
186 | res=rk05_read_sector(disk,track*16+order2[sector],order2[sector]*0400); | |
187 | if (res<0) return res; | |
188 | res=rk05_status(&status); | |
189 | if (res<0) return res; | |
190 | if (status != RK05_STATUS_OK){ | |
191 | retries--; | |
192 | warning("Error on sector %i, will retry %i times.\n",sector, retries); | |
193 | INFO rk05_perror(status); | |
194 | res=rk05_recalibrate(disk); | |
195 | if (res<0) return res; | |
196 | res=rk05_status(&status); | |
197 | if (res<0) return res; | |
198 | } else { | |
199 | retries++; | |
200 | break; | |
201 | } | |
202 | } | |
203 | } | |
204 | if(retries==0){ | |
205 | err("Failed to read track %i. Giving up.\n",track); | |
206 | errno=EIO; | |
207 | return -1; | |
208 | } else { | |
209 | warning("Now it succeeded.\n"); | |
210 | } | |
211 | } | |
212 | res=get_buffer(target+(4096*track)); | |
213 | if(res<0) return res; | |
214 | } | |
215 | info("\n"); | |
216 | debug("rk05_read_disk():Success\n"); | |
217 | return 0; | |
218 | } | |
219 | ||
220 | int rk05_write_disk(uint8_t disk, uint16_t * target){ | |
221 | int track,sector; | |
222 | int res; | |
223 | uint16_t status; | |
224 | if (!target){ | |
225 | errno=EINVAL; | |
226 | return -1; | |
227 | } | |
228 | res=rk05_recalibrate(disk); | |
229 | if (res<0) return res; | |
230 | res=rk05_status(&status); | |
231 | if (res<0) return res; | |
232 | if (status != RK05_STATUS_OK){ | |
233 | err("Status error while recalibrating!\n"); | |
234 | ERROR rk05_perror(status); | |
235 | errno=EIO; | |
236 | return -1; | |
237 | } | |
238 | for (track=0; track<RK05_TRACKS; track++){ | |
239 | info("\rWriting drive %i: CYL: %3i, SIDE: %i %s", disk, track/2, track%2, bars(70,RK05_TRACKS-1,track)); | |
240 | res=put_buffer(target+(4096*track)); | |
241 | if (res<0) return res; | |
242 | res=rk05_write_track(disk,track); | |
243 | if (res<0) return res; | |
244 | res=rk05_status(&status); | |
245 | if (res<0) return res; | |
246 | ||
247 | if (status != RK05_STATUS_OK){ | |
248 | int retries; | |
249 | info ("\nAn error occured!\n"); | |
250 | INFO rk05_perror(status); | |
251 | warning("Writing of track %i failed. Will try individual sectors now.\n", track); | |
252 | res=rk05_recalibrate(disk); | |
253 | if (res<0) return res; | |
254 | res=rk05_status(&status); | |
255 | if (res<0) return res; | |
256 | for (sector=0; sector<16; sector++){ | |
257 | retries=16; | |
258 | while(retries){ | |
259 | debug("Writing sector %i with %i tries left\n",order2[sector],retries); | |
260 | res=rk05_write_sector(disk,track*16+order2[sector],order2[sector]*0400); | |
261 | if (res<0) return res; | |
262 | res=rk05_status(&status); | |
263 | if (res<0) return res; | |
264 | if (status != RK05_STATUS_OK){ | |
265 | retries--; | |
266 | warning("Error on sector %i, will retry %i times.\n",order2[sector], retries); | |
267 | INFO rk05_perror(status); | |
268 | res=rk05_recalibrate(disk); | |
269 | if (res<0) return res; | |
270 | res=rk05_status(&status); | |
271 | if (res<0) return res; | |
272 | } else { | |
273 | retries++; | |
274 | break; | |
275 | } | |
276 | } | |
277 | } | |
278 | if(retries==0){ | |
279 | err("Failed to write track %i. Giving up.\n",track); | |
280 | errno=EIO; | |
281 | return -1; | |
282 | } else { | |
283 | warning("Now it succeeded.\n"); | |
284 | } | |
285 | } | |
286 | } | |
287 | info("\n"); | |
288 | debug("rk05_write_disk():Success\n"); | |
289 | return 0; | |
290 | } | |
291 | ||
292 | void rk05_perror(uint16_t status){ | |
293 | fprintf(stderr, "Status: %s\n",(status&04000?"Done":"Busy")); | |
294 | if (status & 02000) fprintf(stderr,"Head in motion.\n"); | |
295 | if (status & 00400) fprintf(stderr,"Seek fail\n"); | |
296 | if (status & 00200) fprintf(stderr,"File not ready\n"); | |
297 | if (status & 00100) fprintf(stderr,"Control busy\n"); | |
298 | if (status & 00040) fprintf(stderr,"Timing error"); | |
299 | if (status & 00020) printf("Write lock error\n"); | |
300 | if (status & 00010) fprintf(stderr,"Parity error\n"); | |
301 | if (status & 00004) fprintf(stderr,"Data request late\n"); | |
302 | if (status & 00002) fprintf(stderr,"Drive status error\n"); | |
303 | if (status & 00001) fprintf(stderr,"Cylinder address error\n"); | |
304 | } |