Initial commit
[pdp8.git] / sw / speed8 / pc / rk05.c
CommitLineData
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
19static 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
40int 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
59int 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
78int 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
95int 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
112int 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
127int 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
141int order1[16]={0, 2, 4, 6, 8, 10, 12, 14, 1,3,5,7,9,11,13,15};
142int order2[16]={0, 3, 6, 9, 12, 15, 1, 4, 7,10,13,2,5,8,11,14};
143int order3[16]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
144int order4[16]={0,4,8,12,1,5,9,13,2,6,10,14,3,7,11,15};
145
146int 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
220int 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
292void 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}